openflow

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 1, 2018 License: MIT Imports: 15 Imported by: 11

README

openflow - The OpenFlow protocol library

Build Status Documentation

The openflow library is a pure Go implementation of the OpenFlow protocol. The ideas of the programming interface mostly borrowed from the Go standard HTTP library.

Installation

$ go get github.com/netrack/openflow

Usage

The usage is pretty similar to the handling HTTP request, but instead of routes we are using message types.

package main

import (
    of "github.com/netrack/openflow"
)

func main() {
    // Define the OpenFlow handler for hello messages.
    of.HandleFunc(of.TypeHello, func(rw of.ResponseWriter, r *of.Request) {
        // Send back hello response.
        rw.Write(&of.Header{Type: of.TypeHello}, nil)
    })

    // Start the TCP server on 6633 port.
    of.ListenAndServe(":6633", nil)
}
package main

import (
    "github.com/netrack/openflow/ofp"
    of "github.com/netrack/openflow"
)

func main() {
    pattern := of.TypeMatcher(of.TypePacketIn)

    mux := of.NewServeMux()
    mux.HandleFunc(pattern, func(rw of.ResponseWriter, r *of.Request) {
        var packet ofp.PacketIn
        packet.ReadFrom(r.Body)

        apply := &ofp.InstructionApplyActions{
            ofp.Actions{&ofp.ActionOutput{ofp.PortFlood, 0}},
        }

        // For each incoming packet-in request, create a
        // respective flow modification command.
        fmod := ofp.NewFlowMod(ofp.FlowAdd, packet)
        fmod.Instructions = ofp.Instructions{apply}

        rw.Write(&of.Header{Type: of.TypeFlowMod}, fmod)
    })

    of.ListenAndServe(":6633", mux)
}

License

The openflow library is distributed under MIT license, therefore you are free to do with code whatever you want. See the LICENSE file for full license text.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrBodyTooLong is returned when actual request body exceeds the
	// length specified in the request header.
	ErrBodyTooLong = errors.New("openflow: Request body is too long")

	// ErrCorruptedHeader is returned when request body does not match
	// the length specified in a request header.
	ErrCorruptedHeader = errors.New("openflow: Corrupted header")
)
View Source
var DefaultHandler = DiscardHandler

DefaultHandler is the Handler used for Requests that don't have a Matcher.

View Source
var DefaultMux = NewTypeMux()

DefaultMux is an instance of the TypeMux used as a default handler in the DefaultServer instance.

View Source
var DiscardHandler = HandlerFunc(func(rw ResponseWriter, r *Request) {})

DiscardHandler is a Handler instance to discard the remote OpenFlow requests.

Functions

func Handle

func Handle(t Type, handler Handler)

Handle registers the handler for the given message type message in the DefaultMux. The documentation for TypeMux

func HandleFunc

func HandleFunc(t Type, f func(ResponseWriter, *Request))

HandleFunc registers the handler function on the given message type in the DefaultMux.

func HandleOnce

func HandleOnce(t Type, handler Handler)

HandleOnce registers a disposable handler for the given message type in the DefaultMux.

func ListenAndServe

func ListenAndServe(addr string, handler Handler) error

ListenAndServe listens on the given TCP address the handler. When handler set to nil, the default handler will be used.

A trivial example is:

of.HandleFunc(of.TypeEchoRequest, func(rw of.ResponseWriter, r *of.Request) {
	rw.Write(&of.Header{Type: of.TypeEchoReply}, nil)
})

of.ListenAndServe(":6633", nil)

func Send

func Send(c Conn, requests ...*Request) error

Send allows to send multiple requests at once to the connection.

The requests will be written to the per-call buffer. If the serialization of all given requests succeeded it will be flushed to the OpenFlow connection.

No data will be written when any of the request failed.

Types

type Conn

