SHARE
TWEET

NOX pyswitch mod by sam russell

a guest Mar 13th, 2012 178 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # Copyright 2008 (C) Nicira, Inc.
  2. #
  3. # This file is part of NOX. Additions from Sam Russell for
  4. # compatibility with OVS on Pronto 3920
  5. #
  6. # NOX is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # NOX is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with NOX.  If not, see <http://www.gnu.org/licenses/>.
  18. # Python L2 learning switch
  19. #
  20. # ----------------------------------------------------------------------
  21. #
  22. # This app functions as the control logic of an L2 learning switch for
  23. # all switches in the network. On each new switch join, it creates
  24. # an L2 MAC cache for that switch.
  25. #
  26. # In addition to learning, flows are set up in the switch for learned
  27. # destination MAC addresses.  Therefore, in the absence of flow-timeout,
  28. # pyswitch should only see one packet per flow (where flows are
  29. # considered to be unidirectional)
  30. #
  31.  
  32. from nox.lib.core     import *
  33.  
  34. from nox.lib.packet.ethernet     import ethernet
  35. from nox.lib.packet.packet_utils import mac_to_str, mac_to_int
  36.  
  37. from twisted.python import log
  38.  
  39. import logging
  40. from time import time
  41. from socket import htons
  42. from struct import unpack
  43.  
  44. logger = logging.getLogger('nox.coreapps.examples.pyswitch')
  45.  
  46. # Global pyswitch instance
  47. inst = None
  48.  
  49. # Timeout for cached MAC entries
  50. CACHE_TIMEOUT = 5
  51.  
  52. # Modified extract_flow except just dest address - another sam edit
  53. def create_l2_out_flow(ethernet):
  54.     attrs = {}
  55.     attrs[core.DL_DST] = ethernet.dst
  56.     return attrs
  57.  
  58. # --
  59. # Given a packet, learn the source and peg to a switch/inport
  60. # --
  61. def do_l2_learning(dpid, inport, packet):
  62.     global inst
  63.  
  64.     # learn MAC on incoming port
  65.     srcaddr = packet.src.tostring()
  66.     if ord(srcaddr[0]) & 1:
  67.         return
  68.     if inst.st[dpid].has_key(srcaddr):
  69.         dst = inst.st[dpid][srcaddr]
  70.         if dst[0] != inport:
  71.             log.msg('MAC has moved from '+str(dst)+'to'+str(inport), system='pyswitch')
  72.         else:
  73.             return
  74.     else:
  75.         log.msg('learned MAC '+mac_to_str(packet.src)+' on %d %d'% (dpid,inport), system="pyswitch")
  76.  
  77.     # learn or update timestamp of entry
  78.     inst.st[dpid][srcaddr] = (inport, time(), packet)
  79.  
  80.     # Replace any old entry for (switch,mac).
  81.     mac = mac_to_int(packet.src)
  82.  
  83. # --
  84. # If we've learned the destination MAC set up a flow and
  85. # send only out of its inport.  Else, flood.
  86. # --
  87. def forward_l2_packet(dpid, inport, packet, buf, bufid):    
  88.     dstaddr = packet.dst.tostring()
  89.     if not ord(dstaddr[0]) & 1 and inst.st[dpid].has_key(dstaddr):
  90.         prt = inst.st[dpid][dstaddr]
  91.         if  prt[0] == inport:
  92.             log.err('**warning** learned port = inport', system="pyswitch")
  93.             inst.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport)
  94.         else:
  95.             # We know the outport, set up a flow
  96.             log.msg('installing flow for ' + str(packet), system="pyswitch")
  97.             # sam edit - just load dest address, the rest doesn't matter
  98.             flow = create_l2_out_flow(packet)
  99.             actions = [[openflow.OFPAT_OUTPUT, [0, prt[0]]]]
  100.             inst.install_datapath_flow(dpid, flow, CACHE_TIMEOUT,
  101.                                        openflow.OFP_FLOW_PERMANENT, actions,
  102.                                        bufid, openflow.OFP_DEFAULT_PRIORITY,
  103.                                        inport, buf)
  104.     else:    
  105.         # haven't learned destination MAC. Flood
  106.         inst.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport)
  107.        
  108. # --
  109. # Responsible for timing out cache entries.
  110. # Is called every 1 second.
  111. # --
  112. def timer_callback():
  113.     global inst
  114.  
  115.     curtime  = time()
  116.     for dpid in inst.st.keys():
  117.         for entry in inst.st[dpid].keys():
  118.             if (curtime - inst.st[dpid][entry][1]) > CACHE_TIMEOUT:
  119.                 log.msg('timing out entry'+mac_to_str(entry)+str(inst.st[dpid][entry])+' on switch %x' % dpid, system='pyswitch')
  120.                 inst.st[dpid].pop(entry)
  121.  
  122.     inst.post_callback(1, timer_callback)
  123.     return True
  124.  
  125. def datapath_leave_callback(dpid):
  126.     logger.info('Switch %x has left the network' % dpid)
  127.     if inst.st.has_key(dpid):
  128.         del inst.st[dpid]
  129.  
  130. def datapath_join_callback(dpid, stats):
  131.     logger.info('Switch %x has joined the network' % dpid)
  132.  
  133. # --
  134. # Packet entry method.
  135. # Drop LLDP packets (or we get confused) and attempt learning and
  136. # forwarding
  137. # --
  138. def packet_in_callback(dpid, inport, reason, len, bufid, packet):
  139.  
  140.     if not packet.parsed:
  141.         log.msg('Ignoring incomplete packet',system='pyswitch')
  142.        
  143.     if not inst.st.has_key(dpid):
  144.         log.msg('registering new switch %x' % dpid,system='pyswitch')
  145.         inst.st[dpid] = {}
  146.  
  147.     # don't forward lldp packets    
  148.     if packet.type == ethernet.LLDP_TYPE:
  149.         return CONTINUE
  150.  
  151.     # learn MAC on incoming port
  152.     do_l2_learning(dpid, inport, packet)
  153.  
  154.     forward_l2_packet(dpid, inport, packet, packet.arr, bufid)
  155.  
  156.     return CONTINUE
  157.  
  158. class pyswitch(Component):
  159.  
  160.     def __init__(self, ctxt):
  161.         global inst
  162.         Component.__init__(self, ctxt)
  163.         self.st = {}
  164.  
  165.         inst = self
  166.  
  167.     def install(self):
  168.         inst.register_for_packet_in(packet_in_callback)
  169.         inst.register_for_datapath_leave(datapath_leave_callback)
  170.         inst.register_for_datapath_join(datapath_join_callback)
  171.         inst.post_callback(1, timer_callback)
  172.  
  173.     def getInterface(self):
  174.         return str(pyswitch)
  175.  
  176. def getFactory():
  177.     class Factory:
  178.         def instance(self, ctxt):
  179.             return pyswitch(ctxt)
  180.  
  181.     return Factory()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top