# # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # # Copyright 2004-2008 University of Zagreb, Croatia. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # This work was supported in part by Croatian Ministry of Science # and Technology through the research contract #IP-2003-143. # #****h* imunes/linkcfg.tcl # NAME # linkcfg.tcl -- file used for manipultaion with links in IMUNES # FUNCTION # This module is used to define all the actions used for configuring # links in IMUNES. # # NOTES # # linkPeers { link_id } # Returns node_ids of link endpoints # # linkByPeers { node1_id node2_id } # Returns link_id whose peers are node1 and node2 # # removeLink { link_id } # Removes the link and related entries in peering node's configs # # getLinkBandwidth { link_id } # ... in bits per second # # getLinkBandwidthString { link_id } # ... as string # # getLinkDelay { link_id } # ... in microseconds # # getLinkDelayString { link_id } # ... as sting # # setLinkBandwidth { link_id bandwidth } # ... in bits per second # # setLinkDelay { link_id delay } # ... in microseconds # # All of the above functions are independent to any Tk objects. This means # they can be used for implementing tasks external to GUI, yet inside the # GUI any updating of related Tk objects (such as text labels etc.) will # have to be implemented by additional Tk code. #**** #****f* linkcfg.tcl/linkPeers # NAME # linkPeers -- get link's peer nodes # SYNOPSIS # set link_peers [linkPeers $link_id] # FUNCTION # Returns node_ids of link endpoints. # INPUTS # * link_id -- link id # RESULT # * link_peers -- returns nodes_ids of a link endpoints # in a list {node1_id node2_id} #**** proc linkPeers { link } { global $link set entry [lsearch -inline [set $link] "nodes {*}"] return [lindex $entry 1] } #****f* linkcfg.tcl/linkByPeers # NAME # linkByPeers -- get link id from peer nodes # SYNOPSIS # set link_id [linkByPeers $node1_id $node2_id] # FUNCTION # Returns link_id whose peers are node1 and node2. # The order of input nodes is irrelevant. # INPUTS # * node1_id -- node id of the first node # * node2_id -- node id of the second node # RESULT # * link_id -- returns id of a link connecting endpoints # node1_id node2_id. #**** proc linkByPeers { node1 node2 } { global link_list foreach link $link_list { set peers [linkPeers $link] if { $peers == "$node1 $node2" || $peers == "$node2 $node1" } { return $link } } } # same as linkByPeers but for links split across canvases proc linkByPeersMirror { node1 node2 } { foreach ifc [ifcList $node1] { set link [lindex [linkByIfc $node1 $ifc] 0] set mirror [getLinkMirror $link] if { $mirror != "" } { set peers [linkPeers $mirror] # link node 1 is real node, link node 2 is always pseudo-node if { [lindex $peers 0] == $node2 } { return $link } } } return "" } #****f* linkcfg.tcl/removeLink # NAME # removeLink -- removes a link. # SYNOPSIS # removeLink $link_id # FUNCTION # Removes the link and related entries in peering node's configs. # Updates the default route for peer nodes. # INPUTS # * link_id -- link id #**** proc removeLink { link } { global link_list $link set pnodes [linkPeers $link] foreach node $pnodes { global $node set i [lsearch $pnodes $node] set peer [lreplace $pnodes $i $i] set ifc [ifcByPeer $node $peer] netconfClearSection $node "interface $ifc" set i [lsearch [set $node] "interface-peer {$ifc $peer}"] set $node [lreplace [set $node] $i $i] } set i [lsearch -exact $link_list $link] set link_list [lreplace $link_list $i $i] } #****f* linkcfg.tcl/getLinkBandwidth # NAME # getLinkBandwidth -- get link bandwidth # SYNOPSIS # set bandwidth [getLinkBandwidth $link_id] # FUNCTION # Returns the link bandwidth expressed in bits per second. # INPUTS # * link_id -- link id # RESULT # * bandwidth -- The value of link bandwidth in bits per second. #**** proc getLinkBandwidth { link } { global $link set entry [lsearch -inline [set $link] "bandwidth *"] return [lindex $entry 1] } #****f* linkcfg.tcl/getLinkBandwidthString # NAME # getLinkBandwidthString -- get link bandwidth string # SYNOPSIS # set bandwidth_str [getLinkBandwidthString $link_id] # FUNCTION # Returns the link bandwidth in form of a number an a mesure unit. # Measure unit is automaticaly asigned depending on the value of bandwidth. # INPUTS # * link_id -- link id # RESULT # * bandwidth_str -- The value of link bandwidth formated in a sting # containing a measure unit. #**** proc getLinkBandwidthString { link } { global $link set bandstr "" set bandwidth [getLinkBandwidth $link] if { $bandwidth > 0 } { if { $bandwidth >= 660000000 } { set bandstr "[format %.2f [expr {$bandwidth / 1000000000.0}]] Gbps" } elseif { $bandwidth >= 99000000 } { set bandstr "[format %d [expr {$bandwidth / 1000000}]] Mbps" } elseif { $bandwidth >= 9900000 } { set bandstr "[format %.2f [expr {$bandwidth / 1000000.0}]] Mbps" } elseif { $bandwidth >= 990000 } { set bandstr "[format %d [expr {$bandwidth / 1000}]] Kbps" } elseif { $bandwidth >= 9900 } { set bandstr "[format %.2f [expr {$bandwidth / 1000.0}]] Kbps" } else { set bandstr "$bandwidth bps" } } return $bandstr } #****f* linkcfg.tcl/setLinkBandwidth # NAME # setLinkBandwidth -- set link bandwidth # SYNOPSIS # setLinkBandwidth $link_id $value # FUNCTION # Sets the link bandwidth in a bits per second. # INPUTS # * link_id -- link id # * value -- link bandwidth in bits per second. #**** proc setLinkBandwidth { link value } { global $link set i [lsearch [set $link] "bandwidth *"] if { $value <= 0 } { set $link [lreplace [set $link] $i $i] } else { set $link [lreplace [set $link] $i $i "bandwidth $value"] } } # # Marko - XXX document! # proc getLinkColor { link } { global $link defLinkColor set entry [lsearch -inline [set $link] "color *"] if { $entry == "" } { return $defLinkColor } else { return [lindex $entry 1] } } proc setLinkColor { link value } { global $link set i [lsearch [set $link] "color *"] set $link [lreplace [set $link] $i $i "color $value"] } proc getLinkWidth { link } { global $link defLinkWidth set entry [lsearch -inline [set $link] "width *"] if { $entry == "" } { return $defLinkWidth } else { return [lindex $entry 1] } } proc setLinkWidth { link value } { global $link set i [lsearch [set $link] "width *"] set $link [lreplace [set $link] $i $i "width $value"] } #****f* linkcfg.tcl/getLinkDelay # NAME # getLinkDelay -- get link delay # SYNOPSIS # set delay [getLinkDelay $link_id] # FUNCTION # Returns the link delay expressed in microseconds. # INPUTS # * link_id -- link id # RESULT # * delay -- The value of link delay in microseconds. #**** proc getLinkDelay { link } { global $link set entry [lsearch -inline [set $link] "delay *"] return [lindex $entry 1] } #****f* linkcfg.tcl/getLinkDelayString # NAME # getLinkDelayString -- get link delay string # SYNOPSIS # set delay [getLinkDelayString $link_id] # FUNCTION # Returns the link delay as a string with avalue and measure unit. # Measure unit is automaticaly asigned depending on the value of delay. # INPUTS # * link_id -- link id # RESULT # * delay -- The value of link delay formated in a string # containing a measure unit. #**** proc getLinkDelayString { link } { global $link set delay [getLinkDelay $link] if { "$delay" != "" } { if { $delay >= 10000 } { set delstr "[expr {$delay / 1000}] ms" } elseif { $delay >= 1000 } { set delstr "[expr {$delay * .001}] ms" } else { set delstr "$delay us" } } else { set delstr "" } return $delstr } #****f* linkcfg.tcl/setLinkDelay # NAME # setLinkDelay -- set link delay # SYNOPSIS # setLinkDelay $link_id $value # FUNCTION # Sets the link delay in microseconds. # INPUTS # * link_id -- link id # * value -- link delay value in microseconds. #**** proc setLinkDelay { link value } { global $link set i [lsearch [set $link] "delay *"] if { $value <= 0 } { set $link [lreplace [set $link] $i $i] } else { set $link [lreplace [set $link] $i $i "delay $value"] } } #****f* linkcfg.tcl/getLinkBER # NAME # getLinkBER -- get link BER # SYNOPSIS # set BER [getLinkBER $link_id] # FUNCTION # Returns 1/BER value of the link. # INPUTS # * link_id -- link id # RESULT # * BER -- The value of 1/BER of the link. #**** proc getLinkBER { link } { global $link set entry [lsearch -inline [set $link] "ber *"] return [lindex $entry 1] } #****f* linkcfg.tcl/setLinkBER # NAME # setLinkBER -- set link BER # SYNOPSIS # setLinkBER $link_id value # FUNCTION # Sets the BER value of the link. # INPUTS # * link_id -- link id # * value -- The value of 1/BER of the link. #**** proc setLinkBER { link value } { global $link set i [lsearch [set $link] "ber *"] if { $value <= 0 } { set $link [lreplace [set $link] $i $i] } else { set $link [lreplace [set $link] $i $i "ber $value"] } } #****f* linkcfg.tcl/getLinkDup # NAME # getLinkDup -- get link packet duplicate value # SYNOPSIS # set duplicate [getLinkDup $link_id] # FUNCTION # Returns the value of the link duplicate percentage. # INPUTS # * link_id -- link id # RESULT # * duplicate -- The percentage of the link packet duplicate value. #**** proc getLinkDup { link } { global $link set entry [lsearch -inline [set $link] "duplicate *"] return [lindex $entry 1] } #****f* linkcfg.tcl/setLinkDup # NAME # setLinkDup -- set link packet duplicate value # SYNOPSIS # setLinkDup $link_id $value # FUNCTION # Set link packet duplicate percentage. # INPUTS # * link_id -- link id # * value -- The percentage of the link packet duplicate value. #**** proc setLinkDup { link value } { global $link set i [lsearch [set $link] "duplicate *"] if { $value <= 0 || $value > 50 } { set $link [lreplace [set $link] $i $i] } else { set $link [lreplace [set $link] $i $i "duplicate $value"] } } #****f* linkcfg.tcl/getLinkMirror # NAME # getLinkMirror -- get link's mirror link # SYNOPSIS # set mirror_link_id [getLinkMirror $link_id] # FUNCTION # Returns the value of the link's mirror link. Mirror link is the other # part of the link connecting node to a pseudo node. Two mirror links # present only one physical link. # INPUTS # * link_id -- link id # RESULT # * mirror_link_id -- Mirror link id #**** proc getLinkMirror { link } { global $link set entry [lsearch -inline [set $link] "mirror *"] return [lindex $entry 1] } #****f* linkcfg.tcl/setLinkMirror # NAME # setLinkMirror -- set link's mirror link # SYNOPSIS # setLinkMirror $link_id $mirror_link_id # FUNCTION # Sets the value of the link's mirror link. Mirror link is the other # part of the link connecting node to a pseudo node. Two mirror links # present only one physical link. # INPUTS # * link_id -- link id # RESULT # * mirror_link_id -- Mirror link id #**** proc setLinkMirror { link value } { global $link set i [lsearch [set $link] "mirror *"] if { $value == "" } { set $link [lreplace [set $link] $i $i] } else { set $link [lreplace [set $link] $i $i "mirror $value"] } } #****f* linkcfg.tcl/splitLink # NAME # splitLink -- slit the link # SYNOPSIS # set nodes [splitLink $link_id $nodetype] # FUNCTION # Splits the link in two parts. Each part of the split link is one # pseudo link. # INPUTS # * link_id -- link id # * nodetype -- type of the new nodes connecting slit links. # Usual value is pseudo. # RESULT # * nodes -- list of node ids of new nodes. #**** proc splitLink { link nodetype } { global link_list $link set orig_nodes [linkPeers $link] set orig_node1 [lindex $orig_nodes 0] set orig_node2 [lindex $orig_nodes 1] set new_node1 [newNode $nodetype] set new_node2 [newNode $nodetype] set new_link1 [newObjectId link] lappend link_list $new_link1 set new_link2 [newObjectId link] lappend link_list $new_link2 set ifc1 [ifcByPeer $orig_node1 $orig_node2] set ifc2 [ifcByPeer $orig_node2 $orig_node1] global $orig_node1 $orig_node2 $new_node1 $new_node2 global $new_link1 $new_link2 set $new_link1 {} set $new_link2 {} set i [lsearch [set $orig_node1] "interface-peer {* $orig_node2}"] set $orig_node1 [lreplace [set $orig_node1] $i $i \ "interface-peer {$ifc1 $new_node1}"] set i [lsearch [set $orig_node2] "interface-peer {* $orig_node1}"] set $orig_node2 [lreplace [set $orig_node2] $i $i \ "interface-peer {$ifc2 $new_node2}"] lappend $new_link1 "nodes {$orig_node1 $new_node1}" lappend $new_link2 "nodes {$orig_node2 $new_node2}" setNodeCanvas $new_node1 [getNodeCanvas $orig_node1] setNodeCanvas $new_node2 [getNodeCanvas $orig_node2] setNodeCoords $new_node1 [getNodeCoords $orig_node2] setNodeCoords $new_node2 [getNodeCoords $orig_node1] if { $nodetype != "pseudo" } { setNodeLabelCoords $new_node1 [getNodeLabelCoords $orig_node2] setNodeLabelCoords $new_node2 [getNodeLabelCoords $orig_node1] } else { setNodeLabelCoords $new_node1 [getNodeCoords $orig_node2] setNodeLabelCoords $new_node2 [getNodeCoords $orig_node1] } lappend $new_node1 "interface-peer {0 $orig_node1}" lappend $new_node2 "interface-peer {0 $orig_node2}" setLinkBandwidth $new_link1 [getLinkBandwidth $link] setLinkBandwidth $new_link2 [getLinkBandwidth $link] setLinkDelay $new_link1 [getLinkDelay $link] setLinkDelay $new_link2 [getLinkDelay $link] setLinkBER $new_link1 [getLinkBER $link] setLinkBER $new_link2 [getLinkBER $link] setLinkDup $new_link1 [getLinkDup $link] setLinkDup $new_link2 [getLinkDup $link] set i [lsearch -exact $link_list $link] set link_list [lreplace $link_list $i $i] return "$new_node1 $new_node2" } #****f* linkcfg.tcl/mergeLink # NAME # mergeLink -- merge the link # SYNOPSIS # set new_link_id [mergeLink $link_id] # FUNCTION # Rebuilts a link from two pseudo link. # INPUTS # * link_id -- pseudo link id # RESULT # * new_link_id -- rebuilt link id. #**** proc mergeLink { link } { global link_list node_list set mirror_link [getLinkMirror $link] if { $mirror_link == "" } { puts "XXX mergeLink called for non-pseudo link!!!" return } set link1_peers [linkPeers $link] set link2_peers [linkPeers $mirror_link] set orig_node1 [lindex $link1_peers 0] set orig_node2 [lindex $link2_peers 0] set pseudo_node1 [lindex $link1_peers 1] set pseudo_node2 [lindex $link2_peers 1] set new_link [newObjectId link] global $orig_node1 $orig_node2 global $new_link set ifc1 [ifcByPeer $orig_node1 $pseudo_node1] set ifc2 [ifcByPeer $orig_node2 $pseudo_node2] set i [lsearch [set $orig_node1] "interface-peer {* $pseudo_node1}"] set $orig_node1 [lreplace [set $orig_node1] $i $i \ "interface-peer {$ifc1 $orig_node2}"] set i [lsearch [set $orig_node2] "interface-peer {* $pseudo_node2}"] set $orig_node2 [lreplace [set $orig_node2] $i $i \ "interface-peer {$ifc2 $orig_node1}"] set $new_link {} lappend $new_link "nodes {$orig_node1 $orig_node2}" setLinkBandwidth $new_link [getLinkBandwidth $link] setLinkDelay $new_link [getLinkDelay $link] setLinkBER $new_link [getLinkBER $link] setLinkDup $new_link [getLinkDup $link] set i [lsearch -exact $link_list $link] set link_list [lreplace $link_list $i $i] set i [lsearch -exact $link_list $mirror_link] set link_list [lreplace $link_list $i $i] lappend link_list $new_link set i [lsearch -exact $node_list $pseudo_node1] set node_list [lreplace $node_list $i $i] set i [lsearch -exact $node_list $pseudo_node2] set node_list [lreplace $node_list $i $i] return $new_link } #****f* linkcfg.tcl/newLink # NAME # newLink -- create new link # SYNOPSIS # set new_link_id [newLink $node1_id $node2_id] # FUNCTION # Creates a new link between nodes node1_id and node2_id. The order of # nodes is irrelevant. # INPUTS # * node1_id -- node id of the peer node # * node2_id -- node id of the second peer node # RESULT # * new_link_id -- new link id. #**** proc newLink { lnode1 lnode2 } { global link_list global $lnode1 $lnode2 global defEthBandwidth defSerBandwidth defSerDelay global defLinkColor defLinkWidth global curcanvas global systype if { [nodeType $lnode1] == "lanswitch" && \ [nodeType $lnode2] != "router" && \ [nodeType $lnode2] != "lanswitch" } { set regular no } if { [nodeType $lnode2] == "lanswitch" && \ [nodeType $lnode1] != "router" && \ [nodeType $lnode1] != "lanswitch" } { set regular no } if { [nodeType $lnode1] == "hub" && \ [nodeType $lnode2] == "hub" } { set regular no } # Boeing: added tunnel, ktunnel types to behave as rj45 if { [nodeType $lnode1] == "rj45" || [nodeType $lnode2] == "rj45" || \ [nodeType $lnode1] == "tunnel" || [nodeType $lnode2] == "tunnel" || \ [nodeType $lnode1] == "ktunnel" || [nodeType $lnode2] == "ktunnel" } { if { [nodeType $lnode1] == "rj45" || [nodeType $lnode1] == "tunnel" || \ [nodeType $lnode1] == "ktunnel" } { set rj45node $lnode1 set othernode $lnode2 } else { set rj45node $lnode2 set othernode $lnode1 } # only allowed to link with certain types if { [lsearch {router lanswitch hub pc host wlan} \ [nodeType $othernode]] < 0} { return } # check if already linked to something else if { [lsearch [set $rj45node] "interface-peer *"] > 0 } { return } } # Boeing: wlan node is always first of the two nodes if { [nodeType $lnode2] == "wlan" } { set tmp $lnode1 set lnode1 $lnode2 set lnode2 $tmp } # end Boeing set link [newObjectId link] global $link set $link {} # pick new interface names or use names from global hint set do_auto_addressing 1 global g_newLink_ifhints if { [info exists g_newLink_ifhints] && $g_newLink_ifhints != "" } { set ifname1 [lindex $g_newLink_ifhints 0] set ifname2 [lindex $g_newLink_ifhints 1] set do_auto_addressing 0 set g_newLink_ifhints "" } else { set ifname1 [newIfc [chooseIfName $lnode1 $lnode2] $lnode1] set ifname2 [newIfc [chooseIfName $lnode2 $lnode1] $lnode2] } lappend $lnode1 "interface-peer {$ifname1 $lnode2}" lappend $lnode2 "interface-peer {$ifname2 $lnode1}" # check for existing interface config (supported by API) # this allows for interfaces/addresses to be configured before the link # is created set ipv4_addr1 [getIfcIPv4addr $lnode1 $ifname1] set ipv6_addr1 [getIfcIPv6addr $lnode1 $ifname1] set ipv4_addr2 [getIfcIPv4addr $lnode2 $ifname2] set ipv6_addr2 [getIfcIPv6addr $lnode2 $ifname2] lappend $link "nodes {$lnode1 $lnode2}" # parameters for links to wlan are based on wlan parameters if { [nodeType $lnode1] == "wlan" } { set bandwidth [getLinkBandwidth $lnode1] set delay [getLinkDelay $lnode1] set model [netconfFetchSection $lnode1 "mobmodel"] if { $bandwidth != "" } { lappend $link "bandwidth [getLinkBandwidth $lnode1]" } set ipv4_addr1 [getIfcIPv4addr $lnode1 wireless] if { $ipv4_addr1 == "" } { ;# allocate WLAN address now setIfcIPv4addr $lnode1 wireless "[findFreeIPv4Net 32].0/32" } set ipv6_addr1 [getIfcIPv6addr $lnode1 wireless] if { $ipv6_addr1 == "" } { setIfcIPv6addr $lnode1 wireless "[findFreeIPv6Net 128]::0/128" } if { [string range $model 0 6] == "coreapi" } { set delay 0; # delay controlled by wireless module } elseif {$delay != ""} { if { [lindex $systype 0] == "FreeBSD" } { lappend $link "delay [expr $delay/2]" } else { lappend $link "delay $delay" } } if { [[typemodel $lnode2].layer] == "NETWORK" } { if { $ipv4_addr2 == "" } { autoIPv4addr $lnode2 $ifname2 } if { $ipv6_addr2 == "" } { autoIPv6addr $lnode2 $ifname2 } } # tunnels also excluded from link settings } elseif { ([nodeType $lnode1] == "lanswitch" || \ [nodeType $lnode2] == "lanswitch" || \ [string first eth "$ifname1 $ifname2"] != -1) && \ [nodeType $lnode1] != "rj45" && [nodeType $lnode2] != "rj45" && \ [nodeType $lnode1] != "tunnel" && [nodeType $lnode2] != "tunnel" && \ [nodeType $lnode1] != "ktunnel" && [nodeType $lnode2] != "ktunnel" } { lappend $link "bandwidth $defEthBandwidth" } elseif { [string first ser "$ifname1 $ifname2"] != -1 } { lappend $link "bandwidth $defSerBandwidth" lappend $link "delay $defSerDelay" } lappend link_list $link if { [nodeType $lnode2] != "pseudo" && [nodeType $lnode1] != "wlan" && [[typemodel $lnode1].layer] == "NETWORK" } { if { $ipv4_addr1 == "" && $do_auto_addressing } { autoIPv4addr $lnode1 $ifname1 } if { $ipv6_addr1 == "" && $do_auto_addressing } { autoIPv6addr $lnode1 $ifname1 } } # assume wlan is always lnode1 if { [nodeType $lnode1] != "pseudo" && [nodeType $lnode1] != "wlan" && [[typemodel $lnode2].layer] == "NETWORK" } { if { $ipv4_addr2 == "" && $do_auto_addressing } { autoIPv4addr $lnode2 $ifname2 } if { $ipv6_addr2 == "" && $do_auto_addressing } { autoIPv6addr $lnode2 $ifname2 } } # tunnel address based on its name if { [nodeType $lnode1] == "tunnel" } { set ipaddr "[getNodeName $lnode1]/24" setIfcIPv4addr $lnode1 e0 $ipaddr } if { [nodeType $lnode2] == "tunnel" } { set ipaddr "[getNodeName $lnode2]/24" setIfcIPv4addr $lnode2 e0 $ipaddr } return $link } #****f* linkcfg.tcl/linkByIfc # NAME # linkByIfg -- get link by interface # SYNOPSIS # set link_id [linkByIfc $node_id $fc] # FUNCTION # Returns the link id of the link connecting the node's interface # INPUTS # * node_id -- node id # * ifc -- interface # RESULT # * link_id -- link id. #**** proc linkByIfc { node ifc } { global link_list set peer [peerByIfc $node $ifc] set dir "" foreach link $link_list { set endpoints [linkPeers $link] if { $endpoints == "$node $peer" } { set dir downstream break } if { $endpoints == "$peer $node" } { set dir upstream break } } if { $dir == "" } { puts "*** linkByIfc error: node=$node ifc=$ifc" } return [list $link $dir] } # Boeing: jitter proc getLinkJitter { link } { global $link set entry [lsearch -inline [set $link] "jitter *"] return [lindex $entry 1] } proc setLinkJitter { link value } { global $link set i [lsearch [set $link] "jitter *"] if { $value <= 0 } { set $link [lreplace [set $link] $i $i] } else { set $link [lreplace [set $link] $i $i "jitter $value"] } } # get any type of link attribute proc getLinkOpaque { link key } { global $link set entry [lsearch -inline [set $link] "$key *"] return [lindex $entry 1] } # set any type of link attribute # passing in a value <= 0 or "" will delete this key proc setLinkOpaque { link key value } { global $link set i [lsearch [set $link] "$key *"] if { $value <= 0 } { set $link [lreplace [set $link] $i $i] } else { set $link [lreplace [set $link] $i $i "$key $value"] } } # # change GUI attributes for a link (width, color, dash) # proc updateLinkGuiAttr { link attr } { global defLinkColor defLinkWidth if { $attr == "" } { return } foreach a $attr { set kv [split $a =] set key [lindex $kv 0] set value [lindex $kv 1] switch -exact -- $key { width { if { $value == "" } { set value $defLinkWidth } setLinkWidth $link $value .c itemconfigure "link && $link" -width [getLinkWidth $link] } color { setLinkColor $link $value .c itemconfigure "link && $link" -fill [getLinkColor $link] } dash { .c itemconfigure "link && $link" -dash $value } default { puts "warning: unsupported GUI link attribute: $key" } } ;# end switch } ;# end foreach attr }