packages feed

nettle-openflow-0.2.0: src/Examples/Hub.hs

{-
A simple controller that responds to each packet-in message by 
installing a flow rule to process the packet-in packet and similar packets
using the switch's Flood port. The rule is installed with a 5 second hard (and inactivity)
timeout so the rule should be removed by the switch after 5 seconds.

This controller uses the Nettle.Servers.Server module and forks a Haskell thread 
for every connecting OpenFlow switch. 
-}

import Nettle.Servers.Server
import Nettle.OpenFlow
import Control.Concurrent
import qualified Data.ByteString as B
import System.Environment

main :: IO ()
main =
  do portNum <- getPortNumber
     ofpServer <- startOpenFlowServer Nothing portNum
     forever (do (switch,sfr) <- acceptSwitch ofpServer
                 forkIO (handleSwitch switch)
             )
     closeServer ofpServer
       
       
getPortNumber :: IO ServerPortNumber       
getPortNumber 
  = do args <- getArgs
       if length args < 1 
         then error "Requires one command-line argument specifying the server port number."
         else return (read (args !! 0))


handleSwitch :: SwitchHandle -> IO ()
handleSwitch switch 
  = do untilNothing (receiveFromSwitch switch) (messageHandler switch)
       closeSwitchHandle switch


messageHandler :: SwitchHandle -> (TransactionID, SCMessage) -> IO ()
messageHandler switch (xid, scmsg) =
  case scmsg of
    PacketIn pkt        -> 
      case enclosedFrame pkt of 
        Left s -> putStrLn (s ++ ": " ++ show (B.unpack (packetData pkt)))
        Right frame -> 
          let flowEntry = AddFlow { match             = frameToExactMatch (receivedOnPort pkt) frame
                                  , priority          = 32768
                                  , actions           = [SendOutPort Flood]
                                  , cookie            = 0
                                  , idleTimeOut       = ExpireAfter 5
                                  , hardTimeOut       = ExpireAfter 5
                                  , notifyWhenRemoved = False
                                  , applyToPacket     = bufferID pkt
                                  , overlapAllowed    = False
                                  } 
          in sendToSwitch switch (xid, FlowMod flowEntry)
    _                   -> return ()