NodeFlow

NodeFlow (http://garyberger.net/?p=537, developed by Gary Berger, technical leader, office of the CTO of Cisco Systems) is a minimalist OpenFlow controller written in JavaScript for Node.js (https://nodejs.org/en/). Node.js is a server-side software system designed for writing scalable internet applications (for example, HTTP servers). It can be considered as a packaged compilation of Google's V8 JavaScript engine, the libuv platform abstraction layer, and a core library, which is written in JavaScript. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices. Programs are written on the server side in JavaScript, using event-driven, asynchronous I/O to minimize overhead and maximize the scalability. Therefore, unlike most JavaScript programs, the program is not executed in a web browser. Instead, it runs as a server-side JavaScript application. NodeFlow is actually a very simple program and relies heavily on a protocol interpreter called OFLIB-NODE written by Zoltan LaJos Kis.

NodeFlow is an experimental system available on GitHub (https://github.com/gaberger/NodeFLow) along with a fork of the OFLIB-NODE libraries (https://github.com/gaberger/oflib-node). The beauty of NodeFlow is its simplicity in running and understanding an OpenFlow controller with fewer than 500 lines of code. Leveraging JavaScript and the high-performance Google V8 JavaScript engine enables network architects to experiment with various SDN features without the need to deal with all of the boilerplate code required for setting up event-driven programming.

The NodeFlow server (that is, OpenFlow controller) instantiates with a simple call to net.createServer. The address and listening port are configured through a start script:

NodeFlowServer.prototype.start = function(address, port) { 
var self = this 
var socket = [] 
var server = net.createServer() 
server.listen(port, address, function(err, result) { 
util.log("NodeFlow listening on:" + address + '@' + port) 
self.emit('started', { "Config": server.address() }) 
}) 

The next step is to create a unique session ID, from which the controller can keep track of each of the different switch connections. The event listener maintains the socket. The main event-processing loop is invoked whenever data is received from the socket channel. The stream library is utilized to buffer the data and return the decoded OpenFlow message in a msgs object. The msg object is passed to the _processMessage function for further processing:

server.on('connection',  
  function(socket) { 
    socket.setNoDelay(noDelay = true) 
    var sessionID = socket.remoteAddress + ":" + socket.remotePort 
    sessions[sessionID] = new sessionKeeper(socket) 
    util.log("Connection from : " + sessionID) 
  
    socket.on('data', function(data) { 
    var msgs = switchStream.process(data); 
    msgs.forEach(function(msg) { 
    if (msg.hasOwnProperty('message')) { 
         self._processMessage(msg, sessionID) 
    } else { 
         util.log('Error: Cannot parse the message.') 
         console.dir(data) 
   } 
}) 

The last part is the event handlers. EventEmitters of Node.js is utilized to trigger the callbacks. These event handlers wait for the specific event to happen and then trigger the processing. NodeFlow handles two specific events: OFPT_PACKET_IN, which is the main event to listen to for OpenFlow PACKET_IN events, and SENDPACKET, which simply encodes and sends out OpenFlow messages:

self.on('OFPT_PACKET_IN',  
  function(obj) { 
  var packet = decode.decodeethernet(obj.message.body.data, 0) 
  nfutils.do_l2_learning(obj, packet) 
  self._forward_l2_packet(obj, packet)  
  }) 
  self.on('SENDPACKET',  
  function(obj) { 
  nfutils.sendPacket(obj.type, obj.packet.outmessage, 
obj.packet.sessionID) })

A simple Net App based on NodeFlow could be a learning switch (following the do_l2_learning function). The learning switch simply searches for the source MAC address, and in case the address is not already in the learning table, it will be inserted in the corresponding source port to the forwarding table:

do_l2_learning: function(obj, packet) { 
  self = this 
  var dl_src = packet.shost 
  var dl_dst = packet.dhost 
  var in_port = obj.message.body.in_port 
  var dpid = obj.dpid 
  if (dl_src == 'ff:ff:ff:ff:ff:ff') { 
  return 
  } 
if (!l2table.hasOwnProperty(dpid)) { 
  l2table[dpid] = new Object() //create object 
  } 
if (l2table[dpid].hasOwnProperty(dl_src)) { 
  var dst = l2table[dpid][dl_src] 
     if (dst != in_port) { 
       util.log("MAC has moved from " + dst + " to " + in_port) 
     } else { 
          return 
     } 
} else { 
     util.log("learned mac " + dl_src + " port : " + in_port) 
     l2table[dpid][dl_src] = in_port 
} 
  if (debug) { 
     console.dir(l2table) 
 } 
} 

The complete NodeFlow server is called server.js, which can be downloaded from the NodeFlow Git repository. To run the NodeFlow controller, execute the Node.js code and pass the NodeFlow server (that is, server.js) to the Node.js binary (for example, node.exe on Windows):

C: program Files
odejs>node server.js 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset