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

889 lines
24 KiB
C
Executable File

// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file bgp/mrt.h
*
* Multithreaded Routing Toolkit (MRT) types and functions.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_BGP_MRT_H_
#define DF_BGP_MRT_H_
#include "bgp/bgp.h"
#include "stm.h"
/**
* \name MRT record types
*
* \note Values are in network order (big endian)
*
* @{
*/
#define MRT_NULL BE16(0) // Deprecated
#define MRT_START BE16(1) // Deprecated
#define MRT_DIE BE16(2) // Deprecated
#define MRT_I_AM_DEAD BE16(3) // Deprecated
#define MRT_PEER_DOWN BE16(4) // Deprecated
#define MRT_BGP BE16(5) // Deprecated, also known as ZEBRA_BGP
#define MRT_RIP BE16(6) // Deprecated
#define MRT_IDRP BE16(7) // Deprecated
#define MRT_RIPNG BE16(8) // Deprecated
#define MRT_BGP4PLUS BE16(9) // Deprecated
#define MRT_BGP4PLUS_01 BE16(10) // Deprecated
#define MRT_OSPFV2 BE16(11)
#define MRT_TABLE_DUMP BE16(12)
#define MRT_TABLE_DUMPV2 BE16(13)
#define MRT_BGP4MP BE16(16)
#define MRT_BGP4MP_ET BE16(17)
#define MRT_ISIS BE16(32)
#define MRT_ISIS_ET BE16(33)
#define MRT_OSPFV3 BE16(48)
#define MRT_OSPFV3_ET BE16(49)
/// 2-octets type for MRT record header type field, network byte order (big endian).
typedef Uint16 MrtType;
/** @} */
/**
* \name MRT subtypes enumeration for records of type BGP/ZEBRA
*
* \warning ZEBRA BGP has been deprecated in favor of BGP4MP.
*
* \see `MrtSubType`
*
* @{
*/
#define ZEBRA_NULL BE16(0)
#define ZEBRA_UPDATE BE16(1)
#define ZEBRA_PREF_UPDATE BE16(2)
#define ZEBRA_STATE_CHANGE BE16(3)
#define ZEBRA_SYNC BE16(4)
#define ZEBRA_OPEN BE16(5)
#define ZEBRA_NOTIFY BE16(6)
#define ZEBRA_KEEPALIVE BE16(7)
/** @} */
/**
* \name MRT subtypes for records of type BGP4MP
*
* BGP4MP is defined in [RFC 6396](https://tools.ietf.org/html/rfc6396#section-4.2),
* and extended by [RFC 8050](https://tools.ietf.org/html/rfc8050#page-2).
*
* \see [IANA BGP4MP Subtype Codes](https://www.iana.org/assignments/mrt/mrt.xhtml#BGP4MP-codes)
* \see `MrtSubType`
*
* @{
*/
#define BGP4MP_STATE_CHANGE BE16(0) ///< RFC 6396
#define BGP4MP_MESSAGE BE16(1) ///< RFC 6396
#define BGP4MP_ENTRY BE16(2) ///< Deprecated
#define BGP4MP_SNAPSHOT BE16(3) ///< Deprecated
#define BGP4MP_MESSAGE_AS4 BE16(4) ///< RFC 6396
#define BGP4MP_STATE_CHANGE_AS4 BE16(5) ///< RFC 6396
#define BGP4MP_MESSAGE_LOCAL BE16(6) ///< RFC 6396
#define BGP4MP_MESSAGE_AS4_LOCAL BE16(7) ///< RFC 6396
#define BGP4MP_MESSAGE_ADDPATH BE16(8) ///< RFC 8050
#define BGP4MP_MESSAGE_AS4_ADDPATH BE16(9) ///< RFC 8050
#define BGP4MP_MESSAGE_LOCAL_ADDPATH BE16(10) ///< RFC 8050
#define BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH BE16(11) ///< RFC 8050
/** @} */
/**
* \name MRT subtypes for records of type TABLE_DUMPV2
*
* Table Dump version 2 is defined in [RFC 6396](https://tools.ietf.org/html/rfc6396#section-4.3).
*
* \see [IANA Table Dump version 2 Subtype Codes](https://www.iana.org/assignments/mrt/mrt.xhtml#table-dump-v2-subtype-codes)
* \see `MrtSubType`
*
* @{
*/
#define TABLE_DUMPV2_PEER_INDEX_TABLE BE16(1) ///< RFC 6396
#define TABLE_DUMPV2_RIB_IPV4_UNICAST BE16(2) ///< RFC 6396
#define TABLE_DUMPV2_RIB_IPV4_MULTICAST BE16(3) ///< RFC 6396
#define TABLE_DUMPV2_RIB_IPV6_UNICAST BE16(4) ///< RFC 6396
#define TABLE_DUMPV2_RIB_IPV6_MULTICAST BE16(5) ///< RFC 6396
#define TABLE_DUMPV2_RIB_GENERIC BE16(6) ///< RFC 6396
#define TABLE_DUMPV2_GEO_PEER_TABLE BE16(7) ///< RFC 6397
#define TABLE_DUMPV2_RIB_IPV4_UNICAST_ADDPATH BE16(8) ///< RFC 8050
#define TABLE_DUMPV2_RIB_IPV4_MULTICAST_ADDPATH BE16(9) ///< RFC 8050
#define TABLE_DUMPV2_RIB_IPV6_UNICAST_ADDPATH BE16(10) ///< RFC 8050
#define TABLE_DUMPV2_RIB_IPV6_MULTICAST_ADDPATH BE16(11) ///< RFC 8050
#define TABLE_DUMPV2_RIB_GENERIC_ADDPATH BE16(12) ///< RFC 8050
/** @} */
/// Type for MRT header subtype field, 2-octets type, network byte order (big endian).
typedef Uint16 MrtSubType;
/// Lookup table for TABLE_DUMPV2 PEER_INDEX.
typedef struct {
// NOTE: Data in this table is accessed atomically,
// despite these fields being signed they are effectively treated as
// unsigned by the library.
Sint16 validCount; ///< Count of valid entries inside `offsets`
Sint16 peerCount; ///< Cached PEER_INDEX_TABLE peer count value
Sint32 offsets[FLEX_ARRAY]; ///< Offset table, `peerCount` entries
} Mrtpeertabv2;
/**
* \brief MRT record type.
*
* Behaves in a similar way to `Bgpmsg`.
* Performs allocations via possibly custom allocator defined in fields
* `allocp` and `memOps`.
* If those fields are left `NULL', it uses `Mem_StdOps`.
*/
typedef struct {
Uint8 *buf; ///< Raw MRT record contents
void *allocp; ///< Optional custom memory allocator
const MemOps *memOps; ///< Optional custom memory operations
/**
* Fast peer offset table, only meaningful for
* `TABLE_DUMPV2` `PEER_INDEX_TABLE`.
*
* \note This is an atomic pointer to a [Mrtpeertabv2](\ref Mrtpeertabv2).
*
* \warning Honest, this field **MUST NOT** be accessed directly.
*/
void *peerOffTab;
} Mrtrecord;
/// Move `Mrtrecord` contents from `src` to `dest`, leaving `src` empty.
FORCE_INLINE void MRT_MOVEREC(Mrtrecord *dest, Mrtrecord *src)
{
EXTERNC void *memcpy(void *, const void *, size_t);
memcpy(dest, src, sizeof(*dest));
src->buf = NULL;
src->peerOffTab = NULL;
}
// Retrieve `MemOps` associated with record `rec`.
FORCE_INLINE const MemOps *MRT_MEMOPS(const Mrtrecord *rec)
{
return rec->memOps ? rec->memOps : Mem_StdOps;
}
#define _MRT_EXHDRMASK ( \
BIT(BE16(MRT_BGP4MP_ET)) | \
BIT(BE16(MRT_ISIS_ET)) | \
BIT(BE16(MRT_OSPFV3_ET)) \
)
#define _TABLE_DUMPV2_RIBMASK ( \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_UNICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_MULTICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_UNICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_MULTICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_GENERIC)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_UNICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_MULTICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_UNICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_MULTICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_GENERIC_ADDPATH)) \
)
#define _TABLE_DUMPV2_V4RIBMASK ( \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_UNICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_MULTICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_UNICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_MULTICAST_ADDPATH)) \
)
#define _TABLE_DUMPV2_V6RIBMASK ( \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_UNICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_MULTICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_UNICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_MULTICAST_ADDPATH)) \
)
#define _TABLE_DUMPV2_UNICASTRIBMASK ( \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_UNICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_UNICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_UNICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_UNICAST_ADDPATH)) \
)
#define _TABLE_DUMPV2_MULTICASTRIBMASK ( \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_MULTICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_MULTICAST)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_MULTICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_MULTICAST_ADDPATH)) \
)
#define _TABLE_DUMPV2_ADDPATHRIBMASK ( \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_UNICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV4_MULTICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_UNICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_IPV6_MULTICAST_ADDPATH)) | \
BIT(BE16(TABLE_DUMPV2_RIB_GENERIC_ADDPATH)) \
)
#define _BGP4MP_AS4MASK ( \
BIT(BE16(BGP4MP_MESSAGE_AS4)) | \
BIT(BE16(BGP4MP_STATE_CHANGE_AS4)) | \
BIT(BE16(BGP4MP_MESSAGE_AS4_LOCAL)) | \
BIT(BE16(BGP4MP_MESSAGE_AS4_ADDPATH)) | \
BIT(BE16(BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH)) \
)
#define _BGP4MP_ADDPATHMASK ( \
BIT(BE16(BGP4MP_MESSAGE_ADDPATH)) | \
BIT(BE16(BGP4MP_MESSAGE_AS4_ADDPATH)) | \
BIT(BE16(BGP4MP_MESSAGE_LOCAL_ADDPATH)) | \
BIT(BE16(BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH)) \
)
#define _BGP4MP_MESSAGEMASK ( \
BIT(BE16(BGP4MP_MESSAGE)) | \
BIT(BE16(BGP4MP_MESSAGE_AS4)) | \
BIT(BE16(BGP4MP_MESSAGE_LOCAL)) | \
BIT(BE16(BGP4MP_MESSAGE_AS4_LOCAL)) | \
BIT(BE16(BGP4MP_MESSAGE_ADDPATH)) | \
BIT(BE16(BGP4MP_MESSAGE_AS4_ADDPATH)) | \
BIT(BE16(BGP4MP_MESSAGE_LOCAL_ADDPATH)) | \
BIT(BE16(BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH)) \
)
#define _ZEBRA_MESSAGEMASK ( \
BIT(BE16(ZEBRA_UPDATE)) | \
BIT(BE16(ZEBRA_OPEN)) | \
BIT(BE16(ZEBRA_NOTIFY)) | \
BIT(BE16(ZEBRA_KEEPALIVE)) \
)
/// Test whether a MRT record type provides extended precision timestamp header.
FORCE_INLINE Boolean MRT_ISEXHDRTYPE(MrtType type)
{
return BE16(type) <= 49 && (_MRT_EXHDRMASK & BIT(BE16(type))) != 0;
}
/// Test whether a MRT record type is BGP4MP.
FORCE_INLINE Boolean MRT_ISBGP4MP(MrtType type)
{
return type == MRT_BGP4MP || type == MRT_BGP4MP_ET;
}
/// Test whether a MRT record type is ISIS.
FORCE_INLINE Boolean MRT_ISISIS(MrtType type)
{
return type == MRT_ISIS || type == MRT_ISIS_ET;
}
/// Test whether a MRT record type is OSPFV3.
FORCE_INLINE Boolean MRT_ISOSPFV3(MrtType type)
{
return type == MRT_OSPFV3 || type == MRT_OSPFV3_ET;
}
/// Test whether a BGP4MP MRT record subtype contains 32-bits ASN.
FORCE_INLINE Boolean BGP4MP_ISASN32BIT(MrtSubType subtype)
{
return BE16(subtype) <= 11 && (_BGP4MP_AS4MASK & BIT(BE16(subtype))) != 0;
}
/// Test whether a BGP4MP MRT subtype belongs has ADD_PATH information.
FORCE_INLINE Boolean BGP4MP_ISADDPATH(MrtSubType subtype)
{
return BE16(subtype) <= 11 &&
(_BGP4MP_ADDPATHMASK & BIT(BE16(subtype))) != 0;
}
/**
* \brief Test whether a BGP4MP MRT subtype wraps a BGP message.
*
* \see `Bgp_UnwrapBgp4mp()`
*/
FORCE_INLINE Boolean BGP4MP_ISMESSAGE(MrtSubType subtype)
{
return BE16(subtype) <= 11 &&
(_BGP4MP_MESSAGEMASK & BIT(BE16(subtype))) != 0;
}
FORCE_INLINE Boolean BGP4MP_ISSTATECHANGE(MrtSubType subtype)
{
return subtype == BGP4MP_STATE_CHANGE ||
subtype == BGP4MP_STATE_CHANGE_AS4;
}
FORCE_INLINE Boolean TABLE_DUMPV2_ISRIB(MrtSubType subtype)
{
return BE16(subtype) <= 12 &&
(_TABLE_DUMPV2_RIBMASK & BIT(BE16(subtype))) != 0;
}
FORCE_INLINE Boolean TABLE_DUMPV2_ISIPV4RIB(MrtSubType subtype)
{
return BE16(subtype) <= 12 &&
(_TABLE_DUMPV2_V4RIBMASK & BIT(BE16(subtype))) != 0;
}
FORCE_INLINE Boolean TABLE_DUMPV2_ISIPV6RIB(MrtSubType subtype)
{
return BE16(subtype) <= 12 &&
(_TABLE_DUMPV2_V6RIBMASK & BIT(BE16(subtype))) != 0;
}
FORCE_INLINE Boolean TABLE_DUMPV2_ISGENERICRIB(MrtSubType subtype)
{
return subtype == TABLE_DUMPV2_RIB_GENERIC ||
subtype == TABLE_DUMPV2_RIB_GENERIC_ADDPATH;
}
FORCE_INLINE Boolean TABLE_DUMPV2_ISUNICASTRIB(MrtSubType subtype)
{
return BE16(subtype) <= 12 &&
(_TABLE_DUMPV2_UNICASTRIBMASK & BIT(BE16(subtype))) != 0;
}
FORCE_INLINE Boolean TABLE_DUMPV2_ISMULTICASTRIB(MrtSubType subtype)
{
return BE16(subtype) <= 12 &&
(_TABLE_DUMPV2_MULTICASTRIBMASK & BIT(BE16(subtype))) != 0;
}
FORCE_INLINE Boolean TABLE_DUMPV2_ISADDPATHRIB(MrtSubType subtype)
{
return BE16(subtype) <= 12 &&
(_TABLE_DUMPV2_ADDPATHRIBMASK & BIT(BE16(subtype))) != 0;
}
/**
* \brief Test whether a ZEBRA BGP message wraps BGP message.
*
* \see `Bgp_UnwrapZebra()`
*/
FORCE_INLINE Boolean ZEBRA_ISMESSAGE(MrtSubType subtype)
{
return BE16(subtype) <= 7 &&
(_ZEBRA_MESSAGEMASK & BIT(BE16(subtype))) != 0;
}
#pragma pack(push, 1)
/**
* \brief MRT header type.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Uint32 timestamp; ///< Unix timestamp
MrtType type; ///< MRT record type
MrtSubType subtype; ///< MRT record subtype
Uint32 len; ///< Record length in bytes **not including** header itself
} Mrthdr;
/**
* \brief Extended MRT header, includes microseconds information.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*
* \see `Mrthdr`
*/
typedef ALIGNED(1, struct) {
Uint32 timestamp;
MrtType type;
MrtSubType subtype;
Uint32 len;
Uint32 microsecs;
} Mrthdrex;
typedef ALIGNED(1, struct) {
Uint32 peerBgpId; ///< Peer BGP identifier
Uint16 viewNameLen; ///< `viewName` field length in chars
char viewName[FLEX_ARRAY]; ///< Optional view name, **not** `\0` terminated
// Uint16 peerCount;
// Mrtpeerent peers[FLEX_ARRAY];
} Mrtpeeridx;
#define MRT_PEER_IP6 BIT(0)
#define MRT_PEER_ASN32BIT BIT(1)
typedef ALIGNED(1, struct) {
Uint8 type;
Uint32 bgpId;
union {
struct {
Ipv4adr addr;
Asn16 asn;
} a16v4;
struct {
Ipv4adr addr;
Asn32 asn;
} a32v4;
struct {
Ipv6adr addr;
Asn16 asn;
} a16v6;
struct {
Ipv6adr addr;
Asn32 asn;
} a32v6;
};
} Mrtpeerentv2;
FORCE_INLINE Boolean MRT_ISPEERIPV6(Uint8 type)
{
return (type & MRT_PEER_IP6) != 0;
}
FORCE_INLINE Boolean MRT_ISPEERASN32BIT(Uint8 type)
{
return (type & MRT_PEER_ASN32BIT) != 0;
}
FORCE_INLINE Asn MRT_GETPEERADDR(Ipadr *dest, const Mrtpeerentv2 *peer)
{
switch (peer->type & (MRT_PEER_IP6|MRT_PEER_ASN32BIT)) {
case MRT_PEER_IP6|MRT_PEER_ASN32BIT:
dest->family = IP6;
dest->v6 = peer->a32v6.addr;
return ASN32BIT(peer->a32v6.asn);
case MRT_PEER_IP6:
dest->family = IP6;
dest->v6 = peer->a16v6.addr;
return ASN16BIT(peer->a16v6.asn);
case MRT_PEER_ASN32BIT:
dest->family = IP4;
dest->v4 = peer->a32v4.addr;
return ASN32BIT(peer->a32v4.asn);
default:
dest->family = IP4;
dest->v4 = peer->a16v4.addr;
return ASN16BIT(peer->a16v4.asn);
}
}
#define _MRT_RIBENT_FIELDS(IpT) \
IpT prefix; \
Uint8 prefixLen; \
Uint8 status; \
Uint32 originatedTime; \
IpT peerAddr; \
Uint16 peerAs; \
Uint16 attrLen
/**
* \brief Legacy TABLE_DUMP RIB entry.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Uint16 viewno;
Uint16 seqno;
union {
struct {
_MRT_RIBENT_FIELDS(Ipv4adr);
// Uint8 attrs[FLEX_ARRAY];
} v4;
struct {
_MRT_RIBENT_FIELDS(Ipv6adr);
// Uint8 attrs[FLEX_ARRAY];
} v6;
};
} Mrtribent;
FORCE_INLINE Boolean RIB_GETPFX(Afi afi,
RawPrefix *dest,
const Mrtribent *rib)
{
EXTERNC void *memcpy(void *, const void *, size_t);
switch (afi) {
case AFI_IP:
if (rib->v4.prefixLen > IPV4_WIDTH)
return FALSE;
dest->width = rib->v4.prefixLen;
memcpy(dest->bytes, &rib->v4.prefix, PFXLEN(rib->v4.prefixLen));
return TRUE;
case AFI_IP6:
if (rib->v6.prefixLen > IPV6_WIDTH)
return FALSE;
dest->width = rib->v6.prefixLen;
memcpy(dest->bytes, &rib->v6.prefix, PFXLEN(rib->v6.prefixLen));
return TRUE;
default:
UNREACHABLE;
return FALSE;
}
}
FORCE_INLINE Uint32 RIB_GETORIGINATED(Afi afi, const Mrtribent *rib)
{
switch (afi) {
case AFI_IP: return rib->v4.originatedTime;
case AFI_IP6: return rib->v6.originatedTime;
default:
UNREACHABLE;
return 0;
}
}
FORCE_INLINE Asn RIB_GETPEERADDR(Afi afi, Ipadr *dest, const Mrtribent *rib)
{
switch (afi) {
case AFI_IP:
dest->family = afi;
dest->v4 = rib->v4.peerAddr;
return ASN16BIT(rib->v4.peerAs);
case AFI_IP6:
dest->family = afi;
dest->v6 = rib->v6.peerAddr;
return ASN16BIT(rib->v6.peerAs);
default:
UNREACHABLE;
return -1;
}
}
// NOTE: RIB AFI is stored inside `Mrthdr subtype` field.
FORCE_INLINE Bgpattrseg *RIB_GETATTRIBS(Afi afi, const Mrtribent *rib)
{
switch (afi) {
case AFI_IP: return (Bgpattrseg *) &rib->v4.attrLen;
case AFI_IP6: return (Bgpattrseg *) &rib->v6.attrLen;
default: UNREACHABLE; return NULL;
}
}
typedef ALIGNED(1, struct) {
Uint32 seqno;
union {
RawPrefix nlri;
struct {
Afi afi;
Safi safi;
RawPrefix nlri;
} gen;
};
} Mrtribhdrv2;
FORCE_INLINE Mrtribhdrv2 *RIBV2_HDR(const Mrthdr *hdr)
{
return (Mrtribhdrv2 *) (hdr + 1);
}
typedef ALIGNED(1, struct) {
Uint16 entryCount;
Uint8 entries[FLEX_ARRAY];
} Mrtribentriesv2;
/**
* \brief TABLE_DUMPV2 RIB entry.
*
* \warning **Misaligned struct**.
* \note Fields are in network order (big endian).
*/
typedef ALIGNED(1, struct) {
Uint16 peerIndex; ///< `Mrtpeerentv2` index inside PEER_INDEX_TABLE
Uint32 originatedTime;
Uint8 data[FLEX_ARRAY];
} Mrtribentv2;
FORCE_INLINE Bgpattrseg *RIBV2_GETATTRIBS(MrtSubType subtype,
const Mrtribentv2 *rib)
{
return (Bgpattrseg *) (TABLE_DUMPV2_ISADDPATHRIB(subtype) ?
rib->data + 4 :
rib->data);
}
FORCE_INLINE Uint32 RIBV2_GETPATHID(const Mrtribentv2 *ent)
{
EXTERNC void *memcpy(void *, const void *, size_t);
Uint32 pathid;
memcpy(&pathid, ent->data, sizeof(pathid));
return pathid;
}
FORCE_INLINE void RIBV2_SETPATHID(Mrtribentv2 *ent, Uint32 pathid)
{
EXTERNC void *memcpy(void *, const void *, size_t);
memcpy(ent->data, &pathid, sizeof(pathid));
}
FORCE_INLINE void RIBV2_GETNLRI(MrtSubType subtype,
Prefix *dest,
const Mrtribhdrv2 *hdr,
const Mrtribentv2 *ent)
{
EXTERNC void *memcpy(void *, const void *, size_t);
if (TABLE_DUMPV2_ISGENERICRIB(subtype)) {
dest->afi = hdr->gen.afi;
dest->safi = hdr->gen.safi;
memcpy(PLAINPFX(dest), &hdr->gen.nlri, 1 + PFXLEN(hdr->gen.nlri.width));
} else {
dest->afi = TABLE_DUMPV2_ISIPV6RIB(subtype) ?
AFI_IP6 :
AFI_IP;
dest->safi = TABLE_DUMPV2_ISMULTICASTRIB(subtype) ?
SAFI_MULTICAST :
SAFI_UNICAST;
memcpy(PLAINPFX(dest), &hdr->nlri, 1 + PFXLEN(hdr->nlri.width));
}
dest->isAddPath = TABLE_DUMPV2_ISADDPATHRIB(subtype);
dest->pathId = (dest->isAddPath) ? RIBV2_GETPATHID(ent) : 0;
}
#define _MRT_BGP4MP_COMFIELDS(AsnT) \
AsnT peerAs, localAs; \
Uint16 iface; \
Afi afi
#define _MRT_BGP4MP_HDRFIELDS(AsnT, IpT) \
_MRT_BGP4MP_COMFIELDS(AsnT); \
IpT peerAddr, localAddr
/// Common header fields to all BGP4MP MRT records.
typedef ALIGNED(1, union) {
struct {
_MRT_BGP4MP_COMFIELDS(Asn32);
} a32;
struct {
_MRT_BGP4MP_COMFIELDS(Asn16);
} a16;
struct {
_MRT_BGP4MP_HDRFIELDS(Asn16, Ipv4adr);
} a16v4;
struct {
_MRT_BGP4MP_HDRFIELDS(Asn16, Ipv6adr);
} a16v6;
struct {
_MRT_BGP4MP_HDRFIELDS(Asn32, Ipv4adr);
} a32v4;
struct {
_MRT_BGP4MP_HDRFIELDS(Asn32, Ipv6adr);
} a32v6;
} Bgp4mphdr;
FORCE_INLINE Bgp4mphdr *BGP4MP_HDR(const Mrthdr *hdr)
{
return (hdr->type == MRT_BGP4MP_ET) ?
(Bgp4mphdr *) ((const Mrthdrex *) hdr + 1) :
(Bgp4mphdr *) (hdr + 1);
}
FORCE_INLINE Asn BGP4MP_GETPEERADDR(MrtSubType subtype,
Ipadr *dest,
const Bgp4mphdr *bgp4mp)
{
if (BGP4MP_ISASN32BIT(subtype)) {
switch (bgp4mp->a32.afi) {
case AFI_IP:
dest->family = IP4;
dest->v4 = bgp4mp->a32v4.peerAddr;
break;
case AFI_IP6:
dest->family = IP6;
dest->v6 = bgp4mp->a32v6.peerAddr;
break;
default:
UNREACHABLE;
break;
}
return ASN32BIT(bgp4mp->a32.peerAs);
} else {
switch (bgp4mp->a16.afi) {
case AFI_IP:
dest->family = IP4;
dest->v4 = bgp4mp->a16v4.peerAddr;
break;
case AFI_IP6:
dest->family = IP6;
dest->v6 = bgp4mp->a16v6.peerAddr;
break;
default:
UNREACHABLE;
break;
}
return ASN16BIT(bgp4mp->a16.peerAs);
}
}
FORCE_INLINE Asn BGP4MP_GETLOCALADDR(MrtSubType subtype,
Ipadr *dest,
const Bgp4mphdr *bgp4mp)
{
if (BGP4MP_ISASN32BIT(subtype)) {
switch (bgp4mp->a32.afi) {
case AFI_IP:
dest->family = IP4;
dest->v4 = bgp4mp->a32v4.localAddr;
break;
case AFI_IP6:
dest->family = IP6;
dest->v6 = bgp4mp->a32v6.localAddr;
break;
default:
UNREACHABLE;
return -1;
}
return ASN32BIT(bgp4mp->a32.localAs);
} else {
switch (bgp4mp->a16.afi) {
case AFI_IP:
dest->family = IP4;
dest->v4 = bgp4mp->a16v4.localAddr;
break;
case AFI_IP6:
dest->family = IP6;
dest->v6 = bgp4mp->a16v6.localAddr;
break;
default:
UNREACHABLE;
return -1;
}
return ASN16BIT(bgp4mp->a16.localAs);
}
}
/// BGP4MP message providing BGP Finite State Machine (FSM) state change information.
typedef ALIGNED(1, union) {
Bgp4mphdr hdr;
struct {
_MRT_BGP4MP_HDRFIELDS(Asn16, Ipv4adr);
BgpFsmState oldState, newState;
} a16v4;
struct {
_MRT_BGP4MP_HDRFIELDS(Asn16, Ipv6adr);
BgpFsmState oldState, newState;
} a16v6;
struct {
_MRT_BGP4MP_HDRFIELDS(Asn32, Ipv4adr);
BgpFsmState oldState, newState;
} a32v4;
struct {
_MRT_BGP4MP_HDRFIELDS(Asn32, Ipv6adr);
BgpFsmState oldState, newState;
} a32v6;
} Bgp4mpstatchng;
typedef ALIGNED(1, struct) {
Uint16 peerAs;
Ipv4adr peerAddr;
} Zebrahdr;
FORCE_INLINE Zebrahdr *ZEBRA_HDR(const Mrthdr *hdr)
{
return (Zebrahdr *) (hdr + 1);
}
typedef ALIGNED(1, struct) {
Zebrahdr hdr;
Uint16 localAs;
Ipv4adr localAddr;
Uint8 msg[FLEX_ARRAY];
} Zebramsghdr;
typedef ALIGNED(1, struct) {
Zebrahdr hdr;
BgpFsmState oldState, newState;
} Zebrastatchng;
#pragma pack(pop)
/// MRT record header size in bytes.
#define MRT_HDRSIZ (4uLL + 2uLL + 2uLL + 4uLL)
/// Extended timestamp MRT record header size in bytes.
#define MRT_EXHDRSIZ (MRT_HDRSIZ + 4uLL)
STATIC_ASSERT(MRT_HDRSIZ == sizeof(Mrthdr), "MRT_HDRSIZ vs Mrthdr size mismatch");
STATIC_ASSERT(MRT_EXHDRSIZ == sizeof(Mrthdrex), "MRT_EXHDRSIZ vs Mrthdrex size mismatch");
/// Retrieve a pointer to a MRT record header.
FORCE_INLINE Mrthdr *MRT_HDR(const Mrtrecord *rec)
{
return (Mrthdr *) rec->buf;
}
typedef struct {
Uint8 *base, *lim;
Uint8 *ptr;
Uint16 peerCount;
Uint16 nextIdx;
} Mrtpeeriterv2;
typedef struct {
Uint8 *base, *lim;
Uint8 *ptr;
Boolean8 isAddPath;
Uint16 entryCount;
Uint16 nextIdx;
} Mrtribiterv2;
Judgement Bgp_MrtFromBuf(Mrtrecord *rec, const void *data, size_t nbytes);
Judgement Bgp_ReadMrt(Mrtrecord *rec, void *streamp, const StmOps *ops);
void Bgp_ClearMrt(Mrtrecord *rec);
// =========================================
// TABLE_DUMPV2 - PEER_INDEX_TABLE
Mrtpeeridx *Bgp_GetMrtPeerIndex(Mrtrecord *rec);
void *Bgp_GetMrtPeerIndexPeers(Mrtrecord *rec, size_t *peersCount, size_t *nbytes);
Judgement Bgp_StartMrtPeersv2(Mrtpeeriterv2 *it, Mrtrecord *rec);
Mrtpeerentv2 *Bgp_NextMrtPeerv2(Mrtpeeriterv2 *it);
Mrtpeerentv2 *Bgp_GetMrtPeerByIndex(Mrtrecord *rec, Uint16 idx);
// =========================================
// TABLE_DUMPV2 - RIB SubTypes
Mrtribhdrv2 *Bgp_GetMrtRibHdrv2(Mrtrecord *rec, size_t *nbytes);
Mrtribentriesv2 *Bgp_GetMrtRibEntriesv2(Mrtrecord *rec, size_t *nbytes);
Judgement Bgp_StartMrtRibEntriesv2(Mrtribiterv2 *it, Mrtrecord *rec);
Mrtribentv2 *Bgp_NextRibEntryv2(Mrtribiterv2 *rec);
// =========================================
// BGP4MP
Bgp4mphdr *Bgp_GetBgp4mpHdr(Mrtrecord *rec, size_t *nbytes);
Judgement Bgp_UnwrapBgp4mp(Mrtrecord *rec, Bgpmsg *msg, unsigned flags);
// =========================================
// DEPRECATED - TABLE_DUMP
Mrtribent *Bgp_GetMrtRibHdr(Mrtrecord *rec);
void *Bgp_GetMrtRibEntry(Mrtrecord *rec, size_t *nbytes);
// =========================================
// DEPRECATED - ZEBRA
Zebrahdr *Bgp_GetZebraHdr(Mrtrecord *rec, size_t *nbytes);
Judgement Bgp_UnwrapZebra(Mrtrecord *rec, Bgpmsg *msg, unsigned flags);
// ==========================================
// RIB attribute segment encoding formats
Judgement Bgp_StartAllRibv2NextHops(Nexthopiter *it,
const Mrthdr *hdr,
const Bgpattrseg *tpa,
Bgpattrtab tab);
Judgement Bgp_RebuildMsgFromRib(const Prefix *nlri,
const Bgpattrseg *tpa,
Bgpmsg *msg,
unsigned flags);
#endif