ofctl_v1_2/3: support IPv6

this patch implements the match conditions using IPv6.

NOTE: OpenFlow1.0 does not support IPv6.

e.g. using ofctl_rest)

curl -X POST -d '{"dpid": 1,
                  "match": {"eth_type": 34525,
                            "ipv6_src": "fe08:2001::/64",
                            "ipv6_dst": "ff02::1"},
                  "actions": [{"type": "OUTPUT",
                               "port": 2}]}' http://localhost:8080/stats/flowentry/add

Signed-off-by: Yuichi Ito <ito.yuichi0@gmail.com>
This commit is contained in:
Yuichi Ito 2013-12-27 10:57:13 +09:00 committed by FUJITA Tomonori
parent 8597df8a00
commit 8e64bc9269
2 changed files with 89 additions and 10 deletions

View File

@ -16,6 +16,7 @@
import struct
import socket
import logging
import netaddr
from ryu.ofproto import inet
from ryu.ofproto import ofproto_v1_2
@ -90,7 +91,9 @@ def to_match(dp, attrs):
'tcp_src': int,
'tcp_dst': int,
'udp_src': int,
'udp_dst': int}
'udp_dst': int,
'ipv6_src': to_match_ipv6,
'ipv6_dst': to_match_ipv6}
match_append = {'in_port': match.set_in_port,
'dl_src': match.set_dl_src,
@ -112,14 +115,17 @@ def to_match(dp, attrs):
'tcp_src': to_match_tpsrc,
'tcp_dst': to_match_tpdst,
'udp_src': to_match_tpsrc,
'udp_dst': to_match_tpdst}
'udp_dst': to_match_tpdst,
'ipv6_src': match.set_ipv6_src_masked,
'ipv6_dst': match.set_ipv6_dst_masked}
for key, value in attrs.items():
if key in convert:
value = convert[key](value)
if key in match_append:
if key == 'nw_src' or key == 'nw_dst' or \
key == 'ipv4_src' or key == 'ipv4_dst':
key == 'ipv4_src' or key == 'ipv4_dst' or \
key == 'ipv6_src' or key == 'ipv6_dst':
# IP address
ip = value[0]
mask = value[1]
@ -128,7 +134,7 @@ def to_match(dp, attrs):
key == 'tcp_src' or key == 'tcp_dst' or \
key == 'udp_src' or key == 'udp_dst':
# tp_src/dst
match = match_append[key](value, match, attrs)
match_append[key](value, match, attrs)
else:
# others
match_append[key](value)
@ -172,6 +178,11 @@ def to_match_ip(value):
return ipv4, netmask
def to_match_ipv6(value):
ip = netaddr.IPNetwork(value)
return ip.ip.words, ip.netmask.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',
@ -186,7 +197,11 @@ def match_to_str(ofmatch):
ofproto_v1_2.OXM_OF_TCP_SRC: 'tp_src',
ofproto_v1_2.OXM_OF_TCP_DST: 'tp_dst',
ofproto_v1_2.OXM_OF_UDP_SRC: 'tp_src',
ofproto_v1_2.OXM_OF_UDP_DST: 'tp_dst'}
ofproto_v1_2.OXM_OF_UDP_DST: 'tp_dst',
ofproto_v1_2.OXM_OF_IPV6_SRC: 'ipv6_src',
ofproto_v1_2.OXM_OF_IPV6_DST: 'ipv6_dst',
ofproto_v1_2.OXM_OF_IPV6_SRC_W: 'ipv6_src',
ofproto_v1_2.OXM_OF_IPV6_DST_W: 'ipv6_dst'}
match = {}
for match_field in ofmatch.fields:
@ -195,6 +210,8 @@ def match_to_str(ofmatch):
value = mac.haddr_to_str(match_field.value)
elif key == 'nw_src' or key == 'nw_dst':
value = match_ip_to_str(match_field.value, match_field.mask)
elif key == 'ipv6_src' or key == 'ipv6_dst':
value = match_ipv6_to_str(match_field.value, match_field.mask)
else:
value = match_field.value
match.setdefault(key, value)
@ -214,6 +231,29 @@ def match_ip_to_str(value, mask):
return ip + netmask
def match_ipv6_to_str(value, mask):
ip_list = []
for word in value:
ip_list.append('%04x' % word)
ip = netaddr.IPNetwork(':'.join(ip_list))
netmask = 128
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'))
if netmask == 128:
ip_str = str(ip.ip)
else:
ip.prefixlen = netmask
ip_str = str(ip)
return ip_str
def send_stats_request(dp, stats, waiters, msgs):
dp.set_xid(stats)
waiters_per_dp = waiters.setdefault(dp.id, {})
@ -263,7 +303,6 @@ def get_flow_stats(dp, waiters):
for stats in msg.body:
actions = actions_to_str(stats.instructions)
match = match_to_str(stats.match)
s = {'priority': stats.priority,
'cookie': stats.cookie,
'idle_timeout': stats.idle_timeout,

View File

@ -16,6 +16,7 @@
import struct
import socket
import logging
import netaddr
from ryu.ofproto import inet
from ryu.ofproto import ofproto_v1_3
@ -223,7 +224,9 @@ def to_match(dp, attrs):
'tcp_src': int,
'tcp_dst': int,
'udp_src': int,
'udp_dst': int}
'udp_dst': int,
'ipv6_src': to_match_ipv6,
'ipv6_dst': to_match_ipv6}
match_append = {'in_port': match.set_in_port,
'dl_src': match.set_dl_src,
@ -247,14 +250,17 @@ def to_match(dp, attrs):
'tcp_src': to_match_tpsrc,
'tcp_dst': to_match_tpdst,
'udp_src': to_match_tpsrc,
'udp_dst': to_match_tpdst}
'udp_dst': to_match_tpdst,
'ipv6_src': match.set_ipv6_src_masked,
'ipv6_dst': match.set_ipv6_dst_masked}
for key, value in attrs.items():
if key in convert:
value = convert[key](value)
if key in match_append:
if key == 'nw_src' or key == 'nw_dst' or \
key == 'ipv4_src' or key == 'ipv4_dst':
key == 'ipv4_src' or key == 'ipv4_dst' or \
key == 'ipv6_src' or key == 'ipv6_dst':
# IP address
ip = value[0]
mask = value[1]
@ -312,6 +318,11 @@ def to_match_ip(value):
return ipv4, netmask
def to_match_ipv6(value):
ip = netaddr.IPNetwork(value)
return ip.ip.words, ip.netmask.words
def to_match_metadata(value):
if '/' in value:
metadata = value.split('/')
@ -336,7 +347,11 @@ def match_to_str(ofmatch):
ofproto_v1_3.OXM_OF_UDP_SRC: 'tp_src',
ofproto_v1_3.OXM_OF_UDP_DST: 'tp_dst',
ofproto_v1_3.OXM_OF_METADATA: 'metadata',
ofproto_v1_3.OXM_OF_METADATA_W: 'metadata'}
ofproto_v1_3.OXM_OF_METADATA_W: 'metadata',
ofproto_v1_3.OXM_OF_IPV6_SRC: 'ipv6_src',
ofproto_v1_3.OXM_OF_IPV6_DST: 'ipv6_dst',
ofproto_v1_3.OXM_OF_IPV6_SRC_W: 'ipv6_src',
ofproto_v1_3.OXM_OF_IPV6_DST_W: 'ipv6_dst'}
match = {}
for match_field in ofmatch.fields:
@ -345,6 +360,8 @@ def match_to_str(ofmatch):
value = mac.haddr_to_str(match_field.value)
elif key == 'nw_src' or key == 'nw_dst':
value = match_ip_to_str(match_field.value, match_field.mask)
elif key == 'ipv6_src' or key == 'ipv6_dst':
value = match_ipv6_to_str(match_field.value, match_field.mask)
elif key == 'metadata':
value = ('%d/%d' % (match_field.value, match_field.mask)
if match_field.mask else '%d' % match_field.value)
@ -367,6 +384,29 @@ def match_ip_to_str(value, mask):
return ip + netmask
def match_ipv6_to_str(value, mask):
ip_list = []
for word in value:
ip_list.append('%04x' % word)
ip = netaddr.IPNetwork(':'.join(ip_list))
netmask = 128
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'))
if netmask == 128:
ip_str = str(ip.ip)
else:
ip.prefixlen = netmask
ip_str = str(ip)
return ip_str
def send_stats_request(dp, stats, waiters, msgs):
dp.set_xid(stats)
waiters_per_dp = waiters.setdefault(dp.id, {})