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