bgpd: prefix-sid srv6 l3vpn service tlv

bgpd already supports BGP Prefix-SID path attribute and
there are some sub-types of Prefix-SID path attribute.
This commits makes bgpd to support additional sub-types.
sub-Type-4 and sub-Type-5 for construct the VPNv4 SRv6 backend
with vpnv4-unicast address family.
This path attributes is already supported by Ciscos IOS-XR and NX-OS.

Prefix-SID sub-Type-4 and sub-Type-5 is defined on following
IETF-drafts.

Supports(A-part-of):
- https://tools.ietf.org/html/draft-dawra-idr-srv6-vpn-04
- https://tools.ietf.org/html/draft-dawra-idr-srv6-vpn-05

Signed-off-by: Hiroki Shirokura <slank.dev@gmail.com>
This commit is contained in:
Hiroki Shirokura 2020-01-09 12:00:43 +09:00
parent 770df5fd80
commit e496b42030
10 changed files with 647 additions and 13 deletions

View file

@ -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. */

View file

@ -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 */

View file

@ -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")

View file

@ -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 */

View file

@ -38,6 +38,7 @@
#include "workqueue.h"
#include "queue.h"
#include "memory.h"
#include "srv6.h"
#include "lib/json.h"
#include "lib_errors.h"
@ -3431,6 +3432,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)) {
@ -3610,6 +3627,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,
@ -8994,6 +9023,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)

View file

@ -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 {

View file

@ -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)) {

116
lib/srv6.c Normal file
View 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
View 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

View file

@ -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 \