ubgpsuite/lonetix/include/df/bgp/bgp.h

1199 lines
38 KiB
C
Executable File

// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file bgp/bgp.h
*
* Border Gateway Protocol version 4 (BGP-4) types and functions.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*
* \see [RFC 4271](https://tools.ietf.org/html/rfc4271)
*/
#ifndef DF_BGP_MSG_H_
#define DF_BGP_MSG_H_
#include "bgp/asn.h"
#include "bgp/prefix.h"
#include "mem.h"
#include "srcloc.h"
#include "stm.h"
/// Result of an operation over a BGP message or data type.
typedef enum {
// NOTE: Enum member ordering is IMPORTANT
// BGP message filtering VM error codes (negative values, fit into Sint8)
BGPEBADVM = -16, ///< Attempting operation on VM with a failed setup state flag
BGPEVMNOPROG = -15, ///< VM program is empty
BGPEVMBADCOMTCH = -14, ///< COMMUNITY Match expression is invalid or too complex
BGPEVMASMTCHESIZE = -13, ///< AS Match expression is so complex it cannot be evaluated within a reasonable memory limit
BGPEVMASNGRPLIM = -12, ///< `BGP_VMOP_ASMTCH` has too many nested grouping levels
BGPEVMBADASMTCH = -11, ///< `BGP_VMOP_ASMTCH` has inconsistent matching rules
BGPEVMBADJMP = -10, ///< Jump instruction beyond program's `END`.
BGPEVMILL = -9, ///< Illegal instruction
BGPEVMOOM = -8, ///< VM heap exhausted (out of memory)
BGPEVMBADENDBLK = -7, ///< `ENDBLK` instruction with no corresponding `BLK`
BGPEVMUFLOW = -6, ///< BGP VM Stack underflow
BGPEVMOFLOW = -5, ///< BGP VM Stack overflow
BGPEVMBADFN = -4, ///< `CALL` instruction references bad function index
BGPEVMBADK = -3, ///< `LOADK` instruction references bad constant index
BGPEVMMSGERR = -2, ///< Accessing BGP message caused an error `Bgp_GetErrStat()` for details)
BGPEVMBADOP = -1, ///< Bad VM instruction operand (e.g. AFI_IP PATRICIA was expected, but AFI_IP6 is provided)
BGPENOERR = 0, ///< No error (success)
BGPENOMEM, ///< Memory allocation failure
// NOTE: following enumeration need not to fit inside `BgpvmRet`
BGPEIO, ///< Read error from input stream (see `Bgp_ReadMsg()`)
BGPEBADTYPE, ///< Provided wrong message type for the required operation
BGPENOADDPATH, ///< Attempt to access ADD_PATH information but message is not ADD_PATH enabled
BGPEBADATTRTYPE, ///< Provided wrong attribute type for the required operation
BGPEBADMARKER, ///< Invalid or corrupted initial BGP marker detected
BGPETRUNCMSG, ///< Truncated BGP message (incomplete header or data)
BGPEOVRSIZ, ///< Oversized BGP message (message length exceeding `BGP_MSGSIZ`)
BGPEBADOPENLEN, ///< BGP OPEN message has inconsistent length
BGPEBADAGGR, ///< Malformed AGGREGATOR attribute
BGPEBADAGGR4, ///< Malformed AS4_AGGREGATOR attribute
BGPEDUPNLRIATTR, ///< Duplicate multiprotocol/NLRI attribute inside UPDATE message
BGPEBADPFXWIDTH, ///< Prefix has illegal width (e.g. IPv4 prefix with `width > 32`)
BGPETRUNCPFX, ///< Message contains a truncated prefix
BGPETRUNCATTR, ///< Truncated BGP attribute
BGPEAFIUNSUP, ///< Unknown address family identifier inside message
BGPESAFIUNSUP, ///< Unknown subsequent address family identifier inside message
BGPEBADMRTTYPE, ///< Provided wrong MRT record type for the required operation
BGPETRUNCMRT, ///< Truncated MRT record (incomplete header or data)
BGPEBADPEERIDXCNT, ///< TABLE_DUMPV2 PEER_INDEX_TABLE record contains incoherent peer entry count
BGPETRUNCPEERV2, ///< TABLE_DUMPV2 PEER_INDEX_TABLE record contains truncated peer entry
BGPEBADRIBV2CNT, ///< TABLE_DUMPV2 RIB record contains incoherent RIB entry count
BGPETRUNCRIBV2, ///< TABLE_DUMPV2 RIB record contains a truncated RIB entry
BGPEBADRIBV2MPREACH, ///< TABLE_DUMPV2 RIB record contains an illegal MP_REACH attribute
BGPERIBNOMPREACH, ///< TABLE_DUMP or TABLE_DUMPV2 IPv6 RIB record lacks MP_REACH_NLRI attribute
BGPEBADPEERIDX, ///< Attempt to access an out of bounds peer entry
} BgpRet;
/// Test whether a `BgpRet` belongs to the `Bgpvm` error category.
FORCE_INLINE Boolean BGP_ISVMERR(BgpRet err)
{
return err < BGPENOERR && err >= BGPEBADVM;
}
/// Test whether a `BgpRet` belongs to the BGP error category.
FORCE_INLINE Boolean BGP_ISMSGERR(BgpRet err)
{
return err >= BGPEBADTYPE && err <= BGPESAFIUNSUP;
}
/// Test whether a `BgpRet` belongs to the MRT error category.
FORCE_INLINE Boolean BGP_ISMRTERR(BgpRet err)
{
return err >= BGPEBADMRTTYPE && err <= BGPEBADPEERIDX;
}
/// Translate a `BgpRet` to a descriptive human readable string.
const char *Bgp_ErrorString(BgpRet err);
/// BGP library current result status.
typedef struct {
/// Latest operation result.
BgpRet code;
/**
* \brief Current error handler function.
*/
void (*func)(BgpRet, Srcloc *, void *);
/// Additional user data, forwarded to error handler unaltered.
void *obj;
} BgpErrStat;
/// Ignoring error handler, no error management is done with this handler.
#define BGP_ERR_IGN ((void (*)(BgpRet, Srcloc *, void *)) 0)
/**
* \brief Abort error handler, terminates execution abnormally on error,
* providing an useful error trace if possible.
*/
#define BGP_ERR_QUIT ((void (*)(BgpRet, Srcloc *, void *)) -1)
/**
* Install BGP error handler.
*/
void Bgp_SetErrFunc(void (*func)(BgpRet, Srcloc *, void *), void *obj);
/// Retrieve the latest operation outcome and extended error status information.
BgpRet Bgp_GetErrStat(BgpErrStat *stat);
/**
* \name BGP message types
*
* @{
*/
#define BGP_OPEN U8_C(1) ///< `OPEN` message
#define BGP_UPDATE U8_C(2) ///< `UPDATE` message
#define BGP_NOTIFICATION U8_C(3) ///< `NOTIFICATION` message
#define BGP_KEEPALIVE U8_C(4) ///< `KEEPALIVE` message
#define BGP_ROUTE_REFRESH U8_C(5) ///< `ROUTE_REFRESH` message
#define BGP_CLOSE U8_C(255) ///< `CLOSE` message
typedef Uint8 BgpType; ///< Message type octet inside BGP header.
/** @} */
/**
* \name BGP Finite State Machine values
*
* \see [RFC 4271 Section 8.2.2](\ref https://tools.ietf.org/html/rfc4271#section-8.2.2)
*
* \note Values are in network byte order (big endian).
*
* @{
*/
#define BGP_FSM_IDLE BE16(1) ///< `IDLE` state
#define BGP_FSM_CONNECT BE16(2) ///< `CONNECT` state
#define BGP_FSM_ACTIVE BE16(3) ///< `ACTIVE` state
#define BGP_FSM_OPENSENT BE16(4) ///< `OPENSENT` state
#define BGP_FSM_OPENCONFIRM BE16(5) ///< `OPENCONFIRM` state
#define BGP_FSM_ESTABLISHED BE16(6) ///< `ESTABLISHED` state
typedef Uint16 BgpFsmState; ///< BGP Finite State Machine status code value.
/** @} */
/// Size of the BGP marker field inside the BGP message header in bytes.
#define BGP_MARKER_LEN 16u
/// Size of the BGP message header, in bytes.
#define BGP_HDRSIZ 19u
/// Maximum legal size for a regular BGP message, in bytes.
#define BGP_MSGSIZ 0x1000u
/// Maximum legal size for an extended BGP message, in bytes.
#define BGP_EXMSGSIZ 0xffffu
/**
* \name BGP message flags
*
* \see `Bgpmsg` `flags` field
*
* @{
*/
/// Flag indicating the `Bgpmsg` structure is using an unowned buffer.
#define BGPF_UNOWNED BIT(0)
/// Flag indicating a BGP message uses 32 bits ASN.
#define BGPF_ASN32BIT BIT(1)
/// Flag indicating a BGP message containing ADD_PATH information.
#define BGPF_ADDPATH BIT(2)
/// Flag to allow BGP messages exceeding 4096 bytes size limit up to 65535 bytes.
#define BGPF_EXMSG BIT(3)
/**
* \brief Flag used by `Bgp_RebuildMsgFromRib()`, specifies attribute parameter
* is in TABLE_DUMPV2 format.
*
* \note If this flag is not set, any ADD_PATH information inside
* NLRI is discarded, as TABLE_DUMP doesn't support it.
*
* \see `Bgp_RebuildMsgFromRib()`
*/
#define BGPF_RIBV2 BIT(4)
/**
* \brief Require strict [RFC 6396](https://tools.ietf.org/html/rfc6396)
* compliance when building a BGP message from a MRT snapshot.
*
* Some MRT RIBs don't fully adhere to RFC format specification, by leaving
* AFI and SAFI information inside MP_REACH as opposed to omitting it as
* required by the standard. Such behavior is detected and tolerated by
* default; by specifying this flag an explicit request is made to apply
* the RFC verbatim.
*
* \see `Bgp_RebuildMsgFromRib()`
*/
#define BGPF_STRICT_RFC6396 BIT(5)
/**
* \brief When rebuilding a `Bgpmsg` from either TABLE_DUMPV2 or TABLE_DUMP,
* strip MP_UNREACH_NLRI if encountered.
*
* \see `Bgp_RebuildMsgFromRib()`
*/
#define BGPF_STRIPUNREACH BIT(6)
/**
* \brief When rebuilding a `Bgpmsg` from either TABLE_DUMPV2 or TABLE_DUMP,
* erase MP_UNREACH_NLRI attribute contents when encountered,
* but leave it in attribute list.
*
* \note Compared to `BGPF_STRIPUNREACH`, this preserves the information that
* an MP_UNREACH_NLRI attribute was effectively encountered, while
* discarding its contents to avoid processing them. It also preserves
* the original attribute offset inside the `Bgpattrtab`, allowing
* efficient lookup over the original RIB, when original content is
* relevant.
*
* \see `Bgp_RebuildMsgFromRib()`
*/
#define BGPF_CLEARUNREACH BIT(7)
/** @} */
/**
* \name BGP parameter codes
*
* @{
*/
/// BGP parameter capability code.
#define BGP_PARM_CAPABILITY U8_C(2)
typedef Uint8 BgpParmCode; ///< Octet inside a `Bgpparm' identifying the parameter
/** @} */
/**
* \name BGP capability codes
*
* \see [IANA Assigned Capability Codes](https://www.iana.org/assignments/capability-codes/capability-codes.xhtml)
*
* @{
*/
#define BGP_CAP_RESERVED U8_C(0) ///< RFC 5492
#define BGP_CAP_MULTIPROTOCOL U8_C(1) ///< RFC 2858
#define BGP_CAP_ROUTE_REFRESH U8_C(2) ///< RFC 2918
#define BGP_CAP_COOPERATIVE_ROUTE_FILTERING U8_C(3) ///< RFC 5291
#define BGP_CAP_MULTIPLE_ROUTES_DEST U8_C(4) ///< RFC 3107
#define BGP_CAP_EXTENDED_NEXT_HOP U8_C(5) ///< RFC 5549
#define BGP_CAP_EXTENDED_MESSAGE U8_C(6) ///< https://tools.ietf.org/html/draft-ietf-idr-bgp-extended-messages-21
#define BGP_CAP_BGPSEC U8_C(7) ///< https://tools.ietf.org/html/draft-ietf-sidr-bgpsec-protocol-23
#define BGP_CAP_MULTIPLE_LABELS U8_C(8) ///< https://www.iana.org/go/rfc8277
#define BGP_CAP_BGP_ROLE U8_C(9) ///< draft-ietf-idr-bgp-open-policy
#define BGP_CAP_GRACEFUL_RESTART U8_C(64) ///< RFC 4724
#define BGP_CAP_ASN32BIT U8_C(65) ///< RFC 6793
#define BGP_CAP_DYNAMIC_CISCO U8_C(66) ///< Cisco version of Dynamic capability
#define BGP_CAP_DYNAMIC U8_C(67)
#define BGP_CAP_MULTISESSION U8_C(68) ///< draft-ietf-idr-bgp-multisession
#define BGP_CAP_ADD_PATH U8_C(69) ///< RFC 7911
#define BGP_CAP_ENHANCED_ROUTE_REFRESH U8_C(70) ///< RFC 7313
#define BGP_CAP_LONG_LIVED_GRACEFUL_RESTART U8_C(71) ///< https://tools.ietf.org/html/draft-uttaro-idr-bgp-persistence-03
#define BGP_CAP_CP_ORF U8_C(72) ///< RFC 7543
#define BGP_CAP_FQDN U8_C(73) ///< https://tools.ietf.org/html/draft-walton-bgp-hostname-capability-02
#define BGP_CAP_ROUTE_REFRESH_CISCO U8_C(128) ///< Deprecated https://www.iana.org/go/rfc8810
#define BGP_CAP_ORF_CISCO U8_C(130) ///< Deprecated https://www.iana.org/go/rfc8810
#define BGP_CAP_MULTISESSION_CISCO U8_C(131) ///< Cisco version of multisession_bgp
typedef Uint8 BgpCapCode;
/** @} */
/**
* \name Known BGP attribute codes
*
* @{
*/
#define BGP_ATTR_ORIGIN U8_C(1)
#define BGP_ATTR_AS_PATH U8_C(2)
#define BGP_ATTR_NEXT_HOP U8_C(3)
#define BGP_ATTR_MULTI_EXIT_DISC U8_C(4)
#define BGP_ATTR_LOCAL_PREF U8_C(5)
#define BGP_ATTR_ATOMIC_AGGREGATE U8_C(6)
#define BGP_ATTR_AGGREGATOR U8_C(7)
#define BGP_ATTR_COMMUNITY U8_C(8)
#define BGP_ATTR_ORIGINATOR_ID U8_C(9)
#define BGP_ATTR_CLUSTER_LIST U8_C(10)
#define BGP_ATTR_DPA U8_C(11)
#define BGP_ATTR_ADVERTISER U8_C(12)
#define BGP_ATTR_RCID_PATH_CLUSTER_ID U8_C(13)
#define BGP_ATTR_MP_REACH_NLRI U8_C(14)
#define BGP_ATTR_MP_UNREACH_NLRI U8_C(15)
#define BGP_ATTR_EXTENDED_COMMUNITY U8_C(16)
#define BGP_ATTR_AS4_PATH U8_C(17)
#define BGP_ATTR_AS4_AGGREGATOR U8_C(18)
#define BGP_ATTR_SAFI_SSA U8_C(19)
#define BGP_ATTR_CONNECTOR U8_C(20)
#define BGP_ATTR_AS_PATHLIMIT U8_C(21)
#define BGP_ATTR_PMSI_TUNNEL U8_C(22)
#define BGP_ATTR_TUNNEL_ENCAPSULATION U8_C(23)
#define BGP_ATTR_TRAFFIC_ENGINEERING U8_C(24)
#define BGP_ATTR_IPV6_ADDRESS_SPECIFIC_EXTENDED_COMMUNITY U8_C(25)
#define BGP_ATTR_AIGP U8_C(26)
#define BGP_ATTR_PE_DISTINGUISHER_LABELS U8_C(27)
#define BGP_ATTR_ENTROPY_LEVEL_CAPABILITY U8_C(28)
#define BGP_ATTR_LS U8_C(29)
#define BGP_ATTR_LARGE_COMMUNITY U8_C(32)
#define BGP_ATTR_BGPSEC_PATH U8_C(33)
#define BGP_ATTR_COMMUNITY_CONTAINER U8_C(34)
#define BGP_ATTR_PREFIX_SID U8_C(40)
#define BGP_ATTR_SET U8_C(128)
#define BGP_ATTR_RESERVED U8_C(255)
typedef Uint8 BgpAttrCode;
/** @} */
/// Length of a fast attribute lookup table.
#define BGP_ATTRTAB_LEN 12 // NOTE: Keep in sync with attributes.c
// Low level BGP attributes offset table manipulation
/// Fast attribute lookup table, keep track of most relevant BGP attributes offset inside TPA.
typedef Sint16 Bgpattrtab[BGP_ATTRTAB_LEN]; // NOTE: despite being Sint16, it's still used as if Uint16
// Special offsets inside Bgpattrtab
/// Attribute offset is yet unknown (special value for `Bgpattrtab`).
#define BGP_ATTR_UNKNOWN -1 // NOTE: 0xffff, DO NOT change! assumed by memset()!
/// Attribute not present inside message TPA (special value for `Bgpattrtab`).
#define BGP_ATTR_NOTFOUND -2
/// `BgpAttrCode` -> index inside `Bgpattrtab` translation table, -1 for "Not available".
extern const Sint8 bgp_attrTabIdx[256];
/// Reset all `Bgpattrtab` entries to `BGP_ATTR_UNKNOWN`.
FORCE_INLINE void BGP_CLRATTRTAB(Bgpattrtab tab)
{
EXTERNC void *memset(void *, int, size_t);
STATIC_ASSERT(BGP_ATTR_UNKNOWN == -1, "memset() assumes BGP_ATTR_UNKNOWN == -1");
memset(tab, 0xff, BGP_ATTRTAB_LEN * sizeof(*tab));
}
/**
* \brief BGP message.
*
* `Bgpmsg` holds memory and metadata required to properly
* intepret a BGP message of any type. This structure
* should not be used to build a BGP message from scratch.
* Its model is biased towards zero-copy and minimal overhead BGP
* decoding. No actual consistency check over BGP data occurs unless it is
* explicitly accessed, thus any operation may fail on corrupted data.
*
* The underlying message buffer may be allocated upon initialization
* (`Bgpmsg` operates on an owned message buffer), or be borrowed as is
* (`Bgpmsg` operates on an unowned message buffer).
* In the latter case the buffer is understood to remain valid
* for the entire lifetime of the message structure, and is not freed on
* `Bgp_ClearMsg()`.
*
* An optional `MemOps` interface may be provided to customize
* memory allocation (e.g. implement memory pools for BGP messages).
* `allocp` and `memOps` fields are never modified by any function,
* thus a `Bgpmsg` structure willing to customize its memory
* allocation policy should initialize in advance these fields for the API
* to use it.
* If `memOps` is `NULL`, `Mem_StdOps` is used.
*
* \see [RFC 4271](https://tools.ietf.org/html/rfc4271)
*/
typedef struct {
Uint8 *buf; ///< Underlying message buffer
Uint16 flags; ///< Message flags, any of the `BGPF_*` flag
void *allocp; ///< Optional allocator for custom memory allocation policy
const MemOps *memOps; ///< Optional custom memory allocation operations
Bgpattrtab table; ///< Fast attribute lookup table
} Bgpmsg;
/// Move `Bgpmsg` contents from `src` to `dest`, leaving `src` empty.
FORCE_INLINE void BGP_MOVEMSG(Bgpmsg *dest, Bgpmsg *src)
{
EXTERNC void *memcpy(void *, const void *, size_t);
memcpy(dest, src, sizeof(*dest));
src->buf = NULL;
}
/// Test `Bgpmsg` flags field for `BGPF_UNOWNED`.
FORCE_INLINE Boolean BGP_ISUNOWNED(Uint16 flags)
{
return (flags & BGPF_UNOWNED) != 0;
}
/// Test `Bgpmsg` flags field for `BGPF_ASN32BIT`.
FORCE_INLINE Boolean BGP_ISASN32BIT(Uint16 flags)
{
return (flags & BGPF_ASN32BIT) != 0;
}
/// Test `Bgpmsg` flags field for `BGPF_ADDPATH`.
FORCE_INLINE Boolean BGP_ISADDPATH(Uint16 flags)
{
return (flags & BGPF_ADDPATH) != 0;
}
/// Test `Bgpmsg` flags field for `BGPF_EXMSG`.
FORCE_INLINE Boolean BGP_ISEXMSG(Uint16 flags)
{
return (flags & BGPF_EXMSG) != 0;
}
/// Retrieve memory operations associated with `msg`.
FORCE_INLINE const MemOps *BGP_MEMOPS(const Bgpmsg *msg)
{
return msg->memOps ? msg->memOps : Mem_StdOps;
}
/**
* \name BGP NOTIFICATION error codes
*
* @{
*/
#define BGP_ERRC_UNSPEC U8_C(0)
#define BGP_ERRC_MSGHDR U8_C(1)
#define BGP_ERRC_OPEN U8_C(2)
#define BGP_ERRC_UPDATE U8_C(3)
#define BGP_ERRC_EXPIRED U8_C(4)
#define BGP_ERRC_FSM U8_C(5)
#define BGP_ERRC_CEASE U8_C(6)
/// [BGP NOTIFICATION](\ref Bgpnotification) error code octet.
typedef Uint8 BgpErrCode;
/**
* \brief [BGP NOTIFICATION](\ref Bgpnotification) error subcode octet.
*
* Depending on the NOTIFICATION message error code, its subcode
* field further elaborates on the BGP error.
*/
typedef Uint8 BgpErrSubCode;
/** @} */
// Specific BGP message types
#pragma pack(push, 1)
/**
* \brief BGP message header.
* \see [RFC 4271](https://tools.ietf.org/html/rfc4271#section-6.1)
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Uint8 marker[BGP_MARKER_LEN]; ///< Marker, should be 0xff filled
Uint16 len; ///< Message length in bytes, including header itself
BgpType type; ///< Message type
} Bgphdr;
/// Retrieve pointer to BGP message header.
FORCE_INLINE Bgphdr *BGP_HDR(const Bgpmsg *msg)
{
return (Bgphdr *) msg->buf;
}
/**
* \brief BGP OPEN message.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Bgphdr hdr; ///< Common message header
Uint8 version; ///< Supported BGP version (typically 4)
Uint16 holdTime; ///< BGP session hold time in seconds
Uint16 myAs; ///< Sender ASN16
Uint32 bgpId; ///< IPv4 address
Uint8 parmsLen; ///< Subsequent parameters field length
Uint8 parms[FLEX_ARRAY]; ///< Open message parameters
} Bgpopen;
/**
* \brief BGP OPEN message parameters segment.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Uint8 len; ///< `parms` field length in bytes
Uint8 parms[FLEX_ARRAY]; ///< Variable-sized portion of parameters
} Bgpparmseg;
/**
* \brief Parameter inside `Bgpparmseg`.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
BgpParmCode code; ///< Parameter type octet
Uint8 len; ///< `data` field length in bytes
Uint8 data[FLEX_ARRAY]; ///< Parameter contents
} Bgpparm;
/**
* \brief CAPABILITY inside a parameter with code `BGP_PARM_CAPABILITY`.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
BgpCapCode code; ///< BGP capability code
Uint8 len; ///< Capability length in bytes, **excluding** the actual header
Uint8 data[FLEX_ARRAY]; ///< Capability contents
} Bgpcap;
/// Return a direct pointer over `Bgpopen` parameters segment.
FORCE_INLINE Bgpparmseg *BGP_OPENPARMS(const Bgpopen *open)
{
return (Bgpparmseg *) &open->parmsLen;
}
/**
* \brief BGP message of type UPDATE, including its header.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Bgphdr hdr;
Uint8 data[FLEX_ARRAY];
} Bgpupdate;
typedef ALIGNED(1, struct) {
Uint16 len;
Uint8 nlri[FLEX_ARRAY];
} Bgpwithdrawnseg;
typedef ALIGNED(1, struct) {
Uint16 len;
Uint8 attrs[FLEX_ARRAY];
} Bgpattrseg;
// NOTE: NLRI segment is handled with no struct
/// Attribute length has an additional byte.
#define BGP_ATTR_EXTENDED BIT(4)
/// Partial attribute flag.
#define BGP_ATTR_PARTIAL BIT(5)
/// Transitive attribute flag.
#define BGP_ATTR_TRANSITIVE BIT(6)
/// Optional attribute flag.
#define BGP_ATTR_OPTIONAL BIT(7)
typedef ALIGNED(1, struct) {
Uint8 flags;
BgpAttrCode code;
Uint8 len;
} Bgpattr;
typedef ALIGNED(1, struct) {
Uint8 flags;
BgpAttrCode code;
Uint16 len;
} Bgpattrex;
FORCE_INLINE Boolean BGP_ISATTREXT(Uint16 flags)
{
return (flags & BGP_ATTR_EXTENDED) != 0;
}
FORCE_INLINE Boolean BGP_ISATTRPART(Uint16 flags)
{
return (flags & BGP_ATTR_PARTIAL) != 0;
}
FORCE_INLINE Boolean BGP_ISATTRTRANS(Uint16 flags)
{
return (flags & BGP_ATTR_TRANSITIVE) != 0;
}
FORCE_INLINE Boolean BGP_ISATTROPT(Uint16 flags)
{
return (flags & BGP_ATTR_OPTIONAL) != 0;
}
FORCE_INLINE size_t BGP_ATTRHDRSIZ(const Bgpattr *attr)
{
return 3 + BGP_ISATTREXT(attr->flags);
}
FORCE_INLINE size_t BGP_ATTRLEN(const Bgpattr *attr)
{
return BGP_ISATTREXT(attr->flags) ?
BE16(((const Bgpattrex *) attr)->len) :
attr->len;
}
FORCE_INLINE void *BGP_ATTRPTR(const Bgpattr *attr)
{
return (Uint8 *) attr + BGP_ATTRHDRSIZ(attr);
}
/**
* \name Possible values of BGP ORIGIN attribute.
*
* @{
*/
#define BGP_ORIGIN_IGP U8_C(0)
#define BGP_ORIGIN_EGP U8_C(1)
#define BGP_ORIGIN_INCOMPLETE U8_C(2)
/// Octet type for BGP ORIGIN attribute code.
typedef Uint8 BgpOriginCode;
/** @} */
FORCE_INLINE Boolean BGP_CHKORIGINSIZ(const Bgpattr *attr)
{
return BGP_ATTRLEN(attr) == 1;
}
FORCE_INLINE BgpOriginCode BGP_ORIGIN(const Bgpattr *attr)
{
return *(const BgpOriginCode *) BGP_ATTRPTR(attr);
}
/// Test whether the length of the provided NEXT_HOP attribute is sensible.
FORCE_INLINE Boolean BGP_CHKNEXTHOPLEN(const Bgpattr *nextHop)
{
return BGP_ATTRLEN(nextHop) == IPV4_SIZE;
}
FORCE_INLINE Boolean BGP_CHKATOMICAGGRSIZ(const Bgpattr *aggr)
{
return BGP_ATTRLEN(aggr) == 0;
}
/**
* \brief Contents of attributes of types `BGP_ATTR_AGGREGATOR` or `BGP_ATTR_AS4_AGGREGATOR`.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
union {
struct {
Asn16 asn;
Ipv4adr addr;
} a16;
struct {
Asn32 asn;
Ipv4adr addr;
} a32;
};
} Bgpaggr;
FORCE_INLINE Boolean BGP_CHKAGGRSIZ(const Bgpattr *aggr, Boolean isAsn32bit)
{
return (2uLL << (isAsn32bit != 0)) + IPV4_SIZE == BGP_ATTRLEN(aggr);
}
FORCE_INLINE Asn BGP_AGGRAS(const Bgpaggr *aggr, Boolean isAsn32bit)
{
return (isAsn32bit) ? ASN32BIT(aggr->a32.asn) : ASN16BIT(aggr->a16.asn);
}
FORCE_INLINE Ipv4adr BGP_AGGRADDR(const Bgpaggr *aggr, Boolean isAsn32bit)
{
return (isAsn32bit) ? aggr->a32.addr : aggr->a16.addr;
}
#define AS_SET U8_C(1)
#define AS_SEQUENCE U8_C(2)
typedef Uint8 AsSegType;
/// AS_PATH segment.
typedef ALIGNED(1, struct) {
AsSegType type; ///< segment type
Uint8 len; ///< count of ASes (as opposed to bytes!) in `data`
Uint8 data[FLEX_ARRAY]; ///< contains `len` ASes (as opposed to `len` bytes!)
} Asseg;
/**
* \name BGP communities
*
* \see [IANA Well known communities list](https://www.iana.org/assignments/bgp-well-known-communities/bgp-well-known-communities.xhtml)
*
* @{
*/
#define BGP_COMMUNITY_PLANNED_SHUT BE32(0xffff0000u)
#define BGP_COMMUNITY_ACCEPT_OWN BE32(0xffff0001u)
#define BGP_COMMUNITY_ROUTE_FILTER_TRANSLATED_V4 BE32(0xffff0002u)
#define BGP_COMMUNITY_ROUTE_FILTER_V4 BE32(0xffff0003u)
#define BGP_COMMUNITY_ROUTE_FILTER_TRANSLATED_V6 BE32(0xffff0004u)
#define BGP_COMMUNITY_ROUTE_FILTER_V6 BE32(0xffff0005u)
#define BGP_COMMUNITY_LLGR_STALE BE32(0xffff0006u)
#define BGP_COMMUNITY_NO_LLGR BE32(0xffff0007u)
#define BGP_COMMUNITY_ACCEPT_OWN_NEXTHOP BE32(0xffff0008u)
#define BGP_COMMUNITY_STANDBY_PE BE32(0xffff0009u)
#define BGP_COMMUNITY_BLACKHOLE BE32(0xffff029au)
#define BGP_COMMUNITY_NO_EXPORT BE32(0xffffff01u)
#define BGP_COMMUNITY_NO_ADVERTISE BE32(0xffffff02u)
#define BGP_COMMUNITY_NO_EXPORT_SUBCONFED BE32(0xffffff03u)
#define BGP_COMMUNITY_NO_PEER BE32(0xffffff04u)
/// BGP Community code type, 4 octects, network byte order (big endian).
typedef Uint32 BgpCommCode;
/**
* \brief BGP COMMUNITY type.
*
* \warning **Misaligned union**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, union) {
struct {
Uint16 hi;
Uint16 lo;
};
BgpCommCode code;
} Bgpcomm;
/**
* \brief BGP EXTENDED_COMMUNITY type.
*
* \warning **Misaligned union**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Uint8 typeHi;
union {
struct {
Uint8 typeLo;
Uint8 value[6];
};
Uint8 exValue[7];
};
} Bgpexcomm;
/**
* \brief BGP LARGE_COMMUNITY type.
*
* \warning **Misaligned union**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Uint32 global;
Uint32 local1;
Uint32 local2;
} Bgplgcomm;
/** @} */
/**
* \brief Address family information found in `MP_REACH_NLRI` and
* `MP_UNREACH_NLRI` attributes.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Afi afi; ///< Address Family Identifier
Safi safi; ///< Subsequent Address Family Identifier
} Bgpmpfam;
/**
* MP_REACH_NLRI NEXT_HOP segment: length followed by network addresses.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Uint8 len; ///< Subsequent address length in bytes
Uint8 data[FLEX_ARRAY]; ///< Actual stored address, `len` bytes wide
} Bgpmpnexthop;
FORCE_INLINE Bgpmpfam *BGP_MPFAMILY(const Bgpattr *attr)
{
return (Bgpmpfam *) BGP_ATTRPTR(attr);
}
FORCE_INLINE Bgpmpnexthop *BGP_MPNEXTHOP(const Bgpattr *attr)
{
return (Bgpmpnexthop *) ((Uint8 *) BGP_ATTRPTR(attr) + 2 + 1);
}
FORCE_INLINE Boolean BGP_CHKMPREACH(const Bgpattr *attr)
{
// AFI(2), SAFI(1), NEXT_HOP(1 + var.), RESERVED(1), NLRI(var.)
size_t len = BGP_ATTRLEN(attr);
return len >= 2uLL + 1uLL + 1uLL &&
len >= 2uLL + 1uLL + 1uLL + BGP_MPNEXTHOP(attr)->len + 1uLL;
}
FORCE_INLINE Boolean BGP_CHKMPUNREACH(const Bgpattr *attr)
{
return BGP_ATTRLEN(attr) >= 2 + 1; // AFI(2), SAFI(1), NLRI
}
/**
* \brief BGP NOTIFICATION message.
*
* \warning **Misaligned struct**
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Bgphdr hdr;
BgpErrCode code; ///< Error code
BgpErrSubCode subcode; ///< Error category subcode
Uint8 msg[FLEX_ARRAY];
} Bgpnotification;
/**
* \brief BGP ROUTE_REFRESH message.
* \see [RFC 2918](https://tools.ietf.org/html/rfc2918)
*
* \warning **Misaligned struct**
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Bgphdr hdr; ///< Common BGP message header
Afi afi;
Uint8 reserved; ///< Reserved field, should be set to 0
Safi safi;
} Bgprouteref;
#pragma pack(pop) // --- misaligned packing END ---
STATIC_ASSERT(BGP_HDRSIZ == sizeof(Bgphdr), "BGP_HDRSIZ vs Bgphdr size mismatch");
typedef struct {
Uint8 *base, *lim;
Uint8 *ptr;
} Bgpparmiter;
typedef struct {
Bgpparmiter pi;
Uint8 *base, *lim;
Uint8 *ptr;
} Bgpcapiter;
/**
* \brief BGP attribute iterator.
*
* \note `struct` should be considered opaque.
*/
typedef struct {
Uint8 *base, *lim;
Uint8 *ptr;
Sint16 *table; // NOTE: accessed atomically as if Uint16 *
Uint64 attrMask[4]; // bitset to keep track of what we've seen so far
} Bgpattriter;
/**
* \brief AS segment iterator.
*
* \note `struct` should be considered opaque.
*/
typedef struct {
Uint8 *base, *lim;
Uint8 *ptr;
Boolean8 asn32bit;
} Assegiter;
/**
* \brief AS path iterator, reconstructs a BGP message AS path.
*
* \note `struct` should be considered opaque.
*/
typedef struct {
Assegiter segs; ///< Segments iterator
Bgpattr *nextAttr; ///< If any AS4_PATH is found, this references it
Uint8 *base, *lim;
Uint8 *ptr;
Uint16 asIdx; // NOTE: Equals to 0xffffu when no ASN has been returned yet
Uint16 maxCount; // NOTE: Could be set to 0xffffu when no limit is imposed
} Aspathiter;
/// Retrieve the current AS segment being iterated inside message AS_PATH.
FORCE_INLINE Asseg *BGP_CURASSEG(const Aspathiter *it)
{
return (Asseg *) it->base;
}
FORCE_INLINE Uint16 BGP_CURASINDEX(const Aspathiter *it)
{
return it->asIdx;
}
/**
* \brief MultiProtocol prefix iterator.
*
* Traverse prefixes coming from a multiprotocol enabled BGP message.
* Returns prefixes from the ATTRIBUTE
* field, when MP_REACH or MP_UNREACH attribute is available,
* and from the WITHDRAWN or NLRI fields.
*
* \note `struct` should be considered opaque.
*/
typedef struct {
Prefixiter rng; ///< Current iterator
Bgpattr *nextAttr; ///< Additional MP_REACH or MP_UNREACH attribute to be iterated
Prefix pfx; ///< Storage for prefix
} Bgpmpiter;
FORCE_INLINE Uint8 *BGP_CURMPBASE(const Bgpmpiter *it)
{
return it->rng.base;
}
FORCE_INLINE Uint8 *BGP_CURMPLIM(const Bgpmpiter *it)
{
return it->rng.lim;
}
/**
* \brief Retrieve pointer to current prefix inside BGP data.
*
* If prefix had PATH ID information the returned pointer references an
* `ApRawPrefix`, otherwise a `RawPrefix`.
*/
FORCE_INLINE void *BGP_CURMPPFX(const Bgpmpiter *it)
{
return it->rng.ptr - PFXLEN(it->pfx.width) - 1 - ((it->rng.isAddPath != 0) << 2);
}
/**
* \brief Retrieve a pointer to the current prefix inside the BGP data.
*
* Always returns a `RawPrefix` pointer, if PATH ID information is
* available it is discarded.
*/
FORCE_INLINE RawPrefix *BGP_CURMPRAWPFX(const Bgpmpiter *it)
{
return (RawPrefix *) (it->rng.ptr - PFXLEN(it->pfx.width) - 1);
}
/**
* \brief BGP UPDATE message NEXT_HOP iterator, returns every NEXT_HOP listed
* inside message across different attributes in sequence.
*
* \note `struct` should be considered opaque.
*/
typedef struct {
Bgpattr *nextHop;
Bgpattr *mpReach;
Uint8 *base, *lim;
Uint8 *ptr;
Afi afi;
Safi safi;
Boolean8 isRibv2; // whether we're dealing with a TABLE_DUMPV2 RIB mpReach
Afi afiRibv2; // only meaningful if isRibv2
Safi safiRibv2; // ditto
Ipadr addr;
} Nexthopiter;
FORCE_INLINE Bgpattr *BGP_CURNEXTHOPATTR(const Nexthopiter *it)
{
return (Bgpattr *) it->base;
}
FORCE_INLINE Afi BGP_CURNEXTHOPAFI(const Nexthopiter *it)
{
return it->afi;
}
FORCE_INLINE Safi BGP_CURNEXTHOPSAFI(const Nexthopiter *it)
{
return it->safi;
}
/**
* \brief BGP community attribute iterator.
*
* May iterate COMMUNITY, EXTENDED_COMMUNITY or LARGE_COMMUNITY.
*
* \note `struct` should be considered opaque.
*/
typedef struct {
Uint8 *base, *lim;
Uint8 *ptr;
} Bgpcommiter;
/**
* \brief Initialize message from existing data.
*
* \param [in,out] msg Cleared BGP message, must not be `NULL`
* \param [in] data Raw bytes to populate the message
* \param [in] nbytes Bytes count inside `data`
* \param [in] flags BGP initialization flags
*
* \return `OK` on success, `NG` on failure.
* Sets BGP error, see `Bgp_GetErrStat()`.
*
* \note Uses `msg->allocp` and `msg->memOps` to allocate memory as needed.
*/
Judgement Bgp_MsgFromBuf(Bgpmsg *msg, const void *data, size_t nbytes, unsigned flags);
/**
* \brief Read a BGP message from stream.
*
* \param [in,out] msg Cleared BGP message, must not be `NULL`
* \param [in] streamp Stream pointer to read from
* \param [in] ops Stream operations, must not be `NULL` and provide `Read()`
* \param [in] flags BGP initialization flags
*
* \return `OK` on success, `NG` on failure.
* Sets BGP error, see `Bgp_GetErrStat()`.
*
* \note Uses `msg->allocp` and `msg->memOps` to allocate memory as needed.
*
* \note Flag `BGPF_UNOWNED` is ignored by this function.
*/
Judgement Bgp_ReadMsg(Bgpmsg *msg, void *streamp, const StmOps *ops, unsigned flags);
/**
* \brief Access contents of a BGP message.
*
* Function shall fail if `msg` doesn't belong to the appropriate
* message type (e.g. trying to access a BGP UPDATE message while `msg` type
* is `BGP_OPEN`).
*
* \return Direct pointer to BGP message contents, `NULL` on error.
* Sets BGP error, see `Bgp_GetErrStat()`.
*
* @{
*/
Bgpopen *Bgp_GetMsgOpen(Bgpmsg *msg);
Bgpupdate *Bgp_GetMsgUpdate(Bgpmsg *msg);
Bgpnotification *Bgp_GetMsgNotification(Bgpmsg *msg);
Bgprouteref *Bgp_GetMsgRouteRefresh(Bgpmsg *msg);
/** @} */
/**
* \brief Assume correct BGP message type and retrieve a pointer to its content.
*
* \param [in] msg A BGP message, must not be `NULL` and have correct header and type!
*
* \return Direct pointer to BGP message contents.
*
* @{
*/
FORCE_INLINE Bgpopen *BGP_MSGOPEN(const Bgpmsg *msg)
{
return (Bgpopen *) msg->buf;
}
FORCE_INLINE Bgpupdate *BGP_MSGUPDATE(const Bgpmsg *msg)
{
return (Bgpupdate *) msg->buf;
}
FORCE_INLINE Bgpnotification *BGP_MSGNOTIFICATION(const Bgpmsg *msg)
{
return (Bgpnotification *) msg->buf;
}
FORCE_INLINE Bgprouteref *BGP_MSGROUTEREFRESH(const Bgpmsg *msg)
{
return (Bgprouteref *) msg->buf;
}
/** @} */
// NOTE: No function is provided to access BGP KEEPALIVE or CLOSE message,
// since their entire content is the BGP header.
/// Clear BGP message and free any owned memory.
void Bgp_ClearMsg(Bgpmsg *msg);
// OPEN Message specific
// =====================
/**
* \brief Retrieve pointer to BGP OPEN message's parameters field.
*
* \see `Bgp_GetMsgOpen()`
*/
Bgpparmseg *Bgp_GetOpenParms(const Bgpopen *msg);
Judgement Bgp_StartMsgParms(Bgpparmiter *it, Bgpmsg *msg);
void Bgp_StartParms(Bgpparmiter *it, const Bgpparmseg *tpa);
Bgpparm *Bgp_NextParm(Bgpparmiter *it);
Judgement Bgp_StartMsgCaps(Bgpcapiter *it, Bgpmsg *msg);
void Bgp_StartCaps(Bgpcapiter *it, const Bgpparmseg *tpa);
Bgpcap *Bgp_NextCap(Bgpcapiter *it);
// UPDATE Message specific
// =======================
Bgpwithdrawnseg *Bgp_GetUpdateWithdrawn(const Bgpupdate *msg);
Bgpattrseg *Bgp_GetUpdateAttributes(const Bgpupdate *msg);
void *Bgp_GetUpdateNlri(const Bgpupdate *msg, size_t *nbytes);
/// Like `Bgp_GetMsgAttribute()`, but operates directly on TPA.
Bgpattr *Bgp_GetUpdateAttribute(const Bgpattrseg *tpa, BgpAttrCode code, Bgpattrtab tab);
/**
* \brief Direct lookup of a specific BGP UPDATE attribute inside message TPA.
*
* Uses `msg->tab` to accelerate common attribute lookup.
*
* \return Attribute with type `code` inside `msg` TPA on success,
* `NULL` if attribute wasn't found or when error occurred.
* Sets BGP error, see `Bgp_GetErrStat()`.
*/
Bgpattr *Bgp_GetMsgAttribute(Bgpmsg *msg, BgpAttrCode code);
void Bgp_StartUpdateAttributes(Bgpattriter *it, const Bgpattrseg *tpa, Bgpattrtab tab);
Judgement Bgp_StartMsgAttributes(Bgpattriter *it, Bgpmsg *msg);
Bgpattr *Bgp_NextAttribute(Bgpattriter *it);
/// Start iterating BGP UPDATE message WITHDRAWN segment.
Judgement Bgp_StartMsgWithdrawn(Prefixiter *it, Bgpmsg *msg);
Judgement Bgp_StartAllMsgWithdrawn(Bgpmpiter*it, Bgpmsg *msg);
/**
* \brief Start iterating BGP UPDATE message NLRI segment.
*
* \param [out] it Iterator to be initialized, must not be `NULL`
* \param [in] msg Message whose NLRI segment is to be iterated, must not be `NULL`
*
* \return `OK` on success, `NG` on error. Sets BGP error state,
* see `Bgp_GetErrStat()`.
*/
Judgement Bgp_StartMsgNlri(Prefixiter *it, Bgpmsg *msg);
Judgement Bgp_StartAllMsgNlri(Bgpmpiter *it, Bgpmsg *msg);
/**
* \brief Get current prefix and advance iterator
*
* \return Current prefix, `NULL` on error or end of iteration.
* Sets BGP error, see `Bgp_GetErrStat()`.
*/
Prefix *Bgp_NextMpPrefix(Bgpmpiter *it);
/**
* \brief Return the BGP aggregator attribute.
*
* Second argument is an input-output ASN32BIT flag argument.
* It should be initially set to TRUE if the BGP message has ASN32BIT
* capability, FALSE otherwise.
* Flag is set to TRUE on return if the resolved AGGREGATOR attribute is
* 32-bits wide.
*/
Bgpattr *Bgp_GetRealAggregator(const Bgpattrseg *tpa, Boolean *isAsn32bit, Bgpattrtab tab);
/// Like `Bgp_GetRealAggregator()`, but operates on `Bgpmsg`.
Bgpattr *Bgp_GetRealMsgAggregator(Bgpmsg *msg, Boolean *isAsn32bit);
Judgement Bgp_StartAllNextHops(Nexthopiter *it, const Bgpattrseg *tpa, Bgpattrtab tab);
Judgement Bgp_StartAllMsgNextHops(Nexthopiter *it, Bgpmsg *msg);
Ipadr *Bgp_NextNextHop(Nexthopiter *it);
Judgement Bgp_StartRealAsPath(Aspathiter *it, const Bgpattrseg *tpa, Boolean isAsn32bit, Bgpattrtab tab);
Judgement Bgp_StartMsgRealAsPath(Aspathiter *it, Bgpmsg *msg);
Asn Bgp_NextAsPath(Aspathiter *it);
// BGP Attributes
// =======================
Judgement Bgp_StartAsSegments(Assegiter *it, const Bgpattr *asPath, Boolean isAsn32bit);
Judgement Bgp_StartAs4Segments(Assegiter *it, const Bgpattr *asPath);
Asseg *Bgp_NextAsSegment(Assegiter *it);
Judgement Bgp_StartCommunity(Bgpcommiter *it, const Bgpattr *comm);
Bgpcomm *Bgp_NextCommunity(Bgpcommiter *it);
Bgpexcomm *Bgp_NextExtendedCommunity(Bgpcommiter *it);
Bgplgcomm *Bgp_NextLargeCommunity(Bgpcommiter *it);
Bgpmpfam *Bgp_GetMpFamily(const Bgpattr *attr); // DEPRECATED
void *Bgp_GetMpNextHop(const Bgpattr *attr, size_t *nbytes); // DEPRECATED
void *Bgp_GetMpRoutes(const Bgpattr *attr, size_t *nbytes); // DEPRECATED
#endif