Openflow 1.1 and later versions allow the use of IP address with
arbitrary bitmask in match fields. This enables related fields
to be interpreted in the following order:

1. Standard CIDR:

    192.168.1.0/24
    fe80::/10

2. Hybrid CIDR format (IP address with dotted decimal or
   colon-hexadecimal mask):

    192.168.1.0/255.255.255.0
    fe80::/ffc0::

3. ACL hybrid CIDR format (Cisco-like ACL bitmask):

    192.168.1.0/0.0.0.255 (equivalent to 192.168.1.0/24)
    fe80::/3f:ffff:ffff:ffff:ffff:ffff:ffff:ffff (equivalent to fe80::/10)

4. IP address with arbitrary bitmask:

    192.168.1.0/0.255.0.255
    fe80::dead:beaf/ffff:0000:ffff:ffff:ffff:ffff:ffff:ffff

Please note that a bitmask with only continuous '1' bits starting from
LSB (e.g. 0.0.0.255) will be considered an ACL hybrid CIDR hostmask,
not an arbitrary bitmask.

You can explicitly specify arbitrary bitmask in separate fields as below:

    nw_src_w, nw_dst_w, ipv4_src_w, ipv4_dst_w,
    arp_spa_w, arp_tpa_w, ipv6_src_w, ipv6_dst_w.

These fields can be filled with only dotted decimal mask (for IPv4)
or colon-hexadecimal mask (for IPv6), and it always override mask
value in the relative match field which has no '_w' suffix.

For examples,

1.  "match": {"dl_type": 2048,
              "nw_src": "192.168.1.2",
              "nw_src_w": "0.255.0.255"}

In this case, the flow has "nw_src" with value "0.168.0.2/0.255.0.255".

2.  "match": {"dl_type": 2048,
              "nw_src": "192.168.1.2/255.255.255.0",
              "nw_src_w": "0.255.0.255"}

The flow also has "nw_src" with value "0.168.0.2/0.255.0.255" while
original mask defined in "nw_src" has been overridden by "nw_src_w".

If "nw_src" did not exist in match fields, "nw_src_w" is ignored.

Reported-by: Yi-Ching Lee <[email protected]>
Reported-by: Li-Der Chou <[email protected]>
Signed-off-by: Wei-Li Tang <[email protected]>
---
 ryu/lib/ofctl_v1_2.py |   40 +++++++++++++++++++++++++++++++++++++---
 ryu/lib/ofctl_v1_3.py |   40 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 74 insertions(+), 6 deletions(-)

diff --git a/ryu/lib/ofctl_v1_2.py b/ryu/lib/ofctl_v1_2.py
index e6023ed..d03ddf3 100644
--- a/ryu/lib/ofctl_v1_2.py
+++ b/ryu/lib/ofctl_v1_2.py
@@ -244,6 +244,16 @@ def to_match(dp, attrs):
                'ipv6_src': to_match_ipv6,
                'ipv6_dst': to_match_ipv6}
 
