Currently, when VLAN ID match field is specified,
ofctl_v1_[23] is compatible with only match combination 1) of
the following three match combinations.
This patch makes it possible to set the all three combinations.

  Match combinations for VLAN ID :
    1) To match only packets with VLAN tag and VID equal value
    2) To match only packets without a VLAN tag
    3) To match only packets with a VLAN tag regardless of its value

In order to set the match combinations 2) or 3), please describe
"dl_vlan" field as hexadecimal string value like as follows.

  Before applying this patch:
    {"dl_vlan": 3 }              # int

  After applying this patch:
    {"dl_vlan": 3 }              # int (same as before applying)
    {"dl_vlan": "0x0000"}        # hexadecimal string without mask
    {"dl_vlan": "0x1000/0x1000"} # hexadecimal string with mask

NOTE: When "dl_vlan" field is described as decimal int value,
      OFPVID_PRESENT(0x1000) bit is automatically applied.
      OTOH, OFPVID_PRESENT(0x1000) bit is NOT automatically applied
      to hexadecimal string value.

For curl command examples, please refer to the following page in 
Ryu-documentation.
http://ryu.readthedocs.org/en/latest/app/ofctl_rest.html#example-of-vlan-id-match-field

Signed-off-by: Minoru TAKAHASHI <[email protected]>
---
 ryu/lib/ofctl_v1_2.py            | 48 ++++++++++++++++++---
 ryu/lib/ofctl_v1_3.py            | 48 ++++++++++++++++++---
 ryu/tests/unit/lib/test_ofctl.py | 92 ++++++++++++++++++++++++++++++++++++++--
 3 files changed, 170 insertions(+), 18 deletions(-)

diff --git a/ryu/lib/ofctl_v1_2.py b/ryu/lib/ofctl_v1_2.py
index 40989a2..c8b9174 100644
--- a/ryu/lib/ofctl_v1_2.py
+++ b/ryu/lib/ofctl_v1_2.py
@@ -198,8 +198,8 @@ def to_match(dp, attrs):
                'eth_src': to_match_eth,
                'dl_type': int,
                'eth_type': int,
-               'dl_vlan': int,
-               'vlan_vid': int,
+               'dl_vlan': to_match_vid,
+               'vlan_vid': to_match_vid,
                'vlan_pcp': int,
                'ip_dscp': int,
                'ip_ecn': int,
@@ -268,9 +268,6 @@ def to_match(dp, attrs):
             ip_proto = attrs.get('nw_proto', attrs.get('ip_proto', 0))
             key = conv[ip_proto][key]
             kwargs[key] = value
-        elif key == 'vlan_vid':
-            # VLAN ID
-            kwargs[key] = value | ofproto_v1_2.OFPVID_PRESENT
         else:
             # others
             kwargs[key] = value
@@ -296,6 +293,28 @@ def to_match_ip(value):
         return value
 
 
+def to_match_vid(value):
+    # NOTE: If "vlan_id/dl_vlan" field is described as decimal int value
+    #       (and decimal string value), it is treated as values of
+    #       VLAN tag, and OFPVID_PRESENT(0x1000) bit is automatically
+    #       applied. OTOH, If it is described as hexadecimal string,
+    #       treated as values of oxm_value (including OFPVID_PRESENT
+    #       bit), and OFPVID_PRESENT bit is NOT automatically applied.
+    if isinstance(value, int):
+        # described as decimal int value
+        return value | ofproto_v1_2.OFPVID_PRESENT
+    else:
+        if '/' in value:
+            val = value.split('/')
+            return int(val[0], 0), int(val[1], 0)
+        else:
+            if value.isdigit():
+                # described as decimal string value
+                return int(value, 10) | ofproto_v1_2.OFPVID_PRESENT
+            else:
+                return int(value, 0)
+
+
 def to_match_metadata(value):
     if '/' in value:
         value = value.split('/')
@@ -330,9 +349,9 @@ def match_to_str(ofmatch):
         mask = match_field['OXMTlv']['mask']
         value = match_field['OXMTlv']['value']
         if key == 'dl_vlan':
