daemon support for unidirectional link effects

also enable link effects between hub/switch and hub/switch connections
(Boeing r1798)
This commit is contained in:
ahrenholz 2013-12-02 21:20:52 +00:00
parent f01ddd7c16
commit 6547b898c3
4 changed files with 147 additions and 48 deletions

View file

@ -299,6 +299,33 @@ class PyCoreNet(PyCoreObj):
with self._linked_lock: with self._linked_lock:
del self._linked[netif] del self._linked[netif]
def netifparamstolink(self, netif):
''' Helper for tolinkmsgs() to build TLVs having link parameters
from interface parameters.
'''
tlvdata = ""
delay = netif.getparam('delay')
bw = netif.getparam('bw')
loss = netif.getparam('loss')
duplicate = netif.getparam('duplicate')
jitter = netif.getparam('jitter')
if delay is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DELAY,
delay)
if bw is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_BW, bw)
if loss is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_PER,
str(loss))
if duplicate is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DUP,
str(duplicate))
if jitter is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_JITTER,
jitter)
return tlvdata
def tolinkmsgs(self, flags): def tolinkmsgs(self, flags):
''' Build CORE API Link Messages for this network. Each link message ''' Build CORE API Link Messages for this network. Each link message
describes a link between this network and a node. describes a link between this network and a node.
@ -323,26 +350,7 @@ class PyCoreNet(PyCoreObj):
self.objid) self.objid)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER,
otherobj.objid) otherobj.objid)
delay = netif.getparam('delay') tlvdata += self.netifparamstolink(netif)
bw = netif.getparam('bw')
loss = netif.getparam('loss')
duplicate = netif.getparam('duplicate')
jitter = netif.getparam('jitter')
if delay is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DELAY,
delay)
if bw is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_BW,
bw)
if loss is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_PER,
str(loss))
if duplicate is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DUP,
str(duplicate))
if jitter is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_JITTER,
jitter)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE, tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE,
self.linktype) self.linktype)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM, tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM,
@ -440,6 +448,17 @@ class PyCoreNetIf(object):
return False return False
self._params[key] = value self._params[key] = value
return True return True
def swapparams(self, name):
''' Swap out the _params dict for name. If name does not exist,
intialize it. This is for supporting separate upstream/downstream
parameters when two layer-2 nodes are linked together.
'''
tmp = self._params
if not hasattr(self, name):
setattr(self, name, {})
self._params = getattr(self, name)
setattr(self, name, tmp)
def setposition(self, x, y, z): def setposition(self, x, y, z):
''' Dispatch to any position hook (self.poshook) handler. ''' Dispatch to any position hook (self.poshook) handler.

View file

@ -96,27 +96,14 @@ class PtpNet(LxBrNet):
if1.node.objid) if1.node.objid)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER,
if2.node.objid) if2.node.objid)
delay = if1.getparam('delay') uni = False
bw = if1.getparam('bw') if if1.getparams() != if2.getparams():
loss = if1.getparam('loss') uni = True
duplicate = if1.getparam('duplicate') tlvdata += self.netifparamstolink(if1)
jitter = if1.getparam('jitter')
if delay is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DELAY,
delay)
if bw is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_BW, bw)
if loss is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_PER,
str(loss))
if duplicate is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DUP,
str(duplicate))
if jitter is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_JITTER,
jitter)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE, tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE,
self.linktype) self.linktype)
if uni:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_UNI, 1)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1NUM, \ tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1NUM, \
if1.node.getifindex(if1)) if1.node.getifindex(if1))
@ -154,7 +141,23 @@ class PtpNet(LxBrNet):
IPAddr(af=family, addr=ipl)) IPAddr(af=family, addr=ipl))
tlvdata += coreapi.CoreLinkTlv.pack(tlvtypemask, mask) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypemask, mask)
msg = coreapi.CoreLinkMessage.pack(flags, tlvdata) msg = coreapi.CoreLinkMessage.pack(flags, tlvdata)
return [msg,] if not uni:
return [msg,]
# build a 2nd link message for the upstream link parameters
# (swap if1 and if2)
tlvdata = ""
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER,
if2.node.objid)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER,
if1.node.objid)
tlvdata += self.netifparamstolink(if2)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_UNI, 1)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1NUM, \
if2.node.getifindex(if2))
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM, \
if1.node.getifindex(if1))
msg2 = coreapi.CoreLinkMessage.pack(0, tlvdata)
return [msg, msg2]
class SwitchNode(LxBrNet): class SwitchNode(LxBrNet):
apitype = coreapi.CORE_NODE_SWITCH apitype = coreapi.CORE_NODE_SWITCH

