Openflow 1.1 and later versions allow the use of IP address with arbitrary bitmask in match fields. This adds arbitrary bitmask support to related functions.
For match_ip*_to_str functions, it outputs full mask address only if the mask cannot be represented in CIDR format. Please notice that to_match_ipv6() is no longer compatible with ACL hybrid CIDR format (Cisco-like ACL bitmasks) after applying this patch. 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, 60 insertions(+), 20 deletions(-) diff --git a/ryu/lib/ofctl_v1_2.py b/ryu/lib/ofctl_v1_2.py index 273b387..9662d3a 100644 --- a/ryu/lib/ofctl_v1_2.py +++ b/ryu/lib/ofctl_v1_2.py @@ -330,18 +330,28 @@ def to_match_ip(value): # ip ipv4 = struct.unpack('!I', socket.inet_aton(ip_mask[0]))[0] # netmask - mask = 32 + netmask = ofproto_v1_2_parser.UINT32_MAX if len(ip_mask) == 2: - mask = int(ip_mask[1]) - netmask = ofproto_v1_2_parser.UINT32_MAX << 32 - mask\ - & ofproto_v1_2_parser.UINT32_MAX + if ip_mask[1].isdigit(): + netmask &= ofproto_v1_2_parser.UINT32_MAX << 32 - int(ip_mask[1]) + else: + netmask = struct.unpack('!I', socket.inet_aton(ip_mask[1]))[0] return ipv4, netmask def to_match_ipv6(value): - ip = netaddr.IPNetwork(value) - return ip.ip.words, ip.netmask.words + ip_mask = value.split('/') + + if len(ip_mask) == 2 and ip_mask[1].isdigit() is False: + ipv6 = netaddr.IPAddress(ip_mask[0]).words + netmask = netaddr.IPAddress(ip_mask[1]).words + else: + network = netaddr.IPNetwork(value) + ipv6 = network.ip.words + netmask = network.netmask.words + + return ipv6, netmask def match_to_str(ofmatch): @@ -389,8 +399,11 @@ def match_ip_to_str(value, mask): ip = socket.inet_ntoa(struct.pack('!I', value)) if mask is not None and mask != 0: - binary_str = bin(mask)[2:].zfill(8) - netmask = '/%d' % len(binary_str.rstrip('0')) + binary_str = bin(mask)[2:].zfill(32).rstrip('0') + if binary_str.find('0') >= 0: + netmask = '/%s' % socket.inet_ntoa(struct.pack('!I', mask)) + else: + netmask = '/%d' % len(binary_str) else: netmask = '' @@ -404,14 +417,21 @@ def match_ipv6_to_str(value, mask): ip = netaddr.IPNetwork(':'.join(ip_list)) netmask = 128 + netmask_str = None if mask is not None: mask_list = [] for word in mask: mask_list.append('%04x' % word) mask_v = netaddr.IPNetwork(':'.join(mask_list)) - netmask = len(mask_v.ip.bits().replace(':', '').rstrip('0')) + binary_str = mask_v.ip.bits().replace(':', '').zfill(128).rstrip('0') + if binary_str.find('0') >= 0: + netmask_str = str(mask_v.ip) + else: + netmask = len(binary_str) - if netmask == 128: + if netmask_str is not None: + ip_str = str(ip.ip) + '/' + netmask_str + elif netmask == 128: ip_str = str(ip.ip) else: ip.prefixlen = netmask diff --git a/ryu/lib/ofctl_v1_3.py b/ryu/lib/ofctl_v1_3.py index 3e2713e..9c470bd 100644 --- a/ryu/lib/ofctl_v1_3.py +++ b/ryu/lib/ofctl_v1_3.py @@ -372,18 +372,28 @@ def to_match_ip(value): # ip ipv4 = struct.unpack('!I', socket.inet_aton(ip_mask[0]))[0] # netmask - mask = 32 + netmask = ofproto_v1_3_parser.UINT32_MAX if len(ip_mask) == 2: - mask = int(ip_mask[1]) - netmask = ofproto_v1_3_parser.UINT32_MAX << 32 - mask\ - & ofproto_v1_3_parser.UINT32_MAX + if ip_mask[1].isdigit(): + netmask &= ofproto_v1_3_parser.UINT32_MAX << 32 - int(ip_mask[1]) + else: + netmask = struct.unpack('!I', socket.inet_aton(ip_mask[1]))[0] return ipv4, netmask def to_match_ipv6(value): - ip = netaddr.IPNetwork(value) - return ip.ip.words, ip.netmask.words + ip_mask = value.split('/') + + if len(ip_mask) == 2 and ip_mask[1].isdigit() is False: + ipv6 = netaddr.IPAddress(ip_mask[0]).words + netmask = netaddr.IPAddress(ip_mask[1]).words + else: + network = netaddr.IPNetwork(value) + ipv6 = network.ip.words + netmask = network.netmask.words + + return ipv6, netmask def to_match_metadata(value): @@ -469,8 +479,11 @@ def match_ip_to_str(value, mask): ip = socket.inet_ntoa(struct.pack('!I', value)) if mask is not None and mask != 0: - binary_str = bin(mask)[2:].zfill(8) - netmask = '/%d' % len(binary_str.rstrip('0')) + binary_str = bin(mask)[2:].zfill(32).rstrip('0') + if binary_str.find('0') >= 0: + netmask = '/%s' % socket.inet_ntoa(struct.pack('!I', mask)) + else: + netmask = '/%d' % len(binary_str) else: netmask = '' @@ -484,14 +497,21 @@ def match_ipv6_to_str(value, mask): ip = netaddr.IPNetwork(':'.join(ip_list)) netmask = 128 + netmask_str = None if mask is not None: mask_list = [] for word in mask: mask_list.append('%04x' % word) mask_v = netaddr.IPNetwork(':'.join(mask_list)) - netmask = len(mask_v.ip.bits().replace(':', '').rstrip('0')) + binary_str = mask_v.ip.bits().replace(':', '').zfill(128).rstrip('0') + if binary_str.find('0') >= 0: + netmask_str = str(mask_v.ip) + else: + netmask = len(binary_str) - if netmask == 128: + if netmask_str is not None: + ip_str = str(ip.ip) + '/' + netmask_str + elif netmask == 128: ip_str = str(ip.ip) else: ip.prefixlen = netmask -- 1.7.9.5 ------------------------------------------------------------------------------ Flow-based real-time traffic analytics software. Cisco certified tool. Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer Customize your own dashboards, set traffic alerts and generate reports. Network behavioral analysis & security monitoring. All-in-one tool. http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk _______________________________________________ Ryu-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ryu-devel