type Conn interface {
	// Receive receives message from input buffer
	Receive() (*Request, error)

	// Send writes message to output buffer
	Send(*Request) error

	// Close closes the connection. Any blocked Read or Write operations
	// will be unblocked and return errors.
	Close() error

	// Flush writes the messages from output buffer to the connection.
	Flush() error

	// LocalAddr returns the local network address.
	LocalAddr() net.Addr

	// RemoteAddr returns the remote network address.
	RemoteAddr() net.Addr

	// SetDeadline sets the read and write deadlines associated with the
	// connection.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for the future Receive calls.
	// If the deadline is reached, Receive will fail with a timeout (see
	// type Error) instead of blocking.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadLine sets the deadline for the future Send calls.
	// If the deadline is reached, Send will fail with a timeout (see
	// type Error) instead of blocking.
	SetWriteDeadline(t time.Time) error
}

Conn is an generic OpenFlow connection.

Multiple goroutines may invoke methods on conn simultaneously.

func Dial

func Dial(network, addr string) (Conn, error)

Dial establishes the remote connection to the address on the given network.

func DialTLS

func DialTLS(network, addr string, config *tls.Config) (Conn, error)

DialTLS establishes the remote connection to the address on the given network and then initiates TLS handshake, returning the resulting TLS connection.

func NewConn

func NewConn(c net.Conn) Conn

NewConn creates a new OpenFlow protocol connection.

type ConnState

type ConnState int

A ConnState represents the state of a client connection to a server. It's used by the optional Server.ConnState hook.

const (
	// StateNew represents a new connection that is expected to
	// send a request immediately. Connections begin at this
	// state and the transition to either StateHandshake or
	// StateClosed.
	StateNew ConnState = iota

	// StateHandshake represents a connection that has initiated
	// OpenFlow handshake routine. After the request is handled,
	// the state transitions to one of: StateHandshake, StateActive,
	// StateIdle or StateClosed.
	StateHandshake

	// StateActive represents a connection that has read 1 or more
	// bytes of the request. The Server.ConnState hook for StateActive
	// fires before the request has been handled.
	StateActive

	// StateIdle represents a connection that has finished
	// handling a request and is in the keep-alive state, waiting
	// for a new request. Connections transition from StateIdle
	// to StateHandshake, StateActive or StateClosed
	StateIdle

	// StateClosed represents a closed connection. This is a
	// terminal state.
	StateClosed
)

func (ConnState) String

func (c ConnState) String() string

String returns the string presentation of the ConnState.

type CookieJar

type CookieJar interface {
	SetCookies(uint64)
	Cookies() uint64
}

CookieJar manages storage and use of cookies in OpenFlow requests.

type CookieMatcher

type CookieMatcher struct {
	Cookies uint64

	// Reader is an OpenFlow message unmarshaler. CookieFilter will use
	// it to access the request cookie value. If the cookie matches, the
	// registered handler will be called to process the request. Otherwise
	// the request will be skipped.
	Reader CookieReader
}

CookieMatcher provides mechanism to hook up the message handler with an opaque data. Filter is safe for concurrent use by multiple goroutines.

func NewCookieMatcher

func NewCookieMatcher(j CookieJar) *CookieMatcher

NewCookieMatcher creates a new cookie matcher. The cookie value will be randomly generated using the functions from the standard library.

func (*CookieMatcher) Match

func (f *CookieMatcher) Match(r *Request) bool

Match compares the cookie from the message with the given one.

Cookie of each incoming request will be compared to the given cookie jar cookie. If the request cookie matches the registered one, the given handler will be used to process the request.

type CookieReader

type CookieReader interface {
	ReadCookie(io.Reader) (CookieJar, error)
}

CookieReader is the interface to read cookie jars.

CookieReader parses the body of the handling request and returns the cookie jar with containing cookies or nil when error occurs.

func CookieReaderOf

func CookieReaderOf(j CookieJar) CookieReader

CookieReaderOf creates a new cookie reader instance from the cookie jar. It uses reflection to create a new examplar of the given type, so the resulting reader is safe to use in multiple go-routines.

type CookieReaderFunc

type CookieReaderFunc func(io.Reader) (CookieJar, error)

The CookieReaderFunc is an adapter to allow use of ordinary functions as OpenFlow handlers. If fn is a function with the appropriate signature, CookieReaderFunc(fn) is a Reader that calls fn.

func (CookieReaderFunc) ReadCookie

func (fn CookieReaderFunc) ReadCookie(r io.Reader) (CookieJar, error)

ReadCookie calls the function with the specifier reader argument.

type Handler

type Handler interface {
	Serve(ResponseWriter, *Request)
}

A Handler responds to an OpenFlow request.

Serve should write the reply headers and the payload to the ResponseWriter and then return. Returning signals that the request is finished.

type HandlerFunc

type HandlerFunc func(ResponseWriter, *Request)

The HandlerFunc type is an adapter to allow use of ordinary functions as OpenFlow handlers.

func (HandlerFunc) Serve

func (h HandlerFunc) Serve(rw ResponseWriter, r *Request)

Serve calls f(rw, r).

type Header struct {
	// Version specifies the version of the protocol.
	Version uint8

	// Type defines a type of the message.
	Type Type

	// Length including this Header.
	Length uint16

	// Transaction is an transaction ID associated with this packet.
	//
	// Replies use the same id as was in the request to facilitate pairing.
	Transaction uint32
}

The Header is a response header. It contains the negotiated version of the OpenFlow, a type and length of the message.

func (*Header) Copy

func (h *Header) Copy() *Header

Copy returns a copy of the request header.

func (*Header) Len

func (h *Header) Len() int

Len of the packet payload including header.

func (*Header) ReadFrom

func (h *Header) ReadFrom(r io.Reader) (int64, error)

ReadFrom reads the header from the given reader in the wire format.

func (*Header) WriteTo

func (h *Header) WriteTo(w io.Writer) (int64, error)

WriteTo writes the header in the write format to the given writer.

type Listener

type Listener interface {
	// Accept waits for and returns the next connection.
	Accept() (Conn, error)

	// Close closes the listener.
	Close() error

	// Addr returns the listener network address.
	Addr() net.Addr
}

Listener is an OpenFlow network listener. Clients should typically use variables of type net.Listener instead of assuming OFP.

func Listen

func Listen(network, laddr string) (Listener, error)

Listen announces on the local network address laddr.

func ListenTLS

func ListenTLS(network, laddr string, config *tls.Config) (Listener, error)

ListenTLS announces on the local network address.

func NewListener

func NewListener(ln net.Listener) Listener

NewListener creates a new instance of the OpenFlow listener from the given network listener.

This function could be used to establish the communication channel over non-TCP sockets, like Unix sockets.

type Matcher

type Matcher interface {
	Match(*Request) bool
}

A Matcher interface is used by multiplexer to find the handler for the received request.

func MultiMatcher

func MultiMatcher(m ...Matcher) Matcher

MultiMatcher creates a new Matcher instance that matches the request by all specified criteria.

func TransactionMatcher

func TransactionMatcher(h *Header) Matcher

TransactionMatcher creates a new matcher that matches the request by the transaction identifier.

If the header has non-zero transaction identifier, it will be used to create a new matcher, otherwise a random number will be generated.

type MatcherFunc

type MatcherFunc struct {
	Func func(*Request) bool
}

MatcherFunc type is an adapter to allow the use of ordinary functions as OpenFlow request matchers.

func (*MatcherFunc) Match

func (m *MatcherFunc) Match(r *Request) bool

Match implements Matcher interface and calls fn(r).

type MultiRoutineRunner

type MultiRoutineRunner struct {
	// contains filtered or unexported fields
}

MultiRoutineRunner is a runner that assigns each function to one of the workers from the pool. So there is always a constant amount of goroutines.

func NewMultiRoutineRunner

func NewMultiRoutineRunner(num int) *MultiRoutineRunner

NewMultiRoutineRunner creates a new instance of MultiRoutinerRunner with a specified amount of workers. Method panics when number is not positive.

func (*MultiRoutineRunner) Run

func (mrr *MultiRoutineRunner) Run(fn func())

Run puts a function in the waiting queue and exists. This method returns control to the parent caller.

type OnDemandRoutineRunner

