README

CoreBGP

GoDev

CoreBGP is a BGP library written in Go that implements the BGP FSM with an event-driven, pluggable model. It exposes an API that empowers the user to:

  • send and validate OPEN message capabilities
  • handle "important" state transitions
  • handle incoming UPDATE messages
  • send outgoing UPDATE messages

CoreBGP does not decode UPDATE messages (besides header validation), manage a routing table, or send its own UPDATE messages. These responsibilities are all passed down to the user. Therefore, the intended user is someone who wants that responsibility.

See this blog post for the background and reasoning behind the development of CoreBGP.

The primary building block of CoreBGP is a Plugin, defined by the following interface:

// Plugin is a BGP peer plugin.
type Plugin interface {
	// GetCapabilities is fired when a peer's FSM is in the Connect state prior
	// to sending an Open message. The returned capabilities are included in the
	// Open message sent to the peer.
	GetCapabilities(peer PeerConfig) []Capability

	// OnOpenMessage is fired when an Open message is received from a peer
	// during the OpenSent state. Returning a non-nil Notification will cause it
	// to be sent to the peer and the FSM will transition to the Idle state.
	//
	// Per RFC5492 a BGP speaker should only send a Notification if a required
	// capability is missing; unknown or unsupported capabilities should be
	// ignored.
	OnOpenMessage(peer PeerConfig, routerID net.IP, capabilities []Capability) *Notification

	// OnEstablished is fired when a peer's FSM transitions to the Established
	// state. The returned UpdateMessageHandler will be fired when an Update
	// message is received from the peer.
	//
	// The provided writer can be used to send Update messages to the peer for
	// the lifetime of the FSM's current, established state. It should be
	// discarded once OnClose() fires.
	OnEstablished(peer PeerConfig, writer UpdateMessageWriter) UpdateMessageHandler

	// OnClose is fired when a peer's FSM transitions out of the Established
	// state.
	OnClose(peer PeerConfig)
}

Here's an example Plugin that logs when a peer enters/leaves an established state and when an UPDATE message is received:

type plugin struct{}

func (p *plugin) GetCapabilities(c corebgp.PeerConfig) []corebgp.Capability {
	caps := make([]corebgp.Capability, 0)
	return caps
}

func (p *plugin) OnOpenMessage(peer corebgp.PeerConfig, routerID net.IP, capabilities []corebgp.Capability) *corebgp.Notification {
	return nil
}

func (p *plugin) OnEstablished(peer corebgp.PeerConfig, writer corebgp.UpdateMessageWriter) corebgp.UpdateMessageHandler {
	log.Println("peer established")
	// send End-of-Rib
	writer.WriteUpdate([]byte{0, 0, 0, 0})
	return p.handleUpdate
}

func (p *plugin) OnClose(peer corebgp.PeerConfig) {
	log.Println("peer closed")
}

func (p *plugin) handleUpdate(peer corebgp.PeerConfig, u []byte) *corebgp.Notification {
	log.Printf("got update message of len: %d", len(u))
	return nil
}

Plugins are attached to peers when they are added to the Server, which manages their lifetime:

routerID := net.ParseIP("192.0.2.1")
srv, err := corebgp.NewServer(routerID)
if err != nil {
    log.Fatalf("error constructing server: %v", err)
}
p := &plugin{}
err = srv.AddPeer(corebgp.PeerConfig{
    LocalAddress:  routerID,
    RemoteAddress: net.ParseIP("198.51.100.10"),
    LocalAS:       65001,
    RemoteAS:      65010,
}, p)
if err != nil {
    log.Fatalf("error adding peer: %v", err)
}

For more examples check out the examples directory and pkg.go.dev for the complete API.

Documentation

Index

Constants

View Source
const (
	NotifCodeMessageHeaderErr uint8 = 1
	NotifCodeOpenMessageErr   uint8 = 2
	NotifCodeUpdateMessageErr uint8 = 3
	NotifCodeHoldTimerExpired uint8 = 4
	NotifCodeFSMErr           uint8 = 5
	NotifCodeCease            uint8 = 6
)

