4

I'm trying to examine a simple OpenFlow ryu switch, and get out of it the destination and source addresses.

I'm using Mininet.

For example for the next commands:

h1 python -m SimpleHTTPServer 80 &
h2 wget -O - h3

The destination is h3 and the source is h2.

Here is the simple switch which I'm using (I'm using Ryu):

    # Copyright (C) 2011 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 mac_to_port
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_0
from ryu.lib.mac import haddr_to_str




class SimpleSwitch(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]

    def __init__(self, *args, **kwargs):
        super(SimpleSwitch, self).__init__(*args, **kwargs)
        self.mac_to_port = {}

    def add_flow(self, datapath, in_port, dst, actions):
        ofproto = datapath.ofproto

        wildcards = ofproto_v1_0.OFPFW_ALL
        wildcards &= ~ofproto_v1_0.OFPFW_IN_PORT
        wildcards &= ~ofproto_v1_0.OFPFW_DL_DST

        match = datapath.ofproto_parser.OFPMatch(
            wildcards, in_port, 0, dst,
            0, 0, 0, 0, 0, 0, 0, 0, 0)

        mod = datapath.ofproto_parser.OFPFlowMod(
            datapath=datapath, match=match, cookie=0,
            command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0,
            priority=ofproto.OFP_DEFAULT_PRIORITY,
            flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
        datapath.send_msg(mod)

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def _packet_in_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto

        dst, src, _eth_type = struct.unpack_from('!6s6sH', buffer(msg.data), 0)

        dpid = datapath.id
        self.mac_to_port.setdefault(dpid, {})

        self.logger.info("packet in %s %s %s %s",
                         dpid, haddr_to_str(src), haddr_to_str(dst),
                         msg.in_port)

        # learn a mac address to avoid FLOOD next time.
        self.mac_to_port[dpid][src] = msg.in_port

        if dst in self.mac_to_port[dpid]:
            out_port = self.mac_to_port[dpid][dst]
        else:
            out_port = ofproto.OFPP_FLOOD

        actions = [datapath.ofproto_parser.OFPActionOutput(out_port)]

        # install a flow to avoid packet_in next time
        if out_port != ofproto.OFPP_FLOOD:
            self.add_flow(datapath, msg.in_port, dst, actions)

        out = datapath.ofproto_parser.OFPPacketOut(
            datapath=datapath, buffer_id=msg.buffer_id, in_port=msg.in_port,
            actions=actions)
        datapath.send_msg(out)

    @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
    def _port_status_handler(self, ev):
        msg = ev.msg
        reason = msg.reason
        port_no = msg.desc.port_no

        ofproto = msg.datapath.ofproto
        if reason == ofproto.OFPPR_ADD:
            self.logger.info("port added %s", port_no)
        elif reason == ofproto.OFPPR_DELETE:
            self.logger.info("port deleted %s", port_no)
        elif reason == ofproto.OFPPR_MODIFY:
            self.logger.info("port modified %s", port_no)
        else:
            self.logger.info("Illeagal port state %s %s", port_no, reason)

I tried to print haddr_to_str(src), haddr_to_str(dst) and got 00:00:00:00:00:03 and ff:ff:ff:ff:ff:ff which is not what I expected. I wanted to get 2 as source and 3 as dest.

3
  • What versions of ryu and mininet are you running? Also, could you elaborate on how you created h1, h2 and h3? For those of us only marginally familiar with mininet (but otherwise good with python / networking), we'd like to help but need a bit more info to replicate the problem Mar 25, 2014 at 7:47
  • @MikePennington I used this command to create h1, h2 and h3 sudo mn --topo single,3 --mac --switch ovsk --controller remote Also, Mininet 2.0 and Ryu installed by couple of command in here osrg.github.io/ryu
    – Numerator
    Mar 25, 2014 at 9:24
  • Did any answer help you? if so, you should accept the answer so that the question doesn't keep popping up forever, looking for an answer. Alternatively, you could provide and accept your own answer.
    – Ron Maupin
    Aug 8, 2017 at 16:23

1 Answer 1

4

Apologies, it took a while to figure out mininet and the OpenFlow ryu controller, but I finally got it...

I tried to print haddr_to_str(src), haddr_to_str(dst) and got 00:00:00:00:00:03 and ff:ff:ff:ff:ff:ff which is not what I expected. I wanted to get 2 as source and 3 as dest.

The short story is that you're decoding the destination mac address correctly... However, IP must ARP to resolve mac addresses, which is why you see ff:ff:ff:ff:ff:ff... those are just the ARP frames in the ryu controller.

This is a complete controller which works and decodes up to the IPv4 layer...

Updated ryu switch packet decoder

You've been decoding raw structs, but it's much easier to use the ryu Packet library instead of unpacking a raw struct of the packet. This is my very quick replacement of _packet_in_handler(), which just prints out the source and destination mac addresses, as well as the upper layer protocols...

from ryu.lib.packet import packet, ethernet, arp, ipv4
import array

@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):

    ### Mike Pennington's logging modifications
    ## Set up to receive the ethernet src / dst addresses
    pkt = packet.Packet(array.array('B', ev.msg.data))
    eth_pkt = pkt.get_protocol(ethernet.ethernet)
    arp_pkt = pkt.get_protocol(arp.arp)
    ip4_pkt = pkt.get_protocol(ipv4.ipv4)
    if arp_pkt:
        pak = arp_pkt
    elif ip4_pkt:
        pak = ip4_pkt
    else:
        pak = eth_pkt
    self.logger.info('  _packet_in_handler: src_mac -> %s' % eth_pkt.src)
    self.logger.info('  _packet_in_handler: dst_mac -> %s' % eth_pkt.dst)
    self.logger.info('  _packet_in_handler: %s' % pak)
    self.logger.info('  ------')
    src = eth_pkt.src  # Set up the src and dst variables so you can use them
    dst = eth_pkt.dst
    ## Mike Pennington's modifications end here

    
    msg = ev.msg
    datapath = msg.datapath
    ofproto = datapath.ofproto

    dpid = datapath.id
    self.mac_to_port.setdefault(dpid, {})

    # learn a mac address to avoid FLOOD next time.
    self.mac_to_port[dpid][src] = msg.in_port

    if dst in self.mac_to_port[dpid]:
        out_port = self.mac_to_port[dpid][dst]
    else:
        out_port = ofproto.OFPP_FLOOD

    actions = [datapath.ofproto_parser.OFPActionOutput(out_port)]

    # install a flow to avoid packet_in next time
    if out_port != ofproto.OFPP_FLOOD:
        self.add_flow(datapath, msg.in_port, dst, actions)

    out = datapath.ofproto_parser.OFPPacketOut(
        datapath=datapath, buffer_id=msg.buffer_id, in_port=msg.in_port,
        actions=actions)
    datapath.send_msg(out)