type OnDemandRoutineRunner struct{}

OnDemandRoutineRunner is a runner that starts each function in a separate goroutine. This handler is useful for initial prototyping, but it is highly recommended to use runner with a fixed amount of workers in order to prevent over goroutining (see MultiRoutineRunner).

func (OnDemandRoutineRunner) Run

func (OnDemandRoutineRunner) Run(fn func())

Run starts a function in a separate go-routine. This method implements Runner interface.

type Request

type Request struct {
	// Header contains the request header fields either received by
	// the server or sent by the client.
	Header Header

	// Body is the request's body. For client requests a nil
	// body means the request has no body, such as a echo requests.
	//
	// For server requests the Request Body is always non-nil
	// but will return EOF immediately when no body is present.
	Body io.Reader

	// The protocol version for incoming requests.
	// Client requests always use OFP/1.3.
	Proto      string
	ProtoMajor int // 1
	ProtoMinor int // 3

	Addr net.Addr

	// ContentLength records the length of the associated content.
	// Values >= 0 indicate that the given number of bytes may
	// be read from Body.
	ContentLength int64
	// contains filtered or unexported fields
}

A Request represents an OpenFlow request received by the server or to be sent by a client.

The field semantics differ slightly between client and server usage.

func NewRequest

func NewRequest(t Type, body io.WriterTo) *Request

NewRequest returns a new Request given a type, address, and optional body.

func (*Request) Conn

func (r *Request) Conn() Conn

Conn returns the instance of the OpenFlow protocol connection.

func (*Request) ProtoAtLeast

func (r *Request) ProtoAtLeast(major, minor int) bool

ProtoAtLeast reports whether the OpenFlow protocol used in the request is at least major.minor.

func (*Request) ReadFrom

func (r *Request) ReadFrom(rd io.Reader) (n int64, err error)

ReadFrom implements ReaderFrom interface. Reads the request in wire format from the r to the Request structure.

func (*Request) WriteTo

func (r *Request) WriteTo(w io.Writer) (n int64, err error)

WriteTo implements WriterTo interface. Writes the request in wire format to w until there's no more data to write or when an error occurs.

type ResponseWriter

type ResponseWriter interface {
	// Write writes the data to the connection as part of an OpenFlow reply.
	Write(*Header, io.WriterTo) error
}

A ResponseWriter interface is used by an OpenFlow handler to construct an OpenFlow Response.

type Runner

type Runner interface {
	Run(func())
}

Runner describes types used to start a function according to the defined concurrency model.

type SequentialRunner

type SequentialRunner struct{}

SequentialRunner is a runner that starts each function one by one. New function does not start execution until the previous one is done.

This runner is useful for debugging purposes.

func (SequentialRunner) Run

func (SequentialRunner) Run(fn func())

Run starts a function as is. This method implements Runner interface.

type ServeMux

type ServeMux struct {
	// contains filtered or unexported fields
}

ServeMux is an OpenFlow request multiplexer.

func NewServeMux

func NewServeMux() *ServeMux

NewServeMux allocates and returns a new ServeMux.

func (*ServeMux) Handle

func (mux *ServeMux) Handle(m Matcher, h Handler)

Handle registers the handler for the given pattern.

func (*ServeMux) HandleFunc

func (mux *ServeMux) HandleFunc(m Matcher, h HandlerFunc)

HandleFunc registers handler function for the given pattern.

func (*ServeMux) HandleOnce

func (mux *ServeMux) HandleOnce(m Matcher, h Handler)

HandleOnce registers disposable handler for the given pattern.

It is not guaranteed that handler will process the first message exemplar of the matching message.

func (*ServeMux) Handler

func (mux *ServeMux) Handler(r *Request) Handler

Handler returns a handler of the specified request.

func (*ServeMux) Serve

func (mux *ServeMux) Serve(rw ResponseWriter, r *Request)

Serve implements Handler internface. It processing the request and writes back the response.

type Server