View file

@ -328,11 +328,14 @@ class LxBrNet(PyCoreNet):
ebq.ebchange(self) ebq.ebchange(self)
def linkconfig(self, netif, bw = None, delay = None, def linkconfig(self, netif, bw = None, delay = None,
loss = None, duplicate = None, jitter = None, netif2 = None): loss = None, duplicate = None, jitter = None, netif2 = None,
devname = None):
''' Configure link parameters by applying tc queuing disciplines on the ''' Configure link parameters by applying tc queuing disciplines on the
interface. interface.
''' '''
tc = [TC_BIN, "qdisc", "replace", "dev", netif.localname] if devname is None:
devname = netif.localname
tc = [TC_BIN, "qdisc", "replace", "dev", devname]
parent = ["root"] parent = ["root"]
changed = False changed = False
if netif.setparam('bw', bw): if netif.setparam('bw', bw):
@ -344,6 +347,9 @@ class LxBrNet(PyCoreNet):
"burst", str(burst), "limit", str(limit)] "burst", str(burst), "limit", str(limit)]
if bw > 0: if bw > 0:
if self.up: if self.up:
if (self.verbose):
self.info("linkconfig: %s" % \
([tc + parent + ["handle", "1:"] + tbf],))
check_call(tc + parent + ["handle", "1:"] + tbf) check_call(tc + parent + ["handle", "1:"] + tbf)
netif.setparam('has_tbf', True) netif.setparam('has_tbf', True)
changed = True changed = True
@ -382,16 +388,22 @@ class LxBrNet(PyCoreNet):
netem += ["loss", "%s%%" % min(loss, 100)] netem += ["loss", "%s%%" % min(loss, 100)]
if duplicate is not None: if duplicate is not None:
netem += ["duplicate", "%s%%" % min(duplicate, 100)] netem += ["duplicate", "%s%%" % min(duplicate, 100)]
if delay <= 0 and loss <= 0 and duplicate <= 0: if delay <= 0 and jitter <= 0 and loss <= 0 and duplicate <= 0:
# possibly remove netem if it exists and parent queue wasn't removed # possibly remove netem if it exists and parent queue wasn't removed
if not netif.getparam('has_netem'): if not netif.getparam('has_netem'):
return return
tc[2] = "delete" tc[2] = "delete"
if self.up: if self.up:
if self.verbose:
self.info("linkconfig: %s" % \
([tc + parent + ["handle", "10:"]],))
check_call(tc + parent + ["handle", "10:"]) check_call(tc + parent + ["handle", "10:"])
netif.setparam('has_netem', False) netif.setparam('has_netem', False)
elif len(netem) > 1: elif len(netem) > 1:
if self.up: if self.up:
if self.verbose:
self.info("linkconfig: %s" % \
([tc + parent + ["handle", "10:"] + netem],))
check_call(tc + parent + ["handle", "10:"] + netem) check_call(tc + parent + ["handle", "10:"] + netem)
netif.setparam('has_netem', True) netif.setparam('has_netem', True)
@ -416,6 +428,16 @@ class LxBrNet(PyCoreNet):
net._linked[netif] = {} net._linked[netif] = {}
netif.net = self netif.net = self
netif.othernet = net netif.othernet = net
return netif
def getlinknetif(self, net):
''' Return the interface of that links this net with another net
(that were linked using linknet()).
'''
for netif in self.netifs():
if hasattr(netif, 'othernet') and netif.othernet == net:
return netif
return None
def addrconfig(self, addrlist): def addrconfig(self, addrlist):
''' Set addresses on the bridge. ''' Set addresses on the bridge.

View file

