summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorShinpei Muraoka <shinpei.muraoka@gmail.com>2016-11-09 10:44:04 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2016-11-14 13:21:04 +0900
commit972c31f0e6f32ae40417a79001353328b965728f (patch)
tree38c6c39e8b0d14631b01ce5bba6f89a489bb31de
parent264d32ea2d1aa900daa7c554505e5e71be45b0fc (diff)
packet/bgp: Support for IP Prefix Route encoding
This patch supports on the basis of the [draft-ietf-bess-evpn-prefix-advertisement-03] Signed-off-by: Shinpei Muraoka <shinpei.muraoka@gmail.com> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--ryu/lib/packet/bgp.py138
-rw-r--r--ryu/tests/packet_data/bgp4/evpn_nlri_ip_prefix.pcapbin0 -> 190 bytes
-rw-r--r--ryu/tests/unit/packet/test_bgp.py1
3 files changed, 139 insertions, 0 deletions
diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py
index 6c527813..6f23b460 100644
--- a/ryu/lib/packet/bgp.py
+++ b/ryu/lib/packet/bgp.py
@@ -1306,6 +1306,7 @@ class EvpnNLRI(StringifyMixin, _TypeDisp):
MAC_IP_ADVERTISEMENT = 0x02
INCLUSIVE_MULTICAST_ETHERNET_TAG = 0x03
ETHERNET_SEGMENT = 0x04
+ IP_PREFIX_ROUTE = 0x05
ROUTE_TYPE_NAME = None # must be defined in subclass
@@ -1858,6 +1859,143 @@ class EvpnEthernetSegmentNLRI(EvpnNLRI):
self.ip_addr_len, ip_addr)
+@EvpnNLRI.register_type(EvpnNLRI.IP_PREFIX_ROUTE)
+class EvpnIpPrefixNLRI(EvpnNLRI):
+ """
+ IP Prefix advertisement route NLRI
+ """
+ ROUTE_TYPE_NAME = 'ip_prefix'
+
+ # +---------------------------------------+
+ # | RD (8 octets) |
+ # +---------------------------------------+
+ # |Ethernet Segment Identifier (10 octets)|
+ # +---------------------------------------+
+ # | Ethernet Tag ID (4 octets) |
+ # +---------------------------------------+
+ # | IP Prefix Length (1 octet) |
+ # +---------------------------------------+
+ # | IP Prefix (4 or 16 octets) |
+ # +---------------------------------------+
+ # | GW IP Address (4 or 16 octets) |
+ # +---------------------------------------+
+ # | MPLS Label (3 octets) |
+ # +---------------------------------------+
+ _PACK_STR = '!8s10sIB%ds%ds3s'
+ NLRI_PREFIX_FIELDS = ['ethernet_tag_id', 'ip_prefix']
+ _TYPE = {
+ 'ascii': [
+ 'route_dist',
+ 'ip_prefix',
+ 'gw_ip_addr'
+ ]
+ }
+ _LABEL_LEN = 3
+
+ def __init__(self, route_dist, ethernet_tag_id, ip_prefix,
+ esi=0, gw_ip_addr=None, mpls_label=None, vni=None, label=None,
+ type_=None, length=None):
+ super(EvpnIpPrefixNLRI, self).__init__(type_, length)
+ self.route_dist = route_dist
+ self.esi = esi
+ self.ethernet_tag_id = ethernet_tag_id
+ self._ip_prefix = None
+ self._ip_prefix_len = None
+ self.ip_prefix = ip_prefix
+
+ if gw_ip_addr is None:
+ if ':' not in self._ip_prefix:
+ self.gw_ip_addr = '0.0.0.0'
+ else:
+ self.gw_ip_addr = '::'
+ else:
+ self.gw_ip_addr = gw_ip_addr
+
+ if label:
+ # If binary type label field value is specified, stores it
+ # and decodes as MPLS label and VNI.
+ self._label = label
+ self._mpls_label, _, _ = self._mpls_label_from_bin(label)
+ self._vni, _ = self._vni_from_bin(label)
+ else:
+ # If either MPLS label or VNI is specified, stores it
+ # and encodes into binary type label field value.
+ self._label = self._serialize_label(mpls_label, vni)
+ self._mpls_label = mpls_label
+ self._vni = vni
+
+ def _serialize_label(self, mpls_label, vni):
+ if mpls_label:
+ return self._mpls_label_to_bin(mpls_label, is_bos=True)
+ elif vni:
+ return vxlan.vni_to_bin(vni)
+ else:
+ return b'\x00' * 3
+
+ @classmethod
+ def parse_value(cls, buf):
+ route_dist, rest = cls._rd_from_bin(buf)
+ esi, rest = cls._esi_from_bin(rest)
+ ethernet_tag_id, rest = cls._ethernet_tag_id_from_bin(rest)
+ ip_prefix_len, rest = cls._ip_addr_len_from_bin(rest)
+ _len = (len(rest) - cls._LABEL_LEN) // 2
+ ip_prefix, rest = cls._ip_addr_from_bin(rest, _len)
+ gw_ip_addr, rest = cls._ip_addr_from_bin(rest, _len)
+
+ return {
+ 'route_dist': route_dist.formatted_str,
+ 'esi': esi,
+ 'ethernet_tag_id': ethernet_tag_id,
+ 'ip_prefix': '%s/%s' % (ip_prefix, ip_prefix_len),
+ 'gw_ip_addr': gw_ip_addr,
+ 'label': rest,
+ }
+
+ def serialize_value(self):
+ route_dist = _RouteDistinguisher.from_str(self.route_dist)
+ ip_prefix = self._ip_addr_to_bin(self._ip_prefix)
+ gw_ip_addr = self._ip_addr_to_bin(self.gw_ip_addr)
+
+ return struct.pack(
+ self._PACK_STR % (len(ip_prefix), len(gw_ip_addr)),
+ route_dist.serialize(), self.esi.serialize(),
+ self.ethernet_tag_id, self._ip_prefix_len, ip_prefix,
+ gw_ip_addr, self._label)
+
+ @property
+ def ip_prefix(self):
+ return '%s/%s' % (self._ip_prefix, self._ip_prefix_len)
+
+ @ip_prefix.setter
+ def ip_prefix(self, ip_prefix):
+ self._ip_prefix, ip_prefix_len = ip_prefix.split('/')
+ self._ip_prefix_len = int(ip_prefix_len)
+
+ @property
+ def mpls_label(self):
+ return self._mpls_label
+
+ @mpls_label.setter
+ def mpls_label(self, mpls_label):
+ self._label = self._mpls_label_to_bin(mpls_label, is_bos=True)
+ self._mpls_label = mpls_label
+ self._vni = None # disables VNI
+
+ @property
+ def vni(self):
+ return self._vni
+
+ @vni.setter
+ def vni(self, vni):
+ self._label = self._vni_to_bin(vni)
+ self._mpls_label = None # disables MPLS label
+ self._vni = vni
+
+ @property
+ def label_list(self):
+ return [self.mpls_label]
+
+
@functools.total_ordering
class RouteTargetMembershipNLRI(StringifyMixin):
"""Route Target Membership NLRI.
diff --git a/ryu/tests/packet_data/bgp4/evpn_nlri_ip_prefix.pcap b/ryu/tests/packet_data/bgp4/evpn_nlri_ip_prefix.pcap
new file mode 100644
index 00000000..f1598ee8
--- /dev/null
+++ b/ryu/tests/packet_data/bgp4/evpn_nlri_ip_prefix.pcap
Binary files differ
diff --git a/ryu/tests/unit/packet/test_bgp.py b/ryu/tests/unit/packet/test_bgp.py
index 28b39769..0d28e6a8 100644
--- a/ryu/tests/unit/packet/test_bgp.py
+++ b/ryu/tests/unit/packet/test_bgp.py
@@ -260,6 +260,7 @@ class Test_bgp(unittest.TestCase):
'evpn_nlri_mac_ip_ad',
'evpn_nlri_inc_multi_eth_tag',
'evpn_nlri_eth_seg',
+ 'evpn_nlri_ip_prefix',
]
for f in files: