mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-29 04:25:43 +00:00
Merge pull request #5653 from slankdev/slankdev-bgpd-support-prefix-sid-srv6-l3vpn
bgpd: additional Prefix-SID sub-types for supporting SRv6 l3vpn
This commit is contained in:
commit
7f1ace03c7
318
bgpd/bgp_attr.c
318
bgpd/bgp_attr.c
@ -32,6 +32,7 @@
|
||||
#include "table.h"
|
||||
#include "filter.h"
|
||||
#include "command.h"
|
||||
#include "srv6.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
@ -201,6 +202,8 @@ static struct hash *encap_hash = NULL;
|
||||
#if ENABLE_BGP_VNC
|
||||
static struct hash *vnc_hash = NULL;
|
||||
#endif
|
||||
static struct hash *srv6_l3vpn_hash;
|
||||
static struct hash *srv6_vpn_hash;
|
||||
|
||||
struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
|
||||
{
|
||||
@ -434,6 +437,158 @@ static void transit_unintern(struct transit **transit)
|
||||
}
|
||||
}
|
||||
|
||||
static void *srv6_l3vpn_hash_alloc(void *p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn *l3vpn)
|
||||
{
|
||||
XFREE(MTYPE_BGP_SRV6_L3VPN, l3vpn);
|
||||
}
|
||||
|
||||
static struct bgp_attr_srv6_l3vpn *
|
||||
srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn *l3vpn)
|
||||
{
|
||||
struct bgp_attr_srv6_l3vpn *find;
|
||||
|
||||
find = hash_get(srv6_l3vpn_hash, l3vpn, srv6_l3vpn_hash_alloc);
|
||||
if (find != l3vpn)
|
||||
srv6_l3vpn_free(l3vpn);
|
||||
find->refcnt++;
|
||||
return find;
|
||||
}
|
||||
|
||||
static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn **l3vpnp)
|
||||
{
|
||||
struct bgp_attr_srv6_l3vpn *l3vpn = *l3vpnp;
|
||||
|
||||
if (l3vpn->refcnt)
|
||||
l3vpn->refcnt--;
|
||||
|
||||
if (l3vpn->refcnt == 0) {
|
||||
hash_release(srv6_l3vpn_hash, l3vpn);
|
||||
srv6_l3vpn_free(l3vpn);
|
||||
*l3vpnp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void *srv6_vpn_hash_alloc(void *p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
static void srv6_vpn_free(struct bgp_attr_srv6_vpn *vpn)
|
||||
{
|
||||
XFREE(MTYPE_BGP_SRV6_VPN, vpn);
|
||||
}
|
||||
|
||||
static struct bgp_attr_srv6_vpn *srv6_vpn_intern(struct bgp_attr_srv6_vpn *vpn)
|
||||
{
|
||||
struct bgp_attr_srv6_vpn *find;
|
||||
|
||||
find = hash_get(srv6_vpn_hash, vpn, srv6_vpn_hash_alloc);
|
||||
if (find != vpn)
|
||||
srv6_vpn_free(vpn);
|
||||
find->refcnt++;
|
||||
return find;
|
||||
}
|
||||
|
||||
static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn **vpnp)
|
||||
{
|
||||
struct bgp_attr_srv6_vpn *vpn = *vpnp;
|
||||
|
||||
if (vpn->refcnt)
|
||||
vpn->refcnt--;
|
||||
|
||||
if (vpn->refcnt == 0) {
|
||||
hash_release(srv6_vpn_hash, vpn);
|
||||
srv6_vpn_free(vpn);
|
||||
*vpnp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t srv6_l3vpn_hash_key_make(const void *p)
|
||||
{
|
||||
const struct bgp_attr_srv6_l3vpn *l3vpn = p;
|
||||
uint32_t key = 0;
|
||||
|
||||
key = jhash(&l3vpn->sid, 16, key);
|
||||
key = jhash_1word(l3vpn->sid_flags, key);
|
||||
key = jhash_1word(l3vpn->endpoint_behavior, key);
|
||||
return key;
|
||||
}
|
||||
|
||||
static bool srv6_l3vpn_hash_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
const struct bgp_attr_srv6_l3vpn *l3vpn1 = p1;
|
||||
const struct bgp_attr_srv6_l3vpn *l3vpn2 = p2;
|
||||
|
||||
return sid_same(&l3vpn1->sid, &l3vpn2->sid)
|
||||
&& l3vpn1->sid_flags == l3vpn2->sid_flags
|
||||
&& l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior;
|
||||
}
|
||||
|
||||
static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn *h1,
|
||||
const struct bgp_attr_srv6_l3vpn *h2)
|
||||
{
|
||||
if (h1 == h2)
|
||||
return true;
|
||||
else if (h1 == NULL || h2 == NULL)
|
||||
return false;
|
||||
else
|
||||
return srv6_l3vpn_hash_cmp((const void *)h1, (const void *)h2);
|
||||
}
|
||||
|
||||
static unsigned int srv6_vpn_hash_key_make(const void *p)
|
||||
{
|
||||
const struct bgp_attr_srv6_vpn *vpn = p;
|
||||
uint32_t key = 0;
|
||||
|
||||
key = jhash(&vpn->sid, 16, key);
|
||||
key = jhash_1word(vpn->sid_flags, key);
|
||||
return key;
|
||||
}
|
||||
|
||||
static bool srv6_vpn_hash_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
const struct bgp_attr_srv6_vpn *vpn1 = p1;
|
||||
const struct bgp_attr_srv6_vpn *vpn2 = p2;
|
||||
|
||||
return sid_same(&vpn1->sid, &vpn2->sid)
|
||||
&& vpn1->sid_flags == vpn2->sid_flags;
|
||||
}
|
||||
|
||||
static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn *h1,
|
||||
const struct bgp_attr_srv6_vpn *h2)
|
||||
{
|
||||
if (h1 == h2)
|
||||
return true;
|
||||
else if (h1 == NULL || h2 == NULL)
|
||||
return false;
|
||||
else
|
||||
return srv6_vpn_hash_cmp((const void *)h1, (const void *)h2);
|
||||
}
|
||||
|
||||
static void srv6_init(void)
|
||||
{
|
||||
srv6_l3vpn_hash =
|
||||
hash_create(srv6_l3vpn_hash_key_make, srv6_l3vpn_hash_cmp,
|
||||
"BGP Prefix-SID SRv6-L3VPN-Service-TLV");
|
||||
srv6_vpn_hash = hash_create(srv6_vpn_hash_key_make, srv6_vpn_hash_cmp,
|
||||
"BGP Prefix-SID SRv6-VPN-Service-TLV");
|
||||
}
|
||||
|
||||
static void srv6_finish(void)
|
||||
{
|
||||
hash_clean(srv6_l3vpn_hash, (void (*)(void *))srv6_l3vpn_free);
|
||||
hash_free(srv6_l3vpn_hash);
|
||||
srv6_l3vpn_hash = NULL;
|
||||
hash_clean(srv6_vpn_hash, (void (*)(void *))srv6_vpn_free);
|
||||
hash_free(srv6_vpn_hash);
|
||||
srv6_vpn_hash = NULL;
|
||||
}
|
||||
|
||||
static unsigned int transit_hash_key_make(const void *p)
|
||||
{
|
||||
const struct transit *transit = p;
|
||||
@ -557,7 +712,9 @@ bool attrhash_cmp(const void *p1, const void *p2)
|
||||
&& overlay_index_same(attr1, attr2)
|
||||
&& attr1->nh_ifindex == attr2->nh_ifindex
|
||||
&& attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
|
||||
&& attr1->distance == attr2->distance)
|
||||
&& attr1->distance == attr2->distance
|
||||
&& srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
|
||||
&& srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn))
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -588,12 +745,22 @@ static void attrhash_finish(void)
|
||||
static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty)
|
||||
{
|
||||
struct attr *attr = bucket->data;
|
||||
char sid_str[BUFSIZ];
|
||||
|
||||
vty_out(vty, "attr[%ld] nexthop %s\n", attr->refcnt,
|
||||
inet_ntoa(attr->nexthop));
|
||||
vty_out(vty, "\tflags: %" PRIu64 " med: %u local_pref: %u origin: %u weight: %u label: %u\n",
|
||||
|
||||
sid_str[0] = '\0';
|
||||
if (attr->srv6_l3vpn)
|
||||
inet_ntop(AF_INET6, &attr->srv6_l3vpn->sid, sid_str, BUFSIZ);
|
||||
else if (attr->srv6_vpn)
|
||||
inet_ntop(AF_INET6, &attr->srv6_vpn->sid, sid_str, BUFSIZ);
|
||||
|
||||
vty_out(vty,
|
||||
"\tflags: %" PRIu64
|
||||
" med: %u local_pref: %u origin: %u weight: %u label: %u sid: %s\n",
|
||||
attr->flag, attr->med, attr->local_pref, attr->origin,
|
||||
attr->weight, attr->label);
|
||||
attr->weight, attr->label, sid_str);
|
||||
}
|
||||
|
||||
void attr_show_all(struct vty *vty)
|
||||
@ -618,6 +785,11 @@ static void *bgp_attr_hash_alloc(void *p)
|
||||
val->vnc_subtlvs = NULL;
|
||||
}
|
||||
#endif
|
||||
if (val->srv6_l3vpn)
|
||||
val->srv6_l3vpn = NULL;
|
||||
if (val->srv6_vpn)
|
||||
val->srv6_vpn = NULL;
|
||||
|
||||
attr->refcnt = 0;
|
||||
return attr;
|
||||
}
|
||||
@ -672,6 +844,18 @@ struct attr *bgp_attr_intern(struct attr *attr)
|
||||
else
|
||||
attr->encap_subtlvs->refcnt++;
|
||||
}
|
||||
if (attr->srv6_l3vpn) {
|
||||
if (!attr->srv6_l3vpn->refcnt)
|
||||
attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
|
||||
else
|
||||
attr->srv6_l3vpn->refcnt++;
|
||||
}
|
||||
if (attr->srv6_vpn) {
|
||||
if (!attr->srv6_vpn->refcnt)
|
||||
attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn);
|
||||
else
|
||||
attr->srv6_vpn->refcnt++;
|
||||
}
|
||||
#if ENABLE_BGP_VNC
|
||||
if (attr->vnc_subtlvs) {
|
||||
if (!attr->vnc_subtlvs->refcnt)
|
||||
@ -862,6 +1046,12 @@ void bgp_attr_unintern_sub(struct attr *attr)
|
||||
if (attr->vnc_subtlvs)
|
||||
encap_unintern(&attr->vnc_subtlvs, VNC_SUBTLV_TYPE);
|
||||
#endif
|
||||
|
||||
if (attr->srv6_l3vpn)
|
||||
srv6_l3vpn_unintern(&attr->srv6_l3vpn);
|
||||
|
||||
if (attr->srv6_vpn)
|
||||
srv6_vpn_unintern(&attr->srv6_vpn);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2147,6 +2337,9 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
|
||||
uint32_t srgb_base;
|
||||
uint32_t srgb_range;
|
||||
int srgb_count;
|
||||
uint8_t sid_type, sid_flags;
|
||||
uint16_t endpoint_behavior;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
if (type == BGP_PREFIX_SID_LABEL_INDEX) {
|
||||
if (STREAM_READABLE(peer->curr) < length
|
||||
@ -2268,13 +2461,81 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Placeholder code for Unsupported TLV
|
||||
* - SRv6 L3 Service TLV (type5)
|
||||
* - SRv6 L2 Service TLV (type6)
|
||||
*/
|
||||
else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE
|
||||
|| type == BGP_PREFIX_SID_SRV6_L2_SERVICE) {
|
||||
/* Placeholder code for the VPN-SID Service type */
|
||||
else if (type == BGP_PREFIX_SID_VPN_SID) {
|
||||
if (STREAM_READABLE(peer->curr) < length
|
||||
|| length != BGP_PREFIX_SID_VPN_SID_LENGTH) {
|
||||
flog_err(EC_BGP_ATTR_LEN,
|
||||
"Prefix SID VPN SID length is %" PRIu16
|
||||
" instead of %u",
|
||||
length, BGP_PREFIX_SID_VPN_SID_LENGTH);
|
||||
return bgp_attr_malformed(args,
|
||||
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
|
||||
args->total);
|
||||
}
|
||||
|
||||
/* Parse VPN-SID Sub-TLV */
|
||||
stream_getc(peer->curr); /* reserved */
|
||||
sid_type = stream_getc(peer->curr); /* sid_type */
|
||||
sid_flags = stream_getc(peer->curr); /* sid_flags */
|
||||
stream_get(&ipv6_sid, peer->curr,
|
||||
sizeof(ipv6_sid)); /* sid_value */
|
||||
|
||||
/* Log VPN-SID Sub-TLV */
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
|
||||
inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
|
||||
zlog_debug(
|
||||
"%s: vpn-sid: sid %s, sid-type 0x%02x sid-flags 0x%02x",
|
||||
__func__, buf, sid_type, sid_flags);
|
||||
}
|
||||
|
||||
/* Configure from Info */
|
||||
attr->srv6_vpn = XMALLOC(MTYPE_BGP_SRV6_VPN,
|
||||
sizeof(struct bgp_attr_srv6_vpn));
|
||||
attr->srv6_vpn->refcnt = 0;
|
||||
attr->srv6_vpn->sid_flags = sid_flags;
|
||||
sid_copy(&attr->srv6_vpn->sid, &ipv6_sid);
|
||||
}
|
||||
|
||||
/* Placeholder code for the SRv6 L3 Service type */
|
||||
else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) {
|
||||
if (STREAM_READABLE(peer->curr) < length
|
||||
|| length != BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH) {
|
||||
flog_err(EC_BGP_ATTR_LEN,
|
||||
"Prefix SID SRv6 L3-Service length is %" PRIu16
|
||||
" instead of %u",
|
||||
length, BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH);
|
||||
return bgp_attr_malformed(args,
|
||||
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
|
||||
args->total);
|
||||
}
|
||||
|
||||
/* Parse L3-SERVICE Sub-TLV */
|
||||
stream_getc(peer->curr); /* reserved */
|
||||
stream_get(&ipv6_sid, peer->curr,
|
||||
sizeof(ipv6_sid)); /* sid_value */
|
||||
sid_flags = stream_getc(peer->curr); /* sid_flags */
|
||||
endpoint_behavior = stream_getw(peer->curr); /* endpoint */
|
||||
stream_getc(peer->curr); /* reserved */
|
||||
|
||||
/* Log L3-SERVICE Sub-TLV */
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
|
||||
inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
|
||||
zlog_debug(
|
||||
"%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
|
||||
__func__, buf, sid_flags, endpoint_behavior);
|
||||
}
|
||||
|
||||
/* Configure from Info */
|
||||
attr->srv6_l3vpn = XMALLOC(MTYPE_BGP_SRV6_L3VPN,
|
||||
sizeof(struct bgp_attr_srv6_l3vpn));
|
||||
attr->srv6_l3vpn->sid_flags = sid_flags;
|
||||
attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
|
||||
sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
|
||||
}
|
||||
|
||||
/* Placeholder code for Unsupported TLV */
|
||||
else {
|
||||
|
||||
if (STREAM_READABLE(peer->curr) < length) {
|
||||
flog_err(
|
||||
@ -2966,9 +3227,8 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
|
||||
|
||||
/* Nexthop AFI */
|
||||
if (afi == AFI_IP
|
||||
&& (safi == SAFI_UNICAST ||
|
||||
safi == SAFI_LABELED_UNICAST ||
|
||||
safi == SAFI_MULTICAST))
|
||||
&& (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST
|
||||
|| safi == SAFI_MPLS_VPN || safi == SAFI_MULTICAST))
|
||||
nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP;
|
||||
else
|
||||
nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
|
||||
@ -3610,6 +3870,36 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
}
|
||||
}
|
||||
|
||||
/* SRv6 Service Information Attribute. */
|
||||
if (afi == AFI_IP && safi == SAFI_MPLS_VPN) {
|
||||
if (attr->srv6_l3vpn) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_PREFIX_SID);
|
||||
stream_putc(s, 24); /* tlv len */
|
||||
stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE);
|
||||
stream_putw(s, 21); /* sub-tlv len */
|
||||
stream_putc(s, 0); /* reserved */
|
||||
stream_put(s, &attr->srv6_l3vpn->sid,
|
||||
sizeof(attr->srv6_l3vpn->sid)); /* sid */
|
||||
stream_putc(s, 0); /* sid_flags */
|
||||
stream_putw(s, 0xffff); /* endpoint */
|
||||
stream_putc(s, 0); /* reserved */
|
||||
} else if (attr->srv6_vpn) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_PREFIX_SID);
|
||||
stream_putc(s, 22); /* tlv len */
|
||||
stream_putc(s, BGP_PREFIX_SID_VPN_SID);
|
||||
stream_putw(s, 0x13); /* tlv len */
|
||||
stream_putc(s, 0x00); /* reserved */
|
||||
stream_putc(s, 0x01); /* sid_type */
|
||||
stream_putc(s, 0x00); /* sif_flags */
|
||||
stream_put(s, &attr->srv6_vpn->sid,
|
||||
sizeof(attr->srv6_vpn->sid)); /* sid */
|
||||
}
|
||||
}
|
||||
|
||||
if (send_as4_path) {
|
||||
/* If the peer is NOT As4 capable, AND */
|
||||
/* there are ASnums > 65535 in path THEN
|
||||
@ -3738,6 +4028,7 @@ void bgp_attr_init(void)
|
||||
cluster_init();
|
||||
transit_init();
|
||||
encap_init();
|
||||
srv6_init();
|
||||
}
|
||||
|
||||
void bgp_attr_finish(void)
|
||||
@ -3750,6 +4041,7 @@ void bgp_attr_finish(void)
|
||||
cluster_finish();
|
||||
transit_finish();
|
||||
encap_finish();
|
||||
srv6_finish();
|
||||
}
|
||||
|
||||
/* Make attribute packet. */
|
||||
|
@ -62,12 +62,15 @@
|
||||
#define BGP_PREFIX_SID_LABEL_INDEX 1
|
||||
#define BGP_PREFIX_SID_IPV6 2
|
||||
#define BGP_PREFIX_SID_ORIGINATOR_SRGB 3
|
||||
#define BGP_PREFIX_SID_VPN_SID 4
|
||||
#define BGP_PREFIX_SID_SRV6_L3_SERVICE 5
|
||||
#define BGP_PREFIX_SID_SRV6_L2_SERVICE 6
|
||||
|
||||
#define BGP_PREFIX_SID_LABEL_INDEX_LENGTH 7
|
||||
#define BGP_PREFIX_SID_IPV6_LENGTH 19
|
||||
#define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6
|
||||
#define BGP_PREFIX_SID_VPN_SID_LENGTH 19
|
||||
#define BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH 21
|
||||
|
||||
#define BGP_ATTR_NH_AFI(afi, attr) \
|
||||
((afi != AFI_L2VPN) ? afi : \
|
||||
@ -111,6 +114,29 @@ enum pta_type {
|
||||
PMSI_TNLTYPE_MAX = PMSI_TNLTYPE_MLDP_MP2MP
|
||||
};
|
||||
|
||||
/*
|
||||
* Prefix-SID type-4
|
||||
* SRv6-VPN-SID-TLV
|
||||
* draft-dawra-idr-srv6-vpn-04
|
||||
*/
|
||||
struct bgp_attr_srv6_vpn {
|
||||
unsigned long refcnt;
|
||||
uint8_t sid_flags;
|
||||
struct in6_addr sid;
|
||||
};
|
||||
|
||||
/*
|
||||
* Prefix-SID type-5
|
||||
* SRv6-L3VPN-Service-TLV
|
||||
* draft-dawra-idr-srv6-vpn-05
|
||||
*/
|
||||
struct bgp_attr_srv6_l3vpn {
|
||||
unsigned long refcnt;
|
||||
uint8_t sid_flags;
|
||||
uint16_t endpoint_behavior;
|
||||
struct in6_addr sid;
|
||||
};
|
||||
|
||||
/* BGP core attribute structure. */
|
||||
struct attr {
|
||||
/* AS Path structure */
|
||||
@ -198,6 +224,12 @@ struct attr {
|
||||
/* MPLS label */
|
||||
mpls_label_t label;
|
||||
|
||||
/* SRv6 VPN SID */
|
||||
struct bgp_attr_srv6_vpn *srv6_vpn;
|
||||
|
||||
/* SRv6 L3VPN SID */
|
||||
struct bgp_attr_srv6_l3vpn *srv6_l3vpn;
|
||||
|
||||
uint16_t encap_tunneltype; /* grr */
|
||||
struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
|
||||
|
||||
|
@ -128,3 +128,6 @@ DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str")
|
||||
DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled")
|
||||
DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name")
|
||||
DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index")
|
||||
|
||||
DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie")
|
||||
DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service")
|
||||
|
@ -126,4 +126,7 @@ DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED)
|
||||
DECLARE_MTYPE(BGP_FLOWSPEC_NAME)
|
||||
DECLARE_MTYPE(BGP_FLOWSPEC_INDEX)
|
||||
|
||||
DECLARE_MTYPE(BGP_SRV6_L3VPN)
|
||||
DECLARE_MTYPE(BGP_SRV6_VPN)
|
||||
|
||||
#endif /* _QUAGGA_BGP_MEMORY_H */
|
||||
|
@ -658,7 +658,7 @@ static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr)
|
||||
nh_afi = afi_iana2int(pkt_nh_afi);
|
||||
|
||||
if (afi != AFI_IP || nh_afi != AFI_IP6
|
||||
|| !(safi == SAFI_UNICAST
|
||||
|| !(safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN
|
||||
|| safi == SAFI_LABELED_UNICAST)) {
|
||||
flog_warn(
|
||||
EC_BGP_CAPABILITY_INVALID_DATA,
|
||||
@ -1435,7 +1435,7 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
|
||||
if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)
|
||||
&& peer->su.sa.sa_family == AF_INET6
|
||||
&& afi == AFI_IP
|
||||
&& (safi == SAFI_UNICAST
|
||||
&& (safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN
|
||||
|| safi == SAFI_LABELED_UNICAST)) {
|
||||
/* RFC 5549 Extended Next Hop Encoding
|
||||
*/
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "workqueue.h"
|
||||
#include "queue.h"
|
||||
#include "memory.h"
|
||||
#include "srv6.h"
|
||||
#include "lib/json.h"
|
||||
#include "lib_errors.h"
|
||||
#include "zclient.h"
|
||||
@ -3645,6 +3646,22 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
|
||||
bgp_set_valid_label(&extra->label[0]);
|
||||
}
|
||||
|
||||
/* Update SRv6 SID */
|
||||
if (attr->srv6_l3vpn) {
|
||||
extra = bgp_path_info_extra_get(pi);
|
||||
if (sid_diff(&extra->sid[0], &attr->srv6_l3vpn->sid)) {
|
||||
sid_copy(&extra->sid[0],
|
||||
&attr->srv6_l3vpn->sid);
|
||||
extra->num_sids = 1;
|
||||
}
|
||||
} else if (attr->srv6_vpn) {
|
||||
extra = bgp_path_info_extra_get(pi);
|
||||
if (sid_diff(&extra->sid[0], &attr->srv6_vpn->sid)) {
|
||||
sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
|
||||
extra->num_sids = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
if ((afi == AFI_IP || afi == AFI_IP6)
|
||||
&& (safi == SAFI_UNICAST)) {
|
||||
@ -3824,6 +3841,18 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
|
||||
bgp_set_valid_label(&extra->label[0]);
|
||||
}
|
||||
|
||||
/* Update SRv6 SID */
|
||||
if (safi == SAFI_MPLS_VPN) {
|
||||
extra = bgp_path_info_extra_get(new);
|
||||
if (attr->srv6_l3vpn) {
|
||||
sid_copy(&extra->sid[0], &attr->srv6_l3vpn->sid);
|
||||
extra->num_sids = 1;
|
||||
} else if (attr->srv6_vpn) {
|
||||
sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
|
||||
extra->num_sids = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update Overlay Index */
|
||||
if (afi == AFI_L2VPN) {
|
||||
overlay_index_update(new->attr,
|
||||
@ -9208,6 +9237,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
|
||||
vty_out(vty, " Remote label: %d\n", label);
|
||||
}
|
||||
|
||||
/* Remote SID */
|
||||
if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) {
|
||||
inet_ntop(AF_INET6, &path->extra->sid, buf, sizeof(buf));
|
||||
if (json_paths)
|
||||
json_object_string_add(json_path, "remoteSid", buf);
|
||||
else
|
||||
vty_out(vty, " Remote SID: %s\n", buf);
|
||||
}
|
||||
|
||||
/* Label Index */
|
||||
if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
|
||||
if (json_paths)
|
||||
|
@ -78,6 +78,9 @@ enum bgp_show_adj_route_type {
|
||||
*/
|
||||
#define BGP_MAX_LABELS 2
|
||||
|
||||
/* Maximum number of sids we can process or send with a prefix. */
|
||||
#define BGP_MAX_SIDS 6
|
||||
|
||||
/* Error codes for handling NLRI */
|
||||
#define BGP_NLRI_PARSE_OK 0
|
||||
#define BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW -1
|
||||
@ -118,6 +121,10 @@ struct bgp_path_info_extra {
|
||||
uint16_t af_flags;
|
||||
#define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0)
|
||||
|
||||
/* SRv6 SID(s) for SRv6-VPN */
|
||||
struct in6_addr sid[BGP_MAX_SIDS];
|
||||
uint32_t num_sids;
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
union {
|
||||
|
||||
|
@ -431,6 +431,14 @@ void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p,
|
||||
else
|
||||
vty_out(vty, " label=%u",
|
||||
decode_label(&bpi->extra->label[0]));
|
||||
|
||||
if (bpi->extra->num_sids) {
|
||||
char buf[BUFSIZ];
|
||||
|
||||
vty_out(vty, " sid=%s",
|
||||
inet_ntop(AF_INET6, &bpi->extra->sid[0], buf,
|
||||
sizeof(buf)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!rfapiGetVncLifetime(bpi->attr, &lifetime)) {
|
||||
|
55
include/linux/seg6.h
Normal file
55
include/linux/seg6.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* SR-IPv6 implementation
|
||||
*
|
||||
* Author:
|
||||
* David Lebrun <david.lebrun@uclouvain.be>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SEG6_H
|
||||
#define _LINUX_SEG6_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/in6.h> /* For struct in6_addr. */
|
||||
|
||||
/*
|
||||
* SRH
|
||||
*/
|
||||
struct ipv6_sr_hdr {
|
||||
__u8 nexthdr;
|
||||
__u8 hdrlen;
|
||||
__u8 type;
|
||||
__u8 segments_left;
|
||||
__u8 first_segment; /* Represents the last_entry field of SRH */
|
||||
__u8 flags;
|
||||
__u16 tag;
|
||||
|
||||
struct in6_addr segments[0];
|
||||
};
|
||||
|
||||
#define SR6_FLAG1_PROTECTED (1 << 6)
|
||||
#define SR6_FLAG1_OAM (1 << 5)
|
||||
#define SR6_FLAG1_ALERT (1 << 4)
|
||||
#define SR6_FLAG1_HMAC (1 << 3)
|
||||
|
||||
#define SR6_TLV_INGRESS 1
|
||||
#define SR6_TLV_EGRESS 2
|
||||
#define SR6_TLV_OPAQUE 3
|
||||
#define SR6_TLV_PADDING 4
|
||||
#define SR6_TLV_HMAC 5
|
||||
|
||||
#define sr_has_hmac(srh) ((srh)->flags & SR6_FLAG1_HMAC)
|
||||
|
||||
struct sr6_tlv {
|
||||
__u8 type;
|
||||
__u8 len;
|
||||
__u8 data[0];
|
||||
};
|
||||
|
||||
#endif
|
33
include/linux/seg6_genl.h
Normal file
33
include/linux/seg6_genl.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef _LINUX_SEG6_GENL_H
|
||||
#define _LINUX_SEG6_GENL_H
|
||||
|
||||
#define SEG6_GENL_NAME "SEG6"
|
||||
#define SEG6_GENL_VERSION 0x1
|
||||
|
||||
enum {
|
||||
SEG6_ATTR_UNSPEC,
|
||||
SEG6_ATTR_DST,
|
||||
SEG6_ATTR_DSTLEN,
|
||||
SEG6_ATTR_HMACKEYID,
|
||||
SEG6_ATTR_SECRET,
|
||||
SEG6_ATTR_SECRETLEN,
|
||||
SEG6_ATTR_ALGID,
|
||||
SEG6_ATTR_HMACINFO,
|
||||
__SEG6_ATTR_MAX,
|
||||
};
|
||||
|
||||
#define SEG6_ATTR_MAX (__SEG6_ATTR_MAX - 1)
|
||||
|
||||
enum {
|
||||
SEG6_CMD_UNSPEC,
|
||||
SEG6_CMD_SETHMAC,
|
||||
SEG6_CMD_DUMPHMAC,
|
||||
SEG6_CMD_SET_TUNSRC,
|
||||
SEG6_CMD_GET_TUNSRC,
|
||||
__SEG6_CMD_MAX,
|
||||
};
|
||||
|
||||
#define SEG6_CMD_MAX (__SEG6_CMD_MAX - 1)
|
||||
|
||||
#endif
|
23
include/linux/seg6_hmac.h
Normal file
23
include/linux/seg6_hmac.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef _LINUX_SEG6_HMAC_H
|
||||
#define _LINUX_SEG6_HMAC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/seg6.h>
|
||||
|
||||
#define SEG6_HMAC_SECRET_LEN 64
|
||||
#define SEG6_HMAC_FIELD_LEN 32
|
||||
|
||||
struct sr6_tlv_hmac {
|
||||
struct sr6_tlv tlvhdr;
|
||||
__u16 reserved;
|
||||
__be32 hmackeyid;
|
||||
__u8 hmac[SEG6_HMAC_FIELD_LEN];
|
||||
};
|
||||
|
||||
enum {
|
||||
SEG6_HMAC_ALGO_SHA1 = 1,
|
||||
SEG6_HMAC_ALGO_SHA256 = 2,
|
||||
};
|
||||
|
||||
#endif
|
41
include/linux/seg6_iptunnel.h
Normal file
41
include/linux/seg6_iptunnel.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* SR-IPv6 implementation
|
||||
*
|
||||
* Author:
|
||||
* David Lebrun <david.lebrun@uclouvain.be>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SEG6_IPTUNNEL_H
|
||||
#define _LINUX_SEG6_IPTUNNEL_H
|
||||
|
||||
#include <linux/seg6.h> /* For struct ipv6_sr_hdr. */
|
||||
|
||||
enum {
|
||||
SEG6_IPTUNNEL_UNSPEC,
|
||||
SEG6_IPTUNNEL_SRH,
|
||||
__SEG6_IPTUNNEL_MAX,
|
||||
};
|
||||
#define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1)
|
||||
|
||||
struct seg6_iptunnel_encap {
|
||||
int mode;
|
||||
struct ipv6_sr_hdr srh[0];
|
||||
};
|
||||
|
||||
#define SEG6_IPTUN_ENCAP_SIZE(x) ((sizeof(*x)) + (((x)->srh->hdrlen + 1) << 3))
|
||||
|
||||
enum {
|
||||
SEG6_IPTUN_MODE_INLINE,
|
||||
SEG6_IPTUN_MODE_ENCAP,
|
||||
SEG6_IPTUN_MODE_L2ENCAP,
|
||||
};
|
||||
|
||||
|
||||
#endif
|
80
include/linux/seg6_local.h
Normal file
80
include/linux/seg6_local.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* SR-IPv6 implementation
|
||||
*
|
||||
* Author:
|
||||
* David Lebrun <david.lebrun@uclouvain.be>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SEG6_LOCAL_H
|
||||
#define _LINUX_SEG6_LOCAL_H
|
||||
|
||||
#include <linux/seg6.h>
|
||||
|
||||
enum {
|
||||
SEG6_LOCAL_UNSPEC,
|
||||
SEG6_LOCAL_ACTION,
|
||||
SEG6_LOCAL_SRH,
|
||||
SEG6_LOCAL_TABLE,
|
||||
SEG6_LOCAL_NH4,
|
||||
SEG6_LOCAL_NH6,
|
||||
SEG6_LOCAL_IIF,
|
||||
SEG6_LOCAL_OIF,
|
||||
SEG6_LOCAL_BPF,
|
||||
__SEG6_LOCAL_MAX,
|
||||
};
|
||||
#define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
|
||||
|
||||
enum {
|
||||
SEG6_LOCAL_ACTION_UNSPEC = 0,
|
||||
/* node segment */
|
||||
SEG6_LOCAL_ACTION_END = 1,
|
||||
/* adjacency segment (IPv6 cross-connect) */
|
||||
SEG6_LOCAL_ACTION_END_X = 2,
|
||||
/* lookup of next seg NH in table */
|
||||
SEG6_LOCAL_ACTION_END_T = 3,
|
||||
/* decap and L2 cross-connect */
|
||||
SEG6_LOCAL_ACTION_END_DX2 = 4,
|
||||
/* decap and IPv6 cross-connect */
|
||||
SEG6_LOCAL_ACTION_END_DX6 = 5,
|
||||
/* decap and IPv4 cross-connect */
|
||||
SEG6_LOCAL_ACTION_END_DX4 = 6,
|
||||
/* decap and lookup of DA in v6 table */
|
||||
SEG6_LOCAL_ACTION_END_DT6 = 7,
|
||||
/* decap and lookup of DA in v4 table */
|
||||
SEG6_LOCAL_ACTION_END_DT4 = 8,
|
||||
/* binding segment with insertion */
|
||||
SEG6_LOCAL_ACTION_END_B6 = 9,
|
||||
/* binding segment with encapsulation */
|
||||
SEG6_LOCAL_ACTION_END_B6_ENCAP = 10,
|
||||
/* binding segment with MPLS encap */
|
||||
SEG6_LOCAL_ACTION_END_BM = 11,
|
||||
/* lookup last seg in table */
|
||||
SEG6_LOCAL_ACTION_END_S = 12,
|
||||
/* forward to SR-unaware VNF with static proxy */
|
||||
SEG6_LOCAL_ACTION_END_AS = 13,
|
||||
/* forward to SR-unaware VNF with masquerading */
|
||||
SEG6_LOCAL_ACTION_END_AM = 14,
|
||||
/* custom BPF action */
|
||||
SEG6_LOCAL_ACTION_END_BPF = 15,
|
||||
|
||||
__SEG6_LOCAL_ACTION_MAX,
|
||||
};
|
||||
|
||||
#define SEG6_LOCAL_ACTION_MAX (__SEG6_LOCAL_ACTION_MAX - 1)
|
||||
|
||||
enum {
|
||||
SEG6_LOCAL_BPF_PROG_UNSPEC,
|
||||
SEG6_LOCAL_BPF_PROG,
|
||||
SEG6_LOCAL_BPF_PROG_NAME,
|
||||
__SEG6_LOCAL_BPF_PROG_MAX,
|
||||
};
|
||||
|
||||
#define SEG6_LOCAL_BPF_PROG_MAX (__SEG6_LOCAL_BPF_PROG_MAX - 1)
|
||||
|
||||
#endif
|
@ -11,4 +11,9 @@ noinst_HEADERS += \
|
||||
include/linux/socket.h \
|
||||
include/linux/net_namespace.h \
|
||||
include/linux/fib_rules.h \
|
||||
include/linux/seg6.h \
|
||||
include/linux/seg6_genl.h \
|
||||
include/linux/seg6_hmac.h \
|
||||
include/linux/seg6_iptunnel.h \
|
||||
include/linux/seg6_local.h \
|
||||
# end
|
||||
|
116
lib/srv6.c
Normal file
116
lib/srv6.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* SRv6 definitions
|
||||
* Copyright (C) 2020 Hiroki Shirokura, LINE Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "srv6.h"
|
||||
#include "log.h"
|
||||
|
||||
const char *seg6local_action2str(uint32_t action)
|
||||
{
|
||||
switch (action) {
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END:
|
||||
return "End";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_X:
|
||||
return "End.X";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_T:
|
||||
return "End.T";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
|
||||
return "End.DX2";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
|
||||
return "End.DX6";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
|
||||
return "End.DX4";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
|
||||
return "End.DT6";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
|
||||
return "End.DT4";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
|
||||
return "End.B6";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
|
||||
return "End.B6.Encap";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
|
||||
return "End.BM";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_S:
|
||||
return "End.S";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
|
||||
return "End.AS";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
|
||||
return "End.AM";
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
|
||||
return "unspec";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
int snprintf_seg6_segs(char *str,
|
||||
size_t size, const struct seg6_segs *segs)
|
||||
{
|
||||
str[0] = '\0';
|
||||
for (size_t i = 0; i < segs->num_segs; i++) {
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
bool not_last = (i + 1) < segs->num_segs;
|
||||
|
||||
inet_ntop(AF_INET6, &segs->segs[i], addr, sizeof(addr));
|
||||
strlcat(str, addr, size);
|
||||
strlcat(str, not_last ? "," : "", size);
|
||||
}
|
||||
return strlen(str);
|
||||
}
|
||||
|
||||
const char *seg6local_context2str(char *str, size_t size,
|
||||
struct seg6local_context *ctx, uint32_t action)
|
||||
{
|
||||
char b0[128];
|
||||
|
||||
switch (action) {
|
||||
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END:
|
||||
snprintf(str, size, "USP");
|
||||
return str;
|
||||
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_X:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
|
||||
inet_ntop(AF_INET6, &ctx->nh6, b0, 128);
|
||||
snprintf(str, size, "nh6 %s", b0);
|
||||
return str;
|
||||
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
|
||||
inet_ntop(AF_INET, &ctx->nh4, b0, 128);
|
||||
snprintf(str, size, "nh4 %s", b0);
|
||||
return str;
|
||||
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_T:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
|
||||
snprintf(str, size, "table %u", ctx->table);
|
||||
return str;
|
||||
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_S:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
|
||||
case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
|
||||
default:
|
||||
snprintf(str, size, "unknown(%s)", __func__);
|
||||
return str;
|
||||
}
|
||||
}
|
133
lib/srv6.h
Normal file
133
lib/srv6.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* SRv6 definitions
|
||||
* Copyright (C) 2020 Hiroki Shirokura, LINE Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_SRV6_H
|
||||
#define _FRR_SRV6_H
|
||||
|
||||
#include <zebra.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define SRV6_MAX_SIDS 16
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define sid2str(sid, str, size) \
|
||||
inet_ntop(AF_INET6, sid, str, size)
|
||||
|
||||
enum seg6_mode_t {
|
||||
INLINE,
|
||||
ENCAP,
|
||||
L2ENCAP,
|
||||
};
|
||||
|
||||
enum seg6local_action_t {
|
||||
ZEBRA_SEG6_LOCAL_ACTION_UNSPEC = 0,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END = 1,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_X = 2,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_T = 3,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_DX2 = 4,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_DX6 = 5,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_DX4 = 6,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_DT6 = 7,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_DT4 = 8,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_B6 = 9,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP = 10,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_BM = 11,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_S = 12,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_AS = 13,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_AM = 14,
|
||||
ZEBRA_SEG6_LOCAL_ACTION_END_BPF = 15,
|
||||
};
|
||||
|
||||
struct seg6_segs {
|
||||
size_t num_segs;
|
||||
struct in6_addr segs[256];
|
||||
};
|
||||
|
||||
struct seg6local_context {
|
||||
struct in_addr nh4;
|
||||
struct in6_addr nh6;
|
||||
uint32_t table;
|
||||
};
|
||||
|
||||
static inline const char *seg6_mode2str(enum seg6_mode_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case INLINE:
|
||||
return "INLINE";
|
||||
case ENCAP:
|
||||
return "ENCAP";
|
||||
case L2ENCAP:
|
||||
return "L2ENCAP";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sid_same(
|
||||
const struct in6_addr *a,
|
||||
const struct in6_addr *b)
|
||||
{
|
||||
if (!a && !b)
|
||||
return true;
|
||||
else if (!(a && b))
|
||||
return false;
|
||||
else
|
||||
return memcmp(a, b, sizeof(struct in6_addr)) == 0;
|
||||
}
|
||||
|
||||
static inline bool sid_diff(
|
||||
const struct in6_addr *a,
|
||||
const struct in6_addr *b)
|
||||
{
|
||||
return !sid_same(a, b);
|
||||
}
|
||||
|
||||
static inline bool sid_zero(
|
||||
const struct in6_addr *a)
|
||||
{
|
||||
struct in6_addr zero = {};
|
||||
|
||||
return sid_same(a, &zero);
|
||||
}
|
||||
|
||||
static inline void *sid_copy(struct in6_addr *dst,
|
||||
const struct in6_addr *src)
|
||||
{
|
||||
return memcpy(dst, src, sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
const char *
|
||||
seg6local_action2str(uint32_t action);
|
||||
|
||||
const char *
|
||||
seg6local_context2str(char *str, size_t size,
|
||||
struct seg6local_context *ctx, uint32_t action);
|
||||
|
||||
int snprintf_seg6_segs(char *str,
|
||||
size_t size, const struct seg6_segs *segs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -51,6 +51,7 @@ lib_libfrr_la_SOURCES = \
|
||||
lib/mlag.c \
|
||||
lib/module.c \
|
||||
lib/mpls.c \
|
||||
lib/srv6.c \
|
||||
lib/network.c \
|
||||
lib/nexthop.c \
|
||||
lib/netns_linux.c \
|
||||
@ -193,6 +194,7 @@ pkginclude_HEADERS += \
|
||||
lib/module.h \
|
||||
lib/monotime.h \
|
||||
lib/mpls.h \
|
||||
lib/srv6.h \
|
||||
lib/network.h \
|
||||
lib/nexthop.h \
|
||||
lib/nexthop_group.h \
|
||||
|
Loading…
Reference in New Issue
Block a user