diff options
Diffstat (limited to 'tests/mininet')
-rw-r--r-- | tests/mininet/l2/mpls/PopMPLS_mpls.mn | 6 | ||||
-rw-r--r-- | tests/mininet/l2/mpls/PushMPLS_ip.mn | 6 | ||||
-rw-r--r-- | tests/mininet/l2/mpls/PushMPLS_mpls.mn | 6 | ||||
-rw-r--r-- | tests/mininet/l2/mpls/test_mpls.py | 127 | ||||
-rw-r--r-- | tests/mininet/l2/vlan/PopVLAN_vlan.mn | 6 | ||||
-rw-r--r-- | tests/mininet/l2/vlan/PopVLAN_vlanvlan.mn | 6 | ||||
-rw-r--r-- | tests/mininet/l2/vlan/PushVLAN_icmp.mn | 6 | ||||
-rw-r--r-- | tests/mininet/l2/vlan/test_vlan.py | 130 | ||||
-rw-r--r-- | tests/mininet/l3/icmp/ICMP_ping.mn | 6 | ||||
-rw-r--r-- | tests/mininet/l3/icmp/ICMP_reply.mn | 6 | ||||
-rw-r--r-- | tests/mininet/l3/icmp/test_icmp.py | 84 | ||||
-rw-r--r-- | tests/mininet/l3/ip_ttl/DecNwTtl.mn | 6 | ||||
-rw-r--r-- | tests/mininet/l3/ip_ttl/test_ip_ttl.py | 84 | ||||
-rw-r--r-- | tests/mininet/packet_lib/arp/ARP_gratuitous.mn | 7 | ||||
-rw-r--r-- | tests/mininet/packet_lib/arp/ARP_reply.mn | 7 | ||||
-rw-r--r-- | tests/mininet/packet_lib/arp/ARP_request.mn | 7 | ||||
-rw-r--r-- | tests/mininet/packet_lib/arp/test_arp.py | 199 | ||||
-rwxr-xr-x | tests/mininet/run_mnet-test.sh | 274 |
18 files changed, 973 insertions, 0 deletions
diff --git a/tests/mininet/l2/mpls/PopMPLS_mpls.mn b/tests/mininet/l2/mpls/PopMPLS_mpls.mn new file mode 100644 index 00000000..45fa9f96 --- /dev/null +++ b/tests/mininet/l2/mpls/PopMPLS_mpls.mn @@ -0,0 +1,6 @@ +TEST_NAME=MPLS-PopMPLS +DUMP_HOST=h2 +DUMP_IF=h2-eth0 +RYU_APP=test_mpls +PCAP_MZ="-t tcp -M 80 -P $TEST_NAME -c 3 -r" +PCAP_FILTER="! mpls && ip.proto==TCP" diff --git a/tests/mininet/l2/mpls/PushMPLS_ip.mn b/tests/mininet/l2/mpls/PushMPLS_ip.mn new file mode 100644 index 00000000..2634e788 --- /dev/null +++ b/tests/mininet/l2/mpls/PushMPLS_ip.mn @@ -0,0 +1,6 @@ +TEST_NAME=IP-PushMPLS +DUMP_HOST=h2 +DUMP_IF=h2-eth0 +RYU_APP=test_mpls +PCAP_MZ="-t tcp -P $TEST_NAME -c 3 -b 00:00:00:00:00:02" +PCAP_FILTER="mpls && ip.proto==TCP" diff --git a/tests/mininet/l2/mpls/PushMPLS_mpls.mn b/tests/mininet/l2/mpls/PushMPLS_mpls.mn new file mode 100644 index 00000000..5ac1702f --- /dev/null +++ b/tests/mininet/l2/mpls/PushMPLS_mpls.mn @@ -0,0 +1,6 @@ +TEST_NAME=MPLS-PushMPLS +DUMP_HOST=h2 +DUMP_IF=h2-eth0 +RYU_APP=test_mpls +PCAP_MZ="-t tcp -M 100 -P $TEST_NAME -c 3 -r" +PCAP_FILTER="mpls.label==100 && mpls.label==200 && ip.proto==TCP" diff --git a/tests/mininet/l2/mpls/test_mpls.py b/tests/mininet/l2/mpls/test_mpls.py new file mode 100644 index 00000000..3090a08c --- /dev/null +++ b/tests/mininet/l2/mpls/test_mpls.py @@ -0,0 +1,127 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# 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 +import struct + +from ryu.base import app_manager +from ryu.controller import ofp_event +from ryu.controller import dpset +from ryu.controller.handler import MAIN_DISPATCHER +from ryu.controller.handler import set_ev_cls +from ryu.ofproto import ofproto_v1_2 +from ryu.ofproto import ether +from ryu.lib.mac import haddr_to_str + + +LOG = logging.getLogger(__name__) + + +class RunTestMininet(app_manager.RyuApp): + + _CONTEXTS = {'dpset': dpset.DPSet} + OFP_VERSIONS = [ofproto_v1_2.OFP_VERSION] + + def __init__(self, *args, **kwargs): + super(RunTestMininet, self).__init__(*args, **kwargs) + + def _add_flow(self, dp, match, actions): + inst = [dp.ofproto_parser.OFPInstructionActions( + dp.ofproto.OFPIT_APPLY_ACTIONS, actions)] + + mod = dp.ofproto_parser.OFPFlowMod( + dp, cookie=0, cookie_mask=0, table_id=0, + command=dp.ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, + priority=0xff, buffer_id=0xffffffff, + out_port=dp.ofproto.OFPP_ANY, out_group=dp.ofproto.OFPG_ANY, + flags=0, match=match, instructions=inst) + + dp.send_msg(mod) + + def _define_flow(self, dp): + in_port = 1 + out_port = 2 + + eth_IP = ether.ETH_TYPE_IP + eth_MPLS = ether.ETH_TYPE_MPLS + + # MPLS(80) -> PopMPLS + LOG.debug("--- add_flow PopMPLS") + m_label = 80 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + match.set_dl_type(eth_MPLS) + match.set_mpls_label(m_label) + actions = [dp.ofproto_parser.OFPActionPopMpls(eth_IP), + dp.ofproto_parser.OFPActionOutput(out_port, 0)] + self._add_flow(dp, match, actions) + + # IP -> PushMPLS(90) + LOG.debug("--- add_flow PushMPLS") + s_label = 90 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + match.set_dl_type(eth_IP) + f = dp.ofproto_parser.OFPMatchField.make( + dp.ofproto.OXM_OF_MPLS_LABEL, s_label) + actions = [dp.ofproto_parser.OFPActionPushMpls(eth_MPLS), + dp.ofproto_parser.OFPActionSetField(f), + dp.ofproto_parser.OFPActionOutput(out_port, 0)] + self._add_flow(dp, match, actions) + + # MPLS(100) -> PushMPLS(200) + LOG.debug("--- add_flow PushMPLS") + m_label = 100 + s_label = 200 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + match.set_dl_type(eth_MPLS) + match.set_mpls_label(m_label) + f = dp.ofproto_parser.OFPMatchField.make( + dp.ofproto.OXM_OF_MPLS_LABEL, s_label) + actions = [dp.ofproto_parser.OFPActionPushMpls(eth_MPLS), + dp.ofproto_parser.OFPActionSetField(f), + dp.ofproto_parser.OFPActionOutput(out_port, 0)] + self._add_flow(dp, match, actions) + + # MPLS(1000):MPLS -> PopMPLS + # LOG.debug("--- add_flow PopMPLS") + # SKIP: ovs not supported + m_label = 1000 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + match.set_dl_type(eth_MPLS) + match.set_mpls_label(m_label) + actions = [dp.ofproto_parser.OFPActionPopMpls(eth_MPLS), + dp.ofproto_parser.OFPActionOutput(out_port, 0)] + # self._add_flow(dp, match, actions) + + @set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER) + def handler_datapath(self, ev): + if ev.enter: + self._define_flow(ev.dp) + + @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) + def packet_in_handler(self, ev): + msg = ev.msg + dst, src, eth_type = struct.unpack_from('!6s6sH', buffer(msg.data), 0) + in_port = msg.match.fields[0].value + + LOG.info("----------------------------------------") + LOG.info("* PacketIn") + LOG.info("in_port=%d, eth_type: %s", in_port, hex(eth_type)) + LOG.info("packet reason=%d buffer_id=%d", msg.reason, msg.buffer_id) + LOG.info("packet in datapath_id=%s src=%s dst=%s", + msg.datapath.id, haddr_to_str(src), haddr_to_str(dst)) diff --git a/tests/mininet/l2/vlan/PopVLAN_vlan.mn b/tests/mininet/l2/vlan/PopVLAN_vlan.mn new file mode 100644 index 00000000..f1d1c6dd --- /dev/null +++ b/tests/mininet/l2/vlan/PopVLAN_vlan.mn @@ -0,0 +1,6 @@ +TEST_NAME=VLAN-PopVLAN +DUMP_HOST=h2 +DUMP_IF=h2-eth0 +RYU_APP=test_vlan +PCAP_MZ="-t tcp -Q 8 -P $TEST_NAME -c 3 -r" +PCAP_FILTER="! vlan && ip.proto==TCP" diff --git a/tests/mininet/l2/vlan/PopVLAN_vlanvlan.mn b/tests/mininet/l2/vlan/PopVLAN_vlanvlan.mn new file mode 100644 index 00000000..90444a75 --- /dev/null +++ b/tests/mininet/l2/vlan/PopVLAN_vlanvlan.mn @@ -0,0 +1,6 @@ +TEST_NAME=VLAN:VLAN-PopVLAN +DUMP_HOST=h2 +DUMP_IF=h2-eth0 +RYU_APP=test_vlan +PCAP_MZ="-t tcp -Q 100,99 -P $TEST_NAME -c 3 -r" +PCAP_FILTER="vlan.id!=100 && vlan.id==99 && ip.proto==TCP" diff --git a/tests/mininet/l2/vlan/PushVLAN_icmp.mn b/tests/mininet/l2/vlan/PushVLAN_icmp.mn new file mode 100644 index 00000000..439ad233 --- /dev/null +++ b/tests/mininet/l2/vlan/PushVLAN_icmp.mn @@ -0,0 +1,6 @@ +TEST_NAME=ICMP-PushVLAN +DUMP_HOST=h2 +DUMP_IF=h2-eth0 +RYU_APP=test_vlan +PCAP_MZ="-t icmp ping -P $TEST_NAME -c 3 -r -b 00:00:00:00:00:02" +PCAP_FILTER="vlan && icmp.type==8" diff --git a/tests/mininet/l2/vlan/test_vlan.py b/tests/mininet/l2/vlan/test_vlan.py new file mode 100644 index 00000000..0b1be7fc --- /dev/null +++ b/tests/mininet/l2/vlan/test_vlan.py @@ -0,0 +1,130 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# 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 +import struct + +from ryu.base import app_manager +from ryu.controller import ofp_event +from ryu.controller import dpset +from ryu.controller.handler import MAIN_DISPATCHER +from ryu.controller.handler import set_ev_cls +from ryu.ofproto import ofproto_v1_2 +from ryu.ofproto import ether +from ryu.ofproto import inet +from ryu.lib.mac import haddr_to_str + + +LOG = logging.getLogger(__name__) + + +class RunTestMininet(app_manager.RyuApp): + + _CONTEXTS = {'dpset': dpset.DPSet} + OFP_VERSIONS = [ofproto_v1_2.OFP_VERSION] + + def __init__(self, *args, **kwargs): + super(RunTestMininet, self).__init__(*args, **kwargs) + + def _add_flow(self, dp, match, actions): + inst = [dp.ofproto_parser.OFPInstructionActions( + dp.ofproto.OFPIT_APPLY_ACTIONS, actions)] + + mod = dp.ofproto_parser.OFPFlowMod( + dp, cookie=0, cookie_mask=0, table_id=0, + command=dp.ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, + priority=0xff, buffer_id=0xffffffff, + out_port=dp.ofproto.OFPP_ANY, out_group=dp.ofproto.OFPG_ANY, + flags=0, match=match, instructions=inst) + + dp.send_msg(mod) + + def _define_flow(self, dp): + in_port = 1 + out_port = 2 + + eth_IP = ether.ETH_TYPE_IP + eth_VLAN = ether.ETH_TYPE_8021Q + ip_ICMP = inet.IPPROTO_ICMP + + # VLAN(8) -> PopVLAN + LOG.debug("--- add_flow VLAN(8) to PopVLAN") + m_vid = 8 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + match.set_dl_type(eth_IP) + match.set_vlan_vid(m_vid) + actions = [dp.ofproto_parser.OFPActionPopVlan(), + dp.ofproto_parser.OFPActionOutput(out_port, 0)] + self._add_flow(dp, match, actions) + + # ICMP -> PushVLAN(9) + LOG.debug("--- add_flow ICMP to PushVLAN(9)") + s_vid = 9 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + match.set_dl_type(eth_IP) + match.set_ip_proto(ip_ICMP) + f = dp.ofproto_parser.OFPMatchField.make( + dp.ofproto.OXM_OF_VLAN_VID, s_vid) + actions = [dp.ofproto_parser.OFPActionPushVlan(eth_VLAN), + dp.ofproto_parser.OFPActionSetField(f), + dp.ofproto_parser.OFPActionOutput(out_port, 0)] + self._add_flow(dp, match, actions) + + # VLAN(10) -> PushVLAN(20) + # LOG.debug("--- add_flow VLAN(10) to PushVLAN(100)") + # SKIP: ovs not supported + m_vid = 10 + s_vid = 20 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + match.set_dl_type(eth_IP) + match.set_vlan_vid(m_vid) + f = dp.ofproto_parser.OFPMatchField.make( + dp.ofproto.OXM_OF_VLAN_VID, s_vid) + actions = [dp.ofproto_parser.OFPActionPushVlan(eth_VLAN), + dp.ofproto_parser.OFPActionSetField(f), + dp.ofproto_parser.OFPActionOutput(out_port, 0)] + # self._add_flow(dp, match, actions) + + # VLAN(100):VLAN -> PopVLAN + LOG.debug("--- add_flow VLAN(100):VLAN to PopVLAN") + m_vid = 100 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + match.set_dl_type(eth_VLAN) + match.set_vlan_vid(m_vid) + actions = [dp.ofproto_parser.OFPActionPopVlan(), + dp.ofproto_parser.OFPActionOutput(out_port, 0)] + self._add_flow(dp, match, actions) + + @set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER) + def handler_datapath(self, ev): + if ev.enter: + self._define_flow(ev.dp) + + @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) + def packet_in_handler(self, ev): + msg = ev.msg + dst, src, eth_type = struct.unpack_from('!6s6sH', buffer(msg.data), 0) + in_port = msg.match.fields[0].value + + LOG.info("----------------------------------------") + LOG.info("* PacketIn") + LOG.info("in_port=%d, eth_type: %s", in_port, hex(eth_type)) + LOG.info("packet reason=%d buffer_id=%d", msg.reason, msg.buffer_id) + LOG.info("packet in datapath_id=%s src=%s dst=%s", + msg.datapath.id, haddr_to_str(src), haddr_to_str(dst)) diff --git a/tests/mininet/l3/icmp/ICMP_ping.mn b/tests/mininet/l3/icmp/ICMP_ping.mn new file mode 100644 index 00000000..f558693d --- /dev/null +++ b/tests/mininet/l3/icmp/ICMP_ping.mn @@ -0,0 +1,6 @@ +TEST_NAME=ICMP-Req +DUMP_HOST=h2 +DUMP_IF=h2-eth0 +RYU_APP=test_icmp +PCAP_MZ="-t icmp ping -c 3 -r -b 00:00:00:00:00:00" +PCAP_FILTER="icmp.type==8" diff --git a/tests/mininet/l3/icmp/ICMP_reply.mn b/tests/mininet/l3/icmp/ICMP_reply.mn new file mode 100644 index 00000000..eb6bc8b6 --- /dev/null +++ b/tests/mininet/l3/icmp/ICMP_reply.mn @@ -0,0 +1,6 @@ +TEST_NAME=ICMP-Reply +DUMP_HOST=h1 +DUMP_IF=h1-eth0 +RYU_APP=test_icmp +PCAP_MZ="-t icmp ping -c 3 -r -B h2" +PCAP_FILTER="icmp.type==0" diff --git a/tests/mininet/l3/icmp/test_icmp.py b/tests/mininet/l3/icmp/test_icmp.py new file mode 100644 index 00000000..090f83e5 --- /dev/null +++ b/tests/mininet/l3/icmp/test_icmp.py @@ -0,0 +1,84 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# 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 +import struct + +from ryu.base import app_manager +from ryu.controller import ofp_event +from ryu.controller import dpset +from ryu.controller.handler import MAIN_DISPATCHER +from ryu.controller.handler import set_ev_cls +from ryu.ofproto import ofproto_v1_2 +from ryu.lib.mac import haddr_to_str + + +LOG = logging.getLogger(__name__) + + +class RunTestMininet(app_manager.RyuApp): + + _CONTEXTS = {'dpset': dpset.DPSet} + OFP_VERSIONS = [ofproto_v1_2.OFP_VERSION] + + def __init__(self, *args, **kwargs): + super(RunTestMininet, self).__init__(*args, **kwargs) + + def _add_flow(self, dp, match, actions): + inst = [dp.ofproto_parser.OFPInstructionActions( + dp.ofproto.OFPIT_APPLY_ACTIONS, actions)] + + mod = dp.ofproto_parser.OFPFlowMod( + dp, cookie=0, cookie_mask=0, table_id=0, + command=dp.ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, + priority=0xff, buffer_id=0xffffffff, + out_port=dp.ofproto.OFPP_ANY, out_group=dp.ofproto.OFPG_ANY, + flags=0, match=match, instructions=inst) + + dp.send_msg(mod) + + def _define_flow(self, dp): + in_port = 1 + out_port = 2 + + # port:1 -> port:2 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + actions = [dp.ofproto_parser.OFPActionOutput(out_port, 0)] + self._add_flow(dp, match, actions) + + # port:1 -> port:2 + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(out_port) + actions = [dp.ofproto_parser.OFPActionOutput(in_port, 0)] + self._add_flow(dp, match, actions) + + @set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER) + def handler_datapath(self, ev): + if ev.enter: + self._define_flow(ev.dp) + + @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) + def packet_in_handler(self, ev): + msg = ev.msg + dst, src, eth_type = struct.unpack_from('!6s6sH', buffer(msg.data), 0) + in_port = msg.match.fields[0].value + + LOG.info("----------------------------------------") + LOG.info("* PacketIn") + LOG.info("in_port=%d, eth_type: %s", in_port, hex(eth_type)) + LOG.info("packet reason=%d buffer_id=%d", msg.reason, msg.buffer_id) + LOG.info("packet in datapath_id=%s src=%s dst=%s", + msg.datapath.id, haddr_to_str(src), haddr_to_str(dst)) diff --git a/tests/mininet/l3/ip_ttl/DecNwTtl.mn b/tests/mininet/l3/ip_ttl/DecNwTtl.mn new file mode 100644 index 00000000..60cd4623 --- /dev/null +++ b/tests/mininet/l3/ip_ttl/DecNwTtl.mn @@ -0,0 +1,6 @@ +TEST_NAME=DecNwTtl +DUMP_HOST=h2 +DUMP_IF=h2-eth0 +RYU_APP=test_ip_ttl +PCAP_MZ="-t icmp ttl=64 -P $TEST_NAME -c 3 -b 00:00:00:00:00:02" +PCAP_FILTER="icmp && ip.ttl==63" diff --git a/tests/mininet/l3/ip_ttl/test_ip_ttl.py b/tests/mininet/l3/ip_ttl/test_ip_ttl.py new file mode 100644 index 00000000..f6f00ab9 --- /dev/null +++ b/tests/mininet/l3/ip_ttl/test_ip_ttl.py @@ -0,0 +1,84 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# 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 +import struct + +from ryu.base import app_manager +from ryu.controller import ofp_event +from ryu.controller import dpset +from ryu.controller.handler import MAIN_DISPATCHER +from ryu.controller.handler import set_ev_cls +from ryu.ofproto import ofproto_v1_2 +from ryu.ofproto import ether +from ryu.lib.mac import haddr_to_str + + +LOG = logging.getLogger(__name__) + + +class RunTestMininet(app_manager.RyuApp): + + _CONTEXTS = {'dpset': dpset.DPSet} + OFP_VERSIONS = [ofproto_v1_2.OFP_VERSION] + + def __init__(self, *args, **kwargs): + super(RunTestMininet, self).__init__(*args, **kwargs) + + def _add_flow(self, dp, match, actions): + inst = [dp.ofproto_parser.OFPInstructionActions( + dp.ofproto.OFPIT_APPLY_ACTIONS, actions)] + + mod = dp.ofproto_parser.OFPFlowMod( + dp, cookie=0, cookie_mask=0, table_id=0, + command=dp.ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, + priority=0xff, buffer_id=0xffffffff, + out_port=dp.ofproto.OFPP_ANY, out_group=dp.ofproto.OFPG_ANY, + flags=0, match=match, instructions=inst) + + dp.send_msg(mod) + + def _define_flow(self, dp): + in_port = 1 + out_port = 2 + + eth_IP = ether.ETH_TYPE_IP + + # ICMP -> DecNwTtl + LOG.debug("--- add_flow DecNwTtl") + match = dp.ofproto_parser.OFPMatch() + match.set_in_port(in_port) + match.set_dl_type(eth_IP) + actions = [dp.ofproto_parser.OFPActionDecNwTtl(), + dp.ofproto_parser.OFPActionOutput(out_port, 0)] + self._add_flow(dp, match, actions) + + @set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER) + def handler_datapath(self, ev): + if ev.enter: + self._define_flow(ev.dp) + + @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) + def packet_in_handler(self, ev): + msg = ev.msg + dst, src, eth_type = struct.unpack_from('!6s6sH', buffer(msg.data), 0) + in_port = msg.match.fields[0].value + + LOG.info("----------------------------------------") + LOG.info("* PacketIn") + LOG.info("in_port=%d, eth_type: %s", in_port, hex(eth_type)) + LOG.info("packet reason=%d buffer_id=%d", msg.reason, msg.buffer_id) + LOG.info("packet in datapath_id=%s src=%s dst=%s", + msg.datapath.id, haddr_to_str(src), haddr_to_str(dst)) diff --git a/tests/mininet/packet_lib/arp/ARP_gratuitous.mn b/tests/mininet/packet_lib/arp/ARP_gratuitous.mn new file mode 100644 index 00000000..ca7a30ae --- /dev/null +++ b/tests/mininet/packet_lib/arp/ARP_gratuitous.mn @@ -0,0 +1,7 @@ +# test-GratuitousARP-request +TEST_NAME=GARP-Request +DUMP_HOST=h1 +DUMP_IF=h1-eth0 +RYU_APP=test_arp +PCAP_MZ="-S" +PCAP_FILTER="arp.isgratuitous && arp.src.proto_ipv4==10.0.0.100 && arp.src.hw_mac==fe:ee:ee:ee:ee:ef" diff --git a/tests/mininet/packet_lib/arp/ARP_reply.mn b/tests/mininet/packet_lib/arp/ARP_reply.mn new file mode 100644 index 00000000..3969cba1 --- /dev/null +++ b/tests/mininet/packet_lib/arp/ARP_reply.mn @@ -0,0 +1,7 @@ +# test-ARP-reply +TEST_NAME=ARP-Reply +DUMP_HOST=h1 +DUMP_IF=h1-eth0 +RYU_APP=test_arp +PCAP_MZ="-t arp request,targetip=10.0.0.100 -c 3 -r" +PCAP_FILTER="arp.opcode==reply && arp.src.proto_ipv4==10.0.0.100 && arp.src.hw_mac==fe:ee:ee:ee:ee:ef" diff --git a/tests/mininet/packet_lib/arp/ARP_request.mn b/tests/mininet/packet_lib/arp/ARP_request.mn new file mode 100644 index 00000000..b44450ef --- /dev/null +++ b/tests/mininet/packet_lib/arp/ARP_request.mn @@ -0,0 +1,7 @@ +# test-ARP-request +TEST_NAME=ARP-Request +DUMP_HOST=h1 +DUMP_IF=h1-eth0 +RYU_APP=test_arp +PCAP_MZ="-t arp request,targetip=10.0.0.1" +PCAP_FILTER="arp.opcode==request && arp.src.proto_ipv4==10.0.0.100 && arp.dst.proto_ipv4==10.0.0.1 && arp.src.hw_mac==fe:ee:ee:ee:ee:ef" diff --git a/tests/mininet/packet_lib/arp/test_arp.py b/tests/mininet/packet_lib/arp/test_arp.py new file mode 100644 index 00000000..39948f54 --- /dev/null +++ b/tests/mininet/packet_lib/arp/test_arp.py @@ -0,0 +1,199 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# 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. + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +import logging +import array +import netaddr + +from ryu.base import app_manager +from ryu.controller import dpset +from ryu.controller import ofp_event +from ryu.controller import handler +from ryu.ofproto import ofproto_v1_2 +from ryu.ofproto import ether +from ryu.ofproto import inet +from ryu.lib import mac +from ryu.lib.packet import packet +from ryu.lib.packet import ethernet +from ryu.lib.packet import arp +from ryu.lib.packet import ipv4 +from ryu.lib.packet import icmp + + +LOG = logging.getLogger(__name__) + + +class RunTestMininet(app_manager.RyuApp): + + _CONTEXTS = {'dpset': dpset.DPSet} + OFP_VERSIONS = [ofproto_v1_2.OFP_VERSION] + + ZERO_MAC = mac.haddr_to_bin('00:00:00:00:00:00') + BROADCAST_MAC = mac.haddr_to_bin('ff:ff:ff:ff:ff:ff') + RYU_MAC = mac.haddr_to_bin('fe:ee:ee:ee:ee:ef') + HOST_MAC = mac.haddr_to_bin('00:00:00:00:00:01') + RYU_IP = int(netaddr.IPAddress('10.0.0.100')) + HOST_IP = int(netaddr.IPAddress('10.0.0.1')) + + def __init__(self, *args, **kwargs): + super(RunTestMininet, self).__init__(*args, **kwargs) + + def _send_msg(self, dp, data): + buffer_id = 0xffffffff + in_port = dp.ofproto.OFPP_LOCAL + actions = [dp.ofproto_parser.OFPActionOutput(1, 0)] + msg = dp.ofproto_parser.OFPPacketOut( + dp, buffer_id, in_port, actions, data) + dp.send_msg(msg) + + def _add_flow(self, dp, match, actions): + inst = [dp.ofproto_parser.OFPInstructionActions( + dp.ofproto.OFPIT_APPLY_ACTIONS, actions)] + mod = dp.ofproto_parser.OFPFlowMod( + dp, cookie=0, cookie_mask=0, table_id=0, + command=dp.ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, + priority=0xff, buffer_id=0xffffffff, + out_port=dp.ofproto.OFPP_ANY, out_group=dp.ofproto.OFPG_ANY, + flags=0, match=match, instructions=inst) + dp.send_msg(mod) + + def _find_protocol(self, pkt, name): + for p in pkt.protocols: + if hasattr(p, 'protocol_name'): + if p.protocol_name == name: + return p + + def _get_protocols(self, pkt): + protocols = {} + for p in pkt: + if hasattr(p, 'protocol_name'): + protocols[p.protocol_name] = p + else: + protocols['payload'] = p + return protocols + + def _build_ether(self, ethertype, dst_mac=HOST_MAC): + e = ethernet.ethernet(dst_mac, self.RYU_MAC, ethertype) + return e + + def _build_arp(self, opcode, dst_ip=HOST_IP): + if opcode == arp.ARP_REQUEST: + _eth_dst_mac = self.BROADCAST_MAC + _arp_dst_mac = self.ZERO_MAC + elif opcode == arp.ARP_REPLY: + _eth_dst_mac = self.HOST_MAC + _arp_dst_mac = self.HOST_MAC + + e = self._build_ether(ether.ETH_TYPE_ARP, _eth_dst_mac) + a = arp.arp(hwtype=1, proto=ether.ETH_TYPE_IP, hlen=6, plen=4, + opcode=opcode, src_mac=self.RYU_MAC, src_ip=self.RYU_IP, + dst_mac=_arp_dst_mac, dst_ip=dst_ip) + p = packet.Packet() + p.add_protocol(e) + p.add_protocol(a) + p.serialize() + + return p + + def _build_echo(self, _type, echo): + e = self._build_ether(ether.ETH_TYPE_IP) + ip = ipv4.ipv4(version=4, header_length=5, tos=0, total_length=84, + identification=0, flags=0, offset=0, ttl=64, + proto=inet.IPPROTO_ICMP, csum=0, + src=self.RYU_IP, dst=self.HOST_IP) + ping = icmp.icmp(_type, code=0, csum=0, data=echo) + + p = packet.Packet() + p.add_protocol(e) + p.add_protocol(ip) + p.add_protocol(ping) + p.serialize() + return p + + def _garp(self): + p = self._build_arp(arp.ARP_REQUEST, self.RYU_IP) + return p.data + + def _arp_request(self): + p = self._build_arp(arp.ARP_REQUEST, self.HOST_IP) + return p.data + + def _arp_reply(self): + p = self._build_arp(arp.ARP_REPLY, self.HOST_IP) + return p.data + + def _echo_request(self, echo): + p = self._build_echo(icmp.ICMP_ECHO_REQUEST, echo) + return p.data + + def _echo_reply(self, echo): + p = self._build_echo(icmp.ICMP_ECHO_REPLY, echo) + return p.data + + @handler.set_ev_cls(ofp_event.EventOFPPacketIn, handler.MAIN_DISPATCHER) + def packet_in_handler(self, ev): + msg = ev.msg + dp = msg.datapath + + pkt = packet.Packet(array.array('B', msg.data)) + p_arp = self._find_protocol(pkt, "arp") + p_icmp = self._find_protocol(pkt, "icmp") + p_ipv4 = self._find_protocol(pkt, "ipv4") + + if p_arp: + src_ip = str(netaddr.IPAddress(p_arp.src_ip)) + dst_ip = str(netaddr.IPAddress(p_arp.dst_ip)) + if p_arp.opcode == arp.ARP_REQUEST: + LOG.debug("--- PacketIn: ARP_Request: %s->%s", src_ip, dst_ip) + if p_arp.dst_ip == self.RYU_IP: + LOG.debug("--- send Pkt: ARP_Reply") + data = self._arp_reply() + self._send_msg(dp, data) + elif p_arp.dst_ip == self.HOST_IP: + LOG.debug(" PacketIn: GARP") + LOG.debug("--- send Pkt: ARP_Request") + data = self._arp_request() + self._send_msg(dp, data) + elif p_arp.opcode == arp.ARP_REPLY: + LOG.debug("--- PacketIn: ARP_Reply: %s->%s", src_ip, dst_ip) + LOG.debug("--- send Pkt: Echo_Request") + echo = icmp.echo(id_=66, seq=1) + data = self._echo_request(echo) + self._send_msg(dp, data) + + if p_icmp: + src = str(netaddr.IPAddress(p_ipv4.src)) + dst = str(netaddr.IPAddress(p_ipv4.dst)) + if p_icmp.type == icmp.ICMP_ECHO_REQUEST: + LOG.debug("--- PacketIn: Echo_Request: %s->%s", src, dst) + if p_ipv4.dst == self.RYU_IP: + LOG.debug("--- send Pkt: Echo_Reply") + echo = p_icmp.data + echo.data = bytearray(echo.data) + data = self._echo_reply(echo) + self._send_msg(dp, data) + elif p_icmp.type == icmp.ICMP_ECHO_REPLY: + LOG.debug("--- PacketIn: Echo_Reply: %s->%s", src, dst) + + @handler.set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER) + def handler_datapath(self, ev): + if ev.enter: + dp = ev.dp + + LOG.debug("--- send Pkt: Gratuitous ARP_Request") + data = self._garp() + self._send_msg(dp, data) diff --git a/tests/mininet/run_mnet-test.sh b/tests/mininet/run_mnet-test.sh new file mode 100755 index 00000000..c1ecbe23 --- /dev/null +++ b/tests/mininet/run_mnet-test.sh @@ -0,0 +1,274 @@ +#!/bin/sh + +RUN_DIR=`dirname $0` +CMD_NAME=`basename $0 .sh` +CMD_PATH=`readlink -f $0` +CMD_DIR=`dirname $CMD_PATH` +DUMP_SEC=10 +DUMP_DELAY=2 +DUMP_DIR=/tmp/test-mn/dump +TEST_LIST= +TEST_SUFFIX=.mn +MN_PRE_FILE=/tmp/test-mn/mn-pre +MN_POST_FILE=/tmp/test-mn/mn-post +PKG_LIST="tshark tcpreplay mz" +RTN=0 + +# usage +usage() { + echo "Usage: $0 [OPTION] [TEST DIR or FILE]..." + echo "" + echo "Run Ryu's test in mininet" + echo "ex.) $ $0 l2 l3/icmp/ICMP_ping.mn" + echo "" + echo "Options:" + echo " -h, --help show this help message and exit" + exit 0 +} + +# set default environment +set_env() { + POST_IF=h1-eth0 + DUMP_HOST=h2 + DUMP_IF=h2-eth0 + TEST_NAME= + DUMP_FILE= + RYU_APP= + RYU_LOG= + PCAP_MZ= + PCAP_FILE= + PCAP_FILTER= + PCAP_COM= + CACHE_HIT= +} + +# making mininet-test-pre-file +mn_pre() { + exec 3>&1 + exec >$MN_PRE_FILE + echo "sh echo '----------------------------------'" + echo "sh echo '(pre) mininet topology dump.'" + echo "sh echo '----------------------------------'" + echo "dump" + echo "net" + echo "sh echo '----------------------------------'" + echo "sh echo '(pre) tshark start.'" + echo "sh echo '----------------------------------'" + echo "$DUMP_HOST tshark -i $DUMP_IF -a duration:$DUMP_SEC -w $DUMP_FILE &" + echo "sh sleep $DUMP_DELAY" + echo "sh echo '----------------------------------'" + exec 1>&3 +} + +# making mininet-test-post-file +mn_post() { + exec 3>&1 + exec >$MN_POST_FILE + echo "sh ovs-vsctl del-controller s1" + echo "sh ovs-vsctl set bridge s1 protocols='[OpenFlow10,OpenFlow12]'" + echo "sh ovs-vsctl set-controller s1 tcp:127.0.0.1" + echo "sh echo '----------------------------------'" + echo "sh echo '(post) packet sending...'" + echo "sh echo '----------------------------------'" + echo $PCAP_COM + echo "sh sleep 1" + echo "sh echo '----------------------------------'" + echo "sh echo '(post) dump flows.'" + echo "sh echo '----------------------------------'" + echo "sh ovs-ofctl dump-flows s1" + echo "sh echo '----------------------------------'" + exec 1>&3 +} + +# ovs cache-hit incremental check +ovs_cache_hit() { + expr `sudo ovs-dpctl show|sed -n 's|lookups: hit:||gp'|awk '{print $1}'` - ${1:-0} +} + +# starting ryu-manager +run_ryu() { + ERRSTAT=0 + ERRTAG="run_ryu() :" + + echo "Inf: RYU_APP=$RYU_APP" + echo "Inf: ryu-manager starting..." + ryu-manager --verbose $RYU_APP 2>$DUMP_DIR/$RYU_LOG & + PID_RYU=$! + sleep 1 + [ -d /proc/$PID_RYU ] || err $ERRTAG "failed to start ryu-manager." + + return $ERRSTAT +} + +# starting mininet and test-script +run_mn() { + echo "Info: mininet starting..." + sudo mn --mac --test none --pre $MN_PRE_FILE --post $MN_POST_FILE \ + --controller remote 127.0.0.1 +} + +# cleaning after mininet +clean_mn() { + wait_ryu + rm -f $MN_PRE_FILE $MN_POST_FILE +} + +# check packet and chache-hit +check() { + PACKET=`tshark -r $DUMP_FILE -R "$PCAP_FILTER" 2>/dev/null` + if [ ! "$PACKET" ]; then + RESULT=NG + REASON="(unmatched packet. please check $DUMP_FILE)" + elif [ "$CACHE_HIT" ] && [ `ovs_cache_hit $CACHE_HIT` -eq 0 ]; then + RESULT=NG + REASON="(ovs cache hit miss.)" + else + RESULT=OK; REASON= + fi + echo + echo "TEST ${TEST_NAME} : $RESULT $REASON" +} + +# stoping ryu-manager +wait_ryu() { + kill -2 $PID_RYU + wait $PID_RYU +} + +# test-main +test_mn() { + DUMP_FILE=$DUMP_DIR/$DUMP_FILE + touch $DUMP_FILE + sudo chmod o+w $DUMP_FILE + [ "$CACHE_HIT" ] && CACHE_HIT=`ovs_cache_hit 0` + mn_pre + mn_post + run_ryu; [ $? -ne 0 ] && return 1 + run_mn; [ $? -ne 0 ] && return 1 + check + + return 0 +} + +err() { + echo Error: $* + ERRSTAT=1 +} + +mnfile_check() { + test=`basename $1 $TEST_SUFFIX` + file=`readlink -f $1` + TEST_DIR=`dirname $file` + ERRSTAT=0 + ERRTAG="mnfile_check() :" + + # test-file check + if [ ! -r $file ]; then + err $ERRTAG "cannot open the file: $file" + return $ERRSTAT + fi + + . $file || err $ERRTAG "failed to include $file" + + # parameter check + [ "$RYU_APP" ] || err $ERRTAG: "RYU_APP is not defined" + [ "$PCAP_FILE" -o "$PCAP_MZ" ] || err $ERRTAG: "PCAP_FILE or PCAP_MZ is not defined" + [ "$PCAP_FILTER" ] || err $ERRTAG "PCAP_FILTER is not defined" + [ "$TEST_NAME" ] || TEST_NAME=$test + [ "$DUMP_FILE" ] || DUMP_FILE=$test.dump + [ "$RYU_LOG" ] || RYU_LOG=ryu-manager.$test.log + [ $ERRSTAT -ne 0 ] && return $ERRSTAT + + # pcap check (pcap-file or mz-option) + if [ "$PCAP_FILE" ]; then + PCAP_FILE=$TEST_DIR/$PCAP_FILE + [ -r $PCAP_FILE ] || err $ERRTAG "PCAP_FILE[$PCAP_FILE] cannot read" + PCAP_COM="h1 tcpreplay -l 3 -i $POST_IF $PCAP_FILE" + elif [ "$PCAP_MZ" ]; then + PCAP_COM="h1 mz $POST_IF $PCAP_MZ" + fi + [ $ERRSTAT -ne 0 ] && return $ERRSTAT + + # ryu-app check + [ -r $TEST_DIR/$RYU_APP -o -r $TEST_DIR/${RYU_APP}.py ] && RYU_APP=$TEST_DIR/$RYU_APP + + return $ERRSTAT +} + +arg_check() { + ARGLIST= + ERRTAG="argcheck() :" + + case "$1" in + -h|--help) usage;; + esac + + if [ $# -ne 0 ]; then + ARGLIST=$* + else + ARGLIST=`find . -type f -name "*$TEST_SUFFIX"` + fi + + for arg in $ARGLIST; do + if [ -d $arg ]; then + file=`find $arg -type f -name "*$TEST_SUFFIX"` + elif [ -f $arg ]; then + file=$arg + else + err $ERRTAG "$arg is not found" + file= + fi + + TEST_LIST="$TEST_LIST $file" + done +} + +pkg_check() { + no_pkg= + for pkg in $PKG_LIST; do + [ ! `which $pkg` ] && no_pkg="$no_pkg $pkg" + done + for pkg in $no_pkg; do + echo "Error: Package [ $pkg ] is not found. Please install." + done + [ "$no_pkg" ] && exit 1 +} + +### main +[ -d $DUMP_DIR ] || mkdir -p $DUMP_DIR + +pkg_check +arg_check $* +echo "\n---------- test target ----------" +for testfile in $TEST_LIST; do echo $testfile; done + +count=0 +for testfile in $TEST_LIST; do + echo "\n---------- test [$testfile] start ----------" + set_env + mnfile_check $testfile && test_mn + case $? in + 0) msg="finished : $RESULT" ;; + *) msg="skipped with error"; RESULT="skip" ;; + esac + eval RESULT_${count}=\$RESULT + eval REASON_${count}=\$REASON + count=`expr $count + 1` + num=`eval echo \\${num_$RESULT:-0}` + eval num_${RESULT}=`expr $num + 1` + [ "$RESULT" != "OK" ] && RTN=1 + clean_mn + echo "\n---------- test [$testfile] $msg ----------" +done + +# output summary results +echo "\n---------- test results ----------" +count=0 +for testfile in $TEST_LIST; do + eval echo \$testfile : \$RESULT_${count} \$REASON_${count} + count=`expr $count + 1` +done +echo "----------------------------------" +echo "Ran $count tests. Result: ${num_OK:+OK=}$num_OK ${num_NG:+NG=}$num_NG ${num_skip:+skip=}$num_skip" + +exit $RTN |