-            value &= ~ofproto_v1_2.OFPVID_PRESENT
+            value = match_vid_to_str(value, mask)
         elif key == 'metadata':
-            value = ('%d/%d' % (value, mask) if mask else '%d' % value)
+            value = match_metadata_to_str(value, mask)
         else:
             if mask is not None:
                 value = value + '/' + mask
@@ -343,6 +362,21 @@ def match_to_str(ofmatch):
     return match
 
 
+def match_metadata_to_str(value, mask):
+    return ('%d/%d' % (value, mask) if mask else '%d' % value)
+
+
+def match_vid_to_str(value, mask):
+    if mask is not None:
+        value = '0x%04x/0x%04x' % (value, mask)
+    else:
+        if value & ofproto_v1_2.OFPVID_PRESENT:
+            value = str(value & ~ofproto_v1_2.OFPVID_PRESENT)
+        else:
+            value = '0x%04x' % value
+    return value
+
+
 def send_stats_request(dp, stats, waiters, msgs):
     dp.set_xid(stats)
     waiters_per_dp = waiters.setdefault(dp.id, {})
diff --git a/ryu/lib/ofctl_v1_3.py b/ryu/lib/ofctl_v1_3.py
index 96c22d2..bc21a7f 100644
--- a/ryu/lib/ofctl_v1_3.py
+++ b/ryu/lib/ofctl_v1_3.py
@@ -215,8 +215,8 @@ def to_match(dp, attrs):
                'eth_src': to_match_eth,
                'dl_type': int,
                'eth_type': int,
-               'dl_vlan': int,
-               'vlan_vid': int,
+               'dl_vlan': to_match_vid,
+               'vlan_vid': to_match_vid,
                'vlan_pcp': int,
                'ip_dscp': int,
                'ip_ecn': int,
@@ -289,9 +289,6 @@ def to_match(dp, attrs):
             ip_proto = attrs.get('nw_proto', attrs.get('ip_proto', 0))
             key = conv[ip_proto][key]
             kwargs[key] = value
-        elif key == 'vlan_vid':
-            # VLAN ID
-            kwargs[key] = value | ofproto_v1_3.OFPVID_PRESENT
         else:
             # others
             kwargs[key] = value
@@ -317,6 +314,28 @@ def to_match_ip(value):
         return value
 
 
+def to_match_vid(value):
+    # NOTE: If "vlan_id/dl_vlan" field is described as decimal int value
+    #       (and decimal string value), it is treated as values of
+    #       VLAN tag, and OFPVID_PRESENT(0x1000) bit is automatically
+    #       applied. OTOH, If it is described as hexadecimal string,
+    #       treated as values of oxm_value (including OFPVID_PRESENT
+    #       bit), and OFPVID_PRESENT bit is NOT automatically applied.
+    if isinstance(value, int):
+        # described as decimal int value
+        return value | ofproto_v1_3.OFPVID_PRESENT
+    else:
+        if '/' in value:
+            val = value.split('/')
+            return int(val[0], 0), int(val[1], 0)
+        else:
+            if value.isdigit():
+                # described as decimal string value
+                return int(value, 10) | ofproto_v1_3.OFPVID_PRESENT
+            else:
+                return int(value, 0)
+
+
 def to_match_metadata(value):
     if '/' in value:
         value = value.split('/')
@@ -352,9 +371,9 @@ def match_to_str(ofmatch):
         mask = match_field['OXMTlv']['mask']
         value = match_field['OXMTlv']['value']
         if key == 'dl_vlan':
-            value &= ~ofproto_v1_3.OFPVID_PRESENT
+            value = match_vid_to_str(value, mask)
         elif key == 'metadata':
-            value = ('%d/%d' % (value, mask) if mask else '%d' % value)
+            value = match_metadata_to_str(value, mask)
         else:
             if mask is not None:
                 value = value + '/' + mask
@@ -365,6 +384,21 @@ def match_to_str(ofmatch):
     return match
 
 