Now, whenever an ethernet packet is sent, you'll see this inside your mininet session...

  _packet_in_handler: src_mac -> 00:00:00:00:00:03
  _packet_in_handler: dst_mac -> 33:33:00:00:00:02
  _packet_in_handler: ethernet(dst='33:33:00:00:00:02',ethertype=34525,src='00:00:00:00:00:03')
  ------

ARP packets look like this...

  _packet_in_handler: src_mac -> 00:00:00:00:00:01
  _packet_in_handler: dst_mac -> ff:ff:ff:ff:ff:ff
  _packet_in_handler: arp(dst_ip='10.0.0.2',dst_mac='00:00:00:00:00:00',hlen=6,hwtype=1,opcode=1,plen=4,proto=2048,src_ip='10.0.0.1',src_mac='00:00:00:00:00:01')
  ------

Demo

Assume I saved the modified code above (including other parts of your source) as ne_question.py.

root@mininet-vm:/home/mininet# ryu-manager ne_question.py &
                 [1] 14073
loading app ne_question.py
loading app ryu.controller.ofp_handler
instantiating app ryu.controller.ofp_handler of OFPHandler
instantiating app ne_question.py of SimpleSwitch

root@mininet-vm:/home/mininet#
  • Next I build the switch topology, as you mentioned in your comment
root@mininet-vm:/home/mininet# mn --topo single,3 --mac --switch ovsk --controller remote
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2 h3
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1) (h3, s1)
*** Configuring hosts
h1 h2 h3
*** Starting controller
*** Starting 1 switches
s1
*** Starting CLI:
mininet>   _packet_in_handler: src_mac -> 00:00:00:00:00:02
  _packet_in_handler: dst_mac -> 33:33:00:00:00:02
  _packet_in_handler: ethernet(dst='33:33:00:00:00:02',ethertype=34525,src='00:00:00:00:00:02')
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:01
  _packet_in_handler: dst_mac -> 33:33:00:00:00:02
  _packet_in_handler: ethernet(dst='33:33:00:00:00:02',ethertype=34525,src='00:00:00:00:00:01')
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:03
  _packet_in_handler: dst_mac -> 33:33:00:00:00:02
  _packet_in_handler: ethernet(dst='33:33:00:00:00:02',ethertype=34525,src='00:00:00:00:00:03')
  ------
  • Finally, I run the web server, and try to pull a page... notice that ARPs are sent to resolve the destination address of the http GET. The destination address of the ARPs are ff:ff:ff:ff:ff:ff. BTW, if you change the wget to h2 wget h1, everything works correctly...
mininet> h1 python -m SimpleHTTPServer 80 &
mininet> h2 wget -O - h1
--2014-03-28 04:22:25--  http://10.0.0.1/
Connecting to 10.0.0.1:80...   _packet_in_handler: src_mac -> 00:00:00:00:00:02
  _packet_in_handler: dst_mac -> ff:ff:ff:ff:ff:ff
  _packet_in_handler: arp(dst_ip='10.0.0.1',dst_mac='00:00:00:00:00:00',hlen=6,hwtype=1,opcode=1,plen=4,proto=2048,src_ip='10.0.0.2',src_mac='00:00:00:00:00:02')
  ------
