diff options
author | Yuichi Ito <ito.yuichi0@gmail.com> | 2014-01-14 17:26:46 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-01-15 19:54:39 +0900 |
commit | a3e6dc6706d0449b64a565e1f82a05b95506a3ef (patch) | |
tree | f4967e947432b7a57dfb9b1f94f778554788042f | |
parent | faebcd2b3f273338ea01e0ff54229a5052eb41c3 (diff) |
rest_firewall: support IPv6 match conditions
this patch gets rest_firewall to support IPv6 match conditions.
'ipv6_src' and 'ipv6_dst' are allowed as key.
'ICMPv6' is allowed as the value of 'nw_proto'.
e.g.)
curl -X POST -d '{"ipv6_src": "10::/64"}' http://localhost:8080/firewall/rules/0000000000000001
curl http://localhost:8080/firewall/rules/0000000000000001
[
{
"access_control_list": [
{
"rules": [
{
"priority": 1,
"dl_type": "IPv6",
"ipv6_src": "10::/64",
"rule_id": 1,
"actions": "ALLOW"
}
]
}
],
"switch_id": "0000000000000001"
}
]
Signed-off-by: Yuichi Ito <ito.yuichi0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/app/rest_firewall.py | 141 |
1 files changed, 119 insertions, 22 deletions
diff --git a/ryu/app/rest_firewall.py b/ryu/app/rest_firewall.py index 4710b0b0..3b4e3af5 100644 --- a/ryu/app/rest_firewall.py +++ b/ryu/app/rest_firewall.py @@ -100,10 +100,12 @@ from ryu.ofproto import ofproto_v1_3_parser # "in_port" : "<int>" # "dl_src" : "<xx:xx:xx:xx:xx:xx>" # "dl_dst" : "<xx:xx:xx:xx:xx:xx>" -# "dl_type" : "<ARP or IPv4>" +# "dl_type" : "<ARP or IPv4 or IPv6>" # "nw_src" : "<A.B.C.D/M>" # "nw_dst" : "<A.B.C.D/M>" -# "nw_proto": "<TCP or UDP or ICMP>" +# "ipv6_src": "<xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/M>" +# "ipv6_dst": "<xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/M>" +# "nw_proto": "<TCP or UDP or ICMP or ICMPv6>" # "tp_src" : "<int>" # "tp_dst" : "<int>" # "actions" : "<ALLOW or DENY>" @@ -112,6 +114,10 @@ from ryu.ofproto import ofproto_v1_3_parser # without specifying dl-type as "ARP" or "IPv4" # will automatically set dl-type as "IPv4". # +# Note: specifying ipv6_src/ipv6_dst +# without specifying dl-type as "IPv6" +# will automatically set dl-type as "IPv6". +# # Note: When "priority" has not been set up, # "0" is set to "priority". # @@ -157,13 +163,17 @@ REST_DST_MAC = 'dl_dst' REST_DL_TYPE = 'dl_type' REST_DL_TYPE_ARP = 'ARP' REST_DL_TYPE_IPV4 = 'IPv4' +REST_DL_TYPE_IPV6 = 'IPv6' REST_DL_VLAN = 'dl_vlan' REST_SRC_IP = 'nw_src' REST_DST_IP = 'nw_dst' +REST_SRC_IPV6 = 'ipv6_src' +REST_DST_IPV6 = 'ipv6_dst' REST_NW_PROTO = 'nw_proto' REST_NW_PROTO_TCP = 'TCP' REST_NW_PROTO_UDP = 'UDP' REST_NW_PROTO_ICMP = 'ICMP' +REST_NW_PROTO_ICMPV6 = 'ICMPv6' REST_TP_SRC = 'tp_src' REST_TP_DST = 'tp_dst' REST_ACTION = 'actions' @@ -878,32 +888,114 @@ class Match(object): _CONVERT = {REST_DL_TYPE: {REST_DL_TYPE_ARP: ether.ETH_TYPE_ARP, - REST_DL_TYPE_IPV4: ether.ETH_TYPE_IP}, + REST_DL_TYPE_IPV4: ether.ETH_TYPE_IP, + REST_DL_TYPE_IPV6: ether.ETH_TYPE_IPV6}, REST_NW_PROTO: {REST_NW_PROTO_TCP: inet.IPPROTO_TCP, REST_NW_PROTO_UDP: inet.IPPROTO_UDP, - REST_NW_PROTO_ICMP: inet.IPPROTO_ICMP}} + REST_NW_PROTO_ICMP: inet.IPPROTO_ICMP, + REST_NW_PROTO_ICMPV6: inet.IPPROTO_ICMPV6}} @staticmethod def to_openflow(rest): - match = {} - set_dltype_flg = False - for key, value in rest.items(): - if (key == REST_SRC_IP or key == REST_DST_IP - or key == REST_NW_PROTO): - if (REST_DL_TYPE in rest) is False: - set_dltype_flg = True - elif (rest[REST_DL_TYPE] != REST_DL_TYPE_IPV4 - and rest[REST_DL_TYPE] != REST_DL_TYPE_ARP): - continue + def __inv_combi(msg): + raise ValueError('Invalid combination: [%s]' % msg) - elif key == REST_TP_SRC or key == REST_TP_DST: - if ((REST_NW_PROTO in rest) is False - or (rest[REST_NW_PROTO] != REST_NW_PROTO_TCP - and rest[REST_NW_PROTO] != REST_NW_PROTO_UDP)): - continue + def __inv_2and1(*args): + __inv_combi('%s=%s and %s' % (args[0], args[1], args[2])) + + def __inv_2and2(*args): + __inv_combi('%s=%s and %s=%s' % ( + args[0], args[1], args[2], args[3])) + + def __inv_1and1(*args): + __inv_combi('%s and %s' % (args[0], args[1])) + + def __inv_1and2(*args): + __inv_combi('%s and %s=%s' % (args[0], args[1], args[2])) + + match = {} + # error check + dl_type = rest.get(REST_DL_TYPE) + nw_proto = rest.get(REST_NW_PROTO) + if dl_type is not None: + if dl_type == REST_DL_TYPE_ARP: + if REST_SRC_IPV6 in rest: + __inv_2and1( + REST_DL_TYPE, REST_DL_TYPE_ARP, REST_SRC_IPV6) + if REST_DST_IPV6 in rest: + __inv_2and1( + REST_DL_TYPE, REST_DL_TYPE_ARP, REST_DST_IPV6) + if nw_proto: + __inv_2and1( + REST_DL_TYPE, REST_DL_TYPE_ARP, REST_NW_PROTO) + elif dl_type == REST_DL_TYPE_IPV4: + if REST_SRC_IPV6 in rest: + __inv_2and1( + REST_DL_TYPE, REST_DL_TYPE_IPV4, REST_SRC_IPV6) + if REST_DST_IPV6 in rest: + __inv_2and1( + REST_DL_TYPE, REST_DL_TYPE_IPV4, REST_DST_IPV6) + if nw_proto == REST_NW_PROTO_ICMPV6: + __inv_2and2( + REST_DL_TYPE, REST_DL_TYPE_IPV4, + REST_NW_PROTO, REST_NW_PROTO_ICMPV6) + elif dl_type == REST_DL_TYPE_IPV6: + if REST_SRC_IP in rest: + __inv_2and1( + REST_DL_TYPE, REST_DL_TYPE_IPV6, REST_SRC_IP) + if REST_DST_IP in rest: + __inv_2and1( + REST_DL_TYPE, REST_DL_TYPE_IPV6, REST_DST_IP) + if nw_proto == REST_NW_PROTO_ICMP: + __inv_2and2( + REST_DL_TYPE, REST_DL_TYPE_IPV6, + REST_NW_PROTO, REST_NW_PROTO_ICMP) + else: + raise ValueError('Unknown dl_type : %s' % dl_type) + else: + if REST_SRC_IP in rest: + if REST_SRC_IPV6 in rest: + __inv_1and1(REST_SRC_IP, REST_SRC_IPV6) + if REST_DST_IPV6 in rest: + __inv_1and1(REST_SRC_IP, REST_DST_IPV6) + if nw_proto == REST_NW_PROTO_ICMPV6: + __inv_1and2( + REST_SRC_IP, REST_NW_PROTO, REST_NW_PROTO_ICMPV6) + rest[REST_DL_TYPE] = REST_DL_TYPE_IPV4 + elif REST_DST_IP in rest: + if REST_SRC_IPV6 in rest: + __inv_1and1(REST_DST_IP, REST_SRC_IPV6) + if REST_DST_IPV6 in rest: + __inv_1and1(REST_DST_IP, REST_DST_IPV6) + if nw_proto == REST_NW_PROTO_ICMPV6: + __inv_1and2( + REST_DST_IP, REST_NW_PROTO, REST_NW_PROTO_ICMPV6) + rest[REST_DL_TYPE] = REST_DL_TYPE_IPV4 + elif REST_SRC_IPV6 in rest: + if nw_proto == REST_NW_PROTO_ICMP: + __inv_1and2( + REST_SRC_IPV6, REST_NW_PROTO, REST_NW_PROTO_ICMP) + rest[REST_DL_TYPE] = REST_DL_TYPE_IPV6 + elif REST_DST_IPV6 in rest: + if nw_proto == REST_NW_PROTO_ICMP: + __inv_1and2( + REST_DST_IPV6, REST_NW_PROTO, REST_NW_PROTO_ICMP) + rest[REST_DL_TYPE] = REST_DL_TYPE_IPV6 + else: + if nw_proto == REST_NW_PROTO_ICMP: + rest[REST_DL_TYPE] = REST_DL_TYPE_IPV4 + elif nw_proto == REST_NW_PROTO_ICMPV6: + rest[REST_DL_TYPE] = REST_DL_TYPE_IPV6 + elif nw_proto == REST_NW_PROTO_TCP or \ + nw_proto == REST_NW_PROTO_UDP: + raise ValueError('no dl_type was specified') + else: + raise ValueError('Unknown nw_proto: %s' % nw_proto) + + for key, value in rest.items(): if key in Match._CONVERT: if value in Match._CONVERT[key]: match.setdefault(key, Match._CONVERT[key][value]) @@ -912,9 +1004,6 @@ class Match(object): else: match.setdefault(key, value) - if set_dltype_flg: - match.setdefault(REST_DL_TYPE, ether.ETH_TYPE_IP) - return match @staticmethod @@ -923,6 +1012,7 @@ class Match(object): mac_dontcare = mac.haddr_to_str(mac.DONTCARE) ip_dontcare = '0.0.0.0' + ipv6_dontcare = '::' match = {} for key, value in of_match.items(): @@ -932,6 +1022,9 @@ class Match(object): elif key == REST_SRC_IP or key == REST_DST_IP: if value == ip_dontcare: continue + elif key == REST_SRC_IPV6 or key == REST_DST_IPV6: + if value == ipv6_dontcare: + continue elif value == 0: continue @@ -948,6 +1041,7 @@ class Match(object): def to_mod_openflow(of_match): mac_dontcare = mac.haddr_to_str(mac.DONTCARE) ip_dontcare = '0.0.0.0' + ipv6_dontcare = '::' match = {} for key, value in of_match.items(): @@ -957,6 +1051,9 @@ class Match(object): elif key == REST_SRC_IP or key == REST_DST_IP: if value == ip_dontcare: continue + elif key == REST_SRC_IPV6 or key == REST_DST_IPV6: + if value == ipv6_dontcare: + continue elif value == 0: continue |