netcore-1.0.0: nettle-openflow/src/Nettle/OpenFlow/Packet.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP, DisambiguateRecordFields, RecordWildCards #-}
module Nettle.OpenFlow.Packet (
-- * Sending packets
PacketOut (..)
, bufferedPacketOut
, unbufferedPacketOut
, receivedPacketOut
, BufferID
-- * Packets not handled by a switch
, PacketInfo (..)
, PacketInReason (..)
, NumBytes
, bufferedAtSwitch
) where
import qualified Data.ByteString as B
import Nettle.OpenFlow.Port
import Nettle.OpenFlow.Action
import Nettle.Ethernet.EthernetFrame
import Data.Word
import Data.Maybe (isJust)
-- | A switch can be remotely commanded to send a packet. The packet
-- can either be a packet buffered at the switch, in which case the
-- bufferID is provided, or it can be specified explicitly by giving
-- the packet data.
data PacketOut
= PacketOutRecord {
bufferIDData :: !(Either BufferID B.ByteString), -- ^either a buffer ID or the data itself
packetInPort :: !(Maybe PortID), -- ^the port at which the packet received, for the purposes of processing this command
packetActions :: !ActionSequence -- ^actions to apply to the packet
} deriving (Eq,Show)
-- |A switch may buffer a packet that it receives.
-- When it does so, the packet is assigned a bufferID
-- which can be used to refer to that packet.
type BufferID = Word32
-- | Constructs a @PacketOut@ value for a packet buffered at a switch.
bufferedPacketOut :: BufferID -> Maybe PortID -> ActionSequence -> PacketOut
bufferedPacketOut bufID inPort actions =
PacketOutRecord { bufferIDData = Left bufID
, packetInPort = inPort
, packetActions = actions
}
-- | Constructs a @PacketOut@ value for an unbuffered packet, including the packet data.
unbufferedPacketOut :: B.ByteString -> Maybe PortID -> ActionSequence -> PacketOut
unbufferedPacketOut pktData inPort actions =
PacketOutRecord { bufferIDData = Right pktData
, packetInPort = inPort
, packetActions = actions
}
-- | Constructs a @PacketOut@ value that processes the packet referred to by the @PacketInfo@ value
-- according to the specified actions.
receivedPacketOut :: PacketInfo -> ActionSequence -> PacketOut
receivedPacketOut (PacketInfo {..}) actions =
case bufferID of
Nothing -> unbufferedPacketOut packetData (Just receivedOnPort) actions
Just bufID -> bufferedPacketOut bufID (Just receivedOnPort) actions
-- | A switch receives packets on its ports. If the packet matches
-- some flow rules, the highest priority rule is executed. If no
-- flow rule matches, the packet is sent to the controller. When
-- packet is sent to the controller, the switch sends a message
-- containing the following information.
data PacketInfo
= PacketInfo {
bufferID :: !(Maybe BufferID), -- ^buffer ID if packet buffered
packetLength :: !NumBytes, -- ^full length of frame
receivedOnPort :: !PortID, -- ^port on which frame was received
reasonSent :: !PacketInReason, -- ^reason packet is being sent
packetData :: !B.ByteString, -- ^ethernet frame, includes full packet only if no buffer ID
enclosedFrame :: !(Either String EthernetFrame) -- ^result of parsing packetData field.
} deriving (Show,Eq)
-- |A PacketInfo message includes the reason that the message
-- was sent, namely either there was no match, or there was
-- a match, and that match's actions included a Sent-To-Controller
-- action.
data PacketInReason = NotMatched | ExplicitSend deriving (Show,Read,Eq,Ord,Enum)
-- | The number of bytes in a packet.
type NumBytes = Int
bufferedAtSwitch :: PacketInfo -> Bool
bufferedAtSwitch = isJust . bufferID