+def match_metadata_to_str(value, mask):
+    return ('%d/%d' % (value, mask) if mask else '%d' % value)
+
+
+def match_vid_to_str(value, mask):
+    if mask is not None:
+        value = '0x%04x/0x%04x' % (value, mask)
+    else:
+        if value & ofproto_v1_3.OFPVID_PRESENT:
+            value = str(value & ~ofproto_v1_3.OFPVID_PRESENT)
+        else:
+            value = '0x%04x' % value
+    return value
+
+
 def send_stats_request(dp, stats, waiters, msgs):
     dp.set_xid(stats)
     waiters_per_dp = waiters.setdefault(dp.id, {})
diff --git a/ryu/tests/unit/lib/test_ofctl.py b/ryu/tests/unit/lib/test_ofctl.py
index dd73b5e..0c09464 100644
--- a/ryu/tests/unit/lib/test_ofctl.py
+++ b/ryu/tests/unit/lib/test_ofctl.py
@@ -189,6 +189,44 @@ class Test_ofctl(unittest.TestCase):
         dp = ofproto_protocol.ProtocolDesc(version=test.ver)
         ofproto = dp.ofproto
 
+        vid_present = dp.ofproto.OFPVID_PRESENT
+        expected_value = {
+            "vlan_vid": {
+                0: {"to_match": 0 | vid_present, "to_str": "0"},
+                3: {"to_match": 3 | vid_present, "to_str": "3"},
+                4095: {"to_match": 4095 | vid_present, "to_str": "4095"},
+                "0": {"to_match": 0 | vid_present, "to_str": "0"},
+                "3": {"to_match": 3 | vid_present, "to_str": "3"},
+                "4095": {"to_match": 4095 | vid_present, "to_str": "4095"},
+                "0x0000": {"to_match": 0x0000, "to_str": "0x0000"},
+                "0x0003": {"to_match": 0x0003, "to_str": "0x0003"},
+                "0x0fff": {"to_match": 0x0fff, "to_str": "0x0fff"},
+                "0x1000": {"to_match": 0x1000, "to_str": "0"},
+                "0x1003": {"to_match": 0x1003, "to_str": "3"},
+                "0x1fff": {"to_match": 0x1fff, "to_str": "4095"},
+                "4096/4096": {"to_match": (4096, 4096),
+                              "to_str": "0x1000/0x1000"},
+                "4096/4097": {"to_match": (4096, 4097),
+                              "to_str": "0x1000/0x1001"},
+                "2744/2748": {"to_match": (2744, 2748),
+                              "to_str": "0x0ab8/0x0abc"},
+                "2748/2748": {"to_match": (2748, 2748),
+                              "to_str": "0x0abc/0x0abc"},
+                "2748/2749": {"to_match": (2748, 2749),
+                              "to_str": "0x0abc/0x0abd"},
+                "0x1000/0x1000": {"to_match": (0x1000, 0x1000),
+                                  "to_str": "0x1000/0x1000"},
+                "0x1000/0x1001": {"to_match": (0x1000, 0x1001),
+                                  "to_str": "0x1000/0x1001"},
+                "0x0ab8/0x0abc": {"to_match": (0x0ab8, 0x0abc),
+                                  "to_str": "0x0ab8/0x0abc"},
+                "0x0abc/0x0abc": {"to_match": (0x0abc, 0x0abc),
+                                  "to_str": "0x0abc/0x0abc"},
+                "0x0abc/0x0abd": {"to_match": (0x0abc, 0x0abd),
+                                  "to_str": "0x0abc/0x0abd"}
+            }
+        }
+
         # str -> match
         match = to_match(dp, attrs)
 
@@ -230,8 +268,7 @@ class Test_ofctl(unittest.TestCase):
                     eq_(ipv6, field_value)
                 return
             elif key == 'vlan_vid':
-                vid = value | ofproto.OFPVID_PRESENT
-                eq_(vid, field_value)
+                eq_(expected_value['vlan_vid'][value]['to_match'], field_value)
                 return
             elif key == 'metadata':
                 # Metadata
@@ -308,6 +345,9 @@ class Test_ofctl(unittest.TestCase):
                     # without mask
                     eq_(ipv6, field_value)
                 return
