diff options
author | YAMAMOTO Takashi <yamamoto@valinux.co.jp> | 2013-10-22 14:27:25 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2013-10-23 12:04:26 +0900 |
commit | 61b89177112d4894aff16d69c20dc398e4e89eec (patch) | |
tree | 1c0ac8433248cec9e52f72bee93fcb0236ebbe01 | |
parent | 3ff6202ad3cccb63d7b61904fdedbf6a70e8ef56 (diff) |
bgp: implement MP_REACH_NLRI
Signed-off-by: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/lib/packet/bgp.py | 123 | ||||
-rw-r--r-- | ryu/tests/unit/packet/test_bgp.py | 25 |
2 files changed, 122 insertions, 26 deletions
diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py index 1ffd035c..eb3e2d13 100644 --- a/ryu/lib/packet/bgp.py +++ b/ryu/lib/packet/bgp.py @@ -28,6 +28,7 @@ RFC 4271 BGP-4 # - RFC 4486 Subcodes for BGP Cease Notification Message # - RFC 4760 Multiprotocol Extensions for BGP-4 +import abc import struct from ryu.ofproto.ofproto_parser import msg_pack_into @@ -85,39 +86,70 @@ def pad(bin, len_): return bin + (len_ - len(bin)) * '\0' -class _IPAddrPrefix(StringifyMixin): +class _AddrPrefix(StringifyMixin): + __metaclass__ = abc.ABCMeta _PACK_STR = '!B' # length - def __init__(self, length, ip_addr): + def __init__(self, length, addr): self.length = length - self.ip_addr = ip_addr + self.addr = addr + + @staticmethod + @abc.abstractmethod + def _to_bin(addr): + return addr + + @staticmethod + @abc.abstractmethod + def _to_text(addr): + return addr @classmethod def parser(cls, buf): (length, ) = struct.unpack_from(cls._PACK_STR, buffer(buf)) rest = buf[struct.calcsize(cls._PACK_STR):] byte_length = (length + 7) / 8 - ip_addr = addrconv.ipv4.bin_to_text(pad(rest[:byte_length], 4)) + addr = cls._to_text(rest[:byte_length]) rest = rest[byte_length:] - return cls(length=length, ip_addr=ip_addr), rest + return cls(length=length, addr=addr), rest def serialize(self): # fixup byte_length = (self.length + 7) / 8 - bin_ip_addr = addrconv.ipv4.text_to_bin(self.ip_addr) + bin_addr = self._to_bin(self.addr) if (self.length % 8) == 0: - bin_ip_addr = bin_ip_addr[:byte_length] + bin_addr = bin_addr[:byte_length] else: # clear trailing bits in the last octet. # rfc doesn't require this. mask = 0xff00 >> (self.length % 8) - last_byte = chr(ord(bin_ip_addr[byte_length - 1]) & mask) - bin_ip_addr = bin_ip_addr[:byte_length - 1] + last_byte - self.ip_addr = addrconv.ipv4.bin_to_text(pad(bin_ip_addr, 4)) + last_byte = chr(ord(bin_addr[byte_length - 1]) & mask) + bin_addr = bin_addr[:byte_length - 1] + last_byte + self.addr = self._to_text(bin_addr) buf = bytearray() msg_pack_into(self._PACK_STR, buf, 0, self.length) - return buf + bytes(bin_ip_addr) + return buf + bytes(bin_addr) + + +class _BinAddrPrefix(_AddrPrefix): + @staticmethod + def _to_bin(addr): + return addr + + @staticmethod + def _to_text(addr): + return addr + + +class _IPAddrPrefix(_AddrPrefix): + @staticmethod + def _to_bin(addr): + return addrconv.ipv4.text_to_bin(addr) + + @staticmethod + def _to_text(addr): + return addrconv.ipv4.bin_to_text(pad(addr, 4)) class _Value(object): @@ -484,26 +516,26 @@ class _BGPPathAttributeAggregatorCommon(_PathAttribute): _VALUE_PACK_STR = None _ATTR_FLAGS = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANSITIVE - def __init__(self, as_number, ip_addr, flags=0, type_=None, length=None): + def __init__(self, as_number, addr, flags=0, type_=None, length=None): super(_BGPPathAttributeAggregatorCommon, self).__init__(flags=flags, type_=type_, length=length) self.as_number = as_number - self.ip_addr = ip_addr + self.addr = addr @classmethod def parse_value(cls, buf): - (as_number, ip_addr) = struct.unpack_from(cls._VALUE_PACK_STR, - buffer(buf)) + (as_number, addr) = struct.unpack_from(cls._VALUE_PACK_STR, + buffer(buf)) return { 'as_number': as_number, - 'ip_addr': addrconv.ipv4.bin_to_text(ip_addr), + 'addr': addrconv.ipv4.bin_to_text(addr), } def serialize_value(self): buf = bytearray() msg_pack_into(self._VALUE_PACK_STR, buf, 0, self.as_number, - addrconv.ipv4.text_to_bin(self.ip_addr)) + addrconv.ipv4.text_to_bin(self.addr)) return buf @@ -518,6 +550,63 @@ class BGPPathAttributeAs4Aggregator(_BGPPathAttributeAggregatorCommon): _VALUE_PACK_STR = '!I4s' +@_PathAttribute.register_type(BGP_ATTR_TYPE_MP_REACH_NLRI) +class BGPPathAttributeMpReachNLRI(_PathAttribute): + _VALUE_PACK_STR = '!HBB' # afi, safi, next hop len + _ATTR_FLAGS = BGP_ATTR_FLAG_OPTIONAL + + def __init__(self, afi, safi, next_hop, nlri, + next_hop_len=0, reserved='\0', + flags=0, type_=None, length=None): + super(BGPPathAttributeMpReachNLRI, self).__init__(flags=flags, + type_=type_, + length=length) + self.afi = afi + self.safi = safi + self.next_hop_len = next_hop_len + self.next_hop = next_hop + self.reserved = reserved + self.nlri = nlri + + @classmethod + def parse_value(cls, buf): + (afi, safi, next_hop_len,) = struct.unpack_from(cls._VALUE_PACK_STR, + buffer(buf)) + rest = buf[struct.calcsize(cls._VALUE_PACK_STR):] + next_hop_bin = rest[:next_hop_len] + rest = rest[next_hop_len:] + reserved = rest[:1] + binnlri = rest[1:] + nlri = [] + while binnlri: + n, binnlri = _BinAddrPrefix.parser(binnlri) + nlri.append(n) + return { + 'afi': afi, + 'safi': safi, + 'next_hop_len': next_hop_len, + 'next_hop': next_hop_bin, + 'reserved': reserved, + 'nlri': nlri, + } + + def serialize_value(self): + # fixup + self.next_hop_len = len(self.next_hop) + self.reserved = '\0' + + buf = bytearray() + msg_pack_into(self._VALUE_PACK_STR, buf, 0, self.afi, + self.safi, self.next_hop_len) + buf += self.next_hop + buf += self.reserved + binnlri = bytearray() + for n in self.nlri: + binnlri += n.serialize() + buf += binnlri + return buf + + class BGPNLRI(_IPAddrPrefix): pass diff --git a/ryu/tests/unit/packet/test_bgp.py b/ryu/tests/unit/packet/test_bgp.py index 2e1da861..0dc7fb61 100644 --- a/ryu/tests/unit/packet/test_bgp.py +++ b/ryu/tests/unit/packet/test_bgp.py @@ -66,15 +66,19 @@ class Test_bgp(unittest.TestCase): def test_update2(self): withdrawn_routes = [bgp.BGPWithdrawnRoute(length=0, - ip_addr='192.0.2.13'), + addr='192.0.2.13'), bgp.BGPWithdrawnRoute(length=1, - ip_addr='192.0.2.13'), + addr='192.0.2.13'), bgp.BGPWithdrawnRoute(length=3, - ip_addr='192.0.2.13'), + addr='192.0.2.13'), bgp.BGPWithdrawnRoute(length=7, - ip_addr='192.0.2.13'), + addr='192.0.2.13'), bgp.BGPWithdrawnRoute(length=32, - ip_addr='192.0.2.13')] + addr='192.0.2.13')] + mp_nlri = [ + bgp._BinAddrPrefix(32, 'efgh\0\0'), + bgp._BinAddrPrefix(16, 'ij\0\0\0\0'), + ] path_attributes = [ bgp.BGPPathAttributeOrigin(value=1), bgp.BGPPathAttributeAsPath(value=[[1000], set([1001, 1002]), @@ -84,16 +88,19 @@ class Test_bgp(unittest.TestCase): bgp.BGPPathAttributeLocalPref(value=1000000000), bgp.BGPPathAttributeAtomicAggregate(), bgp.BGPPathAttributeAggregator(as_number=40000, - ip_addr='192.0.2.99'), + addr='192.0.2.99'), bgp.BGPPathAttributeAs4Path(value=[[1000000], set([1000001, 1002]), [1003, 1000004]]), bgp.BGPPathAttributeAs4Aggregator(as_number=100040000, - ip_addr='192.0.2.99'), + addr='192.0.2.99'), + bgp.BGPPathAttributeMpReachNLRI(afi=afi.IP, safi=safi.MPLS_VPN, + next_hop='abcd', + nlri=mp_nlri), bgp.BGPPathAttributeUnknown(flags=0, type_=100, value=300*'bar') ] nlri = [ - bgp.BGPNLRI(length=24, ip_addr='203.0.113.1'), - bgp.BGPNLRI(length=16, ip_addr='203.0.113.0') + bgp.BGPNLRI(length=24, addr='203.0.113.1'), + bgp.BGPNLRI(length=16, addr='203.0.113.0') ] msg = bgp.BGPUpdate(withdrawn_routes=withdrawn_routes, path_attributes=path_attributes, |