Notification code values

View Source
const (
	NotifSubcodeConnNotSync uint8 = 1
	NotifSubcodeBadLength   uint8 = 2
	NotifSubcodeBadType     uint8 = 3
)

message header Notification subcode values

View Source
const (
	NotifSubcodeUnsupportedVersionNumber uint8 = 1
	NotifSubcodeBadPeerAS                uint8 = 2
	NotifSubcodeBadBgpID                 uint8 = 3
	NotifSubcodeUnsupportedOptionalParam uint8 = 4
	NotifSubcodeUnacceptableHoldTime     uint8 = 5
	NotifSubcodeUnsupportedCapability    uint8 = 6
)

open message Notification subcode values

View Source
const (
	NotifSubcodeMalformedAttr             uint8 = 1
	NotifSubcodeUnrecognizedWellKnownAttr uint8 = 2
	NotifSubcodeMissingWellKnownAttr      uint8 = 3
	NotifSubcodeAttrFlagsError            uint8 = 4
	NotifSubcodeAttrLenError              uint8 = 5
	NotifSubcodeInvalidOrigin             uint8 = 6
	NotifSubcodeInvalidNextHop            uint8 = 8
	NotifSubcodeOptionalAttrError         uint8 = 9
	NotifSubcodeInvalidNetworkField       uint8 = 10
	NotifSubcodeMalformedASPath           uint8 = 11
)

update message Notification subcode values

View Source
const (
	NotifSubcodeUnexpectedMessageOpenSent    uint8 = 1
	NotifSubcodeUnexpectedMessageOpenConfirm uint8 = 2
	NotifSubcodeUnexpectedMessageEstablished uint8 = 3
)

finite state machine error subcode values [RFC6608]

View Source
const (
	// DefaultHoldTime is the default hold down time.
	DefaultHoldTime = time.Second * 90
	// DefaultIdleHoldTime is the default idle state hold time for a peer.
	DefaultIdleHoldTime = time.Second * 5
	// DefaultConnectRetryTime is the default maximum time spent waiting for an
	// outbound dial to connect.
	//
	// https://tools.ietf.org/html/rfc4271#section-8.2.2
	// The exact value of the ConnectRetryTimer is a local matter, but it
	// SHOULD be sufficiently large to allow TCP initialization.
	DefaultConnectRetryTime = time.Second * 5
	// DefaultPort is the default TCP port for a peer.
	DefaultPort = 179
)

Variables

View Source
var (
	ErrServerClosed = errors.New("server closed")
	ErrPeerNotExist = errors.New("peer does not exist")
)

Functions

func SetLogger

func SetLogger(l Logger)

SetLogger enables logging with the provided Logger.

func SetTCPMD5Signature

func SetTCPMD5Signature(fd int, address net.IP, prefixLen uint8,
	key string) error

SetTCPMD5Signature sets a tcp md5 signature on a socket for the provided address, prefix length, and key. This function is only supported on Linux. To unset a signature provide an empty key. Prefix length is ignored on kernels < 4.13.

https://tools.ietf.org/html/rfc2385

Types

type Capability

type Capability struct {
	Code  uint8
	Value []byte
}

Capability is a BGP capability as defined by RFC5492.

type Logger

type Logger func(...interface{})

Logger is a log.Print-compatible function

type Notification

type Notification struct {
	Code    uint8
	Subcode uint8
	Data    []byte
}

Notification is a Notification message.

type PeerConfig

type PeerConfig struct {
	LocalAddress  net.IP
	RemoteAddress net.IP
	LocalAS       uint32
	RemoteAS      uint32
}

PeerConfig is the required configuration for a Peer.

type PeerOption

type PeerOption interface {
	// contains filtered or unexported methods
}

func WithConnectRetryTime

func WithConnectRetryTime(t time.Duration) PeerOption

