Sorry for the extremely late reply! Thank you very much for the example code!!
Concerning the queuing: ok, then we're on the same wavelength :) Over the last couple of weeks, I've been working with your example and implemented a priority queue. So far it works excellent! I was able to get the performance even better by using multiprocessing and performing intensive calculations and some database IO in a separate process. I've also finally cleaned up my profiling code and pushed it to github: https://github.com/Timmmy/pox in the betta branch (sorry that it took so long). Besides the profiler wrapper, it also contains an autoquit module that quits pox after a specified amount of time (I use it for automatic experiments). Kind regards and sorry again for the late reply, Tim 2013/3/26 Murphy McCauley <[email protected]> > I've pushed recoco.consumer to the carp branch which has a couple generic > consumer classes. Using those, you can write a simple component like: > > from pox.core import core > from pox.lib.recoco.consumer import BaseConsumer > import pox.openflow.libopenflow_01 as of > > class MyConsumer (BaseConsumer): > def _do_work (self, work): > # Work is (dpid,packet_in) > dpid,packet_in = work > po = of.ofp_packet_out(data = packet_in) > po.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD)) > > connection = core.openflow.getConnection(dpid) > if connection is None: > self.log.warn("Connection lost before sending packet") > return > connection.send(po) > > def handle_PacketIn (event): > consumer.add_work((event.dpid,event.ofp)) > > def launch (): > global consumer > consumer = MyConsumer() > core.openflow.addListenerByName("PacketIn", handle_PacketIn) > > Here, the normal OpenFlow event Task is acting like a producer, pushing > work items (which in this case are a DPID and a packet_in) to a simple > consumer which just floods the packet back out. So it's a dumb hub, but > written producer-consumer style. BaseConsumer's initializer has some > parameters for maximum batch size and Task priority. > > More comments below. > > On Mar 23, 2013, at 3:59 PM, Tmusic wrote: > > I'm still a bit confused about the work producing and consuming as it's > implemented now. So there is the main task loop in OpenFlow_01_Task which > loops over the connections and calls the read function on each of them. > This read functions calls the appropriate handler which in its turn fires > the appropriate event on the pox core (which are then further handled). So > everything would be processed connection by connection... > > > > But if I understand you correctly, the handlers called by the read > function put the jobs in a queue, which is than emptied by a separate task > loop (which I can't find at the moment). Can you give a hint where (in the > code) the task loop runs that empties the queue and where the filling of > the queue exactly happens? > > Ah, we have miscommunicated. There's no queue in general. The OpenFlow > events are entirely (or almost entirely?) raised by a single Task with a > select loop (OpenFlow_01_Task or whatever). It raises them directly. > > The miscommunication I believe stems from me saying, "The OpenFlow event > handlers are producers that fill a work queue and then you have a consumer > in the form of a recoco Task that tries to drain the queue." I wasn't > describing how it works now. I was describing the solution to your problem. > > The example above *does* implement this. The idea being rather than do > expensive processing directly in the handlers, you're better off handling > them quickly by just shoving them off at a work queue which can try to > handle them later (and perhaps with more flexible priorities). The new > BaseConsumer/FlexConsumer classes are meant to simplify this pattern. > (They're based on the producer/consumer example I posed a few days ago, > but now it's generic.) > > -- Murphy
