You couldn't have gotten too much closer without it working. Attached is a modified version of pyswitch with an example xmlrpc service (running on port 11111) with the echo and add methods, plus a couple methods to actually enable and disable the switch functionality.
-- Murphy On Monday, August 22, 2011 07:01:50 AM chris oleke wrote: > Hi > > I opted to use twisted but I'm not having any luck as well. My application > is an extension of the samplerouting component. I'm still new to python so > not exactly certain on how to run another class within the samplerouting > component. I have had a couple of tries including creating a class outside > samplerouting but no response. One of my trials had NOX return an error > involving pyoxidereactor. I had a look at the webserver.py but didn't > really get much help from it. I tried to setup a class in my samplerouting > def install() like this: > > def install() > class Example(xmlrpc.XMLRPC): > def __init__(self): > xmlrpc.XMLRPC.__init__(self) > self.component = component > > def xmlrpc_echo(self,x): > return x > self.r = self.Example(self) > reactor.listenTCP(8080, server.Site(r)) > reactor.run() > It returned this error: > > 00002|nox|ERR:Cannot change the state of 'samplerouting' to INSTALLED: > 'samplerouting' ran into an error: > cannot install the Python component: Traceback (most recent call > last): > File "./nox/netapps/routing/samplerouting.py", line 130, in > install > self.r = self.Example(self) > AttributeError: SampleRouting instance has no attribute 'Example' > > The other trials I have had that return no errors seem to have no response > with my third party application. I still get a "connection refused" > response. I still think I'm making the call in a wrong way so would > appreciate any advice. > > Regards, > Chris > > On Sat, Aug 20, 2011 at 11:19 AM, Murphy McCauley <jam...@nau.edu> wrote: > > I assume the typo on the last line isn't in your actual code > > (server.serve_forever()). But yes, this won't work. > > server.serve_forever() will block forever, freezing NOX. And you can't > > just put it in another thread because that will crash or hang or cause > > other bad things to happen in NOX. > > > > You should be able to make this work by setting the server timeout to 0, > > and periodically calling its handle_request() inside a timer you'd > > created with post_callback(). However, this essentially would poll for > > requests at some rate and is not a terribly efficient or elegant > > solution, and I wouldn't suggest doing it if you don't have to... > > > > And I don't think you have to -- the recommended way to do XML-RPC in NOX > > would be to use Twisted. The following page has some info on doing > > XML-RPC in Twisted: > > http://twistedmatrix.com/documents/current/web/howto/xmlrpc.html > > > > That might more or less just work in NOX. If it doesn't, take a look in > > NOX's webserver.py to fill in any blanks. > > > > Hope that helps. > > > > -- Murphy > > > > > > On Aug 20, 2011, at 12:26 AM, chris oleke wrote: > > > > Hi, I've got another question still related to my NOX application. It is > > supposed to receive replies from the third party application through use > > of XML-RPC. I have had a go at the SimpleXMLRPCServer but seem to have > > no connection established, my thought is that I'm calling it the wrong > > way. This is how I call it from my application > > > > def run(self): > > self.server = SimpleXMLRPCServer(("localhost", 8080), > > > > requestHandler=RequestHandler) > > > > self.register_introspection_functions() > > self.register_function(test_xml, 'reply_one.test') > > server.server_forever() > > > > test_xml is a function defined within my application. Any help I can get > > will be highly appreciated. > > > > Regards, > > Chris > > > > On Tue, Aug 16, 2011 at 7:38 AM, chris oleke <chrisol...@gmail.com> wrote: > >> Thanks Murphy!! I have tried testing it and I can receive the Hello > >> World continuously on my other application. But since I'm sending the > >> flows from a separate function, I have made some modifications and > >> called the sock.connect from my component's init() and I can receive > >> the flows continuously. > >> > >> On Tue, Aug 16, 2011 at 6:44 AM, Murphy McCauley <jam...@nau.edu> wrote: > >>> If the application you're working with requires that you close the > >>> socket, then it seems like you should be creating, connecting, sending > >>> on, and closing a new socket every ten seconds in response to your > >>> flow stats coming in. > >>> > >>> It looks like you may be not creating and connecting a new socket after > >>> the first run, and are trying to reuse a socket that you'd closed (made > >>> possible by the fact that you're saving a reference to an old one as > >>> self.sock, which you can never actually reuse since you close it). > >>> > >>> I put the following code in an app (and then kick it off by calling it > >>> in my Component's install()), and it seems to work just fine: > >>> > >>> def handle_timer (self): > >>> import socket > >>> self.post_callback(5, self.handle_timer) > >>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) > >>> sock.connect(("",5000)) > >>> sock.send("Hello world!\n") > >>> sock.close() > >>> > >>> Can you test if this seems to work for you? (I just run "nc -lk 5000" > >>> to give it something to connect to.) > >>> > >>> As a sidenote: These calls are blocking, and it's not nice to block the > >>> thread. Using Twisted is the preferred solution. But since this is > >>> only periodic and is connecting to localhost, etc., I am not sure > >>> that's worth worrying about. As I said, it has been a long time since > >>> I have looked at NOX's threading stuff, but nothing immediately comes > >>> to mind about why this wouldn't work. > >>> > >>> -- Murphy > >>> > >>> On Aug 15, 2011, at 2:15 PM, chris oleke wrote: > >>> > >>> Murphy, the thing is I'd pretty much want to maintain the sockets that > >>> I'm using at the moment since the third party application is tailored > >>> to work with them. When I send the data from NOX, I have to close the > >>> sockets because the data won't be received on the other end if the > >>> sockets remain open. My flow stats are generated every 10 seconds so > >>> my aim is to have them sent continously. I had previously tried using > >>> sock.setblocking(0) but encountered an error *"operation already in > >>> progress"* so abandoned using it. > >>> > >>> On Sat, Aug 13, 2011 at 2:34 AM, Murphy McCauley <jam...@nau.edu> wrote: > >>>> It has been long enough since I've looked at the co-op threading in > >>>> NOX that I don't immediately know what the problem you're having with > >>>> the file descriptors going away is. You're sure you're not calling > >>>> close() on them? > >>>> > >>>> You could try setting the socket to non-blocking mode with > >>>> > >>>> sock.setblocking(0). > >>>> > >>>> It might be possible to get asynccore to work, but I think it'd > >>>> probably be some trouble. Twisted, on the other hand, should more or > >>>> less just work. > >>>> > >>>> I think you can probably look at the NOX webservice stuff for a bit > >>>> of an > >>>> > >>>> example, but it shouldn't be much different than any other Twisted > >>>> code. > >>>> > >>>> Or if you would be okay with communicating with the other process via > >>>> JSON strings, you could use jsonmessenger. Look in monitoring.py from > >>>> the monitoring component for an example. > >>>> > >>>> Hope that helps. > >>>> > >>>> -- Murphy > >>>> > >>>> On Aug 12, 2011, at 2:03 PM, chris oleke wrote: > >>>> > >>>> Hi > >>>> > >>>> > >>>> Hopefully this is still within the Nox domain. I have a python > >>>> application that is using sockets to send out flows that I have > >>>> obtained from a flow_stats_in_event to an application external of > >>>> Nox. This is how I’m doing it > >>>> self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) > >>>> self.sock.connect(("",5000)) > >>>> self.sock.send(repr(flows)) > >>>> self.sock.close() > >>>> > >>>> Unfortunately I can only send the flows once before the sockets close > >>>> after which I get the errors below > >>>> self.sock.send(repr(flows)) > >>>> > >>>> File "/usr/lib/python2.6/socket.py", line 167, in _dummy > >>>> > >>>> raise error(EBADF, 'Bad file descriptor') > >>>> > >>>> error: [Errno 9] Bad file descriptor > >>>> > >>>> > >>>> It’s obviously as a result of trying to send information out on a > >>>> socket that’s been closed. I have tried to look at asyncore and see > >>>> if I can have an asynchronous socket but haven’t had any luck and my > >>>> application’s seems to lock/freeze the few times I have tried. Is > >>>> there a way I can have the socket remain connected so I can have > >>>> flows sent constantly and also be able to receive data when sent from > >>>> the external application. I would like a demonstration as well if > >>>> it’s possible. > >>>> > >>>> > >>>> Thanks > >>>> > >>>> Chris > >>>> _______________________________________________ > >>>> nox-dev mailing list > >>>> nox-dev@noxrepo.org > >>>> http://noxrepo.org/mailman/listinfo/nox-dev
# Copyright 2008 (C) Nicira, Inc. # # This file is part of NOX. # # NOX 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. # # NOX 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 NOX. If not, see <http://www.gnu.org/licenses/>. # Python L2 learning switch # # ---------------------------------------------------------------------- # # This app functions as the control logic of an L2 learning switch for # all switches in the network. On each new switch join, it creates # an L2 MAC cache for that switch. # # In addition to learning, flows are set up in the switch for learned # destination MAC addresses. Therefore, in the absence of flow-timeout, # pyswitch should only see one packet per flow (where flows are # considered to be unidirectional) # from nox.lib.core import * from nox.lib.packet.ethernet import ethernet from nox.lib.packet.packet_utils import mac_to_str, mac_to_int from twisted.python import log import logging from time import time from socket import htons from struct import unpack logger = logging.getLogger('nox.coreapps.examples.pyswitch') # Global pyswitch instance inst = None # Timeout for cached MAC entries CACHE_TIMEOUT = 5 # -- # Given a packet, learn the source and peg to a switch/inport # -- def do_l2_learning(dpid, inport, packet): global inst # learn MAC on incoming port srcaddr = packet.src.tostring() if ord(srcaddr[0]) & 1: return if inst.st[dpid].has_key(srcaddr): dst = inst.st[dpid][srcaddr] if dst[0] != inport: log.msg('MAC has moved from '+str(dst)+'to'+str(inport), system='pyswitch') else: return else: log.msg('learned MAC '+mac_to_str(packet.src)+' on %d %d'% (dpid,inport), system="pyswitch") # learn or update timestamp of entry inst.st[dpid][srcaddr] = (inport, time(), packet) # Replace any old entry for (switch,mac). mac = mac_to_int(packet.src) # -- # If we've learned the destination MAC set up a flow and # send only out of its inport. Else, flood. # -- def forward_l2_packet(dpid, inport, packet, buf, bufid): dstaddr = packet.dst.tostring() if not ord(dstaddr[0]) & 1 and inst.st[dpid].has_key(dstaddr): prt = inst.st[dpid][dstaddr] if prt[0] == inport: log.err('**warning** learned port = inport', system="pyswitch") inst.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport) else: # We know the outport, set up a flow log.msg('installing flow for ' + str(packet), system="pyswitch") flow = extract_flow(packet) flow[core.IN_PORT] = inport actions = [[openflow.OFPAT_OUTPUT, [0, prt[0]]]] inst.install_datapath_flow(dpid, flow, CACHE_TIMEOUT, openflow.OFP_FLOW_PERMANENT, actions, bufid, openflow.OFP_DEFAULT_PRIORITY, inport, buf) else: # haven't learned destination MAC. Flood inst.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport) # -- # Responsible for timing out cache entries. # Is called every 1 second. # -- def timer_callback(): global inst curtime = time() for dpid in inst.st.keys(): for entry in inst.st[dpid].keys(): if (curtime - inst.st[dpid][entry][1]) > CACHE_TIMEOUT: log.msg('timing out entry'+mac_to_str(entry)+str(inst.st[dpid][entry])+' on switch %x' % dpid, system='pyswitch') inst.st[dpid].pop(entry) inst.post_callback(1, timer_callback) return True def datapath_leave_callback(dpid): logger.info('Switch %x has left the network' % dpid) if inst.st.has_key(dpid): del inst.st[dpid] def datapath_join_callback(dpid, stats): logger.info('Switch %x has joined the network' % dpid) # -- # Packet entry method. # Drop LLDP packets (or we get confused) and attempt learning and # forwarding # -- def packet_in_callback(dpid, inport, reason, len, bufid, packet): if not packet.parsed: log.msg('Ignoring incomplete packet',system='pyswitch') if not inst.st.has_key(dpid): log.msg('registering new switch %x' % dpid,system='pyswitch') inst.st[dpid] = {} # don't forward lldp packets if packet.type == ethernet.LLDP_TYPE: return CONTINUE # learn MAC on incoming port do_l2_learning(dpid, inport, packet) if enable_switch: forward_l2_packet(dpid, inport, packet, packet.arr, bufid) return CONTINUE enable_switch = True from twisted.internet import reactor from twisted.web import xmlrpc, server class Example(xmlrpc.XMLRPC): def __init__(self, component): xmlrpc.XMLRPC.__init__(self) self.component = component def xmlrpc_echo(self,x): return x def xmlrpc_add(self, a, b): return a + b def xmlrpc_get_switch_state(self): return enable_switch def xmlrpc_set_switch_state(self, state): global enable_switch enable_switch = state return state class pyswitch(Component): def __init__(self, ctxt): global inst Component.__init__(self, ctxt) self.st = {} inst = self def install(self): inst.register_for_packet_in(packet_in_callback) inst.register_for_datapath_leave(datapath_leave_callback) inst.register_for_datapath_join(datapath_join_callback) inst.post_callback(1, timer_callback) self.r = Example(self) reactor.listenTCP(11111, server.Site(self.r)) def getInterface(self): return str(pyswitch) def getFactory(): class Factory: def instance(self, ctxt): return pyswitch(ctxt) return Factory()
_______________________________________________ nox-dev mailing list nox-dev@noxrepo.org http://noxrepo.org/mailman/listinfo/nox-dev