From 999d8d72204c87682b6cf615df57e42b66a4b157 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Wed, 22 Jan 2014 13:06:36 +0900 Subject: [PATCH] bgp: fix IP/MPLS_VPN addresses i misunderstood that RDs were in-core. actually they are on-wire. Signed-off-by: YAMAMOTO Takashi Signed-off-by: FUJITA Tomonori --- ryu/lib/packet/bgp.py | 91 ++++++++++++++++++++++++------- ryu/tests/unit/packet/test_bgp.py | 16 ++++-- 2 files changed, 82 insertions(+), 25 deletions(-) diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py index ffd332ab..6c1d6ad7 100644 --- a/ryu/lib/packet/bgp.py +++ b/ryu/lib/packet/bgp.py @@ -141,8 +141,16 @@ class _AddrPrefix(StringifyMixin): __metaclass__ = abc.ABCMeta _PACK_STR = '!B' # length - def __init__(self, length, addr): + def __init__(self, length, addr, prefixes=None): + # length is on-wire bit length of prefixes+addr. + assert prefixes != () + if isinstance(addr, tuple): + # for _AddrPrefix.parser + # also for _VPNAddrPrefix.__init__ etc + (addr,) = addr self.length = length + if prefixes: + addr = prefixes + (addr,) self.addr = addr @staticmethod @@ -196,19 +204,22 @@ class _BinAddrPrefix(_AddrPrefix): class _LabelledAddrPrefix(_AddrPrefix): _LABEL_PACK_STR = '!3B' - def __init__(self, length, addr, labels=[]): + def __init__(self, length, addr, labels=[], **kwargs): assert isinstance(labels, list) - if isinstance(addr, tuple): + is_tuple = isinstance(addr, tuple) + if is_tuple: + # for _AddrPrefix.parser assert not labels - our_addr = addr - our_length = length + labels = addr[0] + addr = addr[1:] else: - label_length = struct.calcsize(self._LABEL_PACK_STR) * 8 * \ - len(labels) - our_length = label_length + length - our_addr = (labels, addr) - super(_LabelledAddrPrefix, self).__init__(length=our_length, - addr=our_addr) + length += struct.calcsize(self._LABEL_PACK_STR) * 8 * len(labels) + assert length > struct.calcsize(self._LABEL_PACK_STR) * 8 * len(labels) + prefixes = (labels,) + super(_LabelledAddrPrefix, self).__init__(prefixes=prefixes, + length=length, + addr=addr, + **kwargs) @classmethod def _label_to_bin(cls, label): @@ -227,33 +238,36 @@ class _LabelledAddrPrefix(_AddrPrefix): @classmethod def _to_bin(cls, addr): - (labels, prefix) = addr + labels = addr[0] + rest = addr[1:] labels = map(lambda x: x << 4, labels) if labels: labels[-1] |= 1 # bottom of stack bin_labels = map(cls._label_to_bin, labels) return bytes(reduce(lambda x, y: x + y, bin_labels, - bytearray()) + cls._prefix_to_bin(prefix)) + bytearray()) + cls._prefix_to_bin(rest)) @classmethod def _from_bin(cls, addr): + rest = addr labels = [] while True: - (label, addr) = cls._label_from_bin(addr) + (label, rest) = cls._label_from_bin(rest) labels.append(label >> 4) if label & 1: # bottom of stack break - return (labels, cls._prefix_from_bin(addr)) + return (labels,) + cls._prefix_from_bin(rest) class _UnlabelledAddrPrefix(_AddrPrefix): @classmethod def _to_bin(cls, addr): - return cls._prefix_to_bin(addr) + return cls._prefix_to_bin((addr,)) @classmethod - def _from_bin(cls, addr): - return cls._prefix_from_bin(addr) + def _from_bin(cls, binaddr): + (addr,) = cls._prefix_from_bin(binaddr) + return addr class _IPAddrPrefix(_AddrPrefix): @@ -265,14 +279,49 @@ class _IPAddrPrefix(_AddrPrefix): @staticmethod def _prefix_to_bin(addr): + (addr,) = addr return addrconv.ipv4.text_to_bin(addr) @staticmethod def _prefix_from_bin(addr): - return addrconv.ipv4.bin_to_text(pad(addr, 4)) + return (addrconv.ipv4.bin_to_text(pad(addr, 4)),) -class LabelledIPAddrPrefix(_LabelledAddrPrefix, _IPAddrPrefix): +class _VPNAddrPrefix(_AddrPrefix): + _RD_PACK_STR = '!Q' + + def __init__(self, length, addr, prefixes=(), route_dist=0): + if isinstance(addr, tuple): + # for _AddrPrefix.parser + assert not route_dist + assert length > struct.calcsize(self._RD_PACK_STR) * 8 + route_dist = addr[0] + addr = addr[1:] + else: + length += struct.calcsize(self._RD_PACK_STR) * 8 + prefixes = prefixes + (route_dist,) + super(_VPNAddrPrefix, self).__init__(prefixes=prefixes, + length=length, + addr=addr) + + @classmethod + def _prefix_to_bin(cls, addr): + rd = addr[0] + rest = addr[1:] + binrd = bytearray() + msg_pack_into(cls._RD_PACK_STR, binrd, 0, rd) + return binrd + super(_VPNAddrPrefix, cls)._prefix_to_bin(rest) + + @classmethod + def _prefix_from_bin(cls, binaddr): + binrd = binaddr[:8] + binrest = binaddr[8:] + (rd,) = struct.unpack_from(cls._RD_PACK_STR, buffer(binrd)) + return (rd,) + super(_VPNAddrPrefix, cls)._prefix_from_bin(binrest) + + +class LabelledVPNIPAddrPrefix(_LabelledAddrPrefix, _VPNAddrPrefix, + _IPAddrPrefix): pass @@ -282,7 +331,7 @@ class IPAddrPrefix(_UnlabelledAddrPrefix, _IPAddrPrefix): _ADDR_CLASSES = { (afi.IP, safi.UNICAST): IPAddrPrefix, - (afi.IP, safi.MPLS_VPN): LabelledIPAddrPrefix, + (afi.IP, safi.MPLS_VPN): LabelledVPNIPAddrPrefix, } diff --git a/ryu/tests/unit/packet/test_bgp.py b/ryu/tests/unit/packet/test_bgp.py index deebb9ab..6764da4f 100644 --- a/ryu/tests/unit/packet/test_bgp.py +++ b/ryu/tests/unit/packet/test_bgp.py @@ -79,8 +79,12 @@ class Test_bgp(unittest.TestCase): bgp.BGPWithdrawnRoute(length=32, addr='192.0.2.13')] mp_nlri = [ - bgp.LabelledIPAddrPrefix(24, '192.0.9.0', labels=[1, 2, 3]), - bgp.LabelledIPAddrPrefix(26, '192.0.10.192', labels=[5, 6, 7, 8]), + bgp.LabelledVPNIPAddrPrefix(24, '192.0.9.0', + route_dist=100, + labels=[1, 2, 3]), + bgp.LabelledVPNIPAddrPrefix(26, '192.0.10.192', + route_dist=4000000000, + labels=[5, 6, 7, 8]), ] communities = [ bgp.BGP_COMMUNITY_NO_EXPORT, @@ -224,8 +228,12 @@ class Test_bgp(unittest.TestCase): bgp.BGPWithdrawnRoute(length=32, addr='192.0.2.13')] mp_nlri = [ - bgp.LabelledIPAddrPrefix(24, '192.0.9.0', labels=[1, 2, 3]), - bgp.LabelledIPAddrPrefix(26, '192.0.10.192', labels=[5, 6, 7, 8]), + bgp.LabelledVPNIPAddrPrefix(24, '192.0.9.0', + route_dist=100, + labels=[1, 2, 3]), + bgp.LabelledVPNIPAddrPrefix(26, '192.0.10.192', + route_dist=4000000000, + labels=[5, 6, 7, 8]), ] communities = [ bgp.BGP_COMMUNITY_NO_EXPORT,