WithConnectRetryTime returns a PeerOption that sets the connect retry time for a peer.

func WithDialerControl

func WithDialerControl(fn func(network, address string,
	c syscall.RawConn) error) PeerOption

WithDialerControl returns a PeerOption that sets the outbound net.Dialer Control field. This is commonly used to set socket options, e.g. ip TTL, tcp md5, tcp_nodelay, etc...

func WithIdleHoldTime

func WithIdleHoldTime(t time.Duration) PeerOption

WithIdleHoldTime returns a PeerOption that sets the idle hold time for a peer. Idle hold time controls how quickly a peer can oscillate from idle to the connect state.

func WithPassive

func WithPassive() PeerOption

WithPassive returns a PeerOption that sets a Peer to passive mode. In passive mode a peer will not dial out and will only accept incoming connections.

func WithPort

func WithPort(p int) PeerOption

WithPort returns a PeerOption that sets the TCP port for a peer.

type Plugin

type Plugin interface {
	// GetCapabilities is fired when a peer's FSM is in the Connect state prior
	// to sending an Open message. The returned capabilities are included in the
	// Open message sent to the peer.
	GetCapabilities(peer PeerConfig) []Capability

	// OnOpenMessage is fired when an Open message is received from a peer
	// during the OpenSent state. Returning a non-nil Notification will cause it
	// to be sent to the peer and the FSM will transition to the Idle state.
	//
	// Per RFC5492 a BGP speaker should only send a Notification if a required
	// capability is missing; unknown or unsupported capabilities should be
	// ignored.
	OnOpenMessage(peer PeerConfig, routerID net.IP, capabilities []Capability) *Notification

	// OnEstablished is fired when a peer's FSM transitions to the Established
	// state. The returned UpdateMessageHandler will be fired when an Update
	// message is received from the peer.
	//
	// The provided writer can be used to send Update messages to the peer for
	// the lifetime of the FSM's current, established state. It should be
	// discarded once OnClose() fires.
	OnEstablished(peer PeerConfig, writer UpdateMessageWriter) UpdateMessageHandler

	// OnClose is fired when a peer's FSM transitions out of the Established
	// state.
	OnClose(peer PeerConfig)
}

Plugin is a BGP peer plugin.

type Server

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

Server is a BGP server that manages peers.

func NewServer

func NewServer(routerID net.IP) (*Server, error)

NewServer creates a new Server.

func (*Server) AddPeer

func (s *Server) AddPeer(config PeerConfig, plugin Plugin,
	opts ...PeerOption) error

AddPeer adds a peer to the Server to be handled with the provided Plugin and PeerOptions.

func (*Server) Close

func (s *Server) Close()

Close stops the Server. An instance of a stopped Server cannot be re-used.

func (*Server) DeletePeer

func (s *Server) DeletePeer(ip net.IP) error

DeletePeer deletes a peer from the Server.

func (*Server) GetPeer

func (s *Server) GetPeer(ip net.IP) (PeerConfig, error)

GetPeer returns the configuration for the provided peer, or an error if it does not exist.

func (*Server) ListPeers

func (s *Server) ListPeers() []PeerConfig

ListPeers returns the configuration for all peers.

func (*Server) Serve

func (s *Server) Serve(listeners []net.Listener) error

Serve starts all peers' FSMs, starts handling incoming connections if a non-nil listener is provided, and then blocks. Serve returns ErrServerClosed upon Close() or a listener error if one occurs.

type UpdateMessageHandler

type UpdateMessageHandler func(peer PeerConfig, updateMessage []byte) *Notification

UpdateMessageHandler handles Update messages. If a non-nil Notification is returned it will be sent to the peer and the FSM will transition out of the Established state.

type UpdateMessageWriter

type UpdateMessageWriter interface {
	// WriteUpdate sends an update message to the remote peer. An error is
	// returned if the write fails and/or the FSM is no longer in an established
	// state.
	WriteUpdate([]byte) error
}

Directories

Path Synopsis
examples