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:
Donald Sharp 2020-02-04 11:37:10 -05:00 committed by GitHub
commit 7f1ace03c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 886 additions and 15 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

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

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

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

55
include/linux/seg6.h Normal file
View 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
View 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
View 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

View 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

View 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

View File

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