1
0
Fork 0

Merging upstream version 10.2.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-05 10:17:20 +01:00
parent c459d76acf
commit a2d156806a
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
1226 changed files with 49733 additions and 17448 deletions

View file

@ -55,7 +55,7 @@ BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false BreakStringLiterals: false
ColumnLimit: 80 ColumnLimit: 100
# Linux: CommentPragmas: '^ IWYU pragma:' # Linux: CommentPragmas: '^ IWYU pragma:'
CommentPragmas: '\$(FRR|clippy)' CommentPragmas: '\$(FRR|clippy)'
CompactNamespaces: false CompactNamespaces: false
@ -224,4 +224,8 @@ WhitespaceSensitiveMacros:
- "DEFUN_YANG_NOSH" - "DEFUN_YANG_NOSH"
- "DEFUNSH" - "DEFUNSH"
- "DEFUNSH_HIDDEN" - "DEFUNSH_HIDDEN"
- "ALIAS"
- "ALIAS_HIDDEN"
- "ALIAS_YANG"
- "ALIAS_DEPRECATED"
... ...

View file

@ -33,6 +33,8 @@ _libdir=/usr/lib
_user=frr _user=frr
build() { build() {
export ABUILD_APK_INDEX_OPTS="--allow-untrusted"
cd "$builddir" cd "$builddir"
./configure \ ./configure \

View file

@ -108,6 +108,7 @@ babel_interface_address_add (ZAPI_CALLBACK_ARGS)
if (prefix->family == AF_INET) { if (prefix->family == AF_INET) {
flush_interface_routes(ifc->ifp, 0); flush_interface_routes(ifc->ifp, 0);
babel_ifp = babel_get_if_nfo(ifc->ifp); babel_ifp = babel_get_if_nfo(ifc->ifp);
assert (babel_ifp != NULL);
if (babel_ifp->ipv4 == NULL) { if (babel_ifp->ipv4 == NULL) {
babel_ifp->ipv4 = malloc(4); babel_ifp->ipv4 = malloc(4);
if (babel_ifp->ipv4 == NULL) { if (babel_ifp->ipv4 == NULL) {
@ -144,6 +145,7 @@ babel_interface_address_delete (ZAPI_CALLBACK_ARGS)
if (prefix->family == AF_INET) { if (prefix->family == AF_INET) {
flush_interface_routes(ifc->ifp, 0); flush_interface_routes(ifc->ifp, 0);
babel_ifp = babel_get_if_nfo(ifc->ifp); babel_ifp = babel_get_if_nfo(ifc->ifp);
assert (babel_ifp != NULL);
if (babel_ifp->ipv4 != NULL if (babel_ifp->ipv4 != NULL
&& memcmp(babel_ifp->ipv4, &prefix->u.prefix4, IPV4_MAX_BYTELEN) && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, IPV4_MAX_BYTELEN)
== 0) { == 0) {
@ -542,7 +544,10 @@ DEFPY (babel_set_channel,
unsigned unsigned
jitter(babel_interface_nfo *babel_ifp, int urgent) jitter(babel_interface_nfo *babel_ifp, int urgent)
{ {
unsigned interval = babel_ifp->hello_interval; unsigned interval;
assert (babel_ifp != NULL);
interval = babel_ifp->hello_interval;
if(urgent) if(urgent)
interval = MIN(interval, 100); interval = MIN(interval, 100);
else else
@ -553,7 +558,10 @@ jitter(babel_interface_nfo *babel_ifp, int urgent)
unsigned unsigned
update_jitter(babel_interface_nfo *babel_ifp, int urgent) update_jitter(babel_interface_nfo *babel_ifp, int urgent)
{ {
unsigned interval = babel_ifp->hello_interval; unsigned interval;
assert (babel_ifp != NULL);
interval = babel_ifp->hello_interval;
if(urgent) if(urgent)
interval = MIN(interval, 100); interval = MIN(interval, 100);
else else
@ -566,10 +574,11 @@ update_jitter(babel_interface_nfo *babel_ifp, int urgent)
static int static int
interface_recalculate(struct interface *ifp) interface_recalculate(struct interface *ifp)
{ {
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
unsigned char *tmp = NULL; unsigned char *tmp = NULL;
int mtu, rc; int mtu, rc;
struct ipv6_mreq mreq; struct ipv6_mreq mreq;
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
assert (babel_ifp != NULL);
if (!IS_ENABLE(ifp)) if (!IS_ENABLE(ifp))
return -1; return -1;
@ -656,6 +665,7 @@ interface_reset(struct interface *ifp)
int rc; int rc;
struct ipv6_mreq mreq; struct ipv6_mreq mreq;
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
assert (babel_ifp != NULL);
if (!CHECK_FLAG(babel_ifp->flags, BABEL_IF_IS_UP)) if (!CHECK_FLAG(babel_ifp->flags, BABEL_IF_IS_UP))
return 0; return 0;
@ -777,6 +787,7 @@ show_babel_interface_sub (struct vty *vty, struct interface *ifp)
return; return;
} }
babel_ifp = babel_get_if_nfo (ifp); babel_ifp = babel_get_if_nfo (ifp);
assert (babel_ifp != NULL);
vty_out (vty, " Babel protocol is running on this interface\n"); vty_out (vty, " Babel protocol is running on this interface\n");
vty_out (vty, " Operating mode is \"%s\"\n", vty_out (vty, " Operating mode is \"%s\"\n",
CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless"); CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless");
@ -1160,6 +1171,11 @@ DEFUN (show_babel_parameters,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
void babel_if_terminate(void)
{
vector_free(babel_enable_if);
}
void void
babel_if_init(void) babel_if_init(void)
{ {
@ -1228,6 +1244,7 @@ interface_config_write (struct vty *vty)
if (ifp->desc) if (ifp->desc)
vty_out (vty, " description %s\n",ifp->desc); vty_out (vty, " description %s\n",ifp->desc);
babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
assert (babel_ifp != NULL);
/* wireless is the default*/ /* wireless is the default*/
if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED))
{ {
@ -1330,10 +1347,11 @@ babel_interface_allocate (void)
{ {
babel_interface_nfo *babel_ifp; babel_interface_nfo *babel_ifp;
babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
assert (babel_ifp != NULL);
/* All flags are unset */ /* All flags are unset */
babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket_time = babel_now.tv_sec;
babel_ifp->bucket = BUCKET_TOKENS_MAX; babel_ifp->bucket = BUCKET_TOKENS_MAX;
babel_ifp->hello_seqno = (frr_weak_random() & 0xFFFF); babel_ifp->hello_seqno = CHECK_FLAG(frr_weak_random(), 0xFFFF);
babel_ifp->rtt_decay = BABEL_DEFAULT_RTT_DECAY; babel_ifp->rtt_decay = BABEL_DEFAULT_RTT_DECAY;
babel_ifp->rtt_min = BABEL_DEFAULT_RTT_MIN; babel_ifp->rtt_min = BABEL_DEFAULT_RTT_MIN;
babel_ifp->rtt_max = BABEL_DEFAULT_RTT_MAX; babel_ifp->rtt_max = BABEL_DEFAULT_RTT_MAX;
@ -1349,6 +1367,8 @@ babel_interface_allocate (void)
static void static void
babel_interface_free (babel_interface_nfo *babel_ifp) babel_interface_free (babel_interface_nfo *babel_ifp)
{ {
assert (babel_ifp != NULL);
if (babel_ifp->ipv4){ if (babel_ifp->ipv4){
free(babel_ifp->ipv4); free(babel_ifp->ipv4);
babel_ifp->ipv4 = NULL; babel_ifp->ipv4 = NULL;

View file

@ -94,6 +94,7 @@ struct buffered_update {
/* init function */ /* init function */
void babel_if_init(void); void babel_if_init(void);
void babel_if_terminate(void);
/* Callback functions for zebra client */ /* Callback functions for zebra client */
int babel_interface_up (int, struct zclient *, zebra_size_t, vrf_id_t); int babel_interface_up (int, struct zclient *, zebra_size_t, vrf_id_t);

View file

@ -305,9 +305,9 @@ babel_exit_properly(void)
/* Uninstall and flush all routes. */ /* Uninstall and flush all routes. */
debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
flush_all_routes(); babel_clean_routing_process();
babel_interface_close_all();
babel_zebra_close_connexion(); babel_zebra_close_connexion();
babel_if_terminate();
babel_save_state_file(); babel_save_state_file();
debugf(BABEL_DEBUG_COMMON, "Remove pid file."); debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
debugf(BABEL_DEBUG_COMMON, "Done."); debugf(BABEL_DEBUG_COMMON, "Done.");

View file

@ -204,7 +204,7 @@ static void babel_read_protocol(struct event *thread)
making these inits have sense. */ making these inits have sense. */
static void babel_init_routing_process(struct event *thread) static void babel_init_routing_process(struct event *thread)
{ {
myseqno = (frr_weak_random() & 0xFFFF); myseqno = CHECK_FLAG(frr_weak_random(), 0xFFFF);
babel_get_myid(); babel_get_myid();
babel_load_state_file(); babel_load_state_file();
debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid)); debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
@ -299,8 +299,7 @@ babel_initial_noise(void)
} }
/* Delete all the added babel routes, make babeld only speak to zebra. */ /* Delete all the added babel routes, make babeld only speak to zebra. */
static void void babel_clean_routing_process(void)
babel_clean_routing_process(void)
{ {
flush_all_routes(); flush_all_routes();
babel_interface_close_all(); babel_interface_close_all();
@ -445,7 +444,7 @@ babel_fill_with_next_timeout(struct timeval *tv)
#define printIfMin(a,b,c,d) #define printIfMin(a,b,c,d)
#else #else
#define printIfMin(a, b, c, d) \ #define printIfMin(a, b, c, d) \
if (unlikely(debug & BABEL_DEBUG_TIMEOUT)) { \ if (unlikely(CHECK_FLAG(debug, BABEL_DEBUG_TIMEOUT))) { \
printIfMin(a, b, c, d); \ printIfMin(a, b, c, d); \
} }

View file

@ -98,5 +98,6 @@ extern int redistribute_filter(const unsigned char *prefix, unsigned short plen,
extern int resize_receive_buffer(int size); extern int resize_receive_buffer(int size);
extern void schedule_neighbours_check(int msecs, int override); extern void schedule_neighbours_check(int msecs, int override);
extern struct babel *babel_lookup(void); extern struct babel *babel_lookup(void);
extern void babel_clean_routing_process(void);
#endif /* BABEL_BABELD_H */ #endif /* BABEL_BABELD_H */

View file

@ -93,10 +93,6 @@ kernel_route(enum babel_kernel_routes operation, const unsigned char *pref,
if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && if(newmetric == metric && memcmp(newgate, gate, 16) == 0 &&
newifindex == ifindex) newifindex == ifindex)
return 0; return 0;
debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new.");
rc = zebra_route(0, family, pref, plen, gate, ifindex, metric);
if (rc < 0)
return -1;
rc = zebra_route(1, family, pref, plen, newgate, newifindex, rc = zebra_route(1, family, pref, plen, newgate, newifindex,
newmetric); newmetric);

View file

@ -324,8 +324,8 @@ parse_request_subtlv(int ae, const unsigned char *a, int alen,
have_src_prefix = 1; have_src_prefix = 1;
} else { } else {
debugf(BABEL_DEBUG_COMMON,"Received unknown%s Route Request sub-TLV %d.", debugf(BABEL_DEBUG_COMMON,"Received unknown%s Route Request sub-TLV %d.",
((type & 0x80) != 0) ? " mandatory" : "", type); (CHECK_FLAG(type, 0x80) != 0) ? " mandatory" : "", type);
if((type & 0x80) != 0) if(CHECK_FLAG(type, 0x80) != 0)
return -1; return -1;
} }
@ -588,7 +588,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
else else
rc = -1; rc = -1;
if(rc < 0) { if(rc < 0) {
if(message[3] & 0x80) if(CHECK_FLAG(message[3], 0x80))
have_v4_prefix = have_v6_prefix = 0; have_v4_prefix = have_v6_prefix = 0;
goto fail; goto fail;
} }
@ -596,7 +596,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
plen = message[4] + (message[2] == 1 ? 96 : 0); plen = message[4] + (message[2] == 1 ? 96 : 0);
if(message[3] & 0x80) { if(CHECK_FLAG(message[3], 0x80)) {
if(message[2] == 1) { if(message[2] == 1) {
memcpy(v4_prefix, prefix, 16); memcpy(v4_prefix, prefix, 16);
have_v4_prefix = 1; have_v4_prefix = 1;
@ -605,7 +605,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
have_v6_prefix = 1; have_v6_prefix = 1;
} }
} }
if(message[3] & 0x40) { if(CHECK_FLAG(message[3], 0x40)) {
if(message[2] == 1) { if(message[2] == 1) {
memset(router_id, 0, 4); memset(router_id, 0, 4);
memcpy(router_id + 4, prefix + 12, 4); memcpy(router_id + 4, prefix + 12, 4);
@ -620,8 +620,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
goto fail; goto fail;
} }
debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.", debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.",
(message[3] & 0x80) ? "/prefix" : "", ((CHECK_FLAG(message[3], 0x80)) ? "/prefix" : ""),
(message[3] & 0x40) ? "/id" : "", ((CHECK_FLAG(message[3], 0x40)) ? "/id" : ""),
format_prefix(prefix, plen), format_prefix(prefix, plen),
format_address(from), ifp->name); format_address(from), ifp->name);
@ -1059,7 +1059,7 @@ void send_hello_noupdate(struct interface *ifp, unsigned interval)
babel_ifp->hello_seqno, interval, ifp->name); babel_ifp->hello_seqno, interval, ifp->name);
start_message(ifp, MESSAGE_HELLO, start_message(ifp, MESSAGE_HELLO,
(babel_ifp->flags & BABEL_IF_TIMESTAMPS) ? 12 : 6); (CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS) ? 12 : 6));
babel_ifp->buffered_hello = babel_ifp->buffered - 2; babel_ifp->buffered_hello = babel_ifp->buffered - 2;
accumulate_short(ifp, 0); accumulate_short(ifp, 0);
accumulate_short(ifp, babel_ifp->hello_seqno); accumulate_short(ifp, babel_ifp->hello_seqno);

View file

@ -352,7 +352,7 @@ route_stream_done(struct route_stream *stream)
static int static int
metric_to_kernel(int metric) metric_to_kernel(int metric)
{ {
return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; return metric < INFINITY ? metric : KERNEL_INFINITY;
} }
/* This is used to maintain the invariant that the installed route is at /* This is used to maintain the invariant that the installed route is at

View file

@ -211,8 +211,8 @@ mask_prefix(unsigned char *restrict ret,
memset(ret, 0, 16); memset(ret, 0, 16);
memcpy(ret, prefix, plen / 8); memcpy(ret, prefix, plen / 8);
if(plen % 8 != 0) if(plen % 8 != 0)
ret[plen / 8] = ret[plen / 8] = CHECK_FLAG(prefix[plen / 8],
(prefix[plen / 8] & ((0xFF << (8 - (plen % 8))) & 0xFF)); CHECK_FLAG((0xFF << (8 - (plen % 8))), 0xFF));
return ret; return ret;
} }
@ -353,12 +353,13 @@ martian_prefix(const unsigned char *prefix, int plen)
{ {
return return
(plen >= 8 && prefix[0] == 0xFF) || (plen >= 8 && prefix[0] == 0xFF) ||
(plen >= 10 && prefix[0] == 0xFE && (prefix[1] & 0xC0) == 0x80) || (plen >= 10 && prefix[0] == 0xFE &&
(CHECK_FLAG(prefix[1], 0xC0) == 0x80)) ||
(plen >= 128 && memcmp(prefix, zeroes, 15) == 0 && (plen >= 128 && memcmp(prefix, zeroes, 15) == 0 &&
(prefix[15] == 0 || prefix[15] == 1)) || (prefix[15] == 0 || prefix[15] == 1)) ||
(plen >= 96 && v4mapped(prefix) && (plen >= 96 && v4mapped(prefix) &&
((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) || ((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) ||
(plen >= 100 && (prefix[12] & 0xE0) == 0xE0))); (plen >= 100 && CHECK_FLAG(prefix[12], 0xE0) == 0xE0)));
} }
int int

View file

@ -47,19 +47,19 @@ seqno_compare(unsigned short s1, unsigned short s2)
if(s1 == s2) if(s1 == s2)
return 0; return 0;
else else
return ((s2 - s1) & 0x8000) ? 1 : -1; return (CHECK_FLAG((s2 - s1), 0x8000)) ? 1 : -1;
} }
static inline short static inline short
seqno_minus(unsigned short s1, unsigned short s2) seqno_minus(unsigned short s1, unsigned short s2)
{ {
return (short)((s1 - s2) & 0xFFFF); return (short)(CHECK_FLAG((s1 - s2), 0xFFFF));
} }
static inline unsigned short static inline unsigned short
seqno_plus(unsigned short s, int plus) seqno_plus(unsigned short s, int plus)
{ {
return ((s + plus) & 0xFFFF); return CHECK_FLAG((s + plus), 0xFFFF);
} }
/* Returns a time in microseconds on 32 bits (thus modulo 2^32, /* Returns a time in microseconds on 32 bits (thus modulo 2^32,
@ -130,7 +130,7 @@ is_default(const unsigned char *prefix, int plen)
#define debugf(level, ...) \ #define debugf(level, ...) \
do { \ do { \
if (unlikely(debug & level)) \ if (unlikely(CHECK_FLAG(debug, level))) \
zlog_debug(__VA_ARGS__); \ zlog_debug(__VA_ARGS__); \
} while (0) } while (0)

View file

@ -256,19 +256,8 @@ void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
{ {
struct bfd_session *bs;
struct peer_label *pl;
struct bfd_key key; struct bfd_key key;
/* Try to find label first. */
if (bpc->bpc_has_label) {
pl = pl_find(bpc->bpc_label);
if (pl != NULL) {
bs = pl->pl_bs;
return bs;
}
}
/* Otherwise fallback to peer/local hash lookup. */ /* Otherwise fallback to peer/local hash lookup. */
gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
bpc->bpc_localif, bpc->bpc_vrfname); bpc->bpc_localif, bpc->bpc_vrfname);
@ -327,10 +316,8 @@ int bfd_session_enable(struct bfd_session *bs)
bs->ifp = ifp; bs->ifp = ifp;
/* Attempt to use data plane. */ /* Attempt to use data plane. */
if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) { if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0)
control_notify_config(BCM_NOTIFY_CONFIG_ADD, bs);
return 0; return 0;
}
/* Sanity check: don't leak open sockets. */ /* Sanity check: don't leak open sockets. */
if (bs->sock != -1) { if (bs->sock != -1) {
@ -410,8 +397,8 @@ static uint32_t ptm_bfd_gen_ID(void)
* random session identification numbers. * random session identification numbers.
*/ */
do { do {
session_id = ((frr_weak_random() << 16) & 0xFFFF0000) session_id = CHECK_FLAG((frr_weak_random() << 16), 0xFFFF0000) |
| (frr_weak_random() & 0x0000FFFF); CHECK_FLAG(frr_weak_random(), 0x0000FFFF);
} while (session_id == 0 || bfd_id_lookup(session_id) != NULL); } while (session_id == 0 || bfd_id_lookup(session_id) != NULL);
return session_id; return session_id;
@ -502,7 +489,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd)
/* Start sending control packets with poll bit immediately. */ /* Start sending control packets with poll bit immediately. */
ptm_bfd_snd(bfd, 0); ptm_bfd_snd(bfd, 0);
control_notify(bfd, bfd->ses_state); ptm_bfd_notify(bfd, bfd->ses_state);
if (old_state != bfd->ses_state) { if (old_state != bfd->ses_state) {
bfd->stats.session_up++; bfd->stats.session_up++;
@ -538,7 +525,7 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
/* only signal clients when going from up->down state */ /* only signal clients when going from up->down state */
if (old_state == PTM_BFD_UP) if (old_state == PTM_BFD_UP)
control_notify(bfd, PTM_BFD_DOWN); ptm_bfd_notify(bfd, PTM_BFD_DOWN);
/* Stop echo packet transmission if they are active */ /* Stop echo packet transmission if they are active */
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
@ -690,38 +677,6 @@ struct bfd_session *bfd_session_new(void)
return bs; return bs;
} }
int bfd_session_update_label(struct bfd_session *bs, const char *nlabel)
{
/* New label treatment:
* - Check if the label is taken;
* - Try to allocate the memory for it and register;
*/
if (bs->pl == NULL) {
if (pl_find(nlabel) != NULL) {
/* Someone is already using it. */
return -1;
}
pl_new(nlabel, bs);
return 0;
}
/*
* Test label change consistency:
* - Do nothing if it's the same label;
* - Check if the future label is already taken;
* - Change label;
*/
if (strcmp(nlabel, bs->pl->pl_label) == 0)
return -1;
if (pl_find(nlabel) != NULL)
return -1;
strlcpy(bs->pl->pl_label, nlabel, sizeof(bs->pl->pl_label));
return 0;
}
static void _bfd_session_update(struct bfd_session *bs, static void _bfd_session_update(struct bfd_session *bs,
struct bfd_peer_cfg *bpc) struct bfd_peer_cfg *bpc)
{ {
@ -750,9 +705,6 @@ static void _bfd_session_update(struct bfd_session *bs,
bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx; bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx;
} }
if (bpc->bpc_has_label)
bfd_session_update_label(bs, bpc->bpc_label);
if (bpc->bpc_cbit) if (bpc->bpc_cbit)
SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT); SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT);
else else
@ -792,8 +744,6 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
_bfd_session_update(bs, bpc); _bfd_session_update(bs, bpc);
control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
return 0; return 0;
} }
@ -819,8 +769,6 @@ void bfd_session_free(struct bfd_session *bs)
if (bso != NULL) if (bso != NULL)
bs_observer_del(bso); bs_observer_del(bso);
pl_free(bs->pl);
XFREE(MTYPE_BFDD_PROFILE, bs->profile_name); XFREE(MTYPE_BFDD_PROFILE, bs->profile_name);
XFREE(MTYPE_BFDD_CONFIG, bs); XFREE(MTYPE_BFDD_CONFIG, bs);
} }
@ -917,8 +865,6 @@ struct bfd_session *bs_registrate(struct bfd_session *bfd)
if (bglobal.debug_peer_event) if (bglobal.debug_peer_event)
zlog_debug("session-new: %s", bs_to_string(bfd)); zlog_debug("session-new: %s", bs_to_string(bfd));
control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd);
return bfd; return bfd;
} }
@ -941,8 +887,6 @@ int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc)
if (bglobal.debug_peer_event) if (bglobal.debug_peer_event)
zlog_debug("%s: %s", __func__, bs_to_string(bs)); zlog_debug("%s: %s", __func__, bs_to_string(bs));
control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
bfd_session_free(bs); bfd_session_free(bs);
return 0; return 0;
@ -1166,11 +1110,8 @@ void bs_final_handler(struct bfd_session *bs)
* When using demand mode we must disable the detection timer * When using demand mode we must disable the detection timer
* for lost control packets. * for lost control packets.
*/ */
if (bs->demand_mode) { if (bs->demand_mode)
/* Notify watchers about changed timers. */
control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
return; return;
}
/* /*
* Calculate transmission time based on new timers. * Calculate transmission time based on new timers.
@ -1189,9 +1130,6 @@ void bs_final_handler(struct bfd_session *bs)
/* Apply new transmission timer immediately. */ /* Apply new transmission timer immediately. */
ptm_bfd_start_xmt_timer(bs, false); ptm_bfd_start_xmt_timer(bs, false);
/* Notify watchers about changed timers. */
control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
} }
void bs_set_slow_timers(struct bfd_session *bs) void bs_set_slow_timers(struct bfd_session *bs)
@ -1261,7 +1199,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
if (bs->bdc) { if (bs->bdc) {
bs->ses_state = PTM_BFD_ADM_DOWN; bs->ses_state = PTM_BFD_ADM_DOWN;
bfd_dplane_update_session(bs); bfd_dplane_update_session(bs);
control_notify(bs, bs->ses_state); ptm_bfd_notify(bs, bs->ses_state);
return; return;
} }
@ -1273,7 +1211,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
/* Change and notify state change. */ /* Change and notify state change. */
bs->ses_state = PTM_BFD_ADM_DOWN; bs->ses_state = PTM_BFD_ADM_DOWN;
control_notify(bs, bs->ses_state); ptm_bfd_notify(bs, bs->ses_state);
/* Don't try to send packets with a disabled session. */ /* Don't try to send packets with a disabled session. */
if (bs->sock != -1) if (bs->sock != -1)
@ -1289,13 +1227,13 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
if (bs->bdc) { if (bs->bdc) {
bs->ses_state = PTM_BFD_DOWN; bs->ses_state = PTM_BFD_DOWN;
bfd_dplane_update_session(bs); bfd_dplane_update_session(bs);
control_notify(bs, bs->ses_state); ptm_bfd_notify(bs, bs->ses_state);
return; return;
} }
/* Change and notify state change. */ /* Change and notify state change. */
bs->ses_state = PTM_BFD_DOWN; bs->ses_state = PTM_BFD_DOWN;
control_notify(bs, bs->ses_state); ptm_bfd_notify(bs, bs->ses_state);
/* Enable timers if non passive, otherwise stop them. */ /* Enable timers if non passive, otherwise stop them. */
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) { if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) {

View file

@ -20,19 +20,73 @@
#include "lib/queue.h" #include "lib/queue.h"
#include "lib/vrf.h" #include "lib/vrf.h"
#include "bfdctl.h"
#ifdef BFD_DEBUG #ifdef BFD_DEBUG
#define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY) #define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY)
#else #else
#define BFDD_JSON_CONV_OPTIONS (0) #define BFDD_JSON_CONV_OPTIONS (0)
#endif #endif
DECLARE_MGROUP(BFDD); #ifndef MAXNAMELEN
DECLARE_MTYPE(BFDD_CONTROL); #define MAXNAMELEN 32
DECLARE_MTYPE(BFDD_NOTIFICATION); #endif
#define BFDD_SOCK_NAME "%s/bfdd.sock", frr_runstatedir #define BPC_DEF_DETECTMULTIPLIER 3
#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */
#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */
#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */
#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */
DECLARE_MGROUP(BFDD);
DECLARE_MTYPE(BFDD_CLIENT);
DECLARE_MTYPE(BFDD_CLIENT_NOTIFICATION);
struct sockaddr_any {
union {
struct sockaddr_in sa_sin;
struct sockaddr_in6 sa_sin6;
};
};
struct bfd_peer_cfg {
bool bpc_mhop;
bool bpc_ipv4;
struct sockaddr_any bpc_peer;
struct sockaddr_any bpc_local;
bool bpc_has_localif;
char bpc_localif[MAXNAMELEN + 1];
bool bpc_has_vrfname;
char bpc_vrfname[MAXNAMELEN + 1];
bool bpc_has_detectmultiplier;
uint8_t bpc_detectmultiplier;
bool bpc_has_recvinterval;
uint64_t bpc_recvinterval;
bool bpc_has_txinterval;
uint64_t bpc_txinterval;
bool bpc_has_echorecvinterval;
uint64_t bpc_echorecvinterval;
bool bpc_has_echotxinterval;
uint64_t bpc_echotxinterval;
bool bpc_has_minimum_ttl;
uint8_t bpc_minimum_ttl;
bool bpc_echo;
bool bpc_createonly;
bool bpc_shutdown;
bool bpc_cbit;
bool bpc_passive;
bool bpc_has_profile;
char bpc_profile[64];
};
/* bfd Authentication Type. */ /* bfd Authentication Type. */
#define BFD_AUTH_NULL 0 #define BFD_AUTH_NULL 0
@ -97,8 +151,9 @@ struct bfd_echo_pkt {
/* Macros for manipulating control packets */ /* Macros for manipulating control packets */
#define BFD_VERMASK 0x07 #define BFD_VERMASK 0x07
#define BFD_DIAGMASK 0x1F #define BFD_DIAGMASK 0x1F
#define BFD_GETVER(diag) ((diag >> 5) & BFD_VERMASK) #define BFD_GETVER(diag) (CHECK_FLAG((diag >> 5), BFD_VERMASK))
#define BFD_SETVER(diag, val) ((diag) |= (val & BFD_VERMASK) << 5) #define BFD_SETVER(diag, val) \
SET_FLAG((diag), CHECK_FLAG(val, BFD_VERMASK) << 5)
#define BFD_VERSION 1 #define BFD_VERSION 1
#define BFD_PBIT 0x20 #define BFD_PBIT 0x20
#define BFD_FBIT 0x10 #define BFD_FBIT 0x10
@ -106,36 +161,36 @@ struct bfd_echo_pkt {
#define BFD_ABIT 0x04 #define BFD_ABIT 0x04
#define BFD_DEMANDBIT 0x02 #define BFD_DEMANDBIT 0x02
#define BFD_MBIT 0x01 #define BFD_MBIT 0x01
#define BFD_GETMBIT(flags) (flags & BFD_MBIT) #define BFD_GETMBIT(flags) (CHECK_FLAG(flags, BFD_MBIT))
#define BFD_SETDEMANDBIT(flags, val) \ #define BFD_SETDEMANDBIT(flags, val) \
{ \ { \
if ((val)) \ if ((val)) \
flags |= BFD_DEMANDBIT; \ SET_FLAG(flags, BFD_DEMANDBIT); \
} }
#define BFD_SETPBIT(flags, val) \ #define BFD_SETPBIT(flags, val) \
{ \ { \
if ((val)) \ if ((val)) \
flags |= BFD_PBIT; \ SET_FLAG(flags, BFD_PBIT); \
} }
#define BFD_GETPBIT(flags) (flags & BFD_PBIT) #define BFD_GETPBIT(flags) (CHECK_FLAG(flags, BFD_PBIT))
#define BFD_SETFBIT(flags, val) \ #define BFD_SETFBIT(flags, val) \
{ \ { \
if ((val)) \ if ((val)) \
flags |= BFD_FBIT; \ SET_FLAG(flags, BFD_FBIT); \
} }
#define BFD_GETFBIT(flags) (flags & BFD_FBIT) #define BFD_GETFBIT(flags) (CHECK_FLAG(flags, BFD_FBIT))
#define BFD_SETSTATE(flags, val) \ #define BFD_SETSTATE(flags, val) \
{ \ { \
if ((val)) \ if ((val)) \
flags |= (val & 0x3) << 6; \ SET_FLAG(flags, (CHECK_FLAG(val, 0x3) << 6)); \
} }
#define BFD_GETSTATE(flags) ((flags >> 6) & 0x3) #define BFD_GETSTATE(flags) (CHECK_FLAG((flags >> 6), 0x3))
#define BFD_SETCBIT(flags, val) \ #define BFD_SETCBIT(flags, val) \
{ \ { \
if ((val)) \ if ((val)) \
flags |= val; \ SET_FLAG(flags, val); \
} }
#define BFD_GETCBIT(flags) (flags & BFD_CBIT) #define BFD_GETCBIT(flags) (CHECK_FLAG(flags, BFD_CBIT))
#define BFD_ECHO_VERSION 1 #define BFD_ECHO_VERSION 1
#define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt) #define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt)
@ -245,9 +300,6 @@ struct bfd_profile {
/** Profile list type. */ /** Profile list type. */
TAILQ_HEAD(bfdproflist, bfd_profile); TAILQ_HEAD(bfdproflist, bfd_profile);
/* bfd_session shortcut label forwarding. */
struct peer_label;
struct bfd_config_timers { struct bfd_config_timers {
uint32_t desired_min_tx; uint32_t desired_min_tx;
uint32_t required_min_rx; uint32_t required_min_rx;
@ -325,14 +377,6 @@ struct bfd_session {
uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */ uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */
}; };
struct peer_label {
TAILQ_ENTRY(peer_label) pl_entry;
struct bfd_session *pl_bs;
char pl_label[MAXNAMELEN];
};
TAILQ_HEAD(pllist, peer_label);
struct bfd_diag_str_list { struct bfd_diag_str_list {
const char *str; const char *str;
int type; int type;
@ -384,64 +428,6 @@ TAILQ_HEAD(obslist, bfd_session_observer);
#define BFD_DEF_ECHO_PORT 3785 #define BFD_DEF_ECHO_PORT 3785
#define BFD_DEF_MHOP_DEST_PORT 4784 #define BFD_DEF_MHOP_DEST_PORT 4784
/*
* control.c
*
* Daemon control code to speak with local consumers.
*/
/* See 'bfdctrl.h' for client protocol definitions. */
struct bfd_control_buffer {
size_t bcb_left;
size_t bcb_pos;
union {
struct bfd_control_msg *bcb_bcm;
uint8_t *bcb_buf;
};
};
struct bfd_control_queue {
TAILQ_ENTRY(bfd_control_queue) bcq_entry;
struct bfd_control_buffer bcq_bcb;
};
TAILQ_HEAD(bcqueue, bfd_control_queue);
struct bfd_notify_peer {
TAILQ_ENTRY(bfd_notify_peer) bnp_entry;
struct bfd_session *bnp_bs;
};
TAILQ_HEAD(bnplist, bfd_notify_peer);
struct bfd_control_socket {
TAILQ_ENTRY(bfd_control_socket) bcs_entry;
int bcs_sd;
struct event *bcs_ev;
struct event *bcs_outev;
struct bcqueue bcs_bcqueue;
/* Notification data */
uint64_t bcs_notify;
struct bnplist bcs_bnplist;
enum bc_msg_version bcs_version;
enum bc_msg_type bcs_type;
/* Message buffering */
struct bfd_control_buffer bcs_bin;
struct bfd_control_buffer *bcs_bout;
};
TAILQ_HEAD(bcslist, bfd_control_socket);
int control_init(const char *path);
void control_shutdown(void);
int control_notify(struct bfd_session *bs, uint8_t notify_state);
int control_notify_config(const char *op, struct bfd_session *bs);
void control_accept(struct event *t);
/* /*
* bfdd.c * bfdd.c
@ -467,9 +453,6 @@ TAILQ_HEAD(dplane_queue, bfd_dplane_ctx);
struct bfd_global { struct bfd_global {
int bg_csock; int bg_csock;
struct event *bg_csockev; struct event *bg_csockev;
struct bcslist bg_bcslist;
struct pllist bg_pllist;
struct obslist bg_obslist; struct obslist bg_obslist;
@ -515,27 +498,6 @@ extern const struct bfd_state_str_list state_list[];
void socket_close(int *s); void socket_close(int *s);
/*
* config.c
*
* Contains the code related with loading/reloading configuration.
*/
int parse_config(const char *fname);
int config_request_add(const char *jsonstr);
int config_request_del(const char *jsonstr);
char *config_response(const char *status, const char *error);
char *config_notify(struct bfd_session *bs);
char *config_notify_config(const char *op, struct bfd_session *bs);
typedef int (*bpc_handle)(struct bfd_peer_cfg *, void *arg);
int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
bpc_handle bh);
struct peer_label *pl_new(const char *label, struct bfd_session *bs);
struct peer_label *pl_find(const char *label);
void pl_free(struct peer_label *pl);
/* /*
* logging - alias to zebra log * logging - alias to zebra log
*/ */
@ -620,7 +582,6 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
bool is_mhop); bool is_mhop);
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc); struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc);
int bfd_session_update_label(struct bfd_session *bs, const char *nlabel);
void bfd_set_polling(struct bfd_session *bs); void bfd_set_polling(struct bfd_session *bs);
void bs_state_handler(struct bfd_session *bs, int nstate); void bs_state_handler(struct bfd_session *bs, int nstate);
void bs_echo_timer_handler(struct bfd_session *bs); void bs_echo_timer_handler(struct bfd_session *bs);

View file

@ -982,7 +982,7 @@ void bfd_recv_cb(struct event *t)
} }
/* Save remote diagnostics before state switch. */ /* Save remote diagnostics before state switch. */
bfd->remote_diag = cp->diag & BFD_DIAGMASK; bfd->remote_diag = CHECK_FLAG(cp->diag, BFD_DIAGMASK);
/* Update remote timers settings. */ /* Update remote timers settings. */
bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx); bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx);
@ -1738,7 +1738,7 @@ void bfd_peer_mac_set(int sd, struct bfd_session *bfd,
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET)) if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET))
return; return;
if (ifp->flags & IFF_NOARP) if (CHECK_FLAG(ifp->flags, IFF_NOARP))
return; return;
if (peer->sa_sin.sin_family == AF_INET) { if (peer->sa_sin.sin_family == AF_INET) {

View file

@ -1,157 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*********************************************************************
* Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
*
* bfdctl.h: all BFDd control socket protocol definitions.
*
* Authors
* -------
* Rafael Zalamena <rzalamena@opensourcerouting.org>
*/
#ifndef _BFDCTRL_H_
#define _BFDCTRL_H_
#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
/*
* Auxiliary definitions
*/
struct sockaddr_any {
union {
struct sockaddr_in sa_sin;
struct sockaddr_in6 sa_sin6;
};
};
#ifndef MAXNAMELEN
#define MAXNAMELEN 32
#endif
#define BPC_DEF_DETECTMULTIPLIER 3
#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */
#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */
#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */
#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */
/* Peer status */
enum bfd_peer_status {
BPS_SHUTDOWN = 0, /* == PTM_BFD_ADM_DOWN, "adm-down" */
BPS_DOWN = 1, /* == PTM_BFD_DOWN, "down" */
BPS_INIT = 2, /* == PTM_BFD_INIT, "init" */
BPS_UP = 3, /* == PTM_BFD_UP, "up" */
};
struct bfd_peer_cfg {
bool bpc_mhop;
bool bpc_ipv4;
struct sockaddr_any bpc_peer;
struct sockaddr_any bpc_local;
bool bpc_has_label;
char bpc_label[MAXNAMELEN];
bool bpc_has_localif;
char bpc_localif[MAXNAMELEN + 1];
bool bpc_has_vrfname;
char bpc_vrfname[MAXNAMELEN + 1];
bool bpc_has_detectmultiplier;
uint8_t bpc_detectmultiplier;
bool bpc_has_recvinterval;
uint64_t bpc_recvinterval;
bool bpc_has_txinterval;
uint64_t bpc_txinterval;
bool bpc_has_echorecvinterval;
uint64_t bpc_echorecvinterval;
bool bpc_has_echotxinterval;
uint64_t bpc_echotxinterval;
bool bpc_has_minimum_ttl;
uint8_t bpc_minimum_ttl;
bool bpc_echo;
bool bpc_createonly;
bool bpc_shutdown;
bool bpc_cbit;
bool bpc_passive;
bool bpc_has_profile;
char bpc_profile[64];
/* Status information */
enum bfd_peer_status bpc_bps;
uint32_t bpc_id;
uint32_t bpc_remoteid;
uint8_t bpc_diag;
uint8_t bpc_remotediag;
uint8_t bpc_remote_detectmultiplier;
uint64_t bpc_remote_recvinterval;
uint64_t bpc_remote_txinterval;
uint64_t bpc_remote_echointerval;
uint64_t bpc_lastevent;
};
/*
* Protocol definitions
*/
enum bc_msg_version {
BMV_VERSION_1 = 1,
};
enum bc_msg_type {
BMT_RESPONSE = 1,
BMT_REQUEST_ADD = 2,
BMT_REQUEST_DEL = 3,
BMT_NOTIFY = 4,
BMT_NOTIFY_ADD = 5,
BMT_NOTIFY_DEL = 6,
};
/* Notify flags to use with bcm_notify. */
#define BCM_NOTIFY_ALL ((uint64_t)-1)
#define BCM_NOTIFY_PEER_STATE (1ULL << 0)
#define BCM_NOTIFY_CONFIG (1ULL << 1)
#define BCM_NOTIFY_NONE 0
/* Response 'status' definitions. */
#define BCM_RESPONSE_OK "ok"
#define BCM_RESPONSE_ERROR "error"
/* Notify operation. */
#define BCM_NOTIFY_PEER_STATUS "status"
#define BCM_NOTIFY_CONFIG_ADD "add"
#define BCM_NOTIFY_CONFIG_DELETE "delete"
#define BCM_NOTIFY_CONFIG_UPDATE "update"
/* Notification special ID. */
#define BCM_NOTIFY_ID 0
struct bfd_control_msg {
/* Total length without the header. */
uint32_t bcm_length;
/*
* Message request/response id.
* All requests will have a correspondent response with the
* same id.
*/
uint16_t bcm_id;
/* Message type. */
uint8_t bcm_type;
/* Message version. */
uint8_t bcm_ver;
/* Message payload. */
uint8_t bcm_data[0];
};
#endif

View file

@ -28,8 +28,8 @@
* FRR related code. * FRR related code.
*/ */
DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon"); DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon");
DEFINE_MTYPE(BFDD, BFDD_CONTROL, "control socket memory"); DEFINE_MTYPE(BFDD, BFDD_CLIENT, "BFD client data");
DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "control notification data"); DEFINE_MTYPE(BFDD, BFDD_CLIENT_NOTIFICATION, "BFD client notification data");
/* Master of threads. */ /* Master of threads. */
struct event_loop *master; struct event_loop *master;
@ -67,9 +67,6 @@ static void sigterm_handler(void)
/* Stop receiving message from zebra. */ /* Stop receiving message from zebra. */
bfdd_zclient_stop(); bfdd_zclient_stop();
/* Shutdown controller to avoid receiving anymore commands. */
control_shutdown();
/* Shutdown and free all protocol related memory. */ /* Shutdown and free all protocol related memory. */
bfd_shutdown(); bfd_shutdown();
@ -132,10 +129,8 @@ FRR_DAEMON_INFO(bfdd, BFD,
); );
/* clang-format on */ /* clang-format on */
#define OPTION_CTLSOCK 1001
#define OPTION_DPLANEADDR 2000 #define OPTION_DPLANEADDR 2000
static const struct option longopts[] = { static const struct option longopts[] = {
{"bfdctl", required_argument, NULL, OPTION_CTLSOCK},
{"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR}, {"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR},
{0} {0}
}; };
@ -319,7 +314,6 @@ static void bg_init(void)
.cap_num_i = 0, .cap_num_i = 0,
}; };
TAILQ_INIT(&bglobal.bg_bcslist);
TAILQ_INIT(&bglobal.bg_obslist); TAILQ_INIT(&bglobal.bg_obslist);
memcpy(&bglobal.bfdd_privs, &bfdd_privs, memcpy(&bglobal.bfdd_privs, &bfdd_privs,
@ -328,8 +322,7 @@ static void bg_init(void)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char ctl_path[512], dplane_addr[512]; char dplane_addr[512];
bool ctlsockused = false;
int opt; int opt;
bglobal.bg_use_dplane = false; bglobal.bg_use_dplane = false;
@ -339,7 +332,6 @@ int main(int argc, char *argv[])
frr_preinit(&bfdd_di, argc, argv); frr_preinit(&bfdd_di, argc, argv);
frr_opt_add("", longopts, frr_opt_add("", longopts,
" --bfdctl Specify bfdd control socket\n"
" --dplaneaddr Specify BFD data plane address\n"); " --dplaneaddr Specify BFD data plane address\n");
while (true) { while (true) {
@ -348,10 +340,6 @@ int main(int argc, char *argv[])
break; break;
switch (opt) { switch (opt) {
case OPTION_CTLSOCK:
strlcpy(ctl_path, optarg, sizeof(ctl_path));
ctlsockused = true;
break;
case OPTION_DPLANEADDR: case OPTION_DPLANEADDR:
strlcpy(dplane_addr, optarg, sizeof(dplane_addr)); strlcpy(dplane_addr, optarg, sizeof(dplane_addr));
bglobal.bg_use_dplane = true; bglobal.bg_use_dplane = true;
@ -362,15 +350,9 @@ int main(int argc, char *argv[])
} }
} }
if (!ctlsockused)
snprintf(ctl_path, sizeof(ctl_path), BFDD_SOCK_NAME);
/* Initialize FRR infrastructure. */ /* Initialize FRR infrastructure. */
master = frr_init(); master = frr_init();
/* Initialize control socket. */
control_init(ctl_path);
/* Initialize BFD data structures. */ /* Initialize BFD data structures. */
bfd_initialize(); bfd_initialize();
@ -381,9 +363,6 @@ int main(int argc, char *argv[])
/* Initialize zebra connection. */ /* Initialize zebra connection. */
bfdd_zclient_init(&bglobal.bfdd_privs); bfdd_zclient_init(&bglobal.bfdd_privs);
event_add_read(master, control_accept, NULL, bglobal.bg_csock,
&bglobal.bg_csockev);
/* Install commands. */ /* Install commands. */
bfdd_vty_init(); bfdd_vty_init();

View file

@ -338,11 +338,12 @@ void bfd_cli_show_minimum_ttl(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG( DEFPY_YANG(
bfd_peer_mult, bfd_peer_mult_cmd, bfd_peer_mult, bfd_peer_mult_cmd,
"detect-multiplier (2-255)$multiplier", "[no] detect-multiplier ![(2-255)$multiplier]",
NO_STR
"Configure peer detection multiplier\n" "Configure peer detection multiplier\n"
"Configure peer detection multiplier value\n") "Configure peer detection multiplier value\n")
{ {
nb_cli_enqueue_change(vty, "./detection-multiplier", NB_OP_MODIFY, nb_cli_enqueue_change(vty, "./detection-multiplier", no ? NB_OP_DESTROY : NB_OP_MODIFY,
multiplier_str); multiplier_str);
return nb_cli_apply_changes(vty, NULL); return nb_cli_apply_changes(vty, NULL);
} }
@ -356,14 +357,15 @@ void bfd_cli_show_mult(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG( DEFPY_YANG(
bfd_peer_rx, bfd_peer_rx_cmd, bfd_peer_rx, bfd_peer_rx_cmd,
"receive-interval (10-60000)$interval", "[no] receive-interval ![(10-60000)$interval]",
NO_STR
"Configure peer receive interval\n" "Configure peer receive interval\n"
"Configure peer receive interval value in milliseconds\n") "Configure peer receive interval value in milliseconds\n")
{ {
char value[32]; char value[32];
snprintf(value, sizeof(value), "%ld", interval * 1000); snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./required-receive-interval", NB_OP_MODIFY, nb_cli_enqueue_change(vty, "./required-receive-interval", no ? NB_OP_DESTROY : NB_OP_MODIFY,
value); value);
return nb_cli_apply_changes(vty, NULL); return nb_cli_apply_changes(vty, NULL);
@ -379,7 +381,8 @@ void bfd_cli_show_rx(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG( DEFPY_YANG(
bfd_peer_tx, bfd_peer_tx_cmd, bfd_peer_tx, bfd_peer_tx_cmd,
"transmit-interval (10-60000)$interval", "[no] transmit-interval ![(10-60000)$interval]",
NO_STR
"Configure peer transmit interval\n" "Configure peer transmit interval\n"
"Configure peer transmit interval value in milliseconds\n") "Configure peer transmit interval value in milliseconds\n")
{ {
@ -387,7 +390,7 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000); snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./desired-transmission-interval", nb_cli_enqueue_change(vty, "./desired-transmission-interval",
NB_OP_MODIFY, value); no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL); return nb_cli_apply_changes(vty, NULL);
} }
@ -436,7 +439,8 @@ void bfd_cli_show_echo(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG( DEFPY_YANG(
bfd_peer_echo_interval, bfd_peer_echo_interval_cmd, bfd_peer_echo_interval, bfd_peer_echo_interval_cmd,
"echo-interval (10-60000)$interval", "[no] echo-interval ![(10-60000)$interval]",
NO_STR
"Configure peer echo intervals\n" "Configure peer echo intervals\n"
"Configure peer echo rx/tx intervals value in milliseconds\n") "Configure peer echo rx/tx intervals value in milliseconds\n")
{ {
@ -449,16 +453,17 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000); snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval", nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
NB_OP_MODIFY, value); no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
nb_cli_enqueue_change(vty, "./required-echo-receive-interval", nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
NB_OP_MODIFY, value); no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL); return nb_cli_apply_changes(vty, NULL);
} }
DEFPY_YANG( DEFPY_YANG(
bfd_peer_echo_transmit_interval, bfd_peer_echo_transmit_interval_cmd, bfd_peer_echo_transmit_interval, bfd_peer_echo_transmit_interval_cmd,
"echo transmit-interval (10-60000)$interval", "[no] echo transmit-interval ![(10-60000)$interval]",
NO_STR
"Configure peer echo intervals\n" "Configure peer echo intervals\n"
"Configure desired transmit interval\n" "Configure desired transmit interval\n"
"Configure interval value in milliseconds\n") "Configure interval value in milliseconds\n")
@ -472,7 +477,7 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000); snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval", nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
NB_OP_MODIFY, value); no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL); return nb_cli_apply_changes(vty, NULL);
} }
@ -487,7 +492,8 @@ void bfd_cli_show_desired_echo_transmission_interval(
DEFPY_YANG( DEFPY_YANG(
bfd_peer_echo_receive_interval, bfd_peer_echo_receive_interval_cmd, bfd_peer_echo_receive_interval, bfd_peer_echo_receive_interval_cmd,
"echo receive-interval <disabled$disabled|(10-60000)$interval>", "[no] echo receive-interval ![<disabled$disabled|(10-60000)$interval>]",
NO_STR
"Configure peer echo intervals\n" "Configure peer echo intervals\n"
"Configure required receive interval\n" "Configure required receive interval\n"
"Disable echo packets receive\n" "Disable echo packets receive\n"
@ -506,7 +512,7 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000); snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./required-echo-receive-interval", nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
NB_OP_MODIFY, value); no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL); return nb_cli_apply_changes(vty, NULL);
} }
@ -571,17 +577,20 @@ void bfd_cli_show_profile(struct vty *vty, const struct lyd_node *dnode,
} }
ALIAS_YANG(bfd_peer_mult, bfd_profile_mult_cmd, ALIAS_YANG(bfd_peer_mult, bfd_profile_mult_cmd,
"detect-multiplier (2-255)$multiplier", "[no] detect-multiplier ![(2-255)$multiplier]",
NO_STR
"Configure peer detection multiplier\n" "Configure peer detection multiplier\n"
"Configure peer detection multiplier value\n") "Configure peer detection multiplier value\n")
ALIAS_YANG(bfd_peer_tx, bfd_profile_tx_cmd, ALIAS_YANG(bfd_peer_tx, bfd_profile_tx_cmd,
"transmit-interval (10-60000)$interval", "[no] transmit-interval ![(10-60000)$interval]",
NO_STR
"Configure peer transmit interval\n" "Configure peer transmit interval\n"
"Configure peer transmit interval value in milliseconds\n") "Configure peer transmit interval value in milliseconds\n")
ALIAS_YANG(bfd_peer_rx, bfd_profile_rx_cmd, ALIAS_YANG(bfd_peer_rx, bfd_profile_rx_cmd,
"receive-interval (10-60000)$interval", "[no] receive-interval ![(10-60000)$interval]",
NO_STR
"Configure peer receive interval\n" "Configure peer receive interval\n"
"Configure peer receive interval value in milliseconds\n") "Configure peer receive interval value in milliseconds\n")
@ -612,20 +621,23 @@ ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd,
"Configure echo mode\n") "Configure echo mode\n")
ALIAS_YANG(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd, ALIAS_YANG(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd,
"echo-interval (10-60000)$interval", "[no] echo-interval ![(10-60000)$interval]",
NO_STR
"Configure peer echo interval\n" "Configure peer echo interval\n"
"Configure peer echo interval value in milliseconds\n") "Configure peer echo interval value in milliseconds\n")
ALIAS_YANG( ALIAS_YANG(
bfd_peer_echo_transmit_interval, bfd_profile_echo_transmit_interval_cmd, bfd_peer_echo_transmit_interval, bfd_profile_echo_transmit_interval_cmd,
"echo transmit-interval (10-60000)$interval", "[no] echo transmit-interval ![(10-60000)$interval]",
NO_STR
"Configure peer echo intervals\n" "Configure peer echo intervals\n"
"Configure desired transmit interval\n" "Configure desired transmit interval\n"
"Configure interval value in milliseconds\n") "Configure interval value in milliseconds\n")
ALIAS_YANG( ALIAS_YANG(
bfd_peer_echo_receive_interval, bfd_profile_echo_receive_interval_cmd, bfd_peer_echo_receive_interval, bfd_profile_echo_receive_interval_cmd,
"echo receive-interval <disabled$disabled|(10-60000)$interval>", "[no] echo receive-interval ![<disabled$disabled|(10-60000)$interval>]",
NO_STR
"Configure peer echo intervals\n" "Configure peer echo intervals\n"
"Configure required receive interval\n" "Configure required receive interval\n"
"Disable echo packets receive\n" "Disable echo packets receive\n"

View file

@ -84,9 +84,6 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
if (bs->key.ifname[0]) if (bs->key.ifname[0])
vty_out(vty, " interface %s", bs->key.ifname); vty_out(vty, " interface %s", bs->key.ifname);
vty_out(vty, "\n"); vty_out(vty, "\n");
if (bs->pl)
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
} }
static void _display_peer(struct vty *vty, struct bfd_session *bs) static void _display_peer(struct vty *vty, struct bfd_session *bs)
@ -200,9 +197,6 @@ static struct json_object *_peer_json_header(struct bfd_session *bs)
if (bs->key.ifname[0]) if (bs->key.ifname[0])
json_object_string_add(jo, "interface", bs->key.ifname); json_object_string_add(jo, "interface", bs->key.ifname);
if (bs->pl)
json_object_string_add(jo, "label", bs->pl->pl_label);
return jo; return jo;
} }
@ -561,17 +555,11 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
int idx; int idx;
bool mhop; bool mhop;
struct bfd_session *bs = NULL; struct bfd_session *bs = NULL;
struct peer_label *pl;
struct bfd_peer_cfg bpc; struct bfd_peer_cfg bpc;
struct sockaddr_any psa, lsa, *lsap; struct sockaddr_any psa, lsa, *lsap;
char errormsg[128]; char errormsg[128];
/* Look up the BFD peer. */ if (peer_str) {
if (label) {
pl = pl_find(label);
if (pl)
bs = pl->pl_bs;
} else if (peer_str) {
strtosa(peer_str, &psa); strtosa(peer_str, &psa);
if (local_str) { if (local_str) {
strtosa(local_str, &lsa); strtosa(local_str, &lsa);
@ -879,7 +867,6 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL; bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL; bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL;
bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL; bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL;
bpc->bpc_lastevent = monotime(NULL);
/* Safety check: when no error buf is provided len must be zero. */ /* Safety check: when no error buf is provided len must be zero. */
if (ebuf == NULL) if (ebuf == NULL)

View file

@ -1,592 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*********************************************************************
* Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
*
* config.c: implements the BFD daemon configuration handling.
*
* Authors
* -------
* Rafael Zalamena <rzalamena@opensourcerouting.org>
*/
#include <zebra.h>
#include <string.h>
#include "lib/json.h"
#include "bfd.h"
DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory");
/*
* Definitions
*/
enum peer_list_type {
PLT_IPV4,
PLT_IPV6,
PLT_LABEL,
};
/*
* Prototypes
*/
static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg);
static int parse_list(struct json_object *jo, enum peer_list_type plt,
bpc_handle h, void *arg);
static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc);
static int parse_peer_label_config(struct json_object *jo,
struct bfd_peer_cfg *bpc);
static int config_add(struct bfd_peer_cfg *bpc, void *arg);
static int config_del(struct bfd_peer_cfg *bpc, void *arg);
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs);
/*
* Implementation
*/
static int config_add(struct bfd_peer_cfg *bpc,
void *arg __attribute__((unused)))
{
return ptm_bfd_sess_new(bpc) == NULL;
}
static int config_del(struct bfd_peer_cfg *bpc,
void *arg __attribute__((unused)))
{
return ptm_bfd_sess_del(bpc) != 0;
}
static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg)
{
const char *key, *sval;
struct json_object *jo_val;
struct json_object_iterator joi, join;
int error = 0;
JSON_FOREACH (jo, joi, join) {
key = json_object_iter_peek_name(&joi);
jo_val = json_object_iter_peek_value(&joi);
if (strcmp(key, "ipv4") == 0) {
error += parse_list(jo_val, PLT_IPV4, h, arg);
} else if (strcmp(key, "ipv6") == 0) {
error += parse_list(jo_val, PLT_IPV6, h, arg);
} else if (strcmp(key, "label") == 0) {
error += parse_list(jo_val, PLT_LABEL, h, arg);
} else {
sval = json_object_get_string(jo_val);
zlog_warn("%s:%d invalid configuration: %s", __func__,
__LINE__, sval);
error++;
}
}
/*
* Our callers never call free() on json_object and only expect
* the return value, so lets free() it here.
*/
json_object_put(jo);
return error;
}
int parse_config(const char *fname)
{
struct json_object *jo;
jo = json_object_from_file(fname);
if (jo == NULL)
return -1;
return parse_config_json(jo, config_add, NULL);
}
static int parse_list(struct json_object *jo, enum peer_list_type plt,
bpc_handle h, void *arg)
{
struct json_object *jo_val;
struct bfd_peer_cfg bpc;
int allen, idx;
int error = 0, result;
allen = json_object_array_length(jo);
for (idx = 0; idx < allen; idx++) {
jo_val = json_object_array_get_idx(jo, idx);
/* Set defaults. */
memset(&bpc, 0, sizeof(bpc));
bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT;
bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX;
bpc.bpc_txinterval = BFD_DEFDESIREDMINTX;
bpc.bpc_echorecvinterval = BFD_DEF_REQ_MIN_ECHO_RX;
bpc.bpc_echotxinterval = BFD_DEF_DES_MIN_ECHO_TX;
switch (plt) {
case PLT_IPV4:
zlog_debug("ipv4 peers %d:", allen);
bpc.bpc_ipv4 = true;
break;
case PLT_IPV6:
zlog_debug("ipv6 peers %d:", allen);
bpc.bpc_ipv4 = false;
break;
case PLT_LABEL:
zlog_debug("label peers %d:", allen);
if (parse_peer_label_config(jo_val, &bpc) != 0) {
error++;
continue;
}
break;
default:
error++;
zlog_err("%s:%d: unsupported peer type", __func__,
__LINE__);
break;
}
result = parse_peer_config(jo_val, &bpc);
error += result;
if (result == 0)
error += (h(&bpc, arg) != 0);
}
return error;
}
static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
{
const char *key, *sval;
struct json_object *jo_val;
struct json_object_iterator joi, join;
int family_type = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
int error = 0;
zlog_debug(" peer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6");
JSON_FOREACH (jo, joi, join) {
key = json_object_iter_peek_name(&joi);
jo_val = json_object_iter_peek_value(&joi);
if (strcmp(key, "multihop") == 0) {
bpc->bpc_mhop = json_object_get_boolean(jo_val);
zlog_debug(" multihop: %s",
bpc->bpc_mhop ? "true" : "false");
} else if (strcmp(key, "peer-address") == 0) {
sval = json_object_get_string(jo_val);
if (strtosa(sval, &bpc->bpc_peer) != 0
|| bpc->bpc_peer.sa_sin.sin_family != family_type) {
zlog_debug(
"%s:%d failed to parse peer-address '%s'",
__func__, __LINE__, sval);
error++;
}
zlog_debug(" peer-address: %s", sval);
} else if (strcmp(key, "local-address") == 0) {
sval = json_object_get_string(jo_val);
if (strtosa(sval, &bpc->bpc_local) != 0
|| bpc->bpc_local.sa_sin.sin_family
!= family_type) {
zlog_debug(
"%s:%d failed to parse local-address '%s'",
__func__, __LINE__, sval);
error++;
}
zlog_debug(" local-address: %s", sval);
} else if (strcmp(key, "local-interface") == 0) {
bpc->bpc_has_localif = true;
sval = json_object_get_string(jo_val);
if (strlcpy(bpc->bpc_localif, sval,
sizeof(bpc->bpc_localif))
> sizeof(bpc->bpc_localif)) {
zlog_debug(
" local-interface: %s (truncated)",
sval);
error++;
} else {
zlog_debug(" local-interface: %s", sval);
}
} else if (strcmp(key, "vrf-name") == 0) {
bpc->bpc_has_vrfname = true;
sval = json_object_get_string(jo_val);
if (strlcpy(bpc->bpc_vrfname, sval,
sizeof(bpc->bpc_vrfname))
> sizeof(bpc->bpc_vrfname)) {
zlog_debug(" vrf-name: %s (truncated)",
sval);
error++;
} else {
zlog_debug(" vrf-name: %s", sval);
}
} else if (strcmp(key, "detect-multiplier") == 0) {
bpc->bpc_detectmultiplier =
json_object_get_int64(jo_val);
bpc->bpc_has_detectmultiplier = true;
zlog_debug(" detect-multiplier: %u",
bpc->bpc_detectmultiplier);
} else if (strcmp(key, "receive-interval") == 0) {
bpc->bpc_recvinterval = json_object_get_int64(jo_val);
bpc->bpc_has_recvinterval = true;
zlog_debug(" receive-interval: %" PRIu64,
bpc->bpc_recvinterval);
} else if (strcmp(key, "transmit-interval") == 0) {
bpc->bpc_txinterval = json_object_get_int64(jo_val);
bpc->bpc_has_txinterval = true;
zlog_debug(" transmit-interval: %" PRIu64,
bpc->bpc_txinterval);
} else if (strcmp(key, "echo-receive-interval") == 0) {
bpc->bpc_echorecvinterval = json_object_get_int64(jo_val);
bpc->bpc_has_echorecvinterval = true;
zlog_debug(" echo-receive-interval: %" PRIu64,
bpc->bpc_echorecvinterval);
} else if (strcmp(key, "echo-transmit-interval") == 0) {
bpc->bpc_echotxinterval = json_object_get_int64(jo_val);
bpc->bpc_has_echotxinterval = true;
zlog_debug(" echo-transmit-interval: %" PRIu64,
bpc->bpc_echotxinterval);
} else if (strcmp(key, "create-only") == 0) {
bpc->bpc_createonly = json_object_get_boolean(jo_val);
zlog_debug(" create-only: %s",
bpc->bpc_createonly ? "true" : "false");
} else if (strcmp(key, "shutdown") == 0) {
bpc->bpc_shutdown = json_object_get_boolean(jo_val);
zlog_debug(" shutdown: %s",
bpc->bpc_shutdown ? "true" : "false");
} else if (strcmp(key, "echo-mode") == 0) {
bpc->bpc_echo = json_object_get_boolean(jo_val);
zlog_debug(" echo-mode: %s",
bpc->bpc_echo ? "true" : "false");
} else if (strcmp(key, "label") == 0) {
bpc->bpc_has_label = true;
sval = json_object_get_string(jo_val);
if (strlcpy(bpc->bpc_label, sval,
sizeof(bpc->bpc_label))
> sizeof(bpc->bpc_label)) {
zlog_debug(" label: %s (truncated)",
sval);
error++;
} else {
zlog_debug(" label: %s", sval);
}
} else {
sval = json_object_get_string(jo_val);
zlog_warn("%s:%d invalid configuration: '%s: %s'",
__func__, __LINE__, key, sval);
error++;
}
}
if (bpc->bpc_peer.sa_sin.sin_family == 0) {
zlog_debug("%s:%d no peer address provided", __func__,
__LINE__);
error++;
}
return error;
}
static int parse_peer_label_config(struct json_object *jo,
struct bfd_peer_cfg *bpc)
{
struct peer_label *pl;
struct json_object *label;
const char *sval;
/* Get label and translate it to BFD daemon key. */
if (!json_object_object_get_ex(jo, "label", &label))
return 1;
sval = json_object_get_string(label);
pl = pl_find(sval);
if (pl == NULL)
return 1;
zlog_debug(" peer-label: %s", sval);
/* Translate the label into BFD address keys. */
bs_to_bpc(pl->pl_bs, bpc);
return 0;
}
/*
* Control socket JSON parsing.
*/
int config_request_add(const char *jsonstr)
{
struct json_object *jo;
jo = json_tokener_parse(jsonstr);
if (jo == NULL)
return -1;
return parse_config_json(jo, config_add, NULL);
}
int config_request_del(const char *jsonstr)
{
struct json_object *jo;
jo = json_tokener_parse(jsonstr);
if (jo == NULL)
return -1;
return parse_config_json(jo, config_del, NULL);
}
char *config_response(const char *status, const char *error)
{
struct json_object *resp, *jo;
char *jsonstr;
resp = json_object_new_object();
if (resp == NULL)
return NULL;
/* Add 'status' response key. */
jo = json_object_new_string(status);
if (jo == NULL) {
json_object_put(resp);
return NULL;
}
json_object_object_add(resp, "status", jo);
/* Add 'error' response key. */
if (error != NULL) {
jo = json_object_new_string(error);
if (jo == NULL) {
json_object_put(resp);
return NULL;
}
json_object_object_add(resp, "error", jo);
}
/* Generate JSON response. */
jsonstr = XSTRDUP(
MTYPE_BFDD_NOTIFICATION,
json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS));
json_object_put(resp);
return jsonstr;
}
char *config_notify(struct bfd_session *bs)
{
struct json_object *resp;
char *jsonstr;
time_t now;
resp = json_object_new_object();
if (resp == NULL)
return NULL;
json_object_string_add(resp, "op", BCM_NOTIFY_PEER_STATUS);
json_object_add_peer(resp, bs);
/* Add status information */
json_object_int_add(resp, "id", bs->discrs.my_discr);
json_object_int_add(resp, "remote-id", bs->discrs.my_discr);
switch (bs->ses_state) {
case PTM_BFD_UP:
json_object_string_add(resp, "state", "up");
now = monotime(NULL);
json_object_int_add(resp, "uptime", now - bs->uptime.tv_sec);
break;
case PTM_BFD_ADM_DOWN:
json_object_string_add(resp, "state", "adm-down");
break;
case PTM_BFD_DOWN:
json_object_string_add(resp, "state", "down");
now = monotime(NULL);
json_object_int_add(resp, "downtime",
now - bs->downtime.tv_sec);
break;
case PTM_BFD_INIT:
json_object_string_add(resp, "state", "init");
break;
default:
json_object_string_add(resp, "state", "unknown");
break;
}
json_object_int_add(resp, "diagnostics", bs->local_diag);
json_object_int_add(resp, "remote-diagnostics", bs->remote_diag);
/* Generate JSON response. */
jsonstr = XSTRDUP(
MTYPE_BFDD_NOTIFICATION,
json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS));
json_object_put(resp);
return jsonstr;
}
char *config_notify_config(const char *op, struct bfd_session *bs)
{
struct json_object *resp;
char *jsonstr;
resp = json_object_new_object();
if (resp == NULL)
return NULL;
json_object_string_add(resp, "op", op);
json_object_add_peer(resp, bs);
/* On peer deletion we don't need to add any additional information. */
if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0)
goto skip_config;
json_object_int_add(resp, "detect-multiplier", bs->detect_mult);
json_object_int_add(resp, "receive-interval",
bs->timers.required_min_rx / 1000);
json_object_int_add(resp, "transmit-interval",
bs->timers.desired_min_tx / 1000);
json_object_int_add(resp, "echo-receive-interval",
bs->timers.required_min_echo_rx / 1000);
json_object_int_add(resp, "echo-transmit-interval",
bs->timers.desired_min_echo_tx / 1000);
json_object_int_add(resp, "remote-detect-multiplier",
bs->remote_detect_mult);
json_object_int_add(resp, "remote-receive-interval",
bs->remote_timers.required_min_rx / 1000);
json_object_int_add(resp, "remote-transmit-interval",
bs->remote_timers.desired_min_tx / 1000);
json_object_int_add(resp, "remote-echo-receive-interval",
bs->remote_timers.required_min_echo / 1000);
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
json_object_boolean_true_add(resp, "echo-mode");
else
json_object_boolean_false_add(resp, "echo-mode");
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
json_object_boolean_true_add(resp, "shutdown");
else
json_object_boolean_false_add(resp, "shutdown");
skip_config:
/* Generate JSON response. */
jsonstr = XSTRDUP(
MTYPE_BFDD_NOTIFICATION,
json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS));
json_object_put(resp);
return jsonstr;
}
int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
bpc_handle bh)
{
struct json_object *jo;
jo = json_tokener_parse(jsonstr);
if (jo == NULL)
return -1;
return parse_config_json(jo, bh, bcs);
}
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
{
char addr_buf[INET6_ADDRSTRLEN];
/* Add peer 'key' information. */
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
json_object_boolean_true_add(jo, "ipv6");
else
json_object_boolean_false_add(jo, "ipv6");
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
json_object_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
json_object_string_add(jo, "local-address",
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.vrfname[0])
json_object_string_add(jo, "vrf-name", bs->key.vrfname);
} else {
json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
json_object_string_add(
jo, "local-address",
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.ifname[0])
json_object_string_add(jo, "local-interface",
bs->key.ifname);
}
if (bs->pl)
json_object_string_add(jo, "label", bs->pl->pl_label);
return 0;
}
/*
* Label handling
*/
struct peer_label *pl_find(const char *label)
{
struct peer_label *pl;
TAILQ_FOREACH (pl, &bglobal.bg_pllist, pl_entry) {
if (strcmp(pl->pl_label, label) != 0)
continue;
return pl;
}
return NULL;
}
struct peer_label *pl_new(const char *label, struct bfd_session *bs)
{
struct peer_label *pl;
pl = XCALLOC(MTYPE_BFDD_LABEL, sizeof(*pl));
if (strlcpy(pl->pl_label, label, sizeof(pl->pl_label))
> sizeof(pl->pl_label))
zlog_warn("%s:%d: label was truncated", __func__, __LINE__);
pl->pl_bs = bs;
bs->pl = pl;
TAILQ_INSERT_HEAD(&bglobal.bg_pllist, pl, pl_entry);
return pl;
}
void pl_free(struct peer_label *pl)
{
if (pl == NULL)
return;
/* Remove the pointer back. */
pl->pl_bs->pl = NULL;
TAILQ_REMOVE(&bglobal.bg_pllist, pl, pl_entry);
XFREE(MTYPE_BFDD_LABEL, pl);
}

View file

@ -1,844 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*********************************************************************
* Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
*
* control.c: implements the BFD daemon control socket. It will be used
* to talk with clients daemon/scripts/consumers.
*
* Authors
* -------
* Rafael Zalamena <rzalamena@opensourcerouting.org>
*/
#include <zebra.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/un.h>
#include "bfd.h"
/*
* Prototypes
*/
static int sock_set_nonblock(int fd);
struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs);
static void control_queue_free(struct bfd_control_socket *bcs,
struct bfd_control_queue *bcq);
static int control_queue_dequeue(struct bfd_control_socket *bcs);
static int control_queue_enqueue(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static int control_queue_enqueue_first(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs,
struct bfd_session *bs);
static void control_notifypeer_free(struct bfd_control_socket *bcs,
struct bfd_notify_peer *bnp);
struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs,
struct bfd_session *bs);
struct bfd_control_socket *control_new(int sd);
static void control_free(struct bfd_control_socket *bcs);
static void control_reset_buf(struct bfd_control_buffer *bcb);
static void control_read(struct event *t);
static void control_write(struct event *t);
static void control_handle_request_add(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static void control_handle_request_del(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg);
static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg);
static void control_handle_notify_add(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static void control_handle_notify_del(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static void _control_handle_notify(struct hash_bucket *hb, void *arg);
static void control_handle_notify(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static void control_response(struct bfd_control_socket *bcs, uint16_t id,
const char *status, const char *error);
static void _control_notify_config(struct bfd_control_socket *bcs,
const char *op, struct bfd_session *bs);
static void _control_notify(struct bfd_control_socket *bcs,
struct bfd_session *bs);
/*
* Functions
*/
static int sock_set_nonblock(int fd)
{
int flags;
flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
zlog_warn("%s: fcntl F_GETFL: %s", __func__, strerror(errno));
return -1;
}
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) == -1) {
zlog_warn("%s: fcntl F_SETFL: %s", __func__, strerror(errno));
return -1;
}
return 0;
}
int control_init(const char *path)
{
int sd;
mode_t umval;
struct sockaddr_un sun_ = {
.sun_family = AF_UNIX,
};
assert(path);
strlcpy(sun_.sun_path, path, sizeof(sun_.sun_path));
/* Remove previously created sockets. */
unlink(sun_.sun_path);
sd = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
if (sd == -1) {
zlog_err("%s: socket: %s", __func__, strerror(errno));
return -1;
}
umval = umask(0);
if (bind(sd, (struct sockaddr *)&sun_, sizeof(sun_)) == -1) {
zlog_err("%s: bind: %s", __func__, strerror(errno));
close(sd);
return -1;
}
umask(umval);
if (listen(sd, SOMAXCONN) == -1) {
zlog_err("%s: listen: %s", __func__, strerror(errno));
close(sd);
return -1;
}
sock_set_nonblock(sd);
bglobal.bg_csock = sd;
return 0;
}
void control_shutdown(void)
{
struct bfd_control_socket *bcs;
event_cancel(&bglobal.bg_csockev);
socket_close(&bglobal.bg_csock);
while (!TAILQ_EMPTY(&bglobal.bg_bcslist)) {
bcs = TAILQ_FIRST(&bglobal.bg_bcslist);
control_free(bcs);
}
}
void control_accept(struct event *t)
{
int csock, sd = EVENT_FD(t);
csock = accept(sd, NULL, 0);
if (csock == -1) {
zlog_warn("%s: accept: %s", __func__, strerror(errno));
return;
}
control_new(csock);
event_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev);
}
/*
* Client handling
*/
struct bfd_control_socket *control_new(int sd)
{
struct bfd_control_socket *bcs;
bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs));
/* Disable notifications by default. */
bcs->bcs_notify = 0;
bcs->bcs_sd = sd;
event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev);
TAILQ_INIT(&bcs->bcs_bcqueue);
TAILQ_INIT(&bcs->bcs_bnplist);
TAILQ_INSERT_TAIL(&bglobal.bg_bcslist, bcs, bcs_entry);
return bcs;
}
static void control_free(struct bfd_control_socket *bcs)
{
struct bfd_control_queue *bcq;
struct bfd_notify_peer *bnp;
event_cancel(&(bcs->bcs_ev));
event_cancel(&(bcs->bcs_outev));
close(bcs->bcs_sd);
TAILQ_REMOVE(&bglobal.bg_bcslist, bcs, bcs_entry);
/* Empty output queue. */
while (!TAILQ_EMPTY(&bcs->bcs_bcqueue)) {
bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
control_queue_free(bcs, bcq);
}
/* Empty notification list. */
while (!TAILQ_EMPTY(&bcs->bcs_bnplist)) {
bnp = TAILQ_FIRST(&bcs->bcs_bnplist);
control_notifypeer_free(bcs, bnp);
}
control_reset_buf(&bcs->bcs_bin);
XFREE(MTYPE_BFDD_CONTROL, bcs);
}
struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs,
struct bfd_session *bs)
{
struct bfd_notify_peer *bnp;
bnp = control_notifypeer_find(bcs, bs);
if (bnp)
return bnp;
bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp));
TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry);
bnp->bnp_bs = bs;
bs->refcount++;
return bnp;
}
static void control_notifypeer_free(struct bfd_control_socket *bcs,
struct bfd_notify_peer *bnp)
{
TAILQ_REMOVE(&bcs->bcs_bnplist, bnp, bnp_entry);
bnp->bnp_bs->refcount--;
XFREE(MTYPE_BFDD_CONTROL, bnp);
}
struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs,
struct bfd_session *bs)
{
struct bfd_notify_peer *bnp;
TAILQ_FOREACH (bnp, &bcs->bcs_bnplist, bnp_entry) {
if (bnp->bnp_bs == bs)
return bnp;
}
return NULL;
}
struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs)
{
struct bfd_control_queue *bcq;
bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq));
control_reset_buf(&bcq->bcq_bcb);
TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry);
return bcq;
}
static void control_queue_free(struct bfd_control_socket *bcs,
struct bfd_control_queue *bcq)
{
control_reset_buf(&bcq->bcq_bcb);
TAILQ_REMOVE(&bcs->bcs_bcqueue, bcq, bcq_entry);
XFREE(MTYPE_BFDD_NOTIFICATION, bcq);
}
static int control_queue_dequeue(struct bfd_control_socket *bcs)
{
struct bfd_control_queue *bcq;
/* List is empty, nothing to do. */
if (TAILQ_EMPTY(&bcs->bcs_bcqueue))
goto empty_list;
bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
control_queue_free(bcs, bcq);
/* Get the next buffer to send. */
if (TAILQ_EMPTY(&bcs->bcs_bcqueue))
goto empty_list;
bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
bcs->bcs_bout = &bcq->bcq_bcb;
bcs->bcs_outev = NULL;
event_add_write(master, control_write, bcs, bcs->bcs_sd,
&bcs->bcs_outev);
return 1;
empty_list:
event_cancel(&(bcs->bcs_outev));
bcs->bcs_bout = NULL;
return 0;
}
static int control_queue_enqueue(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
struct bfd_control_queue *bcq;
struct bfd_control_buffer *bcb;
bcq = control_queue_new(bcs);
bcb = &bcq->bcq_bcb;
bcb->bcb_left = sizeof(struct bfd_control_msg) + ntohl(bcm->bcm_length);
bcb->bcb_pos = 0;
bcb->bcb_bcm = bcm;
/* If this is the first item, then dequeue and start using it. */
if (bcs->bcs_bout == NULL) {
bcs->bcs_bout = bcb;
/* New messages, active write events. */
event_add_write(master, control_write, bcs, bcs->bcs_sd,
&bcs->bcs_outev);
}
return 0;
}
static int control_queue_enqueue_first(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
struct bfd_control_queue *bcq, *bcqn;
struct bfd_control_buffer *bcb;
/* Enqueue it somewhere. */
if (control_queue_enqueue(bcs, bcm) == -1)
return -1;
/*
* The item is either the first or the last. So we must first
* check the best case where the item is already the first.
*/
bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
bcb = &bcq->bcq_bcb;
if (bcm == bcb->bcb_bcm)
return 0;
/*
* The item was not the first, so it is the last. We'll try to
* assign it to the head of the queue, however if there is a
* transfer in progress, then we have to make the item as the
* next one.
*
* Interrupting the transfer of in progress message will cause
* the client to lose track of the message position/data.
*/
bcqn = TAILQ_LAST(&bcs->bcs_bcqueue, bcqueue);
TAILQ_REMOVE(&bcs->bcs_bcqueue, bcqn, bcq_entry);
if (bcb->bcb_pos != 0) {
/*
* First position is already being sent, insert into
* second position.
*/
TAILQ_INSERT_AFTER(&bcs->bcs_bcqueue, bcq, bcqn, bcq_entry);
} else {
/*
* Old message didn't start being sent, we still have
* time to put this one in the head of the queue.
*/
TAILQ_INSERT_HEAD(&bcs->bcs_bcqueue, bcqn, bcq_entry);
bcb = &bcqn->bcq_bcb;
bcs->bcs_bout = bcb;
}
return 0;
}
static void control_reset_buf(struct bfd_control_buffer *bcb)
{
/* Get ride of old data. */
XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf);
bcb->bcb_pos = 0;
bcb->bcb_left = 0;
}
static void control_read(struct event *t)
{
struct bfd_control_socket *bcs = EVENT_ARG(t);
struct bfd_control_buffer *bcb = &bcs->bcs_bin;
int sd = bcs->bcs_sd;
struct bfd_control_msg bcm;
ssize_t bread;
size_t plen;
/*
* Check if we have already downloaded message content, if so then skip
* to
* download the rest of it and process.
*
* Otherwise download a new message header and allocate the necessary
* memory.
*/
if (bcb->bcb_buf != NULL)
goto skip_header;
bread = read(sd, &bcm, sizeof(bcm));
if (bread == 0) {
control_free(bcs);
return;
}
if (bread < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
goto schedule_next_read;
zlog_warn("%s: read: %s", __func__, strerror(errno));
control_free(bcs);
return;
}
/* Validate header fields. */
plen = ntohl(bcm.bcm_length);
if (plen < 2) {
zlog_debug("%s: client closed due small message length: %d",
__func__, bcm.bcm_length);
control_free(bcs);
return;
}
#define FRR_BFD_MAXLEN 10 * 1024
if (plen > FRR_BFD_MAXLEN) {
zlog_debug("%s: client closed, invalid message length: %d",
__func__, bcm.bcm_length);
control_free(bcs);
return;
}
if (bcm.bcm_ver != BMV_VERSION_1) {
zlog_debug("%s: client closed due bad version: %d", __func__,
bcm.bcm_ver);
control_free(bcs);
return;
}
/* Prepare the buffer to load the message. */
bcs->bcs_version = bcm.bcm_ver;
bcs->bcs_type = bcm.bcm_type;
bcb->bcb_pos = sizeof(bcm);
bcb->bcb_left = plen;
bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(bcm) + bcb->bcb_left + 1);
if (bcb->bcb_buf == NULL) {
zlog_warn("%s: not enough memory for message size: %zu",
__func__, bcb->bcb_left);
control_free(bcs);
return;
}
memcpy(bcb->bcb_buf, &bcm, sizeof(bcm));
/* Terminate data string with NULL for later processing. */
bcb->bcb_buf[sizeof(bcm) + bcb->bcb_left] = 0;
skip_header:
/* Download the remaining data of the message and process it. */
bread = read(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left);
if (bread == 0) {
control_free(bcs);
return;
}
if (bread < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
goto schedule_next_read;
zlog_warn("%s: read: %s", __func__, strerror(errno));
control_free(bcs);
return;
}
bcb->bcb_pos += bread;
bcb->bcb_left -= bread;
/* We need more data, return to wait more. */
if (bcb->bcb_left > 0)
goto schedule_next_read;
switch (bcb->bcb_bcm->bcm_type) {
case BMT_REQUEST_ADD:
control_handle_request_add(bcs, bcb->bcb_bcm);
break;
case BMT_REQUEST_DEL:
control_handle_request_del(bcs, bcb->bcb_bcm);
break;
case BMT_NOTIFY:
control_handle_notify(bcs, bcb->bcb_bcm);
break;
case BMT_NOTIFY_ADD:
control_handle_notify_add(bcs, bcb->bcb_bcm);
break;
case BMT_NOTIFY_DEL:
control_handle_notify_del(bcs, bcb->bcb_bcm);
break;
default:
zlog_debug("%s: unhandled message type: %d", __func__,
bcb->bcb_bcm->bcm_type);
control_response(bcs, bcb->bcb_bcm->bcm_id, BCM_RESPONSE_ERROR,
"invalid message type");
break;
}
bcs->bcs_version = 0;
bcs->bcs_type = 0;
control_reset_buf(bcb);
schedule_next_read:
bcs->bcs_ev = NULL;
event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev);
}
static void control_write(struct event *t)
{
struct bfd_control_socket *bcs = EVENT_ARG(t);
struct bfd_control_buffer *bcb = bcs->bcs_bout;
int sd = bcs->bcs_sd;
ssize_t bwrite;
bwrite = write(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left);
if (bwrite == 0) {
control_free(bcs);
return;
}
if (bwrite < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
bcs->bcs_outev = NULL;
event_add_write(master, control_write, bcs, bcs->bcs_sd,
&bcs->bcs_outev);
return;
}
zlog_warn("%s: write: %s", __func__, strerror(errno));
control_free(bcs);
return;
}
bcb->bcb_pos += bwrite;
bcb->bcb_left -= bwrite;
if (bcb->bcb_left > 0) {
bcs->bcs_outev = NULL;
event_add_write(master, control_write, bcs, bcs->bcs_sd,
&bcs->bcs_outev);
return;
}
control_queue_dequeue(bcs);
}
/*
* Message processing
*/
static void control_handle_request_add(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
const char *json = (const char *)bcm->bcm_data;
if (config_request_add(json) == 0)
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
else
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
"request add failed");
}
static void control_handle_request_del(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
const char *json = (const char *)bcm->bcm_data;
if (config_request_del(json) == 0)
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
else
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
"request del failed");
}
static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc)
{
struct peer_label *pl;
if (bpc->bpc_has_label) {
pl = pl_find(bpc->bpc_label);
if (pl)
return pl->pl_bs;
}
return bs_peer_find(bpc);
}
static void _control_handle_notify(struct hash_bucket *hb, void *arg)
{
struct bfd_control_socket *bcs = arg;
struct bfd_session *bs = hb->data;
/* Notify peer configuration. */
if (bcs->bcs_notify & BCM_NOTIFY_CONFIG)
_control_notify_config(bcs, BCM_NOTIFY_CONFIG_ADD, bs);
/* Notify peer status. */
if (bcs->bcs_notify & BCM_NOTIFY_PEER_STATE)
_control_notify(bcs, bs);
}
static void control_handle_notify(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
memcpy(&bcs->bcs_notify, bcm->bcm_data, sizeof(bcs->bcs_notify));
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
/*
* If peer asked for notification configuration, send everything that
* was configured until the moment to sync up.
*/
if (bcs->bcs_notify & (BCM_NOTIFY_CONFIG | BCM_NOTIFY_PEER_STATE))
bfd_id_iterate(_control_handle_notify, bcs);
}
static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg)
{
struct bfd_control_socket *bcs = arg;
struct bfd_session *bs = _notify_find_peer(bpc);
if (bs == NULL)
return -1;
control_notifypeer_new(bcs, bs);
/* Notify peer status. */
_control_notify(bcs, bs);
return 0;
}
static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg)
{
struct bfd_control_socket *bcs = arg;
struct bfd_session *bs = _notify_find_peer(bpc);
struct bfd_notify_peer *bnp;
if (bs == NULL)
return -1;
bnp = control_notifypeer_find(bcs, bs);
if (bnp)
control_notifypeer_free(bcs, bnp);
return 0;
}
static void control_handle_notify_add(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
const char *json = (const char *)bcm->bcm_data;
if (config_notify_request(bcs, json, notify_add_cb) == 0) {
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
return;
}
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
"failed to parse notify data");
}
static void control_handle_notify_del(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
const char *json = (const char *)bcm->bcm_data;
if (config_notify_request(bcs, json, notify_del_cb) == 0) {
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
return;
}
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
"failed to parse notify data");
}
/*
* Internal functions used by the BFD daemon.
*/
static void control_response(struct bfd_control_socket *bcs, uint16_t id,
const char *status, const char *error)
{
struct bfd_control_msg *bcm;
char *jsonstr;
size_t jsonstrlen;
/* Generate JSON response. */
jsonstr = config_response(status, error);
if (jsonstr == NULL) {
zlog_warn("%s: config_response: failed to get JSON str",
__func__);
return;
}
/* Allocate data and answer. */
jsonstrlen = strlen(jsonstr);
bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(struct bfd_control_msg) + jsonstrlen);
bcm->bcm_length = htonl(jsonstrlen);
bcm->bcm_ver = BMV_VERSION_1;
bcm->bcm_type = BMT_RESPONSE;
bcm->bcm_id = id;
memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
control_queue_enqueue_first(bcs, bcm);
}
static void _control_notify(struct bfd_control_socket *bcs,
struct bfd_session *bs)
{
struct bfd_control_msg *bcm;
char *jsonstr;
size_t jsonstrlen;
/* Generate JSON response. */
jsonstr = config_notify(bs);
if (jsonstr == NULL) {
zlog_warn("%s: config_notify: failed to get JSON str",
__func__);
return;
}
/* Allocate data and answer. */
jsonstrlen = strlen(jsonstr);
bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(struct bfd_control_msg) + jsonstrlen);
bcm->bcm_length = htonl(jsonstrlen);
bcm->bcm_ver = BMV_VERSION_1;
bcm->bcm_type = BMT_NOTIFY;
bcm->bcm_id = htons(BCM_NOTIFY_ID);
memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
control_queue_enqueue(bcs, bcm);
}
int control_notify(struct bfd_session *bs, uint8_t notify_state)
{
struct bfd_control_socket *bcs;
struct bfd_notify_peer *bnp;
/* Notify zebra listeners as well. */
ptm_bfd_notify(bs, notify_state);
/*
* PERFORMANCE: reuse the bfd_control_msg allocated data for
* all control sockets to avoid wasting memory.
*/
TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
/*
* Test for all notifications first, then search for
* specific peers.
*/
if ((bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) == 0) {
bnp = control_notifypeer_find(bcs, bs);
/*
* If the notification is not configured here,
* don't send it.
*/
if (bnp == NULL)
continue;
}
_control_notify(bcs, bs);
}
return 0;
}
static void _control_notify_config(struct bfd_control_socket *bcs,
const char *op, struct bfd_session *bs)
{
struct bfd_control_msg *bcm;
char *jsonstr;
size_t jsonstrlen;
/* Generate JSON response. */
jsonstr = config_notify_config(op, bs);
if (jsonstr == NULL) {
zlog_warn("%s: config_notify_config: failed to get JSON str",
__func__);
return;
}
/* Allocate data and answer. */
jsonstrlen = strlen(jsonstr);
bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(struct bfd_control_msg) + jsonstrlen);
bcm->bcm_length = htonl(jsonstrlen);
bcm->bcm_ver = BMV_VERSION_1;
bcm->bcm_type = BMT_NOTIFY;
bcm->bcm_id = htons(BCM_NOTIFY_ID);
memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
control_queue_enqueue(bcs, bcm);
}
int control_notify_config(const char *op, struct bfd_session *bs)
{
struct bfd_control_socket *bcs;
struct bfd_notify_peer *bnp;
/* Remove the control sockets notification for this peer. */
if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0 && bs->refcount > 0) {
TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
bnp = control_notifypeer_find(bcs, bs);
if (bnp)
control_notifypeer_free(bcs, bnp);
}
}
/*
* PERFORMANCE: reuse the bfd_control_msg allocated data for
* all control sockets to avoid wasting memory.
*/
TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
/*
* Test for all notifications first, then search for
* specific peers.
*/
if ((bcs->bcs_notify & BCM_NOTIFY_CONFIG) == 0)
continue;
_control_notify_config(bcs, op, bs);
}
return 0;
}

View file

@ -354,7 +354,7 @@ bfd_dplane_session_state_change(struct bfd_dplane_ctx *bdc,
bs->remote_timers.required_min_echo = ntohl(state->required_echo_rx); bs->remote_timers.required_min_echo = ntohl(state->required_echo_rx);
/* Notify and update counters. */ /* Notify and update counters. */
control_notify(bs, bs->ses_state); ptm_bfd_notify(bs, bs->ses_state);
/* No state change. */ /* No state change. */
if (old_state == bs->ses_state) if (old_state == bs->ses_state)

View file

@ -148,7 +148,6 @@ static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag)
"ptm-del-session: [%s] session refcount is zero but it was configured by CLI", "ptm-del-session: [%s] session refcount is zero but it was configured by CLI",
bs_to_string(bs)); bs_to_string(bs));
} else { } else {
control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
bfd_session_free(bs); bfd_session_free(bs);
} }
} }
@ -892,7 +891,7 @@ static struct ptm_client *pc_new(uint32_t pid)
return pc; return pc;
/* Allocate the client data and save it. */ /* Allocate the client data and save it. */
pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc)); pc = XCALLOC(MTYPE_BFDD_CLIENT, sizeof(*pc));
pc->pc_pid = pid; pc->pc_pid = pid;
TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry); TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry);
@ -910,7 +909,7 @@ static void pc_free(struct ptm_client *pc)
pcn_free(pcn); pcn_free(pcn);
} }
XFREE(MTYPE_BFDD_CONTROL, pc); XFREE(MTYPE_BFDD_CLIENT, pc);
} }
static void pc_free_all(void) static void pc_free_all(void)
@ -934,7 +933,7 @@ static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
return pcn; return pcn;
/* Save the client notification data. */ /* Save the client notification data. */
pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn)); pcn = XCALLOC(MTYPE_BFDD_CLIENT_NOTIFICATION, sizeof(*pcn));
TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry); TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry);
pcn->pcn_pc = pc; pcn->pcn_pc = pc;
@ -982,5 +981,5 @@ static void pcn_free(struct ptm_client_notification *pcn)
pcn->pcn_pc = NULL; pcn->pcn_pc = NULL;
TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry); TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry);
XFREE(MTYPE_BFDD_NOTIFICATION, pcn); XFREE(MTYPE_BFDD_CLIENT_NOTIFICATION, pcn);
} }

View file

@ -17,8 +17,6 @@ bfdd_libbfd_a_SOURCES = \
bfdd/bfdd_vty.c \ bfdd/bfdd_vty.c \
bfdd/bfdd_cli.c \ bfdd/bfdd_cli.c \
bfdd/bfd_packet.c \ bfdd/bfd_packet.c \
bfdd/config.c \
bfdd/control.c \
bfdd/dplane.c \ bfdd/dplane.c \
bfdd/event.c \ bfdd/event.c \
bfdd/ptm_adapter.c \ bfdd/ptm_adapter.c \
@ -37,7 +35,6 @@ clippy_scan += \
# end # end
noinst_HEADERS += \ noinst_HEADERS += \
bfdd/bfdctl.h \
bfdd/bfdd_nb.h \ bfdd/bfdd_nb.h \
bfdd/bfd.h \ bfdd/bfd.h \
# end # end

View file

@ -361,8 +361,7 @@ void bgp_addpath_type_changed(struct bgp *bgp)
} }
} }
int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths)
uint8_t paths)
{ {
int action = CAPABILITY_ACTION_UNSET; int action = CAPABILITY_ACTION_UNSET;
@ -392,8 +391,7 @@ int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type,
* change take effect. * change take effect.
*/ */
void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
enum bgp_addpath_strat addpath_type, enum bgp_addpath_strat addpath_type, uint16_t paths)
uint8_t paths)
{ {
struct bgp *bgp = peer->bgp; struct bgp *bgp = peer->bgp;
enum bgp_addpath_strat old_type; enum bgp_addpath_strat old_type;

View file

@ -62,13 +62,11 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat,
* Change the type of addpath used for a peer. * Change the type of addpath used for a peer.
*/ */
void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
enum bgp_addpath_strat addpath_type, enum bgp_addpath_strat addpath_type, uint16_t paths);
uint8_t paths);
void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi,
safi_t safi); safi_t safi);
void bgp_addpath_type_changed(struct bgp *bgp); void bgp_addpath_type_changed(struct bgp *bgp);
extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths);
uint8_t paths);
#endif #endif

View file

@ -198,6 +198,7 @@ static struct hash *vnc_hash = NULL;
#endif #endif
static struct hash *srv6_l3vpn_hash; static struct hash *srv6_l3vpn_hash;
static struct hash *srv6_vpn_hash; static struct hash *srv6_vpn_hash;
static struct hash *evpn_overlay_hash;
struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig) struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
{ {
@ -479,22 +480,11 @@ static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt, int length,
return false; return false;
} }
static uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi) static void stream_put_bgp_aigp_tlv_metric(struct stream *s, uint64_t aigp)
{
uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr);
if (bpi->nexthop)
return aigp + bpi->nexthop->metric;
else
return aigp;
}
static void stream_put_bgp_aigp_tlv_metric(struct stream *s,
struct bgp_path_info *bpi)
{ {
stream_putc(s, BGP_AIGP_TLV_METRIC); stream_putc(s, BGP_AIGP_TLV_METRIC);
stream_putw(s, BGP_AIGP_TLV_METRIC_LEN); stream_putw(s, BGP_AIGP_TLV_METRIC_LEN);
stream_putq(s, bgp_aigp_metric_total(bpi)); stream_putq(s, aigp);
} }
static bool bgp_attr_aigp_valid(uint8_t *pnt, int length) static bool bgp_attr_aigp_valid(uint8_t *pnt, int length)
@ -549,6 +539,81 @@ static bool bgp_attr_aigp_valid(uint8_t *pnt, int length)
return true; return true;
} }
static void *evpn_overlay_hash_alloc(void *p)
{
return p;
}
void evpn_overlay_free(struct bgp_route_evpn *bre)
{
XFREE(MTYPE_BGP_EVPN_OVERLAY, bre);
}
static struct bgp_route_evpn *evpn_overlay_intern(struct bgp_route_evpn *bre)
{
struct bgp_route_evpn *find;
find = hash_get(evpn_overlay_hash, bre, evpn_overlay_hash_alloc);
if (find != bre)
evpn_overlay_free(bre);
find->refcnt++;
return find;
}
static void evpn_overlay_unintern(struct bgp_route_evpn **brep)
{
struct bgp_route_evpn *bre = *brep;
if (!*brep)
return;
if (bre->refcnt)
bre->refcnt--;
if (bre->refcnt == 0) {
hash_release(evpn_overlay_hash, bre);
evpn_overlay_free(bre);
*brep = NULL;
}
}
static uint32_t evpn_overlay_hash_key_make(const void *p)
{
const struct bgp_route_evpn *bre = p;
uint32_t key = 0;
if (IS_IPADDR_V4(&bre->gw_ip))
key = jhash_1word(bre->gw_ip.ipaddr_v4.s_addr, 0);
else
key = jhash2(bre->gw_ip.ipaddr_v6.s6_addr32,
array_size(bre->gw_ip.ipaddr_v6.s6_addr32), 0);
key = jhash_1word(bre->type, key);
key = jhash(bre->eth_s_id.val, sizeof(bre->eth_s_id.val), key);
return key;
}
static bool evpn_overlay_hash_cmp(const void *p1, const void *p2)
{
const struct bgp_route_evpn *bre1 = p1;
const struct bgp_route_evpn *bre2 = p2;
return bgp_route_evpn_same(bre1, bre2);
}
static void evpn_overlay_init(void)
{
evpn_overlay_hash = hash_create(evpn_overlay_hash_key_make,
evpn_overlay_hash_cmp,
"BGP EVPN Overlay");
}
static void evpn_overlay_finish(void)
{
hash_clean_and_free(&evpn_overlay_hash,
(void (*)(void *))evpn_overlay_free);
}
static void *srv6_l3vpn_hash_alloc(void *p) static void *srv6_l3vpn_hash_alloc(void *p)
{ {
return p; return p;
@ -788,6 +853,8 @@ unsigned int attrhash_key_make(const void *p)
MIX(encap_hash_key_make(attr->encap_subtlvs)); MIX(encap_hash_key_make(attr->encap_subtlvs));
if (attr->srv6_l3vpn) if (attr->srv6_l3vpn)
MIX(srv6_l3vpn_hash_key_make(attr->srv6_l3vpn)); MIX(srv6_l3vpn_hash_key_make(attr->srv6_l3vpn));
if (bgp_attr_get_evpn_overlay(attr))
MIX(evpn_overlay_hash_key_make(bgp_attr_get_evpn_overlay(attr)));
if (attr->srv6_vpn) if (attr->srv6_vpn)
MIX(srv6_vpn_hash_key_make(attr->srv6_vpn)); MIX(srv6_vpn_hash_key_make(attr->srv6_vpn));
#ifdef ENABLE_BGP_VNC #ifdef ENABLE_BGP_VNC
@ -814,19 +881,16 @@ bool attrhash_cmp(const void *p1, const void *p2)
const struct attr *attr1 = p1; const struct attr *attr1 = p1;
const struct attr *attr2 = p2; const struct attr *attr2 = p2;
if (attr1->flag == attr2->flag && attr1->origin == attr2->origin if (attr1->flag == attr2->flag && attr1->origin == attr2->origin &&
&& attr1->nexthop.s_addr == attr2->nexthop.s_addr attr1->nexthop.s_addr == attr2->nexthop.s_addr &&
&& attr1->aspath == attr2->aspath attr1->aspath == attr2->aspath &&
&& bgp_attr_get_community(attr1) bgp_attr_get_community(attr1) == bgp_attr_get_community(attr2) &&
== bgp_attr_get_community(attr2) attr1->med == attr2->med && attr1->local_pref == attr2->local_pref &&
&& attr1->med == attr2->med attr1->rmap_change_flags == attr2->rmap_change_flags) {
&& attr1->local_pref == attr2->local_pref
&& attr1->rmap_change_flags == attr2->rmap_change_flags) {
if (attr1->aggregator_as == attr2->aggregator_as && if (attr1->aggregator_as == attr2->aggregator_as &&
attr1->aggregator_addr.s_addr == attr1->aggregator_addr.s_addr ==
attr2->aggregator_addr.s_addr && attr2->aggregator_addr.s_addr &&
attr1->weight == attr2->weight && attr1->weight == attr2->weight && attr1->tag == attr2->tag &&
attr1->tag == attr2->tag &&
attr1->label_index == attr2->label_index && attr1->label_index == attr2->label_index &&
attr1->mp_nexthop_len == attr2->mp_nexthop_len && attr1->mp_nexthop_len == attr2->mp_nexthop_len &&
bgp_attr_get_ecommunity(attr1) == bgp_attr_get_ecommunity(attr1) ==
@ -835,10 +899,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
bgp_attr_get_ipv6_ecommunity(attr2) && bgp_attr_get_ipv6_ecommunity(attr2) &&
bgp_attr_get_lcommunity(attr1) == bgp_attr_get_lcommunity(attr1) ==
bgp_attr_get_lcommunity(attr2) && bgp_attr_get_lcommunity(attr2) &&
bgp_attr_get_cluster(attr1) == bgp_attr_get_cluster(attr1) == bgp_attr_get_cluster(attr2) &&
bgp_attr_get_cluster(attr2) && bgp_attr_get_transit(attr1) == bgp_attr_get_transit(attr2) &&
bgp_attr_get_transit(attr1) ==
bgp_attr_get_transit(attr2) &&
bgp_attr_get_aigp_metric(attr1) == bgp_attr_get_aigp_metric(attr1) ==
bgp_attr_get_aigp_metric(attr2) && bgp_attr_get_aigp_metric(attr2) &&
attr1->rmap_table_id == attr2->rmap_table_id && attr1->rmap_table_id == attr2->rmap_table_id &&
@ -870,8 +932,7 @@ bool attrhash_cmp(const void *p1, const void *p2)
srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) &&
attr1->srte_color == attr2->srte_color && attr1->srte_color == attr2->srte_color &&
attr1->nh_type == attr2->nh_type && attr1->nh_type == attr2->nh_type &&
attr1->bh_type == attr2->bh_type && attr1->bh_type == attr2->bh_type && attr1->otc == attr2->otc)
attr1->otc == attr2->otc)
return true; return true;
} }
@ -961,6 +1022,7 @@ struct attr *bgp_attr_intern(struct attr *attr)
struct ecommunity *ipv6_ecomm = NULL; struct ecommunity *ipv6_ecomm = NULL;
struct lcommunity *lcomm = NULL; struct lcommunity *lcomm = NULL;
struct community *comm = NULL; struct community *comm = NULL;
struct bgp_route_evpn *bre = NULL;
/* Intern referenced structure. */ /* Intern referenced structure. */
if (attr->aspath) { if (attr->aspath) {
@ -1027,6 +1089,16 @@ struct attr *bgp_attr_intern(struct attr *attr)
else else
attr->encap_subtlvs->refcnt++; attr->encap_subtlvs->refcnt++;
} }
bre = bgp_attr_get_evpn_overlay(attr);
if (bre) {
if (!bre->refcnt)
bgp_attr_set_evpn_overlay(attr,
evpn_overlay_intern(bre));
else
bre->refcnt++;
}
if (attr->srv6_l3vpn) { if (attr->srv6_l3vpn) {
if (!attr->srv6_l3vpn->refcnt) if (!attr->srv6_l3vpn->refcnt)
attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn); attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
@ -1072,14 +1144,14 @@ struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp,
memset(attr, 0, sizeof(struct attr)); memset(attr, 0, sizeof(struct attr));
attr->origin = origin; attr->origin = origin;
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN));
attr->aspath = aspath_empty(bgp->asnotation); attr->aspath = aspath_empty(bgp->asnotation);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
attr->weight = BGP_ATTR_DEFAULT_WEIGHT; attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
attr->tag = 0; attr->tag = 0;
attr->label_index = BGP_INVALID_LABEL_INDEX; attr->label_index = BGP_INVALID_LABEL_INDEX;
attr->label = MPLS_INVALID_LABEL; attr->label = MPLS_INVALID_LABEL;
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
attr->mp_nexthop_len = IPV6_MAX_BYTELEN; attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
attr->local_pref = bgp->default_local_pref; attr->local_pref = bgp->default_local_pref;
@ -1101,18 +1173,18 @@ struct attr *bgp_attr_aggregate_intern(
/* Origin attribute. */ /* Origin attribute. */
attr.origin = origin; attr.origin = origin;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN); SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN));
/* MED */ /* MED */
attr.med = 0; attr.med = 0;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC));
/* AS path attribute. */ /* AS path attribute. */
if (aspath) if (aspath)
attr.aspath = aspath_intern(aspath); attr.aspath = aspath_intern(aspath);
else else
attr.aspath = aspath_empty(bgp->asnotation); attr.aspath = aspath_empty(bgp->asnotation);
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH); SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
if (community) { if (community) {
uint32_t gshut = COMMUNITY_GSHUT; uint32_t gshut = COMMUNITY_GSHUT;
@ -1142,8 +1214,8 @@ struct attr *bgp_attr_aggregate_intern(
attr.weight = BGP_ATTR_DEFAULT_WEIGHT; attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
attr.mp_nexthop_len = IPV6_MAX_BYTELEN; attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
if (!aggregate->as_set || atomic_aggregate) if (!aggregate->as_set || atomic_aggregate)
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE); SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE));
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR); SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
attr.aggregator_as = bgp->confed_id; attr.aggregator_as = bgp->confed_id;
else else
@ -1161,7 +1233,7 @@ struct attr *bgp_attr_aggregate_intern(
*/ */
if (p->family == AF_INET) { if (p->family == AF_INET) {
/* Next hop attribute. */ /* Next hop attribute. */
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
attr.mp_nexthop_len = IPV4_MAX_BYTELEN; attr.mp_nexthop_len = IPV4_MAX_BYTELEN;
} }
@ -1216,6 +1288,7 @@ void bgp_attr_unintern_sub(struct attr *attr)
struct lcommunity *lcomm = NULL; struct lcommunity *lcomm = NULL;
struct community *comm = NULL; struct community *comm = NULL;
struct transit *transit; struct transit *transit;
struct bgp_route_evpn *bre;
/* aspath refcount shoud be decrement. */ /* aspath refcount shoud be decrement. */
aspath_unintern(&attr->aspath); aspath_unintern(&attr->aspath);
@ -1257,6 +1330,10 @@ void bgp_attr_unintern_sub(struct attr *attr)
srv6_l3vpn_unintern(&attr->srv6_l3vpn); srv6_l3vpn_unintern(&attr->srv6_l3vpn);
srv6_vpn_unintern(&attr->srv6_vpn); srv6_vpn_unintern(&attr->srv6_vpn);
bre = bgp_attr_get_evpn_overlay(attr);
evpn_overlay_unintern(&bre);
bgp_attr_set_evpn_overlay(attr, NULL);
} }
/* Free bgp attribute and aspath. */ /* Free bgp attribute and aspath. */
@ -1289,6 +1366,7 @@ void bgp_attr_flush(struct attr *attr)
struct cluster_list *cluster; struct cluster_list *cluster;
struct lcommunity *lcomm; struct lcommunity *lcomm;
struct community *comm; struct community *comm;
struct bgp_route_evpn *bre;
if (attr->aspath && !attr->aspath->refcnt) { if (attr->aspath && !attr->aspath->refcnt) {
aspath_free(attr->aspath); aspath_free(attr->aspath);
@ -1347,6 +1425,11 @@ void bgp_attr_flush(struct attr *attr)
bgp_attr_set_vnc_subtlvs(attr, NULL); bgp_attr_set_vnc_subtlvs(attr, NULL);
} }
#endif #endif
bre = bgp_attr_get_evpn_overlay(attr);
if (bre && !bre->refcnt) {
evpn_overlay_free(bre);
bgp_attr_set_evpn_overlay(attr, NULL);
}
} }
/* Implement draft-scudder-idr-optional-transitive behaviour and /* Implement draft-scudder-idr-optional-transitive behaviour and
@ -1467,8 +1550,8 @@ bgp_attr_flags_diagnose(struct bgp_attr_parser_args *args,
uint8_t real_flags = args->flags; uint8_t real_flags = args->flags;
const uint8_t attr_code = args->type; const uint8_t attr_code = args->type;
desired_flags &= ~BGP_ATTR_FLAG_EXTLEN; UNSET_FLAG(desired_flags, BGP_ATTR_FLAG_EXTLEN);
real_flags &= ~BGP_ATTR_FLAG_EXTLEN; UNSET_FLAG(real_flags, BGP_ATTR_FLAG_EXTLEN);
for (i = 0; i <= 2; i++) /* O,T,P, but not E */ for (i = 0; i <= 2; i++) /* O,T,P, but not E */
if (CHECK_FLAG(desired_flags, attr_flag_str[i].key) if (CHECK_FLAG(desired_flags, attr_flag_str[i].key)
!= CHECK_FLAG(real_flags, attr_flag_str[i].key)) { != CHECK_FLAG(real_flags, attr_flag_str[i].key)) {
@ -1582,7 +1665,7 @@ static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args *args)
&& CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS)) && CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS))
SET_FLAG(mask, BGP_ATTR_FLAG_PARTIAL); SET_FLAG(mask, BGP_ATTR_FLAG_PARTIAL);
if ((flags & ~mask) == attr_flags_values[attr_code]) if (CHECK_FLAG(flags, ~mask) == attr_flags_values[attr_code])
return false; return false;
bgp_attr_flags_diagnose(args, attr_flags_values[attr_code]); bgp_attr_flags_diagnose(args, attr_flags_values[attr_code]);
@ -1624,7 +1707,7 @@ bgp_attr_origin(struct bgp_attr_parser_args *args)
} }
/* Set oring attribute flag. */ /* Set oring attribute flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN));
return 0; return 0;
} }
@ -1674,7 +1757,7 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
} }
/* Set aspath attribute flag. */ /* Set aspath attribute flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
} }
@ -1778,7 +1861,7 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
} }
/* Set aspath attribute flag. */ /* Set aspath attribute flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
} }
@ -1828,7 +1911,7 @@ bgp_attr_nexthop(struct bgp_attr_parser_args *args)
} }
attr->nexthop.s_addr = stream_get_ipv4(peer->curr); attr->nexthop.s_addr = stream_get_ipv4(peer->curr);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
} }
@ -1851,7 +1934,7 @@ static enum bgp_attr_parse_ret bgp_attr_med(struct bgp_attr_parser_args *args)
attr->med = stream_getl(peer->curr); attr->med = stream_getl(peer->curr);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
} }
@ -1889,7 +1972,7 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args)
STREAM_GETL(peer->curr, attr->local_pref); STREAM_GETL(peer->curr, attr->local_pref);
/* Set the local-pref flag. */ /* Set the local-pref flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
@ -1918,7 +2001,7 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
goto atomic_ignore; goto atomic_ignore;
/* Set atomic aggregate flag. */ /* Set atomic aggregate flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
@ -1976,7 +2059,7 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
zlog_debug("%s: attributes: %s", __func__, attr_str); zlog_debug("%s: attributes: %s", __func__, attr_str);
} }
} else { } else {
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
} }
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
@ -2027,7 +2110,7 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
zlog_debug("%s: attributes: %s", __func__, attr_str); zlog_debug("%s: attributes: %s", __func__, attr_str);
} }
} else { } else {
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR));
} }
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
@ -2066,12 +2149,13 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
* should not send them * should not send them
*/ */
if (BGP_DEBUG(as4, AS4)) { if (BGP_DEBUG(as4, AS4)) {
if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))) if (CHECK_FLAG(attr->flag,
(ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))))
zlog_debug("[AS4] %s %s AS4_PATH", peer->host, zlog_debug("[AS4] %s %s AS4_PATH", peer->host,
"AS4 capable peer, yet it sent"); "AS4 capable peer, yet it sent");
if (attr->flag if (CHECK_FLAG(attr->flag,
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))))
zlog_debug("[AS4] %s %s AS4_AGGREGATOR", zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
peer->host, peer->host,
"AS4 capable peer, yet it sent"); "AS4 capable peer, yet it sent");
@ -2083,8 +2167,9 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
/* We have a asn16 peer. First, look for AS4_AGGREGATOR /* We have a asn16 peer. First, look for AS4_AGGREGATOR
* because that may override AS4_PATH * because that may override AS4_PATH
*/ */
if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) { if (CHECK_FLAG(attr->flag, (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))) {
if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) { if (CHECK_FLAG(attr->flag,
(ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)))) {
/* received both. /* received both.
* if the as_number in aggregator is not AS_TRANS, * if the as_number in aggregator is not AS_TRANS,
* then AS4_AGGREGATOR and AS4_PATH shall be ignored * then AS4_AGGREGATOR and AS4_PATH shall be ignored
@ -2124,13 +2209,14 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
attr->aggregator_as = as4_aggregator; attr->aggregator_as = as4_aggregator;
/* sweep it under the carpet and simulate a "good" /* sweep it under the carpet and simulate a "good"
* AGGREGATOR */ * AGGREGATOR */
attr->flag |= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)); SET_FLAG(attr->flag,
(ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)));
} }
} }
/* need to reconcile NEW_AS_PATH and AS_PATH */ /* need to reconcile NEW_AS_PATH and AS_PATH */
if (!ignore_as4_path if (!ignore_as4_path &&
&& (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) { (CHECK_FLAG(attr->flag, (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))))) {
newpath = aspath_reconcile_as4(attr->aspath, as4_path); newpath = aspath_reconcile_as4(attr->aspath, as4_path);
if (!newpath) if (!newpath)
return BGP_ATTR_PARSE_ERROR; return BGP_ATTR_PARSE_ERROR;
@ -2215,7 +2301,7 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args)
attr->originator_id.s_addr = stream_get_ipv4(peer->curr); attr->originator_id.s_addr = stream_get_ipv4(peer->curr);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
@ -2473,7 +2559,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
stream_forward_getp(s, nlri_len); stream_forward_getp(s, nlri_len);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
#undef LEN_LEFT #undef LEN_LEFT
@ -2525,7 +2611,7 @@ int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
stream_forward_getp(s, withdraw_len); stream_forward_getp(s, withdraw_len);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
} }
@ -2575,7 +2661,6 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
struct peer *const peer = args->peer; struct peer *const peer = args->peer;
struct attr *const attr = args->attr; struct attr *const attr = args->attr;
const bgp_size_t length = args->length; const bgp_size_t length = args->length;
uint8_t sticky = 0;
bool proxy = false; bool proxy = false;
struct ecommunity *ecomm; struct ecommunity *ecomm;
@ -2586,8 +2671,7 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
args->total); args->total);
} }
ecomm = ecommunity_parse( ecomm = ecommunity_parse(stream_pnt(peer->curr), length,
stream_pnt(peer->curr), length,
CHECK_FLAG(peer->flags, CHECK_FLAG(peer->flags,
PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
bgp_attr_set_ecommunity(attr, ecomm); bgp_attr_set_ecommunity(attr, ecomm);
@ -2605,23 +2689,22 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg); attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg);
/* Extract MAC mobility sequence number, if any. */ /* Extract MAC mobility sequence number, if any. */
attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky); attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr);
attr->sticky = sticky;
/* Check if this is a Gateway MAC-IP advertisement */ /* Check if this is a Gateway MAC-IP advertisement */
attr->default_gw = bgp_attr_default_gw(attr); bgp_attr_default_gw(attr);
/* Handle scenario where router flag ecommunity is not /* Handle scenario where router flag ecommunity is not
* set but default gw ext community is present. * set but default gw ext community is present.
* Use default gateway, set and propogate R-bit. * Use default gateway, set and propogate R-bit.
*/ */
if (attr->default_gw) if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW))
attr->router_flag = 1; SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER);
/* Check EVPN Neighbor advertisement flags, R-bit */ /* Check EVPN Neighbor advertisement flags, R-bit */
bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy); bgp_attr_evpn_na_flag(attr, &proxy);
if (proxy) if (proxy)
attr->es_flags |= ATTR_ES_PROXY_ADVERT; SET_FLAG(attr->es_flags, ATTR_ES_PROXY_ADVERT);
/* Extract the Rmac, if any */ /* Extract the Rmac, if any */
if (bgp_attr_rmac(attr, &attr->rmac)) { if (bgp_attr_rmac(attr, &attr->rmac)) {
@ -2692,6 +2775,9 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args)
uint8_t type = args->type; uint8_t type = args->type;
uint8_t flag = args->flags; uint8_t flag = args->flags;
if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto encap_ignore;
if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS) if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
|| !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) { || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
zlog_err("Tunnel Encap attribute flag isn't optional and transitive %d", zlog_err("Tunnel Encap attribute flag isn't optional and transitive %d",
@ -2810,7 +2896,14 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args)
args->total); args->total);
} }
return 0; SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ENCAP));
return BGP_ATTR_PARSE_PROCEED;
encap_ignore:
stream_forward_getp(peer->curr, length);
return bgp_attr_ignore(peer, type);
} }
@ -3202,6 +3295,9 @@ enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args)
size_t headersz = sizeof(type) + sizeof(length); size_t headersz = sizeof(type) + sizeof(length);
size_t psid_parsed_length = 0; size_t psid_parsed_length = 0;
if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto prefix_sid_ignore;
while (STREAM_READABLE(peer->curr) > 0 while (STREAM_READABLE(peer->curr) > 0
&& psid_parsed_length < args->length) { && psid_parsed_length < args->length) {
@ -3249,6 +3345,11 @@ enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args)
SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
prefix_sid_ignore:
stream_forward_getp(peer->curr, args->length);
return bgp_attr_ignore(peer, args->type);
} }
/* PMSI tunnel attribute (RFC 6514) /* PMSI tunnel attribute (RFC 6514)
@ -3263,6 +3364,9 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
uint8_t tnl_type; uint8_t tnl_type;
int attr_parse_len = 2 + BGP_LABEL_BYTES; int attr_parse_len = 2 + BGP_LABEL_BYTES;
if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto pmsi_tunnel_ignore;
/* Verify that the receiver is expecting "ingress replication" as we /* Verify that the receiver is expecting "ingress replication" as we
* can only support that. * can only support that.
*/ */
@ -3291,7 +3395,7 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
} }
} }
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL));
bgp_attr_set_pmsi_tnl_type(attr, tnl_type); bgp_attr_set_pmsi_tnl_type(attr, tnl_type);
stream_get(&attr->label, peer->curr, BGP_LABEL_BYTES); stream_get(&attr->label, peer->curr, BGP_LABEL_BYTES);
@ -3299,6 +3403,11 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
stream_forward_getp(peer->curr, length - attr_parse_len); stream_forward_getp(peer->curr, length - attr_parse_len);
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
pmsi_tunnel_ignore:
stream_forward_getp(peer->curr, length);
return bgp_attr_ignore(peer, args->type);
} }
/* AIGP attribute (rfc7311) */ /* AIGP attribute (rfc7311) */
@ -3369,7 +3478,7 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
args->total); args->total);
} }
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_OTC); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC));
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
@ -3566,18 +3675,17 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
* unused. They MUST be zero when sent and MUST be ignored when * unused. They MUST be zero when sent and MUST be ignored when
* received. * received.
*/ */
flag = 0xF0 & stream_getc(BGP_INPUT(peer)); flag = CHECK_FLAG(0xF0, stream_getc(BGP_INPUT(peer)));
type = stream_getc(BGP_INPUT(peer)); type = stream_getc(BGP_INPUT(peer));
/* Check whether Extended-Length applies and is in bounds */ /* Check whether Extended-Length applies and is in bounds */
if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN)
&& ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) { && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) {
flog_warn( flog_warn(EC_BGP_EXT_ATTRIBUTE_TOO_SMALL,
EC_BGP_EXT_ATTRIBUTE_TOO_SMALL,
"%s: Extended length set, but just %lu bytes of attr header", "%s: Extended length set, but just %lu bytes of attr header",
peer->host, peer->host,
(unsigned long)(endp (unsigned long)(endp -
- stream_pnt(BGP_INPUT(peer)))); stream_pnt(BGP_INPUT(peer))));
if (peer->sort != BGP_PEER_EBGP) { if (peer->sort != BGP_PEER_EBGP) {
bgp_notify_send(peer->connection, bgp_notify_send(peer->connection,
@ -3924,7 +4032,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
* Finally do the checks on the aspath we did not do yet * Finally do the checks on the aspath we did not do yet
* because we waited for a potentially synthesized aspath. * because we waited for a potentially synthesized aspath.
*/ */
if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) { if (CHECK_FLAG(attr->flag, (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))) {
ret = bgp_attr_aspath_check(peer, attr); ret = bgp_attr_aspath_check(peer, attr);
if (ret != BGP_ATTR_PARSE_PROCEED) if (ret != BGP_ATTR_PARSE_PROCEED)
goto done; goto done;
@ -4102,8 +4210,8 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
case SAFI_MULTICAST: case SAFI_MULTICAST:
case SAFI_LABELED_UNICAST: case SAFI_LABELED_UNICAST:
case SAFI_EVPN: { case SAFI_EVPN: {
if (attr->mp_nexthop_len if (attr->mp_nexthop_len ==
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
stream_putc(s, stream_putc(s,
BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL); BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL);
stream_put(s, &attr->mp_nexthop_global, stream_put(s, &attr->mp_nexthop_global,
@ -4324,12 +4432,12 @@ static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer,
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN); | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, attrtype); stream_putc(s, attrtype);
stream_putw(s, attrlenfield & 0xffff); stream_putw(s, CHECK_FLAG(attrlenfield, 0xffff));
} else { } else {
/* 1-octet length field */ /* 1-octet length field */
stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL); stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL);
stream_putc(s, attrtype); stream_putc(s, attrtype);
stream_putc(s, attrlenfield & 0xff); stream_putc(s, CHECK_FLAG(attrlenfield, 0xff));
} }
if (attrtype == BGP_ATTR_ENCAP) { if (attrtype == BGP_ATTR_ENCAP) {
@ -4440,14 +4548,11 @@ static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer,
} }
/* Make attribute packet. */ /* Make attribute packet. */
bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct stream *s,
struct stream *s, struct attr *attr, struct attr *attr, struct bpacket_attr_vec_arr *vecarr,
struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from,
struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels,
struct peer *from, struct prefix_rd *prd, bool addpath_capable, uint32_t addpath_tx_id)
mpls_label_t *label, uint8_t num_labels,
bool addpath_capable, uint32_t addpath_tx_id,
struct bgp_path_info *bpi)
{ {
size_t cp; size_t cp;
size_t aspath_sizep; size_t aspath_sizep;
@ -4476,6 +4581,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
bgp_packet_mpattr_end(s, mpattrlen_pos); bgp_packet_mpattr_end(s, mpattrlen_pos);
} }
(void)peer_sort(peer);
/* Origin attribute. */ /* Origin attribute. */
stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_ORIGIN); stream_putc(s, BGP_ATTR_ORIGIN);
@ -4569,15 +4676,15 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
&& !peer_cap_enhe(peer, afi, safi)) { && !peer_cap_enhe(peer, afi, safi)) {
afi_t nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len); afi_t nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))) {
stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_NEXT_HOP); stream_putc(s, BGP_ATTR_NEXT_HOP);
bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s, bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
attr); attr);
stream_putc(s, 4); stream_putc(s, 4);
stream_put_ipv4(s, attr->nexthop.s_addr); stream_put_ipv4(s, attr->nexthop.s_addr);
} else if (peer_cap_enhe(from, afi, safi) } else if (peer_cap_enhe(from, afi, safi) ||
|| (nh_afi == AFI_IP6)) { (nh_afi == AFI_IP6)) {
/* /*
* Likely this is the case when an IPv4 prefix was * Likely this is the case when an IPv4 prefix was
* received with Extended Next-hop capability in this * received with Extended Next-hop capability in this
@ -4599,8 +4706,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
} }
/* MED attribute. */ /* MED attribute. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC) if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) ||
|| bgp->maxmed_active) { bgp->maxmed_active) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC); stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
stream_putc(s, 4); stream_putc(s, 4);
@ -4618,14 +4725,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
} }
/* Atomic aggregate. */ /* Atomic aggregate. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) {
stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE); stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
stream_putc(s, 0); stream_putc(s, 0);
} }
/* Aggregator. */ /* Aggregator. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
/* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */ /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_AGGREGATOR); stream_putc(s, BGP_ATTR_AGGREGATOR);
@ -4656,8 +4763,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
} }
/* Community attribute. */ /* Community attribute. */
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) &&
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) { CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
struct community *comm = NULL; struct community *comm = NULL;
comm = bgp_attr_get_community(attr); comm = bgp_attr_get_community(attr);
@ -4681,8 +4788,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
* Large Community attribute. * Large Community attribute.
*/ */
if (CHECK_FLAG(peer->af_flags[afi][safi], if (CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_SEND_LARGE_COMMUNITY) PEER_FLAG_SEND_LARGE_COMMUNITY) &&
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) { CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) { if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
stream_putc(s, stream_putc(s,
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
@ -4712,7 +4819,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_putc(s, BGP_ATTR_ORIGINATOR_ID); stream_putc(s, BGP_ATTR_ORIGINATOR_ID);
stream_putc(s, 4); stream_putc(s, 4);
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) if (CHECK_FLAG(attr->flag,
ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))
stream_put_in_addr(s, &attr->originator_id); stream_put_in_addr(s, &attr->originator_id);
else else
stream_put_in_addr(s, &from->remote_id); stream_put_in_addr(s, &from->remote_id);
@ -4725,7 +4833,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_putc(s, cluster->length + 4); stream_putc(s, cluster->length + 4);
/* If this peer configuration's parent BGP has /* If this peer configuration's parent BGP has
* cluster_id. */ * cluster_id. */
if (bgp->config & BGP_CONFIG_CLUSTER_ID) if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID))
stream_put_in_addr(s, &bgp->cluster_id); stream_put_in_addr(s, &bgp->cluster_id);
else else
stream_put_in_addr(s, &bgp->router_id); stream_put_in_addr(s, &bgp->router_id);
@ -4734,7 +4842,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_putc(s, 4); stream_putc(s, 4);
/* If this peer configuration's parent BGP has /* If this peer configuration's parent BGP has
* cluster_id. */ * cluster_id. */
if (bgp->config & BGP_CONFIG_CLUSTER_ID) if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID))
stream_put_in_addr(s, &bgp->cluster_id); stream_put_in_addr(s, &bgp->cluster_id);
else else
stream_put_in_addr(s, &bgp->router_id); stream_put_in_addr(s, &bgp->router_id);
@ -4902,7 +5010,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
} }
/* PMSI Tunnel */ /* PMSI Tunnel */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PMSI_TUNNEL); stream_putc(s, BGP_ATTR_PMSI_TUNNEL);
stream_putc(s, 9); // Length stream_putc(s, 9); // Length
@ -4915,7 +5023,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
} }
/* OTC */ /* OTC */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_OTC); stream_putc(s, BGP_ATTR_OTC);
stream_putc(s, 4); stream_putc(s, 4);
@ -4923,10 +5031,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
} }
/* AIGP */ /* AIGP */
if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) && if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && AIGP_TRANSMIT_ALLOWED(peer)) {
(CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
peer->sub_sort == BGP_PEER_EBGP_OAD ||
peer->sort != BGP_PEER_EBGP)) {
/* At the moment only AIGP Metric TLV exists for AIGP /* At the moment only AIGP Metric TLV exists for AIGP
* attribute. If more comes in, do not forget to update * attribute. If more comes in, do not forget to update
* attr_len variable to include new ones. * attr_len variable to include new ones.
@ -4936,7 +5041,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc(s, BGP_ATTR_AIGP); stream_putc(s, BGP_ATTR_AIGP);
stream_putc(s, attr_len); stream_putc(s, attr_len);
stream_put_bgp_aigp_tlv_metric(s, bpi); stream_put_bgp_aigp_tlv_metric(s, attr->aigp_metric);
} }
/* Unknown transit attribute. */ /* Unknown transit attribute. */
@ -5006,6 +5111,7 @@ void bgp_attr_init(void)
transit_init(); transit_init();
encap_init(); encap_init();
srv6_init(); srv6_init();
evpn_overlay_init();
} }
void bgp_attr_finish(void) void bgp_attr_finish(void)
@ -5019,6 +5125,7 @@ void bgp_attr_finish(void)
transit_finish(); transit_finish();
encap_finish(); encap_finish();
srv6_finish(); srv6_finish();
evpn_overlay_finish();
} }
/* Make attribute packet. */ /* Make attribute packet. */
@ -5064,7 +5171,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
} }
/* MED attribute. */ /* MED attribute. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC); stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
stream_putc(s, 4); stream_putc(s, 4);
@ -5072,7 +5179,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
} }
/* Local preference. */ /* Local preference. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) {
stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_LOCAL_PREF); stream_putc(s, BGP_ATTR_LOCAL_PREF);
stream_putc(s, 4); stream_putc(s, 4);
@ -5080,14 +5187,14 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
} }
/* Atomic aggregate. */ /* Atomic aggregate. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) {
stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE); stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
stream_putc(s, 0); stream_putc(s, 0);
} }
/* Aggregator. */ /* Aggregator. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_AGGREGATOR); stream_putc(s, BGP_ATTR_AGGREGATOR);
stream_putc(s, 8); stream_putc(s, 8);
@ -5096,7 +5203,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
} }
/* Community attribute. */ /* Community attribute. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
struct community *comm = NULL; struct community *comm = NULL;
comm = bgp_attr_get_community(attr); comm = bgp_attr_get_community(attr);
@ -5107,9 +5214,8 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putw(s, comm->size * 4); stream_putw(s, comm->size * 4);
} else { } else {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
BGP_ATTR_FLAG_OPTIONAL BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putc(s, comm->size * 4); stream_putc(s, comm->size * 4);
} }
@ -5117,7 +5223,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
} }
/* Large Community attribute. */ /* Large Community attribute. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) { if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
stream_putc(s, stream_putc(s,
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
@ -5126,9 +5232,8 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
stream_putw(s, stream_putw(s,
lcom_length(bgp_attr_get_lcommunity(attr))); lcom_length(bgp_attr_get_lcommunity(attr)));
} else { } else {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
BGP_ATTR_FLAG_OPTIONAL BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putc(s, stream_putc(s,
lcom_length(bgp_attr_get_lcommunity(attr))); lcom_length(bgp_attr_get_lcommunity(attr)));
@ -5172,11 +5277,10 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
} }
/* Prefix SID */ /* Prefix SID */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID))) {
if (attr->label_index != BGP_INVALID_LABEL_INDEX) { if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
BGP_ATTR_FLAG_OPTIONAL BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PREFIX_SID); stream_putc(s, BGP_ATTR_PREFIX_SID);
stream_putc(s, 10); stream_putc(s, 10);
stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX); stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
@ -5188,7 +5292,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
} }
/* OTC */ /* OTC */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_OTC); stream_putc(s, BGP_ATTR_OTC);
stream_putc(s, 4); stream_putc(s, 4);
@ -5196,7 +5300,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
} }
/* AIGP */ /* AIGP */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP)) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP))) {
/* At the moment only AIGP Metric TLV exists for AIGP /* At the moment only AIGP Metric TLV exists for AIGP
* attribute. If more comes in, do not forget to update * attribute. If more comes in, do not forget to update
* attr_len variable to include new ones. * attr_len variable to include new ones.
@ -5206,7 +5310,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_AIGP); stream_putc(s, BGP_ATTR_AIGP);
stream_putc(s, attr_len); stream_putc(s, attr_len);
stream_put_bgp_aigp_tlv_metric(s, bpi); stream_put_bgp_aigp_tlv_metric(s, attr->aigp_metric);
} }
/* Return total size of attribute. */ /* Return total size of attribute. */

View file

@ -197,9 +197,6 @@ struct attr {
#define ATTR_ES_L3_NHG_ACTIVE (1 << 6) #define ATTR_ES_L3_NHG_ACTIVE (1 << 6)
#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) #define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE)
/* NA router flag (R-bit) support in EVPN */
uint8_t router_flag;
/* Distance as applied by Route map */ /* Distance as applied by Route map */
uint8_t distance; uint8_t distance;
@ -212,7 +209,7 @@ struct attr {
/* has the route-map changed any attribute? /* has the route-map changed any attribute?
Used on the peer outbound side. */ Used on the peer outbound side. */
uint32_t rmap_change_flags; uint16_t rmap_change_flags;
/* Multi-Protocol Nexthop, AFI IPv6 */ /* Multi-Protocol Nexthop, AFI IPv6 */
struct in6_addr mp_nexthop_global; struct in6_addr mp_nexthop_global;
@ -256,11 +253,12 @@ struct attr {
/* MP Nexthop length */ /* MP Nexthop length */
uint8_t mp_nexthop_len; uint8_t mp_nexthop_len;
/* Static MAC for EVPN */ /* EVPN flags */
uint8_t sticky; uint8_t evpn_flags;
#define ATTR_EVPN_FLAG_STICKY (1 << 0)
/* Flag for default gateway extended community in EVPN */ #define ATTR_EVPN_FLAG_DEFAULT_GW (1 << 1)
uint8_t default_gw; /* NA router flag (R-bit) support in EVPN */
#define ATTR_EVPN_FLAG_ROUTER (1 << 2)
/* route tag */ /* route tag */
route_tag_t tag; route_tag_t tag;
@ -280,7 +278,7 @@ struct attr {
struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */ struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */
#endif #endif
/* EVPN */ /* EVPN */
struct bgp_route_evpn evpn_overlay; struct bgp_route_evpn *evpn_overlay;
/* EVPN MAC Mobility sequence number, if any. */ /* EVPN MAC Mobility sequence number, if any. */
uint32_t mm_seqnum; uint32_t mm_seqnum;
@ -295,7 +293,7 @@ struct attr {
/* EVPN local router-mac */ /* EVPN local router-mac */
struct ethaddr rmac; struct ethaddr rmac;
uint16_t encap_tunneltype; uint8_t encap_tunneltype;
/* rmap set table */ /* rmap set table */
uint32_t rmap_table_id; uint32_t rmap_table_id;
@ -355,7 +353,7 @@ struct transit {
__builtin_choose_expr((X) >= 1 && (X) <= 64, 1ULL << ((X)-1), (void)0) __builtin_choose_expr((X) >= 1 && (X) <= 64, 1ULL << ((X)-1), (void)0)
#define BGP_CLUSTER_LIST_LENGTH(attr) \ #define BGP_CLUSTER_LIST_LENGTH(attr) \
(((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) \ (CHECK_FLAG((attr)->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) \
? bgp_attr_get_cluster((attr))->length \ ? bgp_attr_get_cluster((attr))->length \
: 0) : 0)
@ -389,12 +387,12 @@ extern struct attr *bgp_attr_aggregate_intern(
struct community *community, struct ecommunity *ecommunity, struct community *community, struct ecommunity *ecommunity,
struct lcommunity *lcommunity, struct bgp_aggregate *aggregate, struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
uint8_t atomic_aggregate, const struct prefix *p); uint8_t atomic_aggregate, const struct prefix *p);
extern bgp_size_t bgp_packet_attribute( extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct stream *s,
struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, struct attr *attr, struct bpacket_attr_vec_arr *vecarr,
struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, struct prefix *p, afi_t afi, safi_t safi, struct peer *from,
safi_t safi, struct peer *from, struct prefix_rd *prd, struct prefix_rd *prd, mpls_label_t *label,
mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint8_t num_labels, bool addpath_capable,
uint32_t addpath_tx_id, struct bgp_path_info *bpi); uint32_t addpath_tx_id);
extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi, extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
const struct prefix *p); const struct prefix *p);
extern bool attrhash_cmp(const void *arg1, const void *arg2); extern bool attrhash_cmp(const void *arg1, const void *arg2);
@ -587,6 +585,10 @@ static inline void bgp_attr_set_transit(struct attr *attr,
attr->transit = transit; attr->transit = transit;
} }
#define AIGP_TRANSMIT_ALLOWED(peer) \
(CHECK_FLAG((peer)->flags, PEER_FLAG_AIGP) || ((peer)->sub_sort == BGP_PEER_EBGP_OAD) || \
((peer)->sort != BGP_PEER_EBGP))
static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr) static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr)
{ {
return attr->aigp_metric; return attr->aigp_metric;
@ -595,11 +597,19 @@ static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr)
static inline void bgp_attr_set_aigp_metric(struct attr *attr, uint64_t aigp) static inline void bgp_attr_set_aigp_metric(struct attr *attr, uint64_t aigp)
{ {
attr->aigp_metric = aigp; attr->aigp_metric = aigp;
if (aigp)
SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)); SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP));
} }
static inline uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi)
{
uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr);
if (bpi->nexthop)
return aigp + bpi->nexthop->metric;
else
return aigp;
}
static inline struct cluster_list *bgp_attr_get_cluster(const struct attr *attr) static inline struct cluster_list *bgp_attr_get_cluster(const struct attr *attr)
{ {
return attr->cluster1; return attr->cluster1;
@ -616,16 +626,16 @@ static inline void bgp_attr_set_cluster(struct attr *attr,
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST));
} }
static inline const struct bgp_route_evpn * static inline struct bgp_route_evpn *
bgp_attr_get_evpn_overlay(const struct attr *attr) bgp_attr_get_evpn_overlay(const struct attr *attr)
{ {
return &attr->evpn_overlay; return attr->evpn_overlay;
} }
static inline void bgp_attr_set_evpn_overlay(struct attr *attr, static inline void bgp_attr_set_evpn_overlay(struct attr *attr,
struct bgp_route_evpn *eo) struct bgp_route_evpn *bre)
{ {
memcpy(&attr->evpn_overlay, eo, sizeof(struct bgp_route_evpn)); attr->evpn_overlay = bre;
} }
static inline struct bgp_attr_encap_subtlv * static inline struct bgp_attr_encap_subtlv *
@ -648,5 +658,6 @@ bgp_attr_set_vnc_subtlvs(struct attr *attr,
} }
extern bool route_matches_soo(struct bgp_path_info *pi, struct ecommunity *soo); extern bool route_matches_soo(struct bgp_path_info *pi, struct ecommunity *soo);
extern void evpn_overlay_free(struct bgp_route_evpn *bre);
#endif /* _QUAGGA_BGP_ATTR_H */ #endif /* _QUAGGA_BGP_ATTR_H */

View file

@ -24,6 +24,13 @@
bool bgp_route_evpn_same(const struct bgp_route_evpn *e1, bool bgp_route_evpn_same(const struct bgp_route_evpn *e1,
const struct bgp_route_evpn *e2) const struct bgp_route_evpn *e2)
{ {
if (!e1 && e2)
return false;
if (!e2 && e1)
return false;
if (!e1 && !e2)
return true;
return (e1->type == e2->type && return (e1->type == e2->type &&
!memcmp(&(e1->eth_s_id), &(e2->eth_s_id), sizeof(esi_t)) && !memcmp(&(e1->eth_s_id), &(e2->eth_s_id), sizeof(esi_t)) &&
!ipaddr_cmp(&(e1->gw_ip), &(e2->gw_ip))); !ipaddr_cmp(&(e1->gw_ip), &(e2->gw_ip)));
@ -115,14 +122,14 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
/* /*
* return true if attr contains default gw extended community * return true if attr contains default gw extended community
*/ */
uint8_t bgp_attr_default_gw(struct attr *attr) void bgp_attr_default_gw(struct attr *attr)
{ {
struct ecommunity *ecom; struct ecommunity *ecom;
uint32_t i; uint32_t i;
ecom = bgp_attr_get_ecommunity(attr); ecom = bgp_attr_get_ecommunity(attr);
if (!ecom || !ecom->size) if (!ecom || !ecom->size)
return 0; return;
/* If there is a default gw extendd community return true otherwise /* If there is a default gw extendd community return true otherwise
* return 0 */ * return 0 */
@ -136,10 +143,9 @@ uint8_t bgp_attr_default_gw(struct attr *attr)
if ((type == ECOMMUNITY_ENCODE_OPAQUE if ((type == ECOMMUNITY_ENCODE_OPAQUE
&& sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW)) && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
return 1; SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
} }
UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
return 0;
} }
/* /*
@ -183,7 +189,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg)
* Fetch and return the sequence number from MAC Mobility extended * Fetch and return the sequence number from MAC Mobility extended
* community, if present, else 0. * community, if present, else 0.
*/ */
uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr)
{ {
struct ecommunity *ecom; struct ecommunity *ecom;
uint32_t i; uint32_t i;
@ -212,10 +218,11 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
continue; continue;
flags = *pnt++; flags = *pnt++;
if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) if (CHECK_FLAG(flags,
*sticky = 1; ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY))
SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
else else
*sticky = 0; UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
pnt++; pnt++;
pnt = ptr_get_be32(pnt, &seq_num); pnt = ptr_get_be32(pnt, &seq_num);
@ -229,8 +236,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
/* /*
* return true if attr contains router flag extended community * return true if attr contains router flag extended community
*/ */
void bgp_attr_evpn_na_flag(struct attr *attr, void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy)
uint8_t *router_flag, bool *proxy)
{ {
struct ecommunity *ecom; struct ecommunity *ecom;
uint32_t i; uint32_t i;
@ -253,10 +259,12 @@ void bgp_attr_evpn_na_flag(struct attr *attr,
sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) { sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) {
val = *pnt++; val = *pnt++;
if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) if (CHECK_FLAG(val,
*router_flag = 1; ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG))
SET_FLAG(attr->evpn_flags,
ATTR_EVPN_FLAG_ROUTER);
if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG) if (CHECK_FLAG(val, ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG))
*proxy = true; *proxy = true;
break; break;

View file

@ -23,6 +23,7 @@ enum overlay_index_type {
* MAC overlay index is stored in the RMAC attribute. * MAC overlay index is stored in the RMAC attribute.
*/ */
struct bgp_route_evpn { struct bgp_route_evpn {
unsigned long refcnt;
enum overlay_index_type type; enum overlay_index_type type;
esi_t eth_s_id; esi_t eth_s_id;
struct ipaddr gw_ip; struct ipaddr gw_ip;
@ -36,12 +37,10 @@ extern void bgp_add_routermac_ecom(struct attr *attr,
extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
struct prefix *dst); struct prefix *dst);
extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr);
uint8_t *sticky); extern void bgp_attr_default_gw(struct attr *attr);
extern uint8_t bgp_attr_default_gw(struct attr *attr);
extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag, extern void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy);
bool *proxy);
extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg); extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg);

View file

@ -934,9 +934,8 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
stream_putw(s, 0); stream_putw(s, 0);
/* 5: Encode all the attributes, except MP_REACH_NLRI attr. */ /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
total_attr_len = total_attr_len = bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi, safi, peer,
bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi, NULL, NULL, 0, 0, 0);
safi, peer, NULL, NULL, 0, 0, 0, NULL);
/* space check? */ /* space check? */
@ -1047,7 +1046,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
{ {
uint8_t bpi_num_labels; uint8_t bpi_num_labels, adjin_num_labels;
afi_t afi; afi_t afi;
safi_t safi; safi_t safi;
@ -1241,11 +1240,12 @@ afibreak:
bpi_num_labels ? bpi->extra->labels->label : NULL, bpi_num_labels ? bpi->extra->labels->label : NULL,
bpi_num_labels); bpi_num_labels);
if (adjin) if (adjin) {
/* TODO: set label here when adjin supports labels */ adjin_num_labels = adjin->labels ? adjin->labels->num_labels : 0;
bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd,
bn_p, prd, adjin->attr, afi, safi, adjin->uptime, adjin->attr, afi, safi, adjin->uptime,
NULL, 0); adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels);
}
if (bn) if (bn)
bgp_dest_unlock_node(bn); bgp_dest_unlock_node(bn);
@ -1382,7 +1382,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
struct peer *peer; struct peer *peer;
struct bgp_dest *bn = NULL; struct bgp_dest *bn = NULL;
bool written = false; bool written = false;
uint8_t bpi_num_labels; uint8_t bpi_num_labels, adjin_num_labels;
bqe = bmp_pull(bmp); bqe = bmp_pull(bmp);
if (!bqe) if (!bqe)
@ -1453,10 +1453,11 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
if (adjin->peer == peer) if (adjin->peer == peer)
break; break;
} }
/* TODO: set label here when adjin supports labels */ adjin_num_labels = adjin && adjin->labels ? adjin->labels->num_labels : 0;
bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd,
&bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi, adjin ? adjin->attr : NULL, afi, safi,
adjin ? adjin->uptime : monotime(NULL), NULL, 0); adjin ? adjin->uptime : monotime(NULL),
adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels);
written = true; written = true;
} }
@ -2543,9 +2544,9 @@ DEFPY(bmp_monitor_cfg, bmp_monitor_cmd,
prev = bt->afimon[afi][safi]; prev = bt->afimon[afi][safi];
if (no) if (no)
bt->afimon[afi][safi] &= ~flag; UNSET_FLAG(bt->afimon[afi][safi], flag);
else else
bt->afimon[afi][safi] |= flag; SET_FLAG(bt->afimon[afi][safi], flag);
if (prev == bt->afimon[afi][safi]) if (prev == bt->afimon[afi][safi])
return CMD_SUCCESS; return CMD_SUCCESS;
@ -2743,7 +2744,7 @@ DEFPY(show_bmp,
} }
out = ttable_dump(tt, "\n"); out = ttable_dump(tt, "\n");
vty_out(vty, "%s", out); vty_out(vty, "%s", out);
XFREE(MTYPE_TMP, out); XFREE(MTYPE_TMP_TTABLE, out);
ttable_del(tt); ttable_del(tt);
vty_out(vty, "\n %zu connected clients:\n", vty_out(vty, "\n %zu connected clients:\n",
@ -2770,7 +2771,7 @@ DEFPY(show_bmp,
} }
out = ttable_dump(tt, "\n"); out = ttable_dump(tt, "\n");
vty_out(vty, "%s", out); vty_out(vty, "%s", out);
XFREE(MTYPE_TMP, out); XFREE(MTYPE_TMP_TTABLE, out);
ttable_del(tt); ttable_del(tt);
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
@ -2828,8 +2829,7 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
afi2str_lower(afi), safi2str(safi)); afi2str_lower(afi), safi2str(safi));
} }
frr_each (bmp_listeners, &bt->listeners, bl) frr_each (bmp_listeners, &bt->listeners, bl)
vty_out(vty, " \n bmp listener %pSU port %d\n", vty_out(vty, " bmp listener %pSU port %d\n", &bl->addr, bl->port);
&bl->addr, bl->port);
frr_each (bmp_actives, &bt->actives, ba) { frr_each (bmp_actives, &bt->actives, ba) {
vty_out(vty, " bmp connect %s port %u min-retry %u max-retry %u", vty_out(vty, " bmp connect %s port %u min-retry %u max-retry %u",

View file

@ -69,7 +69,7 @@ static void attr_parse(struct stream *s, uint16_t len)
flag = stream_getc(s); flag = stream_getc(s);
type = stream_getc(s); type = stream_getc(s);
if (flag & BGP_ATTR_FLAG_EXTLEN) if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN))
length = stream_getw(s); length = stream_getw(s);
else else
length = stream_getc(s); length = stream_getc(s);

View file

@ -182,7 +182,7 @@ community_list_insert(struct community_list_handler *ch, const char *name,
} }
/* In case of name is all digit character */ /* In case of name is all digit character */
if (i == strlen(name)) { if (i == strlen(name) && number <= COMMUNITY_LIST_NUMBER_MAX) {
new->sort = COMMUNITY_LIST_NUMBER; new->sort = COMMUNITY_LIST_NUMBER;
/* Set access_list to number list. */ /* Set access_list to number list. */
@ -496,8 +496,8 @@ static char *community_str_get(struct community *com, int i)
break; break;
default: default:
str = XSTRDUP(MTYPE_COMMUNITY_STR, "65536:65535"); str = XSTRDUP(MTYPE_COMMUNITY_STR, "65536:65535");
as = (comval >> 16) & 0xFFFF; as = CHECK_FLAG((comval >> 16), 0xFFFF);
val = comval & 0xFFFF; val = CHECK_FLAG(comval, 0xFFFF);
snprintf(str, strlen(str), "%u:%d", as, val); snprintf(str, strlen(str), "%u:%d", as, val);
break; break;
} }

View file

@ -20,6 +20,10 @@
/* Number and string based community-list name. */ /* Number and string based community-list name. */
#define COMMUNITY_LIST_STRING 0 #define COMMUNITY_LIST_STRING 0
#define COMMUNITY_LIST_NUMBER 1 #define COMMUNITY_LIST_NUMBER 1
/* The numbered community-list (including large/ext communities)
* have a range between 1-500.
*/
#define COMMUNITY_LIST_NUMBER_MAX 500
#define COMMUNITY_SEQ_NUMBER_AUTO -1 #define COMMUNITY_SEQ_NUMBER_AUTO -1

View file

@ -416,13 +416,12 @@ static void set_community_string(struct community *com, bool make_json,
} }
break; break;
default: default:
as = (comval >> 16) & 0xFFFF; as = CHECK_FLAG((comval >> 16), 0xFFFF);
val = comval & 0xFFFF; val = CHECK_FLAG(comval, 0xFFFF);
char buf[32]; char buf[32];
snprintf(buf, sizeof(buf), "%u:%d", as, val); snprintf(buf, sizeof(buf), "%u:%d", as, val);
const char *com2alias = const char *com2alias =
translate_alias ? bgp_community2alias(buf) translate_alias ? bgp_community2alias(buf) : buf;
: buf;
strlcat(str, com2alias, len); strlcat(str, com2alias, len);
if (make_json) { if (make_json) {

View file

@ -779,7 +779,8 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
bgp = bgp_get_default(); bgp = bgp_get_default();
if (bgp == NULL) {
if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "No BGP process is configured\n"); vty_out(vty, "No BGP process is configured\n");
return CMD_WARNING; return CMD_WARNING;
} }

View file

@ -2558,7 +2558,7 @@ static int bgp_debug_per_prefix(const struct prefix *p,
struct bgp_debug_filter *filter; struct bgp_debug_filter *filter;
struct listnode *node, *nnode; struct listnode *node, *nnode;
if (term_bgp_debug_type & BGP_DEBUG_TYPE) { if (CHECK_FLAG(term_bgp_debug_type, BGP_DEBUG_TYPE)) {
/* We are debugging all prefixes so return true */ /* We are debugging all prefixes so return true */
if (!per_prefix_list || list_isempty(per_prefix_list)) if (!per_prefix_list || list_isempty(per_prefix_list))
return 1; return 1;
@ -2591,7 +2591,7 @@ static bool bgp_debug_per_peer(char *host, const struct prefix *p,
struct bgp_debug_filter *filter; struct bgp_debug_filter *filter;
struct listnode *node, *nnode; struct listnode *node, *nnode;
if (term_bgp_debug_type & BGP_DEBUG_TYPE) { if (CHECK_FLAG(term_bgp_debug_type, BGP_DEBUG_TYPE)) {
/* We are debugging all peers so return true */ /* We are debugging all peers so return true */
if (!per_peer_list || list_isempty(per_peer_list)) if (!per_peer_list || list_isempty(per_peer_list))
return true; return true;

View file

@ -515,7 +515,7 @@ static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type,
/* Fill in the values. */ /* Fill in the values. */
eval->val[0] = type; eval->val[0] = type;
if (!trans) if (!trans)
eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; SET_FLAG(eval->val[0], ECOMMUNITY_FLAG_NON_TRANSITIVE);
eval->val[1] = sub_type; eval->val[1] = sub_type;
if (type == ECOMMUNITY_ENCODE_AS) { if (type == ECOMMUNITY_ENCODE_AS) {
encode_route_target_as(as, val, eval, trans); encode_route_target_as(as, val, eval, trans);
@ -1293,11 +1293,12 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
== ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL) { == ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL) {
uint8_t flags = *++pnt; uint8_t flags = *++pnt;
snprintf(encbuf, snprintf(encbuf, sizeof(encbuf),
sizeof(encbuf), "ESI-label-Rt:%s", "ESI-label-Rt:%s",
(flags & CHECK_FLAG(flags,
ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG) ? ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG)
"SA":"AA"); ? "SA"
: "AA");
} else if (*pnt } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION) { == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION) {
uint8_t alg; uint8_t alg;
@ -1337,12 +1338,11 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
char buf[ECOMMUNITY_STRLEN]; char buf[ECOMMUNITY_STRLEN];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
ecommunity_rt_soo_str_internal(buf, sizeof(buf), ecommunity_rt_soo_str_internal(
(const uint8_t *)pnt, buf, sizeof(buf), (const uint8_t *)pnt,
type & CHECK_FLAG(type,
~ECOMMUNITY_ENCODE_TRANS_EXP, ~ECOMMUNITY_ENCODE_TRANS_EXP),
ECOMMUNITY_ROUTE_TARGET, ECOMMUNITY_ROUTE_TARGET, format,
format,
ecom->unit_size); ecom->unit_size);
snprintf(encbuf, sizeof(encbuf), "%s", buf); snprintf(encbuf, sizeof(encbuf), "%s", buf);
} else if (sub_type == } else if (sub_type ==
@ -1350,10 +1350,10 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
char buf[64]; char buf[64];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
ecommunity_rt_soo_str_internal(buf, sizeof(buf), ecommunity_rt_soo_str_internal(
(const uint8_t *)pnt, buf, sizeof(buf), (const uint8_t *)pnt,
type & CHECK_FLAG(type,
~ECOMMUNITY_ENCODE_TRANS_EXP, ~ECOMMUNITY_ENCODE_TRANS_EXP),
ECOMMUNITY_ROUTE_TARGET, ECOMMUNITY_ROUTE_TARGET,
ECOMMUNITY_FORMAT_DISPLAY, ECOMMUNITY_FORMAT_DISPLAY,
ecom->unit_size); ecom->unit_size);
@ -1363,10 +1363,10 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
char buf[16]; char buf[16];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
ecommunity_rt_soo_str(buf, sizeof(buf), ecommunity_rt_soo_str(
(const uint8_t *)pnt, buf, sizeof(buf), (const uint8_t *)pnt,
type & CHECK_FLAG(type,
~ECOMMUNITY_ENCODE_TRANS_EXP, ~ECOMMUNITY_ENCODE_TRANS_EXP),
ECOMMUNITY_ROUTE_TARGET, ECOMMUNITY_ROUTE_TARGET,
ECOMMUNITY_FORMAT_DISPLAY); ECOMMUNITY_FORMAT_DISPLAY);
snprintf(encbuf, sizeof(encbuf), snprintf(encbuf, sizeof(encbuf),
@ -1640,12 +1640,13 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
} else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_ACTION) { } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_ACTION) {
api->action = ACTION_TRAFFIC_ACTION; api->action = ACTION_TRAFFIC_ACTION;
/* else distribute code is set by default */ /* else distribute code is set by default */
if (ecom_eval->val[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL)) if (CHECK_FLAG(ecom_eval->val[5],
api->u.za.filter |= TRAFFIC_ACTION_TERMINATE; (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL)))
SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_TERMINATE);
else else
api->u.za.filter |= TRAFFIC_ACTION_DISTRIBUTE; SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_DISTRIBUTE);
if (ecom_eval->val[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE) if (ecom_eval->val[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE)
api->u.za.filter |= TRAFFIC_ACTION_SAMPLE; SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_SAMPLE);
} else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_MARKING) { } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_MARKING) {
api->action = ACTION_MARKING; api->action = ACTION_MARKING;
@ -1940,7 +1941,7 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
return new; return new;
type = *eval; type = *eval;
if (type & ECOMMUNITY_FLAG_NON_TRANSITIVE) if (CHECK_FLAG(type, ECOMMUNITY_FLAG_NON_TRANSITIVE))
return new; return new;
/* Transitive link-bandwidth exists, replace with the passed /* Transitive link-bandwidth exists, replace with the passed

View file

@ -155,12 +155,12 @@ struct ecommunity_ip6 {
/* Extended community value is eight octet. */ /* Extended community value is eight octet. */
struct ecommunity_val { struct ecommunity_val {
char val[ECOMMUNITY_SIZE]; uint8_t val[ECOMMUNITY_SIZE];
}; };
/* IPv6 Extended community value is eight octet. */ /* IPv6 Extended community value is eight octet. */
struct ecommunity_val_ipv6 { struct ecommunity_val_ipv6 {
char val[IPV6_ECOMMUNITY_SIZE]; uint8_t val[IPV6_ECOMMUNITY_SIZE];
}; };
#define ecom_length_size(X, Y) ((X)->size * (Y)) #define ecom_length_size(X, Y) ((X)->size * (Y))

View file

@ -117,7 +117,7 @@ int vni_list_cmp(void *p1, void *p2)
static unsigned int vrf_import_rt_hash_key_make(const void *p) static unsigned int vrf_import_rt_hash_key_make(const void *p)
{ {
const struct vrf_irt_node *irt = p; const struct vrf_irt_node *irt = p;
const char *pnt = irt->rt.val; const uint8_t *pnt = irt->rt.val;
return jhash(pnt, 8, 0x5abc1234); return jhash(pnt, 8, 0x5abc1234);
} }
@ -229,7 +229,7 @@ static int is_vrf_present_in_irt_vrfs(struct list *vrfs, struct bgp *bgp_vrf)
static unsigned int import_rt_hash_key_make(const void *p) static unsigned int import_rt_hash_key_make(const void *p)
{ {
const struct irt_node *irt = p; const struct irt_node *irt = p;
const char *pnt = irt->rt.val; const uint8_t *pnt = irt->rt.val;
return jhash(pnt, 8, 0xdeadbeef); return jhash(pnt, 8, 0xdeadbeef);
} }
@ -621,7 +621,7 @@ static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl,
struct listnode *node; struct listnode *node;
if (bgp->advertise_autort_rfc8365) if (bgp->advertise_autort_rfc8365)
vni |= EVPN_AUTORT_VXLAN; SET_FLAG(vni, EVPN_AUTORT_VXLAN);
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true); encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true);
ecomadd = ecommunity_new(); ecomadd = ecommunity_new();
@ -1159,9 +1159,8 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
} }
/* Add MAC mobility (sticky) if needed. */ /* Add MAC mobility (sticky) if needed. */
if (attr->sticky) { if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY)) {
seqnum = 0; seqnum = 0;
memset(&ecom_sticky, 0, sizeof(ecom_sticky));
encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); encode_mac_mobility_extcomm(1, seqnum, &eval_sticky);
ecom_sticky.size = 1; ecom_sticky.size = 1;
ecom_sticky.unit_size = ECOMMUNITY_SIZE; ecom_sticky.unit_size = ECOMMUNITY_SIZE;
@ -1179,8 +1178,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
} }
/* Add default gateway, if needed. */ /* Add default gateway, if needed. */
if (attr->default_gw) { if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) {
memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
encode_default_gw_extcomm(&eval_default_gw); encode_default_gw_extcomm(&eval_default_gw);
ecom_default_gw.size = 1; ecom_default_gw.size = 1;
ecom_default_gw.unit_size = ECOMMUNITY_SIZE; ecom_default_gw.unit_size = ECOMMUNITY_SIZE;
@ -1191,9 +1189,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
} }
proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT); proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT);
if (attr->router_flag || proxy) { if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER) || proxy) {
memset(&ecom_na, 0, sizeof(ecom_na)); encode_na_flag_extcomm(&eval_na,
encode_na_flag_extcomm(&eval_na, attr->router_flag, proxy); CHECK_FLAG(attr->evpn_flags,
ATTR_EVPN_FLAG_ROUTER),
proxy);
ecom_na.size = 1; ecom_na.size = 1;
ecom_na.unit_size = ECOMMUNITY_SIZE; ecom_na.unit_size = ECOMMUNITY_SIZE;
ecom_na.val = (uint8_t *)eval_na.val; ecom_na.val = (uint8_t *)eval_na.val;
@ -1278,12 +1278,15 @@ enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn
flags = 0; flags = 0;
if (pi->sub_type == BGP_ROUTE_IMPORTED) { if (pi->sub_type == BGP_ROUTE_IMPORTED) {
if (pi->attr->sticky) if (CHECK_FLAG(pi->attr->evpn_flags,
ATTR_EVPN_FLAG_STICKY))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
if (pi->attr->default_gw) if (CHECK_FLAG(pi->attr->evpn_flags,
ATTR_EVPN_FLAG_DEFAULT_GW))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
if (is_evpn_prefix_ipaddr_v6(p) && if (is_evpn_prefix_ipaddr_v6(p) &&
pi->attr->router_flag) CHECK_FLAG(pi->attr->evpn_flags,
ATTR_EVPN_FLAG_ROUTER))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
seq = mac_mobility_seqnum(pi->attr); seq = mac_mobility_seqnum(pi->attr);
@ -1311,12 +1314,11 @@ enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn
* flag set install the local entry as a router entry * flag set install the local entry as a router entry
*/ */
if (is_evpn_prefix_ipaddr_v6(p) && if (is_evpn_prefix_ipaddr_v6(p) &&
(pi->attr->es_flags & CHECK_FLAG(pi->attr->es_flags, ATTR_ES_PEER_ROUTER))
ATTR_ES_PEER_ROUTER))
SET_FLAG(flags, SET_FLAG(flags,
ZEBRA_MACIP_TYPE_ROUTER_FLAG); ZEBRA_MACIP_TYPE_ROUTER_FLAG);
if (!(pi->attr->es_flags & ATTR_ES_PEER_ACTIVE)) if (!CHECK_FLAG(pi->attr->es_flags, ATTR_ES_PEER_ACTIVE))
SET_FLAG(flags, SET_FLAG(flags,
ZEBRA_MACIP_TYPE_PROXY_ADVERT); ZEBRA_MACIP_TYPE_PROXY_ADVERT);
} }
@ -1608,12 +1610,16 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
struct bgp_labels bgp_labels = {}; struct bgp_labels bgp_labels = {};
struct bgp_path_info *local_pi = NULL; struct bgp_path_info *local_pi = NULL;
struct bgp_path_info *tmp_pi = NULL; struct bgp_path_info *tmp_pi = NULL;
struct aspath *new_aspath;
struct attr static_attr = { 0 };
*route_changed = 0; *route_changed = 0;
/* See if this is an update of an existing route, or a new add. */ /* See if this is an update of an existing route, or a new add. */
local_pi = bgp_evpn_route_get_local_path(bgp_evpn, dest); local_pi = bgp_evpn_route_get_local_path(bgp_evpn, dest);
static_attr = *attr;
/* /*
* create a new route entry if one doesn't exist. * create a new route entry if one doesn't exist.
* Otherwise see if route attr has changed * Otherwise see if route attr has changed
@ -1623,8 +1629,19 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
/* route has changed as this is the first entry */ /* route has changed as this is the first entry */
*route_changed = 1; *route_changed = 1;
/*
* if the asn values are different, copy the as of
* source vrf to the target entry
*/
if (bgp_vrf->as != bgp_evpn->as) {
new_aspath = aspath_dup(static_attr.aspath);
new_aspath = aspath_add_seq(new_aspath, bgp_vrf->as);
static_attr.aspath = new_aspath;
}
/* Add (or update) attribute to hash. */ /* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(attr); attr_new = bgp_attr_intern(&static_attr);
bgp_attr_flush(&static_attr);
/* create the route info from attribute */ /* create the route info from attribute */
pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0, pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
@ -1738,20 +1755,30 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) { BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) {
if (src_attr && if (src_attr &&
!IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) { !IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) {
attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; struct bgp_route_evpn *bre =
SET_IPADDR_V6(&attr.evpn_overlay.gw_ip); XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6, sizeof(struct bgp_route_evpn));
bre->type = OVERLAY_INDEX_GATEWAY_IP;
SET_IPADDR_V6(&bre->gw_ip);
memcpy(&bre->gw_ip.ipaddr_v6,
&src_attr->mp_nexthop_global, &src_attr->mp_nexthop_global,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
bgp_attr_set_evpn_overlay(&attr, bre);
} }
} else if (src_afi == AFI_IP && } else if (src_afi == AFI_IP &&
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) { BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) {
if (src_attr && src_attr->nexthop.s_addr != 0) { if (src_attr && src_attr->nexthop.s_addr != 0) {
attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; struct bgp_route_evpn *bre =
SET_IPADDR_V4(&attr.evpn_overlay.gw_ip); XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4, sizeof(struct bgp_route_evpn));
&src_attr->nexthop, sizeof(struct in_addr));
bre->type = OVERLAY_INDEX_GATEWAY_IP;
SET_IPADDR_V4(&bre->gw_ip);
memcpy(&bre->gw_ip.ipaddr_v4, &src_attr->nexthop,
sizeof(struct in_addr));
bgp_attr_set_evpn_overlay(&attr, bre);
} }
} }
@ -1840,7 +1867,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi,
*active_on_peer = true; *active_on_peer = true;
} }
if (second_best_path->attr->router_flag) if (CHECK_FLAG(second_best_path->attr->evpn_flags,
ATTR_EVPN_FLAG_ROUTER))
*peer_router = true; *peer_router = true;
/* we use both proxy and non-proxy imports to /* we use both proxy and non-proxy imports to
@ -1883,42 +1911,44 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp,
mac); mac);
attr->mm_sync_seqnum = max_sync_seq; attr->mm_sync_seqnum = max_sync_seq;
if (active_on_peer) if (active_on_peer)
attr->es_flags |= ATTR_ES_PEER_ACTIVE; SET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE);
else else
attr->es_flags &= ~ATTR_ES_PEER_ACTIVE; UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE);
if (proxy_from_peer) if (proxy_from_peer)
attr->es_flags |= ATTR_ES_PEER_PROXY; SET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY);
else else
attr->es_flags &= ~ATTR_ES_PEER_PROXY; UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY);
if (peer_router) if (peer_router)
attr->es_flags |= ATTR_ES_PEER_ROUTER; SET_FLAG(attr->es_flags, ATTR_ES_PEER_ROUTER);
else else
attr->es_flags &= ~ATTR_ES_PEER_ROUTER; UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ROUTER);
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) { if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
char esi_buf[ESI_STR_LEN]; char esi_buf[ESI_STR_LEN];
zlog_debug( zlog_debug("setup sync info for %pFX es %s max_seq %d %s%s%s",
"setup sync info for %pFX es %s max_seq %d %s%s%s",
evp, evp,
esi_to_str(esi, esi_buf, esi_to_str(esi, esi_buf,
sizeof(esi_buf)), sizeof(esi_buf)),
max_sync_seq, max_sync_seq,
(attr->es_flags & ATTR_ES_PEER_ACTIVE) CHECK_FLAG(attr->es_flags,
ATTR_ES_PEER_ACTIVE)
? "peer-active " ? "peer-active "
: "", : "",
(attr->es_flags & ATTR_ES_PEER_PROXY) CHECK_FLAG(attr->es_flags,
ATTR_ES_PEER_PROXY)
? "peer-proxy " ? "peer-proxy "
: "", : "",
(attr->es_flags & ATTR_ES_PEER_ROUTER) CHECK_FLAG(attr->es_flags,
ATTR_ES_PEER_ROUTER)
? "peer-router " ? "peer-router "
: ""); : "");
} }
} }
} else { } else {
attr->mm_sync_seqnum = 0; attr->mm_sync_seqnum = 0;
attr->es_flags &= ~ATTR_ES_PEER_ACTIVE; UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE);
attr->es_flags &= ~ATTR_ES_PEER_PROXY; UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY);
} }
} }
@ -1940,7 +1970,6 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
struct attr local_attr; struct attr local_attr;
struct bgp_labels bgp_labels = {}; struct bgp_labels bgp_labels = {};
int route_change = 1; int route_change = 1;
uint8_t sticky = 0;
const struct prefix_evpn *evp; const struct prefix_evpn *evp;
*pi = NULL; *pi = NULL;
@ -1972,9 +2001,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
local_attr = *attr; local_attr = *attr;
/* Extract MAC mobility sequence number, if any. */ /* Extract MAC mobility sequence number, if any. */
local_attr.mm_seqnum = local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(&local_attr);
bgp_attr_mac_mobility_seqnum(&local_attr, &sticky);
local_attr.sticky = sticky;
/* Add (or update) attribute to hash. */ /* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(&local_attr); attr_new = bgp_attr_intern(&local_attr);
@ -2069,9 +2096,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
BGP_PATH_ATTR_CHANGED); BGP_PATH_ATTR_CHANGED);
/* Extract MAC mobility sequence number, if any. */ /* Extract MAC mobility sequence number, if any. */
local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum( local_attr.mm_seqnum =
&local_attr, &sticky); bgp_attr_mac_mobility_seqnum(&local_attr);
local_attr.sticky = sticky;
attr_new = bgp_attr_intern(&local_attr); attr_new = bgp_attr_intern(&local_attr);
@ -2114,21 +2140,17 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp,
} }
} }
if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP
&& (curr_select->sub_type == BGP_ROUTE_IMPORTED ||
bgp_evpn_attr_is_sync(curr_select->attr)))
if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP && if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP &&
(curr_select->sub_type == BGP_ROUTE_IMPORTED || (curr_select->sub_type == BGP_ROUTE_IMPORTED ||
bgp_evpn_attr_is_sync(curr_select->attr))) { bgp_evpn_attr_is_sync(curr_select->attr))) {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
evpn_zebra_install(bgp, vpn, evpn_zebra_install(bgp, vpn,
(const struct prefix_evpn *) (const struct prefix_evpn *)
bgp_dest_get_prefix( bgp_dest_get_prefix(dest),
dest),
curr_select); curr_select);
else else
bgp_zebra_route_install(dest, curr_select, bgp, bgp_zebra_route_install(dest, curr_select, bgp, true,
true, vpn, false); vpn, false);
} }
} }
@ -2204,21 +2226,23 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
attr.nexthop = vpn->originator_ip; attr.nexthop = vpn->originator_ip;
attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0; if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY))
attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_STICKY);
attr.router_flag = CHECK_FLAG(flags, if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW))
ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER);
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
attr.es_flags |= ATTR_ES_PROXY_ADVERT; SET_FLAG(attr.es_flags, ATTR_ES_PROXY_ADVERT);
if (esi && bgp_evpn_is_esi_valid(esi)) { if (esi && bgp_evpn_is_esi_valid(esi)) {
memcpy(&attr.esi, esi, sizeof(esi_t)); memcpy(&attr.esi, esi, sizeof(esi_t));
attr.es_flags |= ATTR_ES_IS_LOCAL; SET_FLAG(attr.es_flags, ATTR_ES_IS_LOCAL);
} }
/* PMSI is only needed for type-3 routes */ /* PMSI is only needed for type-3 routes */
if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) { if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL));
bgp_attr_set_pmsi_tnl_type(&attr, PMSI_TNLTYPE_INGR_REPL); bgp_attr_set_pmsi_tnl_type(&attr, PMSI_TNLTYPE_INGR_REPL);
} }
@ -2250,8 +2274,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
* IPv4 or IPv6 global addresses and we're advertising L3VNI with * IPv4 or IPv6 global addresses and we're advertising L3VNI with
* these routes. * these routes.
*/ */
add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok( add_l3_ecomm =
vpn, p, (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL); bgp_evpn_route_add_l3_ecomm_ok(vpn, p,
CHECK_FLAG(attr.es_flags,
ATTR_ES_IS_LOCAL)
? &attr.esi
: NULL);
if (bgp->evpn_info) if (bgp->evpn_info)
macvrf_soo = bgp->evpn_info->soo; macvrf_soo = bgp->evpn_info->soo;
@ -2509,13 +2537,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
attr.nexthop = vpn->originator_ip; attr.nexthop = vpn->originator_ip;
attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr.sticky = (local_pi->attr->sticky) ? 1 : 0; attr.evpn_flags = local_pi->attr->evpn_flags;
attr.router_flag = (local_pi->attr->router_flag) ? 1 : 0;
attr.es_flags = local_pi->attr->es_flags; attr.es_flags = local_pi->attr->es_flags;
if (local_pi->attr->default_gw) { if (CHECK_FLAG(local_pi->attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) {
attr.default_gw = 1; SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
if (is_evpn_prefix_ipaddr_v6(&evp)) if (is_evpn_prefix_ipaddr_v6(&evp))
attr.router_flag = 1; SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER);
} }
memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t)); memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t));
bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr,
@ -2524,9 +2551,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
/* Add L3 VNI RTs and RMAC for non IPv6 link-local if /* Add L3 VNI RTs and RMAC for non IPv6 link-local if
* using L3 VNI for type-2 routes also. * using L3 VNI for type-2 routes also.
*/ */
add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok( add_l3_ecomm =
vpn, &evp, bgp_evpn_route_add_l3_ecomm_ok(vpn, &evp,
(attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL); CHECK_FLAG(attr.es_flags,
ATTR_ES_IS_LOCAL)
? &attr.esi
: NULL);
if (bgp->evpn_info) if (bgp->evpn_info)
macvrf_soo = bgp->evpn_info->soo; macvrf_soo = bgp->evpn_info->soo;
@ -3030,6 +3060,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
bool use_l3nhg = false; bool use_l3nhg = false;
bool is_l3nhg_active = false; bool is_l3nhg_active = false;
char buf1[INET6_ADDRSTRLEN]; char buf1[INET6_ADDRSTRLEN];
struct bgp_route_evpn *bre;
memset(pp, 0, sizeof(struct prefix)); memset(pp, 0, sizeof(struct prefix));
ip_prefix_from_evpn_prefix(evp, pp); ip_prefix_from_evpn_prefix(evp, pp);
@ -3063,45 +3094,43 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
* make sure to set the flag for next hop attribute. * make sure to set the flag for next hop attribute.
*/ */
attr = *parent_pi->attr; attr = *parent_pi->attr;
if (attr.evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP) { bre = bgp_attr_get_evpn_overlay(&attr);
if (afi == AFI_IP6) if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
evpn_convert_nexthop_to_ipv6(&attr);
else {
attr.nexthop = attr.mp_nexthop_global_in;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
}
} else {
/* /*
* If gateway IP overlay index is specified in the NLRI of * If gateway IP overlay index is specified in the NLRI of
* EVPN RT-5, this gateway IP should be used as the nexthop * EVPN RT-5, this gateway IP should be used as the nexthop
* for the prefix in the VRF * for the prefix in the VRF
*/ */
if (bgp_debug_zebra(NULL)) { if (bgp_debug_zebra(NULL)) {
zlog_debug( zlog_debug("Install gateway IP %s as nexthop for prefix %pFX in vrf %s",
"Install gateway IP %s as nexthop for prefix %pFX in vrf %s", inet_ntop(pp->family, &bre->gw_ip, buf1,
inet_ntop(pp->family, &attr.evpn_overlay.gw_ip, sizeof(buf1)),
buf1, sizeof(buf1)), pp, pp, vrf_id_to_name(bgp_vrf->vrf_id));
vrf_id_to_name(bgp_vrf->vrf_id));
} }
if (afi == AFI_IP6) { if (afi == AFI_IP6) {
memcpy(&attr.mp_nexthop_global, memcpy(&attr.mp_nexthop_global, &bre->gw_ip.ipaddr_v6,
&attr.evpn_overlay.gw_ip.ipaddr_v6,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
attr.mp_nexthop_len = IPV6_MAX_BYTELEN; attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
} else { } else {
attr.nexthop = attr.evpn_overlay.gw_ip.ipaddr_v4; attr.nexthop = bre->gw_ip.ipaddr_v4;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
}
} else {
if (afi == AFI_IP6)
evpn_convert_nexthop_to_ipv6(&attr);
else {
attr.nexthop = attr.mp_nexthop_global_in;
SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
} }
} }
bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg, bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg,
&is_l3nhg_active, NULL); &is_l3nhg_active, NULL);
if (use_l3nhg) if (use_l3nhg)
attr.es_flags |= ATTR_ES_L3_NHG_USE; SET_FLAG(attr.es_flags, ATTR_ES_L3_NHG_USE);
if (is_l3nhg_active) if (is_l3nhg_active)
attr.es_flags |= ATTR_ES_L3_NHG_ACTIVE; SET_FLAG(attr.es_flags, ATTR_ES_L3_NHG_ACTIVE);
/* Check if route entry is already present. */ /* Check if route entry is already present. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
@ -3143,22 +3172,20 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
} }
/* Gateway IP nexthop should be resolved */ /* Gateway IP nexthop should be resolved */
if (attr.evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) { if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
if (bgp_find_or_add_nexthop(bgp_vrf, bgp_vrf, afi, safi, pi, if (bgp_find_or_add_nexthop(bgp_vrf, bgp_vrf, afi, safi, pi,
NULL, 0, NULL)) NULL, 0, NULL))
bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID); bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
else { else {
if (BGP_DEBUG(nht, NHT)) { if (BGP_DEBUG(nht, NHT)) {
inet_ntop(pp->family, inet_ntop(pp->family, &bre->gw_ip, buf1,
&attr.evpn_overlay.gw_ip, sizeof(buf1));
buf1, sizeof(buf1));
zlog_debug("%s: gateway IP NH unresolved", zlog_debug("%s: gateway IP NH unresolved",
buf1); buf1);
} }
bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID); bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID);
} }
} else { } else {
/* as it is an importation, change nexthop */ /* as it is an importation, change nexthop */
bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF); bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF);
} }
@ -3267,8 +3294,7 @@ static int install_evpn_route_entry_in_vni_common(
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("VNI %d path %pFX chg to %s es", zlog_debug("VNI %d path %pFX chg to %s es",
vpn->vni, &pi->net->rn->p, vpn->vni, &pi->net->rn->p,
new_local_es ? "local" new_local_es ? "local" : "non-local");
: "non-local");
bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED); bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED);
} }
@ -3451,8 +3477,7 @@ uninstall_evpn_route_entry_in_vni_mac(struct bgp *bgp, struct bgpevpn *vpn,
* Uninstall route entry from the VRF routing table and send message * Uninstall route entry from the VRF routing table and send message
* to zebra, if appropriate. * to zebra, if appropriate.
*/ */
static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, const struct prefix_evpn *evp,
const struct prefix_evpn *evp,
struct bgp_path_info *parent_pi) struct bgp_path_info *parent_pi)
{ {
struct bgp_dest *dest; struct bgp_dest *dest;
@ -3631,7 +3656,7 @@ static int is_route_matching_for_vrf(struct bgp *bgp_vrf,
assert(attr); assert(attr);
/* Route should have valid RT to be even considered. */ /* Route should have valid RT to be even considered. */
if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
return 0; return 0;
ecom = bgp_attr_get_ecommunity(attr); ecom = bgp_attr_get_ecommunity(attr);
@ -3698,7 +3723,7 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn,
assert(attr); assert(attr);
/* Route should have valid RT to be even considered. */ /* Route should have valid RT to be even considered. */
if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
return 0; return 0;
ecom = bgp_attr_get_ecommunity(attr); ecom = bgp_attr_get_ecommunity(attr);
@ -3820,9 +3845,7 @@ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
} }
/* don't import hosts that are locally attached */ /* don't import hosts that are locally attached */
static inline bool bool bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf, const struct prefix_evpn *evp,
bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf,
const struct prefix_evpn *evp,
struct bgp_path_info *pi, int install) struct bgp_path_info *pi, int install)
{ {
esi_t *esi; esi_t *esi;
@ -4200,7 +4223,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
return 0; return 0;
/* If we don't have Route Target, nothing much to do. */ /* If we don't have Route Target, nothing much to do. */
if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
return 0; return 0;
/* EAD prefix in the global table doesn't include the VTEP-IP so /* EAD prefix in the global table doesn't include the VTEP-IP so
@ -4689,7 +4712,6 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
{ {
struct prefix_rd prd; struct prefix_rd prd;
struct prefix_evpn p = {}; struct prefix_evpn p = {};
struct bgp_route_evpn evpn = {};
uint8_t ipaddr_len; uint8_t ipaddr_len;
uint8_t macaddr_len; uint8_t macaddr_len;
/* holds the VNI(s) as in packet */ /* holds the VNI(s) as in packet */
@ -4731,9 +4753,9 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
STREAM_GET(&attr->esi, pkt, sizeof(esi_t)); STREAM_GET(&attr->esi, pkt, sizeof(esi_t));
if (bgp_evpn_is_esi_local_and_non_bypass(&attr->esi)) if (bgp_evpn_is_esi_local_and_non_bypass(&attr->esi))
attr->es_flags |= ATTR_ES_IS_LOCAL; SET_FLAG(attr->es_flags, ATTR_ES_IS_LOCAL);
else else
attr->es_flags &= ~ATTR_ES_IS_LOCAL; UNSET_FLAG(attr->es_flags, ATTR_ES_IS_LOCAL);
} else { } else {
STREAM_FORWARD_GETP(pkt, sizeof(esi_t)); STREAM_FORWARD_GETP(pkt, sizeof(esi_t));
} }
@ -4791,11 +4813,11 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
if (attr) if (attr)
bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
&label[0], num_labels, 0, &evpn); &label[0], num_labels, 0, NULL);
else else
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label[0], ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label[0],
num_labels, &evpn); num_labels);
goto done; goto done;
fail: fail:
@ -4835,8 +4857,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
* Note: We just simply ignore the values as it is not clear if * Note: We just simply ignore the values as it is not clear if
* doing anything else is better. * doing anything else is better.
*/ */
if (attr && if (attr && CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
enum pta_type pmsi_tnl_type = bgp_attr_get_pmsi_tnl_type(attr); enum pta_type pmsi_tnl_type = bgp_attr_get_pmsi_tnl_type(attr);
if (pmsi_tnl_type != PMSI_TNLTYPE_INGR_REPL if (pmsi_tnl_type != PMSI_TNLTYPE_INGR_REPL
@ -4885,8 +4906,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
0, 0, NULL); 0, 0, NULL);
else else
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
NULL);
return 0; return 0;
} }
@ -4899,7 +4919,8 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
{ {
struct prefix_rd prd; struct prefix_rd prd;
struct prefix_evpn p; struct prefix_evpn p;
struct bgp_route_evpn evpn; struct bgp_route_evpn *evpn = XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
sizeof(struct bgp_route_evpn));
uint8_t ippfx_len; uint8_t ippfx_len;
uint32_t eth_tag; uint32_t eth_tag;
mpls_label_t label; /* holds the VNI as in the packet */ mpls_label_t label; /* holds the VNI as in the packet */
@ -4914,6 +4935,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
flog_err(EC_BGP_EVPN_ROUTE_INVALID, flog_err(EC_BGP_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-5 NLRI with invalid length %d", "%u:%s - Rx EVPN Type-5 NLRI with invalid length %d",
peer->bgp->vrf_id, peer->host, psize); peer->bgp->vrf_id, peer->host, psize);
evpn_overlay_free(evpn);
return -1; return -1;
} }
@ -4929,12 +4951,9 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
p.prefixlen = EVPN_ROUTE_PREFIXLEN; p.prefixlen = EVPN_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE; p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
/* Additional information outside of prefix - ESI and GW IP */
memset(&evpn, 0, sizeof(evpn));
/* Fetch ESI overlay index */ /* Fetch ESI overlay index */
if (attr) if (attr)
memcpy(&evpn.eth_s_id, pfx, sizeof(esi_t)); memcpy(&evpn->eth_s_id, pfx, sizeof(esi_t));
pfx += ESI_BYTES; pfx += ESI_BYTES;
/* Fetch Ethernet Tag. */ /* Fetch Ethernet Tag. */
@ -4949,6 +4968,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
EC_BGP_EVPN_ROUTE_INVALID, EC_BGP_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-5 NLRI with invalid IP Prefix length %d", "%u:%s - Rx EVPN Type-5 NLRI with invalid IP Prefix length %d",
peer->bgp->vrf_id, peer->host, ippfx_len); peer->bgp->vrf_id, peer->host, ippfx_len);
evpn_overlay_free(evpn);
return -1; return -1;
} }
p.prefix.prefix_addr.ip_prefix_length = ippfx_len; p.prefix.prefix_addr.ip_prefix_length = ippfx_len;
@ -4961,16 +4981,16 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
SET_IPADDR_V4(&p.prefix.prefix_addr.ip); SET_IPADDR_V4(&p.prefix.prefix_addr.ip);
memcpy(&p.prefix.prefix_addr.ip.ipaddr_v4, pfx, 4); memcpy(&p.prefix.prefix_addr.ip.ipaddr_v4, pfx, 4);
pfx += 4; pfx += 4;
SET_IPADDR_V4(&evpn.gw_ip); SET_IPADDR_V4(&evpn->gw_ip);
memcpy(&evpn.gw_ip.ipaddr_v4, pfx, 4); memcpy(&evpn->gw_ip.ipaddr_v4, pfx, 4);
pfx += 4; pfx += 4;
} else { } else {
SET_IPADDR_V6(&p.prefix.prefix_addr.ip); SET_IPADDR_V6(&p.prefix.prefix_addr.ip);
memcpy(&p.prefix.prefix_addr.ip.ipaddr_v6, pfx, memcpy(&p.prefix.prefix_addr.ip.ipaddr_v6, pfx,
IPV6_MAX_BYTELEN); IPV6_MAX_BYTELEN);
pfx += IPV6_MAX_BYTELEN; pfx += IPV6_MAX_BYTELEN;
SET_IPADDR_V6(&evpn.gw_ip); SET_IPADDR_V6(&evpn->gw_ip);
memcpy(&evpn.gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN); memcpy(&evpn->gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN);
pfx += IPV6_MAX_BYTELEN; pfx += IPV6_MAX_BYTELEN;
} }
@ -4988,20 +5008,20 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
* An update containing a non-zero gateway IP and a non-zero ESI * An update containing a non-zero gateway IP and a non-zero ESI
* at the same time is should be treated as withdraw * at the same time is should be treated as withdraw
*/ */
if (bgp_evpn_is_esi_valid(&evpn.eth_s_id) && if (bgp_evpn_is_esi_valid(&evpn->eth_s_id) &&
!ipaddr_is_zero(&evpn.gw_ip)) { !ipaddr_is_zero(&evpn->gw_ip)) {
flog_err(EC_BGP_EVPN_ROUTE_INVALID, flog_err(EC_BGP_EVPN_ROUTE_INVALID,
"%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.", "%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.",
peer->host); peer->host);
is_valid_update = false; is_valid_update = false;
} else if (bgp_evpn_is_esi_valid(&evpn.eth_s_id)) } else if (bgp_evpn_is_esi_valid(&evpn->eth_s_id))
evpn.type = OVERLAY_INDEX_ESI; evpn->type = OVERLAY_INDEX_ESI;
else if (!ipaddr_is_zero(&evpn.gw_ip)) else if (!ipaddr_is_zero(&evpn->gw_ip))
evpn.type = OVERLAY_INDEX_GATEWAY_IP; evpn->type = OVERLAY_INDEX_GATEWAY_IP;
if (attr) { if (attr) {
if (is_zero_mac(&attr->rmac) && if (is_zero_mac(&attr->rmac) &&
!bgp_evpn_is_esi_valid(&evpn.eth_s_id) && !bgp_evpn_is_esi_valid(&evpn->eth_s_id) &&
ipaddr_is_zero(&evpn.gw_ip) && label == 0) { ipaddr_is_zero(&evpn->gw_ip) && label == 0) {
flog_err(EC_BGP_EVPN_ROUTE_INVALID, flog_err(EC_BGP_EVPN_ROUTE_INVALID,
"%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero", "%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero",
peer->host); peer->host);
@ -5016,7 +5036,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
if (attr && is_valid_update) if (attr && is_valid_update)
bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
&label, 1, 0, &evpn); &label, 1, 0, evpn);
else { else {
if (!is_valid_update) { if (!is_valid_update) {
char attr_str[BUFSIZ] = {0}; char attr_str[BUFSIZ] = {0};
@ -5028,8 +5048,8 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
attr_str); attr_str);
} }
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1);
&evpn); evpn_overlay_free(evpn);
} }
return 0; return 0;
@ -5043,12 +5063,16 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
int len; int len;
char temp[16]; char temp[16];
const struct evpn_addr *p_evpn_p; const struct evpn_addr *p_evpn_p;
struct bgp_route_evpn *bre = NULL;
memset(&temp, 0, sizeof(temp)); memset(&temp, 0, sizeof(temp));
if (p->family != AF_EVPN) if (p->family != AF_EVPN)
return; return;
p_evpn_p = &(p->u.prefix_evpn); p_evpn_p = &(p->u.prefix_evpn);
if (attr)
bre = bgp_attr_get_evpn_overlay(attr);
/* len denites the total len of IP and GW-IP in the route /* len denites the total len of IP and GW-IP in the route
IP and GW-IP have to be both ipv4 or ipv6 IP and GW-IP have to be both ipv4 or ipv6
*/ */
@ -5059,7 +5083,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
/* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */ /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */
stream_putc(s, 8 + 10 + 4 + 1 + len + 3); stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
stream_put(s, prd->val, 8); stream_put(s, prd->val, 8);
if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_ESI) if (attr && bre && bre->type == OVERLAY_INDEX_ESI)
stream_put(s, &attr->esi, sizeof(esi_t)); stream_put(s, &attr->esi, sizeof(esi_t));
else else
stream_put(s, 0, sizeof(esi_t)); stream_put(s, 0, sizeof(esi_t));
@ -5069,15 +5093,11 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
stream_put_ipv4(s, p_evpn_p->prefix_addr.ip.ipaddr_v4.s_addr); stream_put_ipv4(s, p_evpn_p->prefix_addr.ip.ipaddr_v4.s_addr);
else else
stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16); stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16);
if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) { if (attr && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
const struct bgp_route_evpn *evpn_overlay =
bgp_attr_get_evpn_overlay(attr);
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
stream_put_ipv4(s, stream_put_ipv4(s, bre->gw_ip.ipaddr_v4.s_addr);
evpn_overlay->gw_ip.ipaddr_v4.s_addr);
else else
stream_put(s, &(evpn_overlay->gw_ip.ipaddr_v6), 16); stream_put(s, &(bre->gw_ip.ipaddr_v6), 16);
} else { } else {
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
stream_put_ipv4(s, 0); stream_put_ipv4(s, 0);
@ -5439,7 +5459,7 @@ void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl,
struct ecommunity_val eval; struct ecommunity_val eval;
if (bgp->advertise_autort_rfc8365) if (bgp->advertise_autort_rfc8365)
vni |= EVPN_AUTORT_VXLAN; SET_FLAG(vni, EVPN_AUTORT_VXLAN);
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true); encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true);
@ -7717,18 +7737,18 @@ static void bgp_evpn_remote_ip_process_nexthops(struct bgpevpn *vpn,
* MAC/IP route or SVI or tenant vrf being added to EVI. * MAC/IP route or SVI or tenant vrf being added to EVI.
* Set nexthop as valid only if it is already L3 reachable * Set nexthop as valid only if it is already L3 reachable
*/ */
if (resolve && bnc->flags & BGP_NEXTHOP_EVPN_INCOMPLETE) { if (resolve && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) {
bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
bnc->flags |= BGP_NEXTHOP_VALID; SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED; SET_FLAG(bnc->change_flags, BGP_NEXTHOP_MACIP_CHANGED);
evaluate_paths(bnc); evaluate_paths(bnc);
} }
/* MAC/IP route or SVI or tenant vrf being deleted from EVI */ /* MAC/IP route or SVI or tenant vrf being deleted from EVI */
if (!resolve && bnc->flags & BGP_NEXTHOP_VALID) { if (!resolve && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
bnc->flags &= ~BGP_NEXTHOP_VALID; UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE; SET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED; SET_FLAG(bnc->change_flags, BGP_NEXTHOP_MACIP_CHANGED);
evaluate_paths(bnc); evaluate_paths(bnc);
} }
} }

View file

@ -195,4 +195,8 @@ extern enum zclient_send_status
evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p, struct bgp_path_info *pi, const struct prefix_evpn *p, struct bgp_path_info *pi,
bool is_sync); bool is_sync);
bool bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf, const struct prefix_evpn *evp,
struct bgp_path_info *pi, int install);
int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, const struct prefix_evpn *evp,
struct bgp_path_info *parent_pi);
#endif /* _QUAGGA_BGP_EVPN_H */ #endif /* _QUAGGA_BGP_EVPN_H */

View file

@ -770,8 +770,7 @@ int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi,
0, 0, NULL); 0, 0, NULL);
} else { } else {
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
NULL);
} }
return 0; return 0;
} }
@ -1239,8 +1238,7 @@ int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
0, 0, NULL); 0, 0, NULL);
} else { } else {
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
NULL);
} }
return 0; return 0;
} }
@ -1406,8 +1404,8 @@ bgp_zebra_send_remote_es_vtep(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep,
return ZCLIENT_SEND_SUCCESS; return ZCLIENT_SEND_SUCCESS;
} }
if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
flags |= ZAPI_ES_VTEP_FLAG_ESR_RXED; SET_FLAG(flags, ZAPI_ES_VTEP_FLAG_ESR_RXED);
s = zclient->obuf; s = zclient->obuf;
stream_reset(s); stream_reset(s);
@ -1966,9 +1964,9 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
*/ */
static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller) static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
{ {
if ((es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) if (CHECK_FLAG(es->flags, (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) ||
|| listcount(es->macip_evi_path_list) listcount(es->macip_evi_path_list) ||
|| listcount(es->macip_global_path_list)) listcount(es->macip_global_path_list))
return; return;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
@ -1993,8 +1991,8 @@ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es *es) static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es *es)
{ {
return (es->flags & BGP_EVPNES_LOCAL) return CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL) &&
&& !(es->flags & BGP_EVPNES_BYPASS); !CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS);
} }
/* init local info associated with the ES */ /* init local info associated with the ES */
@ -2076,8 +2074,8 @@ bool bgp_evpn_es_add_l3_ecomm_ok(esi_t *esi)
es = bgp_evpn_es_find(esi); es = bgp_evpn_es_find(esi);
return (!es || !(es->flags & BGP_EVPNES_LOCAL) return (!es || !CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL) ||
|| bgp_evpn_local_es_is_active(es)); bgp_evpn_local_es_is_active(es));
} }
static bool bgp_evpn_is_valid_local_path(struct bgp_path_info *pi) static bool bgp_evpn_is_valid_local_path(struct bgp_path_info *pi)
@ -2177,9 +2175,9 @@ static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es *es,
attr_tmp = *pi->attr; attr_tmp = *pi->attr;
if (is_local) if (is_local)
attr_tmp.es_flags |= ATTR_ES_IS_LOCAL; SET_FLAG(attr_tmp.es_flags, ATTR_ES_IS_LOCAL);
else else
attr_tmp.es_flags &= ~ATTR_ES_IS_LOCAL; UNSET_FLAG(attr_tmp.es_flags, ATTR_ES_IS_LOCAL);
attr_new = bgp_attr_intern(&attr_tmp); attr_new = bgp_attr_intern(&attr_tmp);
bgp_attr_unintern(&pi->attr); bgp_attr_unintern(&pi->attr);
pi->attr = attr_new; pi->attr = attr_new;
@ -2473,9 +2471,9 @@ static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es,
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
vtep_flag_str[0] = '\0'; vtep_flag_str[0] = '\0';
if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str)); strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE) if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str)); strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
if (!strlen(vtep_flag_str)) if (!strlen(vtep_flag_str))
@ -2507,15 +2505,15 @@ static void bgp_evpn_es_json_vtep_fill(json_object *json_vteps,
json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4", json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4",
&es_vtep->vtep_ip); &es_vtep->vtep_ip);
if (es_vtep->flags & (BGP_EVPNES_VTEP_ESR | if (CHECK_FLAG(es_vtep->flags,
BGP_EVPNES_VTEP_ACTIVE)) { (BGP_EVPNES_VTEP_ESR | BGP_EVPNES_VTEP_ACTIVE))) {
json_flags = json_object_new_array(); json_flags = json_object_new_array();
if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
json_array_string_add(json_flags, "esr"); json_array_string_add(json_flags, "esr");
if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE) if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
json_array_string_add(json_flags, "active"); json_array_string_add(json_flags, "active");
json_object_object_add(json_vtep_entry, "flags", json_flags); json_object_object_add(json_vtep_entry, "flags", json_flags);
if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) { if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR)) {
json_object_int_add(json_vtep_entry, "dfPreference", json_object_int_add(json_vtep_entry, "dfPreference",
es_vtep->df_pref); es_vtep->df_pref);
json_object_string_add( json_object_string_add(
@ -2539,9 +2537,9 @@ static void bgp_evpn_es_vteps_show_detail(struct vty *vty,
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
vtep_flag_str[0] = '\0'; vtep_flag_str[0] = '\0';
if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str)); strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE) if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str)); strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
if (!strlen(vtep_flag_str)) if (!strlen(vtep_flag_str))
@ -2550,7 +2548,7 @@ static void bgp_evpn_es_vteps_show_detail(struct vty *vty,
vty_out(vty, " %pI4 flags: %s", &es_vtep->vtep_ip, vty_out(vty, " %pI4 flags: %s", &es_vtep->vtep_ip,
vtep_flag_str); vtep_flag_str);
if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
vty_out(vty, " df_alg: %s df_pref: %u\n", vty_out(vty, " df_alg: %s df_pref: %u\n",
evpn_es_df_alg2str(es_vtep->df_alg, alg_buf, evpn_es_df_alg2str(es_vtep->df_alg, alg_buf,
sizeof(alg_buf)), sizeof(alg_buf)),
@ -2575,11 +2573,12 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
json_object_string_addf(json, "rd", "%pRDP", json_object_string_addf(json, "rd", "%pRDP",
&es->es_base_frag->prd); &es->es_base_frag->prd);
if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) { if (CHECK_FLAG(es->flags,
(BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))) {
json_types = json_object_new_array(); json_types = json_object_new_array();
if (es->flags & BGP_EVPNES_LOCAL) if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
json_array_string_add(json_types, "local"); json_array_string_add(json_types, "local");
if (es->flags & BGP_EVPNES_REMOTE) if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
json_array_string_add(json_types, "remote"); json_array_string_add(json_types, "remote");
json_object_object_add(json, "type", json_types); json_object_object_add(json, "type", json_types);
} }
@ -2599,11 +2598,11 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ]; char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
type_str[0] = '\0'; type_str[0] = '\0';
if (es->flags & BGP_EVPNES_BYPASS) if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS))
strlcat(type_str, "B", sizeof(type_str)); strlcat(type_str, "B", sizeof(type_str));
if (es->flags & BGP_EVPNES_LOCAL) if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
strlcat(type_str, "L", sizeof(type_str)); strlcat(type_str, "L", sizeof(type_str));
if (es->flags & BGP_EVPNES_REMOTE) if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
strlcat(type_str, "R", sizeof(type_str)); strlcat(type_str, "R", sizeof(type_str));
if (es->inconsistencies) if (es->inconsistencies)
strlcat(type_str, "I", sizeof(type_str)); strlcat(type_str, "I", sizeof(type_str));
@ -2630,16 +2629,16 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
/* Add the "brief" info first */ /* Add the "brief" info first */
bgp_evpn_es_show_entry(vty, es, json); bgp_evpn_es_show_entry(vty, es, json);
if (es->flags if (CHECK_FLAG(es->flags,
& (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI |
| BGP_EVPNES_BYPASS)) { BGP_EVPNES_BYPASS))) {
json_flags = json_object_new_array(); json_flags = json_object_new_array();
if (es->flags & BGP_EVPNES_OPER_UP) if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP))
json_array_string_add(json_flags, "up"); json_array_string_add(json_flags, "up");
if (es->flags & BGP_EVPNES_ADV_EVI) if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
json_array_string_add(json_flags, json_array_string_add(json_flags,
"advertiseEVI"); "advertiseEVI");
if (es->flags & BGP_EVPNES_BYPASS) if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS))
json_array_string_add(json_flags, "bypass"); json_array_string_add(json_flags, "bypass");
json_object_object_add(json, "flags", json_flags); json_object_object_add(json, "flags", json_flags);
} }
@ -2655,7 +2654,7 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
listcount(es->macip_global_path_list)); listcount(es->macip_global_path_list));
json_object_int_add(json, "inconsistentVniVtepCount", json_object_int_add(json, "inconsistentVniVtepCount",
es->incons_evi_vtep_cnt); es->incons_evi_vtep_cnt);
if (es->flags & BGP_EVPNES_LOCAL) if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
json_object_int_add(json, "localEsDfPreference", json_object_int_add(json, "localEsDfPreference",
es->df_pref); es->df_pref);
if (listcount(es->es_vtep_list)) { if (listcount(es->es_vtep_list)) {
@ -2673,7 +2672,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
} }
if (es->inconsistencies) { if (es->inconsistencies) {
json_incons = json_object_new_array(); json_incons = json_object_new_array();
if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST) if (CHECK_FLAG(es->inconsistencies,
BGP_EVPNES_INCONS_VTEP_LIST))
json_array_string_add(json_incons, json_array_string_add(json_incons,
"vni-vtep-mismatch"); "vni-vtep-mismatch");
json_object_object_add(json, "inconsistencies", json_object_object_add(json, "inconsistencies",
@ -2684,9 +2684,9 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
char type_str[4]; char type_str[4];
type_str[0] = '\0'; type_str[0] = '\0';
if (es->flags & BGP_EVPNES_LOCAL) if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
strlcat(type_str, "L", sizeof(type_str)); strlcat(type_str, "L", sizeof(type_str));
if (es->flags & BGP_EVPNES_REMOTE) if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
strlcat(type_str, "R", sizeof(type_str)); strlcat(type_str, "R", sizeof(type_str));
vty_out(vty, "ESI: %s\n", es->esi_str); vty_out(vty, "ESI: %s\n", es->esi_str);
@ -2694,10 +2694,10 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
vty_out(vty, " RD: %pRDP\n", vty_out(vty, " RD: %pRDP\n",
es->es_base_frag ? &es->es_base_frag->prd : NULL); es->es_base_frag ? &es->es_base_frag->prd : NULL);
vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip); vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip);
if (es->flags & BGP_EVPNES_LOCAL) if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
vty_out(vty, " Local ES DF preference: %u\n", vty_out(vty, " Local ES DF preference: %u\n",
es->df_pref); es->df_pref);
if (es->flags & BGP_EVPNES_BYPASS) if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS))
vty_out(vty, " LACP bypass: on\n"); vty_out(vty, " LACP bypass: on\n");
vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list)); vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
vty_out(vty, " Remote VNI Count: %d\n", vty_out(vty, " Remote VNI Count: %d\n",
@ -2711,7 +2711,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
es->incons_evi_vtep_cnt); es->incons_evi_vtep_cnt);
if (es->inconsistencies) { if (es->inconsistencies) {
incons_str[0] = '\0'; incons_str[0] = '\0';
if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST) if (CHECK_FLAG(es->inconsistencies,
BGP_EVPNES_INCONS_VTEP_LIST))
strlcat(incons_str, "vni-vtep-mismatch", strlcat(incons_str, "vni-vtep-mismatch",
sizeof(incons_str)); sizeof(incons_str));
} else { } else {
@ -2935,7 +2936,7 @@ static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf *es_vrf)
static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf) static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf)
{ {
if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)) if (!CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE))
return; return;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
@ -2943,7 +2944,7 @@ static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf)
es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id, es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
es_vrf->nhg_id); es_vrf->nhg_id);
bgp_evpn_l3nhg_zebra_del(es_vrf); bgp_evpn_l3nhg_zebra_del(es_vrf);
es_vrf->flags &= ~BGP_EVPNES_VRF_NHG_ACTIVE; UNSET_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE);
/* MAC-IPs can now be installed via the L3NHG */ /* MAC-IPs can now be installed via the L3NHG */
bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg-deactivate"); bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg-deactivate");
} }
@ -2955,7 +2956,7 @@ static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update)
return; return;
} }
if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) { if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE)) {
if (!update) if (!update)
return; return;
} else { } else {
@ -2963,7 +2964,7 @@ static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update)
zlog_debug("es %s vrf %u nhg %u activate", zlog_debug("es %s vrf %u nhg %u activate",
es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id, es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
es_vrf->nhg_id); es_vrf->nhg_id);
es_vrf->flags |= BGP_EVPNES_VRF_NHG_ACTIVE; SET_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE);
/* MAC-IPs can now be installed via the L3NHG */ /* MAC-IPs can now be installed via the L3NHG */
bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg_activate"); bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg_activate");
} }
@ -3184,7 +3185,7 @@ void bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi, bool *use_l3nhg,
return; return;
*use_l3nhg = true; *use_l3nhg = true;
if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE))
*is_l3nhg_active = true; *is_l3nhg_active = true;
if (es_vrf_p) if (es_vrf_p)
*es_vrf_p = es_vrf; *es_vrf_p = es_vrf;
@ -3276,9 +3277,9 @@ static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
json_object_string_add(json, "esi", es->esi_str); json_object_string_add(json, "esi", es->esi_str);
json_object_string_add(json, "vrf", bgp_vrf->name_pretty); json_object_string_add(json, "vrf", bgp_vrf->name_pretty);
if (es_vrf->flags & (BGP_EVPNES_VRF_NHG_ACTIVE)) { if (CHECK_FLAG(es_vrf->flags, (BGP_EVPNES_VRF_NHG_ACTIVE))) {
json_types = json_object_new_array(); json_types = json_object_new_array();
if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE))
json_array_string_add(json_types, "active"); json_array_string_add(json_types, "active");
json_object_object_add(json, "flags", json_types); json_object_object_add(json, "flags", json_types);
} }
@ -3290,7 +3291,7 @@ static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
char flags_str[4]; char flags_str[4];
flags_str[0] = '\0'; flags_str[0] = '\0';
if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE))
strlcat(flags_str, "A", sizeof(flags_str)); strlcat(flags_str, "A", sizeof(flags_str));
vty_out(vty, "%-30s %-15s %-5s %-8u %-8u %u\n", es->esi_str, vty_out(vty, "%-30s %-15s %-5s %-8u %-8u %u\n", es->esi_str,
@ -3400,7 +3401,7 @@ static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep *evi_vtep)
{ {
struct bgp_evpn_es_evi *es_evi = evi_vtep->es_evi; struct bgp_evpn_es_evi *es_evi = evi_vtep->es_evi;
if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD)) if (CHECK_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD)))
/* as long as there is some reference we can't free it */ /* as long as there is some reference we can't free it */
return; return;
@ -3445,7 +3446,8 @@ bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
/* EAD-per-ES is sufficent to activate the PE */ /* EAD-per-ES is sufficent to activate the PE */
ead_activity_flags = BGP_EVPN_EVI_VTEP_EAD_PER_ES; ead_activity_flags = BGP_EVPN_EVI_VTEP_EAD_PER_ES;
if ((evi_vtep->flags & ead_activity_flags) == ead_activity_flags) if (CHECK_FLAG(evi_vtep->flags, ead_activity_flags) ==
ead_activity_flags)
SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
else else
UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
@ -3602,7 +3604,8 @@ bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi)
/* cannot free the element as long as there is a local or remote /* cannot free the element as long as there is a local or remote
* reference * reference
*/ */
if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE)) if (CHECK_FLAG(es_evi->flags,
(BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE)))
return es_evi; return es_evi;
bgp_evpn_es_frag_evi_del(es_evi, false); bgp_evpn_es_frag_evi_del(es_evi, false);
bgp_evpn_es_vrf_deref(es_evi); bgp_evpn_es_vrf_deref(es_evi);
@ -3804,6 +3807,7 @@ int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni)
bgp_evpn_ead_evi_route_update(bgp, es, vpn, &p); bgp_evpn_ead_evi_route_update(bgp, es, vpn, &p);
} }
bgp_evpn_local_es_evi_unistall_local_routes_in_vrfs(es, es_evi);
/* update EAD-ES */ /* update EAD-ES */
if (bgp_evpn_local_es_is_active(es)) if (bgp_evpn_local_es_is_active(es))
bgp_evpn_ead_es_route_update(bgp, es); bgp_evpn_ead_es_route_update(bgp, es);
@ -3924,8 +3928,8 @@ static void bgp_evpn_remote_es_evi_flush(struct bgp_evpn_es_evi *es_evi)
/* delete all VTEPs */ /* delete all VTEPs */
for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list, node, nnode, for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list, node, nnode,
evi_vtep)) { evi_vtep)) {
evi_vtep->flags &= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES UNSET_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
| BGP_EVPN_EVI_VTEP_EAD_PER_EVI); BGP_EVPN_EVI_VTEP_EAD_PER_EVI));
bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
bgp_evpn_es_evi_vtep_free(evi_vtep); bgp_evpn_es_evi_vtep_free(evi_vtep);
} }
@ -3973,9 +3977,9 @@ static char *bgp_evpn_es_evi_vteps_str(char *vtep_str,
vtep_str[0] = '\0'; vtep_str[0] = '\0';
for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) { for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
vtep_flag_str[0] = '\0'; vtep_flag_str[0] = '\0';
if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES) if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES))
strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str)); strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI) if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI))
strlcat(vtep_flag_str, "V", sizeof(vtep_flag_str)); strlcat(vtep_flag_str, "V", sizeof(vtep_flag_str));
if (!strnlen(vtep_flag_str, sizeof(vtep_flag_str))) if (!strnlen(vtep_flag_str, sizeof(vtep_flag_str)))
@ -4006,12 +4010,12 @@ static void bgp_evpn_es_evi_json_vtep_fill(json_object *json_vteps,
json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4", json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4",
&evi_vtep->vtep_ip); &evi_vtep->vtep_ip);
if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD_PER_ES | if (CHECK_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) { BGP_EVPN_EVI_VTEP_EAD_PER_EVI))) {
json_flags = json_object_new_array(); json_flags = json_object_new_array();
if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES) if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES))
json_array_string_add(json_flags, "ead-per-es"); json_array_string_add(json_flags, "ead-per-es");
if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI) if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI))
json_array_string_add(json_flags, "ead-per-evi"); json_array_string_add(json_flags, "ead-per-evi");
json_object_object_add(json_vtep_entry, json_object_object_add(json_vtep_entry,
"flags", json_flags); "flags", json_flags);
@ -4035,12 +4039,12 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
if (es_evi->vpn) if (es_evi->vpn)
json_object_int_add(json, "vni", es_evi->vpn->vni); json_object_int_add(json, "vni", es_evi->vpn->vni);
if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | if (CHECK_FLAG(es_evi->flags, (BGP_EVPNES_EVI_LOCAL |
BGP_EVPNES_EVI_REMOTE)) { BGP_EVPNES_EVI_REMOTE))) {
json_types = json_object_new_array(); json_types = json_object_new_array();
if (es_evi->flags & BGP_EVPNES_EVI_LOCAL) if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
json_array_string_add(json_types, "local"); json_array_string_add(json_types, "local");
if (es_evi->flags & BGP_EVPNES_EVI_REMOTE) if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE))
json_array_string_add(json_types, "remote"); json_array_string_add(json_types, "remote");
json_object_object_add(json, "type", json_types); json_object_object_add(json, "type", json_types);
} }
@ -4059,11 +4063,11 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ]; char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
type_str[0] = '\0'; type_str[0] = '\0';
if (es_evi->flags & BGP_EVPNES_EVI_LOCAL) if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
strlcat(type_str, "L", sizeof(type_str)); strlcat(type_str, "L", sizeof(type_str));
if (es_evi->flags & BGP_EVPNES_EVI_REMOTE) if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE))
strlcat(type_str, "R", sizeof(type_str)); strlcat(type_str, "R", sizeof(type_str));
if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST))
strlcat(type_str, "I", sizeof(type_str)); strlcat(type_str, "I", sizeof(type_str));
bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str)); bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
@ -4090,7 +4094,7 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
json_object_string_addf(json, "esFragmentRd", json_object_string_addf(json, "esFragmentRd",
BGP_RD_AS_FORMAT(mode), BGP_RD_AS_FORMAT(mode),
&es_evi->es_frag->prd); &es_evi->es_frag->prd);
if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) { if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST)) {
json_flags = json_object_new_array(); json_flags = json_object_new_array();
json_array_string_add(json_flags, "es-vtep-mismatch"); json_array_string_add(json_flags, "es-vtep-mismatch");
json_object_object_add(json, "flags", json_flags); json_object_object_add(json, "flags", json_flags);
@ -4100,9 +4104,9 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
char type_str[4]; char type_str[4];
type_str[0] = '\0'; type_str[0] = '\0';
if (es_evi->flags & BGP_EVPNES_EVI_LOCAL) if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
strlcat(type_str, "L", sizeof(type_str)); strlcat(type_str, "L", sizeof(type_str));
if (es_evi->flags & BGP_EVPNES_EVI_REMOTE) if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE))
strlcat(type_str, "R", sizeof(type_str)); strlcat(type_str, "R", sizeof(type_str));
bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str)); bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
@ -4119,8 +4123,10 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
vty_out(vty, " Inconsistencies: %s\n", vty_out(vty, " Inconsistencies: %s\n",
(es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ? CHECK_FLAG(es_evi->flags,
"es-vtep-mismatch":"-"); BGP_EVPNES_EVI_INCONS_VTEP_LIST)
? "es-vtep-mismatch"
: "-");
vty_out(vty, " VTEPs: %s\n", vtep_str); vty_out(vty, " VTEPs: %s\n", vtep_str);
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
@ -4514,12 +4520,12 @@ static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add)
static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh *nh, bool add) static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh *nh, bool add)
{ {
if (add && !is_zero_mac(&nh->rmac)) { if (add && !is_zero_mac(&nh->rmac)) {
nh->flags |= BGP_EVPN_NH_READY_FOR_ZEBRA; SET_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA);
bgp_evpn_nh_zebra_update_send(nh, true); bgp_evpn_nh_zebra_update_send(nh, true);
} else { } else {
if (!(nh->flags & BGP_EVPN_NH_READY_FOR_ZEBRA)) if (!CHECK_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA))
return; return;
nh->flags &= ~BGP_EVPN_NH_READY_FOR_ZEBRA; UNSET_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA);
bgp_evpn_nh_zebra_update_send(nh, false); bgp_evpn_nh_zebra_update_send(nh, false);
} }
} }
@ -4811,7 +4817,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi)
/* if NHG is not being used for this path we don't need to manage the /* if NHG is not being used for this path we don't need to manage the
* nexthops in bgp (they are managed by zebra instead) * nexthops in bgp (they are managed by zebra instead)
*/ */
if (!(pi->attr->es_flags & ATTR_ES_L3_NHG_USE)) { if (!CHECK_FLAG(pi->attr->es_flags, ATTR_ES_L3_NHG_USE)) {
if (nh_info) if (nh_info)
bgp_evpn_path_nh_unlink(nh_info); bgp_evpn_path_nh_unlink(nh_info);
return; return;
@ -5053,3 +5059,38 @@ void bgp_evpn_switch_ead_evi_rx(void)
} }
} }
} }
void bgp_evpn_local_es_evi_unistall_local_routes_in_vrfs(struct bgp_evpn_es *es,
struct bgp_evpn_es_evi *es_evi)
{
struct listnode *node;
struct bgp_path_es_info *es_info;
struct bgp_path_info *pi;
const struct prefix_evpn *evp;
struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf;
if (!es_vrf)
return;
for (ALL_LIST_ELEMENTS_RO(es->macip_global_path_list, node, es_info)) {
pi = es_info->pi;
if (!bgp_evpn_is_macip_path(pi))
continue;
evp = (const struct prefix_evpn *)bgp_dest_get_prefix(pi->net);
if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID) && pi->type == ZEBRA_ROUTE_BGP &&
pi->sub_type == BGP_ROUTE_NORMAL))
continue;
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("route %pFX is matched on local esi %s, uninstall from %s route table",
evp, es->esi_str, es_vrf->bgp_vrf->name_pretty);
if (!bgp_evpn_skip_vrf_import_of_local_es(es_vrf->bgp_vrf, evp, pi, 0))
continue;
uninstall_evpn_route_entry_in_vrf(es_vrf->bgp_vrf, evp, pi);
}
}

View file

@ -459,5 +459,7 @@ extern void bgp_evpn_path_nh_add(struct bgp *bgp_vrf, struct bgp_path_info *pi);
extern void bgp_evpn_path_nh_del(struct bgp *bgp_vrf, struct bgp_path_info *pi); extern void bgp_evpn_path_nh_del(struct bgp *bgp_vrf, struct bgp_path_info *pi);
extern void bgp_evpn_mh_config_ead_export_rt(struct bgp *bgp, extern void bgp_evpn_mh_config_ead_export_rt(struct bgp *bgp,
struct ecommunity *ecom, bool del); struct ecommunity *ecom, bool del);
extern void bgp_evpn_local_es_evi_unistall_local_routes_in_vrfs(struct bgp_evpn_es *es,
struct bgp_evpn_es_evi *es_evi);
#endif /* _FRR_BGP_EVPN_MH_H */ #endif /* _FRR_BGP_EVPN_MH_H */

View file

@ -382,7 +382,7 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq,
} }
static inline void encode_na_flag_extcomm(struct ecommunity_val *eval, static inline void encode_na_flag_extcomm(struct ecommunity_val *eval,
uint8_t na_flag, bool proxy) bool na_flag, bool proxy)
{ {
memset(eval, 0, sizeof(*eval)); memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_EVPN; eval->val[0] = ECOMMUNITY_ENCODE_EVPN;

View file

@ -2561,7 +2561,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
/* Prefix and num paths displayed once per prefix. */ /* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest), route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
NULL, afi, safi, json, false); NULL, afi, safi, json, false, true);
/* Display each path for this prefix. */ /* Display each path for this prefix. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
@ -2663,7 +2663,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
/* Prefix and num paths displayed once per prefix. */ /* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, dest, (struct prefix *)&p, NULL, route_vty_out_detail_header(vty, bgp, dest, (struct prefix *)&p, NULL,
afi, safi, json, false); afi, safi, json, false, true);
evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest); evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
@ -2798,7 +2798,7 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
/* Prefix and num paths displayed once per prefix. */ /* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest), route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
prd, afi, safi, json, false); prd, afi, safi, json, false, false);
if (json) if (json)
json_paths = json_object_new_array(); json_paths = json_object_new_array();
@ -2820,9 +2820,9 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
path_cnt++; path_cnt++;
} }
if (json && path_cnt) { if (json) {
if (path_cnt) if (path_cnt)
json_object_object_addf(json, json_paths, "%pFX", &p); json_object_object_add(json, "paths", json_paths);
json_object_int_add(json, "numPaths", path_cnt); json_object_int_add(json, "numPaths", path_cnt);
} else { } else {
vty_out(vty, "\nDisplayed %u paths for requested prefix\n", vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
@ -2905,9 +2905,10 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
} }
/* Prefix and num paths displayed once per prefix. */ /* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header( route_vty_out_detail_header(vty, bgp, dest,
vty, bgp, dest, bgp_dest_get_prefix(dest), prd, bgp_dest_get_prefix(dest),
afi, safi, json_prefix, false); prd, afi, safi, json_prefix,
false, false);
prefix_cnt++; prefix_cnt++;
} }
@ -3042,9 +3043,10 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
p->prefixlen); p->prefixlen);
} else } else
/* Prefix and num paths displayed once per prefix. */ /* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header( route_vty_out_detail_header(vty, bgp, dest, p,
vty, bgp, dest, p, (struct prefix_rd *)rd_destp, (struct prefix_rd *)rd_destp,
AFI_L2VPN, SAFI_EVPN, json_prefix, false); AFI_L2VPN, SAFI_EVPN,
json_prefix, false, false);
/* For EVPN, the prefix is displayed for each path (to /* For EVPN, the prefix is displayed for each path (to
* fit in with code that already exists). * fit in with code that already exists).
@ -3197,11 +3199,14 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
/* Prefix and num paths displayed once per prefix. */ /* Prefix and num paths displayed once per prefix. */
if (detail) if (detail)
route_vty_out_detail_header( route_vty_out_detail_header(vty, bgp, dest,
vty, bgp, dest, bgp_dest_get_prefix(
bgp_dest_get_prefix(dest), dest),
(struct prefix_rd *)rd_destp, AFI_L2VPN, (struct prefix_rd *)
SAFI_EVPN, json_prefix, false); rd_destp,
AFI_L2VPN, SAFI_EVPN,
json_prefix, false,
false);
/* For EVPN, the prefix is displayed for each path (to /* For EVPN, the prefix is displayed for each path (to
* fit in * fit in
@ -4840,7 +4845,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
char *vrf = NULL; char *vrf = NULL;
char *neighbor = NULL; char *neighbor = NULL;
as_t as = 0; /* 0 means AS filter not set */ as_t as = 0; /* 0 means AS filter not set */
int as_type = AS_UNSPECIFIED; enum peer_asn_type as_type = AS_UNSPECIFIED;
uint16_t show_flags = 0; uint16_t show_flags = 0;
if (argv_find(argv, argc, "vrf", &idx_vrf)) if (argv_find(argv, argc, "vrf", &idx_vrf))

View file

@ -195,7 +195,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
NULL, 0, 0, NULL); NULL, 0, 0, NULL);
} else { } else {
bgp_withdraw(peer, &p, 0, afi, safi, ZEBRA_ROUTE_BGP, bgp_withdraw(peer, &p, 0, afi, safi, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL); BGP_ROUTE_NORMAL, NULL, NULL, 0);
} }
XFREE(MTYPE_TMP, temp); XFREE(MTYPE_TMP, temp);

View file

@ -305,14 +305,14 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
break; break;
mval->value = value; mval->value = value;
if (op[5] == 1) if (op[5] == 1)
mval->compare_operator |= SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_LESS_THAN; OPERATOR_COMPARE_LESS_THAN);
if (op[6] == 1) if (op[6] == 1)
mval->compare_operator |= SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_GREATER_THAN; OPERATOR_COMPARE_GREATER_THAN);
if (op[7] == 1) if (op[7] == 1)
mval->compare_operator |= SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_EQUAL_TO; OPERATOR_COMPARE_EQUAL_TO);
if (op[1] == 1) if (op[1] == 1)
mval->unary_operator = OPERATOR_UNARY_AND; mval->unary_operator = OPERATOR_UNARY_AND;
else else
@ -413,16 +413,16 @@ int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
mval->value = value; mval->value = value;
if (op[6] == 1) { if (op[6] == 1) {
/* different from */ /* different from */
mval->compare_operator |= SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_LESS_THAN; OPERATOR_COMPARE_LESS_THAN);
mval->compare_operator |= SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_GREATER_THAN; OPERATOR_COMPARE_GREATER_THAN);
} else } else
mval->compare_operator |= SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_EQUAL_TO; OPERATOR_COMPARE_EQUAL_TO);
if (op[7] == 1) if (op[7] == 1)
mval->compare_operator |= SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_EXACT_MATCH; OPERATOR_COMPARE_EXACT_MATCH);
if (op[1] == 1) if (op[1] == 1)
mval->unary_operator = mval->unary_operator =
OPERATOR_UNARY_AND; OPERATOR_UNARY_AND;
@ -467,11 +467,11 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
case FLOWSPEC_SRC_PREFIX: case FLOWSPEC_SRC_PREFIX:
bitmask = 0; bitmask = 0;
if (type == FLOWSPEC_DEST_PREFIX) { if (type == FLOWSPEC_DEST_PREFIX) {
bitmask |= PREFIX_DST_PRESENT; SET_FLAG(bitmask, PREFIX_DST_PRESENT);
prefix = &bpem->dst_prefix; prefix = &bpem->dst_prefix;
prefix_offset = &bpem->dst_prefix_offset; prefix_offset = &bpem->dst_prefix_offset;
} else { } else {
bitmask |= PREFIX_SRC_PRESENT; SET_FLAG(bitmask, PREFIX_SRC_PRESENT);
prefix = &bpem->src_prefix; prefix = &bpem->src_prefix;
prefix_offset = &bpem->src_prefix_offset; prefix_offset = &bpem->src_prefix_offset;
} }
@ -491,14 +491,16 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
*/ */
if (prefix->family == AF_INET if (prefix->family == AF_INET
&& prefix->u.prefix4.s_addr == INADDR_ANY) && prefix->u.prefix4.s_addr == INADDR_ANY)
bpem->match_bitmask_iprule |= bitmask; SET_FLAG(bpem->match_bitmask_iprule,
bitmask);
else if (prefix->family == AF_INET6 else if (prefix->family == AF_INET6
&& !memcmp(&prefix->u.prefix6, && !memcmp(&prefix->u.prefix6,
&in6addr_any, &in6addr_any,
sizeof(struct in6_addr))) sizeof(struct in6_addr)))
bpem->match_bitmask_iprule |= bitmask; SET_FLAG(bpem->match_bitmask_iprule,
bitmask);
else else
bpem->match_bitmask |= bitmask; SET_FLAG(bpem->match_bitmask, bitmask);
} }
offset += ret; offset += ret;
break; break;
@ -640,8 +642,8 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
|| bpem->match_dst_port_num || bpem->match_protocol_num || bpem->match_dst_port_num || bpem->match_protocol_num
|| bpem->match_bitmask || bpem->match_flowlabel_num) || bpem->match_bitmask || bpem->match_flowlabel_num)
bpem->type = BGP_PBR_IPSET; bpem->type = BGP_PBR_IPSET;
else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) || else if (CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_SRC_PRESENT) ||
(bpem->match_bitmask_iprule & PREFIX_DST_PRESENT)) CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_DST_PRESENT))
/* the extracted policy rule may not need an /* the extracted policy rule may not need an
* iptables/ipset filtering. check this may not be * iptables/ipset filtering. check this may not be
* a standard ip rule : permit any to any ( eg) * a standard ip rule : permit any to any ( eg)

View file

@ -602,6 +602,7 @@ const char *const peer_down_str[] = {
"Socket Error", "Socket Error",
"Admin. shutdown (RTT)", "Admin. shutdown (RTT)",
"Suppress Fib Turned On or Off", "Suppress Fib Turned On or Off",
"Password config change",
}; };
static void bgp_graceful_restart_timer_off(struct peer_connection *connection, static void bgp_graceful_restart_timer_off(struct peer_connection *connection,
@ -687,6 +688,11 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
COMMUNITY_NO_LLGR)) COMMUNITY_NO_LLGR))
continue; continue;
if (bgp_attr_get_community(pi->attr) &&
community_include(bgp_attr_get_community(pi->attr),
COMMUNITY_LLGR_STALE))
continue;
if (bgp_debug_neighbor_events(peer)) if (bgp_debug_neighbor_events(peer))
zlog_debug( zlog_debug(
"%pBP Long-lived set stale community (LLGR_STALE) for: %pFX", "%pBP Long-lived set stale community (LLGR_STALE) for: %pFX",
@ -695,10 +701,8 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
attr = *pi->attr; attr = *pi->attr;
bgp_attr_add_llgr_community(&attr); bgp_attr_add_llgr_community(&attr);
pi->attr = bgp_attr_intern(&attr); pi->attr = bgp_attr_intern(&attr);
bgp_recalculate_afi_safi_bestpaths( bgp_process(peer->bgp, rm, pi, afi,
peer->bgp, afi, safi); safi);
break;
} }
} }
} else { } else {
@ -715,6 +719,11 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
COMMUNITY_NO_LLGR)) COMMUNITY_NO_LLGR))
continue; continue;
if (bgp_attr_get_community(pi->attr) &&
community_include(bgp_attr_get_community(pi->attr),
COMMUNITY_LLGR_STALE))
continue;
if (bgp_debug_neighbor_events(peer)) if (bgp_debug_neighbor_events(peer))
zlog_debug( zlog_debug(
"%pBP Long-lived set stale community (LLGR_STALE) for: %pFX", "%pBP Long-lived set stale community (LLGR_STALE) for: %pFX",
@ -723,10 +732,7 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
attr = *pi->attr; attr = *pi->attr;
bgp_attr_add_llgr_community(&attr); bgp_attr_add_llgr_community(&attr);
pi->attr = bgp_attr_intern(&attr); pi->attr = bgp_attr_intern(&attr);
bgp_recalculate_afi_safi_bestpaths(peer->bgp, bgp_process(peer->bgp, dest, pi, afi, safi);
afi, safi);
break;
} }
} }
} }
@ -1482,7 +1488,7 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection)
EVENT_OFF(connection->t_connect); EVENT_OFF(connection->t_connect);
EVENT_OFF(connection->t_holdtime); EVENT_OFF(connection->t_holdtime);
EVENT_OFF(connection->t_routeadv); EVENT_OFF(connection->t_routeadv);
EVENT_OFF(peer->connection->t_delayopen); EVENT_OFF(connection->t_delayopen);
/* Clear input and output buffer. */ /* Clear input and output buffer. */
frr_with_mutex (&connection->io_mtx) { frr_with_mutex (&connection->io_mtx) {
@ -1801,18 +1807,14 @@ bgp_connect_fail(struct peer_connection *connection)
*/ */
static void bgp_connect_in_progress_update_connection(struct peer *peer) static void bgp_connect_in_progress_update_connection(struct peer *peer)
{ {
if (bgp_getsockname(peer) < 0) { bgp_updatesockname(peer);
if (!peer->su_remote && if (!peer->su_remote && !BGP_CONNECTION_SU_UNSPEC(peer->connection)) {
!BGP_CONNECTION_SU_UNSPEC(peer->connection)) {
/* if connect initiated, then dest port and dest addresses are well known */ /* if connect initiated, then dest port and dest addresses are well known */
peer->su_remote = sockunion_dup(&peer->connection->su); peer->su_remote = sockunion_dup(&peer->connection->su);
if (sockunion_family(peer->su_remote) == AF_INET) if (sockunion_family(peer->su_remote) == AF_INET)
peer->su_remote->sin.sin_port = peer->su_remote->sin.sin_port = htons(peer->port);
htons(peer->port);
else if (sockunion_family(peer->su_remote) == AF_INET6) else if (sockunion_family(peer->su_remote) == AF_INET6)
peer->su_remote->sin6.sin6_port = peer->su_remote->sin6.sin6_port = htons(peer->port);
htons(peer->port);
}
} }
} }
@ -2046,9 +2048,10 @@ static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi,
} }
gr_info->eor_required++; gr_info->eor_required++;
/* Send message to RIB indicating route update pending */ /* Send message to RIB indicating route update pending */
if (gr_info->af_enabled[afi][safi] == false) { if (gr_info->af_enabled == false) {
gr_info->af_enabled[afi][safi] = true; gr_info->af_enabled = true;
/* Send message to RIB */ gr_info->route_sync = false;
bgp->gr_route_sync_pending = true;
bgp_zebra_update(bgp, afi, safi, bgp_zebra_update(bgp, afi, safi,
ZEBRA_CLIENT_ROUTE_UPDATE_PENDING); ZEBRA_CLIENT_ROUTE_UPDATE_PENDING);
} }
@ -2082,7 +2085,7 @@ static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi)
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)
&& BGP_PEER_RESTARTING_MODE(peer)) { && BGP_PEER_RESTARTING_MODE(peer)) {
/* Check if the forwarding state is preserved */ /* Check if the forwarding state is preserved */
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) { if (bgp_gr_is_forwarding_preserved(bgp)) {
gr_info = &(bgp->gr_info[afi][safi]); gr_info = &(bgp->gr_info[afi][safi]);
ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info); ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info);
} }
@ -2199,8 +2202,7 @@ bgp_establish(struct peer_connection *connection)
} else { } else {
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
BGP_PEER_RESTARTING_MODE(peer) && BGP_PEER_RESTARTING_MODE(peer) &&
CHECK_FLAG(peer->bgp->flags, bgp_gr_is_forwarding_preserved(peer->bgp))
BGP_FLAG_GR_PRESERVE_FWD))
peer->bgp->gr_info[afi][safi] peer->bgp->gr_info[afi][safi]
.eor_required++; .eor_required++;
} }
@ -2695,33 +2697,11 @@ int bgp_event_update(struct peer_connection *connection,
} }
/* BGP GR Code */ /* BGP GR Code */
int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, static inline void
enum global_mode global_new_state, bgp_peer_inherit_global_gr_mode(struct peer *peer,
enum global_mode global_old_state) enum global_mode global_gr_mode)
{ {
struct peer *peer = {0}; switch (global_gr_mode) {
struct listnode *node = {0};
struct listnode *nnode = {0};
enum peer_mode peer_old_state = PEER_INVALID;
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("%s [BGP_GR] Peer: (%s) :", __func__,
peer->host);
peer_old_state = bgp_peer_gr_mode_get(peer);
if (peer_old_state == PEER_GLOBAL_INHERIT) {
/*
*Reset only these peers and send a
*new open message with the change capabilities.
*Considering the mode to be "global_new_state" and
*do all operation accordingly
*/
switch (global_new_state) {
case GLOBAL_HELPER: case GLOBAL_HELPER:
BGP_PEER_GR_HELPER_ENABLE(peer); BGP_PEER_GR_HELPER_ENABLE(peer);
break; break;
@ -2732,16 +2712,46 @@ int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
BGP_PEER_GR_DISABLE(peer); BGP_PEER_GR_DISABLE(peer);
break; break;
case GLOBAL_INVALID: case GLOBAL_INVALID:
zlog_debug("%s [BGP_GR] GLOBAL_INVALID", default:
__func__); zlog_err("Unexpected Global GR mode %d", global_gr_mode);
return BGP_ERR_GR_OPERATION_FAILED;
}
}
} }
}
bgp->global_gr_present_state = global_new_state; static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp,
enum global_mode global_new_state)
{
struct peer *peer = {0};
struct listnode *node = {0};
struct listnode *nnode = {0};
enum peer_mode peer_old_state = PEER_INVALID;
return BGP_GR_SUCCESS; /* TODO: Need to handle peer-groups. */
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
peer_old_state = bgp_peer_gr_mode_get(peer);
if (peer_old_state != PEER_GLOBAL_INHERIT)
continue;
bgp_peer_inherit_global_gr_mode(peer, global_new_state);
bgp_peer_gr_flags_update(peer);
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64
"...resetting session",
peer, peer->peer_gr_new_status_flag,
peer->flags);
peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
/* Reset session to match with behavior for other peer
* configs that require the session to be re-setup.
*/
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status))
bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset_safe(peer, &nnode);
}
} }
int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd)
@ -2749,46 +2759,27 @@ int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd)
enum global_mode global_new_state = GLOBAL_INVALID; enum global_mode global_new_state = GLOBAL_INVALID;
enum global_mode global_old_state = GLOBAL_INVALID; enum global_mode global_old_state = GLOBAL_INVALID;
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("%s [BGP_GR]START: global_gr_cmd :%s:", __func__,
print_global_gr_cmd(global_gr_cmd));
global_old_state = bgp_global_gr_mode_get(bgp); global_old_state = bgp_global_gr_mode_get(bgp);
global_new_state = bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd];
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] global_old_gr_state :%s:", zlog_debug("%s: Handle GR command %s, current GR state %s, new GR state %s",
print_global_gr_mode(global_old_state)); bgp->name_pretty, print_global_gr_cmd(global_gr_cmd),
print_global_gr_mode(global_old_state),
if (global_old_state != GLOBAL_INVALID) {
global_new_state =
bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd];
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] global_new_gr_state :%s:",
print_global_gr_mode(global_new_state)); print_global_gr_mode(global_new_state));
} else {
zlog_err("%s [BGP_GR] global_old_state == GLOBAL_INVALID", if (global_old_state == GLOBAL_INVALID)
__func__);
return BGP_ERR_GR_OPERATION_FAILED; return BGP_ERR_GR_OPERATION_FAILED;
} if (global_new_state == GLOBAL_INVALID)
if (global_new_state == GLOBAL_INVALID) {
zlog_err("%s [BGP_GR] global_new_state == GLOBAL_INVALID",
__func__);
return BGP_ERR_GR_INVALID_CMD; return BGP_ERR_GR_INVALID_CMD;
} if (global_new_state == global_old_state)
if (global_new_state == global_old_state) {
/* Trace msg */
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"%s [BGP_GR] global_new_state == global_old_state :%s",
__func__,
print_global_gr_mode(global_new_state));
return BGP_GR_NO_OPERATION; return BGP_GR_NO_OPERATION;
}
return bgp_gr_lookup_n_update_all_peer(bgp, global_new_state, /* Update global GR mode and process all peers in instance. */
global_old_state); bgp->global_gr_present_state = global_new_state;
bgp_gr_update_mode_of_all_peers(bgp, global_new_state);
return BGP_GR_SUCCESS;
} }
const char *print_peer_gr_mode(enum peer_mode pr_mode) const char *print_peer_gr_mode(enum peer_mode pr_mode)
@ -2903,179 +2894,102 @@ int bgp_neighbor_graceful_restart(struct peer *peer,
{ {
enum peer_mode peer_new_state = PEER_INVALID; enum peer_mode peer_new_state = PEER_INVALID;
enum peer_mode peer_old_state = PEER_INVALID; enum peer_mode peer_old_state = PEER_INVALID;
struct bgp_peer_gr peer_state; struct bgp_peer_gr gr_fsm;
int result = BGP_GR_FAILURE; int result = BGP_GR_FAILURE;
/*
* fetch peer_old_state from peer structure also
* fetch global_old_state from bgp structure,
* peer had a back pointer to bgpo struct ;
*/
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:",
__func__, peer->host,
print_peer_gr_cmd(peer_gr_cmd));
peer_old_state = bgp_peer_gr_mode_get(peer); peer_old_state = bgp_peer_gr_mode_get(peer);
gr_fsm = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd];
peer_new_state = gr_fsm.next_state;
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("%s [BGP_GR] peer_old_state: %d", __func__, zlog_debug("%pBP: Handle GR command %s, current GR state %s, new GR state %s",
peer_old_state); peer, print_peer_gr_cmd(peer_gr_cmd),
print_peer_gr_mode(peer_old_state),
print_peer_gr_mode(peer_new_state));
if (peer_old_state == PEER_INVALID) if (peer_old_state == PEER_INVALID)
return BGP_ERR_GR_OPERATION_FAILED; return BGP_ERR_GR_OPERATION_FAILED;
peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd];
peer_new_state = peer_state.next_state;
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("%s [BGP_GR] peer_new_state: %d", __func__,
peer_new_state);
if (peer_new_state == PEER_INVALID) if (peer_new_state == PEER_INVALID)
return BGP_ERR_GR_INVALID_CMD; return BGP_ERR_GR_INVALID_CMD;
if (peer_new_state != peer_old_state) { if (peer_new_state == peer_old_state)
result = peer_state.action_fun(peer, peer_old_state,
peer_new_state);
} else {
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] peer_old_state == peer_new_state !");
return BGP_GR_NO_OPERATION; return BGP_GR_NO_OPERATION;
}
if (result == BGP_GR_SUCCESS) { result = gr_fsm.action_fun(peer, peer_old_state, peer_new_state);
/* Update the mode i.e peer_new_state into the peer structure */
peer->peer_gr_present_state = peer_new_state;
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] Successfully change the state of the peer to : %s : !",
print_peer_gr_mode(peer_new_state));
return BGP_GR_SUCCESS;
}
return result; return result;
} }
unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, static inline bool gr_mode_matches(enum peer_mode peer_gr_mode,
enum peer_mode new_peer_state) enum global_mode global_gr_mode)
{ {
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) if ((peer_gr_mode == PEER_HELPER && global_gr_mode == GLOBAL_HELPER) ||
zlog_debug( (peer_gr_mode == PEER_GR && global_gr_mode == GLOBAL_GR) ||
"%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!", (peer_gr_mode == PEER_DISABLE && global_gr_mode == GLOBAL_DISABLE))
__func__, print_peer_gr_mode(old_peer_state), return true;
print_peer_gr_mode(new_peer_state)); return false;
enum global_mode bgp_gr_global_mode = GLOBAL_INVALID;
unsigned int ret = BGP_GR_FAILURE;
if (old_peer_state == new_peer_state) {
/* Nothing to do over here as the present and old state is the
* same */
return BGP_GR_NO_OPERATION;
}
if ((old_peer_state == PEER_INVALID)
|| (new_peer_state == PEER_INVALID)) {
/* something bad happend , print error message */
return BGP_ERR_GR_INVALID_CMD;
}
bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp);
if ((old_peer_state == PEER_GLOBAL_INHERIT)
&& (new_peer_state != PEER_GLOBAL_INHERIT)) {
/* fetch the Mode running in the Global state machine
*from the bgp structure into a variable called
*bgp_gr_global_mode
*/
/* Here we are checking if the
*1. peer_new_state == global_mode == helper_mode
*2. peer_new_state == global_mode == GR_mode
*3. peer_new_state == global_mode == disabled_mode
*/
BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer);
if ((int)new_peer_state == (int)bgp_gr_global_mode) {
/* This is incremental updates i.e no tear down
* of the existing session
* as the peer is already working in the same mode.
*/
ret = BGP_GR_SUCCESS;
} else {
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] Peer state changed from :%s ",
print_peer_gr_mode(old_peer_state));
bgp_peer_move_to_gr_mode(peer, new_peer_state);
ret = BGP_GR_SUCCESS;
}
}
/* In the case below peer is going into Global inherit mode i.e.
* the peer would work as the mode configured at the global level
*/
else if ((new_peer_state == PEER_GLOBAL_INHERIT)
&& (old_peer_state != PEER_GLOBAL_INHERIT)) {
/* Here in this case it would be destructive
* in all the cases except one case when,
* Global GR is configured Disabled
* and present_peer_state is not disable
*/
BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
if ((int)old_peer_state == (int)bgp_gr_global_mode) {
/* This is incremental updates
*i.e no tear down of the existing session
*as the peer is already working in the same mode.
*/
ret = BGP_GR_SUCCESS;
} else {
/* Destructive always */
/* Tear down the old session
* and send the new capability
* as per the bgp_gr_global_mode
*/
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] Peer state changed from :%s",
print_peer_gr_mode(old_peer_state));
bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode);
ret = BGP_GR_SUCCESS;
}
} else {
/*
*This else case, it include all the cases except -->
*(new_peer_state != Peer_Global) &&
*( old_peer_state != Peer_Global )
*/
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] Peer state changed from :%s",
print_peer_gr_mode(old_peer_state));
bgp_peer_move_to_gr_mode(peer, new_peer_state);
ret = BGP_GR_SUCCESS;
}
return ret;
} }
inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state,
enum peer_mode new_state)
{
enum global_mode global_gr_mode;
bool session_reset = true;
if (old_state == new_state)
return BGP_GR_NO_OPERATION;
if ((old_state == PEER_INVALID) || (new_state == PEER_INVALID))
return BGP_ERR_GR_INVALID_CMD;
global_gr_mode = bgp_global_gr_mode_get(peer->bgp);
if ((old_state == PEER_GLOBAL_INHERIT) &&
(new_state != PEER_GLOBAL_INHERIT)) {
BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer);
if (gr_mode_matches(new_state, global_gr_mode))
/* Peer was inheriting the global state and
* its new state still is the same, so a
* session reset is not needed.
*/
session_reset = false;
} else if ((new_state == PEER_GLOBAL_INHERIT) &&
(old_state != PEER_GLOBAL_INHERIT)) {
BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
if (gr_mode_matches(old_state, global_gr_mode))
/* Peer is inheriting the global state and
* its old state was also the same, so a
* session reset is not needed.
*/
session_reset = false;
}
/* Ensure we move to the new state and update flags */
bgp_peer_move_to_gr_mode(peer, new_state);
if (session_reset) {
peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
/* Reset session to match with behavior for other peer
* configs that require the session to be re-setup.
*/
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status))
bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
}
return BGP_GR_SUCCESS;
}
void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state)
{ {
int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp); enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp);
enum peer_mode old_state = bgp_peer_gr_mode_get(peer);
switch (new_state) { switch (new_state) {
case PEER_HELPER: case PEER_HELPER:
@ -3089,57 +3003,38 @@ inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state)
break; break;
case PEER_GLOBAL_INHERIT: case PEER_GLOBAL_INHERIT:
BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
bgp_peer_inherit_global_gr_mode(peer, global_gr_mode);
if (bgp_global_gr_mode == GLOBAL_HELPER) {
BGP_PEER_GR_HELPER_ENABLE(peer);
} else if (bgp_global_gr_mode == GLOBAL_GR) {
BGP_PEER_GR_ENABLE(peer);
} else if (bgp_global_gr_mode == GLOBAL_DISABLE) {
BGP_PEER_GR_DISABLE(peer);
} else {
zlog_err(
"[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!");
}
break; break;
case PEER_INVALID:
default: default:
zlog_err( zlog_err(
"[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!"); "[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!");
break; break;
} }
bgp_peer_gr_flags_update(peer);
peer->peer_gr_present_state = new_state;
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !", zlog_debug("%pBP: Peer GR mode changed from %s to %s, GR flags 0x%x peer flags 0x%" PRIx64,
new_state); peer, print_peer_gr_mode(old_state),
print_peer_gr_mode(new_state),
peer->peer_gr_new_status_flag, peer->flags);
} }
void bgp_peer_gr_flags_update(struct peer *peer) void bgp_peer_gr_flags_update(struct peer *peer)
{ {
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("%s [BGP_GR] called !", __func__);
if (CHECK_FLAG(peer->peer_gr_new_status_flag, if (CHECK_FLAG(peer->peer_gr_new_status_flag,
PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER);
else else
UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER);
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !",
peer->host,
(CHECK_FLAG(peer->flags,
PEER_FLAG_GRACEFUL_RESTART_HELPER)
? "Set"
: "UnSet"));
if (CHECK_FLAG(peer->peer_gr_new_status_flag, if (CHECK_FLAG(peer->peer_gr_new_status_flag,
PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) PEER_GRACEFUL_RESTART_NEW_STATE_RESTART))
SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART);
else else
UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART);
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !",
peer->host,
(CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
? "Set"
: "UnSet"));
if (CHECK_FLAG(peer->peer_gr_new_status_flag, if (CHECK_FLAG(peer->peer_gr_new_status_flag,
PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT))
SET_FLAG(peer->flags, SET_FLAG(peer->flags,
@ -3147,28 +3042,28 @@ void bgp_peer_gr_flags_update(struct peer *peer)
else else
UNSET_FLAG(peer->flags, UNSET_FLAG(peer->flags,
PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT);
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug( zlog_debug("%pBP: Peer flags updated to 0x%" PRIx64
"[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !", ", GR flags 0x%x, GR mode %s",
peer->host, peer, peer->flags, peer->peer_gr_new_status_flag,
(CHECK_FLAG(peer->flags, print_peer_gr_mode(bgp_peer_gr_mode_get(peer)));
PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT)
? "Set"
: "UnSet"));
if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
&& !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) {
zlog_debug("[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!",
peer->host);
/*
* If GR has been completely disabled for the peer and we were
* acting as the Helper for the peer (i.e., keeping stale routes
* and running the restart timer or stalepath timer), clear those
* states.
*/
if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) &&
!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) {
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP: GR disabled, stopping NSF and clearing stale routes",
peer);
peer_nsf_stop(peer); peer_nsf_stop(peer);
zlog_debug(
"[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!",
peer->host);
} }
} }
} }

View file

@ -151,7 +151,7 @@ int bgp_neighbor_graceful_restart(struct peer *peer,
enum peer_gr_command peer_gr_cmd); enum peer_gr_command peer_gr_cmd);
unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state,
enum peer_mode new_peer_state); enum peer_mode new_peer_state);
void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state); void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state);
unsigned int bgp_peer_gr_helper_enable(struct peer *peer); unsigned int bgp_peer_gr_helper_enable(struct peer *peer);
unsigned int bgp_peer_gr_enable(struct peer *peer); unsigned int bgp_peer_gr_enable(struct peer *peer);
unsigned int bgp_peer_gr_global_inherit(struct peer *peer); unsigned int bgp_peer_gr_global_inherit(struct peer *peer);
@ -160,9 +160,6 @@ enum peer_mode bgp_peer_gr_mode_get(struct peer *peer);
enum global_mode bgp_global_gr_mode_get(struct bgp *bgp); enum global_mode bgp_global_gr_mode_get(struct bgp *bgp);
enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer); enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer);
unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer); unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer);
int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
enum global_mode global_new_state,
enum global_mode global_old_state);
void bgp_peer_gr_flags_update(struct peer *peer); void bgp_peer_gr_flags_update(struct peer *peer);
const char *print_peer_gr_mode(enum peer_mode pr_mode); const char *print_peer_gr_mode(enum peer_mode pr_mode);
const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd); const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);

View file

@ -38,7 +38,7 @@ static void *bgp_labels_hash_alloc(void *p)
struct bgp_labels *new; struct bgp_labels *new;
uint8_t i; uint8_t i;
new = XMALLOC(MTYPE_BGP_LABELS, sizeof(struct bgp_labels)); new = XCALLOC(MTYPE_BGP_LABELS, sizeof(struct bgp_labels));
new->num_labels = labels->num_labels; new->num_labels = labels->num_labels;
for (i = 0; i < labels->num_labels; i++) for (i = 0; i < labels->num_labels; i++)
@ -576,7 +576,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
} else { } else {
bgp_withdraw(peer, &p, addpath_id, packet->afi, bgp_withdraw(peer, &p, addpath_id, packet->afi,
SAFI_UNICAST, ZEBRA_ROUTE_BGP, SAFI_UNICAST, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, NULL, &label, 1, NULL); BGP_ROUTE_NORMAL, NULL, &label, 1);
} }
} }

View file

@ -143,7 +143,6 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
const struct prefix *p = bgp_dest_get_prefix(dest); const struct prefix *p = bgp_dest_get_prefix(dest);
struct prefix_evpn *pevpn = (struct prefix_evpn *)dest; struct prefix_evpn *pevpn = (struct prefix_evpn *)dest;
struct prefix_rd prd; struct prefix_rd prd;
struct bgp_route_evpn *evpn;
if (pevpn->family == AF_EVPN if (pevpn->family == AF_EVPN
&& pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
@ -195,12 +194,10 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
continue; continue;
} }
memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
sizeof(evpn));
bgp_update(peer, p, pi->addpath_rx_id, pi->attr, bgp_update(peer, p, pi->addpath_rx_id, pi->attr,
AFI_L2VPN, SAFI_EVPN, ZEBRA_ROUTE_BGP, AFI_L2VPN, SAFI_EVPN, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, &prd, label_pnt, BGP_ROUTE_NORMAL, &prd, label_pnt, num_labels,
num_labels, 1, evpn); 1, bgp_attr_get_evpn_overlay(pi->attr));
} }
} }
} }

View file

@ -63,8 +63,7 @@ DEFINE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled),
(vrf, enabled)); (vrf, enabled));
/* bgpd options, we use GNU getopt library. */ /* bgpd options, we use GNU getopt library. */
static const struct option longopts[] = { static const struct option longopts[] = { { "bgp_port", required_argument, NULL, 'p' },
{ "bgp_port", required_argument, NULL, 'p' },
{ "listenon", required_argument, NULL, 'l' }, { "listenon", required_argument, NULL, 'l' },
{ "no_kernel", no_argument, NULL, 'n' }, { "no_kernel", no_argument, NULL, 'n' },
{ "skip_runas", no_argument, NULL, 'S' }, { "skip_runas", no_argument, NULL, 'S' },
@ -72,9 +71,8 @@ static const struct option longopts[] = {
{ "int_num", required_argument, NULL, 'I' }, { "int_num", required_argument, NULL, 'I' },
{ "no_zebra", no_argument, NULL, 'Z' }, { "no_zebra", no_argument, NULL, 'Z' },
{ "socket_size", required_argument, NULL, 's' }, { "socket_size", required_argument, NULL, 's' },
{ "v6-with-v4-nexthops", no_argument, NULL, 'v' }, { "v6-with-v4-nexthops", no_argument, NULL, 'x' },
{ 0 } { 0 } };
};
/* signal definitions */ /* signal definitions */
void sighup(void); void sighup(void);
@ -424,11 +422,12 @@ int main(int argc, char **argv)
int buffer_size = BGP_SOCKET_SNDBUF_SIZE; int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
char *address; char *address;
struct listnode *node; struct listnode *node;
bool v6_with_v4_nexthops = false;
addresses->cmp = (int (*)(void *, void *))strcmp; addresses->cmp = (int (*)(void *, void *))strcmp;
frr_preinit(&bgpd_di, argc, argv); frr_preinit(&bgpd_di, argc, argv);
frr_opt_add("p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts, frr_opt_add("p:l:SnZe:I:s:x" DEPRECATED_OPTIONS, longopts,
" -p, --bgp_port Set BGP listen port number (0 means do not listen).\n" " -p, --bgp_port Set BGP listen port number (0 means do not listen).\n"
" -l, --listenon Listen on specified address (implies -n)\n" " -l, --listenon Listen on specified address (implies -n)\n"
" -n, --no_kernel Do not install route to kernel.\n" " -n, --no_kernel Do not install route to kernel.\n"
@ -437,7 +436,7 @@ int main(int argc, char **argv)
" -e, --ecmp Specify ECMP to use.\n" " -e, --ecmp Specify ECMP to use.\n"
" -I, --int_num Set instance number (label-manager)\n" " -I, --int_num Set instance number (label-manager)\n"
" -s, --socket_size Set BGP peer socket send buffer size\n" " -s, --socket_size Set BGP peer socket send buffer size\n"
" , --v6-with-v4-nexthop Allow BGP to form v6 neighbors using v4 nexthops\n"); " -x, --v6-with-v4-nexthop Allow BGP to form v6 neighbors using v4 nexthops\n");
/* Command line argument treatment. */ /* Command line argument treatment. */
while (1) { while (1) {
@ -499,8 +498,8 @@ int main(int argc, char **argv)
case 's': case 's':
buffer_size = atoi(optarg); buffer_size = atoi(optarg);
break; break;
case 'v': case 'x':
bm->v6_with_v4_nexthops = true; v6_with_v4_nexthops = true;
break; break;
default: default:
frr_help_exit(1); frr_help_exit(1);
@ -511,13 +510,18 @@ int main(int argc, char **argv)
/* BGP master init. */ /* BGP master init. */
bgp_master_init(frr_init(), buffer_size, addresses); bgp_master_init(frr_init(), buffer_size, addresses);
bm->startup_time = monotime(NULL);
bm->port = bgp_port; bm->port = bgp_port;
bm->v6_with_v4_nexthops = v6_with_v4_nexthops;
if (bgp_port == 0) if (bgp_port == 0)
bgp_option_set(BGP_OPT_NO_LISTEN); bgp_option_set(BGP_OPT_NO_LISTEN);
if (no_fib_flag || no_zebra_flag) if (no_fib_flag || no_zebra_flag)
bgp_option_set(BGP_OPT_NO_FIB); bgp_option_set(BGP_OPT_NO_FIB);
if (no_zebra_flag) if (no_zebra_flag)
bgp_option_set(BGP_OPT_NO_ZEBRA); bgp_option_set(BGP_OPT_NO_ZEBRA);
if (bgpd_di.graceful_restart)
SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART);
bgp_error_init(); bgp_error_init();
/* Initializations. */ /* Initializations. */
libagentx_init(); libagentx_init();

View file

@ -135,3 +135,5 @@ DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message"); DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message");
DEFINE_MTYPE(BGPD, BGP_SOFT_VERSION, "Software Version"); DEFINE_MTYPE(BGPD, BGP_SOFT_VERSION, "Software Version");
DEFINE_MTYPE(BGPD, BGP_EVPN_OVERLAY, "BGP EVPN Overlay");

View file

@ -134,4 +134,6 @@ DECLARE_MTYPE(BGP_NOTIFICATION);
DECLARE_MTYPE(BGP_SOFT_VERSION); DECLARE_MTYPE(BGP_SOFT_VERSION);
DECLARE_MTYPE(BGP_EVPN_OVERLAY);
#endif /* _QUAGGA_BGP_MEMORY_H */ #endif /* _QUAGGA_BGP_MEMORY_H */

View file

@ -2,8 +2,10 @@
/* /*
* BGP Multipath * BGP Multipath
* Copyright (C) 2010 Google Inc. * Copyright (C) 2010 Google Inc.
* 2024 Nvidia Corporation
* Donald Sharp
* *
* This file is part of Quagga * This file is part of FRR
*/ */
#include <zebra.h> #include <zebra.h>
@ -190,78 +192,6 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
return compare; return compare;
} }
/*
* bgp_path_info_mpath_cmp
*
* This function determines our multipath list ordering. By ordering
* the list we can deterministically select which paths are included
* in the multipath set. The ordering also helps in detecting changes
* in the multipath selection so we can detect whether to send an
* update to zebra.
*
* The order of paths is determined first by received nexthop, and then
* by peer address if the nexthops are the same.
*/
static int bgp_path_info_mpath_cmp(void *val1, void *val2)
{
struct bgp_path_info *bpi1, *bpi2;
int compare;
bpi1 = val1;
bpi2 = val2;
compare = bgp_path_info_nexthop_cmp(bpi1, bpi2);
if (!compare) {
if (!bpi1->peer->su_remote && !bpi2->peer->su_remote)
compare = 0;
else if (!bpi1->peer->su_remote)
compare = 1;
else if (!bpi2->peer->su_remote)
compare = -1;
else
compare = sockunion_cmp(bpi1->peer->su_remote,
bpi2->peer->su_remote);
}
return compare;
}
/*
* bgp_mp_list_init
*
* Initialize the mp_list, which holds the list of multipaths
* selected by bgp_best_selection
*/
void bgp_mp_list_init(struct list *mp_list)
{
assert(mp_list);
memset(mp_list, 0, sizeof(struct list));
mp_list->cmp = bgp_path_info_mpath_cmp;
}
/*
* bgp_mp_list_clear
*
* Clears all entries out of the mp_list
*/
void bgp_mp_list_clear(struct list *mp_list)
{
assert(mp_list);
list_delete_all_node(mp_list);
}
/*
* bgp_mp_list_add
*
* Adds a multipath entry to the mp_list
*/
void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo)
{
assert(mp_list && mpinfo);
listnode_add_sort(mp_list, mpinfo);
}
/* /*
* bgp_path_info_mpath_new * bgp_path_info_mpath_new
* *
@ -274,6 +204,7 @@ static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void)
new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO, new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
sizeof(struct bgp_path_info_mpath)); sizeof(struct bgp_path_info_mpath));
new_mpath->mp_count = 1;
return new_mpath; return new_mpath;
} }
@ -287,6 +218,8 @@ void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath)
if (mpath && *mpath) { if (mpath && *mpath) {
if ((*mpath)->mp_attr) if ((*mpath)->mp_attr)
bgp_attr_unintern(&(*mpath)->mp_attr); bgp_attr_unintern(&(*mpath)->mp_attr);
(*mpath)->mp_attr = NULL;
XFREE(MTYPE_BGP_MPATH_INFO, *mpath); XFREE(MTYPE_BGP_MPATH_INFO, *mpath);
} }
} }
@ -313,49 +246,6 @@ bgp_path_info_mpath_get(struct bgp_path_info *path)
return path->mpath; return path->mpath;
} }
/*
* bgp_path_info_mpath_enqueue
*
* Enqueue a path onto the multipath list given the previous multipath
* list entry
*/
static void bgp_path_info_mpath_enqueue(struct bgp_path_info *prev_info,
struct bgp_path_info *path)
{
struct bgp_path_info_mpath *prev, *mpath;
prev = bgp_path_info_mpath_get(prev_info);
mpath = bgp_path_info_mpath_get(path);
if (!prev || !mpath)
return;
mpath->mp_next = prev->mp_next;
mpath->mp_prev = prev;
if (prev->mp_next)
prev->mp_next->mp_prev = mpath;
prev->mp_next = mpath;
SET_FLAG(path->flags, BGP_PATH_MULTIPATH);
}
/*
* bgp_path_info_mpath_dequeue
*
* Remove a path from the multipath list
*/
void bgp_path_info_mpath_dequeue(struct bgp_path_info *path)
{
struct bgp_path_info_mpath *mpath = path->mpath;
if (!mpath)
return;
if (mpath->mp_prev)
mpath->mp_prev->mp_next = mpath->mp_next;
if (mpath->mp_next)
mpath->mp_next->mp_prev = mpath->mp_prev;
mpath->mp_next = mpath->mp_prev = NULL;
UNSET_FLAG(path->flags, BGP_PATH_MULTIPATH);
}
/* /*
* bgp_path_info_mpath_next * bgp_path_info_mpath_next
* *
@ -363,9 +253,16 @@ void bgp_path_info_mpath_dequeue(struct bgp_path_info *path)
*/ */
struct bgp_path_info *bgp_path_info_mpath_next(struct bgp_path_info *path) struct bgp_path_info *bgp_path_info_mpath_next(struct bgp_path_info *path)
{ {
if (!path->mpath || !path->mpath->mp_next) path = path->next;
while (path) {
if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH))
return path;
path = path->next;
}
return NULL; return NULL;
return path->mpath->mp_next->mp_info;
} }
/* /*
@ -386,7 +283,8 @@ struct bgp_path_info *bgp_path_info_mpath_first(struct bgp_path_info *path)
uint32_t bgp_path_info_mpath_count(struct bgp_path_info *path) uint32_t bgp_path_info_mpath_count(struct bgp_path_info *path)
{ {
if (!path->mpath) if (!path->mpath)
return 0; return 1;
return path->mpath->mp_count; return path->mpath->mp_count;
} }
@ -411,6 +309,10 @@ static void bgp_path_info_mpath_count_set(struct bgp_path_info *path,
* bgp_path_info_mpath_lb_update * bgp_path_info_mpath_lb_update
* *
* Update cumulative info related to link-bandwidth * Update cumulative info related to link-bandwidth
*
* This is only set on the first mpath of the list
* as such we should UNSET the flags when removing
* to ensure nothing accidently happens
*/ */
static void bgp_path_info_mpath_lb_update(struct bgp_path_info *path, bool set, static void bgp_path_info_mpath_lb_update(struct bgp_path_info *path, bool set,
bool all_paths_lb, uint64_t cum_bw) bool all_paths_lb, uint64_t cum_bw)
@ -472,10 +374,10 @@ bool bgp_path_info_mpath_chkwtd(struct bgp *bgp, struct bgp_path_info *path)
*/ */
if (bgp->lb_handling != BGP_LINK_BW_SKIP_MISSING && if (bgp->lb_handling != BGP_LINK_BW_SKIP_MISSING &&
bgp->lb_handling != BGP_LINK_BW_DEFWT_4_MISSING) bgp->lb_handling != BGP_LINK_BW_DEFWT_4_MISSING)
return (path->mpath->mp_flags & BGP_MP_LB_ALL); return CHECK_FLAG(path->mpath->mp_flags, BGP_MP_LB_ALL);
/* At least one path should have bandwidth. */ /* At least one path should have bandwidth. */
return (path->mpath->mp_flags & BGP_MP_LB_PRESENT); return CHECK_FLAG(path->mpath->mp_flags, BGP_MP_LB_PRESENT);
} }
/* /*
@ -511,58 +413,51 @@ static void bgp_path_info_mpath_attr_set(struct bgp_path_info *path,
/* /*
* bgp_path_info_mpath_update * bgp_path_info_mpath_update
* *
* Compare and sync up the multipath list with the mp_list generated by * Compare and sync up the multipath flags with what was choosen
* bgp_best_selection * in best selection
*/ */
void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *new_best, struct bgp_path_info *new_best, struct bgp_path_info *old_best,
struct bgp_path_info *old_best, uint32_t num_candidates, struct bgp_maxpaths_cfg *mpath_cfg)
struct list *mp_list,
struct bgp_maxpaths_cfg *mpath_cfg)
{ {
uint16_t maxpaths, mpath_count, old_mpath_count; uint16_t maxpaths, mpath_count, old_mpath_count;
uint64_t bwval; uint64_t bwval;
uint64_t cum_bw, old_cum_bw; uint64_t cum_bw, old_cum_bw;
struct listnode *mp_node, *mp_next_node; struct bgp_path_info *cur_iterator = NULL;
struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; bool mpath_changed, debug;
int mpath_changed, debug;
bool all_paths_lb; bool all_paths_lb;
char path_buf[PATH_ADDPATH_STR_BUFFER]; char path_buf[PATH_ADDPATH_STR_BUFFER];
bool old_mpath, new_mpath;
mpath_changed = 0; mpath_changed = false;
maxpaths = multipath_num; maxpaths = multipath_num;
mpath_count = 0; mpath_count = 0;
cur_mpath = NULL;
old_mpath_count = 0; old_mpath_count = 0;
old_cum_bw = cum_bw = 0; old_cum_bw = cum_bw = 0;
prev_mpath = new_best;
mp_node = listhead(mp_list);
debug = bgp_debug_bestpath(dest); debug = bgp_debug_bestpath(dest);
if (new_best) {
mpath_count++;
if (new_best != old_best)
bgp_path_info_mpath_dequeue(new_best);
maxpaths = (new_best->peer->sort == BGP_PEER_IBGP)
? mpath_cfg->maxpaths_ibgp
: mpath_cfg->maxpaths_ebgp;
}
if (old_best) { if (old_best) {
cur_mpath = bgp_path_info_mpath_first(old_best);
old_mpath_count = bgp_path_info_mpath_count(old_best); old_mpath_count = bgp_path_info_mpath_count(old_best);
if (old_mpath_count == 1)
SET_FLAG(old_best->flags, BGP_PATH_MULTIPATH);
old_cum_bw = bgp_path_info_mpath_cumbw(old_best); old_cum_bw = bgp_path_info_mpath_cumbw(old_best);
bgp_path_info_mpath_count_set(old_best, 0); bgp_path_info_mpath_count_set(old_best, 0);
bgp_path_info_mpath_lb_update(old_best, false, false, 0); bgp_path_info_mpath_lb_update(old_best, false, false, 0);
bgp_path_info_mpath_dequeue(old_best); bgp_path_info_mpath_free(&old_best->mpath);
old_best->mpath = NULL;
}
if (new_best) {
maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ? mpath_cfg->maxpaths_ibgp
: mpath_cfg->maxpaths_ebgp;
cur_iterator = new_best;
} }
if (debug) if (debug)
zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64, zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64
dest, bgp->name_pretty, " maxpaths set %u",
new_best ? new_best->peer->host : "NONE", dest, bgp->name_pretty, new_best ? new_best->peer->host : "NONE",
mp_list ? listcount(mp_list) : 0, old_mpath_count, num_candidates, old_mpath_count, old_cum_bw, maxpaths);
old_cum_bw);
/* /*
* We perform an ordered walk through both lists in parallel. * We perform an ordered walk through both lists in parallel.
@ -576,212 +471,105 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
* to skip over it * to skip over it
*/ */
all_paths_lb = true; /* We'll reset if any path doesn't have LB. */ all_paths_lb = true; /* We'll reset if any path doesn't have LB. */
while (mp_node || cur_mpath) {
struct bgp_path_info *tmp_info;
while (cur_iterator) {
old_mpath = CHECK_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
new_mpath = CHECK_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW);
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW);
/* /*
* We can bail out of this loop if all existing paths on the * If the current mpath count is equal to the number of
* multipath list have been visited (for cleanup purposes) and * maxpaths that can be used then we can bail, after
* the maxpath requirement is fulfulled * we clean up the flags associated with the rest of the
* bestpaths
*/ */
if (!cur_mpath && (mpath_count >= maxpaths)) if (mpath_count >= maxpaths) {
break; while (cur_iterator) {
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW);
mp_next_node = mp_node ? listnextnode(mp_node) : NULL; cur_iterator = cur_iterator->next;
next_mpath = }
cur_mpath ? bgp_path_info_mpath_next(cur_mpath) : NULL;
tmp_info = mp_node ? listgetdata(mp_node) : NULL;
if (debug) if (debug)
zlog_debug("%pBD(%s): comparing candidate %s with existing mpath %s", zlog_debug("%pBD(%s): Mpath count %u is equal to maximum paths allowed, finished comparision for MPATHS",
dest, bgp->name_pretty, dest, bgp->name_pretty, mpath_count);
tmp_info ? tmp_info->peer->host : "NONE",
cur_mpath ? cur_mpath->peer->host : "NONE");
break;
}
if (debug)
zlog_debug("%pBD(%s): Candidate %s old_mpath: %u new_mpath: %u, Nexthop %pI4 current mpath count: %u",
dest, bgp->name_pretty, cur_iterator->peer->host, old_mpath,
new_mpath, &cur_iterator->attr->nexthop, mpath_count);
/* /*
* If equal, the path was a multipath and is still a multipath. * There is nothing to do if the cur_iterator is neither a old path
* Insert onto new multipath list if maxpaths allows. * or a new path
*/ */
if (mp_node && (listgetdata(mp_node) == cur_mpath)) { if (!old_mpath && !new_mpath) {
list_delete_node(mp_list, mp_node); UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
bgp_path_info_mpath_dequeue(cur_mpath); cur_iterator = cur_iterator->next;
if ((mpath_count < maxpaths)
&& prev_mpath
&& bgp_path_info_nexthop_cmp(prev_mpath,
cur_mpath)) {
bgp_path_info_mpath_enqueue(prev_mpath,
cur_mpath);
prev_mpath = cur_mpath;
mpath_count++;
if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(
cur_mpath->attr),
&bwval) ||
ecommunity_linkbw_present(
bgp_attr_get_ipv6_ecommunity(
cur_mpath->attr),
&bwval))
cum_bw += bwval;
else
all_paths_lb = false;
if (debug) {
bgp_path_info_path_with_addpath_rx_str(
cur_mpath, path_buf,
sizeof(path_buf));
zlog_debug("%pBD: %s is still multipath, cur count %d",
dest, path_buf, mpath_count);
}
} else {
mpath_changed = 1;
if (debug) {
bgp_path_info_path_with_addpath_rx_str(
cur_mpath, path_buf,
sizeof(path_buf));
zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d",
dest, path_buf,
&cur_mpath->attr->nexthop,
mpath_count);
}
}
mp_node = mp_next_node;
cur_mpath = next_mpath;
continue; continue;
} }
if (cur_mpath if (new_mpath) {
&& (!mp_node
|| (bgp_path_info_mpath_cmp(cur_mpath,
listgetdata(mp_node))
< 0))) {
/*
* If here, we have an old multipath and either the
* mp_list
* is finished or the next mp_node points to a later
* multipath, so we need to purge this path from the
* multipath list
*/
bgp_path_info_mpath_dequeue(cur_mpath);
mpath_changed = 1;
if (debug) {
bgp_path_info_path_with_addpath_rx_str(
cur_mpath, path_buf, sizeof(path_buf));
zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d",
dest, path_buf,
&cur_mpath->attr->nexthop,
mpath_count);
}
cur_mpath = next_mpath;
} else {
/*
* If here, we have a path on the mp_list that was not
* previously
* a multipath (due to non-equivalance or maxpaths
* exceeded),
* or the matching multipath is sorted later in the
* multipath
* list. Before we enqueue the path on the new multipath
* list,
* make sure its not on the old_best multipath list or
* referenced
* via next_mpath:
* - If next_mpath points to this new path, update
* next_mpath to
* point to the multipath after this one
* - Dequeue the path from the multipath list just to
* make sure
*/
new_mpath = listgetdata(mp_node);
list_delete_node(mp_list, mp_node);
assert(new_mpath);
assert(prev_mpath);
if ((mpath_count < maxpaths) && (new_mpath != new_best)
&& bgp_path_info_nexthop_cmp(prev_mpath,
new_mpath)) {
bgp_path_info_mpath_dequeue(new_mpath);
bgp_path_info_mpath_enqueue(prev_mpath,
new_mpath);
prev_mpath = new_mpath;
mpath_changed = 1;
mpath_count++; mpath_count++;
if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(
new_mpath->attr), if (cur_iterator != new_best)
SET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
if (!old_mpath)
mpath_changed = true;
if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(cur_iterator->attr),
&bwval) || &bwval) ||
ecommunity_linkbw_present( ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(
bgp_attr_get_ipv6_ecommunity( cur_iterator->attr),
new_mpath->attr),
&bwval)) &bwval))
cum_bw += bwval; cum_bw += bwval;
else else
all_paths_lb = false; all_paths_lb = false;
if (debug) { if (debug) {
bgp_path_info_path_with_addpath_rx_str( bgp_path_info_path_with_addpath_rx_str(cur_iterator, path_buf,
new_mpath, path_buf,
sizeof(path_buf)); sizeof(path_buf));
zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d", zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d cum_bw: %" PRIu64
dest, path_buf, " all_paths_lb: %u",
&new_mpath->attr->nexthop, dest, path_buf, &cur_iterator->attr->nexthop,
mpath_count); mpath_count, cum_bw, all_paths_lb);
} }
} else {
/*
* We know that old_mpath is true and new_mpath is false in this path
*/
mpath_changed = true;
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
} }
mp_node = mp_next_node;
} cur_iterator = cur_iterator->next;
} }
if (new_best) { if (new_best) {
bgp_path_info_mpath_count_set(new_best, mpath_count - 1); if (mpath_count > 1 || new_best->mpath) {
if (mpath_count <= 1 || bgp_path_info_mpath_count_set(new_best, mpath_count);
(!ecommunity_linkbw_present(bgp_attr_get_ecommunity( bgp_path_info_mpath_lb_update(new_best, true, all_paths_lb, cum_bw);
new_best->attr), }
&bwval) &&
!ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(
new_best->attr),
&bwval)))
all_paths_lb = false;
else
cum_bw += bwval;
bgp_path_info_mpath_lb_update(new_best, true,
all_paths_lb, cum_bw);
if (debug) if (debug)
zlog_debug("%pBD(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64, zlog_debug("%pBD(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64,
dest, bgp->name_pretty, mpath_count, dest, bgp->name_pretty, mpath_count,
mpath_changed ? "YES" : "NO", all_paths_lb, mpath_changed ? "YES" : "NO", all_paths_lb,
cum_bw); cum_bw);
if (mpath_count == 1)
UNSET_FLAG(new_best->flags, BGP_PATH_MULTIPATH);
if (mpath_changed if (mpath_changed
|| (bgp_path_info_mpath_count(new_best) != old_mpath_count)) || (bgp_path_info_mpath_count(new_best) != old_mpath_count))
SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG); SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG);
if ((mpath_count - 1) != old_mpath_count || if ((mpath_count) != old_mpath_count || old_cum_bw != cum_bw)
old_cum_bw != cum_bw)
SET_FLAG(new_best->flags, BGP_PATH_LINK_BW_CHG); SET_FLAG(new_best->flags, BGP_PATH_LINK_BW_CHG);
} }
} }
/*
* bgp_mp_dmed_deselect
*
* Clean up multipath information for BGP_PATH_DMED_SELECTED path that
* is not selected as best path
*/
void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best)
{
struct bgp_path_info *mpinfo, *mpnext;
if (!dmed_best)
return;
for (mpinfo = bgp_path_info_mpath_first(dmed_best); mpinfo;
mpinfo = mpnext) {
mpnext = bgp_path_info_mpath_next(mpinfo);
bgp_path_info_mpath_dequeue(mpinfo);
}
bgp_path_info_mpath_count_set(dmed_best, 0);
UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG);
UNSET_FLAG(dmed_best->flags, BGP_PATH_LINK_BW_CHG);
assert(bgp_path_info_mpath_first(dmed_best) == NULL);
}
/* /*
* bgp_path_info_mpath_aggregate_update * bgp_path_info_mpath_aggregate_update
* *
@ -816,7 +604,7 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
if (!new_best) if (!new_best)
return; return;
if (!bgp_path_info_mpath_count(new_best)) { if (bgp_path_info_mpath_count(new_best) == 1) {
if ((new_attr = bgp_path_info_mpath_attr(new_best))) { if ((new_attr = bgp_path_info_mpath_attr(new_best))) {
bgp_attr_unintern(&new_attr); bgp_attr_unintern(&new_attr);
bgp_path_info_mpath_attr_set(new_best, NULL); bgp_path_info_mpath_attr_set(new_best, NULL);

View file

@ -2,8 +2,9 @@
/* /*
* BGP Multipath * BGP Multipath
* Copyright (C) 2010 Google Inc. * Copyright (C) 2010 Google Inc.
* 2024 Nvidia Corporation
* *
* This file is part of Quagga * This file is part of FRR
*/ */
#ifndef _FRR_BGP_MPATH_H #ifndef _FRR_BGP_MPATH_H
@ -13,27 +14,24 @@
* multipath selections, lazily allocated to save memory * multipath selections, lazily allocated to save memory
*/ */
struct bgp_path_info_mpath { struct bgp_path_info_mpath {
/* Points to the first multipath (on bestpath) or the next multipath */
struct bgp_path_info_mpath *mp_next;
/* Points to the previous multipath or NULL on bestpath */
struct bgp_path_info_mpath *mp_prev;
/* Points to bgp_path_info associated with this multipath info */ /* Points to bgp_path_info associated with this multipath info */
struct bgp_path_info *mp_info; struct bgp_path_info *mp_info;
/* When attached to best path, the number of selected multipaths */ /* When attached to best path, the number of selected multipaths */
uint16_t mp_count; uint16_t mp_count;
/* Flags - relevant as noted. */ /* Flags - relevant as noted, attached to bestpath. */
uint16_t mp_flags; uint16_t mp_flags;
#define BGP_MP_LB_PRESENT 0x1 /* Link-bandwidth present for >= 1 path */ #define BGP_MP_LB_PRESENT 0x1 /* Link-bandwidth present for >= 1 path */
#define BGP_MP_LB_ALL 0x2 /* Link-bandwidth present for all multipaths */ #define BGP_MP_LB_ALL 0x2 /* Link-bandwidth present for all multipaths */
/* Aggregated attribute for advertising multipath route */ /*
* Aggregated attribute for advertising multipath route,
* attached to bestpath
*/
struct attr *mp_attr; struct attr *mp_attr;
/* Cumulative bandiwdth of all multipaths - attached to best path. */ /* Cumulative bandiwdth of all multipaths - attached to bestpath. */
uint64_t cum_bw; uint64_t cum_bw;
}; };
@ -47,23 +45,16 @@ extern int bgp_maximum_paths_unset(struct bgp *bgp, afi_t afi, safi_t safi,
/* Functions used by bgp_best_selection to record current /* Functions used by bgp_best_selection to record current
* multipath selections * multipath selections
*/ */
extern int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, extern int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, struct bgp_path_info *bpi2);
struct bgp_path_info *bpi2);
extern void bgp_mp_list_init(struct list *mp_list);
extern void bgp_mp_list_clear(struct list *mp_list);
extern void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo);
extern void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best);
extern void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, extern void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *new_best, struct bgp_path_info *new_best,
struct bgp_path_info *old_best, struct bgp_path_info *old_best, uint32_t num_candidates,
struct list *mp_list,
struct bgp_maxpaths_cfg *mpath_cfg); struct bgp_maxpaths_cfg *mpath_cfg);
extern void extern void
bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best, bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
struct bgp_path_info *old_best); struct bgp_path_info *old_best);
/* Unlink and free multipath information associated with a bgp_path_info */ /* Unlink and free multipath information associated with a bgp_path_info */
extern void bgp_path_info_mpath_dequeue(struct bgp_path_info *path);
extern void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath); extern void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath);
/* Walk list of multipaths associated with a best path */ /* Walk list of multipaths associated with a best path */

View file

@ -34,6 +34,7 @@
#include "bgpd/bgp_nht.h" #include "bgpd/bgp_nht.h"
#include "bgpd/bgp_evpn.h" #include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_memory.h" #include "bgpd/bgp_memory.h"
#include "bgpd/bgp_aspath.h"
#ifdef ENABLE_BGP_VNC #ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h" #include "bgpd/rfapi/rfapi_backend.h"
@ -245,7 +246,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
} else { } else {
bgp_withdraw(peer, &p, addpath_id, packet->afi, bgp_withdraw(peer, &p, addpath_id, packet->afi,
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, &prd, &label, 1, NULL); BGP_ROUTE_NORMAL, &prd, &label, 1);
} }
} }
/* Packet length consistency check. */ /* Packet length consistency check. */
@ -280,7 +281,8 @@ done:
* *
* Sending this vrf-label association is qualified by a) whether vrf->vpn * Sending this vrf-label association is qualified by a) whether vrf->vpn
* exporting is active ("export vpn" is enabled, vpn-policy RD and RT list * exporting is active ("export vpn" is enabled, vpn-policy RD and RT list
* are set) and b) whether vpn-policy label is set. * are set), b) whether vpn-policy label is set and c) the vrf loopback
* interface is up.
* *
* If any of these conditions do not hold, then we send MPLS_LABEL_NONE * If any of these conditions do not hold, then we send MPLS_LABEL_NONE
* for this vrf, which zebra interprets to mean "delete this vrf-label * for this vrf, which zebra interprets to mean "delete this vrf-label
@ -288,6 +290,7 @@ done:
*/ */
void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi)
{ {
struct interface *ifp;
mpls_label_t label = MPLS_LABEL_NONE; mpls_label_t label = MPLS_LABEL_NONE;
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
@ -301,6 +304,8 @@ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi)
} }
if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) { if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) {
ifp = if_get_vrf_loopback(bgp->vrf_id);
if (ifp && if_is_up(ifp))
label = bgp->vpn_policy[afi].tovpn_label; label = bgp->vpn_policy[afi].tovpn_label;
} }
@ -381,6 +386,18 @@ void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi)
if (!vrf) if (!vrf)
return; return;
if (bgp->vpn_policy[afi].tovpn_sid_locator) {
ctx.block_len =
bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length;
ctx.node_len =
bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
ctx.function_len =
bgp->vpn_policy[afi]
.tovpn_sid_locator->function_bits_length;
ctx.argument_len =
bgp->vpn_policy[afi]
.tovpn_sid_locator->argument_bits_length;
}
ctx.table = vrf->data.l.table_id; ctx.table = vrf->data.l.table_id;
act = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4 act = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6; : ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
@ -432,6 +449,12 @@ void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp)
if (!vrf) if (!vrf)
return; return;
if (bgp->tovpn_sid_locator) {
ctx.block_len = bgp->tovpn_sid_locator->block_bits_length;
ctx.node_len = bgp->tovpn_sid_locator->node_bits_length;
ctx.function_len = bgp->tovpn_sid_locator->function_bits_length;
ctx.argument_len = bgp->tovpn_sid_locator->argument_bits_length;
}
ctx.table = vrf->data.l.table_id; ctx.table = vrf->data.l.table_id;
act = ZEBRA_SEG6_LOCAL_ACTION_END_DT46; act = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx); zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx);
@ -470,6 +493,8 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi) void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
{ {
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
struct srv6_sid_ctx ctx = {};
struct seg6local_context seg6localctx = {};
if (bgp->vrf_id == VRF_UNKNOWN) { if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug) if (debug)
@ -482,12 +507,30 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
zlog_debug("%s: deleting sid for vrf %s afi (id=%d)", __func__, zlog_debug("%s: deleting sid for vrf %s afi (id=%d)", __func__,
bgp->name_pretty, bgp->vrf_id); bgp->name_pretty, bgp->vrf_id);
if (bgp->vpn_policy[afi].tovpn_sid_locator) {
seg6localctx.block_len =
bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length;
seg6localctx.node_len =
bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
seg6localctx.function_len =
bgp->vpn_policy[afi]
.tovpn_sid_locator->function_bits_length;
seg6localctx.argument_len =
bgp->vpn_policy[afi]
.tovpn_sid_locator->argument_bits_length;
}
zclient_send_localsid(zclient, zclient_send_localsid(zclient,
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent, bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent,
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL); bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
&seg6localctx);
XFREE(MTYPE_BGP_SRV6_SID, XFREE(MTYPE_BGP_SRV6_SID,
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent); bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = NULL; bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = NULL;
ctx.vrf_id = bgp->vrf_id;
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
bgp_zebra_release_srv6_sid(&ctx);
} }
/* /*
@ -497,6 +540,8 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp) void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
{ {
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
struct srv6_sid_ctx ctx = {};
struct seg6local_context seg6localctx = {};
if (bgp->vrf_id == VRF_UNKNOWN) { if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug) if (debug)
@ -510,11 +555,24 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
zlog_debug("%s: deleting sid for vrf %s (id=%d)", __func__, zlog_debug("%s: deleting sid for vrf %s (id=%d)", __func__,
bgp->name_pretty, bgp->vrf_id); bgp->name_pretty, bgp->vrf_id);
if (bgp->tovpn_sid_locator) {
seg6localctx.block_len =
bgp->tovpn_sid_locator->block_bits_length;
seg6localctx.node_len = bgp->tovpn_sid_locator->node_bits_length;
seg6localctx.function_len =
bgp->tovpn_sid_locator->function_bits_length;
seg6localctx.argument_len =
bgp->tovpn_sid_locator->argument_bits_length;
}
zclient_send_localsid(zclient, bgp->tovpn_zebra_vrf_sid_last_sent, zclient_send_localsid(zclient, bgp->tovpn_zebra_vrf_sid_last_sent,
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
NULL); &seg6localctx);
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent); XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
bgp->tovpn_zebra_vrf_sid_last_sent = NULL; bgp->tovpn_zebra_vrf_sid_last_sent = NULL;
ctx.vrf_id = bgp->vrf_id;
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
bgp_zebra_release_srv6_sid(&ctx);
} }
/* /*
@ -591,7 +649,7 @@ int vpn_leak_label_callback(
return 0; return 0;
} }
static void sid_register(struct bgp *bgp, const struct in6_addr *sid, void sid_register(struct bgp *bgp, const struct in6_addr *sid,
const char *locator_name) const char *locator_name)
{ {
struct bgp_srv6_function *func; struct bgp_srv6_function *func;
@ -631,108 +689,97 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
return false; return false;
} }
/* /**
* This function generates a new SID based on bgp->srv6_locator_chunks and * Return the SRv6 SID value obtained by composing the LOCATOR and FUNCTION.
* index. The locator and generated SID are stored in arguments sid_locator
* and sid, respectively.
* *
* if index != 0: try to allocate as index-mode * @param sid_value SRv6 SID value returned
* else: try to allocate as auto-mode * @param locator Parent locator of the SRv6 SID
* @param sid_func Function part of the SID
* @return True if success, False otherwise
*/ */
static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index, static bool srv6_sid_compose(struct in6_addr *sid_value,
struct srv6_locator_chunk *sid_locator_chunk, struct srv6_locator *locator, uint32_t sid_func)
struct in6_addr *sid)
{ {
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
struct listnode *node;
struct srv6_locator_chunk *chunk;
bool alloced = false;
int label = 0; int label = 0;
uint8_t offset = 0; uint8_t offset = 0;
uint8_t func_len = 0, shift_len = 0; uint8_t func_len = 0, shift_len = 0;
uint32_t index_max = 0; uint32_t sid_func_max = 0;
if (!bgp || !sid_locator_chunk || !sid) if (!locator || !sid_value)
return false; return false;
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) { if (locator->function_bits_length >
if (chunk->function_bits_length >
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) { BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
if (debug) if (debug)
zlog_debug( zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length must be less or equal to %d",
"%s: invalid SRv6 Locator chunk (%pFX): Function Length must be less or equal to %d", __func__, &locator->prefix,
__func__, &chunk->prefix,
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH); BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH);
continue; return false;
} }
index_max = (1 << chunk->function_bits_length) - 1; /* Max value that can be encoded in the Function part of the SID */
sid_func_max = (1 << locator->function_bits_length) - 1;
if (index > index_max) { if (sid_func > sid_func_max) {
if (debug) if (debug)
zlog_debug( zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length is too short to support specified function (%u)",
"%s: skipped SRv6 Locator chunk (%pFX): Function Length is too short to support specified index (%u)", __func__, &locator->prefix, sid_func);
__func__, &chunk->prefix, index); return false;
continue;
} }
*sid = chunk->prefix.prefix; /**
*sid_locator_chunk = *chunk; * Let's build the SID value.
offset = chunk->block_bits_length + chunk->node_bits_length; * sid_value = LOC:FUNC::
func_len = chunk->function_bits_length; */
/* First, we put the locator (LOC) in the most significant bits of sid_value */
*sid_value = locator->prefix.prefix;
/*
* Then, we compute the offset at which we have to place the function (FUNC).
* FUNC will be placed immediately after LOC, i.e. at block_bits_length + node_bits_length
*/
offset = locator->block_bits_length + locator->node_bits_length;
/*
* The FUNC part of the SID is advertised in the label field of SRv6 Service TLV.
* (see SID Transposition Scheme, RFC 9252 section #4).
* Therefore, we need to encode the FUNC in the most significant bits of the
* 20-bit label.
*/
func_len = locator->function_bits_length;
shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len; shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;
if (index != 0) { label = sid_func << shift_len;
label = index << shift_len;
if (label < MPLS_LABEL_UNRESERVED_MIN) { if (label < MPLS_LABEL_UNRESERVED_MIN) {
if (debug) if (debug)
zlog_debug( zlog_debug("%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
"%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use", __func__, &locator->prefix, label);
__func__, &chunk->prefix, return false;
label);
continue;
} }
transpose_sid(sid, label, offset, func_len); if (sid_exist(bgp_get_default(), sid_value)) {
if (sid_exist(bgp, sid)) zlog_warn("%s: skipped to allocate SRv6 SID (%pFX): SID %pI6 already in use",
continue; __func__, &locator->prefix, sid_value);
alloced = true; return false;
break;
} }
for (uint32_t i = 1; i < index_max; i++) { /* Finally, we put the FUNC in sid_value at the computed offset */
label = i << shift_len; transpose_sid(sid_value, label, offset, func_len);
if (label < MPLS_LABEL_UNRESERVED_MIN) {
if (debug)
zlog_debug(
"%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
__func__, &chunk->prefix,
label);
continue;
}
transpose_sid(sid, label, offset, func_len);
if (sid_exist(bgp, sid))
continue;
alloced = true;
break;
}
}
if (!alloced) return true;
return 0;
sid_register(bgp, sid, bgp->srv6_locator_name);
return label;
} }
void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf, void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
afi_t afi) afi_t afi)
{ {
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
struct srv6_locator_chunk *tovpn_sid_locator; struct in6_addr tovpn_sid = {};
struct in6_addr *tovpn_sid; uint32_t tovpn_sid_index = 0;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false; bool tovpn_sid_auto = false;
struct srv6_sid_ctx ctx = {};
uint32_t sid_func;
if (debug) if (debug)
zlog_debug("%s: try to allocate new SID for vrf %s: afi %s", zlog_debug("%s: try to allocate new SID for vrf %s: afi %s",
@ -744,11 +791,18 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
/* /*
* skip when bgp vpn instance ins't allocated * skip when bgp vpn instance ins't allocated
* or srv6 locator chunk isn't allocated * or srv6 locator isn't allocated
*/ */
if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks) if (!bgp_vpn || !bgp_vpn->srv6_locator)
return; return;
if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf SRv6 SID",
__func__, bgp_vrf->name_pretty);
return;
}
tovpn_sid_index = bgp_vrf->vpn_policy[afi].tovpn_sid_index; tovpn_sid_index = bgp_vrf->vpn_policy[afi].tovpn_sid_index;
tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_SID_AUTO); BGP_VPN_POLICY_TOVPN_SID_AUTO);
@ -764,40 +818,34 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
return; return;
} }
tovpn_sid_locator = srv6_locator_chunk_alloc(); if (!tovpn_sid_auto) {
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); if (!srv6_sid_compose(&tovpn_sid, bgp_vpn->srv6_locator,
tovpn_sid_index)) {
tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index, zlog_err("%s: failed to compose sid for vrf %s: afi %s",
tovpn_sid_locator, tovpn_sid);
if (tovpn_sid_transpose_label == 0) {
if (debug)
zlog_debug(
"%s: not allocated new sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi)); __func__, bgp_vrf->name_pretty, afi2str(afi));
srv6_locator_chunk_free(&tovpn_sid_locator);
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
return; return;
} }
}
if (debug) ctx.vrf_id = bgp_vrf->vrf_id;
zlog_debug("%s: new sid %pI6 allocated for vrf %s: afi %s", ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
__func__, tovpn_sid, bgp_vrf->name_pretty, : ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
afi2str(afi)); if (!bgp_zebra_request_srv6_sid(&ctx, &tovpn_sid,
bgp_vpn->srv6_locator_name, &sid_func)) {
bgp_vrf->vpn_policy[afi].tovpn_sid = tovpn_sid; zlog_err("%s: failed to request sid for vrf %s: afi %s",
bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator; __func__, bgp_vrf->name_pretty, afi2str(afi));
bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label = return;
tovpn_sid_transpose_label; }
} }
void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf) void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
{ {
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
struct srv6_locator_chunk *tovpn_sid_locator; struct in6_addr tovpn_sid = {};
struct in6_addr *tovpn_sid; uint32_t tovpn_sid_index = 0;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false; bool tovpn_sid_auto = false;
struct srv6_sid_ctx ctx = {};
uint32_t sid_func;
if (debug) if (debug)
zlog_debug("%s: try to allocate new SID for vrf %s", __func__, zlog_debug("%s: try to allocate new SID for vrf %s", __func__,
@ -809,11 +857,18 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
/* /*
* skip when bgp vpn instance ins't allocated * skip when bgp vpn instance ins't allocated
* or srv6 locator chunk isn't allocated * or srv6 locator isn't allocated
*/ */
if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks) if (!bgp_vpn || !bgp_vpn->srv6_locator)
return; return;
if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf SRv6 SID",
__func__, bgp_vrf->name_pretty);
return;
}
tovpn_sid_index = bgp_vrf->tovpn_sid_index; tovpn_sid_index = bgp_vrf->tovpn_sid_index;
tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO); tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO);
@ -828,28 +883,23 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
return; return;
} }
tovpn_sid_locator = srv6_locator_chunk_alloc(); if (!tovpn_sid_auto) {
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); if (!srv6_sid_compose(&tovpn_sid, bgp_vpn->srv6_locator,
bgp_vrf->tovpn_sid_index)) {
tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index, zlog_err("%s: failed to compose new sid for vrf %s",
tovpn_sid_locator, tovpn_sid);
if (tovpn_sid_transpose_label == 0) {
if (debug)
zlog_debug("%s: not allocated new sid for vrf %s",
__func__, bgp_vrf->name_pretty); __func__, bgp_vrf->name_pretty);
srv6_locator_chunk_free(&tovpn_sid_locator);
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
return; return;
} }
}
if (debug) ctx.vrf_id = bgp_vrf->vrf_id;
zlog_debug("%s: new sid %pI6 allocated for vrf %s", __func__, ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
tovpn_sid, bgp_vrf->name_pretty); if (!bgp_zebra_request_srv6_sid(&ctx, &tovpn_sid,
bgp_vpn->srv6_locator_name, &sid_func)) {
bgp_vrf->tovpn_sid = tovpn_sid; zlog_err("%s: failed to request new sid for vrf %s", __func__,
bgp_vrf->tovpn_sid_locator = tovpn_sid_locator; bgp_vrf->name_pretty);
bgp_vrf->tovpn_sid_transpose_label = tovpn_sid_transpose_label; return;
}
} }
void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi) void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
@ -872,6 +922,7 @@ void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
uint32_t tovpn_sid_index = 0; uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false; bool tovpn_sid_auto = false;
struct srv6_sid_ctx ctx = {};
if (debug) if (debug)
zlog_debug("%s: try to remove SID for vrf %s: afi %s", __func__, zlog_debug("%s: try to remove SID for vrf %s: afi %s", __func__,
@ -885,9 +936,22 @@ void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
if (tovpn_sid_index != 0 || tovpn_sid_auto) if (tovpn_sid_index != 0 || tovpn_sid_auto)
return; return;
srv6_locator_chunk_free(&bgp_vrf->vpn_policy[afi].tovpn_sid_locator); if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf label",
__func__, bgp_vrf->name_pretty);
return;
}
srv6_locator_free(bgp_vrf->vpn_policy[afi].tovpn_sid_locator);
bgp_vrf->vpn_policy[afi].tovpn_sid_locator = NULL;
if (bgp_vrf->vpn_policy[afi].tovpn_sid) { if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
ctx.vrf_id = bgp_vrf->vrf_id;
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
bgp_zebra_release_srv6_sid(&ctx);
sid_unregister(bgp_vpn, bgp_vrf->vpn_policy[afi].tovpn_sid); sid_unregister(bgp_vpn, bgp_vrf->vpn_policy[afi].tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->vpn_policy[afi].tovpn_sid); XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->vpn_policy[afi].tovpn_sid);
} }
@ -899,6 +963,7 @@ void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
uint32_t tovpn_sid_index = 0; uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false; bool tovpn_sid_auto = false;
struct srv6_sid_ctx ctx = {};
if (debug) if (debug)
zlog_debug("%s: try to remove SID for vrf %s", __func__, zlog_debug("%s: try to remove SID for vrf %s", __func__,
@ -912,9 +977,21 @@ void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
if (tovpn_sid_index != 0 || tovpn_sid_auto) if (tovpn_sid_index != 0 || tovpn_sid_auto)
return; return;
srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator); if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf label",
__func__, bgp_vrf->name_pretty);
return;
}
srv6_locator_free(bgp_vrf->tovpn_sid_locator);
bgp_vrf->tovpn_sid_locator = NULL;
if (bgp_vrf->tovpn_sid) { if (bgp_vrf->tovpn_sid) {
ctx.vrf_id = bgp_vrf->vrf_id;
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
bgp_zebra_release_srv6_sid(&ctx);
sid_unregister(bgp_vpn, bgp_vrf->tovpn_sid); sid_unregister(bgp_vpn, bgp_vrf->tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid); XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
} }
@ -1536,8 +1613,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
struct attr static_attr = {0}; struct attr static_attr = {0};
struct attr *new_attr = NULL; struct attr *new_attr = NULL;
safi_t safi = SAFI_MPLS_VPN; safi_t safi = SAFI_MPLS_VPN;
mpls_label_t label_val; mpls_label_t label_val = { 0 };
mpls_label_t label; mpls_label_t label = { 0 };
struct bgp_dest *bn; struct bgp_dest *bn;
const char *debugmsg; const char *debugmsg;
int nexthop_self_flag = 0; int nexthop_self_flag = 0;
@ -1759,8 +1836,9 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
/* Set SID for SRv6 VPN */ /* Set SID for SRv6 VPN */
if (from_bgp->vpn_policy[afi].tovpn_sid_locator) { if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
struct srv6_locator_chunk *locator = struct srv6_locator *locator =
from_bgp->vpn_policy[afi].tovpn_sid_locator; from_bgp->vpn_policy[afi].tovpn_sid_locator;
encode_label( encode_label(
from_bgp->vpn_policy[afi].tovpn_sid_transpose_label, from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
&label); &label);
@ -1801,8 +1879,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
.tovpn_sid_locator->prefix.prefix, .tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
} else if (from_bgp->tovpn_sid_locator) { } else if (from_bgp->tovpn_sid_locator) {
struct srv6_locator_chunk *locator = struct srv6_locator *locator = from_bgp->tovpn_sid_locator;
from_bgp->tovpn_sid_locator;
encode_label(from_bgp->tovpn_sid_transpose_label, &label); encode_label(from_bgp->tovpn_sid_transpose_label, &label);
static_attr.srv6_l3vpn = static_attr.srv6_l3vpn =
XCALLOC(MTYPE_BGP_SRV6_L3VPN, XCALLOC(MTYPE_BGP_SRV6_L3VPN,
@ -2079,6 +2157,7 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
struct bgp *src_vrf; struct bgp *src_vrf;
struct interface *ifp = NULL; struct interface *ifp = NULL;
char rd_buf[RD_ADDRSTRLEN]; char rd_buf[RD_ADDRSTRLEN];
struct aspath *new_aspath;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
@ -2136,6 +2215,32 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return; return;
} }
bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);
/* Check if leaked route has our asn. If so, don't import it. */
if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as)) {
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
if (bpi->extra && bpi->extra->vrfleak &&
(struct bgp_path_info *)bpi->extra->vrfleak->parent ==
path_vpn) {
break;
}
}
if (bpi) {
if (debug)
zlog_debug("%s: blocking import of %p, as-path match",
__func__, bpi);
bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
bgp_process(to_bgp, bn, bpi, afi, safi);
}
bgp_dest_unlock_node(bn);
return;
}
if (debug) if (debug)
zlog_debug("%s: updating RD %s, %pFX to %s", __func__, rd_buf, zlog_debug("%s: updating RD %s, %pFX to %s", __func__, rd_buf,
p, to_bgp->name_pretty); p, to_bgp->name_pretty);
@ -2288,6 +2393,21 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
nexthop_self_flag = 0; nexthop_self_flag = 0;
} }
/*
* if the asn values are different, copy the asn of the source vrf
* into the entry before importing. This helps with as-path loop
* detection
*/
if (path_vpn->extra && path_vpn->extra->vrfleak &&
path_vpn->extra->vrfleak->bgp_orig &&
(to_bgp->as != path_vpn->extra->vrfleak->bgp_orig->as)) {
new_aspath = aspath_dup(static_attr.aspath);
new_aspath =
aspath_add_seq(new_aspath,
path_vpn->extra->vrfleak->bgp_orig->as);
static_attr.aspath = new_aspath;
}
new_attr = bgp_attr_intern(&static_attr); new_attr = bgp_attr_intern(&static_attr);
bgp_attr_flush(&static_attr); bgp_attr_flush(&static_attr);
@ -3789,7 +3909,8 @@ void bgp_vpn_leak_unimport(struct bgp *from_bgp)
bool is_vrf_leak_bind; bool is_vrf_leak_bind;
int debug; int debug;
if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF &&
from_bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
return; return;
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |

View file

@ -419,6 +419,8 @@ struct bgp_mplsvpn_nh_label_bind_cache *bgp_mplsvpn_nh_label_bind_find(
struct bgp_mplsvpn_nh_label_bind_cache_head *tree, struct prefix *p, struct bgp_mplsvpn_nh_label_bind_cache_head *tree, struct prefix *p,
mpls_label_t orig_label); mpls_label_t orig_label);
void bgp_mplsvpn_nexthop_init(void); void bgp_mplsvpn_nexthop_init(void);
extern void sid_register(struct bgp *bgp, const struct in6_addr *sid,
const char *locator_name);
extern void sid_unregister(struct bgp *bgp, const struct in6_addr *sid); extern void sid_unregister(struct bgp *bgp, const struct in6_addr *sid);
#endif /* _QUAGGA_BGP_MPLSVPN_H */ #endif /* _QUAGGA_BGP_MPLSVPN_H */

View file

@ -590,6 +590,11 @@ static int bgp_vrf_check_update_active(struct bgp *bgp, struct interface *ifp)
/* add trap in here */ /* add trap in here */
bgp->snmp_stats->active = new_active; bgp->snmp_stats->active = new_active;
if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) {
bgp_mpls_l3vpn_update_last_changed(bgp);
return 0;
}
/* send relevent trap */ /* send relevent trap */
if (bgp->snmp_stats->active) if (bgp->snmp_stats->active)
trap = MPLSL3VPNVRFUP; trap = MPLSL3VPNVRFUP;

View file

@ -861,8 +861,7 @@ int bgp_connect(struct peer_connection *connection)
htons(peer->port), ifindex); htons(peer->port), ifindex);
} }
/* After TCP connection is established. Get local address and port. */ void bgp_updatesockname(struct peer *peer)
int bgp_getsockname(struct peer *peer)
{ {
if (peer->su_local) { if (peer->su_local) {
sockunion_free(peer->su_local); sockunion_free(peer->su_local);
@ -876,6 +875,12 @@ int bgp_getsockname(struct peer *peer)
peer->su_local = sockunion_getsockname(peer->connection->fd); peer->su_local = sockunion_getsockname(peer->connection->fd);
peer->su_remote = sockunion_getpeername(peer->connection->fd); peer->su_remote = sockunion_getpeername(peer->connection->fd);
}
/* After TCP connection is established. Get local address and port. */
int bgp_getsockname(struct peer *peer)
{
bgp_updatesockname(peer);
if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote, if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote,
&peer->nexthop, peer)) { &peer->nexthop, peer)) {

View file

@ -23,6 +23,7 @@ extern void bgp_close_vrf_socket(struct bgp *bgp);
extern void bgp_close(void); extern void bgp_close(void);
extern int bgp_connect(struct peer_connection *connection); extern int bgp_connect(struct peer_connection *connection);
extern int bgp_getsockname(struct peer *peer); extern int bgp_getsockname(struct peer *peer);
extern void bgp_updatesockname(struct peer *peer);
extern int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p, extern int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p,
const char *password); const char *password);

View file

@ -1003,7 +1003,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
if (bnc->is_evpn_gwip_nexthop) if (bnc->is_evpn_gwip_nexthop)
json_object_boolean_true_add(json_nexthop, json_object_boolean_true_add(json_nexthop,
"isEvpnGatewayIp"); "isEvpnGatewayIp");
json_object_string_addf(json, "resolvedPrefix", "%pFX", json_object_string_addf(json_nexthop, "resolvedPrefix", "%pFX",
&bnc->resolved_prefix); &bnc->resolved_prefix);
} else { } else {
vty_out(vty, " %s valid [IGP metric %d], #paths %d", vty_out(vty, " %s valid [IGP metric %d], #paths %d",

View file

@ -38,7 +38,7 @@ struct bgp_nexthop_cache {
uint32_t metric; uint32_t metric;
/* Nexthop number and nexthop linked list.*/ /* Nexthop number and nexthop linked list.*/
uint8_t nexthop_num; uint16_t nexthop_num;
/* This flag is set to TRUE for a bnc that is gateway IP overlay index /* This flag is set to TRUE for a bnc that is gateway IP overlay index
* nexthop. * nexthop.
@ -66,6 +66,7 @@ struct bgp_nexthop_cache {
#define BGP_STATIC_ROUTE (1 << 4) #define BGP_STATIC_ROUTE (1 << 4)
#define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5) #define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5)
#define BGP_NEXTHOP_LABELED_VALID (1 << 6) #define BGP_NEXTHOP_LABELED_VALID (1 << 6)
#define BGP_NEXTHOP_ULTIMATE (1 << 7)
/* /*
* This flag is added for EVPN gateway IP nexthops. * This flag is added for EVPN gateway IP nexthops.

View file

@ -347,11 +347,10 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
&p.u.prefix6)) &p.u.prefix6))
ifindex = pi->peer->connection->su.sin6.sin6_scope_id; ifindex = pi->peer->connection->su.sin6.sin6_scope_id;
if (!is_bgp_static_route && orig_prefix if (!is_bgp_static_route && orig_prefix && prefix_same(&p, orig_prefix) &&
&& prefix_same(&p, orig_prefix)) { CHECK_FLAG(bgp_route->flags, BGP_FLAG_IMPORT_CHECK)) {
if (BGP_DEBUG(nht, NHT)) { if (BGP_DEBUG(nht, NHT)) {
zlog_debug( zlog_debug("%s(%pFX): prefix loops through itself (import-check enabled)",
"%s(%pFX): prefix loops through itself",
__func__, &p); __func__, &p);
} }
return 0; return 0;
@ -405,12 +404,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
peer); peer);
} else { } else {
if (BGP_DEBUG(nht, NHT)) if (BGP_DEBUG(nht, NHT))
zlog_debug( zlog_debug("Found existing bnc %pFX(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p, resolved prefix %pFX",
"Found existing bnc %pFX(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p",
&bnc->prefix, bnc->ifindex_ipv6_ll, &bnc->prefix, bnc->ifindex_ipv6_ll,
bnc->bgp->name_pretty, bnc->flags, bnc->bgp->name_pretty, bnc->flags,
bnc->ifindex_ipv6_ll, bnc->path_count, bnc->ifindex_ipv6_ll, bnc->path_count,
bnc->nht_info); bnc->nht_info, &bnc->resolved_prefix);
} }
if (pi && is_route_parent_evpn(pi)) if (pi && is_route_parent_evpn(pi))
@ -485,6 +483,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
bnc->metric; bnc->metric;
else if (bpi_ultimate->extra) else if (bpi_ultimate->extra)
bpi_ultimate->extra->igpmetric = 0; bpi_ultimate->extra->igpmetric = 0;
SET_FLAG(bnc->flags, BGP_NEXTHOP_ULTIMATE);
} else if (peer) { } else if (peer) {
/* /*
* Let's not accidentally save the peer data for a peer * Let's not accidentally save the peer data for a peer
@ -503,6 +503,10 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
*/ */
if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW)
return 1; return 1;
else if (safi == SAFI_UNICAST && pi &&
pi->sub_type == BGP_ROUTE_IMPORTED &&
CHECK_FLAG(bnc->flags, BGP_NEXTHOP_ULTIMATE))
return bgp_isvalid_nexthop(bnc);
else if (safi == SAFI_UNICAST && pi && else if (safi == SAFI_UNICAST && pi &&
pi->sub_type == BGP_ROUTE_IMPORTED && pi->sub_type == BGP_ROUTE_IMPORTED &&
BGP_PATH_INFO_NUM_LABELS(pi) && !bnc->is_evpn_gwip_nexthop) BGP_PATH_INFO_NUM_LABELS(pi) && !bnc->is_evpn_gwip_nexthop)
@ -602,10 +606,10 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
} }
if (nhr->metric != bnc->metric) if (nhr->metric != bnc->metric)
bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED; SET_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED);
if (nhr->nexthop_num != bnc->nexthop_num) if (nhr->nexthop_num != bnc->nexthop_num)
bnc->change_flags |= BGP_NEXTHOP_CHANGED; SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
if (import_check && (nhr->type == ZEBRA_ROUTE_BGP || if (import_check && (nhr->type == ZEBRA_ROUTE_BGP ||
!prefix_same(&bnc->prefix, &nhr->prefix))) { !prefix_same(&bnc->prefix, &nhr->prefix))) {
@ -631,11 +635,12 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
if (!bnc->is_evpn_gwip_nexthop) if (!bnc->is_evpn_gwip_nexthop)
bnc->flags |= BGP_NEXTHOP_VALID; SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
bnc->metric = nhr->metric; bnc->metric = nhr->metric;
bnc->nexthop_num = nhr->nexthop_num; bnc->nexthop_num = nhr->nexthop_num;
bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */ UNSET_FLAG(bnc->flags,
BGP_NEXTHOP_LABELED_VALID); /* check below */
for (i = 0; i < nhr->nexthop_num; i++) { for (i = 0; i < nhr->nexthop_num; i++) {
int num_labels = 0; int num_labels = 0;
@ -647,11 +652,12 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
* we receive from bgp. This is to allow us * we receive from bgp. This is to allow us
* to work with v4 routing over v6 nexthops * to work with v4 routing over v6 nexthops
*/ */
if (peer && !peer->ifp if (peer && !peer->ifp &&
&& CHECK_FLAG(peer->flags, CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE) &&
PEER_FLAG_CAPABILITY_ENHE) !CHECK_FLAG(bnc->bgp->flags,
&& nhr->prefix.family == AF_INET6 BGP_FLAG_IPV6_NO_AUTO_RA) &&
&& nexthop->type != NEXTHOP_TYPE_BLACKHOLE) { nhr->prefix.family == AF_INET6 &&
nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
struct interface *ifp; struct interface *ifp;
ifp = if_lookup_by_index(nexthop->ifindex, ifp = if_lookup_by_index(nexthop->ifindex,
@ -665,8 +671,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
/* There is at least one label-switched path */ /* There is at least one label-switched path */
if (nexthop->nh_label && if (nexthop->nh_label &&
nexthop->nh_label->num_labels) { nexthop->nh_label->num_labels) {
SET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID);
bnc->flags |= BGP_NEXTHOP_LABELED_VALID;
num_labels = nexthop->nh_label->num_labels; num_labels = nexthop->nh_label->num_labels;
} }
@ -690,7 +695,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
* determined * determined
* that there has been a change. * that there has been a change.
*/ */
if (bnc->change_flags & BGP_NEXTHOP_CHANGED) if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
continue; continue;
for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next) for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
@ -698,7 +703,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
break; break;
if (!oldnh) if (!oldnh)
bnc->change_flags |= BGP_NEXTHOP_CHANGED; SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
} }
bnc_nexthop_free(bnc); bnc_nexthop_free(bnc);
bnc->nexthop = nhlist_head; bnc->nexthop = nhlist_head;
@ -722,19 +727,22 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
: "failed")); : "failed"));
if (evpn_resolved) { if (evpn_resolved) {
bnc->flags |= BGP_NEXTHOP_VALID; SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; UNSET_FLAG(bnc->flags,
bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED; BGP_NEXTHOP_EVPN_INCOMPLETE);
SET_FLAG(bnc->change_flags,
BGP_NEXTHOP_MACIP_CHANGED);
} else { } else {
bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE; SET_FLAG(bnc->flags,
bnc->flags &= ~BGP_NEXTHOP_VALID; BGP_NEXTHOP_EVPN_INCOMPLETE);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
} }
} }
} else { } else {
memset(&bnc->resolved_prefix, 0, sizeof(bnc->resolved_prefix)); memset(&bnc->resolved_prefix, 0, sizeof(bnc->resolved_prefix));
bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
bnc->flags &= ~BGP_NEXTHOP_VALID; UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; UNSET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID);
bnc->nexthop_num = nhr->nexthop_num; bnc->nexthop_num = nhr->nexthop_num;
/* notify bgp fsm if nbr ip goes from valid->invalid */ /* notify bgp fsm if nbr ip goes from valid->invalid */
@ -753,7 +761,7 @@ static void bgp_nht_ifp_table_handle(struct bgp *bgp,
{ {
struct bgp_nexthop_cache *bnc; struct bgp_nexthop_cache *bnc;
struct nexthop *nhop; struct nexthop *nhop;
uint8_t other_nh_count; uint16_t other_nh_count;
bool nhop_ll_found = false; bool nhop_ll_found = false;
bool nhop_found = false; bool nhop_found = false;
@ -1176,7 +1184,7 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
static void register_zebra_rnh(struct bgp_nexthop_cache *bnc) static void register_zebra_rnh(struct bgp_nexthop_cache *bnc)
{ {
/* Check if we have already registered */ /* Check if we have already registered */
if (bnc->flags & BGP_NEXTHOP_REGISTERED) if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
return; return;
if (bnc->ifindex_ipv6_ll) { if (bnc->ifindex_ipv6_ll) {
@ -1305,11 +1313,13 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
bool bnc_is_valid_nexthop = false; bool bnc_is_valid_nexthop = false;
bool path_valid = false; bool path_valid = false;
struct bgp_route_evpn *bre =
bgp_attr_get_evpn_overlay(path->attr);
if (safi == SAFI_UNICAST && if (safi == SAFI_UNICAST &&
path->sub_type == BGP_ROUTE_IMPORTED && path->sub_type == BGP_ROUTE_IMPORTED &&
BGP_PATH_INFO_NUM_LABELS(path) && BGP_PATH_INFO_NUM_LABELS(path) &&
(path->attr->evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP)) { !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)) {
bnc_is_valid_nexthop = bnc_is_valid_nexthop =
bgp_isvalid_nexthop_for_l3vpn(bnc, path) bgp_isvalid_nexthop_for_l3vpn(bnc, path)
? true ? true
@ -1520,6 +1530,10 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
return; return;
bgp = peer->bgp; bgp = peer->bgp;
if (CHECK_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA))
return;
if (!sockunion2hostprefix(&peer->connection->su, &p)) { if (!sockunion2hostprefix(&peer->connection->su, &p)) {
zlog_warn("%s: Unable to convert sockunion to prefix for %s", zlog_warn("%s: Unable to convert sockunion to prefix for %s",
__func__, peer->host); __func__, peer->host);

View file

@ -519,20 +519,17 @@ static int bgp_capability_restart(struct peer *peer,
UNSET_FLAG(restart_flag_time, 0xF000); UNSET_FLAG(restart_flag_time, 0xF000);
peer->v_gr_restart = restart_flag_time; peer->v_gr_restart = restart_flag_time;
if (bgp_debug_neighbor_events(peer)) { if (bgp_debug_neighbor_events(peer))
zlog_debug( zlog_debug("%pBP OPEN has GR capability, Restart time %d R-bit %s N-bit %s",
"%s Peer has%srestarted. Restart Time: %d, N-bit set: %s", peer, peer->v_gr_restart,
peer->host,
CHECK_FLAG(peer->cap, CHECK_FLAG(peer->cap,
PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)
? " " ? "SET"
: " not ", : "NOT-SET",
peer->v_gr_restart,
CHECK_FLAG(peer->cap, CHECK_FLAG(peer->cap,
PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV)
? "yes" ? "SET"
: "no"); : "NOT-SET");
}
while (stream_get_getp(s) + 4 <= end) { while (stream_get_getp(s) + 4 <= end) {
afi_t afi; afi_t afi;
@ -556,14 +553,12 @@ static int bgp_capability_restart(struct peer *peer,
iana_safi2str(pkt_safi)); iana_safi2str(pkt_safi));
} else { } else {
if (bgp_debug_neighbor_events(peer)) if (bgp_debug_neighbor_events(peer))
zlog_debug( zlog_debug("%pBP F-bit %s for %s", peer,
"%s Address family %s is%spreserved", CHECK_FLAG(peer->af_cap[afi][safi],
peer->host, get_afi_safi_str(afi, safi, false),
CHECK_FLAG(
peer->af_cap[afi][safi],
PEER_CAP_RESTART_AF_PRESERVE_RCV) PEER_CAP_RESTART_AF_PRESERVE_RCV)
? " " ? "SET"
: " not "); : "NOT-SET",
get_afi_safi_str(afi, safi, false));
SET_FLAG(peer->af_cap[afi][safi], SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_RESTART_AF_RCV); PEER_CAP_RESTART_AF_RCV);
@ -1379,7 +1374,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
* Check that we can read the opt_type and fetch it * Check that we can read the opt_type and fetch it
*/ */
if (STREAM_READABLE(s) < 1) { if (STREAM_READABLE(s) < 1) {
zlog_info("%s Option length error", peer->host); zlog_err("%s Option length error", peer->host);
bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR); BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1; return -1;
@ -1392,7 +1387,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
*/ */
if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)) { if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)) {
if (STREAM_READABLE(s) < 2) { if (STREAM_READABLE(s) < 2) {
zlog_info("%s Option length error", peer->host); zlog_err("%s Option length error", peer->host);
bgp_notify_send(peer->connection, bgp_notify_send(peer->connection,
BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR); BGP_NOTIFY_OPEN_MALFORMED_ATTR);
@ -1402,7 +1397,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
opt_length = stream_getw(s); opt_length = stream_getw(s);
} else { } else {
if (STREAM_READABLE(s) < 1) { if (STREAM_READABLE(s) < 1) {
zlog_info("%s Option length error", peer->host); zlog_err("%s Option length error", peer->host);
bgp_notify_send(peer->connection, bgp_notify_send(peer->connection,
BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR); BGP_NOTIFY_OPEN_MALFORMED_ATTR);
@ -1414,7 +1409,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
/* Option length check. */ /* Option length check. */
if (STREAM_READABLE(s) < opt_length) { if (STREAM_READABLE(s) < opt_length) {
zlog_info("%s Option length error (%d)", peer->host, zlog_err("%s Option length error (%d)", peer->host,
opt_length); opt_length);
bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR); BGP_NOTIFY_OPEN_MALFORMED_ATTR);
@ -1587,15 +1582,12 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
uint32_t restart_time; uint32_t restart_time;
unsigned long capp = 0; unsigned long capp = 0;
unsigned long rcapp = 0; unsigned long rcapp = 0;
struct bgp *bgp = peer->bgp;
if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
&& !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER))
return; return;
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] Sending helper Capability for Peer :%s :",
peer->host);
SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP); stream_putc(s, BGP_OPEN_OPT_CAP);
capp = stream_get_endp(s); /* Set Capability Len Pointer */ capp = stream_get_endp(s); /* Set Capability Len Pointer */
@ -1605,42 +1597,41 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
/* Set Restart Capability Len Pointer */ /* Set Restart Capability Len Pointer */
rcapp = stream_get_endp(s); rcapp = stream_get_endp(s);
stream_putc(s, 0); stream_putc(s, 0);
restart_time = peer->bgp->restart_time; restart_time = bgp->restart_time;
if (peer->bgp->t_startup) { if (peer->bgp->t_startup || bgp_in_graceful_restart()) {
SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT);
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV);
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] Sending R-Bit for peer: %s",
peer->host);
} }
if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) {
SET_FLAG(restart_time, GRACEFUL_RESTART_N_BIT); SET_FLAG(restart_time, GRACEFUL_RESTART_N_BIT);
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV);
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] Sending N-Bit for peer: %s",
peer->host);
} }
stream_putw(s, restart_time); stream_putw(s, restart_time);
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("%s: Sending GR Capability, Restart time %d R-bit %s, N-bit %s",
peer->host, bgp->restart_time,
CHECK_FLAG(peer->cap,
PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV)
? "SET"
: "NOT-SET",
CHECK_FLAG(peer->cap,
PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV)
? "SET"
: "NOT-SET");
/* Send address-family specific graceful-restart capability /* Send address-family specific graceful-restart capability
* only when GR config is present * only when GR config is present
*/ */
if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) { if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) {
if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)
&& BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] F bit Set");
FOREACH_AFI_SAFI (afi, safi) { FOREACH_AFI_SAFI (afi, safi) {
bool f_bit = false;
if (!peer->afc[afi][safi]) if (!peer->afc[afi][safi])
continue; continue;
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:",
afi, safi);
/* Convert AFI, SAFI to values for /* Convert AFI, SAFI to values for
* packet. * packet.
*/ */
@ -1648,11 +1639,15 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
&pkt_safi); &pkt_safi);
stream_putw(s, pkt_afi); stream_putw(s, pkt_afi);
stream_putc(s, pkt_safi); stream_putc(s, pkt_safi);
if (CHECK_FLAG(peer->bgp->flags,
BGP_FLAG_GR_PRESERVE_FWD)) f_bit = bgp_gr_is_forwarding_preserved(bgp);
stream_putc(s, GRACEFUL_RESTART_F_BIT);
else if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
stream_putc(s, 0); zlog_debug("... F-bit %s for %s",
f_bit ? "SET" : "NOT-SET",
get_afi_safi_str(afi, safi, false));
stream_putc(s, f_bit ? GRACEFUL_RESTART_F_BIT : 0);
} }
} }

View file

@ -651,6 +651,7 @@ void bgp_open_send(struct peer_connection *connection)
uint16_t send_holdtime; uint16_t send_holdtime;
as_t local_as; as_t local_as;
struct peer *peer = connection->peer; struct peer *peer = connection->peer;
bool ext_opt_params = false;
if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
send_holdtime = peer->holdtime; send_holdtime = peer->holdtime;
@ -677,15 +678,17 @@ void bgp_open_send(struct peer_connection *connection)
/* Set capabilities */ /* Set capabilities */
if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) {
(void)bgp_open_capability(s, peer, true); ext_opt_params = true;
(void)bgp_open_capability(s, peer, ext_opt_params);
} else { } else {
struct stream *tmp = stream_new(STREAM_SIZE(s)); struct stream *tmp = stream_new(STREAM_SIZE(s));
stream_copy(tmp, s); stream_copy(tmp, s);
if (bgp_open_capability(tmp, peer, false) if (bgp_open_capability(tmp, peer, ext_opt_params) >
> BGP_OPEN_NON_EXT_OPT_LEN) { BGP_OPEN_NON_EXT_OPT_LEN) {
stream_free(tmp); stream_free(tmp);
(void)bgp_open_capability(s, peer, true); ext_opt_params = true;
(void)bgp_open_capability(s, peer, ext_opt_params);
} else { } else {
stream_copy(s, tmp); stream_copy(s, tmp);
stream_free(tmp); stream_free(tmp);
@ -696,10 +699,10 @@ void bgp_open_send(struct peer_connection *connection)
bgp_packet_set_size(s); bgp_packet_set_size(s);
if (bgp_debug_neighbor_events(peer)) if (bgp_debug_neighbor_events(peer))
zlog_debug( zlog_debug("%pBP fd %d sending OPEN%s, version %d, my as %u, holdtime %d, id %pI4",
"%s sending OPEN, version %d, my as %u, holdtime %d, id %pI4", peer, peer->connection->fd,
peer->host, BGP_VERSION_4, local_as, send_holdtime, ext_opt_params ? " (Extended)" : "", BGP_VERSION_4,
&peer->local_id); local_as, send_holdtime, &peer->local_id);
/* Dump packet if debug option is set. */ /* Dump packet if debug option is set. */
/* bgp_packet_dump (s); */ /* bgp_packet_dump (s); */
@ -982,6 +985,7 @@ static void bgp_notify_send_internal(struct peer_connection *connection,
peer->notify.code = bgp_notify.code; peer->notify.code = bgp_notify.code;
peer->notify.subcode = bgp_notify.subcode; peer->notify.subcode = bgp_notify.subcode;
peer->notify.length = bgp_notify.length; peer->notify.length = bgp_notify.length;
peer->notify.hard_reset = hard_reset;
if (bgp_notify.length && data) { if (bgp_notify.length && data) {
bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION, bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION,
@ -1112,10 +1116,10 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
s = stream_new(peer->max_packet_size); s = stream_new(peer->max_packet_size);
/* Make BGP update packet. */ /* Make BGP update packet. */
if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_RCV)) if (!CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_RCV))
return;
bgp_packet_set_marker(s, BGP_MSG_ROUTE_REFRESH_NEW); bgp_packet_set_marker(s, BGP_MSG_ROUTE_REFRESH_NEW);
else
bgp_packet_set_marker(s, BGP_MSG_ROUTE_REFRESH_OLD);
/* Encode Route Refresh message. */ /* Encode Route Refresh message. */
stream_putw(s, pkt_afi); stream_putw(s, pkt_afi);
@ -1295,7 +1299,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
stream_putc(s, 0); stream_putc(s, 0);
gr_restart_time = peer->bgp->restart_time; gr_restart_time = peer->bgp->restart_time;
if (peer->bgp->t_startup) { if (peer->bgp->t_startup || bgp_in_graceful_restart()) {
SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT);
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV);
} }
@ -1800,6 +1804,23 @@ static int bgp_open_receive(struct peer_connection *connection,
mp_capability = 0; mp_capability = 0;
optlen = stream_getc(peer->curr); optlen = stream_getc(peer->curr);
/* If we previously had some more capabilities e.g.:
* FQDN, SOFT_VERSION, we MUST clear the values we used
* before, to avoid using stale data.
* Checking peer->cap is enough before checking for the real
* data, but we don't have this check everywhere in the code,
* thus let's clear the data here too before parsing the
* capabilities.
*/
if (peer->hostname)
XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
if (peer->domainname)
XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
if (peer->soft_version)
XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
/* Extended Optional Parameters Length for BGP OPEN Message */ /* Extended Optional Parameters Length for BGP OPEN Message */
if (optlen == BGP_OPEN_NON_EXT_OPT_LEN if (optlen == BGP_OPEN_NON_EXT_OPT_LEN
|| CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { || CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) {
@ -1977,6 +1998,14 @@ static int bgp_open_receive(struct peer_connection *connection,
BGP_NOTIFY_OPEN_BAD_PEER_AS, BGP_NOTIFY_OPEN_BAD_PEER_AS,
notify_data_remote_as, 2); notify_data_remote_as, 2);
return BGP_Stop; return BGP_Stop;
} else if (peer->as_type == AS_AUTO) {
if (remote_as == peer->bgp->as) {
peer->as = peer->local_as;
SET_FLAG(peer->as_type, AS_INTERNAL);
} else {
peer->as = remote_as;
SET_FLAG(peer->as_type, AS_EXTERNAL);
}
} else if (peer->as_type == AS_INTERNAL) { } else if (peer->as_type == AS_INTERNAL) {
if (remote_as != peer->bgp->as) { if (remote_as != peer->bgp->as) {
if (bgp_debug_neighbor_events(peer)) if (bgp_debug_neighbor_events(peer))
@ -2378,13 +2407,13 @@ static int bgp_update_receive(struct peer_connection *connection,
ret = bgp_dump_attr(&attr, peer->rcvd_attr_str, ret = bgp_dump_attr(&attr, peer->rcvd_attr_str,
sizeof(peer->rcvd_attr_str)); sizeof(peer->rcvd_attr_str));
if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) {
peer->stat_upd_7606++; peer->stat_upd_7606++;
if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW)
flog_err( flog_err(
EC_BGP_UPDATE_RCV, EC_BGP_UPDATE_RCV,
"%pBP rcvd UPDATE with errors in attr(s)!! Withdrawing route.", "%pBP rcvd UPDATE with errors in attr(s)!! Withdrawing route.",
peer); peer);
}
if (ret && bgp_debug_update(peer, NULL, NULL, 1) && if (ret && bgp_debug_update(peer, NULL, NULL, 1) &&
BGP_DEBUG(update, UPDATE_DETAIL)) { BGP_DEBUG(update, UPDATE_DETAIL)) {
@ -2673,6 +2702,19 @@ static int bgp_notify_receive(struct peer_connection *connection,
inner.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM) inner.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM)
UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
/* Resend the next OPEN message with a global AS number if we received
* a `Bad Peer AS` notification. This is only valid if `dual-as` is
* configured.
*/
if (inner.code == BGP_NOTIFY_OPEN_ERR &&
inner.subcode == BGP_NOTIFY_OPEN_BAD_PEER_AS &&
CHECK_FLAG(peer->flags, PEER_FLAG_DUAL_AS)) {
if (peer->change_local_as != peer->bgp->as)
peer->change_local_as = peer->bgp->as;
else
peer->change_local_as = peer->local_as;
}
/* If Graceful-Restart N-bit (Notification) is exchanged, /* If Graceful-Restart N-bit (Notification) is exchanged,
* and it's not a Hard Reset, let's retain the routes. * and it's not a Hard Reset, let's retain the routes.
*/ */

View file

@ -173,33 +173,33 @@ static int snprintf_bgp_pbr_match_val(char *str, int len,
ptr += delta; ptr += delta;
len -= delta; len -= delta;
} else { } else {
if (mval->unary_operator & OPERATOR_UNARY_OR) { if (CHECK_FLAG(mval->unary_operator, OPERATOR_UNARY_OR)) {
delta = snprintf(ptr, len, ", or "); delta = snprintf(ptr, len, ", or ");
ptr += delta; ptr += delta;
len -= delta; len -= delta;
} }
if (mval->unary_operator & OPERATOR_UNARY_AND) { if (CHECK_FLAG(mval->unary_operator, OPERATOR_UNARY_AND)) {
delta = snprintf(ptr, len, ", and "); delta = snprintf(ptr, len, ", and ");
ptr += delta; ptr += delta;
len -= delta; len -= delta;
} }
} }
if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN) { if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_LESS_THAN)) {
delta = snprintf(ptr, len, "<"); delta = snprintf(ptr, len, "<");
ptr += delta; ptr += delta;
len -= delta; len -= delta;
} }
if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN) { if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_GREATER_THAN)) {
delta = snprintf(ptr, len, ">"); delta = snprintf(ptr, len, ">");
ptr += delta; ptr += delta;
len -= delta; len -= delta;
} }
if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO) { if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_EQUAL_TO)) {
delta = snprintf(ptr, len, "="); delta = snprintf(ptr, len, "=");
ptr += delta; ptr += delta;
len -= delta; len -= delta;
} }
if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH) { if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_EXACT_MATCH)) {
delta = snprintf(ptr, len, "match"); delta = snprintf(ptr, len, "match");
ptr += delta; ptr += delta;
len -= delta; len -= delta;
@ -287,9 +287,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite(
{ {
if (unary_operator == OPERATOR_UNARY_AND && and_valmask) { if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
if (type_entry == FLOWSPEC_TCP_FLAGS) { if (type_entry == FLOWSPEC_TCP_FLAGS) {
and_valmask->mask |= SET_FLAG(and_valmask->mask, CHECK_FLAG(TCP_HEADER_ALL_FLAGS, ~(value)));
TCP_HEADER_ALL_FLAGS &
~(value);
} else if (type_entry == FLOWSPEC_DSCP || } else if (type_entry == FLOWSPEC_DSCP ||
type_entry == FLOWSPEC_FLOW_LABEL || type_entry == FLOWSPEC_FLOW_LABEL ||
type_entry == FLOWSPEC_PKT_LEN || type_entry == FLOWSPEC_PKT_LEN ||
@ -302,9 +300,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite(
sizeof(struct bgp_pbr_val_mask)); sizeof(struct bgp_pbr_val_mask));
if (type_entry == FLOWSPEC_TCP_FLAGS) { if (type_entry == FLOWSPEC_TCP_FLAGS) {
and_valmask->val = TCP_HEADER_ALL_FLAGS; and_valmask->val = TCP_HEADER_ALL_FLAGS;
and_valmask->mask |= SET_FLAG(and_valmask->mask, CHECK_FLAG(TCP_HEADER_ALL_FLAGS, ~(value)));
TCP_HEADER_ALL_FLAGS &
~(value);
} else if (type_entry == FLOWSPEC_DSCP || } else if (type_entry == FLOWSPEC_DSCP ||
type_entry == FLOWSPEC_FLOW_LABEL || type_entry == FLOWSPEC_FLOW_LABEL ||
type_entry == FLOWSPEC_FRAGMENT || type_entry == FLOWSPEC_FRAGMENT ||
@ -346,14 +342,10 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
if (i != 0 && list[i].unary_operator != if (i != 0 && list[i].unary_operator !=
unary_operator) unary_operator)
return false; return false;
if (!(list[i].compare_operator & if (!CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_EQUAL_TO) &&
OPERATOR_COMPARE_EQUAL_TO) && !CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_EXACT_MATCH)) {
!(list[i].compare_operator & if (CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_LESS_THAN) &&
OPERATOR_COMPARE_EXACT_MATCH)) { CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_GREATER_THAN)) {
if ((list[i].compare_operator &
OPERATOR_COMPARE_LESS_THAN) &&
(list[i].compare_operator &
OPERATOR_COMPARE_GREATER_THAN)) {
ret = bgp_pbr_extract_enumerate_unary_opposite( ret = bgp_pbr_extract_enumerate_unary_opposite(
unary_operator, and_valmask, unary_operator, and_valmask,
or_valmask, list[i].value, or_valmask, list[i].value,
@ -366,15 +358,15 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
} }
if (unary_operator == OPERATOR_UNARY_AND && and_valmask) { if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
if (type_entry == FLOWSPEC_TCP_FLAGS) if (type_entry == FLOWSPEC_TCP_FLAGS)
and_valmask->mask |= SET_FLAG(and_valmask->mask,
TCP_HEADER_ALL_FLAGS & list[i].value; CHECK_FLAG(TCP_HEADER_ALL_FLAGS, list[i].value));
} else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) { } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
and_valmask = XCALLOC(MTYPE_PBR_VALMASK, and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
sizeof(struct bgp_pbr_val_mask)); sizeof(struct bgp_pbr_val_mask));
if (type_entry == FLOWSPEC_TCP_FLAGS) { if (type_entry == FLOWSPEC_TCP_FLAGS) {
and_valmask->val = TCP_HEADER_ALL_FLAGS; and_valmask->val = TCP_HEADER_ALL_FLAGS;
and_valmask->mask |= SET_FLAG(and_valmask->mask,
TCP_HEADER_ALL_FLAGS & list[i].value; CHECK_FLAG(TCP_HEADER_ALL_FLAGS, list[i].value));
} else if (type_entry == FLOWSPEC_DSCP || } else if (type_entry == FLOWSPEC_DSCP ||
type_entry == FLOWSPEC_FLOW_LABEL || type_entry == FLOWSPEC_FLOW_LABEL ||
type_entry == FLOWSPEC_ICMP_TYPE || type_entry == FLOWSPEC_ICMP_TYPE ||
@ -402,8 +394,8 @@ static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list[],
uint8_t unary_operator_val; uint8_t unary_operator_val;
bool double_check = false; bool double_check = false;
if ((unary_operator & OPERATOR_UNARY_OR) && if (CHECK_FLAG(unary_operator, OPERATOR_UNARY_OR) &&
(unary_operator & OPERATOR_UNARY_AND)) { CHECK_FLAG(unary_operator, OPERATOR_UNARY_AND)) {
unary_operator_val = OPERATOR_UNARY_AND; unary_operator_val = OPERATOR_UNARY_AND;
double_check = true; double_check = true;
} else } else
@ -431,12 +423,12 @@ static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list[],
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
if (i == 0) if (i == 0)
continue; continue;
if (list[i].unary_operator & OPERATOR_UNARY_OR) if (CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_OR))
unary_operator = OPERATOR_UNARY_OR; unary_operator = OPERATOR_UNARY_OR;
if ((list[i].unary_operator & OPERATOR_UNARY_AND if ((CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_AND) &&
&& unary_operator == OPERATOR_UNARY_OR) || unary_operator == OPERATOR_UNARY_OR) ||
(list[i].unary_operator & OPERATOR_UNARY_OR (CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_OR) &&
&& unary_operator == OPERATOR_UNARY_AND)) unary_operator == OPERATOR_UNARY_AND))
return 0; return 0;
} }
return unary_operator; return unary_operator;
@ -723,8 +715,8 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
} }
} }
} else if (!(api->match_bitmask & PREFIX_SRC_PRESENT) && } else if (!CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT) &&
!(api->match_bitmask & PREFIX_DST_PRESENT)) { !CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) {
if (BGP_DEBUG(pbr, PBR)) { if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api); bgp_pbr_print_policy_route(api);
zlog_debug("BGP: match actions without src or dst address can not operate. ignoring."); zlog_debug("BGP: match actions without src or dst address can not operate. ignoring.");
@ -775,21 +767,18 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
} }
api_action = &api->actions[action_count - 1]; api_action = &api->actions[action_count - 1];
if ((ecom_eval->val[1] == if ((ecom_eval->val[1] == ECOMMUNITY_REDIRECT_VRF) &&
(char)ECOMMUNITY_REDIRECT_VRF) && (ecom_eval->val[0] == ECOMMUNITY_ENCODE_TRANS_EXP ||
(ecom_eval->val[0] ==
(char)ECOMMUNITY_ENCODE_TRANS_EXP ||
ecom_eval->val[0] == ecom_eval->val[0] ==
(char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 || ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
ecom_eval->val[0] == ecom_eval->val[0] ==
(char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) { ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
struct ecommunity *eckey = ecommunity_new(); struct ecommunity *eckey = ecommunity_new();
struct ecommunity_val ecom_copy; struct ecommunity_val ecom_copy;
memcpy(&ecom_copy, ecom_eval, memcpy(&ecom_copy, ecom_eval,
sizeof(struct ecommunity_val)); sizeof(struct ecommunity_val));
ecom_copy.val[0] &= UNSET_FLAG(ecom_copy.val[0], ECOMMUNITY_ENCODE_TRANS_EXP);
~ECOMMUNITY_ENCODE_TRANS_EXP;
ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET; ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
ecommunity_add_val(eckey, &ecom_copy, ecommunity_add_val(eckey, &ecom_copy,
false, false); false, false);
@ -800,9 +789,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
eckey); eckey);
ecommunity_free(&eckey); ecommunity_free(&eckey);
} else if ((ecom_eval->val[0] == } else if ((ecom_eval->val[0] ==
(char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH) && ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
(ecom_eval->val[1] == (ecom_eval->val[1] ==
(char)ECOMMUNITY_REDIRECT_IP_NH)) { ECOMMUNITY_REDIRECT_IP_NH)) {
/* in case the 2 ecom present, /* in case the 2 ecom present,
* do not overwrite * do not overwrite
* draft-ietf-idr-flowspec-redirect * draft-ietf-idr-flowspec-redirect
@ -861,10 +850,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
= ecom_eval->val[7]; = ecom_eval->val[7];
api_action_redirect_ip = api_action; api_action_redirect_ip = api_action;
} }
} else if ((ecom_eval->val[0] == } else if ((ecom_eval->val[0] == ECOMMUNITY_ENCODE_IP) &&
(char)ECOMMUNITY_ENCODE_IP) &&
(ecom_eval->val[1] == (ecom_eval->val[1] ==
(char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) { ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) {
/* in case the 2 ecom present, /* in case the 2 ecom present,
* overwrite simpson draft * overwrite simpson draft
* update redirect ip fields * update redirect ip fields
@ -888,7 +876,7 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
} }
} else { } else {
if (ecom_eval->val[0] != if (ecom_eval->val[0] !=
(char)ECOMMUNITY_ENCODE_TRANS_EXP) ECOMMUNITY_ENCODE_TRANS_EXP)
continue; continue;
ret = ecommunity_fill_pbr_action(ecom_eval, ret = ecommunity_fill_pbr_action(ecom_eval,
api_action, api_action,
@ -920,9 +908,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
} }
api_action = &api->actions[action_count - 1]; api_action = &api->actions[action_count - 1];
if ((ipv6_ecom_eval->val[1] == if ((ipv6_ecom_eval->val[1] ==
(char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) && ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) &&
(ipv6_ecom_eval->val[0] == (ipv6_ecom_eval->val[0] ==
(char)ECOMMUNITY_ENCODE_TRANS_EXP)) { ECOMMUNITY_ENCODE_TRANS_EXP)) {
struct ecommunity *eckey = ecommunity_new(); struct ecommunity *eckey = ecommunity_new();
struct ecommunity_val_ipv6 ecom_copy; struct ecommunity_val_ipv6 ecom_copy;
@ -958,12 +946,12 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
return -1; return -1;
/* check inconsistency in the match rule */ /* check inconsistency in the match rule */
if (api->match_bitmask & PREFIX_SRC_PRESENT) { if (CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT)) {
src = &api->src_prefix; src = &api->src_prefix;
afi = family2afi(src->family); afi = family2afi(src->family);
valid_prefix = 1; valid_prefix = 1;
} }
if (api->match_bitmask & PREFIX_DST_PRESENT) { if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) {
dst = &api->dst_prefix; dst = &api->dst_prefix;
if (valid_prefix && afi != family2afi(dst->family)) { if (valid_prefix && afi != family2afi(dst->family)) {
if (BGP_DEBUG(pbr, PBR)) { if (BGP_DEBUG(pbr, PBR)) {
@ -1207,12 +1195,10 @@ bool bgp_pbr_rule_hash_equal(const void *arg1, const void *arg2)
if (r1->action != r2->action) if (r1->action != r2->action)
return false; return false;
if ((r1->flags & MATCH_IP_SRC_SET) && if (CHECK_FLAG(r1->flags, MATCH_IP_SRC_SET) && !prefix_same(&r1->src, &r2->src))
!prefix_same(&r1->src, &r2->src))
return false; return false;
if ((r1->flags & MATCH_IP_DST_SET) && if (CHECK_FLAG(r1->flags, MATCH_IP_DST_SET) && !prefix_same(&r1->dst, &r2->dst))
!prefix_same(&r1->dst, &r2->dst))
return false; return false;
return true; return true;
@ -1429,7 +1415,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
delta = snprintf(ptr, sizeof(return_string), "MATCH : "); delta = snprintf(ptr, sizeof(return_string), "MATCH : ");
len -= delta; len -= delta;
ptr += delta; ptr += delta;
if (api->match_bitmask & PREFIX_SRC_PRESENT) { if (CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT)) {
struct prefix *p = &(api->src_prefix); struct prefix *p = &(api->src_prefix);
if (api->src_prefix_offset) if (api->src_prefix_offset)
@ -1441,7 +1427,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
ptr += delta; ptr += delta;
INCREMENT_DISPLAY(ptr, nb_items, len); INCREMENT_DISPLAY(ptr, nb_items, len);
} }
if (api->match_bitmask & PREFIX_DST_PRESENT) { if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) {
struct prefix *p = &(api->dst_prefix); struct prefix *p = &(api->dst_prefix);
INCREMENT_DISPLAY(ptr, nb_items, len); INCREMENT_DISPLAY(ptr, nb_items, len);
@ -1584,21 +1570,18 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
delta = snprintf(ptr, len, "@action "); delta = snprintf(ptr, len, "@action ");
len -= delta; len -= delta;
ptr += delta; ptr += delta;
if (api->actions[i].u.za.filter if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_TERMINATE)) {
& TRAFFIC_ACTION_TERMINATE) {
delta = snprintf(ptr, len, delta = snprintf(ptr, len,
" terminate (apply filter(s))"); " terminate (apply filter(s))");
len -= delta; len -= delta;
ptr += delta; ptr += delta;
} }
if (api->actions[i].u.za.filter if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_DISTRIBUTE)) {
& TRAFFIC_ACTION_DISTRIBUTE) {
delta = snprintf(ptr, len, " distribute"); delta = snprintf(ptr, len, " distribute");
len -= delta; len -= delta;
ptr += delta; ptr += delta;
} }
if (api->actions[i].u.za.filter if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_SAMPLE)) {
& TRAFFIC_ACTION_SAMPLE) {
delta = snprintf(ptr, len, " sample"); delta = snprintf(ptr, len, " sample");
len -= delta; len -= delta;
ptr += delta; ptr += delta;
@ -1749,12 +1732,10 @@ static int bgp_pbr_get_same_rule(struct hash_bucket *bucket, void *arg)
if (r1->flags != r2->flags) if (r1->flags != r2->flags)
return HASHWALK_CONTINUE; return HASHWALK_CONTINUE;
if ((r1->flags & MATCH_IP_SRC_SET) && if (CHECK_FLAG(r1->flags, MATCH_IP_SRC_SET) && !prefix_same(&r1->src, &r2->src))
!prefix_same(&r1->src, &r2->src))
return HASHWALK_CONTINUE; return HASHWALK_CONTINUE;
if ((r1->flags & MATCH_IP_DST_SET) && if (CHECK_FLAG(r1->flags, MATCH_IP_DST_SET) && !prefix_same(&r1->dst, &r2->dst))
!prefix_same(&r1->dst, &r2->dst))
return HASHWALK_CONTINUE; return HASHWALK_CONTINUE;
/* this function is used for two cases: /* this function is used for two cases:
@ -1843,11 +1824,11 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
pbr_rule.vrf_id = bpf->vrf_id; pbr_rule.vrf_id = bpf->vrf_id;
if (bpf->src) { if (bpf->src) {
prefix_copy(&pbr_rule.src, bpf->src); prefix_copy(&pbr_rule.src, bpf->src);
pbr_rule.flags |= MATCH_IP_SRC_SET; SET_FLAG(pbr_rule.flags, MATCH_IP_SRC_SET);
} }
if (bpf->dst) { if (bpf->dst) {
prefix_copy(&pbr_rule.dst, bpf->dst); prefix_copy(&pbr_rule.dst, bpf->dst);
pbr_rule.flags |= MATCH_IP_DST_SET; SET_FLAG(pbr_rule.flags, MATCH_IP_DST_SET);
} }
bpr = &pbr_rule; bpr = &pbr_rule;
/* A previous entry may already exist /* A previous entry may already exist
@ -1870,32 +1851,32 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
temp.family = bpf->family; temp.family = bpf->family;
if (bpf->src) { if (bpf->src) {
temp.flags |= MATCH_IP_SRC_SET; SET_FLAG(temp.flags, MATCH_IP_SRC_SET);
prefix_copy(&temp2.src, bpf->src); prefix_copy(&temp2.src, bpf->src);
} else } else
temp2.src.family = bpf->family; temp2.src.family = bpf->family;
if (bpf->dst) { if (bpf->dst) {
temp.flags |= MATCH_IP_DST_SET; SET_FLAG(temp.flags, MATCH_IP_DST_SET);
prefix_copy(&temp2.dst, bpf->dst); prefix_copy(&temp2.dst, bpf->dst);
} else } else
temp2.dst.family = bpf->family; temp2.dst.family = bpf->family;
if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) { if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
if (bpf->protocol == IPPROTO_ICMP) if (bpf->protocol == IPPROTO_ICMP)
temp.flags |= MATCH_ICMP_SET; SET_FLAG(temp.flags, MATCH_ICMP_SET);
temp.flags |= MATCH_PORT_SRC_SET; SET_FLAG(temp.flags, MATCH_PORT_SRC_SET);
temp2.src_port_min = src_port->min_port; temp2.src_port_min = src_port->min_port;
if (src_port->max_port) { if (src_port->max_port) {
temp.flags |= MATCH_PORT_SRC_RANGE_SET; SET_FLAG(temp.flags, MATCH_PORT_SRC_RANGE_SET);
temp2.src_port_max = src_port->max_port; temp2.src_port_max = src_port->max_port;
} }
} }
if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) { if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
if (bpf->protocol == IPPROTO_ICMP) if (bpf->protocol == IPPROTO_ICMP)
temp.flags |= MATCH_ICMP_SET; SET_FLAG(temp.flags, MATCH_ICMP_SET);
temp.flags |= MATCH_PORT_DST_SET; SET_FLAG(temp.flags, MATCH_PORT_DST_SET);
temp2.dst_port_min = dst_port->min_port; temp2.dst_port_min = dst_port->min_port;
if (dst_port->max_port) { if (dst_port->max_port) {
temp.flags |= MATCH_PORT_DST_RANGE_SET; SET_FLAG(temp.flags, MATCH_PORT_DST_RANGE_SET);
temp2.dst_port_max = dst_port->max_port; temp2.dst_port_max = dst_port->max_port;
} }
} }
@ -1907,7 +1888,7 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
temp.pkt_len_max = pkt_len->max_port; temp.pkt_len_max = pkt_len->max_port;
} else if (bpf->pkt_len_val) { } else if (bpf->pkt_len_val) {
if (bpf->pkt_len_val->mask) if (bpf->pkt_len_val->mask)
temp.flags |= MATCH_PKT_LEN_INVERSE_SET; SET_FLAG(temp.flags, MATCH_PKT_LEN_INVERSE_SET);
temp.pkt_len_min = bpf->pkt_len_val->val; temp.pkt_len_min = bpf->pkt_len_val->val;
} }
if (bpf->tcp_flags) { if (bpf->tcp_flags) {
@ -1916,32 +1897,32 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
} }
if (bpf->dscp) { if (bpf->dscp) {
if (bpf->dscp->mask) if (bpf->dscp->mask)
temp.flags |= MATCH_DSCP_INVERSE_SET; SET_FLAG(temp.flags, MATCH_DSCP_INVERSE_SET);
else else
temp.flags |= MATCH_DSCP_SET; SET_FLAG(temp.flags, MATCH_DSCP_SET);
temp.dscp_value = bpf->dscp->val; temp.dscp_value = bpf->dscp->val;
} }
if (bpf->flow_label) { if (bpf->flow_label) {
if (bpf->flow_label->mask) if (bpf->flow_label->mask)
temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET; SET_FLAG(temp.flags, MATCH_FLOW_LABEL_INVERSE_SET);
else else
temp.flags |= MATCH_FLOW_LABEL_SET; SET_FLAG(temp.flags, MATCH_FLOW_LABEL_SET);
temp.flow_label = bpf->flow_label->val; temp.flow_label = bpf->flow_label->val;
} }
if (bpf->fragment) { if (bpf->fragment) {
if (bpf->fragment->mask) if (bpf->fragment->mask)
temp.flags |= MATCH_FRAGMENT_INVERSE_SET; SET_FLAG(temp.flags, MATCH_FRAGMENT_INVERSE_SET);
temp.fragment = bpf->fragment->val; temp.fragment = bpf->fragment->val;
} }
if (bpf->src == NULL || bpf->dst == NULL) { if (bpf->src == NULL || bpf->dst == NULL) {
if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)) if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)))
temp.type = IPSET_NET_PORT; temp.type = IPSET_NET_PORT;
else else
temp.type = IPSET_NET; temp.type = IPSET_NET;
} else { } else {
if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)) if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)))
temp.type = IPSET_NET_PORT_NET; temp.type = IPSET_NET_PORT_NET;
else else
temp.type = IPSET_NET_NET; temp.type = IPSET_NET_NET;
@ -2319,11 +2300,11 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
pbr_rule.vrf_id = bpf->vrf_id; pbr_rule.vrf_id = bpf->vrf_id;
pbr_rule.priority = 20; pbr_rule.priority = 20;
if (bpf->src) { if (bpf->src) {
pbr_rule.flags |= MATCH_IP_SRC_SET; SET_FLAG(pbr_rule.flags, MATCH_IP_SRC_SET);
prefix_copy(&pbr_rule.src, bpf->src); prefix_copy(&pbr_rule.src, bpf->src);
} }
if (bpf->dst) { if (bpf->dst) {
pbr_rule.flags |= MATCH_IP_DST_SET; SET_FLAG(pbr_rule.flags, MATCH_IP_DST_SET);
prefix_copy(&pbr_rule.dst, bpf->dst); prefix_copy(&pbr_rule.dst, bpf->dst);
} }
pbr_rule.action = bpa; pbr_rule.action = bpa;
@ -2380,32 +2361,32 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
temp.vrf_id = bpf->vrf_id; temp.vrf_id = bpf->vrf_id;
temp.family = bpf->family; temp.family = bpf->family;
if (bpf->src) if (bpf->src)
temp.flags |= MATCH_IP_SRC_SET; SET_FLAG(temp.flags, MATCH_IP_SRC_SET);
if (bpf->dst) if (bpf->dst)
temp.flags |= MATCH_IP_DST_SET; SET_FLAG(temp.flags, MATCH_IP_DST_SET);
if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) { if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
if (bpf->protocol == IPPROTO_ICMP) if (bpf->protocol == IPPROTO_ICMP)
temp.flags |= MATCH_ICMP_SET; SET_FLAG(temp.flags, MATCH_ICMP_SET);
temp.flags |= MATCH_PORT_SRC_SET; SET_FLAG(temp.flags, MATCH_PORT_SRC_SET);
} }
if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) { if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
if (bpf->protocol == IPPROTO_ICMP) if (bpf->protocol == IPPROTO_ICMP)
temp.flags |= MATCH_ICMP_SET; SET_FLAG(temp.flags, MATCH_ICMP_SET);
temp.flags |= MATCH_PORT_DST_SET; SET_FLAG(temp.flags, MATCH_PORT_DST_SET);
} }
if (src_port && src_port->max_port) if (src_port && src_port->max_port)
temp.flags |= MATCH_PORT_SRC_RANGE_SET; SET_FLAG(temp.flags, MATCH_PORT_SRC_RANGE_SET);
if (dst_port && dst_port->max_port) if (dst_port && dst_port->max_port)
temp.flags |= MATCH_PORT_DST_RANGE_SET; SET_FLAG(temp.flags, MATCH_PORT_DST_RANGE_SET);
if (bpf->src == NULL || bpf->dst == NULL) { if (bpf->src == NULL || bpf->dst == NULL) {
if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)) if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)))
temp.type = IPSET_NET_PORT; temp.type = IPSET_NET_PORT;
else else
temp.type = IPSET_NET; temp.type = IPSET_NET;
} else { } else {
if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)) if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)))
temp.type = IPSET_NET_PORT_NET; temp.type = IPSET_NET_PORT_NET;
else else
temp.type = IPSET_NET_NET; temp.type = IPSET_NET_NET;
@ -2416,7 +2397,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
temp.pkt_len_max = pkt_len->max_port; temp.pkt_len_max = pkt_len->max_port;
} else if (bpf->pkt_len_val) { } else if (bpf->pkt_len_val) {
if (bpf->pkt_len_val->mask) if (bpf->pkt_len_val->mask)
temp.flags |= MATCH_PKT_LEN_INVERSE_SET; SET_FLAG(temp.flags, MATCH_PKT_LEN_INVERSE_SET);
temp.pkt_len_min = bpf->pkt_len_val->val; temp.pkt_len_min = bpf->pkt_len_val->val;
} }
if (bpf->tcp_flags) { if (bpf->tcp_flags) {
@ -2425,26 +2406,26 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
} }
if (bpf->dscp) { if (bpf->dscp) {
if (bpf->dscp->mask) if (bpf->dscp->mask)
temp.flags |= MATCH_DSCP_INVERSE_SET; SET_FLAG(temp.flags, MATCH_DSCP_INVERSE_SET);
else else
temp.flags |= MATCH_DSCP_SET; SET_FLAG(temp.flags, MATCH_DSCP_SET);
temp.dscp_value = bpf->dscp->val; temp.dscp_value = bpf->dscp->val;
} }
if (bpf->flow_label) { if (bpf->flow_label) {
if (bpf->flow_label->mask) if (bpf->flow_label->mask)
temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET; SET_FLAG(temp.flags, MATCH_FLOW_LABEL_INVERSE_SET);
else else
temp.flags |= MATCH_FLOW_LABEL_SET; SET_FLAG(temp.flags, MATCH_FLOW_LABEL_SET);
temp.flow_label = bpf->flow_label->val; temp.flow_label = bpf->flow_label->val;
} }
if (bpf->fragment) { if (bpf->fragment) {
if (bpf->fragment->mask) if (bpf->fragment->mask)
temp.flags |= MATCH_FRAGMENT_INVERSE_SET; SET_FLAG(temp.flags, MATCH_FRAGMENT_INVERSE_SET);
temp.fragment = bpf->fragment->val; temp.fragment = bpf->fragment->val;
} }
if (bpf->protocol) { if (bpf->protocol) {
temp.protocol = bpf->protocol; temp.protocol = bpf->protocol;
temp.flags |= MATCH_PROTOCOL_SET; SET_FLAG(temp.flags, MATCH_PROTOCOL_SET);
} }
temp.action = bpa; temp.action = bpa;
bpm = hash_get(bgp->pbr_match_hash, &temp, bpm = hash_get(bgp->pbr_match_hash, &temp,
@ -2661,13 +2642,13 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
memset(&nh, 0, sizeof(nh)); memset(&nh, 0, sizeof(nh));
memset(&bpf, 0, sizeof(bpf)); memset(&bpf, 0, sizeof(bpf));
memset(&bpof, 0, sizeof(bpof)); memset(&bpof, 0, sizeof(bpof));
if (api->match_bitmask & PREFIX_SRC_PRESENT || if (CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT) ||
(api->type == BGP_PBR_IPRULE && (api->type == BGP_PBR_IPRULE &&
api->match_bitmask_iprule & PREFIX_SRC_PRESENT)) CHECK_FLAG(api->match_bitmask_iprule, PREFIX_SRC_PRESENT)))
src = &api->src_prefix; src = &api->src_prefix;
if (api->match_bitmask & PREFIX_DST_PRESENT || if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT) ||
(api->type == BGP_PBR_IPRULE && (api->type == BGP_PBR_IPRULE &&
api->match_bitmask_iprule & PREFIX_DST_PRESENT)) CHECK_FLAG(api->match_bitmask_iprule, PREFIX_DST_PRESENT)))
dst = &api->dst_prefix; dst = &api->dst_prefix;
if (api->type == BGP_PBR_IPRULE) if (api->type == BGP_PBR_IPRULE)
bpf.type = api->type; bpf.type = api->type;
@ -2812,8 +2793,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
} }
break; break;
case ACTION_TRAFFIC_ACTION: case ACTION_TRAFFIC_ACTION:
if (api->actions[i].u.za.filter if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_SAMPLE)) {
& TRAFFIC_ACTION_SAMPLE) {
if (BGP_DEBUG(pbr, PBR)) { if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api); bgp_pbr_print_policy_route(api);
zlog_warn("PBR: Sample action Ignored"); zlog_warn("PBR: Sample action Ignored");

View file

@ -525,8 +525,6 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
else else
bgp_dest_set_bgp_path_info(dest, pi->next); bgp_dest_set_bgp_path_info(dest, pi->next);
bgp_path_info_mpath_dequeue(pi);
pi->next = NULL; pi->next = NULL;
pi->prev = NULL; pi->prev = NULL;
@ -541,8 +539,6 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
static struct bgp_dest *bgp_path_info_reap_unsorted(struct bgp_dest *dest, static struct bgp_dest *bgp_path_info_reap_unsorted(struct bgp_dest *dest,
struct bgp_path_info *pi) struct bgp_path_info *pi)
{ {
bgp_path_info_mpath_dequeue(pi);
pi->next = NULL; pi->next = NULL;
pi->prev = NULL; pi->prev = NULL;
@ -837,8 +833,13 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
* with the * with the
* sticky flag. * sticky flag.
*/ */
if (newattr->sticky != existattr->sticky) { bool new_sticky = CHECK_FLAG(newattr->evpn_flags,
if (newattr->sticky && !existattr->sticky) { ATTR_EVPN_FLAG_STICKY);
bool exist_sticky = CHECK_FLAG(existattr->evpn_flags,
ATTR_EVPN_FLAG_STICKY);
if (new_sticky != exist_sticky) {
if (new_sticky && !exist_sticky) {
*reason = bgp_path_selection_evpn_sticky_mac; *reason = bgp_path_selection_evpn_sticky_mac;
if (debug) if (debug)
zlog_debug( zlog_debug(
@ -847,7 +848,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
return 1; return 1;
} }
if (!newattr->sticky && existattr->sticky) { if (!new_sticky && exist_sticky) {
*reason = bgp_path_selection_evpn_sticky_mac; *reason = bgp_path_selection_evpn_sticky_mac;
if (debug) if (debug)
zlog_debug( zlog_debug(
@ -1063,12 +1064,37 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
} }
} }
/* Tie-breaker - AIGP (Metric TLV) attribute */ /* 3. Local route check. We prefer:
* - BGP_ROUTE_STATIC
* - BGP_ROUTE_AGGREGATE
* - BGP_ROUTE_REDISTRIBUTE
*/
new_origin = !(new->sub_type == BGP_ROUTE_NORMAL || new->sub_type == BGP_ROUTE_IMPORTED);
exist_origin = !(exist->sub_type == BGP_ROUTE_NORMAL ||
exist->sub_type == BGP_ROUTE_IMPORTED);
if (new_origin && !exist_origin) {
*reason = bgp_path_selection_local_route;
if (debug)
zlog_debug("%s: %s wins over %s due to preferred BGP_ROUTE type", pfx_buf,
new_buf, exist_buf);
return 1;
}
if (!new_origin && exist_origin) {
*reason = bgp_path_selection_local_route;
if (debug)
zlog_debug("%s: %s loses to %s due to preferred BGP_ROUTE type", pfx_buf,
new_buf, exist_buf);
return 0;
}
/* 3.5. Tie-breaker - AIGP (Metric TLV) attribute */
if (CHECK_FLAG(newattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && if (CHECK_FLAG(newattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) &&
CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) &&
CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP)) { CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP)) {
uint64_t new_aigp = bgp_attr_get_aigp_metric(newattr); uint64_t new_aigp = bgp_aigp_metric_total(new);
uint64_t exist_aigp = bgp_attr_get_aigp_metric(existattr); uint64_t exist_aigp = bgp_aigp_metric_total(exist);
if (new_aigp < exist_aigp) { if (new_aigp < exist_aigp) {
*reason = bgp_path_selection_aigp; *reason = bgp_path_selection_aigp;
@ -1093,34 +1119,6 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
} }
} }
/* 3. Local route check. We prefer:
* - BGP_ROUTE_STATIC
* - BGP_ROUTE_AGGREGATE
* - BGP_ROUTE_REDISTRIBUTE
*/
new_origin = !(new->sub_type == BGP_ROUTE_NORMAL ||
new->sub_type == BGP_ROUTE_IMPORTED);
exist_origin = !(exist->sub_type == BGP_ROUTE_NORMAL ||
exist->sub_type == BGP_ROUTE_IMPORTED);
if (new_origin && !exist_origin) {
*reason = bgp_path_selection_local_route;
if (debug)
zlog_debug(
"%s: %s wins over %s due to preferred BGP_ROUTE type",
pfx_buf, new_buf, exist_buf);
return 1;
}
if (!new_origin && exist_origin) {
*reason = bgp_path_selection_local_route;
if (debug)
zlog_debug(
"%s: %s loses to %s due to preferred BGP_ROUTE type",
pfx_buf, new_buf, exist_buf);
return 0;
}
/* Here if these are imported routes then get ultimate pi for /* Here if these are imported routes then get ultimate pi for
* path compare. * path compare.
*/ */
@ -1588,8 +1586,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
if (ret == 1) { if (ret == 1) {
*reason = bgp_path_selection_neighbor_ip; *reason = bgp_path_selection_neighbor_ip;
if (debug) if (debug)
zlog_debug( zlog_debug("%s: %s loses to %s due to Neighbor IP comparison",
"%s: %s loses to %s due to Neighor IP comparison",
pfx_buf, new_buf, exist_buf); pfx_buf, new_buf, exist_buf);
return 0; return 0;
} }
@ -1597,8 +1594,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
if (ret == -1) { if (ret == -1) {
*reason = bgp_path_selection_neighbor_ip; *reason = bgp_path_selection_neighbor_ip;
if (debug) if (debug)
zlog_debug( zlog_debug("%s: %s wins over %s due to Neighbor IP comparison",
"%s: %s wins over %s due to Neighor IP comparison",
pfx_buf, new_buf, exist_buf); pfx_buf, new_buf, exist_buf);
return 1; return 1;
} }
@ -1780,14 +1776,13 @@ static bool bgp_community_filter(struct peer *peer, struct attr *attr)
return true; return true;
/* NO_EXPORT check. */ /* NO_EXPORT check. */
if (peer->sort == BGP_PEER_EBGP && if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD &&
community_include(bgp_attr_get_community(attr), community_include(bgp_attr_get_community(attr), COMMUNITY_NO_EXPORT))
COMMUNITY_NO_EXPORT))
return true; return true;
/* NO_EXPORT_SUBCONFED check. */ /* NO_EXPORT_SUBCONFED check. */
if (peer->sort == BGP_PEER_EBGP if ((peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD) ||
|| peer->sort == BGP_PEER_CONFED) peer->sort == BGP_PEER_CONFED)
if (community_include(bgp_attr_get_community(attr), if (community_include(bgp_attr_get_community(attr),
COMMUNITY_NO_EXPORT_SUBCONFED)) COMMUNITY_NO_EXPORT_SUBCONFED))
return true; return true;
@ -2156,6 +2151,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
bool nh_reset = false; bool nh_reset = false;
uint64_t cum_bw; uint64_t cum_bw;
mpls_label_t label; mpls_label_t label;
bool global_and_ll = false;
if (DISABLE_BGP_ANNOUNCE) if (DISABLE_BGP_ANNOUNCE)
return false; return false;
@ -2170,8 +2166,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
from = pi->peer; from = pi->peer;
filter = &peer->filter[afi][safi]; filter = &peer->filter[afi][safi];
bgp = SUBGRP_INST(subgrp); bgp = SUBGRP_INST(subgrp);
piattr = bgp_path_info_mpath_count(pi) ? bgp_path_info_mpath_attr(pi) piattr = bgp_path_info_mpath_count(pi) > 1 ? bgp_path_info_mpath_attr(pi) : pi->attr;
: pi->attr;
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT) && if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT) &&
peer->pmax_out[afi][safi] != 0 && peer->pmax_out[afi][safi] != 0 &&
@ -2467,30 +2462,37 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
* we do not announce LL address as `::`. * we do not announce LL address as `::`.
*/ */
if (NEXTHOP_IS_V6) { if (NEXTHOP_IS_V6) {
attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) {
if ((CHECK_FLAG(peer->af_flags[afi][safi], /* nexthop local unchanged: only include the link-local nexthop if it
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) * was already present.
&& IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) */
|| (!reflect && !transparent if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local))
&& IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) global_and_ll = true;
&& peer->shared_network } else if (!reflect && !transparent &&
&& (from == bgp->peer_self IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) && peer->shared_network &&
|| peer->sort == BGP_PEER_EBGP))) { (from == bgp->peer_self || peer->sort == BGP_PEER_EBGP))
global_and_ll = true;
if (global_and_ll) {
if (safi == SAFI_MPLS_VPN) if (safi == SAFI_MPLS_VPN)
attr->mp_nexthop_len = attr->mp_nexthop_len =
BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL; BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL;
else else
attr->mp_nexthop_len = attr->mp_nexthop_len =
BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
} } else
attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
/* Clear off link-local nexthop in source, whenever it is not /* Clear off link-local nexthop in source, whenever it is not
* needed to * needed to
* ensure more prefixes share the same attribute for * ensure more prefixes share the same attribute for
* announcement. * announcement.
*/ */
if (!(CHECK_FLAG(peer->af_flags[afi][safi], if (!(CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) ||
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED))) !IPV6_ADDR_SAME(&peer->nexthop.v6_global, &from->nexthop.v6_global))
/* Reset if "nexthop-local unchanged" is not set or originating and destination peer
* does not share the same subnet.
*/
memset(&attr->mp_nexthop_local, 0, IPV6_MAX_BYTELEN); memset(&attr->mp_nexthop_local, 0, IPV6_MAX_BYTELEN);
} }
@ -2814,6 +2816,21 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
false)); false));
} }
/*
* Adjust AIGP for propagation when the nexthop is set to ourselves,
* e.g., using "set ip nexthop peer-address" or when advertising to
* EBGP. Note in route reflection the nexthop is usually unmodified
* and the AIGP should not be adjusted in that case.
*/
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && AIGP_TRANSMIT_ALLOWED(peer)) {
if (nh_reset ||
CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_NEXTHOP_PEER_ADDRESS)) {
uint64_t aigp = bgp_aigp_metric_total(pi);
bgp_attr_set_aigp_metric(attr, aigp);
}
}
return true; return true;
} }
@ -2848,13 +2865,12 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *pi2; struct bgp_path_info *pi2;
int paths_eq, do_mpath; int paths_eq, do_mpath;
bool debug, any_comparisons; bool debug, any_comparisons;
struct list mp_list;
char pfx_buf[PREFIX2STR_BUFFER] = {}; char pfx_buf[PREFIX2STR_BUFFER] = {};
char path_buf[PATH_ADDPATH_STR_BUFFER]; char path_buf[PATH_ADDPATH_STR_BUFFER];
enum bgp_path_selection_reason reason = bgp_path_selection_none; enum bgp_path_selection_reason reason = bgp_path_selection_none;
bool unsorted_items = true; bool unsorted_items = true;
uint32_t num_candidates = 0;
bgp_mp_list_init(&mp_list);
do_mpath = do_mpath =
(mpath_cfg->maxpaths_ebgp > 1 || mpath_cfg->maxpaths_ibgp > 1); (mpath_cfg->maxpaths_ebgp > 1 || mpath_cfg->maxpaths_ibgp > 1);
@ -3229,7 +3245,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
"%pBD(%s): %s is the bestpath, add to the multipath list", "%pBD(%s): %s is the bestpath, add to the multipath list",
dest, bgp->name_pretty, dest, bgp->name_pretty,
path_buf); path_buf);
bgp_mp_list_add(&mp_list, pi); SET_FLAG(pi->flags, BGP_PATH_MULTIPATH_NEW);
num_candidates++;
continue; continue;
} }
@ -3242,15 +3259,6 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
if (!peer_established(pi->peer->connection)) if (!peer_established(pi->peer->connection))
continue; continue;
if (!bgp_path_info_nexthop_cmp(pi, new_select)) {
if (debug)
zlog_debug(
"%pBD(%s): %s has the same nexthop as the bestpath, skip it",
dest, bgp->name_pretty,
path_buf);
continue;
}
bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, bgp_path_info_cmp(bgp, pi, new_select, &paths_eq,
mpath_cfg, debug, pfx_buf, afi, safi, mpath_cfg, debug, pfx_buf, afi, safi,
&dest->reason); &dest->reason);
@ -3261,15 +3269,14 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
"%pBD(%s): %s is equivalent to the bestpath, add to the multipath list", "%pBD(%s): %s is equivalent to the bestpath, add to the multipath list",
dest, bgp->name_pretty, dest, bgp->name_pretty,
path_buf); path_buf);
bgp_mp_list_add(&mp_list, pi); SET_FLAG(pi->flags, BGP_PATH_MULTIPATH_NEW);
num_candidates++;
} }
} }
} }
bgp_path_info_mpath_update(bgp, dest, new_select, old_select, &mp_list, bgp_path_info_mpath_update(bgp, dest, new_select, old_select, num_candidates, mpath_cfg);
mpath_cfg);
bgp_path_info_mpath_aggregate_update(new_select, old_select); bgp_path_info_mpath_aggregate_update(new_select, old_select);
bgp_mp_list_clear(&mp_list);
bgp_addpath_update_ids(bgp, dest, afi, safi); bgp_addpath_update_ids(bgp, dest, afi, safi);
@ -3624,7 +3631,16 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info_pair old_and_new; struct bgp_path_info_pair old_and_new;
int debug = 0; int debug = 0;
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) { /*
* For default bgp instance, which is deleted i.e. marked hidden
* we are skipping SAFI_MPLS_VPN route table deletion
* in bgp_cleanup_routes.
* So, we need to delete routes from VPNV4 table.
* Here for !IS_BGP_INSTANCE_HIDDEN,
* !(SAFI_MPLS_VPN && AF_IP/AF_IP6),
* we ignore the event for the prefix.
*/
if (BGP_INSTANCE_HIDDEN_DELETE_IN_PROGRESS(bgp, afi, safi)) {
if (dest) if (dest)
debug = bgp_debug_bestpath(dest); debug = bgp_debug_bestpath(dest);
if (debug) if (debug)
@ -3763,7 +3779,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
if (old_select || new_select) { if (old_select || new_select) {
bgp_bump_version(dest); bgp_bump_version(dest);
if (!bgp->t_rmap_def_originate_eval) if (!bgp->t_rmap_def_originate_eval &&
bgp->rmap_def_originate_eval_timer)
event_add_timer( event_add_timer(
bm->master, bm->master,
update_group_refresh_default_originate_route_map, update_group_refresh_default_originate_route_map,
@ -3872,6 +3889,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
struct bgp_dest *dest; struct bgp_dest *dest;
int cnt = 0; int cnt = 0;
struct afi_safi_info *thread_info; struct afi_safi_info *thread_info;
bool route_sync_pending = false;
if (bgp->gr_info[afi][safi].t_route_select) { if (bgp->gr_info[afi][safi].t_route_select) {
struct event *t = bgp->gr_info[afi][safi].t_route_select; struct event *t = bgp->gr_info[afi][safi].t_route_select;
@ -3881,7 +3899,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
EVENT_OFF(bgp->gr_info[afi][safi].t_route_select); EVENT_OFF(bgp->gr_info[afi][safi].t_route_select);
} }
if (BGP_DEBUG(update, UPDATE_OUT)) { if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) {
zlog_debug("%s: processing route for %s : cnt %d", __func__, zlog_debug("%s: processing route for %s : cnt %d", __func__,
get_afi_safi_str(afi, safi, false), get_afi_safi_str(afi, safi, false),
bgp->gr_info[afi][safi].gr_deferred); bgp->gr_info[afi][safi].gr_deferred);
@ -3914,6 +3932,21 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
/* Send route processing complete message to RIB */ /* Send route processing complete message to RIB */
bgp_zebra_update(bgp, afi, safi, bgp_zebra_update(bgp, afi, safi,
ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
bgp->gr_info[afi][safi].route_sync = true;
/* If this instance is all done, check for GR completion overall */
FOREACH_AFI_SAFI_NSF (afi, safi) {
if (bgp->gr_info[afi][safi].af_enabled &&
!bgp->gr_info[afi][safi].route_sync) {
route_sync_pending = true;
break;
}
}
if (!route_sync_pending) {
bgp->gr_route_sync_pending = false;
bgp_update_gr_completion();
}
return; return;
} }
@ -4001,8 +4034,9 @@ static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp)
return pqnode; return pqnode;
} }
void bgp_process(struct bgp *bgp, struct bgp_dest *dest, static void bgp_process_internal(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *pi, afi_t afi, safi_t safi) struct bgp_path_info *pi, afi_t afi,
safi_t safi, bool early_process)
{ {
#define ARBITRARY_PROCESS_QLEN 10000 #define ARBITRARY_PROCESS_QLEN 10000
struct work_queue *wq = bgp->process_queue; struct work_queue *wq = bgp->process_queue;
@ -4065,9 +4099,8 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
struct work_queue_item *item = work_queue_last_item(wq); struct work_queue_item *item = work_queue_last_item(wq);
pqnode = item->data; pqnode = item->data;
if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) ||
|| pqnode->bgp != bgp (pqnode->queued >= ARBITRARY_PROCESS_QLEN && !early_process))
|| pqnode->queued >= ARBITRARY_PROCESS_QLEN)
pqnode = bgp_processq_alloc(bgp); pqnode = bgp_processq_alloc(bgp);
else else
pqnode_reuse = 1; pqnode_reuse = 1;
@ -4081,6 +4114,9 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
/* can't be enqueued twice */ /* can't be enqueued twice */
assert(STAILQ_NEXT(dest, pq) == NULL); assert(STAILQ_NEXT(dest, pq) == NULL);
if (early_process)
STAILQ_INSERT_HEAD(&pqnode->pqueue, dest, pq);
else
STAILQ_INSERT_TAIL(&pqnode->pqueue, dest, pq); STAILQ_INSERT_TAIL(&pqnode->pqueue, dest, pq);
pqnode->queued++; pqnode->queued++;
@ -4090,6 +4126,18 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
return; return;
} }
void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *pi, afi_t afi, safi_t safi)
{
bgp_process_internal(bgp, dest, pi, afi, safi, false);
}
void bgp_process_early(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *pi, afi_t afi, safi_t safi)
{
bgp_process_internal(bgp, dest, pi, afi, safi, true);
}
void bgp_add_eoiu_mark(struct bgp *bgp) void bgp_add_eoiu_mark(struct bgp *bgp)
{ {
struct bgp_process_queue *pqnode; struct bgp_process_queue *pqnode;
@ -4582,10 +4630,10 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
* will not be interned. In which case, it is ok to update the * will not be interned. In which case, it is ok to update the
* attr->evpn_overlay, so that, this can be stored in adj_in. * attr->evpn_overlay, so that, this can be stored in adj_in.
*/ */
if ((afi == AFI_L2VPN) && evpn) { if ((afi == AFI_L2VPN) && evpn)
memcpy(&attr->evpn_overlay, evpn, bgp_attr_set_evpn_overlay(attr, evpn);
sizeof(struct bgp_route_evpn)); else
} evpn_overlay_free(evpn);
bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels); bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels);
} }
@ -4624,7 +4672,22 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (aspath_get_last_as(attr->aspath) == bgp->as) if (aspath_get_last_as(attr->aspath) == bgp->as)
do_loop_check = 0; do_loop_check = 0;
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) /* When using bgp ipv4 labeled session, the local prefix is
* received by a peer, and finds out that the proposed prefix
* and its next-hop are the same. To avoid a route loop locally,
* no nexthop entry is referenced for that prefix, and the route
* will not be selected.
*
* As it has been done for ipv4-unicast, apply the following fix
* for labeled address families: when the received peer is
* a route reflector, the prefix has to be selected, even if the
* route can not be installed locally.
*/
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT) ||
(safi == SAFI_UNICAST && !peer->afc[afi][safi] &&
peer->afc[afi][SAFI_LABELED_UNICAST] &&
CHECK_FLAG(peer->af_flags[afi][SAFI_LABELED_UNICAST],
PEER_FLAG_REFLECTOR_CLIENT)))
bgp_nht_param_prefix = NULL; bgp_nht_param_prefix = NULL;
else else
bgp_nht_param_prefix = p; bgp_nht_param_prefix = p;
@ -4747,8 +4810,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
* evpn to new_atr.evpn_overlay before it is interned. * evpn to new_atr.evpn_overlay before it is interned.
*/ */
if (soft_reconfig && (afi == AFI_L2VPN) && evpn) if (soft_reconfig && (afi == AFI_L2VPN) && evpn)
memcpy(&new_attr.evpn_overlay, evpn, bgp_attr_set_evpn_overlay(&new_attr, evpn);
sizeof(struct bgp_route_evpn)); else
evpn_overlay_free(evpn);
/* Apply incoming route-map. /* Apply incoming route-map.
* NB: new_attr may now contain newly allocated values from route-map * NB: new_attr may now contain newly allocated values from route-map
@ -4772,8 +4836,6 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
false); false);
} }
if (peer->sort == BGP_PEER_EBGP) {
/* rfc7999: /* rfc7999:
* A BGP speaker receiving an announcement tagged with the * A BGP speaker receiving an announcement tagged with the
* BLACKHOLE community SHOULD add the NO_ADVERTISE or * BLACKHOLE community SHOULD add the NO_ADVERTISE or
@ -4788,6 +4850,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
COMMUNITY_BLACKHOLE)) COMMUNITY_BLACKHOLE))
bgp_attr_add_no_export_community(&new_attr); bgp_attr_add_no_export_community(&new_attr);
if (peer->sort == BGP_PEER_EBGP) {
/* If we receive the graceful-shutdown community from an eBGP /* If we receive the graceful-shutdown community from an eBGP
* peer we must lower local-preference */ * peer we must lower local-preference */
if (bgp_attr_get_community(&new_attr) && if (bgp_attr_get_community(&new_attr) &&
@ -5424,7 +5487,7 @@ filtered:
void bgp_withdraw(struct peer *peer, const struct prefix *p, void bgp_withdraw(struct peer *peer, const struct prefix *p,
uint32_t addpath_id, afi_t afi, safi_t safi, int type, uint32_t addpath_id, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd, mpls_label_t *label, int sub_type, struct prefix_rd *prd, mpls_label_t *label,
uint8_t num_labels, struct bgp_route_evpn *evpn) uint8_t num_labels)
{ {
struct bgp *bgp; struct bgp *bgp;
char pfx_buf[BGP_PRD_PATH_STRLEN]; char pfx_buf[BGP_PRD_PATH_STRLEN];
@ -5653,7 +5716,7 @@ static void bgp_soft_reconfig_table_update(struct peer *peer,
struct bgp_path_info *pi; struct bgp_path_info *pi;
uint8_t num_labels; uint8_t num_labels;
mpls_label_t *label_pnt; mpls_label_t *label_pnt;
struct bgp_route_evpn evpn; struct bgp_route_evpn *bre = NULL;
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (pi->peer == peer) if (pi->peer == peer)
@ -5661,15 +5724,13 @@ static void bgp_soft_reconfig_table_update(struct peer *peer,
num_labels = ain->labels ? ain->labels->num_labels : 0; num_labels = ain->labels ? ain->labels->num_labels : 0;
label_pnt = num_labels ? &ain->labels->label[0] : NULL; label_pnt = num_labels ? &ain->labels->label[0] : NULL;
if (pi) if (pi)
memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr), bre = bgp_attr_get_evpn_overlay(pi->attr);
sizeof(evpn));
else
memset(&evpn, 0, sizeof(evpn));
bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id, bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id,
ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd,
label_pnt, num_labels, 1, &evpn); label_pnt, num_labels, 1, bre);
} }
static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi, static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
@ -6218,7 +6279,6 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
vpn_leak_to_vrf_withdraw(pi); vpn_leak_to_vrf_withdraw(pi);
bgp_rib_remove(rm, pi, peer, afi, safi); bgp_rib_remove(rm, pi, peer, afi, safi);
break;
} }
} }
} else { } else {
@ -6247,7 +6307,6 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
pi); pi);
bgp_rib_remove(dest, pi, peer, afi, safi); bgp_rib_remove(dest, pi, peer, afi, safi);
break;
} }
} }
} }
@ -6405,18 +6464,23 @@ void bgp_cleanup_routes(struct bgp *bgp)
if (afi != AFI_L2VPN) { if (afi != AFI_L2VPN) {
safi_t safi; safi_t safi;
safi = SAFI_MPLS_VPN; safi = SAFI_MPLS_VPN;
for (dest = bgp_table_top(bgp->rib[afi][safi]); dest; if (!IS_BGP_INSTANCE_HIDDEN(bgp)) {
dest = bgp_route_next(dest)) { for (dest = bgp_table_top(bgp->rib[afi][safi]);
table = bgp_dest_get_bgp_table_info(dest); dest; dest = bgp_route_next(dest)) {
table = bgp_dest_get_bgp_table_info(
dest);
if (table != NULL) { if (table != NULL) {
bgp_cleanup_table(bgp, table, afi, safi); bgp_cleanup_table(bgp, table,
afi, safi);
bgp_table_finish(&table); bgp_table_finish(&table);
bgp_dest_set_bgp_table_info(dest, NULL); bgp_dest_set_bgp_table_info(dest,
dest = bgp_dest_unlock_node(dest); NULL);
dest = bgp_dest_unlock_node(
dest);
assert(dest); assert(dest);
} }
} }
}
safi = SAFI_ENCAP; safi = SAFI_ENCAP;
for (dest = bgp_table_top(bgp->rib[afi][safi]); dest; for (dest = bgp_table_top(bgp->rib[afi][safi]); dest;
dest = bgp_route_next(dest)) { dest = bgp_route_next(dest)) {
@ -6588,7 +6652,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
else else
bgp_withdraw(peer, &p, addpath_id, afi, safi, bgp_withdraw(peer, &p, addpath_id, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
NULL, 0, NULL); NULL, 0);
/* Do not send BGP notification twice when maximum-prefix count /* Do not send BGP notification twice when maximum-prefix count
* overflow. */ * overflow. */
@ -6698,9 +6762,6 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
if (afi == AFI_IP) if (afi == AFI_IP)
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
if (bgp_static->igpmetric)
bgp_attr_set_aigp_metric(&attr, bgp_static->igpmetric);
if (bgp_static->atomic) if (bgp_static->atomic)
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
@ -6719,15 +6780,25 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
if (afi == AFI_L2VPN) { if (afi == AFI_L2VPN) {
if (bgp_static->gatewayIp.family == AF_INET) { if (bgp_static->gatewayIp.family == AF_INET) {
SET_IPADDR_V4(&attr.evpn_overlay.gw_ip); struct bgp_route_evpn *bre =
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4, XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
sizeof(struct bgp_route_evpn));
SET_IPADDR_V4(&bre->gw_ip);
memcpy(&bre->gw_ip.ipaddr_v4,
&bgp_static->gatewayIp.u.prefix4, &bgp_static->gatewayIp.u.prefix4,
IPV4_MAX_BYTELEN); IPV4_MAX_BYTELEN);
bgp_attr_set_evpn_overlay(&attr, bre);
} else if (bgp_static->gatewayIp.family == AF_INET6) { } else if (bgp_static->gatewayIp.family == AF_INET6) {
SET_IPADDR_V6(&attr.evpn_overlay.gw_ip); struct bgp_route_evpn *bre =
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6, XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
sizeof(struct bgp_route_evpn));
SET_IPADDR_V6(&bre->gw_ip);
memcpy(&bre->gw_ip.ipaddr_v6,
&bgp_static->gatewayIp.u.prefix6, &bgp_static->gatewayIp.u.prefix6,
IPV6_MAX_BYTELEN); IPV6_MAX_BYTELEN);
bgp_attr_set_evpn_overlay(&attr, bre);
} }
memcpy(&attr.esi, bgp_static->eth_s_id, sizeof(esi_t)); memcpy(&attr.esi, bgp_static->eth_s_id, sizeof(esi_t));
if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) { if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) {
@ -8955,9 +9026,6 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
attr.tag = tag; attr.tag = tag;
if (metric)
bgp_attr_set_aigp_metric(&attr, metric);
afi = family2afi(p->family); afi = family2afi(p->family);
red = bgp_redist_lookup(bgp, afi, type, instance); red = bgp_redist_lookup(bgp, afi, type, instance);
@ -8967,16 +9035,15 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
/* Copy attribute for modification. */ /* Copy attribute for modification. */
attr_new = attr; attr_new = attr;
if (red->redist_metric_flag) { if (red->redist_metric_flag)
attr_new.med = red->redist_metric; attr_new.med = red->redist_metric;
bgp_attr_set_aigp_metric(&attr_new, red->redist_metric);
}
/* Apply route-map. */ /* Apply route-map. */
if (red->rmap.name) { if (red->rmap.name) {
memset(&rmap_path, 0, sizeof(rmap_path)); memset(&rmap_path, 0, sizeof(rmap_path));
rmap_path.peer = bgp->peer_self; rmap_path.peer = bgp->peer_self;
rmap_path.attr = &attr_new; rmap_path.attr = &attr_new;
rmap_path.type = type;
SET_FLAG(bgp->peer_self->rmap_type, SET_FLAG(bgp->peer_self->rmap_type,
PEER_RMAP_TYPE_REDISTRIBUTE); PEER_RMAP_TYPE_REDISTRIBUTE);
@ -10091,6 +10158,7 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
json_object *json_path = NULL; json_object *json_path = NULL;
json_object *json_nexthop = NULL; json_object *json_nexthop = NULL;
json_object *json_overlay = NULL; json_object *json_overlay = NULL;
struct bgp_route_evpn *bre = NULL;
if (!path->extra) if (!path->extra)
return; return;
@ -10156,12 +10224,14 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
} }
} }
const struct bgp_route_evpn *eo = bgp_attr_get_evpn_overlay(attr); bre = bgp_attr_get_evpn_overlay(attr);
if (bre) {
if (!json_path) if (!json_path)
vty_out(vty, "/%pIA", &eo->gw_ip); vty_out(vty, "/%pIA", &bre->gw_ip);
else else
json_object_string_addf(json_overlay, "gw", "%pIA", &eo->gw_ip); json_object_string_addf(json_overlay, "gw", "%pIA",
&bre->gw_ip);
}
if (bgp_attr_get_ecommunity(attr)) { if (bgp_attr_get_ecommunity(attr)) {
char *mac = NULL; char *mac = NULL;
@ -10496,6 +10566,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
mpls_label_t label = MPLS_INVALID_LABEL; mpls_label_t label = MPLS_INVALID_LABEL;
struct bgp_path_info *bpi_ultimate = struct bgp_path_info *bpi_ultimate =
bgp_get_imported_bpi_ultimate(path); bgp_get_imported_bpi_ultimate(path);
struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr);
if (json_paths) { if (json_paths) {
json_path = json_object_new_object(); json_path = json_object_new_object();
@ -10522,12 +10593,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
} }
} }
if (safi == SAFI_EVPN if (safi == SAFI_EVPN && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
&& attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
char gwip_buf[INET6_ADDRSTRLEN]; char gwip_buf[INET6_ADDRSTRLEN];
ipaddr2str(&attr->evpn_overlay.gw_ip, gwip_buf, ipaddr2str(&bre->gw_ip, gwip_buf, sizeof(gwip_buf));
sizeof(gwip_buf));
if (json_paths) if (json_paths)
json_object_string_add(json_path, "gatewayIP", json_object_string_add(json_path, "gatewayIP",
@ -10540,8 +10609,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, "\n"); vty_out(vty, "\n");
if (path->extra && path->extra->vrfleak && if (path->extra && path->extra->vrfleak && path->extra->vrfleak->parent) {
path->extra->vrfleak->parent && !json_paths) {
struct bgp_path_info *parent_ri; struct bgp_path_info *parent_ri;
struct bgp_dest *dest, *pdest; struct bgp_dest *dest, *pdest;
@ -10551,15 +10619,31 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (dest && dest->pdest) { if (dest && dest->pdest) {
pdest = dest->pdest; pdest = dest->pdest;
if (is_pi_family_evpn(parent_ri)) { if (is_pi_family_evpn(parent_ri)) {
if (json_paths) {
json_object_string_addf(
json_path, "importedFrom",
BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)
bgp_dest_get_prefix(
pdest));
if (safi != SAFI_EVPN)
json_object_string_add(json_path,
"vni",
vni_buf);
} else {
vty_out(vty, " Imported from "); vty_out(vty, " Imported from ");
vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation), vty_out(vty,
(struct prefix_rd *)bgp_dest_get_prefix( BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)
bgp_dest_get_prefix(
pdest)); pdest));
vty_out(vty, ":%pFX, VNI %s", vty_out(vty, ":%pFX, VNI %s",
(struct prefix_evpn *) (struct prefix_evpn *)
bgp_dest_get_prefix(dest), bgp_dest_get_prefix(dest),
vni_buf); vni_buf);
if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG)) }
if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG) &&
!json_paths) {
vty_out(vty, ", L3NHG %s", vty_out(vty, ", L3NHG %s",
CHECK_FLAG( CHECK_FLAG(
attr->es_flags, attr->es_flags,
@ -10567,15 +10651,36 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
? "active" ? "active"
: "inactive"); : "inactive");
vty_out(vty, "\n"); vty_out(vty, "\n");
} else if (json_paths) {
json_object_boolean_add(
json_path, "l3nhg",
CHECK_FLAG(attr->es_flags,
ATTR_ES_L3_NHG));
json_object_boolean_add(
json_path, "l3nhgActive",
CHECK_FLAG(attr->es_flags,
ATTR_ES_L3_NHG_ACTIVE));
}
} else {
if (json_paths) {
json_object_string_addf(
json_path, "importedFrom",
BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)
bgp_dest_get_prefix(
pdest));
} else { } else {
vty_out(vty, " Imported from "); vty_out(vty, " Imported from ");
vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation), vty_out(vty,
(struct prefix_rd *)bgp_dest_get_prefix( BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)
bgp_dest_get_prefix(
pdest)); pdest));
vty_out(vty, ":%pFX\n", vty_out(vty, ":%pFX\n",
(struct prefix_evpn *) (struct prefix_evpn *)
bgp_dest_get_prefix(dest)); bgp_dest_get_prefix(
dest));
}
} }
} }
} }
@ -11085,9 +11190,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, ", otc %u", attr->otc); vty_out(vty, ", otc %u", attr->otc);
} }
if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH) if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH) ||
|| (CHECK_FLAG(path->flags, BGP_PATH_SELECTED) (CHECK_FLAG(path->flags, BGP_PATH_SELECTED) && bgp_path_info_mpath_count(path) > 1)) {
&& bgp_path_info_mpath_count(path))) {
if (json_paths) if (json_paths)
json_object_boolean_true_add(json_path, "multipath"); json_object_boolean_true_add(json_path, "multipath");
else else
@ -11862,10 +11966,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa
if (!use_json) if (!use_json)
route_vty_out_detail_header( route_vty_out_detail_header(
vty, bgp, dest, vty, bgp, dest,
bgp_dest_get_prefix( bgp_dest_get_prefix(dest),
dest),
prd, table->afi, safi, prd, table->afi, safi,
NULL, false); NULL, false, false);
route_vty_out_detail( route_vty_out_detail(
vty, bgp, dest, dest_p, pi, vty, bgp, dest, dest_p, pi,
@ -11938,10 +12041,12 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa
prd = bgp_rd_from_dest(dest, safi); prd = bgp_rd_from_dest(dest, safi);
route_vty_out_detail_header( route_vty_out_detail_header(vty, bgp, dest,
vty, bgp, dest, bgp_dest_get_prefix(
bgp_dest_get_prefix(dest), prd, dest),
table->afi, safi, json_paths, true); prd, table->afi,
safi, json_paths,
true, false);
vty_out(vty, "\"paths\": "); vty_out(vty, "\"paths\": ");
json_detail_header_used = true; json_detail_header_used = true;
@ -12069,7 +12174,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
bgp = bgp_get_default(); bgp = bgp_get_default();
} }
if (bgp == NULL) { if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) {
if (!use_json) if (!use_json)
vty_out(vty, "No BGP process is configured\n"); vty_out(vty, "No BGP process is configured\n");
else else
@ -12115,6 +12220,8 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
vty_out(vty, "{\n"); vty_out(vty, "{\n");
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
if (IS_BGP_INSTANCE_HIDDEN(bgp))
continue;
route_output = true; route_output = true;
if (use_json) { if (use_json) {
if (!is_first) if (!is_first)
@ -12147,7 +12254,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
struct bgp_dest *dest, const struct prefix *p, struct bgp_dest *dest, const struct prefix *p,
const struct prefix_rd *prd, afi_t afi, const struct prefix_rd *prd, afi_t afi,
safi_t safi, json_object *json, safi_t safi, json_object *json,
bool incremental_print) bool incremental_print, bool local_table)
{ {
struct bgp_path_info *pi; struct bgp_path_info *pi;
struct peer *peer; struct peer *peer;
@ -12179,7 +12286,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
mpls_lse_decode(dest->local_label, &label, &ttl, &exp, &bos); mpls_lse_decode(dest->local_label, &label, &ttl, &exp, &bos);
has_valid_label = bgp_is_valid_label(&label); has_valid_label = bgp_is_valid_label(&dest->local_label);
if (safi == SAFI_EVPN) { if (safi == SAFI_EVPN) {
if (!json) { if (!json) {
@ -12365,8 +12472,14 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
json_object_object_add(json, "advertisedTo", json_object_object_add(json, "advertisedTo",
json_adv_to); json_adv_to);
} else { } else {
if (!json && first) if (!json && first) {
vty_out(vty, " Not advertised to any peer"); if (!local_table)
vty_out(vty,
" Not advertised to any peer");
else
vty_out(vty,
" Local BGP table not advertised");
}
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
} }
@ -12405,10 +12518,10 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
} }
if (header) { if (header) {
route_vty_out_detail_header( route_vty_out_detail_header(vty, bgp, bgp_node,
vty, bgp, bgp_node, bgp_dest_get_prefix(bgp_node),
bgp_dest_get_prefix(bgp_node), pfx_rd, AFI_IP, pfx_rd, AFI_IP, safi,
safi, json_header, false); json_header, false, false);
header = 0; header = 0;
} }
(*display)++; (*display)++;
@ -12627,7 +12740,7 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str,
{ {
if (!bgp) { if (!bgp) {
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) { if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) {
if (!use_json) if (!use_json)
vty_out(vty, "No BGP process is configured\n"); vty_out(vty, "No BGP process is configured\n");
else else
@ -12878,7 +12991,7 @@ DEFUN (show_ip_bgp_l2vpn_evpn_statistics,
struct json_object *json_afi_safi = NULL, *json = NULL; struct json_object *json_afi_safi = NULL, *json = NULL;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp, false); &bgp, uj);
if (!idx) if (!idx)
return CMD_WARNING; return CMD_WARNING;
@ -12916,7 +13029,7 @@ DEFUN(show_ip_bgp_afi_safi_statistics, show_ip_bgp_afi_safi_statistics_cmd,
struct json_object *json_afi_safi = NULL, *json = NULL; struct json_object *json_afi_safi = NULL, *json = NULL;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp, false); &bgp, uj);
if (!idx) if (!idx)
return CMD_WARNING; return CMD_WARNING;
@ -13579,6 +13692,8 @@ enum bgp_stats {
BGP_STATS_ASPATH_MAXSIZE, BGP_STATS_ASPATH_MAXSIZE,
BGP_STATS_ASPATH_TOTSIZE, BGP_STATS_ASPATH_TOTSIZE,
BGP_STATS_ASN_HIGHEST, BGP_STATS_ASN_HIGHEST,
BGP_STATS_REDISTRIBUTED,
BGP_STATS_LOCAL_AGGREGATES,
BGP_STATS_MAX, BGP_STATS_MAX,
}; };
@ -13608,6 +13723,8 @@ static const char *table_stats_strs[][2] = {
[BGP_STATS_ASPATH_TOTSIZE] = {"Average AS-Path size (bytes)", [BGP_STATS_ASPATH_TOTSIZE] = {"Average AS-Path size (bytes)",
"averageAsPathSizeBytes"}, "averageAsPathSizeBytes"},
[BGP_STATS_ASN_HIGHEST] = {"Highest public ASN", "highestPublicAsn"}, [BGP_STATS_ASN_HIGHEST] = {"Highest public ASN", "highestPublicAsn"},
[BGP_STATS_REDISTRIBUTED] = {"Redistributed routes", "totalRedistributed"},
[BGP_STATS_LOCAL_AGGREGATES] = {"Local aggregates", "totalLocalAggregates"},
[BGP_STATS_MAX] = {NULL, NULL} [BGP_STATS_MAX] = {NULL, NULL}
}; };
@ -13657,6 +13774,15 @@ static void bgp_table_stats_rn(struct bgp_dest *dest, struct bgp_dest *top,
ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)))
ts->counts[BGP_STATS_AGGREGATES]++; ts->counts[BGP_STATS_AGGREGATES]++;
if (pi->peer == ts->table->bgp->peer_self) {
if (pi->sub_type == BGP_ROUTE_REDISTRIBUTE)
ts->counts[BGP_STATS_REDISTRIBUTED]++;
if ((pi->type == ZEBRA_ROUTE_BGP) &&
(pi->sub_type == BGP_ROUTE_AGGREGATE))
ts->counts[BGP_STATS_LOCAL_AGGREGATES]++;
}
/* as-path stats */ /* as-path stats */
if (pi->attr->aspath) { if (pi->attr->aspath) {
unsigned int hops = aspath_count_hops(pi->attr->aspath); unsigned int hops = aspath_count_hops(pi->attr->aspath);
@ -14272,7 +14398,7 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix,
int idx = 0; int idx = 0;
char *network = NULL; char *network = NULL;
struct bgp *bgp = bgp_get_default(); struct bgp *bgp = bgp_get_default();
if (!bgp) { if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "Can't find default instance\n"); vty_out(vty, "Can't find default instance\n");
return CMD_WARNING; return CMD_WARNING;
} }
@ -14387,7 +14513,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
struct bgp_adj_out *adj = NULL; struct bgp_adj_out *adj = NULL;
struct bgp_dest *dest; struct bgp_dest *dest;
struct bgp *bgp; struct bgp *bgp;
struct attr attr; struct attr attr, attr_unchanged;
int ret; int ret;
struct update_subgroup *subgrp; struct update_subgroup *subgrp;
struct peer_af *paf = NULL; struct peer_af *paf = NULL;
@ -14567,6 +14693,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
} }
attr = *ain->attr; attr = *ain->attr;
attr_unchanged = *ain->attr;
route_filtered = false; route_filtered = false;
/* Filter prefix using distribute list, /* Filter prefix using distribute list,
@ -14622,9 +14749,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
json_ar, json_net, json_ar, json_net,
"%pFX", rn_p); "%pFX", rn_p);
} else } else
route_vty_out_tmp(vty, bgp, dest, rn_p, route_vty_out_tmp(vty, bgp, dest, rn_p, &attr_unchanged,
&attr, safi, use_json, safi, use_json, json_ar, wide);
json_ar, wide);
bgp_attr_flush(&attr); bgp_attr_flush(&attr);
(*output_count)++; (*output_count)++;
} }
@ -15774,7 +15900,7 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
/* BGP structure lookup. */ /* BGP structure lookup. */
if (view_name) { if (view_name) {
bgp = bgp_lookup_by_name(view_name); bgp = bgp_lookup_by_name(view_name);
if (bgp == NULL) { if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "%% Can't find BGP instance %s\n", vty_out(vty, "%% Can't find BGP instance %s\n",
view_name); view_name);
return CMD_WARNING; return CMD_WARNING;

View file

@ -313,6 +313,11 @@ struct bgp_path_info {
#define BGP_PATH_STALE (1 << 8) #define BGP_PATH_STALE (1 << 8)
#define BGP_PATH_REMOVED (1 << 9) #define BGP_PATH_REMOVED (1 << 9)
#define BGP_PATH_COUNTED (1 << 10) #define BGP_PATH_COUNTED (1 << 10)
/*
* A BGP_PATH_MULTIPATH flag is not set on the best path
* it is set on every other node that is part of ECMP
* for that particular dest
*/
#define BGP_PATH_MULTIPATH (1 << 11) #define BGP_PATH_MULTIPATH (1 << 11)
#define BGP_PATH_MULTIPATH_CHG (1 << 12) #define BGP_PATH_MULTIPATH_CHG (1 << 12)
#define BGP_PATH_RIB_ATTR_CHG (1 << 13) #define BGP_PATH_RIB_ATTR_CHG (1 << 13)
@ -322,6 +327,15 @@ struct bgp_path_info {
#define BGP_PATH_MPLSVPN_LABEL_NH (1 << 17) #define BGP_PATH_MPLSVPN_LABEL_NH (1 << 17)
#define BGP_PATH_MPLSVPN_NH_LABEL_BIND (1 << 18) #define BGP_PATH_MPLSVPN_NH_LABEL_BIND (1 << 18)
#define BGP_PATH_UNSORTED (1 << 19) #define BGP_PATH_UNSORTED (1 << 19)
/*
* BGP_PATH_MULTIPATH_NEW is set on those bgp_path_info
* nodes that we have decided should possibly be in the
* ecmp path for a particular dest. This flag is
* removed when the bgp_path_info's are looked at to
* decide on whether or not a bgp_path_info is on
* the actual ecmp path.
*/
#define BGP_PATH_MULTIPATH_NEW (1 << 20)
/* BGP route type. This can be static, RIP, OSPF, BGP etc. */ /* BGP route type. This can be static, RIP, OSPF, BGP etc. */
uint8_t type; uint8_t type;
@ -802,13 +816,22 @@ extern void bgp_update(struct peer *peer, const struct prefix *p,
extern void bgp_withdraw(struct peer *peer, const struct prefix *p, extern void bgp_withdraw(struct peer *peer, const struct prefix *p,
uint32_t addpath_id, afi_t afi, safi_t safi, int type, uint32_t addpath_id, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd, int sub_type, struct prefix_rd *prd,
mpls_label_t *label, uint8_t num_labels, mpls_label_t *label, uint8_t num_labels);
struct bgp_route_evpn *evpn);
/* for bgp_nexthop and bgp_damp */ /*
* Add a route to be processed for bgp bestpath through the bgp
* workqueue. This route is added to the end of all other routes
* queued for processing
*
* bgp_process_early adds the route for processing at the beginning
* of the current queue for processing.
*/
extern void bgp_process(struct bgp *bgp, struct bgp_dest *dest, extern void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *pi, afi_t afi, safi_t safi); struct bgp_path_info *pi, afi_t afi, safi_t safi);
extern void bgp_process_early(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *pi, afi_t afi, safi_t safi);
/* /*
* Add an end-of-initial-update marker to the process queue. This is just a * Add an end-of-initial-update marker to the process queue. This is just a
* queue element with NULL bgp node. * queue element with NULL bgp node.
@ -904,7 +927,8 @@ extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
const struct prefix *p, const struct prefix *p,
const struct prefix_rd *prd, afi_t afi, const struct prefix_rd *prd, afi_t afi,
safi_t safi, json_object *json, safi_t safi, json_object *json,
bool incremental_print); bool incremental_print,
bool local_table);
extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
struct bgp_dest *bn, const struct prefix *p, struct bgp_dest *bn, const struct prefix *p,
struct bgp_path_info *path, afi_t afi, struct bgp_path_info *path, afi_t afi,

View file

@ -251,7 +251,7 @@ route_match_peer(void *rule, const struct prefix *prefix, void *object)
peer = ((struct bgp_path_info *)object)->peer; peer = ((struct bgp_path_info *)object)->peer;
if (pc->interface) { if (pc->interface) {
if (!peer->conf_if || !peer->group) if (!peer->conf_if && !peer->group)
return RMAP_NOMATCH; return RMAP_NOMATCH;
if (peer->conf_if && strcmp(peer->conf_if, pc->interface) == 0) if (peer->conf_if && strcmp(peer->conf_if, pc->interface) == 0)
@ -680,9 +680,8 @@ route_match_address_prefix_list(void *rule, afi_t afi,
plist = prefix_list_lookup(afi, (char *)rule); plist = prefix_list_lookup(afi, (char *)rule);
if (plist == NULL) { if (plist == NULL) {
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL)))
zlog_debug( zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH",
"%s: Prefix List %s specified does not exist defaulting to NO_MATCH", __func__, (char *)rule, afi2str(afi));
__func__, (char *)rule);
return RMAP_NOMATCH; return RMAP_NOMATCH;
} }
@ -1237,6 +1236,8 @@ route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
struct ipaddr *gw_ip = rule; struct ipaddr *gw_ip = rule;
struct bgp_path_info *path; struct bgp_path_info *path;
struct prefix_evpn *evp; struct prefix_evpn *evp;
struct bgp_route_evpn *bre = XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
sizeof(struct bgp_route_evpn));
if (prefix->family != AF_EVPN) if (prefix->family != AF_EVPN)
return RMAP_OKAY; return RMAP_OKAY;
@ -1252,9 +1253,9 @@ route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
path = object; path = object;
/* Set gateway-ip value. */ /* Set gateway-ip value. */
path->attr->evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; bre->type = OVERLAY_INDEX_GATEWAY_IP;
memcpy(&path->attr->evpn_overlay.gw_ip, &gw_ip->ip.addr, memcpy(&bre->gw_ip, &gw_ip->ip.addr, IPADDRSZ(gw_ip));
IPADDRSZ(gw_ip)); bgp_attr_set_evpn_overlay(path->attr, bre);
return RMAP_OKAY; return RMAP_OKAY;
} }
@ -1991,10 +1992,9 @@ route_set_ip_nexthop(void *rule, const struct prefix *prefix, void *object)
SET_FLAG(path->attr->rmap_change_flags, SET_FLAG(path->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_UNCHANGED); BATTR_RMAP_NEXTHOP_UNCHANGED);
} else if (rins->peer_address) { } else if (rins->peer_address) {
if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN) if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)) &&
|| CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) peer->su_remote &&
&& peer->su_remote sockunion_family(peer->su_remote) == AF_INET) {
&& sockunion_family(peer->su_remote) == AF_INET) {
path->attr->nexthop.s_addr = path->attr->nexthop.s_addr =
sockunion2ip(peer->su_remote); sockunion2ip(peer->su_remote);
path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
@ -3220,7 +3220,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
return RMAP_OKAY; return RMAP_OKAY;
bw_bytes = (peer->bgp->lb_ref_bw * 1000 * 1000) / 8; bw_bytes = (peer->bgp->lb_ref_bw * 1000 * 1000) / 8;
mpath_count = bgp_path_info_mpath_count(path) + 1; mpath_count = bgp_path_info_mpath_count(path);
bw_bytes *= mpath_count; bw_bytes *= mpath_count;
} }
@ -3451,19 +3451,15 @@ route_set_aigp_metric(void *rule, const struct prefix *pfx, void *object)
{ {
const char *aigp_metric = rule; const char *aigp_metric = rule;
struct bgp_path_info *path = object; struct bgp_path_info *path = object;
uint32_t aigp = 0; uint32_t aigp;
if (strmatch(aigp_metric, "igp-metric")) { /* Note: the metric is stored as MED for a locally redistributed. */
if (!path->nexthop) if (strmatch(aigp_metric, "igp-metric"))
return RMAP_NOMATCH; aigp = path->nexthop ? path->nexthop->metric : path->attr->med;
else
bgp_attr_set_aigp_metric(path->attr, path->nexthop->metric);
} else {
aigp = atoi(aigp_metric); aigp = atoi(aigp_metric);
bgp_attr_set_aigp_metric(path->attr, aigp);
}
path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AIGP); bgp_attr_set_aigp_metric(path->attr, aigp);
return RMAP_OKAY; return RMAP_OKAY;
} }
@ -3949,8 +3945,7 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
path = object; path = object;
peer = path->peer; peer = path->peer;
if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN) if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)) {
|| CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) {
/* Set next hop preference to global */ /* Set next hop preference to global */
SET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL); SET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL);
SET_FLAG(path->attr->rmap_change_flags, SET_FLAG(path->attr->rmap_change_flags,
@ -4076,10 +4071,8 @@ route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx, void *object)
path = object; path = object;
peer = path->peer; peer = path->peer;
if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN) if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)) &&
|| CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) peer->su_remote && sockunion_family(peer->su_remote) == AF_INET6) {
&& peer->su_remote
&& sockunion_family(peer->su_remote) == AF_INET6) {
peer_address = peer->su_remote->sin6.sin6_addr; peer_address = peer->su_remote->sin6.sin6_addr;
/* Set next hop value and length in attribute. */ /* Set next hop value and length in attribute. */
if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) { if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) {
@ -4094,7 +4087,6 @@ route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx, void *object)
path->attr->mp_nexthop_len = path->attr->mp_nexthop_len =
BGP_ATTR_NHLEN_IPV6_GLOBAL; BGP_ATTR_NHLEN_IPV6_GLOBAL;
} }
} else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) { } else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) {
/* The next hop value will be set as part of packet /* The next hop value will be set as part of packet
* rewrite. * rewrite.
@ -7144,7 +7136,7 @@ DEFUN_YANG (no_set_atomic_aggregate,
DEFPY_YANG (set_aigp_metric, DEFPY_YANG (set_aigp_metric,
set_aigp_metric_cmd, set_aigp_metric_cmd,
"set aigp-metric <igp-metric|(1-4294967295)>$aigp_metric", "set aigp-metric <igp-metric|(0-4294967295)>$aigp_metric",
SET_STR SET_STR
"BGP AIGP attribute (AIGP Metric TLV)\n" "BGP AIGP attribute (AIGP Metric TLV)\n"
"AIGP Metric value from IGP protocol\n" "AIGP Metric value from IGP protocol\n"
@ -7164,7 +7156,7 @@ DEFPY_YANG (set_aigp_metric,
DEFPY_YANG (no_set_aigp_metric, DEFPY_YANG (no_set_aigp_metric,
no_set_aigp_metric_cmd, no_set_aigp_metric_cmd,
"no set aigp-metric [<igp-metric|(1-4294967295)>]", "no set aigp-metric [<igp-metric|(0-4294967295)>]",
NO_STR NO_STR
SET_STR SET_STR
"BGP AIGP attribute (AIGP Metric TLV)\n" "BGP AIGP attribute (AIGP Metric TLV)\n"
@ -7236,43 +7228,6 @@ DEFUN_YANG (no_set_aggregator_as,
return nb_cli_apply_changes(vty, NULL); return nb_cli_apply_changes(vty, NULL);
} }
DEFUN_YANG (match_ipv6_next_hop,
match_ipv6_next_hop_cmd,
"match ipv6 next-hop ACCESSLIST6_NAME",
MATCH_STR
IPV6_STR
"Match IPv6 next-hop address of route\n"
"IPv6 access-list name\n")
{
const char *xpath =
"./match-condition[condition='frr-route-map:ipv6-next-hop-list']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_value, sizeof(xpath_value),
"%s/rmap-match-condition/list-name", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
argv[argc - 1]->arg);
return nb_cli_apply_changes(vty, NULL);
}
DEFUN_YANG (no_match_ipv6_next_hop,
no_match_ipv6_next_hop_cmd,
"no match ipv6 next-hop [ACCESSLIST6_NAME]",
NO_STR
MATCH_STR
IPV6_STR
"Match IPv6 next-hop address of route\n"
"IPv6 access-list name\n")
{
const char *xpath =
"./match-condition[condition='frr-route-map:ipv6-next-hop-list']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
DEFUN_YANG (match_ipv6_next_hop_address, DEFUN_YANG (match_ipv6_next_hop_address,
match_ipv6_next_hop_address_cmd, match_ipv6_next_hop_address_cmd,
"match ipv6 next-hop address X:X::X:X", "match ipv6 next-hop address X:X::X:X",
@ -7330,45 +7285,6 @@ ALIAS_HIDDEN (no_match_ipv6_next_hop_address,
"Match IPv6 next-hop address of route\n" "Match IPv6 next-hop address of route\n"
"IPv6 address of next hop\n") "IPv6 address of next hop\n")
DEFUN_YANG (match_ipv6_next_hop_prefix_list,
match_ipv6_next_hop_prefix_list_cmd,
"match ipv6 next-hop prefix-list PREFIXLIST_NAME",
MATCH_STR
IPV6_STR
"Match IPv6 next-hop address of route\n"
"Match entries by prefix-list\n"
"IPv6 prefix-list name\n")
{
const char *xpath =
"./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-list']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_value, sizeof(xpath_value),
"%s/rmap-match-condition/list-name", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
argv[argc - 1]->arg);
return nb_cli_apply_changes(vty, NULL);
}
DEFUN_YANG (no_match_ipv6_next_hop_prefix_list,
no_match_ipv6_next_hop_prefix_list_cmd,
"no match ipv6 next-hop prefix-list [PREFIXLIST_NAME]",
NO_STR
MATCH_STR
IPV6_STR
"Match IPv6 next-hop address of route\n"
"Match entries by prefix-list\n"
"IPv6 prefix-list name\n")
{
const char *xpath =
"./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-list']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
DEFPY_YANG (match_ipv4_next_hop, DEFPY_YANG (match_ipv4_next_hop,
match_ipv4_next_hop_cmd, match_ipv4_next_hop_cmd,
"match ip next-hop address A.B.C.D", "match ip next-hop address A.B.C.D",
@ -8041,12 +7957,8 @@ void bgp_route_map_init(void)
route_map_install_set(&route_set_ipv6_nexthop_peer_cmd); route_map_install_set(&route_set_ipv6_nexthop_peer_cmd);
route_map_install_match(&route_match_rpki_extcommunity_cmd); route_map_install_match(&route_match_rpki_extcommunity_cmd);
install_element(RMAP_NODE, &match_ipv6_next_hop_cmd);
install_element(RMAP_NODE, &match_ipv6_next_hop_address_cmd); install_element(RMAP_NODE, &match_ipv6_next_hop_address_cmd);
install_element(RMAP_NODE, &match_ipv6_next_hop_prefix_list_cmd);
install_element(RMAP_NODE, &no_match_ipv6_next_hop_cmd);
install_element(RMAP_NODE, &no_match_ipv6_next_hop_address_cmd); install_element(RMAP_NODE, &no_match_ipv6_next_hop_address_cmd);
install_element(RMAP_NODE, &no_match_ipv6_next_hop_prefix_list_cmd);
install_element(RMAP_NODE, &match_ipv6_next_hop_old_cmd); install_element(RMAP_NODE, &match_ipv6_next_hop_old_cmd);
install_element(RMAP_NODE, &no_match_ipv6_next_hop_old_cmd); install_element(RMAP_NODE, &no_match_ipv6_next_hop_old_cmd);
install_element(RMAP_NODE, &match_ipv4_next_hop_cmd); install_element(RMAP_NODE, &match_ipv4_next_hop_cmd);

View file

@ -1920,81 +1920,6 @@ DEFUN (no_rpki_retry_interval,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
#if CONFDATE > 20240916
CPP_NOTICE("Remove rpki_cache_cmd")
#endif
DEFPY(rpki_cache, rpki_cache_cmd,
"rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH]> [source <A.B.C.D>$bindaddr] preference (1-255)",
RPKI_OUTPUT_STRING
"Install a cache server to current group\n"
"IP address of cache server\n"
"Hostname of cache server\n"
"TCP port number\n"
"SSH port number\n"
"SSH user name\n"
"Path to own SSH private key\n"
"Path to the known hosts file\n"
"Configure source IP address of RPKI connection\n"
"Define a Source IP Address\n"
"Preference of the cache server\n"
"Preference value\n")
{
int return_value;
struct listnode *cache_node;
struct cache *current_cache;
struct rpki_vrf *rpki_vrf;
bool init;
if (vty->node == RPKI_VRF_NODE)
rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf);
else
rpki_vrf = VTY_GET_CONTEXT(rpki_vrf);
if (!rpki_vrf)
return CMD_WARNING_CONFIG_FAILED;
if (!rpki_vrf || !rpki_vrf->cache_list)
return CMD_WARNING;
init = !!list_isempty(rpki_vrf->cache_list);
for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node,
current_cache)) {
if (current_cache->preference == preference) {
vty_out(vty,
"Cache with preference %ld is already configured\n",
preference);
return CMD_WARNING;
}
}
// use ssh connection
if (ssh_uname) {
#if defined(FOUND_SSH)
return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname,
ssh_privkey, known_hosts_path,
preference, bindaddr_str);
#else
return_value = SUCCESS;
vty_out(vty,
"ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n");
#endif
} else { // use tcp connection
return_value = add_tcp_cache(rpki_vrf, cache, tcpport,
preference, bindaddr_str);
}
if (return_value == ERROR) {
vty_out(vty, "Could not create new rpki cache\n");
return CMD_WARNING;
}
if (init)
start(rpki_vrf);
return CMD_SUCCESS;
}
DEFPY(rpki_cache_tcp, rpki_cache_tcp_cmd, DEFPY(rpki_cache_tcp, rpki_cache_tcp_cmd,
"rpki cache tcp <A.B.C.D|WORD>$cache TCPPORT [source <A.B.C.D>$bindaddr] preference (1-255)", "rpki cache tcp <A.B.C.D|WORD>$cache TCPPORT [source <A.B.C.D>$bindaddr] preference (1-255)",
RPKI_OUTPUT_STRING RPKI_OUTPUT_STRING
@ -2820,7 +2745,6 @@ static void install_cli_commands(void)
/* Install rpki cache commands */ /* Install rpki cache commands */
install_element(RPKI_NODE, &rpki_cache_tcp_cmd); install_element(RPKI_NODE, &rpki_cache_tcp_cmd);
install_element(RPKI_NODE, &rpki_cache_ssh_cmd); install_element(RPKI_NODE, &rpki_cache_ssh_cmd);
install_element(RPKI_NODE, &rpki_cache_cmd);
install_element(RPKI_NODE, &no_rpki_cache_cmd); install_element(RPKI_NODE, &no_rpki_cache_cmd);
/* RPKI_VRF_NODE commands */ /* RPKI_VRF_NODE commands */
@ -2844,7 +2768,6 @@ static void install_cli_commands(void)
/* Install rpki cache commands */ /* Install rpki cache commands */
install_element(RPKI_VRF_NODE, &rpki_cache_tcp_cmd); install_element(RPKI_VRF_NODE, &rpki_cache_tcp_cmd);
install_element(RPKI_VRF_NODE, &rpki_cache_ssh_cmd); install_element(RPKI_VRF_NODE, &rpki_cache_ssh_cmd);
install_element(RPKI_VRF_NODE, &rpki_cache_cmd);
install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd); install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd);
/* Install show commands */ /* Install show commands */

View file

@ -7,7 +7,6 @@
#define __BGP_SCRIPT__ #define __BGP_SCRIPT__
#include <zebra.h> #include <zebra.h>
#include "bgpd.h"
#ifdef HAVE_SCRIPTING #ifdef HAVE_SCRIPTING
@ -18,6 +17,10 @@
*/ */
void bgp_script_init(void); void bgp_script_init(void);
/* Forward references */
struct peer;
struct attr;
void lua_pushpeer(lua_State *L, const struct peer *peer); void lua_pushpeer(lua_State *L, const struct peer *peer);
void lua_pushattr(lua_State *L, const struct attr *attr); void lua_pushattr(lua_State *L, const struct attr *attr);

View file

@ -50,6 +50,21 @@ DEFPY(bgp_snmp_traps_rfc4273, bgp_snmp_traps_rfc4273_cmd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFPY(bgp_snmp_traps_rfc4382, bgp_snmp_traps_rfc4382_cmd,
"[no$no] bgp snmp traps rfc4382",
NO_STR BGP_STR
"Configure BGP SNMP\n"
"Configure SNMP traps for BGP\n"
"Configure use of rfc4382 SNMP traps for BGP\n")
{
if (no) {
UNSET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382);
return CMD_SUCCESS;
}
SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382);
return CMD_SUCCESS;
}
DEFPY(bgp_snmp_traps_bgp4_mibv2, bgp_snmp_traps_bgp4_mibv2_cmd, DEFPY(bgp_snmp_traps_bgp4_mibv2, bgp_snmp_traps_bgp4_mibv2_cmd,
"[no$no] bgp snmp traps bgp4-mibv2", "[no$no] bgp snmp traps bgp4-mibv2",
NO_STR BGP_STR NO_STR BGP_STR
@ -69,9 +84,12 @@ static void bgp_snmp_traps_init(void)
{ {
install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4273_cmd); install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4273_cmd);
install_element(CONFIG_NODE, &bgp_snmp_traps_bgp4_mibv2_cmd); install_element(CONFIG_NODE, &bgp_snmp_traps_bgp4_mibv2_cmd);
install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4382_cmd);
SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273);
/* BGP4MIBv2 traps are disabled by default */ /* BGP4MIBv2 traps are disabled by default */
SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382);
} }
int bgp_cli_snmp_traps_config_write(struct vty *vty) int bgp_cli_snmp_traps_config_write(struct vty *vty)
@ -86,6 +104,10 @@ int bgp_cli_snmp_traps_config_write(struct vty *vty)
vty_out(vty, "bgp snmp traps bgp4-mibv2\n"); vty_out(vty, "bgp snmp traps bgp4-mibv2\n");
write++; write++;
} }
if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) {
vty_out(vty, "no bgp snmp traps rfc4382\n");
write++;
}
return write; return write;
} }

View file

@ -933,7 +933,9 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
else else
return SNMP_IPADDRESS(bgp_empty_addr); return SNMP_IPADDRESS(bgp_empty_addr);
case BGP4V2_NLRI_AS_PATH_CALC_LENGTH: case BGP4V2_NLRI_AS_PATH_CALC_LENGTH:
return SNMP_INTEGER(path->attr->aspath->segments->length); return SNMP_INTEGER((path->attr->aspath && path->attr->aspath->segments)
? path->attr->aspath->segments->length
: 0);
case BGP4V2_NLRI_AS_PATH: case BGP4V2_NLRI_AS_PATH:
return aspath_snmp_pathseg(path->attr->aspath, var_len); return aspath_snmp_pathseg(path->attr->aspath, var_len);
case BGP4V2_NLRI_PATH_ATTR_UNKNOWN: case BGP4V2_NLRI_PATH_ATTR_UNKNOWN:

View file

@ -343,7 +343,12 @@ static unsigned int updgrp_hash_key_make(const void *p)
key = 0; key = 0;
key = jhash_1word(peer->sort, key); /* EBGP or IBGP */ /* `remote-as auto` technically uses identical peer->sort.
* After OPEN message is parsed, this is updated accordingly, but
* we need to call the peer_sort() here also to properly create
* separate subgroups.
*/
key = jhash_1word(peer_sort((struct peer *)peer), key);
key = jhash_1word(peer->sub_sort, key); /* OAD */ key = jhash_1word(peer->sub_sort, key); /* OAD */
key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key); key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key);
key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
@ -778,8 +783,11 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
json_updgrp, "replaceLocalAs", json_updgrp, "replaceLocalAs",
CHECK_FLAG(updgrp->conf->flags, CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_REPLACE_AS)); PEER_FLAG_LOCAL_AS_REPLACE_AS));
json_object_boolean_add(json_updgrp, "dualAs",
CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_DUAL_AS));
} else { } else {
vty_out(vty, " Local AS %u%s%s\n", vty_out(vty, " Local AS %u%s%s%s\n",
updgrp->conf->change_local_as, updgrp->conf->change_local_as,
CHECK_FLAG(updgrp->conf->flags, CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_NO_PREPEND) PEER_FLAG_LOCAL_AS_NO_PREPEND)
@ -788,6 +796,10 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
CHECK_FLAG(updgrp->conf->flags, CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_REPLACE_AS) PEER_FLAG_LOCAL_AS_REPLACE_AS)
? " replace-as" ? " replace-as"
: "",
CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_DUAL_AS)
? " dual-as"
: ""); : "");
} }
} }
@ -2011,6 +2023,8 @@ int update_group_adjust_soloness(struct peer *peer, int set)
struct peer_group *group; struct peer_group *group;
struct listnode *node, *nnode; struct listnode *node, *nnode;
peer_flag_set(peer, PEER_FLAG_LONESOUL);
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
peer_lonesoul_or_not(peer, set); peer_lonesoul_or_not(peer, set);
if (peer_established(peer->connection)) if (peer_established(peer->connection))

View file

@ -738,9 +738,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
/* 5: Encode all the attributes, except MP_REACH_NLRI /* 5: Encode all the attributes, except MP_REACH_NLRI
* attr. */ * attr. */
total_attr_len = bgp_packet_attribute( total_attr_len = bgp_packet_attribute(NULL, peer, s, adv->baa->attr,
NULL, peer, s, adv->baa->attr, &vecarr, NULL, &vecarr, NULL, afi, safi, from, NULL,
afi, safi, from, NULL, NULL, 0, 0, 0, path); NULL, 0, 0, 0);
space_remaining = space_remaining =
STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s)) STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
@ -861,7 +861,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p, bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p,
label_pnt, num_labels, label_pnt, num_labels,
addpath_capable, addpath_tx_id, addpath_capable, addpath_tx_id,
&adv->baa->attr->evpn_overlay, bgp_attr_get_evpn_overlay(
adv->baa->attr),
pfx_buf, sizeof(pfx_buf)); pfx_buf, sizeof(pfx_buf));
zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
subgrp->update_group->id, subgrp->id, subgrp->update_group->id, subgrp->id,
@ -1148,12 +1149,9 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
/* Make place for total attribute length. */ /* Make place for total attribute length. */
pos = stream_get_endp(s); pos = stream_get_endp(s);
stream_putw(s, 0); stream_putw(s, 0);
total_attr_len = total_attr_len = bgp_packet_attribute(NULL, peer, s, attr, &vecarr, &p, afi, safi, from,
bgp_packet_attribute(NULL, peer, s, attr, &vecarr, &p, afi, NULL, &label, num_labels, addpath_capable,
safi, from, NULL, &label, num_labels, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
addpath_capable,
BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE,
NULL);
/* Set Total Path Attribute Length. */ /* Set Total Path Attribute Length. */
stream_putw_at(s, pos, total_attr_len); stream_putw_at(s, pos, total_attr_len);

File diff suppressed because it is too large Load diff

View file

@ -60,8 +60,6 @@ struct bgp;
#define VTY_BGP_GR_ROUTER_DETECT(_bgp, _peer, _peer_list) \ #define VTY_BGP_GR_ROUTER_DETECT(_bgp, _peer, _peer_list) \
do { \ do { \
if (_peer->bgp->t_startup) \
bgp_peer_gr_flags_update(_peer); \
for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \
if (CHECK_FLAG(peer_loop->flags, \ if (CHECK_FLAG(peer_loop->flags, \
PEER_FLAG_GRACEFUL_RESTART)) \ PEER_FLAG_GRACEFUL_RESTART)) \
@ -84,27 +82,24 @@ struct bgp;
} \ } \
} while (0) } while (0)
#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \ #define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(_bgp, \
_bgp, _peer_list, _ret) \ _peer_list, _ret) \
do { \ do { \
struct peer *peer_loop; \ struct peer *peer_loop; \
bool gr_router_detected = false; \ bool gr_router_detected = false; \
struct listnode *node = {0}; \ struct listnode *node = { 0 }; \
struct listnode *nnode = {0}; \ struct listnode *nnode = { 0 }; \
for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \
if (peer_loop->bgp->t_startup) \
bgp_peer_gr_flags_update(peer_loop); \
if (CHECK_FLAG(peer_loop->flags, \ if (CHECK_FLAG(peer_loop->flags, \
PEER_FLAG_GRACEFUL_RESTART)) \ PEER_FLAG_GRACEFUL_RESTART)) \
gr_router_detected = true; \ gr_router_detected = true; \
} \ } \
if (gr_router_detected \ if (gr_router_detected && \
&& _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
if (bgp_zebra_send_capabilities(_bgp, false)) \ if (bgp_zebra_send_capabilities(_bgp, false)) \
_ret = BGP_ERR_INVALID_VALUE; \ _ret = BGP_ERR_INVALID_VALUE; \
} else if (!gr_router_detected \ } else if (!gr_router_detected && \
&& _bgp->present_zebra_gr_state \ _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \
== ZEBRA_GR_ENABLE) { \
if (bgp_zebra_send_capabilities(_bgp, true)) \ if (bgp_zebra_send_capabilities(_bgp, true)) \
_ret = BGP_ERR_INVALID_VALUE; \ _ret = BGP_ERR_INVALID_VALUE; \
} \ } \
@ -166,8 +161,9 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty,
int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv, int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv,
int argc, struct bgp **bgp, bool use_json); int argc, struct bgp **bgp, bool use_json);
extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
safi_t safi, const char *neighbor, int as_type, safi_t safi, const char *neighbor,
as_t as, uint16_t show_flags); enum peer_asn_type as_type, as_t as,
uint16_t show_flags);
extern bool peergroup_flag_check(struct peer *peer, uint64_t flag); extern bool peergroup_flag_check(struct peer *peer, uint64_t flag);
extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
uint64_t flag); uint64_t flag);

View file

@ -195,7 +195,7 @@ static int bgp_ifp_destroy(struct interface *ifp)
bgp = ifp->vrf->info; bgp = ifp->vrf->info;
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx Intf del VRF %u IF %s", ifp->vrf->vrf_id, zlog_debug("Rx Intf del VRF %s IF %s", ifp->vrf->name,
ifp->name); ifp->name);
if (bgp) { if (bgp) {
@ -220,8 +220,7 @@ static int bgp_ifp_up(struct interface *ifp)
bgp_mac_add_mac_entry(ifp); bgp_mac_add_mac_entry(ifp);
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf->vrf_id, zlog_debug("Rx Intf up VRF %s IF %s", ifp->vrf->name, ifp->name);
ifp->name);
if (!bgp) if (!bgp)
return 0; return 0;
@ -235,7 +234,7 @@ static int bgp_ifp_up(struct interface *ifp)
hook_call(bgp_vrf_status_changed, bgp, ifp); hook_call(bgp_vrf_status_changed, bgp, ifp);
bgp_nht_ifp_up(ifp); bgp_nht_ifp_up(ifp);
if (bgp_get_default() && if_is_loopback(ifp)) { if (bgp_get_default() && if_is_vrf(ifp)) {
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP);
@ -259,7 +258,7 @@ static int bgp_ifp_down(struct interface *ifp)
bgp_mac_del_mac_entry(ifp); bgp_mac_del_mac_entry(ifp);
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx Intf down VRF %u IF %s", ifp->vrf->vrf_id, zlog_debug("Rx Intf down VRF %s IF %s", ifp->vrf->name,
ifp->name); ifp->name);
if (!bgp) if (!bgp)
@ -290,7 +289,7 @@ static int bgp_ifp_down(struct interface *ifp)
hook_call(bgp_vrf_status_changed, bgp, ifp); hook_call(bgp_vrf_status_changed, bgp, ifp);
bgp_nht_ifp_down(ifp); bgp_nht_ifp_down(ifp);
if (bgp_get_default() && if_is_loopback(ifp)) { if (bgp_get_default() && if_is_vrf(ifp)) {
vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP);
vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6);
vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP); vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP);
@ -319,8 +318,8 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
return 0; return 0;
if (bgp_debug_zebra(ifc->address)) if (bgp_debug_zebra(ifc->address))
zlog_debug("Rx Intf address add VRF %u IF %s addr %pFX", vrf_id, zlog_debug("Rx Intf address add VRF %s IF %s addr %pFX",
ifc->ifp->name, ifc->address); ifc->ifp->vrf->name, ifc->ifp->name, ifc->address);
if (!bgp) if (!bgp)
return 0; return 0;
@ -398,8 +397,8 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
return 0; return 0;
if (bgp_debug_zebra(ifc->address)) if (bgp_debug_zebra(ifc->address))
zlog_debug("Rx Intf address del VRF %u IF %s addr %pFX", vrf_id, zlog_debug("Rx Intf address del VRF %s IF %s addr %pFX",
ifc->ifp->name, ifc->address); ifc->ifp->vrf->name, ifc->ifp->name, ifc->address);
if (bgp && if_is_operative(ifc->ifp)) { if (bgp && if_is_operative(ifc->ifp)) {
bgp_connected_delete(bgp, ifc); bgp_connected_delete(bgp, ifc);
@ -450,8 +449,8 @@ static int bgp_interface_nbr_address_add(ZAPI_CALLBACK_ARGS)
return 0; return 0;
if (bgp_debug_zebra(ifc->address)) if (bgp_debug_zebra(ifc->address))
zlog_debug("Rx Intf neighbor add VRF %u IF %s addr %pFX", zlog_debug("Rx Intf neighbor add VRF %s IF %s addr %pFX",
vrf_id, ifc->ifp->name, ifc->address); ifc->ifp->vrf->name, ifc->ifp->name, ifc->address);
if (if_is_operative(ifc->ifp)) { if (if_is_operative(ifc->ifp)) {
bgp = bgp_lookup_by_vrf_id(vrf_id); bgp = bgp_lookup_by_vrf_id(vrf_id);
@ -473,8 +472,8 @@ static int bgp_interface_nbr_address_delete(ZAPI_CALLBACK_ARGS)
return 0; return 0;
if (bgp_debug_zebra(ifc->address)) if (bgp_debug_zebra(ifc->address))
zlog_debug("Rx Intf neighbor del VRF %u IF %s addr %pFX", zlog_debug("Rx Intf neighbor del VRF %s IF %s addr %pFX",
vrf_id, ifc->ifp->name, ifc->address); ifc->ifp->vrf->name, ifc->ifp->name, ifc->address);
if (if_is_operative(ifc->ifp)) { if (if_is_operative(ifc->ifp)) {
bgp = bgp_lookup_by_vrf_id(vrf_id); bgp = bgp_lookup_by_vrf_id(vrf_id);
@ -543,7 +542,7 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS)
/* Now perform the add/update. */ /* Now perform the add/update. */
bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex, bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex,
nhtype, bhtype, api.distance, api.metric, nhtype, api.distance, bhtype, api.metric,
api.type, api.instance, api.tag); api.type, api.instance, api.tag);
} else { } else {
bgp_redistribute_delete(bgp, &api.prefix, api.type, bgp_redistribute_delete(bgp, &api.prefix, api.type,
@ -556,13 +555,14 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS)
if (add) { if (add) {
inet_ntop(api.prefix.family, &nexthop, buf, inet_ntop(api.prefix.family, &nexthop, buf,
sizeof(buf)); sizeof(buf));
zlog_debug( zlog_debug("Rx route ADD %s %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI,
"Rx route ADD VRF %u %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI, bgp->name_pretty,
vrf_id, zebra_route_string(api.type), zebra_route_string(api.type), api.instance,
api.instance, &api.prefix, buf, nhtype, ifindex, &api.prefix, buf, nhtype, ifindex,
api.metric, api.distance, api.tag); api.metric, api.distance, api.tag);
} else { } else {
zlog_debug("Rx route DEL VRF %u %s[%d] %pFX", vrf_id, zlog_debug("Rx route DEL %s %s[%d] %pFX",
bgp->name_pretty,
zebra_route_string(api.type), api.instance, zebra_route_string(api.type), api.instance,
&api.prefix); &api.prefix);
} }
@ -1098,6 +1098,8 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
struct attr *attr, bool is_evpn, struct attr *attr, bool is_evpn,
struct zapi_nexthop *api_nh) struct zapi_nexthop *api_nh)
{ {
struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr);
api_nh->gate.ipv4 = *nexthop; api_nh->gate.ipv4 = *nexthop;
api_nh->vrf_id = nh_bgp->vrf_id; api_nh->vrf_id = nh_bgp->vrf_id;
@ -1114,7 +1116,7 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
* treat the nexthop as NEXTHOP_TYPE_IPV4 * treat the nexthop as NEXTHOP_TYPE_IPV4
* Else, mark the nexthop as onlink. * Else, mark the nexthop as onlink.
*/ */
if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)
api_nh->type = NEXTHOP_TYPE_IPV4; api_nh->type = NEXTHOP_TYPE_IPV4;
else { else {
api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
@ -1140,9 +1142,11 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
struct zapi_nexthop *api_nh) struct zapi_nexthop *api_nh)
{ {
struct attr *attr; struct attr *attr;
struct bgp_route_evpn *bre;
attr = pi->attr; attr = pi->attr;
api_nh->vrf_id = nh_bgp->vrf_id; api_nh->vrf_id = nh_bgp->vrf_id;
bre = bgp_attr_get_evpn_overlay(attr);
if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) { if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) {
api_nh->type = attr->nh_type; api_nh->type = attr->nh_type;
@ -1153,7 +1157,7 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
* treat the nexthop as NEXTHOP_TYPE_IPV4 * treat the nexthop as NEXTHOP_TYPE_IPV4
* Else, mark the nexthop as onlink. * Else, mark the nexthop as onlink.
*/ */
if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)
api_nh->type = NEXTHOP_TYPE_IPV6; api_nh->type = NEXTHOP_TYPE_IPV6;
else { else {
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
@ -1251,6 +1255,7 @@ static void bgp_zebra_announce_parse_nexthop(
uint32_t ttl = 0; uint32_t ttl = 0;
uint32_t bos = 0; uint32_t bos = 0;
uint32_t exp = 0; uint32_t exp = 0;
struct bgp_route_evpn *bre = NULL;
/* Determine if we're doing weighted ECMP or not */ /* Determine if we're doing weighted ECMP or not */
do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info); do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info);
@ -1365,6 +1370,7 @@ static void bgp_zebra_announce_parse_nexthop(
} }
is_evpn = !!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN); is_evpn = !!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN);
bre = bgp_attr_get_evpn_overlay(mpinfo->attr);
/* Did we get proper nexthop info to update zebra? */ /* Did we get proper nexthop info to update zebra? */
if (!nh_updated) if (!nh_updated)
@ -1400,9 +1406,7 @@ static void bgp_zebra_announce_parse_nexthop(
api_nh->labels[0] = nh_label; api_nh->labels[0] = nh_label;
} }
if (is_evpn if (is_evpn && !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP))
&& mpinfo->attr->evpn_overlay.type
!= OVERLAY_INDEX_GATEWAY_IP)
memcpy(&api_nh->rmac, &(mpinfo->attr->rmac), memcpy(&api_nh->rmac, &(mpinfo->attr->rmac),
sizeof(struct ethaddr)); sizeof(struct ethaddr));
@ -1526,7 +1530,6 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
struct peer *peer; struct peer *peer;
uint32_t metric; uint32_t metric;
route_tag_t tag; route_tag_t tag;
bool is_add;
uint32_t nhg_id = 0; uint32_t nhg_id = 0;
struct bgp_table *table = bgp_dest_table(dest); struct bgp_table *table = bgp_dest_table(dest);
const struct prefix *p = bgp_dest_get_prefix(dest); const struct prefix *p = bgp_dest_get_prefix(dest);
@ -1580,9 +1583,7 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
table->afi, table->safi, &nhg_id, table->afi, table->safi, &nhg_id,
&metric, &tag, &allow_recursion); &metric, &tag, &allow_recursion);
is_add = (valid_nh_count || nhg_id) ? true : false; if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) {
if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) {
struct bgp_zebra_opaque bzo = {}; struct bgp_zebra_opaque bzo = {};
const char *reason = const char *reason =
bgp_path_selection_reason2str(dest->reason); bgp_path_selection_reason2str(dest->reason);
@ -1638,18 +1639,17 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
} }
if (bgp_debug_zebra(p)) { if (bgp_debug_zebra(p)) {
zlog_debug( zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI
"Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI
" count %d nhg %d", " count %d nhg %d",
is_add ? "add" : "delete", bgp->vrf_id, &api.prefix, bgp->name_pretty, api.tableid, &api.prefix,
api.metric, api.tag, api.nexthop_num, nhg_id); api.metric, api.tag, api.nexthop_num, nhg_id);
bgp_debug_zebra_nh(&api); bgp_debug_zebra_nh(&api);
zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)",
__func__, p, (allow_recursion ? "" : "NOT ")); __func__, p, (allow_recursion ? "" : "NOT "));
} }
return zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
zclient, &api); return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
} }
@ -1731,8 +1731,8 @@ enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest,
} }
if (bgp_debug_zebra(p)) if (bgp_debug_zebra(p))
zlog_debug("Tx route delete VRF %u %pFX", bgp->vrf_id, zlog_debug("Tx route delete %s (table id %u) %pFX",
&api.prefix); bgp->name_pretty, api.tableid, &api.prefix);
return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
} }
@ -1778,8 +1778,9 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e)
} }
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("BGP %s route %pBD(%s) with dest %p and flags 0x%x to zebra", zlog_debug("BGP %s%s route %pBD(%s) with dest %p and flags 0x%x to zebra",
install ? "announcing" : "withdrawing", dest, install ? "announcing" : "withdrawing",
is_evpn ? " evpn" : " ", dest,
table->bgp->name_pretty, dest, dest->flags); table->bgp->name_pretty, dest, dest->flags);
if (install) { if (install) {
@ -2069,8 +2070,8 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type,
return CMD_SUCCESS; return CMD_SUCCESS;
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Tx redistribute add VRF %u afi %d %s %d", zlog_debug("Tx redistribute add %s afi %d %s %d",
bgp->vrf_id, afi, zebra_route_string(type), bgp->name_pretty, afi, zebra_route_string(type),
instance); instance);
/* Send distribute add message to zebra. */ /* Send distribute add message to zebra. */
@ -2090,8 +2091,8 @@ int bgp_redistribute_resend(struct bgp *bgp, afi_t afi, int type,
return -1; return -1;
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Tx redistribute del/add VRF %u afi %d %s %d", zlog_debug("Tx redistribute del/add %s afi %d %s %d",
bgp->vrf_id, afi, zebra_route_string(type), bgp->name_pretty, afi, zebra_route_string(type),
instance); instance);
/* Send distribute add message to zebra. */ /* Send distribute add message to zebra. */
@ -2185,9 +2186,9 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type,
if (bgp_install_info_to_zebra(bgp)) { if (bgp_install_info_to_zebra(bgp)) {
/* Send distribute delete message to zebra. */ /* Send distribute delete message to zebra. */
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Tx redistribute del VRF %u afi %d %s %d", zlog_debug("Tx redistribute del %s afi %d %s %d",
bgp->vrf_id, afi, zebra_route_string(type), bgp->name_pretty, afi,
instance); zebra_route_string(type), instance);
zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi,
type, instance, bgp->vrf_id); type, instance, bgp->vrf_id);
} }
@ -2290,7 +2291,7 @@ void bgp_zebra_instance_register(struct bgp *bgp)
return; return;
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Registering VRF %u", bgp->vrf_id); zlog_debug("Registering %s", bgp->name_pretty);
/* Register for router-id, interfaces, redistributed routes. */ /* Register for router-id, interfaces, redistributed routes. */
zclient_send_reg_requests(zclient, bgp->vrf_id); zclient_send_reg_requests(zclient, bgp->vrf_id);
@ -2312,7 +2313,7 @@ void bgp_zebra_instance_deregister(struct bgp *bgp)
return; return;
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Deregistering VRF %u", bgp->vrf_id); zlog_debug("Deregistering %s", bgp->name_pretty);
/* For EVPN instance, unregister learning about VNIs, if appropriate. */ /* For EVPN instance, unregister learning about VNIs, if appropriate. */
if (bgp->advertise_all_vni) if (bgp->advertise_all_vni)
@ -2326,6 +2327,9 @@ void bgp_zebra_initiate_radv(struct bgp *bgp, struct peer *peer)
{ {
uint32_t ra_interval = BGP_UNNUM_DEFAULT_RA_INTERVAL; uint32_t ra_interval = BGP_UNNUM_DEFAULT_RA_INTERVAL;
if (CHECK_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA))
return;
/* Don't try to initiate if we're not connected to Zebra */ /* Don't try to initiate if we're not connected to Zebra */
if (zclient->sock < 0) if (zclient->sock < 0)
return; return;
@ -3325,7 +3329,7 @@ static int bgp_ifp_create(struct interface *ifp)
struct bgp *bgp; struct bgp *bgp;
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx Intf add VRF %u IF %s", ifp->vrf->vrf_id, zlog_debug("Rx Intf add VRF %s IF %s", ifp->vrf->name,
ifp->name); ifp->name);
bgp = ifp->vrf->info; bgp = ifp->vrf->info;
@ -3378,11 +3382,278 @@ static int bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
return 0; return 0;
} }
/**
* Internal function to process an SRv6 locator
*
* @param locator The locator to be processed
*/
static int bgp_zebra_process_srv6_locator_internal(struct srv6_locator *locator)
{
struct bgp *bgp = bgp_get_default();
if (!bgp || !bgp->srv6_enabled || !locator)
return -1;
/*
* Check if the main BGP instance is configured to use the received
* locator
*/
if (strcmp(bgp->srv6_locator_name, locator->name) != 0) {
zlog_err("%s: SRv6 Locator name unmatch %s:%s", __func__,
bgp->srv6_locator_name, locator->name);
return 0;
}
zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u",
__func__, locator->name, &locator->prefix,
locator->block_bits_length, locator->node_bits_length,
locator->function_bits_length, locator->argument_bits_length);
/* Store the locator in the main BGP instance */
bgp->srv6_locator = srv6_locator_alloc(locator->name);
srv6_locator_copy(bgp->srv6_locator, locator);
/*
* Process VPN-to-VRF and VRF-to-VPN leaks to advertise new locator
* and SIDs.
*/
vpn_leak_postchange_all();
return 0;
}
static int bgp_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)
{
struct bgp *bgp = bgp_get_default();
struct srv6_locator *locator;
struct srv6_sid_ctx ctx;
struct in6_addr sid_addr;
enum zapi_srv6_sid_notify note;
struct bgp *bgp_vrf;
struct vrf *vrf;
struct listnode *node, *nnode;
char buf[256];
struct in6_addr *tovpn_sid;
struct prefix_ipv6 tmp_prefix;
uint32_t sid_func;
bool found = false;
if (!bgp || !bgp->srv6_enabled)
return -1;
if (!bgp->srv6_locator) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: ignoring SRv6 SID notify: locator not set",
__func__);
return -1;
}
/* Decode the received notification message */
if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr,
&sid_func, NULL, &note, NULL)) {
zlog_err("%s : error in msg decode", __func__);
return -1;
}
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 %s",
__func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx),
&sid_addr, zapi_srv6_sid_notify2str(note));
/* Get the BGP instance for which the SID has been requested, if any */
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp_vrf)) {
vrf = vrf_lookup_by_id(bgp_vrf->vrf_id);
if (!vrf)
continue;
if (vrf->vrf_id == ctx.vrf_id) {
found = true;
break;
}
}
if (!found) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: ignoring SRv6 SID notify: No VRF suitable for received SID ctx %s sid_value %pI6",
__func__,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx),
&sid_addr);
return -1;
}
/* Handle notification */
switch (note) {
case ZAPI_SRV6_SID_ALLOCATED:
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("SRv6 SID %pI6 %s : ALLOCATED", &sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
/* Verify that the received SID belongs to the configured locator */
tmp_prefix.family = AF_INET6;
tmp_prefix.prefixlen = IPV6_MAX_BITLEN;
tmp_prefix.prefix = sid_addr;
if (!prefix_match((struct prefix *)&bgp->srv6_locator->prefix,
(struct prefix *)&tmp_prefix))
return -1;
/* Get label */
uint8_t func_len = bgp->srv6_locator->function_bits_length;
uint8_t shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH -
func_len;
int label = sid_func << shift_len;
/* Un-export VPN to VRF routes */
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp,
bgp_vrf);
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, bgp,
bgp_vrf);
locator = srv6_locator_alloc(bgp->srv6_locator_name);
srv6_locator_copy(locator, bgp->srv6_locator);
/* Store SID, locator, and label */
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
*tovpn_sid = sid_addr;
if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT6) {
XFREE(MTYPE_BGP_SRV6_SID,
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
srv6_locator_free(
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
sid_unregister(bgp,
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid = tovpn_sid;
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator = locator;
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_transpose_label =
label;
} else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT4) {
XFREE(MTYPE_BGP_SRV6_SID,
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
srv6_locator_free(
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
sid_unregister(bgp,
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid = tovpn_sid;
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator = locator;
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_transpose_label =
label;
} else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT46) {
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
srv6_locator_free(bgp_vrf->tovpn_sid_locator);
sid_unregister(bgp, bgp_vrf->tovpn_sid);
bgp_vrf->tovpn_sid = tovpn_sid;
bgp_vrf->tovpn_sid_locator = locator;
bgp_vrf->tovpn_sid_transpose_label = label;
} else {
srv6_locator_free(locator);
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Unsupported behavior. Not assigned SRv6 SID: %s %pI6",
srv6_sid_ctx2str(buf, sizeof(buf),
&ctx),
&sid_addr);
return -1;
}
/* Register the new SID */
sid_register(bgp, tovpn_sid, bgp->srv6_locator_name);
/* Export VPN to VRF routes */
vpn_leak_postchange_all();
break;
case ZAPI_SRV6_SID_RELEASED:
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
/* Un-export VPN to VRF routes */
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp,
bgp_vrf);
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, bgp,
bgp_vrf);
/* Remove SID, locator, and label */
if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT6) {
XFREE(MTYPE_BGP_SRV6_SID,
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
if (bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator) {
srv6_locator_free(bgp->vpn_policy[AFI_IP6]
.tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator =
NULL;
}
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_transpose_label =
0;
/* Unregister the SID */
sid_unregister(bgp,
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
} else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT4) {
XFREE(MTYPE_BGP_SRV6_SID,
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
if (bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator) {
srv6_locator_free(bgp->vpn_policy[AFI_IP]
.tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator =
NULL;
}
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_transpose_label =
0;
/* Unregister the SID */
sid_unregister(bgp,
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
} else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT46) {
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
if (bgp_vrf->tovpn_sid_locator) {
srv6_locator_free(bgp_vrf->tovpn_sid_locator);
bgp_vrf->tovpn_sid_locator = NULL;
}
bgp_vrf->tovpn_sid_transpose_label = 0;
/* Unregister the SID */
sid_unregister(bgp, bgp_vrf->tovpn_sid);
} else {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Unsupported behavior. Not assigned SRv6 SID: %s %pI6",
srv6_sid_ctx2str(buf, sizeof(buf),
&ctx),
&sid_addr);
return -1;
}
/* Export VPN to VRF routes*/
vpn_leak_postchange_all();
break;
case ZAPI_SRV6_SID_FAIL_ALLOC:
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("SRv6 SID %pI6 %s: Failed to allocate",
&sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
/* Error will be logged by zebra module */
break;
case ZAPI_SRV6_SID_FAIL_RELEASE:
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: SRv6 SID %pI6 %s failure to release",
__func__, &sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
/* Error will be logged by zebra module */
break;
}
return 0;
}
static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
{ {
struct srv6_locator loc = {}; struct srv6_locator loc = {};
struct bgp *bgp = bgp_get_default(); struct bgp *bgp = bgp_get_default();
const char *loc_name = bgp->srv6_locator_name;
if (!bgp || !bgp->srv6_enabled) if (!bgp || !bgp->srv6_enabled)
return 0; return 0;
@ -3390,10 +3661,7 @@ static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
return -1; return -1;
if (bgp_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) return bgp_zebra_process_srv6_locator_internal(&loc);
return -1;
return 0;
} }
static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
@ -3401,7 +3669,8 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
struct srv6_locator loc = {}; struct srv6_locator loc = {};
struct bgp *bgp = bgp_get_default(); struct bgp *bgp = bgp_get_default();
struct listnode *node, *nnode; struct listnode *node, *nnode;
struct srv6_locator_chunk *chunk, *tovpn_sid_locator; struct srv6_locator_chunk *chunk;
struct srv6_locator *tovpn_sid_locator;
struct bgp_srv6_function *func; struct bgp_srv6_function *func;
struct bgp *bgp_vrf; struct bgp *bgp_vrf;
struct in6_addr *tovpn_sid; struct in6_addr *tovpn_sid;
@ -3413,6 +3682,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
return -1; return -1;
// clear SRv6 locator
if (bgp->srv6_locator) {
srv6_locator_free(bgp->srv6_locator);
bgp->srv6_locator = NULL;
}
// refresh chunks // refresh chunks
for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk)) for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk))
if (prefix_match((struct prefix *)&loc.prefix, if (prefix_match((struct prefix *)&loc.prefix,
@ -3489,10 +3764,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
tmp_prefi.prefixlen = IPV6_MAX_BITLEN; tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix; tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix, if (prefix_match((struct prefix *)&loc.prefix,
(struct prefix *)&tmp_prefi)) (struct prefix *)&tmp_prefi)) {
srv6_locator_chunk_free( srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP]
&bgp_vrf->vpn_policy[AFI_IP]
.tovpn_sid_locator); .tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator =
NULL;
}
} }
/* refresh vpnv6 tovpn_sid_locator */ /* refresh vpnv6 tovpn_sid_locator */
@ -3503,10 +3780,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
tmp_prefi.prefixlen = IPV6_MAX_BITLEN; tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix; tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix, if (prefix_match((struct prefix *)&loc.prefix,
(struct prefix *)&tmp_prefi)) (struct prefix *)&tmp_prefi)) {
srv6_locator_chunk_free( srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP6]
&bgp_vrf->vpn_policy[AFI_IP6]
.tovpn_sid_locator); .tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator =
NULL;
}
} }
/* refresh per-vrf tovpn_sid_locator */ /* refresh per-vrf tovpn_sid_locator */
@ -3516,9 +3795,10 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
tmp_prefi.prefixlen = IPV6_MAX_BITLEN; tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix; tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix, if (prefix_match((struct prefix *)&loc.prefix,
(struct prefix *)&tmp_prefi)) (struct prefix *)&tmp_prefi)) {
srv6_locator_chunk_free( srv6_locator_free(bgp_vrf->tovpn_sid_locator);
&bgp_vrf->tovpn_sid_locator); bgp_vrf->tovpn_sid_locator = NULL;
}
} }
} }
@ -3555,6 +3835,7 @@ static zclient_handler *const bgp_handlers[] = {
[ZEBRA_SRV6_LOCATOR_DELETE] = bgp_zebra_process_srv6_locator_delete, [ZEBRA_SRV6_LOCATOR_DELETE] = bgp_zebra_process_srv6_locator_delete,
[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
bgp_zebra_process_srv6_locator_chunk, bgp_zebra_process_srv6_locator_chunk,
[ZEBRA_SRV6_SID_NOTIFY] = bgp_zebra_srv6_sid_notify,
}; };
static int bgp_if_new_hook(struct interface *ifp) static int bgp_if_new_hook(struct interface *ifp)
@ -3582,16 +3863,19 @@ void bgp_if_init(void)
hook_register_prio(if_del, 0, bgp_if_delete_hook); hook_register_prio(if_del, 0, bgp_if_delete_hook);
} }
static void bgp_start_label_manager(struct event *start)
{
bgp_zebra_label_manager_connect();
}
static bool bgp_zebra_label_manager_ready(void) static bool bgp_zebra_label_manager_ready(void)
{ {
return (zclient_sync->sock > 0); return (zclient_sync->sock > 0);
} }
static void bgp_start_label_manager(struct event *start)
{
if (!bgp_zebra_label_manager_ready() &&
!bgp_zebra_label_manager_connect())
event_add_timer(bm->master, bgp_start_label_manager, NULL, 1,
&bm->t_bgp_start_label_manager);
}
static bool bgp_zebra_label_manager_connect(void) static bool bgp_zebra_label_manager_connect(void)
{ {
/* Connect to label manager. */ /* Connect to label manager. */
@ -3963,6 +4247,11 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable)
return BGP_GR_FAILURE; return BGP_GR_FAILURE;
} }
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s(%d): Sending GR capability %s to zebra",
bgp->name_pretty, bgp->vrf_id,
disable ? "disabled" : "enabled");
/* Check if capability is already sent. If the flag force is set /* Check if capability is already sent. If the flag force is set
* send the capability since this can be initial bgp configuration * send the capability since this can be initial bgp configuration
*/ */
@ -3978,8 +4267,8 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable)
if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api) if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api)
== ZCLIENT_SEND_FAILURE) { == ZCLIENT_SEND_FAILURE) {
zlog_err("%s: %s error sending capability", __func__, zlog_err("%s(%d): Error sending GR capability to zebra",
bgp->name_pretty); bgp->name_pretty, bgp->vrf_id);
ret = BGP_GR_FAILURE; ret = BGP_GR_FAILURE;
} else { } else {
if (disable) if (disable)
@ -3987,9 +4276,6 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable)
else else
bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE; bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE;
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: %s send capabilty success", __func__,
bgp->name_pretty);
ret = BGP_GR_SUCCESS; ret = BGP_GR_SUCCESS;
} }
return ret; return ret;
@ -4087,6 +4373,89 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name)
return srv6_manager_release_locator_chunk(zclient, name); return srv6_manager_release_locator_chunk(zclient, name);
} }
/**
* Ask the SRv6 Manager (zebra) about a specific locator
*
* @param name Locator name
* @return 0 on success, -1 otherwise
*/
int bgp_zebra_srv6_manager_get_locator(const char *name)
{
if (!name)
return -1;
/*
* Send the Get Locator request to the SRv6 Manager and return the
* result
*/
return srv6_manager_get_locator(zclient, name);
}
/**
* Ask the SRv6 Manager (zebra) to allocate a SID.
*
* Optionally, it is possible to provide an IPv6 address (sid_value parameter).
*
* When sid_value is provided, the SRv6 Manager allocates the requested SID
* address, if the request can be satisfied (explicit allocation).
*
* When sid_value is not provided, the SRv6 Manager allocates any available SID
* from the provided locator (dynamic allocation).
*
* @param ctx Context to be associated with the request SID
* @param sid_value IPv6 address to be associated with the requested SID (optional)
* @param locator_name Name of the locator from which the SID must be allocated
* @param sid_func SID Function allocated by the SRv6 Manager.
*/
bool bgp_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx,
struct in6_addr *sid_value,
const char *locator_name, uint32_t *sid_func)
{
int ret;
if (!ctx || !locator_name)
return false;
/*
* Send the Get SRv6 SID request to the SRv6 Manager and check the
* result
*/
ret = srv6_manager_get_sid(zclient, ctx, sid_value, locator_name,
sid_func);
if (ret < 0) {
zlog_warn("%s: error getting SRv6 SID!", __func__);
return false;
}
return true;
}
/**
* Ask the SRv6 Manager (zebra) to release a previously allocated SID.
*
* This function is used to tell the SRv6 Manager that BGP no longer intends
* to use the SID.
*
* @param ctx Context to be associated with the SID to be released
*/
void bgp_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx)
{
int ret;
if (!ctx)
return;
/*
* Send the Release SRv6 SID request to the SRv6 Manager and check the
* result
*/
ret = srv6_manager_release_sid(zclient, ctx);
if (ret < 0) {
zlog_warn("%s: error releasing SRv6 SID!", __func__);
return;
}
}
void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
ifindex_t ifindex, vrf_id_t vrf_id, ifindex_t ifindex, vrf_id_t vrf_id,
enum lsp_types_t ltype, struct prefix *p, enum lsp_types_t ltype, struct prefix *p,

View file

@ -117,6 +117,13 @@ extern int bgp_zebra_update(struct bgp *bgp, afi_t afi, safi_t safi,
extern int bgp_zebra_stale_timer_update(struct bgp *bgp); extern int bgp_zebra_stale_timer_update(struct bgp *bgp);
extern int bgp_zebra_srv6_manager_get_locator_chunk(const char *name); extern int bgp_zebra_srv6_manager_get_locator_chunk(const char *name);
extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name); extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name);
extern int bgp_zebra_srv6_manager_get_locator(const char *name);
extern bool bgp_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx,
struct in6_addr *sid_value,
const char *locator_name,
uint32_t *sid_func);
extern void bgp_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx);
extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
ifindex_t index, vrf_id_t vrfid, ifindex_t index, vrf_id_t vrfid,
enum lsp_types_t ltype, enum lsp_types_t ltype,

File diff suppressed because it is too large Load diff

View file

@ -56,10 +56,12 @@ struct bgp_pbr_config;
* behavior * behavior
* in the system. * in the system.
*/ */
enum { AS_UNSPECIFIED = 0, enum peer_asn_type {
AS_SPECIFIED, AS_UNSPECIFIED = 1,
AS_INTERNAL, AS_SPECIFIED = 2,
AS_EXTERNAL, AS_INTERNAL = 4,
AS_EXTERNAL = 8,
AS_AUTO = 16,
}; };
/* Zebra Gracaful Restart states */ /* Zebra Gracaful Restart states */
@ -129,6 +131,7 @@ struct bgp_master {
#define BGP_OPT_NO_ZEBRA (1 << 2) #define BGP_OPT_NO_ZEBRA (1 << 2)
#define BGP_OPT_TRAPS_RFC4273 (1 << 3) #define BGP_OPT_TRAPS_RFC4273 (1 << 3)
#define BGP_OPT_TRAPS_BGP4MIBV2 (1 << 4) #define BGP_OPT_TRAPS_BGP4MIBV2 (1 << 4)
#define BGP_OPT_TRAPS_RFC4382 (1 << 5)
uint64_t updgrp_idspace; uint64_t updgrp_idspace;
uint64_t subgrp_idspace; uint64_t subgrp_idspace;
@ -163,6 +166,24 @@ struct bgp_master {
uint32_t flags; uint32_t flags;
#define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0) #define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0)
#define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1) #define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1)
#define BM_FLAG_MAINTENANCE_MODE (1 << 2)
#define BM_FLAG_GR_RESTARTER (1 << 3)
#define BM_FLAG_GR_DISABLED (1 << 4)
#define BM_FLAG_GR_PRESERVE_FWD (1 << 5)
#define BM_FLAG_GRACEFUL_RESTART (1 << 6)
#define BM_FLAG_GR_COMPLETE (1 << 7)
#define BM_FLAG_IPV6_NO_AUTO_RA (1 << 8)
#define BM_FLAG_GR_CONFIGURED (BM_FLAG_GR_RESTARTER | BM_FLAG_GR_DISABLED)
/* BGP-wide graceful restart config params */
uint32_t restart_time;
uint32_t stalepath_time;
uint32_t select_defer_time;
uint32_t rib_stale_time;
time_t startup_time;
time_t gr_completion_time;
bool terminating; /* global flag that sigint terminate seen */ bool terminating; /* global flag that sigint terminate seen */
@ -250,7 +271,7 @@ struct vpn_policy {
*/ */
uint32_t tovpn_sid_index; /* unset => set to 0 */ uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid; struct in6_addr *tovpn_sid;
struct srv6_locator_chunk *tovpn_sid_locator; struct srv6_locator *tovpn_sid_locator;
uint32_t tovpn_sid_transpose_label; uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent; struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
}; };
@ -293,9 +314,9 @@ struct graceful_restart_info {
/* Best route select */ /* Best route select */
struct event *t_route_select; struct event *t_route_select;
/* AFI, SAFI enabled */ /* AFI, SAFI enabled */
bool af_enabled[AFI_MAX][SAFI_MAX]; bool af_enabled;
/* Route update completed */ /* Route update completed */
bool route_sync[AFI_MAX][SAFI_MAX]; bool route_sync;
}; };
enum global_mode { enum global_mode {
@ -470,9 +491,7 @@ struct bgp {
uint32_t restarted_peers; uint32_t restarted_peers;
uint32_t implicit_eors; uint32_t implicit_eors;
uint32_t explicit_eors; uint32_t explicit_eors;
#define BGP_UPDATE_DELAY_DEF 0 #define BGP_UPDATE_DELAY_DEFAULT 0
#define BGP_UPDATE_DELAY_MIN 0
#define BGP_UPDATE_DELAY_MAX 3600
/* Reference bandwidth for BGP link-bandwidth. Used when /* Reference bandwidth for BGP link-bandwidth. Used when
* the LB value has to be computed based on some other * the LB value has to be computed based on some other
@ -532,6 +551,9 @@ struct bgp {
#define BGP_FLAG_ENFORCE_FIRST_AS (1ULL << 36) #define BGP_FLAG_ENFORCE_FIRST_AS (1ULL << 36)
#define BGP_FLAG_DYNAMIC_CAPABILITY (1ULL << 37) #define BGP_FLAG_DYNAMIC_CAPABILITY (1ULL << 37)
#define BGP_FLAG_VNI_DOWN (1ULL << 38) #define BGP_FLAG_VNI_DOWN (1ULL << 38)
#define BGP_FLAG_INSTANCE_HIDDEN (1ULL << 39)
/* Prohibit BGP from enabling IPv6 RA on interfaces */
#define BGP_FLAG_IPV6_NO_AUTO_RA (1ULL << 40)
/* BGP default address-families. /* BGP default address-families.
* New peers inherit enabled afi/safis from bgp instance. * New peers inherit enabled afi/safis from bgp instance.
@ -547,6 +569,9 @@ struct bgp {
*/ */
enum zebra_gr_mode present_zebra_gr_state; enum zebra_gr_mode present_zebra_gr_state;
/* Is deferred path selection still not complete? */
bool gr_route_sync_pending;
/* BGP Per AF flags */ /* BGP Per AF flags */
uint16_t af_flags[AFI_MAX][SAFI_MAX]; uint16_t af_flags[AFI_MAX][SAFI_MAX];
#define BGP_CONFIG_DAMPENING (1 << 0) #define BGP_CONFIG_DAMPENING (1 << 0)
@ -815,11 +840,12 @@ struct bgp {
/* BGP VPN SRv6 backend */ /* BGP VPN SRv6 backend */
bool srv6_enabled; bool srv6_enabled;
char srv6_locator_name[SRV6_LOCNAME_SIZE]; char srv6_locator_name[SRV6_LOCNAME_SIZE];
struct srv6_locator *srv6_locator;
struct list *srv6_locator_chunks; struct list *srv6_locator_chunks;
struct list *srv6_functions; struct list *srv6_functions;
uint32_t tovpn_sid_index; /* unset => set to 0 */ uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid; struct in6_addr *tovpn_sid;
struct srv6_locator_chunk *tovpn_sid_locator; struct srv6_locator *tovpn_sid_locator;
uint32_t tovpn_sid_transpose_label; uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent; struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
@ -1226,7 +1252,7 @@ struct peer {
struct peer_af *peer_af_array[BGP_AF_MAX]; struct peer_af *peer_af_array[BGP_AF_MAX];
/* Peer's remote AS number. */ /* Peer's remote AS number. */
int as_type; enum peer_asn_type as_type;
as_t as; as_t as;
/* for vty as format */ /* for vty as format */
char *as_pretty; char *as_pretty;
@ -1485,6 +1511,7 @@ struct peer {
#define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */ #define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */
#define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */ #define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */
#define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39) #define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39)
#define PEER_FLAG_DUAL_AS (1ULL << 40)
/* /*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
@ -1797,6 +1824,7 @@ struct peer {
#define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */ #define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */
#define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */ #define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */
#define PEER_DOWN_SUPPRESS_FIB_PENDING 36U /* Suppress fib pending changed */ #define PEER_DOWN_SUPPRESS_FIB_PENDING 36U /* Suppress fib pending changed */
#define PEER_DOWN_PASSWORD_CHANGE 37U /* neighbor password command */
/* /*
* Remember to update peer_down_str in bgp_fsm.c when you add * Remember to update peer_down_str in bgp_fsm.c when you add
* a new value to the last_reset reason * a new value to the last_reset reason
@ -1805,16 +1833,13 @@ struct peer {
struct stream *last_reset_cause; struct stream *last_reset_cause;
/* The kind of route-map Flags.*/ /* The kind of route-map Flags.*/
uint16_t rmap_type; uint8_t rmap_type;
#define PEER_RMAP_TYPE_IN (1U << 0) /* neighbor route-map in */ #define PEER_RMAP_TYPE_IN (1U << 0) /* neighbor route-map in */
#define PEER_RMAP_TYPE_OUT (1U << 1) /* neighbor route-map out */ #define PEER_RMAP_TYPE_OUT (1U << 1) /* neighbor route-map out */
#define PEER_RMAP_TYPE_NETWORK (1U << 2) /* network route-map */ #define PEER_RMAP_TYPE_NETWORK (1U << 2) /* network route-map */
#define PEER_RMAP_TYPE_REDISTRIBUTE (1U << 3) /* redistribute route-map */ #define PEER_RMAP_TYPE_REDISTRIBUTE (1U << 3) /* redistribute route-map */
#define PEER_RMAP_TYPE_DEFAULT (1U << 4) /* default-originate route-map */ #define PEER_RMAP_TYPE_DEFAULT (1U << 4) /* default-originate route-map */
#define PEER_RMAP_TYPE_NOSET (1U << 5) /* not allow to set commands */ #define PEER_RMAP_TYPE_AGGREGATE (1U << 5) /* aggregate-address route-map */
#define PEER_RMAP_TYPE_IMPORT (1U << 6) /* neighbor route-map import */
#define PEER_RMAP_TYPE_EXPORT (1U << 7) /* neighbor route-map export */
#define PEER_RMAP_TYPE_AGGREGATE (1U << 8) /* aggregate-address route-map */
/** Peer overwrite configuration. */ /** Peer overwrite configuration. */
struct bfd_session_config { struct bfd_session_config {
@ -2132,6 +2157,7 @@ enum bgp_clear_type {
enum bgp_create_error_code { enum bgp_create_error_code {
BGP_SUCCESS = 0, BGP_SUCCESS = 0,
BGP_CREATED = 1, BGP_CREATED = 1,
BGP_INSTANCE_EXISTS = 2,
BGP_ERR_INVALID_VALUE = -1, BGP_ERR_INVALID_VALUE = -1,
BGP_ERR_INVALID_FLAG = -2, BGP_ERR_INVALID_FLAG = -2,
BGP_ERR_INVALID_AS = -3, BGP_ERR_INVALID_AS = -3,
@ -2261,8 +2287,9 @@ extern bool peer_afc_advertised(struct peer *peer);
extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp);
extern struct peer *peer_create(union sockunion *su, const char *conf_if, extern struct peer *peer_create(union sockunion *su, const char *conf_if,
struct bgp *bgp, as_t local_as, as_t remote_as, struct bgp *bgp, as_t local_as, as_t remote_as,
int as_type, struct peer_group *group, enum peer_asn_type as_type,
bool config_node, const char *as_str); struct peer_group *group, bool config_node,
const char *as_str);
extern struct peer *peer_create_accept(struct bgp *); extern struct peer *peer_create_accept(struct bgp *);
extern void peer_xfer_config(struct peer *dst, struct peer *src); extern void peer_xfer_config(struct peer *dst, struct peer *src);
extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
@ -2335,13 +2362,13 @@ extern void bgp_listen_limit_unset(struct bgp *bgp);
extern bool bgp_update_delay_active(struct bgp *); extern bool bgp_update_delay_active(struct bgp *);
extern bool bgp_update_delay_configured(struct bgp *); extern bool bgp_update_delay_configured(struct bgp *);
extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi);
extern void peer_as_change(struct peer *peer, as_t as, int as_type, extern void peer_as_change(struct peer *peer, as_t as,
const char *as_str); enum peer_asn_type as_type, const char *as_str);
extern int peer_remote_as(struct bgp *bgp, union sockunion *su, extern int peer_remote_as(struct bgp *bgp, union sockunion *su,
const char *conf_if, as_t *as, int as_type, const char *conf_if, as_t *as,
const char *as_str); enum peer_asn_type as_type, const char *as_str);
extern int peer_group_remote_as(struct bgp *bgp, const char *peer_str, as_t *as, extern int peer_group_remote_as(struct bgp *bgp, const char *peer_str, as_t *as,
int as_type, const char *as_str); enum peer_asn_type as_type, const char *as_str);
extern int peer_delete(struct peer *peer); extern int peer_delete(struct peer *peer);
extern void peer_notify_unconfig(struct peer *peer); extern void peer_notify_unconfig(struct peer *peer);
extern int peer_group_delete(struct peer_group *); extern int peer_group_delete(struct peer_group *);
@ -2422,7 +2449,7 @@ extern int peer_allowas_in_set(struct peer *, afi_t, safi_t, int, int);
extern int peer_allowas_in_unset(struct peer *, afi_t, safi_t); extern int peer_allowas_in_unset(struct peer *, afi_t, safi_t);
extern int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, extern int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
bool replace_as, const char *as_str); bool replace_as, bool dual_as, const char *as_str);
extern int peer_local_as_unset(struct peer *); extern int peer_local_as_unset(struct peer *);
extern int peer_prefix_list_set(struct peer *, afi_t, safi_t, int, extern int peer_prefix_list_set(struct peer *, afi_t, safi_t, int,
@ -2742,12 +2769,67 @@ static inline bool bgp_in_graceful_shutdown(struct bgp *bgp)
!!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)); !!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN));
} }
static inline bool bgp_in_graceful_restart(void)
{
/* True if BGP has (re)started gracefully (based on flags
* noted at startup) and GR is not complete.
*/
return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) &&
!CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE));
}
static inline bool bgp_is_graceful_restart_complete(void)
{
/* True if BGP has (re)started gracefully (based on flags
* noted at startup) and GR is marked as complete.
*/
return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) &&
CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE));
}
static inline void bgp_update_gr_completion(void)
{
struct listnode *node, *nnode;
struct bgp *bgp;
/*
* Check and mark GR complete. This is done when deferred
* path selection has been completed for all instances and
* route-advertisement/EOR and route-sync with zebra has
* been invoked.
*/
if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) ||
CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE))
return;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
if (bgp->gr_route_sync_pending)
return;
}
SET_FLAG(bm->flags, BM_FLAG_GR_COMPLETE);
bm->gr_completion_time = monotime(NULL);
}
static inline bool bgp_gr_is_forwarding_preserved(struct bgp *bgp)
{
/*
* Is forwarding state preserved? Based either on config
* or if BGP restarted gracefully.
* TBD: Additional AFI/SAFI based checks etc.
*/
return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) ||
CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD));
}
/* For benefit of rfapi */ /* For benefit of rfapi */
extern struct peer *peer_new(struct bgp *bgp); extern struct peer *peer_new(struct bgp *bgp);
extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
const char *ip_str, bool use_json); const char *ip_str, bool use_json);
extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
const char *as_pretty,
enum asnotation_mode asnotation,
const char *name, const char *name,
enum bgp_instance_type inst_type); enum bgp_instance_type inst_type);
@ -2781,10 +2863,25 @@ extern bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf,
extern void srv6_function_free(struct bgp_srv6_function *func); extern void srv6_function_free(struct bgp_srv6_function *func);
extern void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode);
#ifdef _FRR_ATTRIBUTE_PRINTFRR #ifdef _FRR_ATTRIBUTE_PRINTFRR
/* clang-format off */ /* clang-format off */
#pragma FRR printfrr_ext "%pBP" (struct peer *) #pragma FRR printfrr_ext "%pBP" (struct peer *)
/* clang-format on */ /* clang-format on */
#endif #endif
/* Macro to check if default bgp instance is hidden */
#define IS_BGP_INSTANCE_HIDDEN(_bgp) \
(CHECK_FLAG(_bgp->flags, BGP_FLAG_INSTANCE_HIDDEN) && \
(_bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT || \
_bgp->inst_type == BGP_INSTANCE_TYPE_VRF))
/* Macro to check if bgp instance delete in-progress and !hidden */
#define BGP_INSTANCE_HIDDEN_DELETE_IN_PROGRESS(_bgp, _afi, _safi) \
(CHECK_FLAG(_bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) && \
!IS_BGP_INSTANCE_HIDDEN(_bgp) && \
!(_afi == AFI_IP && _safi == SAFI_MPLS_VPN) && \
!(_afi == AFI_IP6 && _safi == SAFI_MPLS_VPN))
#endif /* _QUAGGA_BGPD_H */ #endif /* _QUAGGA_BGPD_H */

View file

@ -388,7 +388,7 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn,
bgp_withdraw(bpi->peer, p, 0, /* addpath_id */ bgp_withdraw(bpi->peer, p, 0, /* addpath_id */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, 0, NULL); /* tag not used for unicast */ NULL, 0); /* tag not used for unicast */
} }
static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi) static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi)
@ -473,16 +473,14 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi)
if (ri->type == ZEBRA_ROUTE_VNC_DIRECT if (ri->type == ZEBRA_ROUTE_VNC_DIRECT
&& ri->sub_type == BGP_ROUTE_REDISTRIBUTE) { && ri->sub_type == BGP_ROUTE_REDISTRIBUTE) {
bgp_withdraw(ri->peer, bgp_dest_get_prefix(dest),
bgp_withdraw(
ri->peer, bgp_dest_get_prefix(dest),
0, /* addpath_id */ 0, /* addpath_id */
AFI_IP, SAFI_UNICAST, AFI_IP, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */ NULL, /* RD not used for unicast */
NULL, 0, NULL,
NULL); /* tag not used for unicast */ 0); /* tag not used for unicast */
} }
} }
} }
@ -864,8 +862,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */ NULL, /* RD not used for unicast */
NULL, 0, NULL, 0); /* tag not used for unicast */
NULL); /* tag not used for unicast */
/* /*
* yuck! * yuck!
* - but consistent with rest of function * - but consistent with rest of function
@ -893,8 +890,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */ NULL, /* RD not used for unicast */
NULL, 0, NULL, 0); /* tag not used for unicast */
NULL); /* tag not used for unicast */
} }
} }
} }
@ -1131,7 +1127,7 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
BGP_ROUTE_REDISTRIBUTE, BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for NULL, /* RD not used for
unicast */ unicast */
NULL, 0, NULL); /* tag not NULL, 0); /* tag not
used for used for
unicast */ unicast */
} }
@ -1359,7 +1355,7 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
0, /* addpath_id */ 0, /* addpath_id */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, 0, NULL); /* tag not used for unicast */ NULL, 0); /* tag not used for unicast */
return; return;
} }
@ -1471,7 +1467,6 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt,
for (ALL_LIST_ELEMENTS_RO(nve_list, hln, for (ALL_LIST_ELEMENTS_RO(nve_list, hln,
irfd)) { irfd)) {
bgp_withdraw(irfd->peer, bgp_withdraw(irfd->peer,
agg_node_get_prefix(rn), agg_node_get_prefix(rn),
0, /* addpath_id */ 0, /* addpath_id */
@ -1480,7 +1475,7 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt,
BGP_ROUTE_REDISTRIBUTE, BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for NULL, /* RD not used for
unicast */ unicast */
NULL, 0, NULL); /* tag not NULL, 0); /* tag not
used for used for
unicast, unicast,
EVPN EVPN
@ -1715,8 +1710,7 @@ static void vncExportWithdrawTimer(struct event *t)
bgp_withdraw(eti->peer, p, 0, /* addpath_id */ bgp_withdraw(eti->peer, p, 0, /* addpath_id */
family2afi(p->family), SAFI_UNICAST, eti->type, family2afi(p->family), SAFI_UNICAST, eti->type,
eti->subtype, NULL, /* RD not used for unicast */ eti->subtype, NULL, /* RD not used for unicast */
NULL, 0, NULL, 0); /* tag not used for unicast, EVPN neither */
NULL); /* tag not used for unicast, EVPN neither */
/* /*
* Free the eti * Free the eti
@ -2001,7 +1995,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
ZEBRA_ROUTE_VNC_DIRECT_RH, ZEBRA_ROUTE_VNC_DIRECT_RH,
BGP_ROUTE_REDISTRIBUTE, BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */ NULL, /* RD not used for unicast */
NULL, 0, NULL); /* tag not used for NULL, 0); /* tag not used for
unicast, EVPN unicast, EVPN
neither */ neither */
} }

View file

@ -7,7 +7,7 @@
## ##
AC_PREREQ([2.69]) AC_PREREQ([2.69])
AC_INIT([frr], [10.1.1], [https://github.com/frrouting/frr/issues]) AC_INIT([frr], [10.2], [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/" PACKAGE_URL="https://frrouting.org/"
AC_SUBST([PACKAGE_URL]) AC_SUBST([PACKAGE_URL])
PACKAGE_FULLNAME="FRRouting" PACKAGE_FULLNAME="FRRouting"
@ -847,9 +847,12 @@ AC_ARG_WITH([crypto],
AC_ARG_WITH([frr-format], AC_ARG_WITH([frr-format],
AS_HELP_STRING([--with-frr-format[=<.../frr-format.so>]], [use frr-format GCC plugin])) AS_HELP_STRING([--with-frr-format[=<.../frr-format.so>]], [use frr-format GCC plugin]))
AC_ARG_ENABLE([version-build-config], AC_ARG_ENABLE([version_build_config],
AS_HELP_STRING([--disable-version-build-config], [do not include build configs in show version command])) AS_HELP_STRING([--disable-version-build-config], [do not include build configs in show version command]))
AC_ARG_ENABLE([python_runtime],
AS_HELP_STRING([--disable-python-runtime], [do not install python scripts or have python runtime dependency]))
#if openssl, else use the internal #if openssl, else use the internal
AS_IF([test "$with_crypto" = "openssl"], [ AS_IF([test "$with_crypto" = "openssl"], [
AC_CHECK_LIB([crypto], [EVP_DigestInit], [LIBS="$LIBS -lcrypto"], [], []) AC_CHECK_LIB([crypto], [EVP_DigestInit], [LIBS="$LIBS -lcrypto"], [], [])
@ -2811,6 +2814,9 @@ AM_CONDITIONAL([PATHD], [test "$enable_pathd" != "no"])
AM_CONDITIONAL([PATHD_PCEP], [test "$enable_pathd" != "no"]) AM_CONDITIONAL([PATHD_PCEP], [test "$enable_pathd" != "no"])
AM_CONDITIONAL([DP_DPDK], [test "$enable_dp_dpdk" = "yes"]) AM_CONDITIONAL([DP_DPDK], [test "$enable_dp_dpdk" = "yes"])
AM_CONDITIONAL([PYTHON_RUNTIME_DEPENDENCY], [test "$enable_python_runtime" != "no"])
AC_CONFIG_FILES([Makefile],[ AC_CONFIG_FILES([Makefile],[
test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build" test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build"
${PYTHON} "${ac_abs_top_srcdir}/python/makefile.py" ${makefile_devbuild} || exit 1 ${PYTHON} "${ac_abs_top_srcdir}/python/makefile.py" ${makefile_devbuild} || exit 1
@ -2913,7 +2919,8 @@ compiler : ${CC}
compiler flags : ${CFLAGS} ${WERROR} ${AC_CFLAGS} ${SAN_FLAGS} compiler flags : ${CFLAGS} ${WERROR} ${AC_CFLAGS} ${SAN_FLAGS}
make : ${MAKE-make} make : ${MAKE-make}
linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM}
state file directory : ${e_frr_runstatedir} local state file dir : ${e_frr_libstatedir}
run state file dir : ${e_frr_runstatedir}
config file directory : ${e_frr_sysconfdir} config file directory : ${e_frr_sysconfdir}
module directory : ${e_moduledir} module directory : ${e_moduledir}
script directory : ${e_scriptdir} script directory : ${e_scriptdir}

View file

@ -9,3 +9,4 @@ BGPD
next-hop-tracking next-hop-tracking
bgp-typecodes bgp-typecodes
bmp

View file

@ -18,6 +18,7 @@ import re
import pygments import pygments
from sphinx.highlighting import lexers from sphinx.highlighting import lexers
from sphinx.util import logging from sphinx.util import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
@ -53,18 +54,26 @@ source_suffix = ".rst"
master_doc = "index" master_doc = "index"
# General information about the project. # General information about the project.
project = u"FRR" project = "FRR"
copyright = u"2017, FRR" copyright = "2017, FRR"
author = u"FRR authors" author = "FRR authors"
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
# built documents. # built documents.
# The short X.Y version. # The short X.Y version.
version = u"?.?" version = "?.?"
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = u"?.?-?" release = "?.?-?"
# Set canonical URL from the Read the Docs Domain
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
# Tell Jinja2 templates the build is running on Read the Docs
html_context = {}
if os.environ.get("READTHEDOCS", "") == "True":
html_context["READTHEDOCS"] = True
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -95,7 +104,7 @@ replace_vars = {
# extract version information, installation location, other stuff we need to # extract version information, installation location, other stuff we need to
# use when building final documents # use when building final documents
val = re.compile('^S\["([^"]+)"\]="(.*)"$') val = re.compile(r'^S\["([^"]+)"\]="(.*)"$')
try: try:
with open("../../config.status", "r") as cfgstatus: with open("../../config.status", "r") as cfgstatus:
for ln in cfgstatus.readlines(): for ln in cfgstatus.readlines():
@ -287,7 +296,7 @@ latex_elements = {
# (source start file, target name, title, # (source start file, target name, title,
# author, documentclass [howto, manual, or own class]). # author, documentclass [howto, manual, or own class]).
latex_documents = [ latex_documents = [
(master_doc, "FRR.tex", u"FRR Developer's Manual", u"FRR", "manual"), (master_doc, "FRR.tex", "FRR Developer's Manual", "FRR", "manual"),
] ]
# The name of an image file (relative to this directory) to place at the top of # The name of an image file (relative to this directory) to place at the top of
@ -315,7 +324,7 @@ latex_logo = "../figures/frr-logo-medium.png"
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [(master_doc, "frr", u"FRR Developer's Manual", [author], 1)] man_pages = [(master_doc, "frr", "FRR Developer's Manual", [author], 1)]
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
# man_show_urls = False # man_show_urls = False
@ -330,7 +339,7 @@ texinfo_documents = [
( (
master_doc, master_doc,
"frr", "frr",
u"FRR Developer's Manual", "FRR Developer's Manual",
author, author,
"FRR", "FRR",
"One line description of project.", "One line description of project.",
@ -358,27 +367,29 @@ texinfo_documents = [
with open("../extra/frrlexer.py", "rb") as lex: with open("../extra/frrlexer.py", "rb") as lex:
frrlexerpy = lex.read() frrlexerpy = lex.read()
frrfmt_re = re.compile(r'^\s*%(?P<spec>[^\s]+)\s+\((?P<types>.*)\)\s*$') frrfmt_re = re.compile(r"^\s*%(?P<spec>[^\s]+)\s+\((?P<types>.*)\)\s*$")
def parse_frrfmt(env, text, node): def parse_frrfmt(env, text, node):
from sphinx import addnodes from sphinx import addnodes
m = frrfmt_re.match(text) m = frrfmt_re.match(text)
if not m: if not m:
logger.warning('could not parse frrfmt:: %r' % (text), location=node) logger.warning("could not parse frrfmt:: %r" % (text), location=node)
node += addnodes.desc_name(text, text) node += addnodes.desc_name(text, text)
return text return text
spec, types = m.group('spec'), m.group('types') spec, types = m.group("spec"), m.group("types")
node += addnodes.desc_sig_operator('%', '%') node += addnodes.desc_sig_operator("%", "%")
node += addnodes.desc_name(spec + ' ', spec + ' ') node += addnodes.desc_name(spec + " ", spec + " ")
plist = addnodes.desc_parameterlist() plist = addnodes.desc_parameterlist()
for typ in types.split(','): for typ in types.split(","):
typ = typ.strip() typ = typ.strip()
plist += addnodes.desc_parameter(typ, typ) plist += addnodes.desc_parameter(typ, typ)
node += plist node += plist
return '%' + spec return "%" + spec
# custom extensions here # custom extensions here
def setup(app): def setup(app):

View file

@ -147,7 +147,7 @@ Front-End Interface:
- change route_map_init() to route_map_init_new(false) and remove from - change route_map_init() to route_map_init_new(false) and remove from
VTYSH_ROUTE_MAP_CONFIG (leave in VTYSH_ROUTE_MAP_SHOW). VTYSH_ROUTE_MAP_CONFIG (leave in VTYSH_ROUTE_MAP_SHOW).
- remove vrf_cmd_init(NULL) => remove from VTYSH_INTERFACE_SUBSET - remove vrf_cmd_init(NULL) => remove from VTYSH_INTERFACE_SUBSET
...
Back-End Interface: Back-End Interface:

View file

@ -87,7 +87,7 @@ Generate skeleton instance data:
* XML: * XML:
.. code:: sh .. code:: sh
$ pyang -p <yang-search-path> \ $ pyang -p <yang-search-path> \
-f sample-xml-skeleton --sample-xml-skeleton-defaults \ -f sample-xml-skeleton --sample-xml-skeleton-defaults \
@ -95,7 +95,7 @@ Generate skeleton instance data:
* JSON: * JSON:
.. code:: sh .. code:: sh
$ pyang -p <yang-search-path> \ $ pyang -p <yang-search-path> \
-f jsonxsl module.yang -o module.xsl -f jsonxsl module.yang -o module.xsl

View file

@ -0,0 +1,69 @@
OSPF Neighor Retransmission List
================================
Overview
--------
OSPF neighbor link-state retransmission lists are implemented using
both a sparse Link State Database (LSDB) and a doubly-linked list.
Rather than previous per-neighbor periodic timer, a per-neighbor
timer is set to the expiration time of the next scheduled LSA
retransmission.
Sparse Link State Database (LSDB)
---------------------------------
When an explicit or implied acknowledgment is recieved from a
neighbor in 2-way state or higher, the acknowledge LSA must be
removed from the neighbor's link state retransmission list. In order
to do this efficiently, a sparse LSDB is utilized. LSDB entries also
include a pointer to the corresponding list entry so that it may be
efficiently removed from the doubly-linked list.
The sparse LSDB is implemented using the OSPF functions is
ospf_lsdb.[c,h]. OSPF LSDBs are implemented as an array of route
tables (lib/table.[c,h]). What is unique of the LS Retransmission
list LSDB is that each entry also has a pointer into the doubly-linked
list to facilitate fast deletions.
Doubly-Linked List
------------------
In addition to the sparse LSDB, LSAs on a neighbor LS retransmission
list are also maintained in a linked-list order chronologically
with the LSA scheduled for the next retransmission at the head of
the list.
The doubly-link list is implemented using the dlist macros in
lib/typesafe.h.
LSA LS Retransmission List Addition
------------------------------------
When an LSA is added to a neighbor retransmission list, it is
added to both the sparse LSDB and the doubly-linked list with a pointer
in the LSDB route-table node to the list entry. The LSA is added to
the tail of the list with the expiration time set to the current time
with the retransmission interval added. If the neighbor retransmission
timer is not set, it is set to expire at the time of the newly added
LSA.
LSA LS Retransmission List Deletion
-----------------------------------
When an LSA is deleted from a neighbor retransmission list, it is
deleted from eboth the sparse LSDB and the doubly-linked list with the
pointer the LSDB route-table node used to efficiently delete the entry
from the list. If the LSA at the head of the list was removed, then
the neighbor retransmission timer is reset to the expiration of the
LSA at the head of the list or canceled if the list is empty.
Neighbor LS Retransmission List Expiration
------------------------------------------
When the neighbor retransmission timer expires, the LSA at the top of
list and any in a configured window (e.g., 50 milliseconds) are
retransmitted. The LSAs that have been retransmitted are removed from
the list and readded to the tail of the list with a new expiration time
which is retransmit-interval seconds in the future.

View file

@ -8,6 +8,7 @@ OSPFD
:maxdepth: 2 :maxdepth: 2
ospf-api ospf-api
ospf-ls-retrans
ospf-sr ospf-sr
cspf cspf

View file

@ -68,6 +68,8 @@ buster.)
+----------------+-------------------+-----------------------------------------+ +----------------+-------------------+-----------------------------------------+
| pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (default enabled) | | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (default enabled) |
+----------------+-------------------+-----------------------------------------+ +----------------+-------------------+-----------------------------------------+
| pkg.frr.grpc | pkg.frr.nogrpc | builds with grpc support (default: no) |
+----------------+-------------------+-----------------------------------------+
* the ``-uc -us`` options to disable signing the packages with your GPG key * the ``-uc -us`` options to disable signing the packages with your GPG key

View file

@ -67,24 +67,27 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24.
############### FRRouting (FRR) configure options ################# ############### FRRouting (FRR) configure options #################
# with-feature options # with-feature options
%{!?with_pam: %global with_pam 0 } %{!?with_babeld: %global with_babeld 1 }
%{!?with_ospfclient: %global with_ospfclient 1 } %{!?with_bfdd: %global with_bfdd 1 }
%{!?with_ospfapi: %global with_ospfapi 1 }
%{!?with_irdp: %global with_irdp 1 }
%{!?with_rtadv: %global with_rtadv 1 }
%{!?with_ldpd: %global with_ldpd 1 }
%{!?with_nhrpd: %global with_nhrpd 1 }
%{!?with_eigrp: %global with_eigrpd 1 }
%{!?with_shared: %global with_shared 1 }
%{!?with_multipath: %global with_multipath 256 }
%{!?frr_user: %global frr_user frr }
%{!?vty_group: %global vty_group frrvty }
%{!?with_fpm: %global with_fpm 0 }
%{!?with_watchfrr: %global with_watchfrr 1 }
%{!?with_bgp_vnc: %global with_bgp_vnc 0 } %{!?with_bgp_vnc: %global with_bgp_vnc 0 }
%{!?with_cumulus: %global with_cumulus 0 }
%{!?with_eigrpd: %global with_eigrpd 1 }
%{!?with_fpm: %global with_fpm 1 }
%{!?with_mgmtd_test_be_client: %global with_mgmtd_test_be_client 0 }
%{!?with_ldpd: %global with_ldpd 1 }
%{!?with_multipath: %global with_multipath 256 }
%{!?with_nhrpd: %global with_nhrpd 1 }
%{!?with_ospfapi: %global with_ospfapi 1 }
%{!?with_ospfclient: %global with_ospfclient 1 }
%{!?with_pam: %global with_pam 0 }
%{!?with_pbrd: %global with_pbrd 1 }
%{!?with_pimd: %global with_pimd 1 } %{!?with_pimd: %global with_pimd 1 }
%{!?with_pim6d: %global with_pim6d 1 } %{!?with_pim6d: %global with_pim6d 1 }
%{!?with_rpki: %global with_rpki 0 } %{!?with_vrrpd: %global with_vrrpd 1 }
%{!?with_rtadv: %global with_rtadv 1 }
%{!?with_watchfrr: %global with_watchfrr 1 }
%{!?with_pathd: %global with_pathd 1 }
%{!?with_grpc: %global with_grpc 0 }
8. Build the RPM:: 8. Build the RPM::

View file

@ -523,6 +523,7 @@ object which contains methods corresponding to each of the ``zlog`` levels:
log.error("error") log.error("error")
log.notice("notice") log.notice("notice")
log.debug("debug") log.debug("debug")
log.trace("trace")
The log messages will show up in the daemon's log output. The log messages will show up in the daemon's log output.

View file

@ -33,10 +33,11 @@ Installing Topotest Requirements
net-tools \ net-tools \
python3-pip \ python3-pip \
iputils-ping \ iputils-ping \
iptables \
tshark \ tshark \
valgrind valgrind
python3 -m pip install wheel python3 -m pip install wheel
python3 -m pip install 'pytest>=6.2.4' 'pytest-xdist>=2.3.0' python3 -m pip install 'pytest>=8.3.2' 'pytest-asyncio>=0.24.0' 'pytest-xdist>=3.6.1'
python3 -m pip install 'scapy>=2.4.5' python3 -m pip install 'scapy>=2.4.5'
python3 -m pip install xmltodict python3 -m pip install xmltodict
python3 -m pip install git+https://github.com/Exa-Networks/exabgp@0659057837cd6c6351579e9f0fa47e9fb7de7311 python3 -m pip install git+https://github.com/Exa-Networks/exabgp@0659057837cd6c6351579e9f0fa47e9fb7de7311
@ -411,6 +412,14 @@ for ``master`` branch:
and create ``frr`` user and ``frrvty`` group as shown above. and create ``frr`` user and ``frrvty`` group as shown above.
Newer versions of Address Sanitizers require a sysctl to be changed
to allow for the tests to be successfully run. This is also true
for Undefined behavior Sanitizers as well as Memory Sanitizer.
.. code:: shell
sysctl vm.mmap_rnd_bits=28
Debugging Topotest Failures Debugging Topotest Failures
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -722,8 +731,8 @@ packages.
Code coverage can automatically be gathered for any topotest run. To support Code coverage can automatically be gathered for any topotest run. To support
this FRR must first be compiled with the ``--enable-gcov`` configure option. this FRR must first be compiled with the ``--enable-gcov`` configure option.
This will cause *.gnco files to be created during the build. When topotests are This will cause \*.gnco files to be created during the build. When topotests are
run the statistics are generated and stored in *.gcda files. Topotest run the statistics are generated and stored in \*.gcda files. Topotest
infrastructure will gather these files, capture the information into a infrastructure will gather these files, capture the information into a
``coverage.info`` ``lcov`` file and also report the coverage summary. ``coverage.info`` ``lcov`` file and also report the coverage summary.
@ -732,7 +741,7 @@ If you build your FRR in a directory outside of the FRR source directory you
will also need to pass the ``--cov-frr-build-dir`` argument specifying the build will also need to pass the ``--cov-frr-build-dir`` argument specifying the build
directory location. directory location.
During the topotest run the *.gcda files are generated into a ``gcda`` During the topotest run the \*.gcda files are generated into a ``gcda``
sub-directory of the top-level run directory (i.e., normally sub-directory of the top-level run directory (i.e., normally
``/tmp/topotests/gcda``). These files will then be copied at the end of the ``/tmp/topotests/gcda``). These files will then be copied at the end of the
topotest run into the FRR build directory where the ``gcov`` and ``lcov`` topotest run into the FRR build directory where the ``gcov`` and ``lcov``
@ -747,9 +756,49 @@ The ``coverage.info`` file can then be used to generate coverage reports or file
markup (e.g., using the ``genhtml`` utility) or enable markup within your markup (e.g., using the ``genhtml`` utility) or enable markup within your
IDE/editor if supported (e.g., the emacs ``cov-mode`` package) IDE/editor if supported (e.g., the emacs ``cov-mode`` package)
NOTE: the *.gcda files in ``/tmp/topotests/gcda`` are cumulative so if you do NOTE: the \*.gcda files in ``/tmp/topotests/gcda`` are cumulative so if you do
not remove them they will aggregate data across multiple topotest runs. not remove them they will aggregate data across multiple topotest runs.
How to reproduce failed Tests
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Generally tests fail but recreating the test failure reliably is not necessarily
easy, or it happens once every 10 runs locally. Here are some generic strategies
that are employed to allow for the test to be reproduced reliably
.. code:: console
cd <test directory>
ln -s test_the_test_name.py test_a.py
ln -s test_the_test_name.py test_b.py
This allows you to run multiple copies of the same test with one full test run.
Additionally if you need to modify the test you don't need to recopy everything
to make it work. By adding multiple copies of the same occassionally failing test
you raise the odds of it failing again. Additionally you have easily accessible
good and bad runs to compare.
.. code:: console
sudo -E python3 -m pytest -n <some value> --dist=loadfile
Choose a n value that is greater than the number of cpu's avalaible on the system.
This changes the timing and may or may not make it more likely that the test fails.
Be aware, though, that this changes memory requirements as well as may make other
tests fail more often as well. You should choose values that do not cause the system
to go into swap usage.
.. code:: console
stress -n <number of cpu's to put at 100%>
By filling up cpu's with programs that do nothing you also change the timing again and
may cause the problem to happen more often.
There is no magic bullet here. You as a developer might have to experiment with different
values and different combinations of the above to cause the problem to happen more often.
These are just the tools that we know of at this point in time.
.. _topotests_docker: .. _topotests_docker:
@ -1292,6 +1341,15 @@ Example:
router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
router.load_config(TopoRouter.RD_OSPF) router.load_config(TopoRouter.RD_OSPF)
or using unified config (specifying which daemons to run is optional):
.. code:: py
for _, (rname, router) in enumerate(router_list.items(), 1):
router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)), [
(TopoRouter.RD_ZEBRA, "-s 90000000"),
(TopoRouter.RD_MGMTD, None),
(TopoRouter.RD_BGP, None)]
- The topology definition or build function - The topology definition or build function

View file

@ -6,9 +6,10 @@ Process & Workflow
.. highlight:: none .. highlight:: none
FRR is a large project developed by many different groups. This section FRR is a large project developed by many different groups. This
documents standards for code style & quality, commit messages, pull requests section documents standards for code style & quality, commit messages,
and best practices that all contributors are asked to follow. pull requests (PRs) and best practices that all contributors are asked
to follow.
This chapter is "descriptive/post-factual" in that it documents pratices that This chapter is "descriptive/post-factual" in that it documents pratices that
are in use; it is not "definitive/pre-factual" in prescribing practices. This are in use; it is not "definitive/pre-factual" in prescribing practices. This
@ -241,7 +242,7 @@ discontinued.
The LTS branch duties are the following ones: The LTS branch duties are the following ones:
- organise meetings on a (bi-)weekly or monthly basis, the handling of issues - organise meetings on a (bi-)weekly or monthly basis, the handling of issues
and pull requested relative to that branch. When time permits, this may be done and pull requests relative to that branch. When time permits, this may be done
during the regularly scheduled FRR meeting. during the regularly scheduled FRR meeting.
- ensure the stability of the branch, by using and eventually adapting the - ensure the stability of the branch, by using and eventually adapting the
@ -324,11 +325,17 @@ relevant to your work.
Submitting Patches and Enhancements Submitting Patches and Enhancements
=================================== ===================================
FRR accepts patches using GitHub pull requests. FRR accepts patches using GitHub pull requests (PRs). The typical FRR
developer will maintain a fork of the FRR project in GitHub; see the
GitHub documentation for help setting up an account and creating a
fork repository. Keep the ``master`` branch of your fork up-to-date
with the FRR version. Create a dev branch in your fork and commit your
work there. When ready, create a pull-request between your dev branch
in your fork and the main FRR repository in GitHub.
The base branch for new contributions and non-critical bug fixes should be The base branch for new contributions and non-critical bug fixes
``master``. Please ensure your pull request is based on this branch when you should be ``master``. Please ensure your pull request targets this
submit it. branch when you submit it.
Code submitted by pull request will be automatically tested by one or more CI Code submitted by pull request will be automatically tested by one or more CI
systems. Once the automated tests succeed, other developers will review your systems. Once the automated tests succeed, other developers will review your
@ -531,6 +538,42 @@ After Submitting Your Changes
community members. community members.
- Your submission is done once it is merged to the master branch. - Your submission is done once it is merged to the master branch.
Reverting the changes
=====================
When you revert a regular commit in Git, the process is straightforward - it
undoes the changes introduced by that commit. However, reverting a merge commit
is more complex. While it undoes the data changes brought in by the merge, it
does not alter the repository's history or the merge's effect on it.
Reverting a Merge Commit
------------------------
When you revert a merge commit, the following occurs:
* The changes made by the merge are undone;
* The merge itself remains in the history: it continues to be recognized as the point where two branches were joined;
* Future merges will still treat this as the last shared state, regardless of the revert.
Thus, a "revert" in Git undoes data changes, but it does not serve as a true "undo"
for the historical effects of a commit.
Reverting a Merge and Bisectability
-----------------------------------
Consider the implications of reverting a merge and then reverting that revert.
This scenario complicates the debugging process, especially when using tools like
git bisect. A reverted merge effectively consolidates all changes from the original
merge into a single commit, but in reverse. This creates a challenge for debugging,
as you lose the granularity of individual commits, making it difficult to identify
the specific change causing an issue.
Considerations
--------------
When reverting the changes, e.g. a full Pull Request, we SHOULD revert every commit
individually, and not use git revert on merge commits.
Programming Languages, Tools and Libraries Programming Languages, Tools and Libraries
========================================== ==========================================
@ -1306,6 +1349,16 @@ MemorySanitizer
to ``configure``. to ``configure``.
UndefinedSanitizer
Similar to AddressSanitizer, this tool provides runtime instrumentation for
detecting use of undefined behavior in C. Testing your own code with this
tool before submission is encouraged. You can enable it by passing::
--enable-undefined-sanitizer
to ``configure``. If you run FRR with this you will probably also have
to set ``sudo sysctl vm.mmap_rnd_bits=28``
All of the above tools are available in the Clang/LLVM toolchain since 3.4. All of the above tools are available in the Clang/LLVM toolchain since 3.4.
AddressSanitizer and ThreadSanitizer are available in recent versions of GCC, AddressSanitizer and ThreadSanitizer are available in recent versions of GCC,
but are no longer actively maintained. MemorySanitizer is not available in GCC. but are no longer actively maintained. MemorySanitizer is not available in GCC.
@ -1315,6 +1368,14 @@ but are no longer actively maintained. MemorySanitizer is not available in GCC.
The different Sanitizers are mostly incompatible with each other. Please The different Sanitizers are mostly incompatible with each other. Please
refer to GCC/LLVM documentation for details. refer to GCC/LLVM documentation for details.
.. note::
The different sanitizers also require setting
sysctl vm.mmap_rnd_bits=28
in order to work properly.
frr-format plugin frr-format plugin
This is a GCC plugin provided with FRR that does extended type checks for This is a GCC plugin provided with FRR that does extended type checks for
``%pFX``-style printfrr extensions. To use this plugin, ``%pFX``-style printfrr extensions. To use this plugin,

View file

@ -1,10 +1,33 @@
BFD SOCKET BFD
---------- ---
The following option controls the BFD daemon control socket location. The following options controls the BFD daemon auxiliary sockets.
.. option:: --bfdctl bfd-control-socket .. option:: --dplaneaddr <type>:<address>[<:port>]
Opens the BFD daemon control socket located at the pointed location. Configure the distributed BFD data plane listening socket bind address.
(default: |INSTALL_PREFIX_STATE|/bfdd.sock) One would expect the data plane to run in the same machine as FRR, so
the suggested configuration would be:
``--dplaneaddr unix:/var/run/frr/bfdd_dplane.sock``
Or using IPv4:
``--dplaneaddr ipv4:127.0.0.1``
Or using IPv6:
``--dplaneaddr ipv6:[::1]``
It is also possible to specify a port (for IPv4/IPv6 only):
``--dplaneaddr ipv6:[::1]:50701``
(if omitted the default port is ``50700``).
It is also possible to operate in client mode (instead of listening for
connections). To connect to a data plane server append the letter 'c' to
the protocol, example:
``--dplaneaddr ipv4c:127.0.0.1``

View file

@ -91,7 +91,7 @@ replace_vars = {
# extract version information, installation location, other stuff we need to # extract version information, installation location, other stuff we need to
# use when building final documents # use when building final documents
val = re.compile('^S\["([^"]+)"\]="(.*)"$') val = re.compile(r'^S\["([^"]+)"\]="(.*)"$')
try: try:
with open("../../config.status", "r") as cfgstatus: with open("../../config.status", "r") as cfgstatus:
for ln in cfgstatus.readlines(): for ln in cfgstatus.readlines():

View file

@ -1,47 +1,8 @@
.. _overview: .. _overview:
******** *********
Overview
********
`FRR`_ is a fully featured, high performance, free software IP routing suite.
FRR implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and
more (see :ref:`feature-matrix`), as well as many of their extensions.
FRR is a high performance suite written primarily in C. It can easily handle
full Internet routing tables and is suitable for use on hardware ranging from
cheap SBCs to commercial grade routers. It is actively used in production by
hundreds of companies, universities, research labs and governments.
FRR is distributed under GPLv2, with development modeled after the Linux
kernel. Anyone may contribute features, bug fixes, tools, documentation
updates, or anything else.
FRR is a fork of `Quagga <http://www.quagga.net/>`_.
.. _how-to-get-frr:
How to get FRR
==============
The official FRR website is located at |PACKAGE_URL| and contains further
information, as well as links to additional resources.
Several distributions provide packages for FRR. Check your distribution's
repositories to find out if a suitable version is available.
Up-to-date Debian & Redhat packages are available at https://deb.frrouting.org/
& https://rpm.frrouting.org/ respectively.
For instructions on installing from source, refer to the
`developer documentation <http://docs.frrouting.org/projects/dev-guide/en/latest/>`_.
.. _about-frr:
About FRR About FRR
========= *********
FRR provides IP routing services. Its role in a networking stack is to exchange FRR provides IP routing services. Its role in a networking stack is to exchange
routing information with other routers, make routing and policy decisions, and routing information with other routers, make routing and policy decisions, and
@ -55,11 +16,8 @@ light L2 functionality as well, but this is mostly left to the platform. This
makes it suitable for deployments ranging from small home networks with static makes it suitable for deployments ranging from small home networks with static
routes to Internet exchanges running full Internet tables. routes to Internet exchanges running full Internet tables.
FRR runs on all modern \*NIX operating systems, including Linux and the BSDs.
Feature support varies by platform; see the :ref:`feature-matrix`.
System Requirements System Requirements
------------------- ===================
System resources needed by FRR are highly dependent on workload. Routing System resources needed by FRR are highly dependent on workload. Routing
software performance is particularly susceptible to external factors such as: software performance is particularly susceptible to external factors such as:
@ -86,8 +44,8 @@ information with peers about how to forward packets. Forwarding plane
performance largely depends on choice of NIC / ASIC. performance largely depends on choice of NIC / ASIC.
System Architecture Architecture
------------------- ============
.. index:: .. index::
pair: architecture; FRR pair: architecture; FRR
@ -146,9 +104,8 @@ routing stack.
.. _supported-platforms: .. _supported-platforms:
Supported Platforms Platform Support
------------------- ================
Currently FRR supports GNU/Linux and BSD. Porting FRR to other platforms is not Currently FRR supports GNU/Linux and BSD. Porting FRR to other platforms is not
too difficult as platform dependent code should be mostly limited to the too difficult as platform dependent code should be mostly limited to the
@ -366,6 +323,8 @@ BGP
:t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009.` :t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009.`
- :rfc:`5668` - :rfc:`5668`
:t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009.` :t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009.`
- :rfc:`5701`
:t:`IPv6 Address Specific BGP Extended Community Attribute. Y. Rekhter. 2009.`
- :rfc:`6286` - :rfc:`6286`
:t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan. June 2011.` :t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan. June 2011.`
- :rfc:`6472` - :rfc:`6472`

23
doc/user/basics.rst Normal file
View file

@ -0,0 +1,23 @@
.. _basics:
######
Basics
######
.. toctree::
:maxdepth: 2
basic
extlog
vtysh
grpc
filter
routemap
affinitymap
ipv6
kernel
snmp
scripting
nexthop_groups

View file

@ -1,12 +1,19 @@
.. _bfd: .. _bfd:
********************************** ***
Bidirectional Forwarding Detection BFD
********************************** ***
:abbr:`BFD (Bidirectional Forwarding Detection)` stands for :abbr:`BFD (Bidirectional Forwarding Detection)` is:
Bidirectional Forwarding Detection and it is described and extended by
the following RFCs: a protocol intended to detect faults in the bidirectional path between two
forwarding engines, including interfaces, data link(s), and to the extent
possible the forwarding engines themselves, with potentially very low
latency.
-- :rfc:`5880`
It is described and extended by the following RFCs:
* :rfc:`5880` * :rfc:`5880`
* :rfc:`5881` * :rfc:`5881`
@ -38,19 +45,6 @@ may also be specified (:ref:`common-invocation-options`).
.. program:: bfdd .. program:: bfdd
.. option:: --bfdctl <unix-socket>
Set the BFD daemon control socket location. If using a non-default
socket location::
/usr/lib/frr/bfdd --bfdctl /tmp/bfdd.sock
The default UNIX socket location is |INSTALL_PREFIX_STATE|/bfdd.sock
This option overrides the location addition that the -N option provides
to the bfdd.sock
.. option:: --dplaneaddr <type>:<address>[<:port>] .. option:: --dplaneaddr <type>:<address>[<:port>]
Configure the distributed BFD data plane listening socket bind address. Configure the distributed BFD data plane listening socket bind address.
@ -72,7 +66,7 @@ may also be specified (:ref:`common-invocation-options`).
--dplaneaddr ipv6:[::1]:50701 --dplaneaddr ipv6:[::1]:50701
(if ommited the default port is ``50700``). (if omitted the default port is ``50700``).
It is also possible to operate in client mode (instead of listening for It is also possible to operate in client mode (instead of listening for
connections). To connect to a data plane server append the letter 'c' to connections). To connect to a data plane server append the letter 'c' to

Some files were not shown because too many files have changed in this diff Show more