Hi Fujita, Sorry to keep bothering you. As you say, It seems like to corrupted the patch by mailer. I'm very sorry to have troubled you so much.
This appears sent by send-email command Also, created the patch by format-patch. Thank you. Signed-off-by: Kiyonari Harigae <[email protected]> --- ryu/lib/ofctl_v1_3.py | 108 ++++++++++----- ryu/tests/integrated/test_ofctl.py | 271 +++++++++++++++++++++++++++++++++++++ 2 files changed, 345 insertions(+), 34 deletions(-) create mode 100644 ryu/tests/integrated/test_ofctl.py diff --git a/ryu/lib/ofctl_v1_3.py b/ryu/lib/ofctl_v1_3.py index 39d1366..3e2713e 100644 --- a/ryu/lib/ofctl_v1_3.py +++ b/ryu/lib/ofctl_v1_3.py @@ -87,23 +87,7 @@ def to_action(dp, dic): elif action_type == 'SET_FIELD': field = dic.get('field') value = dic.get('value') - if field == 'eth_dst': - field = ofp.OXM_OF_ETH_DST - value = mac.haddr_to_bin(str(value)) - elif field == 'eth_src': - field = ofp.OXM_OF_ETH_SRC - value = mac.haddr_to_bin(str(value)) - elif field == 'vlan_vid': - field = ofp.OXM_OF_VLAN_VID - value = int(value) - elif field == 'mpls_label': - field = ofp.OXM_OF_MPLS_LABEL - value = int(value) - else: - LOG.debug('Unknown field: %s' % field) - return None - f = parser.OFPMatchField.make(field, value) - result = parser.OFPActionSetField(f) + result = parser.OFPActionSetField(**{field: value}) elif action_type == 'PUSH_PBB': ethertype = int(dic.get('ethertype')) result = parser.OFPActionPushPbb(ethertype) @@ -179,17 +163,7 @@ def action_to_str(act): elif action_type == ofproto_v1_3.OFPAT_DEC_NW_TTL: buf = 'DEC_NW_TTL' elif action_type == ofproto_v1_3.OFPAT_SET_FIELD: - if isinstance(act.field, ofproto_v1_3_parser.MTEthDst): - field = 'eth_dst' - elif isinstance(act.field, ofproto_v1_3_parser.MTEthSrc): - field = 'eth_src' - elif isinstance(act.field, ofproto_v1_3_parser.MTVlanVid): - field = 'vlan_vid' - elif isinstance(act.field, ofproto_v1_3_parser.MTMplsLabel): - field = 'mpls_label' - else: - field = '(Unknown field)' - buf = 'SET_FIELD: {%s:%s}' % (field, act.value) + buf = 'SET_FIELD: {%s:%s}' % (act.key, act.value) elif action_type == ofproto_v1_3.OFPAT_PUSH_PBB: buf = 'PUSH_PBB:' + str(act.ethertype) elif action_type == ofproto_v1_3.OFPAT_POP_PBB: @@ -234,12 +208,15 @@ def actions_to_str(instructions): def to_match(dp, attrs): match = dp.ofproto_parser.OFPMatch() - convert = {'in_port': int, + 'in_phy_port': int, 'dl_src': mac.haddr_to_bin, 'dl_dst': mac.haddr_to_bin, 'dl_type': int, 'dl_vlan': int, + 'vlan_pcp': int, + 'ip_dscp': int, + 'ip_ecn': int, 'nw_src': to_match_ip, 'nw_dst': to_match_ip, 'nw_proto': int, @@ -258,16 +235,35 @@ def to_match(dp, attrs): 'tcp_dst': int, 'udp_src': int, 'udp_dst': int, + 'sctp_src': int, + 'sctp_dst': int, + 'icmpv4_type': int, + 'icmpv4_code': int, + 'arp_op': int, 'arp_spa': to_match_ip, 'arp_tpa': to_match_ip, + 'arp_sha': mac.haddr_to_bin, + 'arp_tha': mac.haddr_to_bin, 'ipv6_src': to_match_ipv6, - 'ipv6_dst': to_match_ipv6} + 'ipv6_dst': to_match_ipv6, + 'ipv6_flabel': int, + 'icmpv6_type': int, + 'icmpv6_code': int, + 'ipv6_nd_target': to_match_ipv6, + 'ipv6_nd_sll': mac.haddr_to_bin, + 'ipv6_nd_tll': mac.haddr_to_bin, + 'mpls_tc': int, + 'mpls_bos': int, + 'pbb_isid': int, + 'tunnel_id': int, + 'ipv6_exthdr': int} match_append = {'in_port': match.set_in_port, 'dl_src': match.set_dl_src, 'dl_dst': match.set_dl_dst, 'dl_type': match.set_dl_type, 'dl_vlan': match.set_vlan_vid, + 'vlan_pcp': match.set_vlan_pcp, 'nw_src': match.set_ipv4_src_masked, 'nw_dst': match.set_ipv4_dst_masked, 'nw_proto': match.set_ip_proto, @@ -279,6 +275,8 @@ def to_match(dp, attrs): 'eth_dst': match.set_dl_dst, 'eth_type': match.set_dl_type, 'vlan_vid': match.set_vlan_vid, + 'ip_dscp': match.set_ip_dscp, + 'ip_ecn': match.set_ip_ecn, 'ipv4_src': match.set_ipv4_src_masked, 'ipv4_dst': match.set_ipv4_dst_masked, 'ip_proto': match.set_ip_proto, @@ -286,10 +284,28 @@ def to_match(dp, attrs): 'tcp_dst': to_match_tpdst, 'udp_src': to_match_tpsrc, 'udp_dst': to_match_tpdst, + 'sctp_src': match.set_sctp_src, + 'sctp_dst': match.set_sctp_dst, + 'icmpv4_type': match.set_icmpv4_type, + 'icmpv4_code': match.set_icmpv4_code, + 'arp_op': match.set_arp_opcode, 'arp_spa': match.set_arp_spa_masked, 'arp_tpa': match.set_arp_tpa_masked, + 'arp_sha': match.set_arp_sha, + 'arp_tha': match.set_arp_tha, 'ipv6_src': match.set_ipv6_src_masked, - 'ipv6_dst': match.set_ipv6_dst_masked} + 'ipv6_dst': match.set_ipv6_dst_masked, + 'ipv6_flabel': match.set_ipv6_flabel, + 'icmpv6_type': match.set_icmpv6_type, + 'icmpv6_code': match.set_icmpv6_code, + 'ipv6_nd_target': match.set_ipv6_nd_target, + 'ipv6_nd_sll': match.set_ipv6_nd_sll, + 'ipv6_nd_tll': match.set_ipv6_nd_tll, + 'mpls_tc': match.set_mpls_tc, + 'mpls_bos': match.set_mpls_bos, + 'pbb_isid': match.set_pbb_isid, + 'tunnel_id': match.set_tunnel_id, + 'ipv6_exthdr': match.set_ipv6_exthdr} if attrs.get('dl_type') == ether.ETH_TYPE_ARP or \ attrs.get('eth_type') == ether.ETH_TYPE_ARP: @@ -380,10 +396,14 @@ def to_match_metadata(value): def match_to_str(ofmatch): keys = {ofproto_v1_3.OXM_OF_IN_PORT: 'in_port', + ofproto_v1_3.OXM_OF_IN_PHY_PORT: 'in_phy_port', ofproto_v1_3.OXM_OF_ETH_SRC: 'dl_src', ofproto_v1_3.OXM_OF_ETH_DST: 'dl_dst', ofproto_v1_3.OXM_OF_ETH_TYPE: 'dl_type', ofproto_v1_3.OXM_OF_VLAN_VID: 'dl_vlan', + ofproto_v1_3.OXM_OF_VLAN_PCP: 'vlan_pcp', + ofproto_v1_3.OXM_OF_IP_DSCP: 'ip_dscp', + ofproto_v1_3.OXM_OF_IP_ECN: 'ip_ecn', ofproto_v1_3.OXM_OF_IPV4_SRC: 'nw_src', ofproto_v1_3.OXM_OF_IPV4_DST: 'nw_dst', ofproto_v1_3.OXM_OF_IPV4_SRC_W: 'nw_src', @@ -393,22 +413,42 @@ def match_to_str(ofmatch): ofproto_v1_3.OXM_OF_TCP_DST: 'tp_dst', ofproto_v1_3.OXM_OF_UDP_SRC: 'tp_src', ofproto_v1_3.OXM_OF_UDP_DST: 'tp_dst', + ofproto_v1_3.OXM_OF_SCTP_SRC: 'sctp_src', + ofproto_v1_3.OXM_OF_SCTP_DST: 'sctp_dst', + ofproto_v1_3.OXM_OF_ICMPV4_TYPE: 'icmpv4_type', + ofproto_v1_3.OXM_OF_ICMPV4_CODE: 'icmpv4_code', ofproto_v1_3.OXM_OF_MPLS_LABEL: 'mpls_label', + ofproto_v1_3.OXM_OF_MPLS_TC: 'mpls_tc', + ofproto_v1_3.OXM_OF_MPLS_BOS: 'mpls_bos', ofproto_v1_3.OXM_OF_METADATA: 'metadata', ofproto_v1_3.OXM_OF_METADATA_W: 'metadata', + ofproto_v1_3.OXM_OF_ARP_OP: 'arp_op', ofproto_v1_3.OXM_OF_ARP_SPA: 'arp_spa', ofproto_v1_3.OXM_OF_ARP_TPA: 'arp_tpa', ofproto_v1_3.OXM_OF_ARP_SPA_W: 'arp_spa', ofproto_v1_3.OXM_OF_ARP_TPA_W: 'arp_tpa', + ofproto_v1_3.OXM_OF_ARP_SHA: 'arp_sha', + ofproto_v1_3.OXM_OF_ARP_THA: 'arp_tha', 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'} + ofproto_v1_3.OXM_OF_IPV6_DST_W: 'ipv6_dst', + ofproto_v1_3.OXM_OF_IPV6_FLABEL: 'ipv6_flabel', + ofproto_v1_3.OXM_OF_ICMPV6_TYPE: 'icmpv6_type', + ofproto_v1_3.OXM_OF_ICMPV6_CODE: 'icmpv6_code', + ofproto_v1_3.OXM_OF_IPV6_ND_TARGET: 'ipv6_nd_target', + ofproto_v1_3.OXM_OF_IPV6_ND_SLL: 'ipv6_nd_sll', + ofproto_v1_3.OXM_OF_IPV6_ND_TLL: 'ipv6_nd_tll', + ofproto_v1_3.OXM_OF_PBB_ISID: 'pbb_isid', + ofproto_v1_3.OXM_OF_TUNNEL_ID: 'tunnel_id', + ofproto_v1_3.OXM_OF_IPV6_EXTHDR: 'ipv6_exthdr'} match = {} for match_field in ofmatch.fields: key = keys[match_field.header] - if key == 'dl_src' or key == 'dl_dst': + if key == 'dl_src' or key == 'dl_dst' or key == 'arp_sha' or \ + key == 'arp_tha' or key == 'ipv6_nd_tll' or \ + key == 'ipv6_nd_sll': value = mac.haddr_to_str(match_field.value) elif key == 'nw_src' or key == 'nw_dst' or \ key == 'arp_spa' or key == 'arp_tpa': @@ -490,7 +530,7 @@ def get_desc_stats(dp, waiters): def get_flow_stats(dp, waiters): - table_id = 0 + table_id = dp.ofproto.OFPTT_ALL flags = 0 out_port = dp.ofproto.OFPP_ANY out_group = dp.ofproto.OFPG_ANY diff --git a/ryu/tests/integrated/test_ofctl.py b/ryu/tests/integrated/test_ofctl.py new file mode 100644 index 0000000..4c0c8ee --- /dev/null +++ b/ryu/tests/integrated/test_ofctl.py @@ -0,0 +1,271 @@ +# Copyright 2014 Kiyonari Harigae <lakshmi at cloudysunny14 org> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging + +from ryu.base import app_manager +from ryu.controller import dpset +from ryu.controller.handler import set_ev_cls +from ryu.exception import OFPUnknownVersion +from ryu.lib import ofctl_v1_0 +from ryu.lib import ofctl_v1_2 +from ryu.lib import ofctl_v1_3 +from ryu.lib import hub +from ryu.controller import ofp_event +from ryu.controller import dpset +from ryu.controller.handler import MAIN_DISPATCHER +from ryu.ofproto import ofproto_v1_0 +from ryu.ofproto import ofproto_v1_2 +from ryu.ofproto import ofproto_v1_3 + +LOG = logging.getLogger(__name__) +LOG_TEST_FINISH = 'TEST_FINISHED: Tests=[%s] (OK=%s NG=%s)' + + +def _to_of_flow(match, actions): + LOG.info('ACTIONS:%s', actions) + flow = {'cookie': 0, + 'cookie_mask': 0, + 'priority': 0, + 'table_id': 0, + 'flags': 0, + 'idle_timeout': 0, + 'hard_timeout': 0, + 'match': match, + 'actions': actions} + return flow + + +def _delete_all_flows(dp): + match = dp.ofproto_parser.OFPMatch() + m = dp.ofproto_parser.OFPFlowMod(dp, 0, 0, dp.ofproto.OFPTT_ALL, + dp.ofproto.OFPFC_DELETE, + 0, 0, 0, 0xffffffff, + dp.ofproto.OFPP_ANY, + dp.ofproto.OFPG_ANY, + 0, match, []) + + dp.send_msg(m) + + +class OFCTLTester(app_manager.RyuApp): + + OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] + + _CONTEXTS = {'dpset': dpset.DPSet} + + _OFCTL = {ofproto_v1_0.OFP_VERSION: ofctl_v1_0, + ofproto_v1_2.OFP_VERSION: ofctl_v1_2, + ofproto_v1_3.OFP_VERSION: ofctl_v1_3} + + def __init__(self, *args, **kwargs): + super(OFCTLTester, self).__init__(*args, **kwargs) + self.dpset = kwargs['dpset'] + self.waiters = {} + + def stats_reply_handler(self, ev): + msg = ev.msg + dp = msg.datapath + + if dp.id not in self.waiters: + return + if msg.xid not in self.waiters[dp.id]: + return + lock, msgs = self.waiters[dp.id][msg.xid] + msgs.append(msg) + + flags = 0 + if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION or \ + dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: + flags = dp.ofproto.OFPSF_REPLY_MORE + elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: + flags = dp.ofproto.OFPMPF_REPLY_MORE + + if msg.flags & flags: + return + del self.waiters[dp.id][msg.xid] + lock.set() + + # for OpenFlow version1.0 + @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER) + def stats_reply_handler_v1_0(self, ev): + self.stats_reply_handler(ev) + + # for OpenFlow version1.2 or later + @set_ev_cls(ofp_event.EventOFPStatsReply, MAIN_DISPATCHER) + def stats_reply_handler_v1_2(self, ev): + self.stats_reply_handler(ev) + + @set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER) + def datapath_handler(self, ev): + # Target switch datapath + self.dp = ev.dp + version = self.dp.ofproto.OFP_VERSION + if version not in self._OFCTL: + raise OFPUnknownVersion(version=version) + self.ofctl = self._OFCTL[version] + hub.spawn(self._do_test) + + def _do_test(self): + ofctl = self.ofctl + dp = self.dp + waiters = self.waiters + action_type = {'type': 'SET_FIELD'} + test_actions = [({'field': 'eth_dst', + 'value': '11:11:11:11:11:11'}, + {'in_port': 1}), + ({'field': 'eth_dst', + 'value': '11:11:11:11:11:11'}, + {'in_phy_port': 5}), + ({'field': 'eth_dst', + 'value': '11:11:11:11:11:11'}, + {'dl_dst': '11:11:11:11:11:11'}), + ({'field': 'eth_src', + 'value': '11:11:11:11:11:11'}, + {'dl_src': '11:11:11:11:11:11'}), + ({'field': 'eth_type', + 'value': 2048}, + {'dl_type': 2048}), + ({'field': 'vlan_vid', + 'value': 1}, + {'dl_vlan': 1}), + ({'field': 'vlan_pcp', + 'value': 0}, + {'dl_vlan': 1}), + ({'field': 'ip_dscp', + 'value': 1}, + {'ip_dscp': 1, 'dl_type': 2048}), + ({'field': 'ip_ecn', + 'value': 1}, + {'ip_ecn': 1, 'dl_type': 2048}), + ({'field': 'ipv4_src', + 'value': '10.0.0.2'}, + {'nw_src': '10.0.0.2', 'dl_type': 2048}), + ({'field': 'ipv4_dst', + 'value': '10.0.0.2'}, + {'nw_dst': '10.0.0.2', 'dl_type': 2048}), + ({'field': 'ip_proto', + 'value': 16}, + {'nw_proto': 16, 'dl_type': 2048}), + ({'field': 'tcp_src', + 'value': 5001}, + {'tp_src': 5001, 'dl_type': 2048, 'nw_proto': 6}), + ({'field': 'tcp_dst', + 'value': 5001}, + {'tp_dst': 5001, 'dl_type': 2048, 'nw_proto': 6}), + ({'field': 'sctp_src', + 'value': 5001}, + {'sctp_src': 5001, 'dl_type': 2048, 'nw_proto': 132}), + ({'field': 'sctp_dst', + 'value': 5001}, + {'sctp_dst': 5001, 'dl_type': 2048, 'nw_proto': 132}), + ({'field': 'icmpv4_type', + 'value': 3}, + {'icmpv4_type': 3, 'dl_type': 2048, 'nw_proto': 1}), + ({'field': 'icmpv4_code', + 'value': 1}, + {'icmpv4_type': 1, 'dl_type': 2048, 'nw_proto': 1}), + ({'field': 'mpls_label', + 'value': 10}, + {'mpls_label': 10, 'dl_type': 34887}), + ({'field': 'mpls_tc', + 'value': 8}, + {'mpls_tc': 8, 'dl_type': 34887}), + ({'field': 'mpls_bos', + 'value': 1}, + {'mpls_bos': 1, 'dl_type': 34887}), + ({'field': 'eth_type', + 'value': 2048}, + {'metadata': '12/15'}), + ({'field': 'arp_op', + 'value': 1}, + {'arp_op': 1, 'dl_type': 2054}), + ({'field': 'arp_spa', + 'value': '10.0.1.1'}, + {'arp_spa': '10.0.1.1', 'dl_type': 2054}), + ({'field': 'arp_tpa', + 'value': '10.0.1.1'}, + {'arp_tpa': '10.0.1.1', 'dl_type': 2054}), + ({'field': 'arp_sha', + 'value': '11:11:11:11:11:11'}, + {'arp_sha': '11:11:11:11:11:11', 'dl_type': 2054}), + ({'field': 'arp_tha', + 'value': '11:11:11:11:11:11'}, + {'arp_tha': '11:11:11:11:11:11', 'dl_type': 2054}), + ({'field': 'ipv6_src', + 'value': '2001:db8:bd05:1d2:288a:1fc0:1:10ee'}, + {'ipv6_src': '2001:db8:bd05:1d2:288a:1fc0:1:10ee', + 'dl_type': 34525}), + ({'field': 'ipv6_dst', + 'value': '2001:db8:bd05:1d2:288a:1fc0:1:10ee'}, + {'ipv6_dst': '2001:db8:bd05:1d2:288a:1fc0:1:10ee', + 'dl_type': 34525}), + ({'field': 'ipv6_flabel', + 'value': 1}, + {'ipv6_flabel': 1, 'dl_type': 34525}), + ({'field': 'icmpv6_type', + 'value': 1}, + {'icmpv6_type': 1, 'dl_type': 34525, 'nw_proto': 58}), + ({'field': 'icmpv6_code', + 'value': 1}, + {'icmpv6_code': 1, 'dl_type': 34525, 'nw_proto': 58}), + ({'field': 'ipv6_nd_target', + 'value': '2001:db8:bd05:1d2:288a:1fc0:1:10ee'}, + {'ipv6_nd_target': + '2001:db8:bd05:1d2:288a:1fc0:1:10ee', + 'dl_type': 34525, 'nw_proto': 58, + 'icmpv6_type': 135}), + ({'field': 'ipv6_nd_sll', + 'value': '18:f6:66:b6:f1:b3'}, + {'ipv6_nd_sll': '18:f6:66:b6:f1:b3', + 'dl_type': 34525, 'nw_proto': 58, + 'icmpv6_type': 135}), + ({'field': 'ipv6_nd_tll', + 'value': '18:f6:66:b6:f1:b3'}, + {'ipv6_nd_tll': '18:f6:66:b6:f1:b3', + 'dl_type': 34525, 'nw_proto': 58, + 'icmpv6_type': 136}), + ({'field': 'pbb_isid', + 'value': 11}, + {'pbb_isid': 11, 'dl_type': 35047}), + ({'field': 'tunnel_id', + 'value': 1}, {'tunnel_id': 1}), + ({'field': 'ipv6_exthdr', + 'value': 1}, + {'ipv6_exthdr': 1, + 'dl_type': 34525, 'nw_proto': 58, + 'icmpv6_type': 136})] + ok = 0 + ng = 0 + for action, match in test_actions: + _delete_all_flows(dp) + cmd = dp.ofproto.OFPFC_ADD + action.update(action_type) + flow = _to_of_flow(match, [action]) + result = False + try: + ofctl.mod_flow_entry(dp, flow, cmd) + msg = ofctl.get_flow_stats(dp, waiters) + flow = msg[msg.keys()[0]][0] + result = True + except(Exception): + LOG.info('Exception occured. %s,%s' % (action, match)) + if result and str(flow['actions'][0]) == \ + 'SET_FIELD: {%s:%s}' % \ + (action['field'], action['value']) and \ + flow['match'] == match: + ok = ok + 1 + else: + ng = ng + 1 + LOG.info(LOG_TEST_FINISH, len(test_actions), ok, ng) -- 1.7.12.4 (Apple Git-37) ------------------------------------------------------------------------------ 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