type Server struct {
	// Addr is an address to listen on.
	Addr string

	// HandlerRunner defines concurrency model of handling requests from
	// the switch within a single connection.
	//
	// By default OnDemandRoutineRunner is used.
	HandlerRunner Runner

	// Handler to invoke on the incoming requests.
	Handler Handler

	// Maximum duration before timing out the read of the request.
	ReadTimeout time.Duration

	// Maximum duration before timing out the write of the response.
	WriteTimeout time.Duration

	// ConnRunner defines concurrency model of processing client connections.
	//
	// By default each accepted connection is handled in a standalone
	// goroutine. Such approach could result in a consuming all CPU and
	// Memory resourses of the computer, therefore it is higly recommended
	// to server connections only on a fixed amount of workers (see
	// MultiRoutineRunner).
	ConnRunner Runner

	// ConnState specifies an optional callback function that is called
	// when a client connection changes state.
	ConnState func(Conn, ConnState)

	// MaxConns defines the maximum number of client connections server
	// handles, the rest will be explicitly closed. Zero means no limit.
	MaxConns int
	// contains filtered or unexported fields
}

A Server defines parameters for running OpenFlow server.

func (*Server) ListenAndServe

func (srv *Server) ListenAndServe() error

ListenAndServe listens on the network address and then calls Server to handle requests on the incoming connections.

func (*Server) Serve

func (srv *Server) Serve(l net.Listener) error

Serve accepts incoming connections on the Listener l, creating a new service goroutine for each.

type Type

type Type uint8

Type is an OpenFlow message type.

