summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYAMAMOTO Takashi <yamamoto@valinux.co.jp>2013-10-22 14:27:25 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2013-10-23 12:04:26 +0900
commit61b89177112d4894aff16d69c20dc398e4e89eec (patch)
tree1c0ac8433248cec9e52f72bee93fcb0236ebbe01
parent3ff6202ad3cccb63d7b61904fdedbf6a70e8ef56 (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.py123
-rw-r--r--ryu/tests/unit/packet/test_bgp.py25
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,