The Route Distinguisher did not include in data structure
for VPNv4 Flow Specification.
This patch adds the Route Distinguisher to data structure
for VPNv4 Flow Specification.
For details, refer to Chapter 8 of RFC 5575.

Signed-off-by: Shinpei Muraoka <[email protected]>
---
 ryu/lib/packet/bgp.py                              |  90 +++++++++++++++++----
 ryu/tests/packet_data/bgp4/flowspec_nlri_ipv4.pcap | Bin 217 -> 273 bytes
 ryu/tests/packet_data/bgp4/flowspec_nlri_vpn4.pcap | Bin 217 -> 289 bytes
 ryu/tests/unit/packet/test_bgp.py                  |   3 +-
 4 files changed, 78 insertions(+), 15 deletions(-)

diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py
index 47feeb3..d22bb0e 100644
--- a/ryu/lib/packet/bgp.py
+++ b/ryu/lib/packet/bgp.py
@@ -1997,7 +1997,7 @@ class _FlowSpecNLRIBase(StringifyMixin, TypeDisp):
     # +-----------------------------------+
     # |     NLRI value  (variable)        |
     # +-----------------------------------+
-
+    ROUTE_FAMILY = None
     _LENGTH_SHORT_FMT = '!B'
     LENGTH_SHORT_SIZE = struct.calcsize(_LENGTH_SHORT_FMT)
     _LENGTH_LONG_FMT = '!H'
@@ -2013,7 +2013,7 @@ class _FlowSpecNLRIBase(StringifyMixin, TypeDisp):
 
     @classmethod
     def parser(cls, buf):
-        (length, ) = struct.unpack_from(
+        (length,) = struct.unpack_from(
             cls._LENGTH_LONG_FMT, six.binary_type(buf))
 
         if length < cls._LENGTH_THRESHOLD:
@@ -2022,7 +2022,14 @@ class _FlowSpecNLRIBase(StringifyMixin, TypeDisp):
         else:
             offset = cls.LENGTH_LONG_SIZE
 
+        kwargs = {'length': length}
         rest = buf[offset:offset + length]
+
+        if cls.ROUTE_FAMILY.safi == subaddr_family.VPN_FLOW_SPEC:
+            route_dist = _RouteDistinguisher.parser(rest[:8])
+            kwargs['route_dist'] = route_dist.formatted_str
+            rest = rest[8:]
+
         rules = []
 
         while rest:
@@ -2036,10 +2043,17 @@ class _FlowSpecNLRIBase(StringifyMixin, TypeDisp):
                         rule.operator & rule.END_OF_LIST):
                     break
 
-        return cls(length, rules), rest
+        kwargs['rules'] = rules
+
+        return cls(**kwargs), rest
 
     def serialize(self):
-        rules_bin = bytearray()
+        rules_bin = b''
+
+        if self.ROUTE_FAMILY.safi == subaddr_family.VPN_FLOW_SPEC:
+            route_dist = _RouteDistinguisher.from_str(self.route_dist)
+            rules_bin += route_dist.serialize()
+
         self.rules.sort(key=lambda x: x.type)
         for _, rules in itertools.groupby(self.rules, key=lambda x: x.type):
             rules = list(rules)
@@ -2114,18 +2128,19 @@ class FlowSpecIPv4NLRI(_FlowSpecNLRIBase):
         =========== ============= ========= ==============================
 
         Example::
+
             >>> msg = bgp.FlowSpecIPv4NLRI.from_user(
             ...     dst_prefix='10.0.0.0/24',
             ...     src_prefix='20.0.0.1/24',
-            ...     ip_proto='==6',
-            ...     port='==80 | ==8000',
+            ...     ip_proto=6,
+            ...     port='80 | 8000',
             ...     dst_port='>9000 & <9050',
             ...     src_port='>=8500 & <=9000',
-            ...     icmp_type='==0',
-            ...     icmp_code='==6',
+            ...     icmp_type=0,
+            ...     icmp_code=6,
             ...     tcp_flags='SYN+ACK & !=URGENT',
-            ...     packet_len='==1000',
-            ...     dscp='==22 | ==24',
+            ...     packet_len=1000,
+            ...     dscp='22 | 24',
             ...     fragment='LF | ==FF')
             >>>
 
@@ -2173,15 +2188,62 @@ class FlowSpecIPv4NLRI(_FlowSpecNLRIBase):
 class FlowSpecVPNv4NLRI(_FlowSpecNLRIBase):
     """
     Flow Specification NLRI class for VPNv4 [RFC 5575]
-
-    See :py:mod:`ryu.lib.packet.bgp.FlowSpecIPv4NLRI`
     """
+
+    # flow-spec NLRI:
+    # +-----------------------------------+
+    # |    length (0xnn or 0xfn nn)       |
+    # +-----------------------------------+
+    # |     RD   (8 octets)               |
+    # +-----------------------------------+
+    # |     NLRI value  (variable)        |
+    # +-----------------------------------+
     ROUTE_FAMILY = RF_VPNv4_FLOW_SPEC
 
+    def __init__(self, length=0, route_dist=None, rules=None):
+        super(FlowSpecVPNv4NLRI, self).__init__(length, rules)
+        assert route_dist is not None
+        self.route_dist = route_dist
+
     @classmethod
-    def from_user(cls, **kwargs):
+    def _from_user(cls, route_dist, **kwargs):
+        rules = []
+        for k, v in kwargs.items():
+            subcls = _FlowSpecComponentBase.lookup_type_name(k)
+            rule = subcls.from_str(str(v))
+            rules.extend(rule)
+        rules.sort(key=lambda x: x.type)
+        return cls(route_dist=route_dist, rules=rules)
 