--2014-03-28 04:00:58--  http://10.0.0.1/
Connecting to 10.0.0.1:80...   _packet_in_handler: src_mac -> 00:00:00:00:00:02
  _packet_in_handler: dst_mac -> 00:00:00:00:00:01
  _packet_in_handler: ipv4(csum=33886,dst='10.0.0.1',flags=2,header_length=5,identification=41563,offset=0,option=None,proto=6,src='10.0.0.2',tos=0,total_length=60,ttl=64,version=4)
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:01
  _packet_in_handler: dst_mac -> 00:00:00:00:00:02
  _packet_in_handler: ipv4(csum=9914,dst='10.0.0.2',flags=2,header_length=5,identification=0,offset=0,option=None,proto=6,src='10.0.0.1',tos=0,total_length=60,ttl=64,version=4)
  ------
connected.
HTTP request sent, awaiting response...   _packet_in_handler: src_mac -> 00:00:00:00:00:02
  _packet_in_handler: dst_mac -> 00:00:00:00:00:01
  _packet_in_handler: ipv4(csum=33893,dst='10.0.0.1',flags=2,header_length=5,identification=41564,offset=0,option=None,proto=6,src='10.0.0.2',tos=0,total_length=52,ttl=64,version=4)
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:02
  _packet_in_handler: dst_mac -> 00:00:00:00:00:01
  _packet_in_handler: ipv4(csum=33784,dst='10.0.0.1',flags=2,header_length=5,identification=41565,offset=0,option=None,proto=6,src='10.0.0.2',tos=0,total_length=160,ttl=64,version=4)
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:01
  _packet_in_handler: dst_mac -> 00:00:00:00:00:02
  _packet_in_handler: ipv4(csum=61034,dst='10.0.0.2',flags=2,header_length=5,identification=14423,offset=0,option=None,proto=6,src='10.0.0.1',tos=0,total_length=52,ttl=64,version=4)
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:01
  _packet_in_handler: dst_mac -> 00:00:00:00:00:02
  _packet_in_handler: ipv4(csum=61016,dst='10.0.0.2',flags=2,header_length=5,identification=14424,offset=0,option=None,proto=6,src='10.0.0.1',tos=0,total_length=69,ttl=64,version=4)
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:01
  _packet_in_handler: dst_mac -> 00:00:00:00:00:02
  _packet_in_handler: ipv4(csum=60037,dst='10.0.0.2',flags=2,header_length=5,identification=14425,offset=0,option=None,proto=6,src='10.0.0.1',tos=0,total_length=1047,ttl=64,version=4)
  ------
200 OK
Length: 858 [text/html]
Saving to: `STDOUT'
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ul>
<li><a href=".bash_history">.bash_history</a>
<li><a href=".bash_logout">.bash_logout</a>
<li><a href=".bashrc">.bashrc</a>
<li><a href=".cache/">.cache/</a>
<li><a href=".gitconfig">.gitconfig</a>
<li><a href=".profile">.profile</a>
<li><a href=".rnd">.rnd</a>
<li><a href=".wireshark/">.wireshark/</a>
<li><a href="install-mininet-vm.sh">install-mininet-vm.sh</a>
<li><a href="mininet/">mininet/</a>
<li><a href="ne_question.py">ne_question.py</a>
<li><a href="ne_question.pyc">ne_question.pyc</a>
<li><a href="of-dissector/">of-dissector/</a>
<li><a href="oflops/">oflops/</a>
<li><a href="oftest/">oftest/</a>
<li><a href="openflow/">openflow/</a>
<li><a href="pox/">pox/</a>
</ul>
<hr>
</body>
</html>

     0K                                                       100%  161M=0s

2014-03-28 04:00:58 (161 MB/s) - written to stdout [858/858]

  _packet_in_handler: src_mac -> 00:00:00:00:00:02
mininet>   _packet_in_handler: dst_mac -> 00:00:00:00:00:01
  _packet_in_handler: ipv4(csum=33891,dst='10.0.0.1',flags=2,header_length=5,identification=41566,offset=0,option=None,proto=6,src='10.0.0.2',tos=0,total_length=52,ttl=64,version=4)
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:02
  _packet_in_handler: dst_mac -> 00:00:00:00:00:01
  _packet_in_handler: ipv4(csum=33890,dst='10.0.0.1',flags=2,header_length=5,identification=41567,offset=0,option=None,proto=6,src='10.0.0.2',tos=0,total_length=52,ttl=64,version=4)
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:02
  _packet_in_handler: dst_mac -> 00:00:00:00:00:01
  _packet_in_handler: ipv4(csum=33889,dst='10.0.0.1',flags=2,header_length=5,identification=41568,offset=0,option=None,proto=6,src='10.0.0.2',tos=0,total_length=52,ttl=64,version=4)
  ------
  _packet_in_handler: src_mac -> 00:00:00:00:00:01
  _packet_in_handler: dst_mac -> 00:00:00:00:00:02
  _packet_in_handler: ipv4(csum=9922,dst='10.0.0.2',flags=2,header_length=5,identification=0,offset=0,option=None,proto=6,src='10.0.0.1',tos=0,total_length=52,ttl=64,version=4)
  ------

mininet>
mininet>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.