+    # Conversion function mapping for explicit arbitrary bitmask fields
+    convert_w = {'nw_src_w': to_match_ip_bitmask,
+                 'nw_dst_w': to_match_ip_bitmask,
+                 'ipv4_src_w': to_match_ip_bitmask,
+                 'ipv4_dst_w': to_match_ip_bitmask,
+                 'arp_spa_w': to_match_ip_bitmask,
+                 'arp_tpa_w': to_match_ip_bitmask,
+                 'ipv6_src_w': to_match_ipv6_bitmask,
+                 'ipv6_dst_w': to_match_ipv6_bitmask}
+
     match_append = {'in_port': match.set_in_port,
                     'dl_src': match.set_dl_src,
                     'dl_dst': match.set_dl_dst,
@@ -289,7 +299,11 @@ def to_match(dp, attrs):
                     key == 'ipv6_src' or key == 'ipv6_dst':
                 # IP address
                 ip = value[0]
-                mask = value[1]
+                # override if explicit arbitrary bitmask defined
+                if key + '_w' in attrs:
+                    mask = convert_w[key + '_w'](attrs.get(key + '_w'))
+                else:
+                    mask = value[1]
                 match_append[key](ip, mask)
             elif key == 'tp_src' or key == 'tp_dst' or \
                     key == 'tcp_src' or key == 'tcp_dst' or \
@@ -326,15 +340,35 @@ def to_match_tpdst(value, match, rest):
 
 
 def to_match_ip(value):
-    ip = netaddr.IPNetwork(value)
+    try:
+        ip = netaddr.IPNetwork(value)
+    except netaddr.core.AddrFormatError:
+        if '/' in value:
+            addr, mask = value.split('/')
+            return (netaddr.IPAddress(addr).value,
+                    netaddr.IPAddress(mask).value)
     return ip.ip.value, ip.netmask.value
 
 
 def to_match_ipv6(value):
-    ip = netaddr.IPNetwork(value)
+    try:
+        ip = netaddr.IPNetwork(value)
+    except netaddr.core.AddrFormatError:
+        if '/' in value:
+            addr, mask = value.split('/')
+            return (netaddr.IPAddress(addr).words,
+                    netaddr.IPAddress(mask).words)
     return ip.ip.words, ip.netmask.words
 
 
+def to_match_ip_bitmask(value):
+    return struct.unpack('!I', socket.inet_aton(value))[0]
+
+
+def to_match_ipv6_bitmask(value):
+    return netaddr.IPAddress(value).words
+
+
 def match_to_str(ofmatch):
     keys = {ofproto_v1_2.OXM_OF_IN_PORT: 'in_port',
             ofproto_v1_2.OXM_OF_ETH_SRC: 'dl_src',
diff --git a/ryu/lib/ofctl_v1_3.py b/ryu/lib/ofctl_v1_3.py
index 748f389..3d6bd0f 100644
--- a/ryu/lib/ofctl_v1_3.py
+++ b/ryu/lib/ofctl_v1_3.py
@@ -258,6 +258,16 @@ def to_match(dp, attrs):
                'tunnel_id': int,
                'ipv6_exthdr': int}
 
+    # Conversion function mapping for explicit arbitrary bitmask fields
+    convert_w = {'nw_src_w': to_match_ip_bitmask,
+                 'nw_dst_w': to_match_ip_bitmask,
+                 'ipv4_src_w': to_match_ip_bitmask,
+                 'ipv4_dst_w': to_match_ip_bitmask,
+                 'arp_spa_w': to_match_ip_bitmask,
+                 'arp_tpa_w': to_match_ip_bitmask,
+                 'ipv6_src_w': to_match_ipv6_bitmask,
+                 'ipv6_dst_w': to_match_ipv6_bitmask}
+
     match_append = {'in_port': match.set_in_port,
                     'dl_src': match.set_dl_src,
                     'dl_dst': match.set_dl_dst,
@@ -326,7 +336,11 @@ def to_match(dp, attrs):
                     key == 'ipv6_src' or key == 'ipv6_dst':
                 # IP address
                 ip = value[0]
-                mask = value[1]
+                # override if explicit arbitrary bitmask defined
+                if key + '_w' in attrs:
+                    mask = convert_w[key + '_w'](attrs.get(key + '_w'))
+                else:
+                    mask = value[1]
                 match_append[key](ip, mask)
             elif key == 'tp_src' or key == 'tp_dst' or \
                     key == 'tcp_src' or key == 'tcp_dst' or \
@@ -368,15 +382,35 @@ def to_match_tpdst(value, match, rest):
 
 
 def to_match_ip(value):
-    ip = netaddr.IPNetwork(value)
+    try:
+        ip = netaddr.IPNetwork(value)
+    except netaddr.core.AddrFormatError:
+        if '/' in value:
+            addr, mask = value.split('/')
+            return (netaddr.IPAddress(addr).value,
+                    netaddr.IPAddress(mask).value)
     return ip.ip.value, ip.netmask.value
 
 
 def to_match_ipv6(value):
-    ip = netaddr.IPNetwork(value)
+    try:
+        ip = netaddr.IPNetwork(value)
+    except netaddr.core.AddrFormatError:
+        if '/' in value:
+            addr, mask = value.split('/')
+            return (netaddr.IPAddress(addr).words,
+                    netaddr.IPAddress(mask).words)
     return ip.ip.words, ip.netmask.words
 
 
+def to_match_ip_bitmask(value):
+    return struct.unpack('!I', socket.inet_aton(value))[0]
+
+
+def to_match_ipv6_bitmask(value):
+    return netaddr.IPAddress(value).words
+
+
 def to_match_metadata(value):
     if '/' in value:
         metadata = value.split('/')
-- 
1.7.9.5


------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and their
applications. Written by three acclaimed leaders in the field,
this first edition is now available. Download your free book today!
http://p.sf.net/sfu/13534_NeoTech
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to