Guest User

NOX pyswitch mod by sam russell

a guest
Mar 13th, 2012
301
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