-        return cls._from_user(**kwargs)
+    @classmethod
+    def from_user(cls, route_dist, **kwargs):
+        """
+        Utility method for creating a NLRI instance.
+
+        This function returns a NLRI instance from human readable format value.
+
+        :param route_dist: Route Distinguisher.
+        :param kwargs: See :py:mod:`ryu.lib.packet.bgp.FlowSpecIPv4NLRI`
+
+        Example::
+
+            >>> msg = bgp.FlowSpecIPv4NLRI.from_user(
+            ...     route_dist='65000:1000',
+            ...     dst_prefix='10.0.0.0/24',
+            ...     src_prefix='20.0.0.1/24',
+            ...     ip_proto=6,
+            ...     port='80 | 8000',
+            ...     dst_port='>9000 & <9050',
+            ...     src_port='>=8500 & <=9000',
+            ...     icmp_type=0,
+            ...     icmp_code=6,
+            ...     tcp_flags='SYN+ACK & !=URGENT',
+            ...     packet_len=1000,
+            ...     dscp='22 | 24',
+            ...     fragment='LF | ==FF')
+            >>>
+        """
+        return cls._from_user(route_dist, **kwargs)
 
 
 class _FlowSpecComponentBase(StringifyMixin, TypeDisp):
diff --git a/ryu/tests/packet_data/bgp4/flowspec_nlri_ipv4.pcap 
b/ryu/tests/packet_data/bgp4/flowspec_nlri_ipv4.pcap
index 
c7953484a05b4a5ae2ac81590000627b82c510ca..885a106ade29829431299112841f9250c4f1f4ed
 100644
GIT binary patch
delta 209
zcmcb~IFV_BME&WE{Sn;v7#LnMKroZj{>wHinVi-LGB9y4xH2%@K6lfBfsrjp4kQA^
zj0~G+bj-Q-iAnU@-ns?}hR+e785kHDIk*_aUA!5@?fw6w0fyyFK(i+}FfuYZFtIT)
zGBEso)xa0az}U*b5U$K9!NtJ9Bq74Uz|06#!N|tQ$tcLE$JoNi!Klv|$r#s|K5?mu
i@&N&b1~vu;rxOee4IB(WEet6Q>_8Hzt$`CvO8@}P7&);3

delta 152
zcmbQpbdzy{ME&*XhKO}Vj0_tY7{HjxX^kKQGni!JU~pw%SloZqfx&?-C<7?Y1d?Oe
zyjADy1&h!aNySeM5)6+c_A)RqGIDS+1YZwg2tIrDKN?`jX9AiX;lRkq<iNz>z{&#T
gr8MxlGcdL?Fz`7tN^mhSFiD6oFfcc=P26Py0FkUOcK`qY

diff --git a/ryu/tests/packet_data/bgp4/flowspec_nlri_vpn4.pcap 
b/ryu/tests/packet_data/bgp4/flowspec_nlri_vpn4.pcap
index 
74a7d174cb2cc1ecd1260b56ca4bcafe2e7243a4..236110dbd35b384c7114479767afa054100ee5fa
 100644
GIT binary patch
delta 247
zcmcb~xR9y-%Hd55nHX3Y5P*e&5y&}{zCXhB86(3_ARC04oc3R~S;^$IMv#GtgTa-7
z;q{$)4h)QJE}kF}AZBFPJR?DQ#^cG0EN{g%NHBbkWM*JsWaQvt5c3XW5VPO&9}O^U
zXJTM*W?10B$jIct#Kr`)_3x_&zElRrHU@@xAm=5}+Fy(kazM)^G#D6|8G#BJ*%&z)
z1sU}iTNpVQ^%)}>;~LW^E;Z3UAfUm(1kusJ#=ziof`OrdgMkZZLP`TWkOXRP-~`hW
E0JD5S$^ZZW

literal 217
zcmca|c+)~A1{MYw`2U}Qff2|tUe+41Es=v^BajWkOipVA8JNK&69<DU1H<C}qYexX
zY(W`7aVC%)!{)6zXD?WU#z-oDYLH-f9I+Q@5+er}L-6$=hTyYT|Dyqhd?ui|5e|%u
zOb$#84y+(Iq%`okGcdL>FgP+wZ~-lq5Mf|oZe(L&3=o!|a8+pstDyV@VP%c0%1vy7
k%1y$`Jx5QlH!^TEvT-s9H865Drf@TgHA?U>FgCCN09~9sOaK4?

diff --git a/ryu/tests/unit/packet/test_bgp.py 
b/ryu/tests/unit/packet/test_bgp.py
index dec1dae..a3b7a68 100644
--- a/ryu/tests/unit/packet/test_bgp.py
+++ b/ryu/tests/unit/packet/test_bgp.py
@@ -561,6 +561,7 @@ class Test_bgp(unittest.TestCase):
         eq_(rest, b'')
 
         msg = bgp.FlowSpecVPNv4NLRI.from_user(
+            route_dist='65001:250',
             dst_prefix='10.0.0.0/24',
             src_prefix='20.0.0.0/24',
             ip_proto='6',
@@ -573,7 +574,7 @@ class Test_bgp(unittest.TestCase):
             packet_len='1000 & 1100',
             dscp='22 24',
             fragment='LF ==FF&==ISF | !=DF')
-        msg2 = bgp.FlowSpecVPNv4NLRI(rules=rules)
+        msg2 = bgp.FlowSpecVPNv4NLRI(route_dist='65001:250', rules=rules)
         binmsg = msg.serialize()
         binmsg2 = msg2.serialize()
         eq_(str(msg), str(msg2))
-- 
2.7.4


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to