Hi guys, I'm having problems receiving ofp_stats_reply messages and similarly other controller-to-switch reply message such as switch configuration replies. I am running a simulated network on mininet and the controller to switch part of the message works fine as I can modify flows and create a functioning network. I can see the ofp_stats_requests and ofp_stats_reply in wireshark so they are being generated however the switches appear to be sending the reply to the local connection 127.0.0.1 instead of back out the port it received the message from hence the POX controller does not receive the reply. Is there an initial switch configuration message I'm forgetting to send or can you guys shed any other light on the problem?
Here is the function that creates the of_stats_request message: def _handle_ConnectionUp (self, event): info_getter(event.connection) bd = of.ofp_port_stats_request( port_no = OFPP_NONE ) pm = of.ofp_stats_request( type=OFPST_PORT, body=bd ) event.connection.send(pm) Here is the function that should be receiving replies however it only ever receives packet.types of LLDP def _handle_PacketIn (self, event): packet = event.parsed print event, packet, packet.type I've included the full code which contains both functions below, it is modified from spanning_tree.py as found in the Betta build: # Copyright 2012 James McCauley # # This file is part of POX. # # POX is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # lub # POX is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with POX. If not, see <http://www.gnu.org/licenses/>. from pox.core import core import pox ### CHANGED from pox.lib.packet.ethernet import ethernet from pox.lib.packet.ipv4 import ipv4 from pox.lib.packet.arp import arp import pox.openflow.libopenflow_01 as of from pox.lib.revent import * from collections import defaultdict from pox.openflow.discovery import Discovery from pox.lib.util import dpidToStr from pox.lib.util import str_to_bool import time from pox.lib.recoco import Timer from pox.lib.packet.ethernet import LLDP_MULTICAST, NDP_MULTICAST from pox.lib.packet.ethernet import ethernet from pox.lib.packet.lldp import lldp, chassis_id, port_id, end_tlv from pox.lib.packet.lldp import ttl, system_description import struct import array import socket import copy from collections import * log = core.getLogger() adj = defaultdict(lambda:defaultdict(lambda:[])) _flood_delay = 5 TIMEOUT_CHECK_PERIOD = 5.0 def _calc_spanning_tree (): def flip (link): return Discovery.Link(link[2],link[3], link[0],link[1]) adj.clear() switches = set() # Add all links and switches for l in core.openflow_discovery.adjacency: adj[l.dpid1][l.dpid2].append(l) switches.add(l.dpid1) switches.add(l.dpid2) # Cull links -- we want a single symmetric link connecting nodes for s1 in switches: for s2 in switches: if s2 not in adj[s1]: continue if not isinstance(adj[s1][s2], list): continue assert s1 is not s2 good = False for l in adj[s1][s2]: if flip(l) in core.openflow_discovery.adjacency: # This is a good one adj[s1][s2] = l.port1 adj[s2][s1] = l.port2 good = True break if not good: del adj[s1][s2] if s1 in adj[s2]: # Delete the other way too del adj[s2][s1] q = [] more = set(switches) done = set() tree = defaultdict(set) while True: q = list(reversed(sorted(list(more)))) + q more.clear() if len(q) == 0: break v = q.pop(False) if v in done: continue done.add(v) for w,p in adj[v].iteritems(): if w in tree: continue more.add(w) tree[v].add((w,p)) tree[w].add((v,adj[w][v])) if False: log.debug("*** SPANNING TREE ***") for sw,ports in tree.iteritems(): log.debug((" %i : " % sw) + " ".join([str(l[0]) for l in sorted(list(ports))])) log.debug("*********************") log.debug("Spanning tree updated") return tree _prev = defaultdict(lambda : defaultdict(lambda : None)) def _reset (event): _prev[event.dpid].clear() def _handle (event): tree = _calc_spanning_tree() try: change_count = 0 for sw, ports in tree.iteritems(): con = core.openflow.getConnection(sw) print con if con is None: continue # Must have disconnected tree_ports = [p[1] for p in ports] for p in con.features.ports: if p.port_no < of.OFPP_MAX: flood = p.port_no in tree_ports if not flood: if not core.openflow_discovery.isSwitchOnlyPort(sw, p.port_no): flood = True if _prev[sw][p.port_no] is flood: continue # Skip change_count += 1 _prev[sw][p.port_no] = flood pm = of.ofp_port_mod( port_no=p.port_no, hw_addr=p.hw_addr, config = 0 if flood else of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD ) con.send(pm) if change_count: log.info("%i ports changed", change_count) except: _prev.clear() log.exception("Couldn't push spanning tree") ttt = False for swsw in _prev: p_count = 0 for ppp in _prev[swsw]: if _prev[swsw][ppp] == True: p_count += 1 host_or_not = True for swswswsw in adj[swsw]: if adj[swsw][swswswsw] == ppp: host_or_not = False if p_count < 2: for pppp in _prev[swsw]: _prev[swsw][pppp] = ttt for swswsw in adj[swsw]: if adj[swsw][swswsw] == pppp: ppppp = adj[swswsw][swsw] _prev[swswsw][ppppp] = ttt con = core.openflow.getConnection(swswsw) for q in con.features.ports: if q.port_no == ppppp: pm = of.ofp_port_mod( port_no=q.port_no, hw_addr=q.hw_addr, config = of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD ) con.send(pm) con = core.openflow.getConnection(swsw) if con is None: continue for q in con.features.ports: if q.port_no == pppp: pm = of.ofp_port_mod( port_no=q.port_no, hw_addr=q.hw_addr, config = of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD ) con.send(pm) class info_getter (object): def __init__(self, connection): self.connection = connection connection.addListeners(self) def _handle_PacketIn (self, event): packet = event.parsed print event, packet, packet.type if packet.type is not OFPST_PORT: return print ' 33 33 33 33 33 ' if packet.type is not of.ofp_stats_reply: return print ' 11 11 11 11 11 ' if packet.ofp_stats_reply.type is not OFPST_PORT: return print ' 22 22 22 22 22 ' class Networker (object): def __init__(self): core.openflow.addListeners(self) self.lemon = 8 def _handle_ConnectionUp (self, event): info_getter(event.connection) bd = of.ofp_port_stats_request( port_no = OFPP_NONE ) pm = of.ofp_stats_request( type=OFPST_PORT, body=bd ) event.connection.send(pm) #pm = of.ofp_stats_request( type=OFPST_DESC ) #event.connection.send(pm) def _handle_PacketIn(self, event): print ' Yup Im being called ' packet = event.parsed print packet if packet.type is OFPST_DESC: print ' OFPST_DESC ' print packet if packet.type is not OFPST_PORT: return print ' 33 33 44 33 33 ' if packet.type is not of.ofp_stats_reply: return print ' 11 11 44 11 11 ' if packet.ofp_stats_reply.type is not OFPST_PORT: return print ' 22 22 44 22 22 ' def launch (): def start_spanning_tree (): core.openflow.addListenerByName("ConnectionUp", _reset) core.openflow_discovery.addListenerByName("LinkEvent", _handle) core.registerNew(Networker) log.debug("Spanning tree component ready") core.call_when_ready(start_spanning_tree, "openflow_discovery") OFPST_DESC = 0 OFPST_FLOW = 1 OFPST_AGGREGATE = 2 OFPST_TABLE = 3 OFPST_PORT = 4 OFPST_QUEUE = 5 OFPST_VENDOR = 0xffff OFPP_MAX = 0xff00 OFPP_IN_PORT = 0xfff8 OFPP_TABLE = 0xfff9 OFPP_NORMAL = 0xfffa OFPP_FLOOD = 0xfffb OFPP_ALL = 0xfffc OFPP_CONTROLLER = 0xfffd OFPP_LOCAL = 0xfffe OFPP_NONE = 0xffff