@ -510,6 +510,13 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler):
node2 = None node2 = None
net = None net = None
net2 = None net2 = None
uni = msg.gettlv(coreapi.CORE_TLV_LINK_UNI)
if uni is not None and uni == 1:
unidirectional = True
else:
unidirectional = False
# one of the nodes may exist on a remote server # one of the nodes may exist on a remote server
if nodenum1 is not None and nodenum2 is not None: if nodenum1 is not None and nodenum2 is not None:
@ -657,7 +664,8 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler):
netaddrlist.append("%s/%s" % (ipv61, ipv6mask1)) netaddrlist.append("%s/%s" % (ipv61, ipv6mask1))
ifindex2 = node2.newnetif(net, addrlist = addrlist, ifindex2 = node2.newnetif(net, addrlist = addrlist,
hwaddr = mac2, ifindex = ifindex2) hwaddr = mac2, ifindex = ifindex2)
net.linkconfig(node2.netif(ifindex2, net), bw = bw, if not unidirectional:
net.linkconfig(node2.netif(ifindex2, net), bw = bw,
delay = delay, loss = loss, delay = delay, loss = loss,
duplicate = duplicate, jitter = jitter) duplicate = duplicate, jitter = jitter)
if node2 is None and net2: if node2 is None and net2:
@ -679,9 +687,19 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler):
if net and net2: if net and net2:
# two layer-2 networks linked together # two layer-2 networks linked together
if isinstance(net2, pycore.nodes.RJ45Node): if isinstance(net2, pycore.nodes.RJ45Node):
net2.linknet(net) # RJ45 nodes have different linknet() netif = net2.linknet(net) # RJ45 nodes have different linknet()
else: else:
net.linknet(net2) netif = net.linknet(net2)
net.linkconfig(netif, bw = bw, delay = delay, loss = loss,
duplicate = duplicate, jitter = jitter)
if not unidirectional:
netif.swapparams('_params_up')
net2.linkconfig(netif, bw = bw, delay = delay, loss = loss,
duplicate = duplicate, jitter = jitter,
devname = netif.name)
netif.swapparams('_params_up')
elif net is None and net2 is None and \ elif net is None and net2 is None and \
(node1 is None or node2 is None): (node1 is None or node2 is None):
# apply address/parameters to PhysicalNodes # apply address/parameters to PhysicalNodes
@ -742,8 +760,44 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler):
duplicate = msg.gettlv(coreapi.CORE_TLV_LINK_DUP) duplicate = msg.gettlv(coreapi.CORE_TLV_LINK_DUP)
jitter = msg.gettlv(coreapi.CORE_TLV_LINK_JITTER) jitter = msg.gettlv(coreapi.CORE_TLV_LINK_JITTER)
numnet = 0 numnet = 0
# TODO: clean up all this logic. Having the add flag or not
# should use the same code block.
if node1 is None and node2 is None: if node1 is None and node2 is None:
raise ValueError, "modify link for unknown nodes" if net and net2:
# modify link between nets
netif = net.getlinknetif(net2)
upstream = False
if netif is None:
upstream = True
netif = net2.getlinknetif(net)
if netif is None:
raise ValueError, "modify unknown link between nets"
if upstream:
netif.swapparams('_params_up')
net.linkconfig(netif, bw = bw, delay = delay,
loss = loss, duplicate = duplicate,
jitter = jitter, devname = netif.name)
netif.swapparams('_params_up')
else:
net.linkconfig(netif, bw = bw, delay = delay,
loss = loss, duplicate = duplicate,
jitter = jitter)
if not unidirectional:
if upstream:
net2.linkconfig(netif, bw = bw, delay = delay,
loss = loss,
duplicate = duplicate,
jitter = jitter)
else:
netif.swapparams('_params_up')
net2.linkconfig(netif, bw = bw, delay = delay,
loss = loss,
duplicate = duplicate,
jitter = jitter,
devname = netif.name)
netif.swapparams('_params_up')
else:
raise ValueError, "modify link for unknown nodes"
elif node1 is None: elif node1 is None:
# node1 = layer 2node, node2 = layer3 node # node1 = layer 2node, node2 = layer3 node
net.linkconfig(node2.netif(ifindex2, net), bw = bw, net.linkconfig(node2.netif(ifindex2, net), bw = bw,
@ -763,7 +817,8 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler):
net.linkconfig(netif1, bw = bw, delay = delay, net.linkconfig(netif1, bw = bw, delay = delay,
loss = loss, duplicate = duplicate, loss = loss, duplicate = duplicate,
jitter = jitter, netif2 = netif2) jitter = jitter, netif2 = netif2)
net.linkconfig(netif2, bw = bw, delay = delay, if not unidirectional:
net.linkconfig(netif2, bw = bw, delay = delay,
loss = loss, duplicate = duplicate, loss = loss, duplicate = duplicate,
jitter = jitter, netif2 = netif1) jitter = jitter, netif2 = netif1)
numnet += 1 numnet += 1