summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYAMAMOTO Takashi <yamamoto@valinux.co.jp>2014-01-15 12:01:17 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2014-01-15 19:54:58 +0900
commitdd70570eab84746978e370a2a8ee96ce79c29f23 (patch)
tree1def775519da752354083e50e3f74e39b0523b62
parent4209fc01709a829927ba9a863870aa1276a9d2ee (diff)
bgp: implement the rest of RFC 3107
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.py120
-rw-r--r--ryu/tests/unit/packet/test_bgp.py8
2 files changed, 111 insertions, 17 deletions
diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py
index 1f8d539b..80217dd5 100644
--- a/ryu/lib/packet/bgp.py
+++ b/ryu/lib/packet/bgp.py
@@ -21,7 +21,6 @@ RFC 4271 BGP-4
# todo
# - notify data
# - notify subcode constants
-# - RFC 3107 Carrying Label Information in BGP-4
# - RFC 4364 BGP/MPLS IP Virtual Private Networks (VPNs)
# - RFC 4486 Subcodes for BGP Cease Notification Message
@@ -34,6 +33,9 @@ from ryu.lib.packet import packet_base
from ryu.lib.packet import stream_parser
from ryu.lib import addrconv
+import safi
+import afi
+
BGP_MSG_OPEN = 1
BGP_MSG_UPDATE = 2
@@ -108,19 +110,19 @@ class _AddrPrefix(StringifyMixin):
@staticmethod
@abc.abstractmethod
def _to_bin(addr):
- return addr
+ pass
@staticmethod
@abc.abstractmethod
- def _to_text(addr):
- return addr
+ def _from_bin(addr):
+ pass
@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
- addr = cls._to_text(rest[:byte_length])
+ addr = cls._from_bin(rest[:byte_length])
rest = rest[byte_length:]
return cls(length=length, addr=addr), rest
@@ -136,7 +138,7 @@ class _AddrPrefix(StringifyMixin):
mask = 0xff00 >> (self.length % 8)
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)
+ self.addr = self._from_bin(bin_addr)
buf = bytearray()
msg_pack_into(self._PACK_STR, buf, 0, self.length)
@@ -149,10 +151,73 @@ class _BinAddrPrefix(_AddrPrefix):
return addr
@staticmethod
- def _to_text(addr):
+ def _from_bin(addr):
return addr
+class _LabelledAddrPrefix(_AddrPrefix):
+ _LABEL_PACK_STR = '!3B'
+
+ def __init__(self, length, addr, labels=[]):
+ assert isinstance(labels, list)
+ if isinstance(addr, tuple):
+ assert not labels
+ our_addr = addr
+ our_length = length
+ 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)
+
+ @classmethod
+ def _label_to_bin(cls, label):
+ buf = bytearray()
+ msg_pack_into(cls._LABEL_PACK_STR, buf, 0,
+ (label & 0xff0000) >> 16,
+ (label & 0x00ff00) >> 8,
+ (label & 0x0000ff) >> 0)
+ return buf
+
+ @classmethod
+ def _label_from_bin(cls, bin):
+ (b1, b2, b3) = struct.unpack_from(cls._LABEL_PACK_STR, buffer(bin))
+ rest = bin[struct.calcsize(cls._LABEL_PACK_STR):]
+ return (b1 << 16) | (b2 << 8) | b3, rest
+
+ @classmethod
+ def _to_bin(cls, addr):
+ (labels, prefix) = addr
+ 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))
+
+ @classmethod
+ def _from_bin(cls, addr):
+ labels = []
+ while True:
+ (label, addr) = cls._label_from_bin(addr)
+ labels.append(label >> 4)
+ if label & 1: # bottom of stack
+ break
+ return (labels, cls._prefix_from_bin(addr))
+
+
+class _UnlabelledAddrPrefix(_AddrPrefix):
+ @classmethod
+ def _to_bin(cls, addr):
+ return cls._prefix_to_bin(addr)
+
+ @classmethod
+ def _from_bin(cls, addr):
+ return cls._prefix_from_bin(addr)
+
+
class _IPAddrPrefix(_AddrPrefix):
_TYPE = {
'ascii': [
@@ -161,14 +226,35 @@ class _IPAddrPrefix(_AddrPrefix):
}
@staticmethod
- def _to_bin(addr):
+ def _prefix_to_bin(addr):
return addrconv.ipv4.text_to_bin(addr)
@staticmethod
- def _to_text(addr):
+ def _prefix_from_bin(addr):
return addrconv.ipv4.bin_to_text(pad(addr, 4))
+class LabelledIPAddrPrefix(_LabelledAddrPrefix, _IPAddrPrefix):
+ pass
+
+
+class IPAddrPrefix(_UnlabelledAddrPrefix, _IPAddrPrefix):
+ pass
+
+
+_ADDR_CLASSES = {
+ (afi.IP, safi.UNICAST): IPAddrPrefix,
+ (afi.IP, safi.MPLS_VPN): LabelledIPAddrPrefix,
+}
+
+
+def _get_addr_class(afi, safi):
+ try:
+ return _ADDR_CLASSES[(afi, safi)]
+ except KeyError:
+ return _BinAddrPrefix
+
+
class _Value(object):
_VALUE_PACK_STR = None
_VALUE_FIELDS = ['value']
@@ -396,7 +482,7 @@ class BGPOptParamCapabilityCarryingLabelInfo(_OptParamEmptyCapability):
pass
-class BGPWithdrawnRoute(_IPAddrPrefix):
+class BGPWithdrawnRoute(IPAddrPrefix):
pass
@@ -847,6 +933,9 @@ class BGPPathAttributeMpReachNLRI(_PathAttribute):
self.next_hop = next_hop
self.reserved = reserved
self.nlri = nlri
+ addr_cls = _get_addr_class(afi, safi)
+ for i in nlri:
+ assert isinstance(i, addr_cls)
@classmethod
def parse_value(cls, buf):
@@ -857,9 +946,10 @@ class BGPPathAttributeMpReachNLRI(_PathAttribute):
rest = rest[next_hop_len:]
reserved = rest[:1]
binnlri = rest[1:]
+ addr_cls = _get_addr_class(afi, safi)
nlri = []
while binnlri:
- n, binnlri = _BinAddrPrefix.parser(binnlri)
+ n, binnlri = addr_cls.parser(binnlri)
nlri.append(n)
return {
'afi': afi,
@@ -901,14 +991,18 @@ class BGPPathAttributeMpUnreachNLRI(_PathAttribute):
self.afi = afi
self.safi = safi
self.withdrawn_routes = withdrawn_routes
+ addr_cls = _get_addr_class(afi, safi)
+ for i in withdrawn_routes:
+ assert isinstance(i, addr_cls)
@classmethod
def parse_value(cls, buf):
(afi, safi,) = struct.unpack_from(cls._VALUE_PACK_STR, buffer(buf))
binnlri = buf[struct.calcsize(cls._VALUE_PACK_STR):]
+ addr_cls = _get_addr_class(afi, safi)
nlri = []
while binnlri:
- n, binnlri = _BinAddrPrefix.parser(binnlri)
+ n, binnlri = addr_cls.parser(binnlri)
nlri.append(n)
return {
'afi': afi,
@@ -926,7 +1020,7 @@ class BGPPathAttributeMpUnreachNLRI(_PathAttribute):
return buf
-class BGPNLRI(_IPAddrPrefix):
+class BGPNLRI(IPAddrPrefix):
pass
diff --git a/ryu/tests/unit/packet/test_bgp.py b/ryu/tests/unit/packet/test_bgp.py
index 0f2975d1..deebb9ab 100644
--- a/ryu/tests/unit/packet/test_bgp.py
+++ b/ryu/tests/unit/packet/test_bgp.py
@@ -79,8 +79,8 @@ class Test_bgp(unittest.TestCase):
bgp.BGPWithdrawnRoute(length=32,
addr='192.0.2.13')]
mp_nlri = [
- bgp._BinAddrPrefix(32, 'efgh\0\0'),
- bgp._BinAddrPrefix(16, 'ij\0\0\0\0'),
+ bgp.LabelledIPAddrPrefix(24, '192.0.9.0', labels=[1, 2, 3]),
+ bgp.LabelledIPAddrPrefix(26, '192.0.10.192', labels=[5, 6, 7, 8]),
]
communities = [
bgp.BGP_COMMUNITY_NO_EXPORT,
@@ -224,8 +224,8 @@ class Test_bgp(unittest.TestCase):
bgp.BGPWithdrawnRoute(length=32,
addr='192.0.2.13')]
mp_nlri = [
- bgp._BinAddrPrefix(32, 'efgh\0\0'),
- bgp._BinAddrPrefix(16, 'ij\0\0\0\0'),
+ bgp.LabelledIPAddrPrefix(24, '192.0.9.0', labels=[1, 2, 3]),
+ bgp.LabelledIPAddrPrefix(26, '192.0.10.192', labels=[5, 6, 7, 8]),
]
communities = [
bgp.BGP_COMMUNITY_NO_EXPORT,