core-extra/gui/linkcfg.tcl
2019-09-25 10:46:41 -07:00

1015 lines
28 KiB
Tcl

#
# 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 {dir "down"} } {
global $link
set entry [lsearch -inline [set $link] "bandwidth *"]
set val [lindex $entry 1] ;# one or more values
if { $dir == "up" } { return [lindex $val 1] }
return [lindex $val 0]
}
#****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 sep ""
set bandwidth [getLinkBandwidth $link]
set bandwidthup [getLinkBandwidth $link up]
if { $bandwidthup > 0 } {
set bandwidth [list $bandwidth $bandwidthup]
set sep " / "
}
foreach bw $bandwidth {
if { $bandstr != "" } { set bandstr "$bandstr$sep" }
set bandstr "$bandstr[getSIStringValue $bw "bps"]"
}
return $bandstr
}
proc getSIStringValue { val suffix } {
if { $val <= 0 } {
return ""
}
if { $val >= 660000000 } {
return "[format %.2f [expr {$val / 1000000000.0}]] G$suffix"
} elseif { $val >= 99000000 } {
return "[format %d [expr {$val / 1000000}]] M$suffix"
} elseif { $val >= 9900000 } {
return "[format %.2f [expr {$val / 1000000.0}]] M$suffix"
} elseif { $val >= 990000 } {
return "[format %d [expr {$val / 1000}]] K$suffix"
} elseif { $val >= 9900 } {
return "[format %.2f [expr {$val / 1000.0}]] K$suffix"
} else {
return "$val $suffix"
}
}
#****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 {
if { [llength $value] > 1 } { set value "{$value}" }
set $link [lreplace [set $link] $i $i "bandwidth $value"]
}
}
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 {dir "down"} } {
global $link
set entry [lsearch -inline [set $link] "delay *"]
set val [lindex $entry 1] ;# one or more values
if { $dir == "up" } { return [lindex $val 1] }
return [lindex $val 0]
}
#****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 plusminus "\261"
set delaystr ""
set sep ""
set delay [getLinkDelay $link]
set delayup [getLinkDelay $link up]
set jitter [getLinkJitter $link]
set jitterup [getLinkJitter $link up]
if { $jitter > 0 && $delay == "" } { set delay 0 }
if { $jitterup > 0 && $delayup == "" } { set delayup 0 }
if { $delayup > 0 || $jitterup > 0 } {
set delay [list $delay $delayup]
set jitter [list $jitter $jitterup]
set sep " / "
}
set i 0
foreach d $delay {
if { $delaystr != "" } { set delaystr "$delaystr$sep" }
if { [lindex $jitter $i] != "" } {
set jstr " ($plusminus"
set jstr "$jstr[getSIMicrosecondValue [lindex $jitter $i]])"
} else {
set jstr ""
}
#set dstr "[getSIMicrosecondValue $d]"
#if { $dstr == "" && $jstr != "" } { set dstr "0 us" }
#set delaystr "$delaystr$dstr$jstr"
set delaystr "$delaystr[getSIMicrosecondValue $d]$jstr"
incr i
}
return $delaystr
}
proc getSIMicrosecondValue { val } {
if { $val == "" } {
return ""
}
if { $val >= 10000 } {
return "[expr {$val / 1000}] ms"
} elseif { $val >= 1000 } {
return "[expr {$val * .001}] ms"
} else {
return "$val us"
}
}
#****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 { [checkEmptyZeroValues $value] } {
set $link [lreplace [set $link] $i $i]
} else {
if { [llength $value] > 1 } { set value "{$value}" }
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 {dir "down"} } {
global $link
set entry [lsearch -inline [set $link] "ber *"]
set val [lindex $entry 1] ;# one or more values
if { $dir == "up" } { return [lindex $val 1] }
return [lindex $val 0]
}
proc getLinkBERString { link } {
set ber [getLinkBER $link]
set berup [getLinkBER $link up]
if { $ber == "" && $berup == "" } { return "" }
set berstr "loss="
if { $ber != "" } {
set berstr "$berstr$ber%"
}
if { $berup != "" } {
set berstr "$berstr / $berup%"
}
return $berstr
}
#****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 { [llength $value] > 1 && [lindex $value 0] <= 0 && \
[lindex $value 1] <= 0 } {
set $link [lreplace [set $link] $i $i]
} elseif { $value <= 0 } {
set $link [lreplace [set $link] $i $i]
} else {
if { [llength $value] > 1 } { set value "{$value}" }
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 {dir "down"} } {
global $link
set entry [lsearch -inline [set $link] "duplicate *"]
set val [lindex $entry 1] ;# one or more values
if { $dir == "up" } { return [lindex $val 1] }
return [lindex $val 0]
}
proc getLinkDupString { link } {
set dup [getLinkDup $link]
set dupup [getLinkDup $link up]
if { $dup == "" && $dupup == "" } { return "" }
set dupstr "dup="
if { $dup != "" } {
set dupstr "$dupstr$dup%"
}
if { $dupup != "" } {
set dupstr "$dupstr / $dupup%"
}
return $dupstr
}
#****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 { [checkEmptyZeroValues $value] } {
set $link [lreplace [set $link] $i $i]
} else {
if { [llength $value] > 1 } { set value "{$value}" }
set $link [lreplace [set $link] $i $i "duplicate $value"]
}
}
# Returns true if link has unidirectional link effects, where
# upstream values may differ from downstream.
proc isLinkUni { link } {
set bw [getLinkBandwidth $link up]
set dl [getLinkDelay $link up]
set jt [getLinkJitter $link up]
set ber [getLinkBER $link up]
set dup [getLinkDup $link up]
if { $bw > 0 || $dl > 0 || $jt > 0 || $ber > 0 || $dup > 0 } {
return true
} else {
return false
}
}
#****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 "error: 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 != ""} {
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]
}
proc getLinkJitter { link {dir "down"} } {
global $link
set entry [lsearch -inline [set $link] "jitter *"]
set val [lindex $entry 1] ;# one or more values
if { $dir == "up" } { return [lindex $val 1] }
return [lindex $val 0]
}
proc setLinkJitter { link value } {
global $link
set i [lsearch [set $link] "jitter *"]
if { [llength $value] <= 1 && $value <= 0 } {
set $link [lreplace [set $link] $i $i]
} elseif { [llength $value] > 1 && [lindex $value 0] <= 0 && \
[lindex $value 1] <= 0 } {
set $link [lreplace [set $link] $i $i]
} else {
if { [llength $value] > 1 } { set value "{$value}" }
set $link [lreplace [set $link] $i $i "jitter $value"]
}
}
# Check for empty or zero values in value.
# Value may be a single value or list where the first two values will be
# inspected; returns true for empty or zero values, false otherwise.
proc checkEmptyZeroValues { value } {
set isempty true
foreach v $value {
if { $v == "" } { continue } ;# this catches common case "{} {}"
if { $v > 0 } { set isempty false }
}
return $isempty
}
# 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
}