mirror of
https://codeberg.org/1414codeforge/ubgpsuite.git
synced 2025-06-05 21:29:11 +02:00
[*] Initial commit
This commit is contained in:
87
lonetix/include/df/bgp/asn.h
Executable file
87
lonetix/include/df/bgp/asn.h
Executable file
@@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* \file bgp/asn.h
|
||||
*
|
||||
* Types, constant and utilities to work with ASN of various width.
|
||||
*
|
||||
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
||||
* \author Lorenzo Cogotti
|
||||
*/
|
||||
|
||||
#ifndef DF_BGP_ASN_H_
|
||||
#define DF_BGP_ASN_H_
|
||||
|
||||
#include "xpt.h"
|
||||
|
||||
/// 2 octet `AS_TRANS` constant, in network order (big-endian).
|
||||
#define AS_TRANS BE16(23456)
|
||||
/// 4 octet `AS_TRANS` constant, in network order (big-endian).
|
||||
#define AS4_TRANS BE32(23456)
|
||||
|
||||
/// 2 bytes wide AS number (ASN16), in network order (big-endian).
|
||||
typedef Uint16 Asn16;
|
||||
/// 4 bytes wide AS number (ASN32), in network order (big-endian).
|
||||
typedef Uint32 Asn32;
|
||||
|
||||
/**
|
||||
* \brief Fat AS type capable of holding either a 4 octet (ASN32) or a 2 octet
|
||||
* (ASN16) AS number, with additional flags indicating ASN properties.
|
||||
*
|
||||
* \note This type doesn't reflect any actual BGP ASN encoding, it is merely
|
||||
* a convenience abstraction, useful when ASN properties should be bundled
|
||||
* with the actual ASN.
|
||||
*/
|
||||
typedef Sint64 Asn; // NOTE: signed so negative values may be used for
|
||||
// special purposes if necessary
|
||||
|
||||
/// `Asn` flag indicating that the currently stored ASN is 4 octet wide (ASN32).
|
||||
#define ASN32BITFLAG BIT(62)
|
||||
|
||||
/**
|
||||
* \brief Return an `Asn` holding an `Asn16` value.
|
||||
*
|
||||
* \note `asn` must be in network order (big endian).
|
||||
*/
|
||||
#define ASN16BIT(asn) ((Asn) ((Asn16) (asn)))
|
||||
|
||||
/**
|
||||
* \brief Return an `Asn` holding a `Asn32`.
|
||||
*
|
||||
* \note `asn` should be in network order (big endian).
|
||||
*/
|
||||
#define ASN32BIT(asn) ((Asn) (ASN32BITFLAG | ((Asn) ((Asn32) asn))))
|
||||
|
||||
/// Test whether an `Asn` is holding a 4 octet wide ASN.
|
||||
FORCE_INLINE Boolean ISASN32BIT(Asn asn)
|
||||
{
|
||||
return (asn & ASN32BITFLAG) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Extract AS number stored inside an `Asn`.
|
||||
*
|
||||
* Returned ASN is extended to `Asn32` even if it was originally an `Asn16`,
|
||||
* this allows code involving `Asn` to treat any ASN uniformly.
|
||||
*
|
||||
* \note Resulting ASN is in network byte order (big endian).
|
||||
*/
|
||||
FORCE_INLINE Asn32 ASN(Asn asn)
|
||||
{
|
||||
Asn32 res = asn & 0xffffffffuLL;
|
||||
|
||||
#if EDN_NATIVE != EDN_BE
|
||||
// Shift _asn of 16 bits if this was originally ASN16,
|
||||
// on LE machines this mimics a BE16 word to BE32 dword extension
|
||||
res <<= (((asn & ASN32BITFLAG) == 0) << 4);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Test whether `asn` represents either `AS_TRANS` or `AS4_TRANS`.
|
||||
FORCE_INLINE Boolean ISASTRANS(Asn asn)
|
||||
{
|
||||
return ASN(asn) == AS4_TRANS;
|
||||
}
|
||||
|
||||
#endif
|
1198
lonetix/include/df/bgp/bgp.h
Executable file
1198
lonetix/include/df/bgp/bgp.h
Executable file
File diff suppressed because it is too large
Load Diff
62
lonetix/include/df/bgp/bytebuf.h
Executable file
62
lonetix/include/df/bgp/bytebuf.h
Executable file
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* \file bgp/bytebuf.h
|
||||
*
|
||||
* Allocator optimized for trivial BGP workflows.
|
||||
*
|
||||
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
||||
* \author Lorenzo Cogotti
|
||||
*/
|
||||
|
||||
#ifndef DF_BGP_MEMBUF_H_
|
||||
#define DF_BGP_MEMBUF_H_
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
/// Memory alignment for `Bgpbytebuf` allocations.
|
||||
#define BGP_MEMBUF_ALIGN 4
|
||||
|
||||
// NOTE: Need at least 4 bytes alignment for TABLE_DUMPV2 peer lookup tables!
|
||||
|
||||
/**
|
||||
* \brief Basic fixed-size packed single-threaded byte buffer.
|
||||
*
|
||||
* Nearly zero-overhead byte pool optimized for typical BGP message
|
||||
* allocations. Returns chunks from an internal fixed-size byte buffer
|
||||
*/
|
||||
typedef struct {
|
||||
size_t size; ///< Buffer block size in bytes
|
||||
size_t pos; ///< Current position inside block
|
||||
ALIGNED(BGP_MEMBUF_ALIGN, Uint8 base[FLEX_ARRAY]); ///< Block buffer
|
||||
} Bgpbytebuf;
|
||||
|
||||
/**
|
||||
* \brief Create `Bgpbytebuf` with statically sized fixed buffer
|
||||
* (as opposed to a flexible array buffer).
|
||||
*
|
||||
* This is useful when the buffer should be placed in statically
|
||||
* allocated variable, e.g.
|
||||
* ```c
|
||||
* static BGP_FIXBYTEBUF(4096) bgp_msgBuf = { 4096 };
|
||||
* ```
|
||||
*
|
||||
* May also be used for a `typedef`:
|
||||
* ```c
|
||||
* typedef BGP_FIXBYTEBUF(1024) Bgpsmallbuf;
|
||||
* ```
|
||||
*
|
||||
* Variables generated by this macro may be used
|
||||
* as `allocp` of any API expecting a `MemOps` interface.
|
||||
*/
|
||||
#define BGP_FIXBYTEBUF(bufsiz) \
|
||||
struct { \
|
||||
size_t size; \
|
||||
size_t pos; \
|
||||
ALIGNED(BGP_MEMBUF_ALIGN, Uint8 base[bufsiz]); \
|
||||
}
|
||||
|
||||
/// `MemOps` operating over `Bgpbytebuf`, use pointer to `Bgpbytebuf` as `allocp`.
|
||||
extern const MemOps *const Mem_BgpBufOps;
|
||||
|
||||
#endif
|
90
lonetix/include/df/bgp/dump.h
Executable file
90
lonetix/include/df/bgp/dump.h
Executable file
@@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* \file bgp/dump.h
|
||||
*
|
||||
* BGP message dump utilities.
|
||||
*
|
||||
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
||||
* \author Lorenzo Cogotti
|
||||
*/
|
||||
|
||||
#ifndef DF_BGP_DUMP_H_
|
||||
#define DF_BGP_DUMP_H_
|
||||
|
||||
#include "mrt.h"
|
||||
|
||||
/**
|
||||
* \brief BGP message dump formatter.
|
||||
*
|
||||
* \note Calling the dump functions directly should be considered low-level,
|
||||
* under normal circumstances use: `Bgp_DumpMsg()`, `Bgp_DumpMrtUpdate()`,
|
||||
* `Bgp_DumpRib()`, and `Bgp_DumpRibv2()`.
|
||||
*/
|
||||
typedef struct {
|
||||
Sint64 (*DumpMsg)(const Bgphdr *, unsigned,
|
||||
void *, const StmOps *,
|
||||
Bgpattrtab);
|
||||
|
||||
Sint64 (*DumpRibv2)(const Mrthdr *,
|
||||
const Mrtpeerentv2 *, const Mrtribentv2 *,
|
||||
void *, const StmOps *,
|
||||
Bgpattrtab);
|
||||
|
||||
Sint64 (*DumpRib)(const Mrthdr *,
|
||||
const Mrtribent *,
|
||||
void *, const StmOps *,
|
||||
Bgpattrtab);
|
||||
|
||||
Sint64 (*DumpBgp4mp)(const Mrthdr *,
|
||||
void *, const StmOps *,
|
||||
Bgpattrtab);
|
||||
|
||||
Sint64 (*DumpZebra)(const Mrthdr *,
|
||||
void *, const StmOps *,
|
||||
Bgpattrtab);
|
||||
} BgpDumpfmt;
|
||||
|
||||
// Standard dump formatters
|
||||
extern const BgpDumpfmt *const Bgp_IsolarioFmt; ///< Isolario `bgpscanner` like output format
|
||||
extern const BgpDumpfmt *const Bgp_IsolarioFmtWc; ///< Isolario `bgpscanner` like output format, with colors
|
||||
|
||||
// extern const BgpDumpfmt *const Bgp_BgpdumpFmt; ///< `bgpdump` style output format
|
||||
// extern const BgpDumpfmt *const Bgp_RawFmt; ///< output message raw bytes
|
||||
// extern const BgpDumpfmt *const Bgp_HexFmt; ///< perform BGP message hexadecimal dump
|
||||
// extern const BgpDumpfmt *const Bgp_CFmt; ///< outputs BGP message as a C-style array
|
||||
|
||||
FORCE_INLINE Sint64 Bgp_DumpMsg(Bgpmsg *msg,
|
||||
void *streamp, const StmOps *ops,
|
||||
const BgpDumpfmt *fmt)
|
||||
{
|
||||
extern Judgement _Bgp_SetErrStat(BgpRet,
|
||||
const char *,
|
||||
const char *,
|
||||
unsigned long long,
|
||||
unsigned);
|
||||
|
||||
Sint64 res = 0;
|
||||
if (ops->Write && fmt->DumpMsg)
|
||||
res = fmt->DumpMsg(BGP_HDR(msg), msg->flags, streamp, ops, msg->table);
|
||||
else
|
||||
_Bgp_SetErrStat(BGPENOERR, NULL, NULL, 0, 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Sint64 Bgp_DumpMrtUpdate(const Mrthdr *hdr,
|
||||
void *streamp, const StmOps *ops,
|
||||
const BgpDumpfmt *fmt);
|
||||
|
||||
Sint64 Bgp_DumpMrtRibv2(const Mrthdr *hdr,
|
||||
const Mrtpeerentv2 *peer, const Mrtribentv2 *ent,
|
||||
void *streamp, const StmOps *ops,
|
||||
const BgpDumpfmt *fmt);
|
||||
|
||||
Sint64 Bgp_DumpMrtRib(const Mrthdr *hdr,
|
||||
const Mrtribent *ent,
|
||||
void *streamp, const StmOps *ops,
|
||||
const BgpDumpfmt *fmt);
|
||||
|
||||
#endif
|
888
lonetix/include/df/bgp/mrt.h
Executable file
888
lonetix/include/df/bgp/mrt.h
Executable file
@@ -0,0 +1,888 @@
|
||||
// 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->subtype == 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
|
44
lonetix/include/df/bgp/patricia.h
Executable file
44
lonetix/include/df/bgp/patricia.h
Executable file
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* \file bgp/patricia.h
|
||||
*
|
||||
* PATRICIA trie implementation.
|
||||
*
|
||||
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
||||
* \author Lorenzo Cogotti
|
||||
*/
|
||||
|
||||
#ifndef DF_BGP_PATRICIA_H_
|
||||
#define DF_BGP_PATRICIA_H_
|
||||
|
||||
#include "bgp/prefix.h"
|
||||
|
||||
/// Opaque type, trie memory chunk block.
|
||||
typedef struct Patblock Patblock;
|
||||
/// Opaque type, concrete trie node.
|
||||
typedef union Patnode Patnode;
|
||||
|
||||
/// PATRICIA trie.
|
||||
typedef struct {
|
||||
Afi afi; ///< AFI type
|
||||
unsigned nprefixes; ///< Prefixes count stored inside trie
|
||||
|
||||
Patnode *head; ///< Trie root node
|
||||
Patblock *blocks; ///< PATRICIA memory blocks
|
||||
Patnode *freeBins[IPV6_SIZE / 4]; ///< Fast free bins
|
||||
} Patricia;
|
||||
|
||||
RawPrefix *Pat_Insert(Patricia *trie, const RawPrefix *pfx);
|
||||
Boolean Pat_Remove(Patricia *trie, const RawPrefix *pfx);
|
||||
|
||||
RawPrefix *Pat_SearchExact(const Patricia *trie, const RawPrefix *pfx);
|
||||
|
||||
Boolean Pat_IsSubnetOf(const Patricia *trie, const RawPrefix *pfx);
|
||||
Boolean Pat_IsSupernetOf(const Patricia *trie, const RawPrefix *pfx);
|
||||
Boolean Pat_IsRelatedOf(const Patricia *trie, const RawPrefix *pfx);
|
||||
|
||||
/// Reset `trie` and free all memory.
|
||||
void Pat_Clear(Patricia *trie);
|
||||
|
||||
#endif
|
222
lonetix/include/df/bgp/prefix.h
Executable file
222
lonetix/include/df/bgp/prefix.h
Executable file
@@ -0,0 +1,222 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* \file bgp/prefix.h
|
||||
*
|
||||
* Network prefixes types and utilities.
|
||||
*
|
||||
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
||||
* \author Lorenzo Cogotti
|
||||
*/
|
||||
|
||||
#ifndef DF_BGP_PREFIX_H_
|
||||
#define DF_BGP_PREFIX_H_
|
||||
|
||||
#include "sys/ip.h"
|
||||
|
||||
/**
|
||||
* \brief `Afi` values.
|
||||
*
|
||||
* \see [Address family numbers](https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml)
|
||||
*
|
||||
* \note Address family numbers are in network order (big endian).
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define AFI_IP BE16(1)
|
||||
#define AFI_IP6 BE16(2)
|
||||
|
||||
/**
|
||||
* \brief Address Family Identifier, as defined by the BGP protocol.
|
||||
*
|
||||
* \note Address family numbers are in network order (big endian).
|
||||
*/
|
||||
typedef Uint16 Afi;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \brief `Safi` values.
|
||||
*
|
||||
* \see [SAFI namespace](https://www.iana.org/assignments/safi-namespace/safi-namespace.xhtml)
|
||||
* \see [RFC 4760](http://www.iana.org/go/rfc4760)
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define SAFI_UNICAST U8_C(1)
|
||||
#define SAFI_MULTICAST U8_C(2)
|
||||
|
||||
/// Subsequent Address Family Identifier, as defined by the BGP protocol.
|
||||
typedef Uint8 Safi;
|
||||
|
||||
/** @} */
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/**
|
||||
* \brief BGP prefix with PATH ID information
|
||||
*
|
||||
* \warning **Misaligned struct**.
|
||||
* \note Fields are in network order (big endian).
|
||||
*/
|
||||
typedef ALIGNED(1, struct) {
|
||||
Uint32 pathId; ///< Path identifier
|
||||
Uint8 width; ///< Prefix length in bits
|
||||
|
||||
/**
|
||||
* \brief Prefix content `union`.
|
||||
*
|
||||
* \warning Only `PFXLEN(width)` bytes are relevant.
|
||||
*/
|
||||
union {
|
||||
Uint8 bytes[16]; ///< Prefix raw bytes
|
||||
Uint16 words[8]; ///< Prefix contents as a sequence of 16-bits values
|
||||
Uint32 dwords[4]; ///< Prefix contents as a sequence of 32-bits values
|
||||
Ipv4adr v4; ///< Prefix as a **full** IPv4 address
|
||||
Ipv6adr v6; ///< Prefix as a **full** IPv6 address
|
||||
};
|
||||
} ApRawPrefix;
|
||||
|
||||
/**
|
||||
* \brief BGP prefix with no PATH ID information.
|
||||
*
|
||||
* \warning **Misaligned struct**.
|
||||
* \note Fields are in network order (big endian).
|
||||
*/
|
||||
typedef ALIGNED(1, struct) {
|
||||
Uint8 width; ///< Prefix length in bits
|
||||
|
||||
/**
|
||||
* \brief Prefix content `union`.
|
||||
*
|
||||
* \warning Only `PFXLEN(width)` bytes are relevant.
|
||||
*/
|
||||
union {
|
||||
Uint8 bytes[16]; ///< Prefix raw bytes
|
||||
Uint16 words[8]; ///< Prefix contents as a sequence of 16-bits values
|
||||
Uint32 dwords[4]; ///< Prefix contents as a sequence of 32-bits values
|
||||
Ipv4adr v4; ///< Prefix as a **full** IPv4 address
|
||||
Ipv6adr v6; ///< Prefix as a **full** IPv6 address
|
||||
};
|
||||
} RawPrefix;
|
||||
|
||||
/**
|
||||
* \brief "Fat" prefix structure, contains both the actual data and metadata about the BGP prefix itself.
|
||||
*
|
||||
* The structure doesn't reflect the actual BGP protocol format,
|
||||
* it is used whenever a raw BGP data pointer isn't sufficient
|
||||
* to convey enough context for a prefix (e.g. iterating every prefix available
|
||||
* inside a BGP message).
|
||||
*
|
||||
* \warning **Misaligned struct**.
|
||||
* \note Fields are in network order (big endian).
|
||||
*
|
||||
* \note Given the significant amount of metadata, it
|
||||
* should be used sparingly, raw prefixes should be preferred
|
||||
* whenever possible to save the overhead.
|
||||
*/
|
||||
typedef ALIGNED(1, struct) {
|
||||
Boolean8 isAddPath; ///< Whether the path identifier is meaningful or not
|
||||
Afi afi; ///< Prefix address family
|
||||
Safi safi; ///< Prefix subsequent AFI
|
||||
Uint32 pathId; ///< Path identifier (only meaningful if `isAddPath` is `TRUE`)
|
||||
Uint8 width; ///< Prefix width, in bits (maximum legal value depends on AFI)
|
||||
|
||||
/**
|
||||
* \brief Prefix content `union`.
|
||||
*
|
||||
* \warning Only `PFXLEN(width)` bytes are relevant.
|
||||
*/
|
||||
union {
|
||||
Uint8 bytes[16]; ///< Prefix raw bytes
|
||||
Uint16 words[8]; ///< Prefix contents as a sequence of 16-bits values
|
||||
Uint32 dwords[4]; ///< Prefix contents as a sequence of 32-bits values
|
||||
Ipv4adr v4; ///< Prefix as a **full** IPv4 address
|
||||
Ipv6adr v6; ///< Prefix as a **full** IPv6 address
|
||||
};
|
||||
} Prefix;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/// Calculate prefix length in bytes from bit width.
|
||||
#define PFXLEN(width) ((size_t) (((width) >> 3) + (((width) & 7) != 0)))
|
||||
/**
|
||||
* \brief Return pointer to `RawPrefix` portion out of `ApRawPrefix`, `Prefix` or `RawPrefix` itself.
|
||||
*
|
||||
* Cast operation is useful to discard PATH ID information where irrelevant.
|
||||
*/
|
||||
#define PLAINPFX(prefix) ((RawPrefix *) (&(prefix)->width))
|
||||
/// Return pointer to `ApRawPrefix` out of `Prefix` or `ApRawPrefix` itself.
|
||||
#define APPFX(prefix) ((ApRawPrefix *) (&(prefix)->pathId))
|
||||
|
||||
/// Maximum length of an IPv6 prefix encoded as a string.
|
||||
#define PFX6_STRLEN (IPV6_STRLEN + 1 + 3)
|
||||
/// Maximum length of an IPv4 prefix encoded as a string.
|
||||
#define PFX4_STRLEN (IPV4_STRLEN + 1 + 2)
|
||||
/// Maximum length of an IPv6 prefix with PATH ID, encoded as a string.
|
||||
#define APPFX6_STRLEN (10 + 1 + PFX6_STRLEN)
|
||||
/// Maximum length of an IPv4 prefix with PATH ID, encoded as a string.
|
||||
#define APPFX4_STRLEN (10 + 1 + PFX4_STRLEN)
|
||||
/// Maximum length of a prefix encoded as a string.
|
||||
#define PFX_STRLEN PFX6_STRLEN
|
||||
/// Maximum length of a prefix with PATH ID, encoded as a string.
|
||||
#define APPFX_STRLEN APPFX6_STRLEN
|
||||
|
||||
/**
|
||||
* Convert a `RawPrefix` of the specified `Afi` to its string representation.
|
||||
*
|
||||
* \return Pointer to the trailing `\0` inside `dest`.
|
||||
*
|
||||
* \note Assumes `dest` is large enough to hold result (use `[PFX_STRLEN + 1]`)
|
||||
*/
|
||||
char *Bgp_PrefixToString(Afi afi, const RawPrefix *pfx, char *dest);
|
||||
/**
|
||||
* Convert an `ApRawPrefix` of the specified `Afi` to its string representation.
|
||||
*
|
||||
* \return Pointer to the trailing `\0` inside `dest`.
|
||||
*
|
||||
* \note Assumes `dest` is large enough to hold result (use `[APPFX_STRLEN + 1]`)
|
||||
*/
|
||||
char *Bgp_ApPrefixToString(Afi afi, const ApRawPrefix *pfx, char *dest);
|
||||
|
||||
/**
|
||||
* \brief Convert string with format `address/width` to `Prefix`.
|
||||
*
|
||||
* \return `OK` on success, `NG` on invalid prefix string.
|
||||
*
|
||||
* \note Does not handle PATH ID, may only return plain prefixes.
|
||||
*/
|
||||
Judgement Bgp_StringToPrefix(const char *s, Prefix *dest);
|
||||
|
||||
/**
|
||||
* \brief Direct iterator over raw prefix data.
|
||||
*
|
||||
* \note `struct` should be considered opaque.
|
||||
*/
|
||||
typedef struct {
|
||||
Afi afi;
|
||||
Safi safi;
|
||||
Boolean8 isAddPath;
|
||||
|
||||
Uint8 *base, *lim;
|
||||
Uint8 *ptr;
|
||||
} Prefixiter;
|
||||
|
||||
/**
|
||||
* \brief Start iterating `nbytes` bytes from `data` for prefixes of the specified `afi` and `safi`.
|
||||
*
|
||||
* \return `OK` on success, `NG` on error. Sets BGP error, see `Bgp_GetErrStat()`.
|
||||
*/
|
||||
Judgement Bgp_StartPrefixes(Prefixiter *it, Afi afi, Safi safi, const void *data, size_t nbytes, Boolean isAddPath);
|
||||
/**
|
||||
* \brief Get current prefix and advance iterator.
|
||||
*
|
||||
* \return Current prefix on success, depending on `isAddPath` prefix type
|
||||
* may be either `RawPrefix` or `ApRawPrefix`. `NULL` on iteration end or
|
||||
* error. Sets BGP error, see `Bgp_GetErrStat()`.
|
||||
*/
|
||||
void *Bgp_NextPrefix(Prefixiter *it);
|
||||
|
||||
#endif
|
385
lonetix/include/df/bgp/vm.h
Executable file
385
lonetix/include/df/bgp/vm.h
Executable file
@@ -0,0 +1,385 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* \file bgp/vm.h
|
||||
*
|
||||
* BGP message filtering engine.
|
||||
*
|
||||
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
||||
* \author Lorenzo Cogotti
|
||||
*/
|
||||
|
||||
#ifndef DF_BGP_VM_H_
|
||||
#define DF_BGP_VM_H_
|
||||
|
||||
#include "bgp.h"
|
||||
|
||||
/**
|
||||
* \name BGP VM bytecode
|
||||
*
|
||||
* \brief Filtering engine instruction OPCODEs and arguments.
|
||||
*
|
||||
* Bytecode format is:
|
||||
* ```
|
||||
* LSB MSB (NATIVE endianness)
|
||||
* +--------+--------+
|
||||
* | OPCODE | ARG |
|
||||
* +--------+--------+
|
||||
* 0 16 bit
|
||||
*
|
||||
* (2 bytes per instruction)
|
||||
* ```
|
||||
*
|
||||
* Bytecode follows native machine endianness, it is NOT endian independent.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// BGP filter VM OPCODE
|
||||
typedef Uint8 Bgpvmopc;
|
||||
/// BGP filter VM bytecode instruction
|
||||
typedef Uint16 Bgpvmbytec;
|
||||
|
||||
/// Returns a VM bytecode with the specified opcode and argument.
|
||||
#define BGP_VMOP(opc, arg) ((Bgpvmbytec) ((((Uint8) (arg)) << 8) | ((Bgpvmopc) opc)))
|
||||
|
||||
/// Extract OPCODE from the specified bytecode.
|
||||
FORCE_INLINE Bgpvmopc BGP_VMOPC(Bgpvmbytec bytec)
|
||||
{
|
||||
return (Bgpvmopc) (bytec & 0xff);
|
||||
}
|
||||
|
||||
/// Extract direct argument from the specified bytecode.
|
||||
FORCE_INLINE Uint8 BGP_VMOPARG(Bgpvmbytec bytec)
|
||||
{
|
||||
return (bytec >> 8);
|
||||
}
|
||||
|
||||
/// NO-OPERATION - does nothing and moves on
|
||||
#define BGP_VMOP_NOP U8_C(0)
|
||||
/// LOAD - Pushes `ARG` constant on stack, interpreting it as a `Sint8`
|
||||
#define BGP_VMOP_LOAD U8_C(1)
|
||||
/// LOAD UNSIGNED - Pushes `ARG` constant on stack, interpreting it as an `Uint8`
|
||||
#define BGP_VMOP_LOADU U8_C(2)
|
||||
/// LOAD NULL - Push a `NULL` address on stack
|
||||
#define BGP_VMOP_LOADN U8_C(3)
|
||||
/// LOADK - Push a new constant (K) on stack, `ARG` is the index inside `K`
|
||||
#define BGP_VMOP_LOADK U8_C(4)
|
||||
/// CALL - invoke an external native function
|
||||
#define BGP_VMOP_CALL U8_C(5)
|
||||
/// BLOCK OPEN - Push a new matching block (used to implement AND/OR chains)
|
||||
#define BGP_VMOP_BLK U8_C(6)
|
||||
/// END BLOCK - Pops the current matching block
|
||||
#define BGP_VMOP_ENDBLK U8_C(7)
|
||||
/// TAG LAST MATCH - Tags last operation's match with `ARG`
|
||||
#define BGP_VMOP_TAG U8_C(8)
|
||||
/// NOT - Boolean negate the topmost stack element
|
||||
#define BGP_VMOP_NOT U8_C(9)
|
||||
/// CONDITIONAL FAIL If TRUE - Fail the current matching `BLK` if topmost stack element is non-zero
|
||||
#define BGP_VMOP_CFAIL U8_C(10)
|
||||
/// CONDITIONAL PASS If TRUE - Pass the current matching `BLK` if topmost stack element is non-zero
|
||||
#define BGP_VMOP_CPASS U8_C(11)
|
||||
|
||||
/// Jump if zero - Skip over a positive number of instructions if topmost stack element is 0.
|
||||
#define BGP_VMOP_JZ U8_C(12)
|
||||
/// Jump if non-zero - Skip over a positive number of instructions if topmost stack element is not 0.
|
||||
#define BGP_VMOP_JNZ U8_C(13)
|
||||
|
||||
/// CHECK TYPE - ARG is the `BgpType` to test against
|
||||
#define BGP_VMOP_CHKT U8_C(14)
|
||||
/// CHECK ATTRIBUTE - ARG is the `BgpAttrCode` to test for existence
|
||||
#define BGP_VMOP_CHKA U8_C(15)
|
||||
|
||||
#define BGP_VMOP_EXCT U8_C(16)
|
||||
#define BGP_VMOP_SUPN U8_C(17)
|
||||
#define BGP_VMOP_SUBN U8_C(18)
|
||||
/// RELATED - Tests whether the BGP message contains prefixes related with the provided ones
|
||||
#define BGP_VMOP_RELT U8_C(19)
|
||||
|
||||
/// Returns `TRUE` if `opc` belongs to an instruction operating on NETwork prefixes.
|
||||
FORCE_INLINE Boolean BGP_ISVMOPNET(Bgpvmopc opc)
|
||||
{
|
||||
return opc >= BGP_VMOP_EXCT && opc <= BGP_VMOP_RELT;
|
||||
}
|
||||
|
||||
/// AS PATH MATCH - Tests BGP message AS PATH against a match expression
|
||||
#define BGP_VMOP_ASMTCH U8_C(20)
|
||||
/// FAST AS PATH MATCH - AS PATH test using precompiled AS PATH match expression
|
||||
#define BGP_VMOP_FASMTC U8_C(21)
|
||||
/// COMMUNITY MATCH - COMMUNITY test using a precompiled COMMUNITY match expression
|
||||
#define BGP_VMOP_COMTCH U8_C(22)
|
||||
/// ALL COMMUNITY MATCH - Like COMTCH, but requires all communities to be present inside message
|
||||
#define BGP_VMOP_ACOMTC U8_C(23)
|
||||
|
||||
/// END - Terminate VM execution with the latest result
|
||||
#define BGP_VMOP_END U8_C(24)
|
||||
|
||||
// #define BGP_VMOP_MOVK MOVE K - Move topmost K index to ARG K index
|
||||
// #define BGP_VMOP_DISCRD DISCARD - discard vm->curMatch if any
|
||||
|
||||
// Bytecode `ARG` values for `NET` class instructions
|
||||
#define BGP_VMOPA_NLRI U8_C(0)
|
||||
#define BGP_VMOPA_MPREACH U8_C(1)
|
||||
#define BGP_VMOPA_ALL_NLRI U8_C(2)
|
||||
#define BGP_VMOPA_WITHDRAWN U8_C(3)
|
||||
#define BGP_VMOPA_MPUNREACH U8_C(4)
|
||||
#define BGP_VMOPA_ALL_WITHDRAWN U8_C(5)
|
||||
|
||||
// Special `Asn` values for `ASMTCH` and `FASMTC` instructions
|
||||
|
||||
#define ASNNOTFLAG BIT(61)
|
||||
|
||||
/// Matches any ASN **except** the provided one.
|
||||
#define ASNNOT(asn) ((Asn) ((asn) | ASNNOTFLAG))
|
||||
|
||||
/// Tests whether `asn` is a negative ASN match.
|
||||
FORCE_INLINE Boolean ISASNNOT(Asn asn)
|
||||
{
|
||||
return (asn & ASNNOTFLAG) != 0;
|
||||
}
|
||||
|
||||
/// Match with the AS_PATH start (^)
|
||||
#define ASN_START ((Asn) 0x0000000100000000LL)
|
||||
/// Match with the AS PATH end ($).
|
||||
#define ASN_END ((Asn) 0x0000000200000000LL)
|
||||
/// Match with any ASN (.).
|
||||
#define ASN_ANY ((Asn) 0x0000000300000000LL)
|
||||
/// Match zero or more ASN (*).
|
||||
#define ASN_STAR ((Asn) 0x0000000400000000LL)
|
||||
/// Match with zero or one ASN (?).
|
||||
#define ASN_QUEST ((Asn) 0x0000000500000000LL)
|
||||
/// Match the previous ASN one or more times (+).
|
||||
#define ASN_PLUS ((Asn) 0x0000000600000000LL)
|
||||
/// Introduce a new group (opening paren for expressions like `( a b c )`)
|
||||
#define ASN_NEWGRP ((Asn) 0x0000000700000000LL)
|
||||
/// Introduce alternative inside matching expression (pipe symbol for expressions like `( a b | b c )`)
|
||||
#define ASN_ALT ((Asn) 0x0000000800000000LL)
|
||||
/// Terminate a group expression (closing paren for expressions like `( a b c )`)
|
||||
#define ASN_ENDGRP ((Asn) 0x0000000900000000LL)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \brief Stack slot.
|
||||
*
|
||||
* The VM stack is a sequence of `Bgpvmval` cells,
|
||||
* interpreted by each instruction as dictated by the opcode.
|
||||
*/
|
||||
typedef union Bgpvmval Bgpvmval;
|
||||
union Bgpvmval {
|
||||
void *ptr; ///< Value as a pointer
|
||||
Sint64 val; ///< Value as a signed integral
|
||||
};
|
||||
|
||||
/// Match info for AS matching expressions.
|
||||
typedef struct Bgpvmasmatch Bgpvmasmatch;
|
||||
struct Bgpvmasmatch {
|
||||
Bgpvmasmatch *next;
|
||||
Aspathiter spos;
|
||||
Aspathiter epos;
|
||||
};
|
||||
|
||||
/// Optimization modes for some matching instructions (e.g. BGP_VMOP_COMTCH/BGP_VMOP_ACOMTC).
|
||||
typedef enum {
|
||||
BGP_VMOPT_NONE, ///< Do not optimize.
|
||||
|
||||
// For COMTCH/ACOMTC
|
||||
BGP_VMOPT_ASSUME_COMTCH, ///< Assume instruction is going to be `COMTCH`
|
||||
BGP_VMOPT_ASSUME_ACOMTC ///< Assume instruction is going to be `ACOMTC`
|
||||
} BgpVmOpt;
|
||||
|
||||
typedef struct Bgpmatchcomm Bgpmatchcomm;
|
||||
struct Bgpmatchcomm {
|
||||
Boolean8 maskHi; // don't match HI (match of type *:N)
|
||||
Boolean8 maskLo; // don't match LO (match of type N:*)
|
||||
Bgpcomm c;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Matching operation result on a BGP message.
|
||||
*
|
||||
* Collect relevant information on a matching operation, including the
|
||||
* direct byte range and position inside BGP message data.
|
||||
*
|
||||
* This structure may be used to further process BGP data after the filtering
|
||||
* is complete. A `Bgpvmmatch` structure is generated for several BGP VM
|
||||
* OPCODEs, and is only valid up to the next [Bgp_VmExec()](@ref Bgp_VmExec)
|
||||
* call on the same VM that originated them.
|
||||
*/
|
||||
typedef struct Bgpvmmatch Bgpvmmatch;
|
||||
struct Bgpvmmatch {
|
||||
Uint32 pc; ///< instruction index that originated this match
|
||||
Boolean8 isMatching; ///< whether this result declares a match or a mismatch
|
||||
Boolean8 isPassing; ///< whether this result produced a `PASS` or a `FAIL` inside filter
|
||||
Uint8 tag; ///< optional tag id for this match (as set by `TAG`)
|
||||
Uint8 *base, *lim; ///< relevant BGP message segment, if any
|
||||
void *pos; ///< pointer to detailed match-specific information
|
||||
Bgpvmmatch *nextMatch; ///< next match in chain (`NULL` if this is the last element)
|
||||
};
|
||||
|
||||
/// Filtering engine error code (a subset of [BgpRet](@ref BgpRet).
|
||||
typedef Sint8 BgpvmRet;
|
||||
|
||||
/// Maximum number of VM constants inside [Bgpvm](@ref Bgpvm).
|
||||
#define MAXBGPVMK 256
|
||||
/// Maximum number of VM callable functions inside [Bgpvm](@ref Bgpvm).
|
||||
#define MAXBGPVMFN 32
|
||||
/// Maximum allowed nested grouping levels inside a `BGP_VMOP_ASMTCH`.
|
||||
#define MAXBGPVMASNGRP 32
|
||||
|
||||
/**
|
||||
* \brief Bytecode-based virtual machine operating on BGP messages.
|
||||
*
|
||||
* Extensible programmable BGP message matching and filtering engine.
|
||||
*/
|
||||
typedef struct Bgpvm Bgpvm;
|
||||
struct Bgpvm {
|
||||
Uint32 pc; ///< VM program counter inside `prog`
|
||||
Uint32 nblk; ///< nested conditional block count
|
||||
Uint32 nmatches; ///< current execution matches count (length of the `matches` list)
|
||||
Uint16 si; ///< VM Stack index
|
||||
Uint16 nk; ///< count of constants (K) available in `k`
|
||||
Uint8 nfuncs; ///< count of functions (FN) available in `funcs`
|
||||
Boolean8 setupFailed; ///< whether a `Bgp_VmEmit()` or `Bgp_VmPermAlloc()` on this VM ever failed.
|
||||
Boolean8 isRunning; ///< whether the VM is being executed
|
||||
BgpvmRet errCode; ///< whether the VM encountered an error
|
||||
Uint32 hLowMark; ///< VM heap low memory mark
|
||||
Uint32 hHighMark; ///< VM heap high memory mark
|
||||
Uint32 hMemSiz; ///< VM heap size in bytes
|
||||
Uint32 progLen; ///< bytecode program instruction count
|
||||
Uint32 progCap; ///< bytecode segment instruction capacity
|
||||
Bgpmsg *msg; ///< current BGP message being processed
|
||||
Bgpvmbytec *prog; ///< VM program bytecode, `progLen` instructions (`prog[progLen]` is always `BGP_VMOP_END`)
|
||||
/**
|
||||
* Filtering VM heap, managed as follows:
|
||||
* ```
|
||||
* hLowMark hHighMark
|
||||
* heap -+ v v
|
||||
* v STACK grows upwards .-.-> <.-.-. TEMP grows downwards
|
||||
* +=====================\-------------------/=============+
|
||||
* | PERM ALLOCS | STACK > < TEMP ALLOCS |
|
||||
* +=====================/-------------------\=============+
|
||||
* [--------------------- hMemSiz -------------------------]
|
||||
*
|
||||
* PERM ALLOCS: Allocations that last forever (until the VM is freed)
|
||||
* - such allocations CANNOT happen while VM is running
|
||||
*
|
||||
* TEMP ALLOCS: Allocations that last up to the next Bgp_VmExec()
|
||||
* - such allocations may only take place while VM is running
|
||||
* ```
|
||||
*/
|
||||
void *heap;
|
||||
Bgpvmmatch *curMatch; ///< current match being updated during VM execution
|
||||
Bgpvmmatch *matches; ///< matches produced during execution (contains `nmatches` elements)
|
||||
Bgpvmval k[MAXBGPVMK]; ///< VM constants (K), `nk` allocated
|
||||
void (*funcs[MAXBGPVMFN])(Bgpvm *); ///< VM functions (FN), `nfuncs` allocated
|
||||
};
|
||||
|
||||
/// Clear the `errCode` error flag on `vm`.
|
||||
FORCE_INLINE void BGP_VMCLRERR(Bgpvm *vm)
|
||||
{
|
||||
vm->errCode = BGPENOERR;
|
||||
}
|
||||
|
||||
/// Clear the `setupFailed` error flag on `vm`.
|
||||
FORCE_INLINE void BGP_VMCLRSETUP(Bgpvm *vm)
|
||||
{
|
||||
vm->setupFailed = FALSE;
|
||||
}
|
||||
|
||||
FORCE_INLINE Sint32 Bgp_VmNewk(Bgpvm *vm)
|
||||
{
|
||||
if (vm->nk >= MAXBGPVMK)
|
||||
return -1;
|
||||
|
||||
return vm->nk++;
|
||||
}
|
||||
|
||||
FORCE_INLINE Sint32 Bgp_VmNewFn(Bgpvm *vm)
|
||||
{
|
||||
if (vm->nfuncs >= MAXBGPVMFN)
|
||||
return -1;
|
||||
|
||||
return vm->nfuncs++;
|
||||
}
|
||||
|
||||
FORCE_INLINE Sint32 BGP_VMSETKA(Bgpvm *vm, Sint32 kidx, void *ptr)
|
||||
{
|
||||
if (kidx >= 0)
|
||||
vm->k[kidx].ptr = ptr;
|
||||
|
||||
return kidx;
|
||||
}
|
||||
|
||||
FORCE_INLINE Sint32 BGP_VMSETK(Bgpvm *vm, Sint32 kidx, Sint64 val)
|
||||
{
|
||||
if (kidx >= 0)
|
||||
vm->k[kidx].val = val;
|
||||
|
||||
return kidx;
|
||||
}
|
||||
|
||||
FORCE_INLINE Sint32 BGP_VMSETFN(Bgpvm *vm, Sint32 idx, void (*fn)(Bgpvm *))
|
||||
{
|
||||
if (idx >= 0)
|
||||
vm->funcs[idx] = fn;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize a new VM with the specified heap size.
|
||||
*
|
||||
* \return `OK` on success, `NG` on out of memory, sets BGP error, VM error,
|
||||
* and, on failure, VM setup failure flag.
|
||||
*/
|
||||
Judgement Bgp_InitVm(Bgpvm *vm, size_t heapSiz);
|
||||
|
||||
/**
|
||||
* \brief Emit a VM bytecode instruction to `vm`.
|
||||
*
|
||||
* \return `OK` if instruction was added successfully, `NG` on out of memory,
|
||||
* sets BGP error, VM error and, on failure, VM setup failure flag.
|
||||
*
|
||||
* \note Emitting `BGP_VMOP_END` has no effect.
|
||||
*/
|
||||
Judgement Bgp_VmEmit(Bgpvm *vm, Bgpvmbytec bytec);
|
||||
/**
|
||||
* \brief Precompile an AS PATH match expression for use with BGP_VMOP_FASMTC.
|
||||
*
|
||||
* \return Pointer suitable as the argument of `BGP_VMOP_FASMTC` instruction
|
||||
* on success, `NULL` on failure.
|
||||
* Precompiled expression is stored inside `vm` permanent heap.
|
||||
*/
|
||||
void *Bgp_VmCompileAsMatch(Bgpvm *vm, const Asn *match, size_t n);
|
||||
void *Bgp_VmCompileCommunityMatch(Bgpvm *vm, const Bgpmatchcomm *match, size_t n, BgpVmOpt opt);
|
||||
|
||||
/**
|
||||
* \brief Perform a permanent heap allocation of `size` bytes to `vm`.
|
||||
*
|
||||
* \return `vm` heap pointer to memory zone on success, `NULL` on failure,
|
||||
* sets BGP error, VM error, and, on failure, `vm` setup failure flag.
|
||||
*
|
||||
* \note This function may only be called if `vm` is not executing!
|
||||
*/
|
||||
void *Bgp_VmPermAlloc(Bgpvm *vm, size_t size);
|
||||
void *Bgp_VmTempAlloc(Bgpvm *vm, size_t size);
|
||||
void Bgp_VmTempFree(Bgpvm *vm, size_t size);
|
||||
|
||||
/**
|
||||
* \brief Execute `vm` bytecode on `msg`.
|
||||
*
|
||||
* \return `TRUE` if `vm` terminated with PASS, `FALSE` if it terminated on
|
||||
* FAIL, or if an error was encountered. Sets BGP error and VM error.
|
||||
*/
|
||||
Boolean Bgp_VmExec(Bgpvm *vm, Bgpmsg *msg);
|
||||
/// Print `vm` bytecode dump to stream.
|
||||
void Bgp_VmDumpProgram(Bgpvm *vm, void *streamp, const StmOps *ops);
|
||||
|
||||
/// Reset `vm` state, but keep allocated memory for further setup.
|
||||
void Bgp_ResetVm(Bgpvm *vm);
|
||||
|
||||
/// Clear `vm` and free all memory.
|
||||
void Bgp_ClearVm(Bgpvm *vm);
|
||||
|
||||
#endif
|
250
lonetix/include/df/bgp/vmintrin.h
Executable file
250
lonetix/include/df/bgp/vmintrin.h
Executable file
@@ -0,0 +1,250 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* \file bgp/vmintrin.h
|
||||
*
|
||||
* BGP VM engine operation intrinsics.
|
||||
*
|
||||
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
||||
* \author Lorenzo Cogotti
|
||||
*
|
||||
* Utilities in this file are meant for low level VM interaction,
|
||||
* usually to implement actual VM extensions.
|
||||
*/
|
||||
|
||||
#ifndef DF_BGP_VMINTRIN_H_
|
||||
#define DF_BGP_VMINTRIN_H_
|
||||
|
||||
#include "bgp/vm.h"
|
||||
|
||||
/// Get current VM program counter.
|
||||
FORCE_INLINE Uint32 BGP_VMCURPC(Bgpvm *vm)
|
||||
{
|
||||
return vm->pc - 1; // PC always references *next* instruction
|
||||
}
|
||||
|
||||
/// Get VM stack base pointer.
|
||||
FORCE_INLINE Bgpvmval *BGP_VMSTK(Bgpvm *vm)
|
||||
{
|
||||
return (Bgpvmval *) ((Uint8 *) vm->heap + vm->hLowMark);
|
||||
}
|
||||
|
||||
/// Get stack value at index `idx`, -1 is topmost value, -2 is second to topmost...
|
||||
FORCE_INLINE Bgpvmval *BGP_VMSTKGET(Bgpvm *vm, Sint32 idx)
|
||||
{
|
||||
Bgpvmval *stk = BGP_VMSTK(vm);
|
||||
|
||||
return &stk[vm->si + idx];
|
||||
}
|
||||
|
||||
/// Equivalent to `BGP_VMSTKGET()`, but returns stack content as `Sint64`.
|
||||
FORCE_INLINE Sint64 BGP_VMPEEK(Bgpvm *vm, Sint32 idx)
|
||||
{
|
||||
return BGP_VMSTKGET(vm, idx)->val;
|
||||
}
|
||||
|
||||
/// Equivalent to `BGP_VMSTKGET()`, but returns stack content as `void *`.
|
||||
FORCE_INLINE void *BGP_VMPEEKA(Bgpvm *vm, Sint32 idx)
|
||||
{
|
||||
return BGP_VMSTKGET(vm, idx)->ptr;
|
||||
}
|
||||
|
||||
/// Pop `n` values from VM stack, **assumes stack is large enough**.
|
||||
FORCE_INLINE void BGP_VMPOPN(Bgpvm *vm, Uint32 n)
|
||||
{
|
||||
vm->si -= n;
|
||||
}
|
||||
|
||||
/// Pop topmost stack value in VM, returning its value as `Sint64`, **assumes stack is not empty**.
|
||||
FORCE_INLINE Sint64 BGP_VMPOP(Bgpvm *vm)
|
||||
{
|
||||
Bgpvmval *stk = BGP_VMSTK(vm);
|
||||
|
||||
return stk[--vm->si].val;
|
||||
}
|
||||
|
||||
/// Like `BGP_VMPOP()`, but returns value as `void *`.
|
||||
FORCE_INLINE void *BGP_VMPOPA(Bgpvm *vm)
|
||||
{
|
||||
Bgpvmval *stk = BGP_VMSTK(vm);
|
||||
|
||||
return stk[--vm->si].ptr;
|
||||
}
|
||||
|
||||
/// Push `v` to stack, **assumes enough stack space is available**.
|
||||
FORCE_INLINE void BGP_VMPUSH(Bgpvm *vm, Sint64 v)
|
||||
{
|
||||
Bgpvmval *stk = BGP_VMSTK(vm);
|
||||
|
||||
stk[vm->si++].val = v;
|
||||
}
|
||||
|
||||
/// Like `BGP_VMPUSH()`, but pushes a pointer.
|
||||
FORCE_INLINE void BGP_VMPUSHA(Bgpvm *vm, void *p)
|
||||
{
|
||||
Bgpvmval *stk = BGP_VMSTK(vm);
|
||||
|
||||
stk[vm->si++].ptr = p;
|
||||
}
|
||||
|
||||
/// Ensure at least `n` elements may be popped from the stack.
|
||||
FORCE_INLINE Boolean BGP_VMCHKSTKSIZ(Bgpvm *vm, Uint32 n)
|
||||
{
|
||||
if (vm->si < n) {
|
||||
vm->errCode = BGPEVMUFLOW;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/// Ensure at least `n` elements may be pushed to the stack.
|
||||
FORCE_INLINE Boolean BGP_VMCHKSTK(Bgpvm *vm, Uint32 n)
|
||||
{
|
||||
size_t siz = vm->si + n;
|
||||
|
||||
siz *= sizeof(Bgpvmval);
|
||||
if (vm->hHighMark - vm->hLowMark < siz) {
|
||||
vm->errCode = BGPEVMOFLOW;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Test whether `vm->msg` header type matches `type`.
|
||||
*
|
||||
* \return Pointer to message header on successful match, `NULL`
|
||||
* otherwise.
|
||||
*/
|
||||
FORCE_INLINE Bgphdr *BGP_VMCHKMSGTYPE(Bgpvm *vm, BgpType type)
|
||||
{
|
||||
Bgphdr *hdr = BGP_HDR(vm->msg);
|
||||
|
||||
return (hdr->type == type) ? hdr : NULL;
|
||||
}
|
||||
|
||||
Judgement Bgp_VmStoreMsgTypeMatch(Bgpvm *vm, Boolean);
|
||||
|
||||
void Bgp_VmStoreMatch(Bgpvm *vm);
|
||||
|
||||
/// Implement `LOAD`.
|
||||
FORCE_INLINE void Bgp_VmDoLoad(Bgpvm *vm, Sint8 val)
|
||||
{
|
||||
if (!BGP_VMCHKSTK(vm, 1))
|
||||
return;
|
||||
|
||||
BGP_VMPUSH(vm, val);
|
||||
}
|
||||
|
||||
/// Implement `LOADU`.
|
||||
FORCE_INLINE void Bgp_VmDoLoadu(Bgpvm *vm, Uint8 val)
|
||||
{
|
||||
if (!BGP_VMCHKSTK(vm, 1))
|
||||
return;
|
||||
|
||||
BGP_VMPUSH(vm, val);
|
||||
}
|
||||
|
||||
/// Implement `LOADK` of `vm->k[idx]`.
|
||||
FORCE_INLINE void Bgp_VmDoLoadk(Bgpvm *vm, Uint8 idx)
|
||||
{
|
||||
if (idx >= vm->nk) {
|
||||
vm->errCode = BGPEVMBADK;
|
||||
return;
|
||||
}
|
||||
if (!BGP_VMCHKSTK(vm, 1))
|
||||
return;
|
||||
|
||||
Bgpvmval *stk = BGP_VMSTK(vm);
|
||||
|
||||
stk[vm->si++] = vm->k[idx];
|
||||
}
|
||||
|
||||
/// Implement `LOADN`.
|
||||
FORCE_INLINE void Bgp_VmDoLoadn(Bgpvm *vm)
|
||||
{
|
||||
if (!BGP_VMCHKSTK(vm, 1)) {
|
||||
vm->errCode = BGPEVMOFLOW;
|
||||
return;
|
||||
}
|
||||
|
||||
BGP_VMPUSHA(vm, NULL);
|
||||
}
|
||||
|
||||
/// Break out of current `BLK`.
|
||||
FORCE_INLINE void Bgp_VmDoBreak(Bgpvm *vm)
|
||||
{
|
||||
Bgpvmopc opc;
|
||||
|
||||
do
|
||||
opc = BGP_VMOPC(vm->prog[vm->pc++]);
|
||||
while (opc != BGP_VMOP_ENDBLK && opc != BGP_VMOP_END);
|
||||
|
||||
if (opc == BGP_VMOP_ENDBLK)
|
||||
vm->nblk--;
|
||||
}
|
||||
|
||||
|
||||
/// Execute `CALL` of function `vm->funcs[idx]`.
|
||||
FORCE_INLINE void Bgp_VmDoCall(Bgpvm *vm, Uint8 idx)
|
||||
{
|
||||
void (*fn)(Bgpvm *);
|
||||
|
||||
if (idx >= vm->nfuncs) {
|
||||
vm->errCode = BGPEVMBADFN;
|
||||
return;
|
||||
}
|
||||
|
||||
fn = vm->funcs[idx];
|
||||
if (fn) fn(vm);
|
||||
}
|
||||
|
||||
/// Implement `CPASS` (Conditional `PASS` if `TRUE`).
|
||||
Boolean Bgp_VmDoCpass(Bgpvm *vm);
|
||||
/// Implement `CFAIL` (Conditional `FAIL` if `TRUE`).
|
||||
Boolean Bgp_VmDoCfail(Bgpvm *vm);
|
||||
|
||||
/// Implement `TAG` instruction with argument `tag`.
|
||||
FORCE_INLINE void Bgp_VmDoTag(Bgpvm *vm, Uint8 tag)
|
||||
{
|
||||
vm->curMatch->tag = tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Implements VM `NOT` instruction.
|
||||
*
|
||||
* Negate stack topmost value.
|
||||
*/
|
||||
FORCE_INLINE void Bgp_VmDoNot(Bgpvm *vm)
|
||||
{
|
||||
// Expected STACK:
|
||||
// -1: Any value interpreted as Sint64
|
||||
|
||||
if (!BGP_VMCHKSTKSIZ(vm, 1))
|
||||
return;
|
||||
|
||||
Bgpvmval *v = BGP_VMSTKGET(vm, -1);
|
||||
|
||||
v->val = !v->val;
|
||||
}
|
||||
|
||||
/// Implements `CHKT` with argument `type`.
|
||||
void Bgp_VmDoChkt(Bgpvm *vm, BgpType type);
|
||||
|
||||
/// Implements `CHKA` with argument `code`.
|
||||
void Bgp_VmDoChka(Bgpvm *vm, BgpAttrCode code);
|
||||
|
||||
void Bgp_VmDoExct(Bgpvm *vm, Uint8 arg);
|
||||
void Bgp_VmDoSupn(Bgpvm *vm, Uint8 arg);
|
||||
void Bgp_VmDoSubn(Bgpvm *vm, Uint8 arg);
|
||||
void Bgp_VmDoRelt(Bgpvm *vm, Uint8 arg);
|
||||
|
||||
void Bgp_VmDoAsmtch(Bgpvm *vm);
|
||||
void Bgp_VmDoFasmtc(Bgpvm *vm);
|
||||
|
||||
void Bgp_VmDoComtch(Bgpvm *vm);
|
||||
void Bgp_VmDoAcomtc(Bgpvm *vm);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user