const (
	// TypeHello is used by either controller or switch during connection
	// setup. It is used for version negotiation. When the connection
	// is established, each side must immediately send a Hello message
	// with the version field set to the highest version supported by
	// the sender. If the version negotiation fails, an Error message
	// is sent with type HelloFailed and code Incompatible.
	TypeHello Type = iota

	// TypeError can be sent by either the switch or the controller and
	// indicates the failure of an operation. The simplest failure pertain
	// to malformed messages or failed version negotiation, while more
	// complex scenarios desbie some failure in state change at the switch.
	TypeError

	// TypeEchoRequest is used to exchange information about latency,
	// bandwidth and liveness. Echo request timeout indicates disconnection.
	TypeEchoRequest

	// TypeEchoReply is used to exchange information about latency,
	// bandwidth and liveness. Echo reply is sent as a response to Echo
	// request.
	TypeEchoReply

	// TypeExperiment is a mechanism for proprietary messages within the
	// protocol.
	TypeExperiment

	// TypeFeaturesRequest is used when a transport channel (TCP, SCTP,
	// TLS) is established between the switch and controller, the first
	// activity is feature determination. The controller will send a
	// feature request to the switch over the transport channel.
	TypeFeaturesRequest

	// TypeFeaturesReply is the switch's reply to the controller
	// enumerating its abilities.
	TypeFeaturesReply

	// TypeGetConfigRequest sequence is used to query and set the
	// fragmentation handling properties of the packet processing pipeline.
	TypeGetConfigRequest

	// TypeGetConfigReply is the switch's reply to the controller
	// that acknowledges configuration requests.
	TypeGetConfigReply

	// TypeSetConfig is used by the controller to alter the switch's
	// configuration. This message is unacknowledged.
	TypeSetConfig

	// TypePacketIn message is a way for the switch to send a captured
	// packet to the controller.
	TypePacketIn

	// TypeFlowRemoved is sent to the controller by the switch when a
	// flow entry in a flow table is removed. It happens when a timeout
	// occurs, either due to inactivity or hard timeout. An idle timeout
	// happens when no packets are matched in a period of time. A hard
	// timeout happens when a certain period of time elapses, regardless
	// of the number of matching packets. Whether the switch sends a
	// TypeFlowRemoved message after a timeout is specified by the
	// TypeFlowMod. Flow entry removal with a TypeFlowMod message from
	// the controller can also lead to a TypeFlowRemoved message.
	TypeFlowRemoved

	// TypePortStatus messages are asynchronous events sent from the
	// switch to the controller indicating a change of status for the
	// indicated port.
	TypePortStatus

	// TypePacketOut is used by the controller to inject packets into the
	// data plane of a particular switch. Such message can either carry a
	// raw packet to inject into the switch, or indicate a local buffer
	// on the switch containing a raw packet to release. Packets injected
	// into the data plane of a switch using this method are not treated
	// the same as packets that arrive on standard ports. The packet jumps
	// to the action set application stage in the standard packet processing
	// pipeline. If the action set indicates table processing is necessary
	// then the input port id is used as the arrival port of the raw packet.
	TypePacketOut

	// TypeFlowMod is one of the main messages, it allows the controller
	// to modify the state of switch.
	TypeFlowMod

	// TypeGroupMod is used by controller to modify group tables.
	TypeGroupMod

	// TypePortMod is used by the controller to modify the state of port.
	TypePortMod

	// TypeTableMod is used to determine a packet's fate when it misses
	// in the table. It can be forwarded to the controller, dropped, or
	// sent to the next table.
	TypeTableMod

	// TypeMultipartRequest is used by the controller to request the
	// state of the datapath.
	TypeMultipartRequest

	// TypeMultipartReply are the replies from the switch to controller
	// on TypeMultipartRequest messages.
	TypeMultipartReply

	// TypeBarrierRequest can be used by the controller to set a
	// synchronization point, ensuring that all previous state messages
	// are completed before the barrier response is sent back to the
	// controller.
	TypeBarrierRequest

	// TypeBarrierReply is a response from the switch to controller
	// on TypeBarrierRequest messages.
	TypeBarrierReply

	// TypeQueueGetConfigRequest can be used by the controller to
	// query the state of queues associated with various ports on switch.
	TypeQueueGetConfigRequest

	// TypeQueueGetConfigReply is a response from the switch to controller
	// on TypeQueueGetConfigReply messages.
	TypeQueueGetConfigReply

	// TypeRoleRequest is the message used by the controller to
	// modify its role among multiple controllers on a switch.
	TypeRoleRequest

	// TypeRoleReply is a response from the switch to controller on
	// TypeRoleRequest.
	TypeRoleReply

	// TypeGetAsyncRequest is used by the controller to request the switch
	// which asynchronous events are enabled on the switch for the
	// communication channel.
	TypeGetAsyncRequest

	// TypeGetAsyncReply is used by the switch as response to controller
	// on TypeAsyncRequest messages.
	TypeGetAsyncReply

	// TypeSetAsync is used by the controller to set which asynchronous
	// messages it should send, as well as to query the switch for which
	// asynchronous messages it will send.
	TypeSetAsync

	// TypeMeterMod used by the controller to modify the meter.
	TypeMeterMod
)

func (Type) String

func (t Type) String() string

type TypeMatcher

type TypeMatcher Type

TypeMatcher used to match requests by their types.

func (TypeMatcher) Match

func (t TypeMatcher) Match(r *Request) bool

Match implements Matcher interface and matches the request by the type.

type TypeMux

type TypeMux struct {
	// contains filtered or unexported fields
}

TypeMux is an OpenFlow request multiplexer. It matches the type of the OpenFlow message against a list of registered handlers and calls the marching handler.

func NewTypeMux

func NewTypeMux() *TypeMux

NewTypeMux creates and returns a new TypeMux.

func (*TypeMux) Handle

func (mux *TypeMux) Handle(t Type, h Handler)

Handle registers the handler for the given message type.

func (*TypeMux) HandleFunc

func (mux *TypeMux) HandleFunc(t Type, f HandlerFunc)

HandleFunc registers handler function for the given message type.

func (*TypeMux) HandleOnce

func (mux *TypeMux) HandleOnce(t Type, h Handler)

HandleOnce registers a disposable handler for the given message type.

func (*TypeMux) Handler

func (mux *TypeMux) Handler(r *Request) Handler

Handler returns a Handler instance for the given OpenFlow request.

func (*TypeMux) Serve

func (mux *TypeMux) Serve(rw ResponseWriter, r *Request)

Serve implements Handler internface. It processing the request and writes back the response.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL