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

Reply via email to