diff options
author | Shinpei Muraoka <shinpei.muraoka@gmail.com> | 2016-11-09 10:44:04 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-11-14 13:21:04 +0900 |
commit | 972c31f0e6f32ae40417a79001353328b965728f (patch) | |
tree | 38c6c39e8b0d14631b01ce5bba6f89a489bb31de | |
parent | 264d32ea2d1aa900daa7c554505e5e71be45b0fc (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.py | 138 | ||||
-rw-r--r-- | ryu/tests/packet_data/bgp4/evpn_nlri_ip_prefix.pcap | bin | 0 -> 190 bytes | |||
-rw-r--r-- | ryu/tests/unit/packet/test_bgp.py | 1 |
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 Binary files differnew file mode 100644 index 00000000..f1598ee8 --- /dev/null +++ b/ryu/tests/packet_data/bgp4/evpn_nlri_ip_prefix.pcap 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: |