diff options
author | Minoru TAKAHASHI <takahashi.minoru7@gmail.com> | 2014-11-28 16:47:02 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-11-29 08:17:01 +0900 |
commit | 1979bde57302a395eb82406dc85cfae20dab8dff (patch) | |
tree | 4661c8ccc0d7d0fcea8c4d11596ef9c118a7224f | |
parent | 31353a95dd4fb43a13a67b549cad214c214c2302 (diff) |
ofctl_v1_2/3: Fully support the match combinations for VLAN ID
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 <takahashi.minoru7@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/lib/ofctl_v1_2.py | 48 | ||||
-rw-r--r-- | ryu/lib/ofctl_v1_3.py | 48 | ||||
-rw-r--r-- | 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 40989a20..c8b91743 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 96c22d2f..bc21a7f5 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 dd73b5ea..0c094647 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 |