+            elif key == 'dl_vlan':
+                eq_(expected_value['vlan_vid'][value]['to_str'], field_value)
+                return
             elif key == 'metadata':
                 # Metadata
                 meta, mask = _to_match_metadata(value)
@@ -373,7 +413,28 @@ class test_data_v1_2():
             {'eth_dst': "aa:bb:cc:11:22:33"},
             {'eth_dst': "aa:bb:cc:11:22:33/00:00:00:00:ff:ff"},
             {'eth_type': 0x800},
-            {'dl_vlan': 5},
+            {'dl_vlan': 0},
+            {'dl_vlan': 3},
+            {'dl_vlan': 4095},
+            {'dl_vlan': "0"},
+            {'dl_vlan': "3"},
+            {'dl_vlan': "4095"},
+            {'dl_vlan': "0x0000"},
+            {'dl_vlan': "0x0003"},
+            {'dl_vlan': "0x0fff"},
+            {'dl_vlan': "0x1000"},
+            {'dl_vlan': "0x1003"},
+            {'dl_vlan': "0x1fff"},
+            {'dl_vlan': "4096/4096"},
+            {'dl_vlan': "4096/4097"},
+            {'dl_vlan': "2744/2748"},
+            {'dl_vlan': "2748/2748"},
+            {'dl_vlan': "2748/2749"},
+            {'dl_vlan': "0x1000/0x1000"},
+            {'dl_vlan': "0x1000/0x1001"},
+            {'dl_vlan': "0x0ab8/0x0abc"},
+            {'dl_vlan': "0x0abc/0x0abc"},
+            {'dl_vlan': "0x0abc/0x0abd"},
             {'vlan_pcp': 3, 'vlan_vid': 3},
             {'ip_dscp': 3, 'eth_type': 0x0800},
             {'ip_ecn': 4, 'eth_type': 0x86dd},
@@ -395,7 +456,28 @@ class test_data_v1_2():
             {'tp_dst': 2, 'ip_proto': 6},
             {'tp_src': 3, 'ip_proto': 17},
             {'tp_dst': 4, 'ip_proto': 17},
+            {'vlan_vid': 0},
             {'vlan_vid': 3},
+            {'vlan_vid': 4095},
+            {'vlan_vid': "0"},
+            {'vlan_vid': "3"},
+            {'vlan_vid': "4095"},
+            {'vlan_vid': "0x0000"},
+            {'vlan_vid': "0x0003"},
+            {'vlan_vid': "0x0fff"},
+            {'vlan_vid': "0x1000"},
+            {'vlan_vid': "0x1003"},
+            {'vlan_vid': "0x1fff"},
+            {'vlan_vid': "4096/4096"},
+            {'vlan_vid': "4096/4097"},
+            {'vlan_vid': "2744/2748"},
+            {'vlan_vid': "2748/2748"},
+            {'vlan_vid': "2748/2749"},
+            {'vlan_vid': "0x1000/0x1000"},
+            {'vlan_vid': "0x1000/0x1001"},
+            {'vlan_vid': "0x0ab8/0x0abc"},
+            {'vlan_vid': "0x0abc/0x0abc"},
+            {'vlan_vid': "0x0abc/0x0abd"},
             {'tcp_src': 3, 'ip_proto': 6},
             {'tcp_dst': 5, 'ip_proto': 6},
             {'udp_src': 2, 'ip_proto': 17},
@@ -590,7 +672,8 @@ def _add_tests_match(cls):
     for attr in cls.attr_list:
         for key, value in attr.items():
             method_name = 'test_' + \
-                str(cls.ver) + '_' + key + '_' + str(value) + '_match'
+                str(cls.ver) + '_' + key + '_' + str(
+                    value) + str(type(value)) + '_match'
 
             def _run(self, name, attr, cls):
                 print ('processing %s ...' % name)
@@ -604,6 +687,7 @@ def _add_tests_match(cls):
             im = new.instancemethod(func, None, Test_ofctl)
             setattr(Test_ofctl, method_name, im)
 
+
 """ Test case """
 
 # for of12
-- 
1.9.1


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=157005751&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to