From 38790febe8e2678b2b204e1b4d075c2d5c553bc0 Mon Sep 17 00:00:00 2001 From: "ahrenholz@gmail.com" Date: Mon, 2 Dec 2013 21:20:52 +0000 Subject: [PATCH] daemon support for unidirectional link effects also enable link effects between hub/switch and hub/switch connections (Boeing r1798) --- trunk/daemon/core/coreobj.py | 59 +++++++++++++++++++---------- trunk/daemon/core/netns/nodes.py | 43 +++++++++++---------- trunk/daemon/core/netns/vnet.py | 28 ++++++++++++-- trunk/daemon/sbin/core-daemon | 65 +++++++++++++++++++++++++++++--- 4 files changed, 147 insertions(+), 48 deletions(-) diff --git a/trunk/daemon/core/coreobj.py b/trunk/daemon/core/coreobj.py index df3e36a1..904a5309 100644 --- a/trunk/daemon/core/coreobj.py +++ b/trunk/daemon/core/coreobj.py @@ -299,6 +299,33 @@ class PyCoreNet(PyCoreObj): with self._linked_lock: 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): ''' Build CORE API Link Messages for this network. Each link message describes a link between this network and a node. @@ -323,26 +350,7 @@ class PyCoreNet(PyCoreObj): self.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, otherobj.objid) - 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) + tlvdata += self.netifparamstolink(netif) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE, self.linktype) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM, @@ -440,6 +448,17 @@ class PyCoreNetIf(object): return False self._params[key] = value 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): ''' Dispatch to any position hook (self.poshook) handler. diff --git a/trunk/daemon/core/netns/nodes.py b/trunk/daemon/core/netns/nodes.py index a644fc06..942fb419 100644 --- a/trunk/daemon/core/netns/nodes.py +++ b/trunk/daemon/core/netns/nodes.py @@ -96,27 +96,14 @@ class PtpNet(LxBrNet): if1.node.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, if2.node.objid) - delay = if1.getparam('delay') - bw = if1.getparam('bw') - loss = if1.getparam('loss') - duplicate = if1.getparam('duplicate') - 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) + uni = False + if if1.getparams() != if2.getparams(): + uni = True + tlvdata += self.netifparamstolink(if1) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE, self.linktype) + if uni: + tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_UNI, 1) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1NUM, \ if1.node.getifindex(if1)) @@ -154,7 +141,23 @@ class PtpNet(LxBrNet): IPAddr(af=family, addr=ipl)) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypemask, mask) 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): apitype = coreapi.CORE_NODE_SWITCH diff --git a/trunk/daemon/core/netns/vnet.py b/trunk/daemon/core/netns/vnet.py index ca6560b1..7edde1b6 100644 --- a/trunk/daemon/core/netns/vnet.py +++ b/trunk/daemon/core/netns/vnet.py @@ -328,11 +328,14 @@ class LxBrNet(PyCoreNet): ebq.ebchange(self) 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 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"] changed = False if netif.setparam('bw', bw): @@ -344,6 +347,9 @@ class LxBrNet(PyCoreNet): "burst", str(burst), "limit", str(limit)] if bw > 0: if self.up: + if (self.verbose): + self.info("linkconfig: %s" % \ + ([tc + parent + ["handle", "1:"] + tbf],)) check_call(tc + parent + ["handle", "1:"] + tbf) netif.setparam('has_tbf', True) changed = True @@ -382,16 +388,22 @@ class LxBrNet(PyCoreNet): netem += ["loss", "%s%%" % min(loss, 100)] if duplicate is not None: 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 if not netif.getparam('has_netem'): return tc[2] = "delete" if self.up: + if self.verbose: + self.info("linkconfig: %s" % \ + ([tc + parent + ["handle", "10:"]],)) check_call(tc + parent + ["handle", "10:"]) netif.setparam('has_netem', False) elif len(netem) > 1: if self.up: + if self.verbose: + self.info("linkconfig: %s" % \ + ([tc + parent + ["handle", "10:"] + netem],)) check_call(tc + parent + ["handle", "10:"] + netem) netif.setparam('has_netem', True) @@ -416,6 +428,16 @@ class LxBrNet(PyCoreNet): net._linked[netif] = {} netif.net = self 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): ''' Set addresses on the bridge. diff --git a/trunk/daemon/sbin/core-daemon b/trunk/daemon/sbin/core-daemon index 10b457b0..25128ccf 100755 --- a/trunk/daemon/sbin/core-daemon +++ b/trunk/daemon/sbin/core-daemon @@ -510,6 +510,13 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler): node2 = None net = 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 if nodenum1 is not None and nodenum2 is not None: @@ -657,7 +664,8 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler): netaddrlist.append("%s/%s" % (ipv61, ipv6mask1)) ifindex2 = node2.newnetif(net, addrlist = addrlist, 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, duplicate = duplicate, jitter = jitter) if node2 is None and net2: @@ -679,9 +687,19 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler): if net and net2: # two layer-2 networks linked together if isinstance(net2, pycore.nodes.RJ45Node): - net2.linknet(net) # RJ45 nodes have different linknet() + netif = net2.linknet(net) # RJ45 nodes have different linknet() 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 \ (node1 is None or node2 is None): # apply address/parameters to PhysicalNodes @@ -742,8 +760,44 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler): duplicate = msg.gettlv(coreapi.CORE_TLV_LINK_DUP) jitter = msg.gettlv(coreapi.CORE_TLV_LINK_JITTER) 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: - 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: # node1 = layer 2node, node2 = layer3 node net.linkconfig(node2.netif(ifindex2, net), bw = bw, @@ -763,7 +817,8 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler): net.linkconfig(netif1, bw = bw, delay = delay, loss = loss, duplicate = duplicate, 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, jitter = jitter, netif2 = netif1) numnet += 1