Merging upstream version 10.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
c459d76acf
commit
a2d156806a
1226 changed files with 49733 additions and 17448 deletions
|
@ -55,7 +55,7 @@ BreakConstructorInitializersBeforeComma: false
|
|||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 80
|
||||
ColumnLimit: 100
|
||||
# Linux: CommentPragmas: '^ IWYU pragma:'
|
||||
CommentPragmas: '\$(FRR|clippy)'
|
||||
CompactNamespaces: false
|
||||
|
@ -224,4 +224,8 @@ WhitespaceSensitiveMacros:
|
|||
- "DEFUN_YANG_NOSH"
|
||||
- "DEFUNSH"
|
||||
- "DEFUNSH_HIDDEN"
|
||||
- "ALIAS"
|
||||
- "ALIAS_HIDDEN"
|
||||
- "ALIAS_YANG"
|
||||
- "ALIAS_DEPRECATED"
|
||||
...
|
||||
|
|
|
@ -33,6 +33,8 @@ _libdir=/usr/lib
|
|||
_user=frr
|
||||
|
||||
build() {
|
||||
export ABUILD_APK_INDEX_OPTS="--allow-untrusted"
|
||||
|
||||
cd "$builddir"
|
||||
|
||||
./configure \
|
||||
|
|
|
@ -108,6 +108,7 @@ babel_interface_address_add (ZAPI_CALLBACK_ARGS)
|
|||
if (prefix->family == AF_INET) {
|
||||
flush_interface_routes(ifc->ifp, 0);
|
||||
babel_ifp = babel_get_if_nfo(ifc->ifp);
|
||||
assert (babel_ifp != NULL);
|
||||
if (babel_ifp->ipv4 == NULL) {
|
||||
babel_ifp->ipv4 = malloc(4);
|
||||
if (babel_ifp->ipv4 == NULL) {
|
||||
|
@ -144,6 +145,7 @@ babel_interface_address_delete (ZAPI_CALLBACK_ARGS)
|
|||
if (prefix->family == AF_INET) {
|
||||
flush_interface_routes(ifc->ifp, 0);
|
||||
babel_ifp = babel_get_if_nfo(ifc->ifp);
|
||||
assert (babel_ifp != NULL);
|
||||
if (babel_ifp->ipv4 != NULL
|
||||
&& memcmp(babel_ifp->ipv4, &prefix->u.prefix4, IPV4_MAX_BYTELEN)
|
||||
== 0) {
|
||||
|
@ -542,7 +544,10 @@ DEFPY (babel_set_channel,
|
|||
unsigned
|
||||
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)
|
||||
interval = MIN(interval, 100);
|
||||
else
|
||||
|
@ -553,7 +558,10 @@ jitter(babel_interface_nfo *babel_ifp, int urgent)
|
|||
unsigned
|
||||
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)
|
||||
interval = MIN(interval, 100);
|
||||
else
|
||||
|
@ -566,10 +574,11 @@ update_jitter(babel_interface_nfo *babel_ifp, int urgent)
|
|||
static int
|
||||
interface_recalculate(struct interface *ifp)
|
||||
{
|
||||
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
|
||||
unsigned char *tmp = NULL;
|
||||
int mtu, rc;
|
||||
struct ipv6_mreq mreq;
|
||||
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
|
||||
assert (babel_ifp != NULL);
|
||||
|
||||
if (!IS_ENABLE(ifp))
|
||||
return -1;
|
||||
|
@ -656,6 +665,7 @@ interface_reset(struct interface *ifp)
|
|||
int rc;
|
||||
struct ipv6_mreq mreq;
|
||||
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
|
||||
assert (babel_ifp != NULL);
|
||||
|
||||
if (!CHECK_FLAG(babel_ifp->flags, BABEL_IF_IS_UP))
|
||||
return 0;
|
||||
|
@ -777,6 +787,7 @@ show_babel_interface_sub (struct vty *vty, struct interface *ifp)
|
|||
return;
|
||||
}
|
||||
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, " Operating mode is \"%s\"\n",
|
||||
CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless");
|
||||
|
@ -1160,6 +1171,11 @@ DEFUN (show_babel_parameters,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
void babel_if_terminate(void)
|
||||
{
|
||||
vector_free(babel_enable_if);
|
||||
}
|
||||
|
||||
void
|
||||
babel_if_init(void)
|
||||
{
|
||||
|
@ -1228,6 +1244,7 @@ interface_config_write (struct vty *vty)
|
|||
if (ifp->desc)
|
||||
vty_out (vty, " description %s\n",ifp->desc);
|
||||
babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
|
||||
assert (babel_ifp != NULL);
|
||||
/* wireless is the default*/
|
||||
if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED))
|
||||
{
|
||||
|
@ -1330,10 +1347,11 @@ babel_interface_allocate (void)
|
|||
{
|
||||
babel_interface_nfo *babel_ifp;
|
||||
babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
|
||||
assert (babel_ifp != NULL);
|
||||
/* All flags are unset */
|
||||
babel_ifp->bucket_time = babel_now.tv_sec;
|
||||
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_min = BABEL_DEFAULT_RTT_MIN;
|
||||
babel_ifp->rtt_max = BABEL_DEFAULT_RTT_MAX;
|
||||
|
@ -1349,6 +1367,8 @@ babel_interface_allocate (void)
|
|||
static void
|
||||
babel_interface_free (babel_interface_nfo *babel_ifp)
|
||||
{
|
||||
assert (babel_ifp != NULL);
|
||||
|
||||
if (babel_ifp->ipv4){
|
||||
free(babel_ifp->ipv4);
|
||||
babel_ifp->ipv4 = NULL;
|
||||
|
|
|
@ -94,6 +94,7 @@ struct buffered_update {
|
|||
|
||||
/* init function */
|
||||
void babel_if_init(void);
|
||||
void babel_if_terminate(void);
|
||||
|
||||
/* Callback functions for zebra client */
|
||||
int babel_interface_up (int, struct zclient *, zebra_size_t, vrf_id_t);
|
||||
|
|
|
@ -305,9 +305,9 @@ babel_exit_properly(void)
|
|||
|
||||
/* Uninstall and flush all routes. */
|
||||
debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
|
||||
flush_all_routes();
|
||||
babel_interface_close_all();
|
||||
babel_clean_routing_process();
|
||||
babel_zebra_close_connexion();
|
||||
babel_if_terminate();
|
||||
babel_save_state_file();
|
||||
debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
|
||||
debugf(BABEL_DEBUG_COMMON, "Done.");
|
||||
|
|
|
@ -204,7 +204,7 @@ static void babel_read_protocol(struct event *thread)
|
|||
making these inits have sense. */
|
||||
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_load_state_file();
|
||||
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. */
|
||||
static void
|
||||
babel_clean_routing_process(void)
|
||||
void babel_clean_routing_process(void)
|
||||
{
|
||||
flush_all_routes();
|
||||
babel_interface_close_all();
|
||||
|
@ -445,7 +444,7 @@ babel_fill_with_next_timeout(struct timeval *tv)
|
|||
#define printIfMin(a,b,c,d)
|
||||
#else
|
||||
#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); \
|
||||
}
|
||||
|
||||
|
|
|
@ -98,5 +98,6 @@ extern int redistribute_filter(const unsigned char *prefix, unsigned short plen,
|
|||
extern int resize_receive_buffer(int size);
|
||||
extern void schedule_neighbours_check(int msecs, int override);
|
||||
extern struct babel *babel_lookup(void);
|
||||
extern void babel_clean_routing_process(void);
|
||||
|
||||
#endif /* BABEL_BABELD_H */
|
||||
|
|
|
@ -93,10 +93,6 @@ kernel_route(enum babel_kernel_routes operation, const unsigned char *pref,
|
|||
if(newmetric == metric && memcmp(newgate, gate, 16) == 0 &&
|
||||
newifindex == ifindex)
|
||||
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,
|
||||
newmetric);
|
||||
|
|
|
@ -324,8 +324,8 @@ parse_request_subtlv(int ae, const unsigned char *a, int alen,
|
|||
have_src_prefix = 1;
|
||||
} else {
|
||||
debugf(BABEL_DEBUG_COMMON,"Received unknown%s Route Request sub-TLV %d.",
|
||||
((type & 0x80) != 0) ? " mandatory" : "", type);
|
||||
if((type & 0x80) != 0)
|
||||
(CHECK_FLAG(type, 0x80) != 0) ? " mandatory" : "", type);
|
||||
if(CHECK_FLAG(type, 0x80) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -588,7 +588,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
|
|||
else
|
||||
rc = -1;
|
||||
if(rc < 0) {
|
||||
if(message[3] & 0x80)
|
||||
if(CHECK_FLAG(message[3], 0x80))
|
||||
have_v4_prefix = have_v6_prefix = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
@ -596,7 +596,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
|
|||
|
||||
plen = message[4] + (message[2] == 1 ? 96 : 0);
|
||||
|
||||
if(message[3] & 0x80) {
|
||||
if(CHECK_FLAG(message[3], 0x80)) {
|
||||
if(message[2] == 1) {
|
||||
memcpy(v4_prefix, prefix, 16);
|
||||
have_v4_prefix = 1;
|
||||
|
@ -605,7 +605,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
|
|||
have_v6_prefix = 1;
|
||||
}
|
||||
}
|
||||
if(message[3] & 0x40) {
|
||||
if(CHECK_FLAG(message[3], 0x40)) {
|
||||
if(message[2] == 1) {
|
||||
memset(router_id, 0, 4);
|
||||
memcpy(router_id + 4, prefix + 12, 4);
|
||||
|
@ -620,8 +620,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
|
|||
goto fail;
|
||||
}
|
||||
debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.",
|
||||
(message[3] & 0x80) ? "/prefix" : "",
|
||||
(message[3] & 0x40) ? "/id" : "",
|
||||
((CHECK_FLAG(message[3], 0x80)) ? "/prefix" : ""),
|
||||
((CHECK_FLAG(message[3], 0x40)) ? "/id" : ""),
|
||||
format_prefix(prefix, plen),
|
||||
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);
|
||||
|
||||
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;
|
||||
accumulate_short(ifp, 0);
|
||||
accumulate_short(ifp, babel_ifp->hello_seqno);
|
||||
|
|
|
@ -352,7 +352,7 @@ route_stream_done(struct route_stream *stream)
|
|||
static int
|
||||
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
|
||||
|
|
|
@ -211,8 +211,8 @@ mask_prefix(unsigned char *restrict ret,
|
|||
memset(ret, 0, 16);
|
||||
memcpy(ret, prefix, plen / 8);
|
||||
if(plen % 8 != 0)
|
||||
ret[plen / 8] =
|
||||
(prefix[plen / 8] & ((0xFF << (8 - (plen % 8))) & 0xFF));
|
||||
ret[plen / 8] = CHECK_FLAG(prefix[plen / 8],
|
||||
CHECK_FLAG((0xFF << (8 - (plen % 8))), 0xFF));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -353,12 +353,13 @@ martian_prefix(const unsigned char *prefix, int plen)
|
|||
{
|
||||
return
|
||||
(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 &&
|
||||
(prefix[15] == 0 || prefix[15] == 1)) ||
|
||||
(plen >= 96 && v4mapped(prefix) &&
|
||||
((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) ||
|
||||
(plen >= 100 && (prefix[12] & 0xE0) == 0xE0)));
|
||||
(plen >= 100 && CHECK_FLAG(prefix[12], 0xE0) == 0xE0)));
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -47,19 +47,19 @@ seqno_compare(unsigned short s1, unsigned short s2)
|
|||
if(s1 == s2)
|
||||
return 0;
|
||||
else
|
||||
return ((s2 - s1) & 0x8000) ? 1 : -1;
|
||||
return (CHECK_FLAG((s2 - s1), 0x8000)) ? 1 : -1;
|
||||
}
|
||||
|
||||
static inline short
|
||||
seqno_minus(unsigned short s1, unsigned short s2)
|
||||
{
|
||||
return (short)((s1 - s2) & 0xFFFF);
|
||||
return (short)(CHECK_FLAG((s1 - s2), 0xFFFF));
|
||||
}
|
||||
|
||||
static inline unsigned short
|
||||
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,
|
||||
|
@ -130,7 +130,7 @@ is_default(const unsigned char *prefix, int plen)
|
|||
|
||||
#define debugf(level, ...) \
|
||||
do { \
|
||||
if (unlikely(debug & level)) \
|
||||
if (unlikely(CHECK_FLAG(debug, level))) \
|
||||
zlog_debug(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
|
82
bfdd/bfd.c
82
bfdd/bfd.c
|
@ -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;
|
||||
struct peer_label *pl;
|
||||
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. */
|
||||
gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
|
||||
bpc->bpc_localif, bpc->bpc_vrfname);
|
||||
|
@ -327,10 +316,8 @@ int bfd_session_enable(struct bfd_session *bs)
|
|||
bs->ifp = ifp;
|
||||
|
||||
/* Attempt to use data plane. */
|
||||
if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) {
|
||||
control_notify_config(BCM_NOTIFY_CONFIG_ADD, bs);
|
||||
if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sanity check: don't leak open sockets. */
|
||||
if (bs->sock != -1) {
|
||||
|
@ -410,8 +397,8 @@ static uint32_t ptm_bfd_gen_ID(void)
|
|||
* random session identification numbers.
|
||||
*/
|
||||
do {
|
||||
session_id = ((frr_weak_random() << 16) & 0xFFFF0000)
|
||||
| (frr_weak_random() & 0x0000FFFF);
|
||||
session_id = CHECK_FLAG((frr_weak_random() << 16), 0xFFFF0000) |
|
||||
CHECK_FLAG(frr_weak_random(), 0x0000FFFF);
|
||||
} while (session_id == 0 || bfd_id_lookup(session_id) != NULL);
|
||||
|
||||
return session_id;
|
||||
|
@ -502,7 +489,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd)
|
|||
/* Start sending control packets with poll bit immediately. */
|
||||
ptm_bfd_snd(bfd, 0);
|
||||
|
||||
control_notify(bfd, bfd->ses_state);
|
||||
ptm_bfd_notify(bfd, bfd->ses_state);
|
||||
|
||||
if (old_state != bfd->ses_state) {
|
||||
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 */
|
||||
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 */
|
||||
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
|
||||
|
@ -690,38 +677,6 @@ struct bfd_session *bfd_session_new(void)
|
|||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
if (bpc->bpc_has_label)
|
||||
bfd_session_update_label(bs, bpc->bpc_label);
|
||||
|
||||
if (bpc->bpc_cbit)
|
||||
SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT);
|
||||
else
|
||||
|
@ -792,8 +744,6 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
|
|||
|
||||
_bfd_session_update(bs, bpc);
|
||||
|
||||
control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -819,8 +769,6 @@ void bfd_session_free(struct bfd_session *bs)
|
|||
if (bso != NULL)
|
||||
bs_observer_del(bso);
|
||||
|
||||
pl_free(bs->pl);
|
||||
|
||||
XFREE(MTYPE_BFDD_PROFILE, bs->profile_name);
|
||||
XFREE(MTYPE_BFDD_CONFIG, bs);
|
||||
}
|
||||
|
@ -917,8 +865,6 @@ struct bfd_session *bs_registrate(struct bfd_session *bfd)
|
|||
if (bglobal.debug_peer_event)
|
||||
zlog_debug("session-new: %s", bs_to_string(bfd));
|
||||
|
||||
control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd);
|
||||
|
||||
return bfd;
|
||||
}
|
||||
|
||||
|
@ -941,8 +887,6 @@ int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc)
|
|||
if (bglobal.debug_peer_event)
|
||||
zlog_debug("%s: %s", __func__, bs_to_string(bs));
|
||||
|
||||
control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
|
||||
|
||||
bfd_session_free(bs);
|
||||
|
||||
return 0;
|
||||
|
@ -1166,11 +1110,8 @@ void bs_final_handler(struct bfd_session *bs)
|
|||
* When using demand mode we must disable the detection timer
|
||||
* for lost control packets.
|
||||
*/
|
||||
if (bs->demand_mode) {
|
||||
/* Notify watchers about changed timers. */
|
||||
control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
|
||||
if (bs->demand_mode)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate transmission time based on new timers.
|
||||
|
@ -1189,9 +1130,6 @@ void bs_final_handler(struct bfd_session *bs)
|
|||
|
||||
/* Apply new transmission timer immediately. */
|
||||
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)
|
||||
|
@ -1261,7 +1199,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
|
|||
if (bs->bdc) {
|
||||
bs->ses_state = PTM_BFD_ADM_DOWN;
|
||||
bfd_dplane_update_session(bs);
|
||||
control_notify(bs, bs->ses_state);
|
||||
ptm_bfd_notify(bs, bs->ses_state);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1273,7 +1211,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
|
|||
|
||||
/* Change and notify state change. */
|
||||
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. */
|
||||
if (bs->sock != -1)
|
||||
|
@ -1289,13 +1227,13 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
|
|||
if (bs->bdc) {
|
||||
bs->ses_state = PTM_BFD_DOWN;
|
||||
bfd_dplane_update_session(bs);
|
||||
control_notify(bs, bs->ses_state);
|
||||
ptm_bfd_notify(bs, bs->ses_state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Change and notify state change. */
|
||||
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. */
|
||||
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) {
|
||||
|
|
185
bfdd/bfd.h
185
bfdd/bfd.h
|
@ -20,19 +20,73 @@
|
|||
#include "lib/queue.h"
|
||||
#include "lib/vrf.h"
|
||||
|
||||
#include "bfdctl.h"
|
||||
|
||||
#ifdef BFD_DEBUG
|
||||
#define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY)
|
||||
#else
|
||||
#define BFDD_JSON_CONV_OPTIONS (0)
|
||||
#endif
|
||||
|
||||
DECLARE_MGROUP(BFDD);
|
||||
DECLARE_MTYPE(BFDD_CONTROL);
|
||||
DECLARE_MTYPE(BFDD_NOTIFICATION);
|
||||
#ifndef MAXNAMELEN
|
||||
#define MAXNAMELEN 32
|
||||
#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. */
|
||||
#define BFD_AUTH_NULL 0
|
||||
|
@ -97,8 +151,9 @@ struct bfd_echo_pkt {
|
|||
/* Macros for manipulating control packets */
|
||||
#define BFD_VERMASK 0x07
|
||||
#define BFD_DIAGMASK 0x1F
|
||||
#define BFD_GETVER(diag) ((diag >> 5) & BFD_VERMASK)
|
||||
#define BFD_SETVER(diag, val) ((diag) |= (val & BFD_VERMASK) << 5)
|
||||
#define BFD_GETVER(diag) (CHECK_FLAG((diag >> 5), BFD_VERMASK))
|
||||
#define BFD_SETVER(diag, val) \
|
||||
SET_FLAG((diag), CHECK_FLAG(val, BFD_VERMASK) << 5)
|
||||
#define BFD_VERSION 1
|
||||
#define BFD_PBIT 0x20
|
||||
#define BFD_FBIT 0x10
|
||||
|
@ -106,36 +161,36 @@ struct bfd_echo_pkt {
|
|||
#define BFD_ABIT 0x04
|
||||
#define BFD_DEMANDBIT 0x02
|
||||
#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) \
|
||||
{ \
|
||||
if ((val)) \
|
||||
flags |= BFD_DEMANDBIT; \
|
||||
SET_FLAG(flags, BFD_DEMANDBIT); \
|
||||
}
|
||||
#define BFD_SETPBIT(flags, 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) \
|
||||
{ \
|
||||
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) \
|
||||
{ \
|
||||
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) \
|
||||
{ \
|
||||
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_PKT_LEN sizeof(struct bfd_echo_pkt)
|
||||
|
||||
|
@ -245,9 +300,6 @@ struct bfd_profile {
|
|||
/** Profile list type. */
|
||||
TAILQ_HEAD(bfdproflist, bfd_profile);
|
||||
|
||||
/* bfd_session shortcut label forwarding. */
|
||||
struct peer_label;
|
||||
|
||||
struct bfd_config_timers {
|
||||
uint32_t desired_min_tx;
|
||||
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 */
|
||||
};
|
||||
|
||||
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 {
|
||||
const char *str;
|
||||
int type;
|
||||
|
@ -384,64 +428,6 @@ TAILQ_HEAD(obslist, bfd_session_observer);
|
|||
#define BFD_DEF_ECHO_PORT 3785
|
||||
#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
|
||||
|
@ -467,9 +453,6 @@ TAILQ_HEAD(dplane_queue, bfd_dplane_ctx);
|
|||
struct bfd_global {
|
||||
int bg_csock;
|
||||
struct event *bg_csockev;
|
||||
struct bcslist bg_bcslist;
|
||||
|
||||
struct pllist bg_pllist;
|
||||
|
||||
struct obslist bg_obslist;
|
||||
|
||||
|
@ -515,27 +498,6 @@ extern const struct bfd_state_str_list state_list[];
|
|||
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
|
||||
*/
|
||||
|
@ -620,7 +582,6 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
|
|||
bool is_mhop);
|
||||
|
||||
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 bs_state_handler(struct bfd_session *bs, int nstate);
|
||||
void bs_echo_timer_handler(struct bfd_session *bs);
|
||||
|
|
|
@ -982,7 +982,7 @@ void bfd_recv_cb(struct event *t)
|
|||
}
|
||||
|
||||
/* 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. */
|
||||
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))
|
||||
return;
|
||||
if (ifp->flags & IFF_NOARP)
|
||||
if (CHECK_FLAG(ifp->flags, IFF_NOARP))
|
||||
return;
|
||||
|
||||
if (peer->sa_sin.sin_family == AF_INET) {
|
||||
|
|
157
bfdd/bfdctl.h
157
bfdd/bfdctl.h
|
@ -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
|
27
bfdd/bfdd.c
27
bfdd/bfdd.c
|
@ -28,8 +28,8 @@
|
|||
* FRR related code.
|
||||
*/
|
||||
DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon");
|
||||
DEFINE_MTYPE(BFDD, BFDD_CONTROL, "control socket memory");
|
||||
DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "control notification data");
|
||||
DEFINE_MTYPE(BFDD, BFDD_CLIENT, "BFD client data");
|
||||
DEFINE_MTYPE(BFDD, BFDD_CLIENT_NOTIFICATION, "BFD client notification data");
|
||||
|
||||
/* Master of threads. */
|
||||
struct event_loop *master;
|
||||
|
@ -67,9 +67,6 @@ static void sigterm_handler(void)
|
|||
/* Stop receiving message from zebra. */
|
||||
bfdd_zclient_stop();
|
||||
|
||||
/* Shutdown controller to avoid receiving anymore commands. */
|
||||
control_shutdown();
|
||||
|
||||
/* Shutdown and free all protocol related memory. */
|
||||
bfd_shutdown();
|
||||
|
||||
|
@ -132,10 +129,8 @@ FRR_DAEMON_INFO(bfdd, BFD,
|
|||
);
|
||||
/* clang-format on */
|
||||
|
||||
#define OPTION_CTLSOCK 1001
|
||||
#define OPTION_DPLANEADDR 2000
|
||||
static const struct option longopts[] = {
|
||||
{"bfdctl", required_argument, NULL, OPTION_CTLSOCK},
|
||||
{"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR},
|
||||
{0}
|
||||
};
|
||||
|
@ -319,7 +314,6 @@ static void bg_init(void)
|
|||
.cap_num_i = 0,
|
||||
};
|
||||
|
||||
TAILQ_INIT(&bglobal.bg_bcslist);
|
||||
TAILQ_INIT(&bglobal.bg_obslist);
|
||||
|
||||
memcpy(&bglobal.bfdd_privs, &bfdd_privs,
|
||||
|
@ -328,8 +322,7 @@ static void bg_init(void)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char ctl_path[512], dplane_addr[512];
|
||||
bool ctlsockused = false;
|
||||
char dplane_addr[512];
|
||||
int opt;
|
||||
|
||||
bglobal.bg_use_dplane = false;
|
||||
|
@ -339,7 +332,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
frr_preinit(&bfdd_di, argc, argv);
|
||||
frr_opt_add("", longopts,
|
||||
" --bfdctl Specify bfdd control socket\n"
|
||||
" --dplaneaddr Specify BFD data plane address\n");
|
||||
|
||||
while (true) {
|
||||
|
@ -348,10 +340,6 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
|
||||
switch (opt) {
|
||||
case OPTION_CTLSOCK:
|
||||
strlcpy(ctl_path, optarg, sizeof(ctl_path));
|
||||
ctlsockused = true;
|
||||
break;
|
||||
case OPTION_DPLANEADDR:
|
||||
strlcpy(dplane_addr, optarg, sizeof(dplane_addr));
|
||||
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. */
|
||||
master = frr_init();
|
||||
|
||||
/* Initialize control socket. */
|
||||
control_init(ctl_path);
|
||||
|
||||
/* Initialize BFD data structures. */
|
||||
bfd_initialize();
|
||||
|
||||
|
@ -381,9 +363,6 @@ int main(int argc, char *argv[])
|
|||
/* Initialize zebra connection. */
|
||||
bfdd_zclient_init(&bglobal.bfdd_privs);
|
||||
|
||||
event_add_read(master, control_accept, NULL, bglobal.bg_csock,
|
||||
&bglobal.bg_csockev);
|
||||
|
||||
/* Install commands. */
|
||||
bfdd_vty_init();
|
||||
|
||||
|
|
|
@ -338,11 +338,12 @@ void bfd_cli_show_minimum_ttl(struct vty *vty, const struct lyd_node *dnode,
|
|||
|
||||
DEFPY_YANG(
|
||||
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 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);
|
||||
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(
|
||||
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 value in milliseconds\n")
|
||||
{
|
||||
char value[32];
|
||||
|
||||
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);
|
||||
|
||||
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(
|
||||
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 value in milliseconds\n")
|
||||
{
|
||||
|
@ -387,7 +390,7 @@ DEFPY_YANG(
|
|||
|
||||
snprintf(value, sizeof(value), "%ld", interval * 1000);
|
||||
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);
|
||||
}
|
||||
|
@ -436,7 +439,8 @@ void bfd_cli_show_echo(struct vty *vty, const struct lyd_node *dnode,
|
|||
|
||||
DEFPY_YANG(
|
||||
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 rx/tx intervals value in milliseconds\n")
|
||||
{
|
||||
|
@ -449,16 +453,17 @@ DEFPY_YANG(
|
|||
|
||||
snprintf(value, sizeof(value), "%ld", interval * 1000);
|
||||
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_OP_MODIFY, value);
|
||||
no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
DEFPY_YANG(
|
||||
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 desired transmit interval\n"
|
||||
"Configure interval value in milliseconds\n")
|
||||
|
@ -472,7 +477,7 @@ DEFPY_YANG(
|
|||
|
||||
snprintf(value, sizeof(value), "%ld", interval * 1000);
|
||||
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);
|
||||
}
|
||||
|
@ -487,7 +492,8 @@ void bfd_cli_show_desired_echo_transmission_interval(
|
|||
|
||||
DEFPY_YANG(
|
||||
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 required receive interval\n"
|
||||
"Disable echo packets receive\n"
|
||||
|
@ -506,7 +512,7 @@ DEFPY_YANG(
|
|||
snprintf(value, sizeof(value), "%ld", interval * 1000);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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,
|
||||
"detect-multiplier (2-255)$multiplier",
|
||||
"[no] detect-multiplier ![(2-255)$multiplier]",
|
||||
NO_STR
|
||||
"Configure peer detection multiplier\n"
|
||||
"Configure peer detection multiplier value\n")
|
||||
|
||||
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 value in milliseconds\n")
|
||||
|
||||
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 value in milliseconds\n")
|
||||
|
||||
|
@ -612,20 +621,23 @@ ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd,
|
|||
"Configure echo mode\n")
|
||||
|
||||
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 value in milliseconds\n")
|
||||
|
||||
ALIAS_YANG(
|
||||
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 desired transmit interval\n"
|
||||
"Configure interval value in milliseconds\n")
|
||||
|
||||
ALIAS_YANG(
|
||||
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 required receive interval\n"
|
||||
"Disable echo packets receive\n"
|
||||
|
|
|
@ -84,9 +84,6 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
|
|||
if (bs->key.ifname[0])
|
||||
vty_out(vty, " interface %s", bs->key.ifname);
|
||||
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)
|
||||
|
@ -200,9 +197,6 @@ static struct json_object *_peer_json_header(struct bfd_session *bs)
|
|||
if (bs->key.ifname[0])
|
||||
json_object_string_add(jo, "interface", bs->key.ifname);
|
||||
|
||||
if (bs->pl)
|
||||
json_object_string_add(jo, "label", bs->pl->pl_label);
|
||||
|
||||
return jo;
|
||||
}
|
||||
|
||||
|
@ -561,17 +555,11 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
|
|||
int idx;
|
||||
bool mhop;
|
||||
struct bfd_session *bs = NULL;
|
||||
struct peer_label *pl;
|
||||
struct bfd_peer_cfg bpc;
|
||||
struct sockaddr_any psa, lsa, *lsap;
|
||||
char errormsg[128];
|
||||
|
||||
/* Look up the BFD peer. */
|
||||
if (label) {
|
||||
pl = pl_find(label);
|
||||
if (pl)
|
||||
bs = pl->pl_bs;
|
||||
} else if (peer_str) {
|
||||
if (peer_str) {
|
||||
strtosa(peer_str, &psa);
|
||||
if (local_str) {
|
||||
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_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL;
|
||||
bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL;
|
||||
bpc->bpc_lastevent = monotime(NULL);
|
||||
|
||||
/* Safety check: when no error buf is provided len must be zero. */
|
||||
if (ebuf == NULL)
|
||||
|
|
592
bfdd/config.c
592
bfdd/config.c
|
@ -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);
|
||||
}
|
844
bfdd/control.c
844
bfdd/control.c
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
||||
/* Notify and update counters. */
|
||||
control_notify(bs, bs->ses_state);
|
||||
ptm_bfd_notify(bs, bs->ses_state);
|
||||
|
||||
/* No state change. */
|
||||
if (old_state == bs->ses_state)
|
||||
|
|
|
@ -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",
|
||||
bs_to_string(bs));
|
||||
} else {
|
||||
control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
|
||||
bfd_session_free(bs);
|
||||
}
|
||||
}
|
||||
|
@ -892,7 +891,7 @@ static struct ptm_client *pc_new(uint32_t pid)
|
|||
return pc;
|
||||
|
||||
/* 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;
|
||||
TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry);
|
||||
|
@ -910,7 +909,7 @@ static void pc_free(struct ptm_client *pc)
|
|||
pcn_free(pcn);
|
||||
}
|
||||
|
||||
XFREE(MTYPE_BFDD_CONTROL, pc);
|
||||
XFREE(MTYPE_BFDD_CLIENT, pc);
|
||||
}
|
||||
|
||||
static void pc_free_all(void)
|
||||
|
@ -934,7 +933,7 @@ static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
|
|||
return pcn;
|
||||
|
||||
/* 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);
|
||||
pcn->pcn_pc = pc;
|
||||
|
@ -982,5 +981,5 @@ static void pcn_free(struct ptm_client_notification *pcn)
|
|||
pcn->pcn_pc = NULL;
|
||||
TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry);
|
||||
|
||||
XFREE(MTYPE_BFDD_NOTIFICATION, pcn);
|
||||
XFREE(MTYPE_BFDD_CLIENT_NOTIFICATION, pcn);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ bfdd_libbfd_a_SOURCES = \
|
|||
bfdd/bfdd_vty.c \
|
||||
bfdd/bfdd_cli.c \
|
||||
bfdd/bfd_packet.c \
|
||||
bfdd/config.c \
|
||||
bfdd/control.c \
|
||||
bfdd/dplane.c \
|
||||
bfdd/event.c \
|
||||
bfdd/ptm_adapter.c \
|
||||
|
@ -37,7 +35,6 @@ clippy_scan += \
|
|||
# end
|
||||
|
||||
noinst_HEADERS += \
|
||||
bfdd/bfdctl.h \
|
||||
bfdd/bfdd_nb.h \
|
||||
bfdd/bfd.h \
|
||||
# end
|
||||
|
|
|
@ -361,8 +361,7 @@ void bgp_addpath_type_changed(struct bgp *bgp)
|
|||
}
|
||||
}
|
||||
|
||||
int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type,
|
||||
uint8_t paths)
|
||||
int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths)
|
||||
{
|
||||
int action = CAPABILITY_ACTION_UNSET;
|
||||
|
||||
|
@ -392,8 +391,7 @@ int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type,
|
|||
* change take effect.
|
||||
*/
|
||||
void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
|
||||
enum bgp_addpath_strat addpath_type,
|
||||
uint8_t paths)
|
||||
enum bgp_addpath_strat addpath_type, uint16_t paths)
|
||||
{
|
||||
struct bgp *bgp = peer->bgp;
|
||||
enum bgp_addpath_strat old_type;
|
||||
|
|
|
@ -62,13 +62,11 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat,
|
|||
* Change the type of addpath used for a peer.
|
||||
*/
|
||||
void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
|
||||
enum bgp_addpath_strat addpath_type,
|
||||
uint8_t paths);
|
||||
enum bgp_addpath_strat addpath_type, uint16_t paths);
|
||||
|
||||
void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi,
|
||||
safi_t safi);
|
||||
|
||||
void bgp_addpath_type_changed(struct bgp *bgp);
|
||||
extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type,
|
||||
uint8_t paths);
|
||||
extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths);
|
||||
#endif
|
||||
|
|
368
bgpd/bgp_attr.c
368
bgpd/bgp_attr.c
|
@ -198,6 +198,7 @@ static struct hash *vnc_hash = NULL;
|
|||
#endif
|
||||
static struct hash *srv6_l3vpn_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)
|
||||
{
|
||||
|
@ -479,22 +480,11 @@ static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt, int length,
|
|||
return false;
|
||||
}
|
||||
|
||||
static 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 void stream_put_bgp_aigp_tlv_metric(struct stream *s,
|
||||
struct bgp_path_info *bpi)
|
||||
static void stream_put_bgp_aigp_tlv_metric(struct stream *s, uint64_t aigp)
|
||||
{
|
||||
stream_putc(s, BGP_AIGP_TLV_METRIC);
|
||||
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)
|
||||
|
@ -549,6 +539,81 @@ static bool bgp_attr_aigp_valid(uint8_t *pnt, int length)
|
|||
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)
|
||||
{
|
||||
return p;
|
||||
|
@ -788,6 +853,8 @@ unsigned int attrhash_key_make(const void *p)
|
|||
MIX(encap_hash_key_make(attr->encap_subtlvs));
|
||||
if (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)
|
||||
MIX(srv6_vpn_hash_key_make(attr->srv6_vpn));
|
||||
#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 *attr2 = p2;
|
||||
|
||||
if (attr1->flag == attr2->flag && attr1->origin == attr2->origin
|
||||
&& attr1->nexthop.s_addr == attr2->nexthop.s_addr
|
||||
&& attr1->aspath == attr2->aspath
|
||||
&& bgp_attr_get_community(attr1)
|
||||
== bgp_attr_get_community(attr2)
|
||||
&& attr1->med == attr2->med
|
||||
&& attr1->local_pref == attr2->local_pref
|
||||
&& attr1->rmap_change_flags == attr2->rmap_change_flags) {
|
||||
if (attr1->flag == attr2->flag && attr1->origin == attr2->origin &&
|
||||
attr1->nexthop.s_addr == attr2->nexthop.s_addr &&
|
||||
attr1->aspath == attr2->aspath &&
|
||||
bgp_attr_get_community(attr1) == bgp_attr_get_community(attr2) &&
|
||||
attr1->med == attr2->med && attr1->local_pref == attr2->local_pref &&
|
||||
attr1->rmap_change_flags == attr2->rmap_change_flags) {
|
||||
if (attr1->aggregator_as == attr2->aggregator_as &&
|
||||
attr1->aggregator_addr.s_addr ==
|
||||
attr2->aggregator_addr.s_addr &&
|
||||
attr1->weight == attr2->weight &&
|
||||
attr1->tag == attr2->tag &&
|
||||
attr1->weight == attr2->weight && attr1->tag == attr2->tag &&
|
||||
attr1->label_index == attr2->label_index &&
|
||||
attr1->mp_nexthop_len == attr2->mp_nexthop_len &&
|
||||
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_lcommunity(attr1) ==
|
||||
bgp_attr_get_lcommunity(attr2) &&
|
||||
bgp_attr_get_cluster(attr1) ==
|
||||
bgp_attr_get_cluster(attr2) &&
|
||||
bgp_attr_get_transit(attr1) ==
|
||||
bgp_attr_get_transit(attr2) &&
|
||||
bgp_attr_get_cluster(attr1) == bgp_attr_get_cluster(attr2) &&
|
||||
bgp_attr_get_transit(attr1) == bgp_attr_get_transit(attr2) &&
|
||||
bgp_attr_get_aigp_metric(attr1) ==
|
||||
bgp_attr_get_aigp_metric(attr2) &&
|
||||
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) &&
|
||||
attr1->srte_color == attr2->srte_color &&
|
||||
attr1->nh_type == attr2->nh_type &&
|
||||
attr1->bh_type == attr2->bh_type &&
|
||||
attr1->otc == attr2->otc)
|
||||
attr1->bh_type == attr2->bh_type && attr1->otc == attr2->otc)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -961,6 +1022,7 @@ struct attr *bgp_attr_intern(struct attr *attr)
|
|||
struct ecommunity *ipv6_ecomm = NULL;
|
||||
struct lcommunity *lcomm = NULL;
|
||||
struct community *comm = NULL;
|
||||
struct bgp_route_evpn *bre = NULL;
|
||||
|
||||
/* Intern referenced structure. */
|
||||
if (attr->aspath) {
|
||||
|
@ -1027,6 +1089,16 @@ struct attr *bgp_attr_intern(struct attr *attr)
|
|||
else
|
||||
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->refcnt)
|
||||
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));
|
||||
|
||||
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->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->tag = 0;
|
||||
attr->label_index = BGP_INVALID_LABEL_INDEX;
|
||||
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->local_pref = bgp->default_local_pref;
|
||||
|
||||
|
@ -1101,18 +1173,18 @@ struct attr *bgp_attr_aggregate_intern(
|
|||
|
||||
/* Origin attribute. */
|
||||
attr.origin = origin;
|
||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
|
||||
SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN));
|
||||
|
||||
/* MED */
|
||||
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. */
|
||||
if (aspath)
|
||||
attr.aspath = aspath_intern(aspath);
|
||||
else
|
||||
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) {
|
||||
uint32_t gshut = COMMUNITY_GSHUT;
|
||||
|
@ -1142,8 +1214,8 @@ struct attr *bgp_attr_aggregate_intern(
|
|||
attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
|
||||
attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
|
||||
if (!aggregate->as_set || atomic_aggregate)
|
||||
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_ATOMIC_AGGREGATE));
|
||||
SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
|
||||
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
|
||||
attr.aggregator_as = bgp->confed_id;
|
||||
else
|
||||
|
@ -1161,7 +1233,7 @@ struct attr *bgp_attr_aggregate_intern(
|
|||
*/
|
||||
if (p->family == AF_INET) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -1216,6 +1288,7 @@ void bgp_attr_unintern_sub(struct attr *attr)
|
|||
struct lcommunity *lcomm = NULL;
|
||||
struct community *comm = NULL;
|
||||
struct transit *transit;
|
||||
struct bgp_route_evpn *bre;
|
||||
|
||||
/* aspath refcount shoud be decrement. */
|
||||
aspath_unintern(&attr->aspath);
|
||||
|
@ -1257,6 +1330,10 @@ void bgp_attr_unintern_sub(struct attr *attr)
|
|||
|
||||
srv6_l3vpn_unintern(&attr->srv6_l3vpn);
|
||||
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. */
|
||||
|
@ -1289,6 +1366,7 @@ void bgp_attr_flush(struct attr *attr)
|
|||
struct cluster_list *cluster;
|
||||
struct lcommunity *lcomm;
|
||||
struct community *comm;
|
||||
struct bgp_route_evpn *bre;
|
||||
|
||||
if (attr->aspath && !attr->aspath->refcnt) {
|
||||
aspath_free(attr->aspath);
|
||||
|
@ -1347,6 +1425,11 @@ void bgp_attr_flush(struct attr *attr)
|
|||
bgp_attr_set_vnc_subtlvs(attr, NULL);
|
||||
}
|
||||
#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
|
||||
|
@ -1467,8 +1550,8 @@ bgp_attr_flags_diagnose(struct bgp_attr_parser_args *args,
|
|||
uint8_t real_flags = args->flags;
|
||||
const uint8_t attr_code = args->type;
|
||||
|
||||
desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
|
||||
real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
|
||||
UNSET_FLAG(desired_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 */
|
||||
if (CHECK_FLAG(desired_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))
|
||||
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;
|
||||
|
||||
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. */
|
||||
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
|
||||
SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1674,7 +1757,7 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
|
|||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -1778,7 +1861,7 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
|
|||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -1828,7 +1911,7 @@ bgp_attr_nexthop(struct bgp_attr_parser_args *args)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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->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;
|
||||
}
|
||||
|
@ -1889,7 +1972,7 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args)
|
|||
STREAM_GETL(peer->curr, attr->local_pref);
|
||||
|
||||
/* 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;
|
||||
|
||||
|
@ -1918,7 +2001,7 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
|
|||
goto atomic_ignore;
|
||||
|
||||
/* 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;
|
||||
|
||||
|
@ -1976,7 +2059,7 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
|
|||
zlog_debug("%s: attributes: %s", __func__, attr_str);
|
||||
}
|
||||
} else {
|
||||
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
|
||||
SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} 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;
|
||||
|
@ -2066,12 +2149,13 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
|
|||
* should not send them
|
||||
*/
|
||||
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,
|
||||
"AS4 capable peer, yet it sent");
|
||||
|
||||
if (attr->flag
|
||||
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
|
||||
if (CHECK_FLAG(attr->flag,
|
||||
(ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))))
|
||||
zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
|
||||
peer->host,
|
||||
"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
|
||||
* because that may override AS4_PATH
|
||||
*/
|
||||
if (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_AS4_AGGREGATOR)))) {
|
||||
if (CHECK_FLAG(attr->flag,
|
||||
(ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)))) {
|
||||
/* received both.
|
||||
* if the as_number in aggregator is not AS_TRANS,
|
||||
* 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;
|
||||
/* sweep it under the carpet and simulate a "good"
|
||||
* 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 */
|
||||
if (!ignore_as4_path
|
||||
&& (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) {
|
||||
if (!ignore_as4_path &&
|
||||
(CHECK_FLAG(attr->flag, (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))))) {
|
||||
newpath = aspath_reconcile_as4(attr->aspath, as4_path);
|
||||
if (!newpath)
|
||||
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->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID);
|
||||
SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID));
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
#undef LEN_LEFT
|
||||
|
@ -2525,7 +2611,7 @@ int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -2575,7 +2661,6 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
|
|||
struct peer *const peer = args->peer;
|
||||
struct attr *const attr = args->attr;
|
||||
const bgp_size_t length = args->length;
|
||||
uint8_t sticky = 0;
|
||||
bool proxy = false;
|
||||
struct ecommunity *ecomm;
|
||||
|
||||
|
@ -2586,8 +2671,7 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
|
|||
args->total);
|
||||
}
|
||||
|
||||
ecomm = ecommunity_parse(
|
||||
stream_pnt(peer->curr), length,
|
||||
ecomm = ecommunity_parse(stream_pnt(peer->curr), length,
|
||||
CHECK_FLAG(peer->flags,
|
||||
PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
|
||||
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);
|
||||
|
||||
/* Extract MAC mobility sequence number, if any. */
|
||||
attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
|
||||
attr->sticky = sticky;
|
||||
attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr);
|
||||
|
||||
/* 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
|
||||
* set but default gw ext community is present.
|
||||
* Use default gateway, set and propogate R-bit.
|
||||
*/
|
||||
if (attr->default_gw)
|
||||
attr->router_flag = 1;
|
||||
if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW))
|
||||
SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER);
|
||||
|
||||
/* 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)
|
||||
attr->es_flags |= ATTR_ES_PROXY_ADVERT;
|
||||
SET_FLAG(attr->es_flags, ATTR_ES_PROXY_ADVERT);
|
||||
|
||||
/* Extract the Rmac, if any */
|
||||
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 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)
|
||||
|| !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
|
||||
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);
|
||||
}
|
||||
|
||||
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 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
|
||||
&& 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));
|
||||
|
||||
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)
|
||||
|
@ -3263,6 +3364,9 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
|
|||
uint8_t tnl_type;
|
||||
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
|
||||
* 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);
|
||||
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);
|
||||
|
||||
return BGP_ATTR_PARSE_PROCEED;
|
||||
|
||||
pmsi_tunnel_ignore:
|
||||
stream_forward_getp(peer->curr, length);
|
||||
|
||||
return bgp_attr_ignore(peer, args->type);
|
||||
}
|
||||
|
||||
/* AIGP attribute (rfc7311) */
|
||||
|
@ -3369,7 +3478,7 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
|
|||
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;
|
||||
|
||||
|
@ -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
|
||||
* received.
|
||||
*/
|
||||
flag = 0xF0 & stream_getc(BGP_INPUT(peer));
|
||||
flag = CHECK_FLAG(0xF0, stream_getc(BGP_INPUT(peer)));
|
||||
type = stream_getc(BGP_INPUT(peer));
|
||||
|
||||
/* Check whether Extended-Length applies and is in bounds */
|
||||
if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN)
|
||||
&& ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) {
|
||||
flog_warn(
|
||||
EC_BGP_EXT_ATTRIBUTE_TOO_SMALL,
|
||||
flog_warn(EC_BGP_EXT_ATTRIBUTE_TOO_SMALL,
|
||||
"%s: Extended length set, but just %lu bytes of attr header",
|
||||
peer->host,
|
||||
(unsigned long)(endp
|
||||
- stream_pnt(BGP_INPUT(peer))));
|
||||
(unsigned long)(endp -
|
||||
stream_pnt(BGP_INPUT(peer))));
|
||||
|
||||
if (peer->sort != BGP_PEER_EBGP) {
|
||||
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
|
||||
* 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);
|
||||
if (ret != BGP_ATTR_PARSE_PROCEED)
|
||||
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_LABELED_UNICAST:
|
||||
case SAFI_EVPN: {
|
||||
if (attr->mp_nexthop_len
|
||||
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
|
||||
if (attr->mp_nexthop_len ==
|
||||
BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
|
||||
stream_putc(s,
|
||||
BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL);
|
||||
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_EXTLEN);
|
||||
stream_putc(s, attrtype);
|
||||
stream_putw(s, attrlenfield & 0xffff);
|
||||
stream_putw(s, CHECK_FLAG(attrlenfield, 0xffff));
|
||||
} else {
|
||||
/* 1-octet length field */
|
||||
stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL);
|
||||
stream_putc(s, attrtype);
|
||||
stream_putc(s, attrlenfield & 0xff);
|
||||
stream_putc(s, CHECK_FLAG(attrlenfield, 0xff));
|
||||
}
|
||||
|
||||
if (attrtype == BGP_ATTR_ENCAP) {
|
||||
|
@ -4440,14 +4548,11 @@ static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer,
|
|||
}
|
||||
|
||||
/* Make attribute packet. */
|
||||
bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
struct stream *s, struct attr *attr,
|
||||
struct bpacket_attr_vec_arr *vecarr,
|
||||
struct prefix *p, afi_t afi, safi_t safi,
|
||||
struct peer *from, struct prefix_rd *prd,
|
||||
mpls_label_t *label, uint8_t num_labels,
|
||||
bool addpath_capable, uint32_t addpath_tx_id,
|
||||
struct bgp_path_info *bpi)
|
||||
bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct stream *s,
|
||||
struct attr *attr, struct bpacket_attr_vec_arr *vecarr,
|
||||
struct prefix *p, afi_t afi, safi_t safi, struct peer *from,
|
||||
struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels,
|
||||
bool addpath_capable, uint32_t addpath_tx_id)
|
||||
{
|
||||
size_t cp;
|
||||
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);
|
||||
}
|
||||
|
||||
(void)peer_sort(peer);
|
||||
|
||||
/* Origin attribute. */
|
||||
stream_putc(s, BGP_ATTR_FLAG_TRANS);
|
||||
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)) {
|
||||
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_NEXT_HOP);
|
||||
bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
|
||||
attr);
|
||||
stream_putc(s, 4);
|
||||
stream_put_ipv4(s, attr->nexthop.s_addr);
|
||||
} else if (peer_cap_enhe(from, afi, safi)
|
||||
|| (nh_afi == AFI_IP6)) {
|
||||
} else if (peer_cap_enhe(from, afi, safi) ||
|
||||
(nh_afi == AFI_IP6)) {
|
||||
/*
|
||||
* Likely this is the case when an IPv4 prefix was
|
||||
* 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. */
|
||||
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)
|
||||
|| bgp->maxmed_active) {
|
||||
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) ||
|
||||
bgp->maxmed_active) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
|
||||
stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
|
||||
stream_putc(s, 4);
|
||||
|
@ -4618,14 +4725,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
|||
}
|
||||
|
||||
/* 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_ATOMIC_AGGREGATE);
|
||||
stream_putc(s, 0);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_AGGREGATOR);
|
||||
|
@ -4656,8 +4763,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
|||
}
|
||||
|
||||
/* Community attribute. */
|
||||
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
|
||||
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
|
||||
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) &&
|
||||
CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
|
||||
struct community *comm = NULL;
|
||||
|
||||
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.
|
||||
*/
|
||||
if (CHECK_FLAG(peer->af_flags[afi][safi],
|
||||
PEER_FLAG_SEND_LARGE_COMMUNITY)
|
||||
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
|
||||
PEER_FLAG_SEND_LARGE_COMMUNITY) &&
|
||||
CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
|
||||
if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
|
||||
stream_putc(s,
|
||||
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, 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);
|
||||
else
|
||||
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);
|
||||
/* If this peer configuration's parent BGP has
|
||||
* 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);
|
||||
else
|
||||
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);
|
||||
/* If this peer configuration's parent BGP has
|
||||
* 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);
|
||||
else
|
||||
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 */
|
||||
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_PMSI_TUNNEL);
|
||||
stream_putc(s, 9); // Length
|
||||
|
@ -4915,7 +5023,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
|||
}
|
||||
|
||||
/* 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_OTC);
|
||||
stream_putc(s, 4);
|
||||
|
@ -4923,10 +5031,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
|||
}
|
||||
|
||||
/* AIGP */
|
||||
if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
|
||||
(CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
|
||||
peer->sub_sort == BGP_PEER_EBGP_OAD ||
|
||||
peer->sort != BGP_PEER_EBGP)) {
|
||||
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && AIGP_TRANSMIT_ALLOWED(peer)) {
|
||||
/* At the moment only AIGP Metric TLV exists for AIGP
|
||||
* attribute. If more comes in, do not forget to update
|
||||
* 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_AIGP);
|
||||
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. */
|
||||
|
@ -5006,6 +5111,7 @@ void bgp_attr_init(void)
|
|||
transit_init();
|
||||
encap_init();
|
||||
srv6_init();
|
||||
evpn_overlay_init();
|
||||
}
|
||||
|
||||
void bgp_attr_finish(void)
|
||||
|
@ -5019,6 +5125,7 @@ void bgp_attr_finish(void)
|
|||
transit_finish();
|
||||
encap_finish();
|
||||
srv6_finish();
|
||||
evpn_overlay_finish();
|
||||
}
|
||||
|
||||
/* Make attribute packet. */
|
||||
|
@ -5064,7 +5171,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
|
|||
}
|
||||
|
||||
/* 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_MULTI_EXIT_DISC);
|
||||
stream_putc(s, 4);
|
||||
|
@ -5072,7 +5179,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
|
|||
}
|
||||
|
||||
/* 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_LOCAL_PREF);
|
||||
stream_putc(s, 4);
|
||||
|
@ -5080,14 +5187,14 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
|
|||
}
|
||||
|
||||
/* 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_ATOMIC_AGGREGATE);
|
||||
stream_putc(s, 0);
|
||||
}
|
||||
|
||||
/* 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_AGGREGATOR);
|
||||
stream_putc(s, 8);
|
||||
|
@ -5096,7 +5203,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
|
|||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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_putw(s, comm->size * 4);
|
||||
} else {
|
||||
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_COMMUNITIES);
|
||||
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. */
|
||||
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) {
|
||||
stream_putc(s,
|
||||
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,
|
||||
lcom_length(bgp_attr_get_lcommunity(attr)));
|
||||
} else {
|
||||
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_LARGE_COMMUNITIES);
|
||||
stream_putc(s,
|
||||
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 */
|
||||
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) {
|
||||
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_PREFIX_SID);
|
||||
stream_putc(s, 10);
|
||||
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 */
|
||||
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_OTC);
|
||||
stream_putc(s, 4);
|
||||
|
@ -5196,7 +5300,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
|
|||
}
|
||||
|
||||
/* 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
|
||||
* attribute. If more comes in, do not forget to update
|
||||
* 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_AIGP);
|
||||
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. */
|
||||
|
|
|
@ -197,9 +197,6 @@ struct attr {
|
|||
#define ATTR_ES_L3_NHG_ACTIVE (1 << 6)
|
||||
#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 */
|
||||
uint8_t distance;
|
||||
|
||||
|
@ -212,7 +209,7 @@ struct attr {
|
|||
|
||||
/* has the route-map changed any attribute?
|
||||
Used on the peer outbound side. */
|
||||
uint32_t rmap_change_flags;
|
||||
uint16_t rmap_change_flags;
|
||||
|
||||
/* Multi-Protocol Nexthop, AFI IPv6 */
|
||||
struct in6_addr mp_nexthop_global;
|
||||
|
@ -256,11 +253,12 @@ struct attr {
|
|||
/* MP Nexthop length */
|
||||
uint8_t mp_nexthop_len;
|
||||
|
||||
/* Static MAC for EVPN */
|
||||
uint8_t sticky;
|
||||
|
||||
/* Flag for default gateway extended community in EVPN */
|
||||
uint8_t default_gw;
|
||||
/* EVPN flags */
|
||||
uint8_t evpn_flags;
|
||||
#define ATTR_EVPN_FLAG_STICKY (1 << 0)
|
||||
#define ATTR_EVPN_FLAG_DEFAULT_GW (1 << 1)
|
||||
/* NA router flag (R-bit) support in EVPN */
|
||||
#define ATTR_EVPN_FLAG_ROUTER (1 << 2)
|
||||
|
||||
/* route tag */
|
||||
route_tag_t tag;
|
||||
|
@ -280,7 +278,7 @@ struct attr {
|
|||
struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */
|
||||
#endif
|
||||
/* EVPN */
|
||||
struct bgp_route_evpn evpn_overlay;
|
||||
struct bgp_route_evpn *evpn_overlay;
|
||||
|
||||
/* EVPN MAC Mobility sequence number, if any. */
|
||||
uint32_t mm_seqnum;
|
||||
|
@ -295,7 +293,7 @@ struct attr {
|
|||
/* EVPN local router-mac */
|
||||
struct ethaddr rmac;
|
||||
|
||||
uint16_t encap_tunneltype;
|
||||
uint8_t encap_tunneltype;
|
||||
|
||||
/* rmap set table */
|
||||
uint32_t rmap_table_id;
|
||||
|
@ -355,7 +353,7 @@ struct transit {
|
|||
__builtin_choose_expr((X) >= 1 && (X) <= 64, 1ULL << ((X)-1), (void)0)
|
||||
|
||||
#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 \
|
||||
: 0)
|
||||
|
||||
|
@ -389,12 +387,12 @@ extern struct attr *bgp_attr_aggregate_intern(
|
|||
struct community *community, struct ecommunity *ecommunity,
|
||||
struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
|
||||
uint8_t atomic_aggregate, const struct prefix *p);
|
||||
extern bgp_size_t bgp_packet_attribute(
|
||||
struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr,
|
||||
struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi,
|
||||
safi_t safi, struct peer *from, struct prefix_rd *prd,
|
||||
mpls_label_t *label, uint8_t num_labels, bool addpath_capable,
|
||||
uint32_t addpath_tx_id, struct bgp_path_info *bpi);
|
||||
extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct stream *s,
|
||||
struct attr *attr, struct bpacket_attr_vec_arr *vecarr,
|
||||
struct prefix *p, afi_t afi, safi_t safi, struct peer *from,
|
||||
struct prefix_rd *prd, mpls_label_t *label,
|
||||
uint8_t num_labels, bool addpath_capable,
|
||||
uint32_t addpath_tx_id);
|
||||
extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
|
||||
const struct prefix *p);
|
||||
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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
attr->aigp_metric = aigp;
|
||||
|
||||
if (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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
static inline const struct bgp_route_evpn *
|
||||
static inline struct bgp_route_evpn *
|
||||
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,
|
||||
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 *
|
||||
|
@ -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 void evpn_overlay_free(struct bgp_route_evpn *bre);
|
||||
|
||||
#endif /* _QUAGGA_BGP_ATTR_H */
|
||||
|
|
|
@ -24,6 +24,13 @@
|
|||
bool bgp_route_evpn_same(const struct bgp_route_evpn *e1,
|
||||
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 &&
|
||||
!memcmp(&(e1->eth_s_id), &(e2->eth_s_id), sizeof(esi_t)) &&
|
||||
!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
|
||||
*/
|
||||
uint8_t bgp_attr_default_gw(struct attr *attr)
|
||||
void bgp_attr_default_gw(struct attr *attr)
|
||||
{
|
||||
struct ecommunity *ecom;
|
||||
uint32_t i;
|
||||
|
||||
ecom = bgp_attr_get_ecommunity(attr);
|
||||
if (!ecom || !ecom->size)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
/* If there is a default gw extendd community return true otherwise
|
||||
* return 0 */
|
||||
|
@ -136,10 +143,9 @@ uint8_t bgp_attr_default_gw(struct attr *attr)
|
|||
|
||||
if ((type == ECOMMUNITY_ENCODE_OPAQUE
|
||||
&& sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
|
||||
return 1;
|
||||
SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
|
||||
}
|
||||
|
||||
return 0;
|
||||
UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
* 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;
|
||||
uint32_t i;
|
||||
|
@ -212,10 +218,11 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
|
|||
continue;
|
||||
flags = *pnt++;
|
||||
|
||||
if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
|
||||
*sticky = 1;
|
||||
if (CHECK_FLAG(flags,
|
||||
ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY))
|
||||
SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
|
||||
else
|
||||
*sticky = 0;
|
||||
UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
|
||||
|
||||
pnt++;
|
||||
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
|
||||
*/
|
||||
void bgp_attr_evpn_na_flag(struct attr *attr,
|
||||
uint8_t *router_flag, bool *proxy)
|
||||
void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy)
|
||||
{
|
||||
struct ecommunity *ecom;
|
||||
uint32_t i;
|
||||
|
@ -253,10 +259,12 @@ void bgp_attr_evpn_na_flag(struct attr *attr,
|
|||
sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) {
|
||||
val = *pnt++;
|
||||
|
||||
if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)
|
||||
*router_flag = 1;
|
||||
if (CHECK_FLAG(val,
|
||||
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;
|
||||
|
||||
break;
|
||||
|
|
|
@ -23,6 +23,7 @@ enum overlay_index_type {
|
|||
* MAC overlay index is stored in the RMAC attribute.
|
||||
*/
|
||||
struct bgp_route_evpn {
|
||||
unsigned long refcnt;
|
||||
enum overlay_index_type type;
|
||||
esi_t eth_s_id;
|
||||
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,
|
||||
struct prefix *dst);
|
||||
extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
|
||||
extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr,
|
||||
uint8_t *sticky);
|
||||
extern uint8_t bgp_attr_default_gw(struct attr *attr);
|
||||
extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr);
|
||||
extern void bgp_attr_default_gw(struct attr *attr);
|
||||
|
||||
extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag,
|
||||
bool *proxy);
|
||||
extern void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy);
|
||||
extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg);
|
||||
|
||||
|
||||
|
|
|
@ -934,9 +934,8 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
|
|||
stream_putw(s, 0);
|
||||
|
||||
/* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
|
||||
total_attr_len =
|
||||
bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi,
|
||||
safi, peer, NULL, NULL, 0, 0, 0, NULL);
|
||||
total_attr_len = bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi, safi, peer,
|
||||
NULL, NULL, 0, 0, 0);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
uint8_t bpi_num_labels;
|
||||
uint8_t bpi_num_labels, adjin_num_labels;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
|
@ -1241,11 +1240,12 @@ afibreak:
|
|||
bpi_num_labels ? bpi->extra->labels->label : NULL,
|
||||
bpi_num_labels);
|
||||
|
||||
if (adjin)
|
||||
/* TODO: set label here when adjin supports labels */
|
||||
bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE,
|
||||
bn_p, prd, adjin->attr, afi, safi, adjin->uptime,
|
||||
NULL, 0);
|
||||
if (adjin) {
|
||||
adjin_num_labels = adjin->labels ? adjin->labels->num_labels : 0;
|
||||
bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd,
|
||||
adjin->attr, afi, safi, adjin->uptime,
|
||||
adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels);
|
||||
}
|
||||
|
||||
if (bn)
|
||||
bgp_dest_unlock_node(bn);
|
||||
|
@ -1382,7 +1382,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
|
|||
struct peer *peer;
|
||||
struct bgp_dest *bn = NULL;
|
||||
bool written = false;
|
||||
uint8_t bpi_num_labels;
|
||||
uint8_t bpi_num_labels, adjin_num_labels;
|
||||
|
||||
bqe = bmp_pull(bmp);
|
||||
if (!bqe)
|
||||
|
@ -1453,10 +1453,11 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
|
|||
if (adjin->peer == peer)
|
||||
break;
|
||||
}
|
||||
/* TODO: set label here when adjin supports labels */
|
||||
bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE,
|
||||
&bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi,
|
||||
adjin ? adjin->uptime : monotime(NULL), NULL, 0);
|
||||
adjin_num_labels = adjin && adjin->labels ? adjin->labels->num_labels : 0;
|
||||
bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd,
|
||||
adjin ? adjin->attr : NULL, afi, safi,
|
||||
adjin ? adjin->uptime : monotime(NULL),
|
||||
adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels);
|
||||
written = true;
|
||||
}
|
||||
|
||||
|
@ -2543,9 +2544,9 @@ DEFPY(bmp_monitor_cfg, bmp_monitor_cmd,
|
|||
|
||||
prev = bt->afimon[afi][safi];
|
||||
if (no)
|
||||
bt->afimon[afi][safi] &= ~flag;
|
||||
UNSET_FLAG(bt->afimon[afi][safi], flag);
|
||||
else
|
||||
bt->afimon[afi][safi] |= flag;
|
||||
SET_FLAG(bt->afimon[afi][safi], flag);
|
||||
|
||||
if (prev == bt->afimon[afi][safi])
|
||||
return CMD_SUCCESS;
|
||||
|
@ -2743,7 +2744,7 @@ DEFPY(show_bmp,
|
|||
}
|
||||
out = ttable_dump(tt, "\n");
|
||||
vty_out(vty, "%s", out);
|
||||
XFREE(MTYPE_TMP, out);
|
||||
XFREE(MTYPE_TMP_TTABLE, out);
|
||||
ttable_del(tt);
|
||||
|
||||
vty_out(vty, "\n %zu connected clients:\n",
|
||||
|
@ -2770,7 +2771,7 @@ DEFPY(show_bmp,
|
|||
}
|
||||
out = ttable_dump(tt, "\n");
|
||||
vty_out(vty, "%s", out);
|
||||
XFREE(MTYPE_TMP, out);
|
||||
XFREE(MTYPE_TMP_TTABLE, out);
|
||||
ttable_del(tt);
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
@ -2828,8 +2829,7 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
|
|||
afi2str_lower(afi), safi2str(safi));
|
||||
}
|
||||
frr_each (bmp_listeners, &bt->listeners, bl)
|
||||
vty_out(vty, " \n bmp listener %pSU port %d\n",
|
||||
&bl->addr, bl->port);
|
||||
vty_out(vty, " bmp listener %pSU port %d\n", &bl->addr, bl->port);
|
||||
|
||||
frr_each (bmp_actives, &bt->actives, ba) {
|
||||
vty_out(vty, " bmp connect %s port %u min-retry %u max-retry %u",
|
||||
|
|
|
@ -69,7 +69,7 @@ static void attr_parse(struct stream *s, uint16_t len)
|
|||
flag = 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);
|
||||
else
|
||||
length = stream_getc(s);
|
||||
|
|
|
@ -182,7 +182,7 @@ community_list_insert(struct community_list_handler *ch, const char *name,
|
|||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Set access_list to number list. */
|
||||
|
@ -496,8 +496,8 @@ static char *community_str_get(struct community *com, int i)
|
|||
break;
|
||||
default:
|
||||
str = XSTRDUP(MTYPE_COMMUNITY_STR, "65536:65535");
|
||||
as = (comval >> 16) & 0xFFFF;
|
||||
val = comval & 0xFFFF;
|
||||
as = CHECK_FLAG((comval >> 16), 0xFFFF);
|
||||
val = CHECK_FLAG(comval, 0xFFFF);
|
||||
snprintf(str, strlen(str), "%u:%d", as, val);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
/* Number and string based community-list name. */
|
||||
#define COMMUNITY_LIST_STRING 0
|
||||
#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
|
||||
|
||||
|
|
|
@ -416,13 +416,12 @@ static void set_community_string(struct community *com, bool make_json,
|
|||
}
|
||||
break;
|
||||
default:
|
||||
as = (comval >> 16) & 0xFFFF;
|
||||
val = comval & 0xFFFF;
|
||||
as = CHECK_FLAG((comval >> 16), 0xFFFF);
|
||||
val = CHECK_FLAG(comval, 0xFFFF);
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%u:%d", as, val);
|
||||
const char *com2alias =
|
||||
translate_alias ? bgp_community2alias(buf)
|
||||
: buf;
|
||||
translate_alias ? bgp_community2alias(buf) : buf;
|
||||
|
||||
strlcat(str, com2alias, len);
|
||||
if (make_json) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
bgp = bgp_get_default();
|
||||
if (bgp == NULL) {
|
||||
|
||||
if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) {
|
||||
vty_out(vty, "No BGP process is configured\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
|
|
@ -2558,7 +2558,7 @@ static int bgp_debug_per_prefix(const struct prefix *p,
|
|||
struct bgp_debug_filter *filter;
|
||||
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 */
|
||||
if (!per_prefix_list || list_isempty(per_prefix_list))
|
||||
return 1;
|
||||
|
@ -2591,7 +2591,7 @@ static bool bgp_debug_per_peer(char *host, const struct prefix *p,
|
|||
struct bgp_debug_filter *filter;
|
||||
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 */
|
||||
if (!per_peer_list || list_isempty(per_peer_list))
|
||||
return true;
|
||||
|
|
|
@ -515,7 +515,7 @@ static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type,
|
|||
/* Fill in the values. */
|
||||
eval->val[0] = type;
|
||||
if (!trans)
|
||||
eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
|
||||
SET_FLAG(eval->val[0], ECOMMUNITY_FLAG_NON_TRANSITIVE);
|
||||
eval->val[1] = sub_type;
|
||||
if (type == ECOMMUNITY_ENCODE_AS) {
|
||||
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) {
|
||||
uint8_t flags = *++pnt;
|
||||
|
||||
snprintf(encbuf,
|
||||
sizeof(encbuf), "ESI-label-Rt:%s",
|
||||
(flags &
|
||||
ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG) ?
|
||||
"SA":"AA");
|
||||
snprintf(encbuf, sizeof(encbuf),
|
||||
"ESI-label-Rt:%s",
|
||||
CHECK_FLAG(flags,
|
||||
ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG)
|
||||
? "SA"
|
||||
: "AA");
|
||||
} else if (*pnt
|
||||
== ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION) {
|
||||
uint8_t alg;
|
||||
|
@ -1337,12 +1338,11 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
|
|||
char buf[ECOMMUNITY_STRLEN];
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ecommunity_rt_soo_str_internal(buf, sizeof(buf),
|
||||
(const uint8_t *)pnt,
|
||||
type &
|
||||
~ECOMMUNITY_ENCODE_TRANS_EXP,
|
||||
ECOMMUNITY_ROUTE_TARGET,
|
||||
format,
|
||||
ecommunity_rt_soo_str_internal(
|
||||
buf, sizeof(buf), (const uint8_t *)pnt,
|
||||
CHECK_FLAG(type,
|
||||
~ECOMMUNITY_ENCODE_TRANS_EXP),
|
||||
ECOMMUNITY_ROUTE_TARGET, format,
|
||||
ecom->unit_size);
|
||||
snprintf(encbuf, sizeof(encbuf), "%s", buf);
|
||||
} else if (sub_type ==
|
||||
|
@ -1350,10 +1350,10 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
|
|||
char buf[64];
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ecommunity_rt_soo_str_internal(buf, sizeof(buf),
|
||||
(const uint8_t *)pnt,
|
||||
type &
|
||||
~ECOMMUNITY_ENCODE_TRANS_EXP,
|
||||
ecommunity_rt_soo_str_internal(
|
||||
buf, sizeof(buf), (const uint8_t *)pnt,
|
||||
CHECK_FLAG(type,
|
||||
~ECOMMUNITY_ENCODE_TRANS_EXP),
|
||||
ECOMMUNITY_ROUTE_TARGET,
|
||||
ECOMMUNITY_FORMAT_DISPLAY,
|
||||
ecom->unit_size);
|
||||
|
@ -1363,10 +1363,10 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
|
|||
char buf[16];
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ecommunity_rt_soo_str(buf, sizeof(buf),
|
||||
(const uint8_t *)pnt,
|
||||
type &
|
||||
~ECOMMUNITY_ENCODE_TRANS_EXP,
|
||||
ecommunity_rt_soo_str(
|
||||
buf, sizeof(buf), (const uint8_t *)pnt,
|
||||
CHECK_FLAG(type,
|
||||
~ECOMMUNITY_ENCODE_TRANS_EXP),
|
||||
ECOMMUNITY_ROUTE_TARGET,
|
||||
ECOMMUNITY_FORMAT_DISPLAY);
|
||||
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) {
|
||||
api->action = ACTION_TRAFFIC_ACTION;
|
||||
/* else distribute code is set by default */
|
||||
if (ecom_eval->val[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL))
|
||||
api->u.za.filter |= TRAFFIC_ACTION_TERMINATE;
|
||||
if (CHECK_FLAG(ecom_eval->val[5],
|
||||
(1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL)))
|
||||
SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_TERMINATE);
|
||||
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)
|
||||
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) {
|
||||
api->action = ACTION_MARKING;
|
||||
|
@ -1940,7 +1941,7 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
|
|||
return new;
|
||||
|
||||
type = *eval;
|
||||
if (type & ECOMMUNITY_FLAG_NON_TRANSITIVE)
|
||||
if (CHECK_FLAG(type, ECOMMUNITY_FLAG_NON_TRANSITIVE))
|
||||
return new;
|
||||
|
||||
/* Transitive link-bandwidth exists, replace with the passed
|
||||
|
|
|
@ -155,12 +155,12 @@ struct ecommunity_ip6 {
|
|||
|
||||
/* Extended community value is eight octet. */
|
||||
struct ecommunity_val {
|
||||
char val[ECOMMUNITY_SIZE];
|
||||
uint8_t val[ECOMMUNITY_SIZE];
|
||||
};
|
||||
|
||||
/* IPv6 Extended community value is eight octet. */
|
||||
struct ecommunity_val_ipv6 {
|
||||
char val[IPV6_ECOMMUNITY_SIZE];
|
||||
uint8_t val[IPV6_ECOMMUNITY_SIZE];
|
||||
};
|
||||
|
||||
#define ecom_length_size(X, Y) ((X)->size * (Y))
|
||||
|
|
320
bgpd/bgp_evpn.c
320
bgpd/bgp_evpn.c
|
@ -117,7 +117,7 @@ int vni_list_cmp(void *p1, void *p2)
|
|||
static unsigned int vrf_import_rt_hash_key_make(const void *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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
const struct irt_node *irt = p;
|
||||
const char *pnt = irt->rt.val;
|
||||
const uint8_t *pnt = irt->rt.val;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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. */
|
||||
if (attr->sticky) {
|
||||
if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY)) {
|
||||
seqnum = 0;
|
||||
memset(&ecom_sticky, 0, sizeof(ecom_sticky));
|
||||
encode_mac_mobility_extcomm(1, seqnum, &eval_sticky);
|
||||
ecom_sticky.size = 1;
|
||||
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. */
|
||||
if (attr->default_gw) {
|
||||
memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
|
||||
if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) {
|
||||
encode_default_gw_extcomm(&eval_default_gw);
|
||||
ecom_default_gw.size = 1;
|
||||
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);
|
||||
if (attr->router_flag || proxy) {
|
||||
memset(&ecom_na, 0, sizeof(ecom_na));
|
||||
encode_na_flag_extcomm(&eval_na, attr->router_flag, proxy);
|
||||
if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER) || proxy) {
|
||||
encode_na_flag_extcomm(&eval_na,
|
||||
CHECK_FLAG(attr->evpn_flags,
|
||||
ATTR_EVPN_FLAG_ROUTER),
|
||||
proxy);
|
||||
ecom_na.size = 1;
|
||||
ecom_na.unit_size = ECOMMUNITY_SIZE;
|
||||
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;
|
||||
|
||||
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);
|
||||
if (pi->attr->default_gw)
|
||||
if (CHECK_FLAG(pi->attr->evpn_flags,
|
||||
ATTR_EVPN_FLAG_DEFAULT_GW))
|
||||
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
|
||||
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);
|
||||
|
||||
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
|
||||
*/
|
||||
if (is_evpn_prefix_ipaddr_v6(p) &&
|
||||
(pi->attr->es_flags &
|
||||
ATTR_ES_PEER_ROUTER))
|
||||
CHECK_FLAG(pi->attr->es_flags, ATTR_ES_PEER_ROUTER))
|
||||
SET_FLAG(flags,
|
||||
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,
|
||||
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_path_info *local_pi = NULL;
|
||||
struct bgp_path_info *tmp_pi = NULL;
|
||||
struct aspath *new_aspath;
|
||||
struct attr static_attr = { 0 };
|
||||
|
||||
*route_changed = 0;
|
||||
|
||||
/* 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);
|
||||
|
||||
static_attr = *attr;
|
||||
|
||||
/*
|
||||
* create a new route entry if one doesn't exist.
|
||||
* 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_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. */
|
||||
attr_new = bgp_attr_intern(attr);
|
||||
attr_new = bgp_attr_intern(&static_attr);
|
||||
bgp_attr_flush(&static_attr);
|
||||
|
||||
/* create the route info from attribute */
|
||||
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)) {
|
||||
if (src_attr &&
|
||||
!IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) {
|
||||
attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
|
||||
SET_IPADDR_V6(&attr.evpn_overlay.gw_ip);
|
||||
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6,
|
||||
struct bgp_route_evpn *bre =
|
||||
XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
|
||||
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,
|
||||
sizeof(struct in6_addr));
|
||||
bgp_attr_set_evpn_overlay(&attr, bre);
|
||||
}
|
||||
} else if (src_afi == AFI_IP &&
|
||||
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) {
|
||||
if (src_attr && src_attr->nexthop.s_addr != 0) {
|
||||
attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
|
||||
SET_IPADDR_V4(&attr.evpn_overlay.gw_ip);
|
||||
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4,
|
||||
&src_attr->nexthop, sizeof(struct in_addr));
|
||||
struct bgp_route_evpn *bre =
|
||||
XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
|
||||
sizeof(struct bgp_route_evpn));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (second_best_path->attr->router_flag)
|
||||
if (CHECK_FLAG(second_best_path->attr->evpn_flags,
|
||||
ATTR_EVPN_FLAG_ROUTER))
|
||||
*peer_router = true;
|
||||
|
||||
/* 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);
|
||||
attr->mm_sync_seqnum = max_sync_seq;
|
||||
if (active_on_peer)
|
||||
attr->es_flags |= ATTR_ES_PEER_ACTIVE;
|
||||
SET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE);
|
||||
else
|
||||
attr->es_flags &= ~ATTR_ES_PEER_ACTIVE;
|
||||
UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE);
|
||||
if (proxy_from_peer)
|
||||
attr->es_flags |= ATTR_ES_PEER_PROXY;
|
||||
SET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY);
|
||||
else
|
||||
attr->es_flags &= ~ATTR_ES_PEER_PROXY;
|
||||
UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY);
|
||||
if (peer_router)
|
||||
attr->es_flags |= ATTR_ES_PEER_ROUTER;
|
||||
SET_FLAG(attr->es_flags, ATTR_ES_PEER_ROUTER);
|
||||
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)) {
|
||||
char esi_buf[ESI_STR_LEN];
|
||||
|
||||
zlog_debug(
|
||||
"setup sync info for %pFX es %s max_seq %d %s%s%s",
|
||||
zlog_debug("setup sync info for %pFX es %s max_seq %d %s%s%s",
|
||||
evp,
|
||||
esi_to_str(esi, esi_buf,
|
||||
sizeof(esi_buf)),
|
||||
max_sync_seq,
|
||||
(attr->es_flags & ATTR_ES_PEER_ACTIVE)
|
||||
CHECK_FLAG(attr->es_flags,
|
||||
ATTR_ES_PEER_ACTIVE)
|
||||
? "peer-active "
|
||||
: "",
|
||||
(attr->es_flags & ATTR_ES_PEER_PROXY)
|
||||
CHECK_FLAG(attr->es_flags,
|
||||
ATTR_ES_PEER_PROXY)
|
||||
? "peer-proxy "
|
||||
: "",
|
||||
(attr->es_flags & ATTR_ES_PEER_ROUTER)
|
||||
CHECK_FLAG(attr->es_flags,
|
||||
ATTR_ES_PEER_ROUTER)
|
||||
? "peer-router "
|
||||
: "");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
attr->mm_sync_seqnum = 0;
|
||||
attr->es_flags &= ~ATTR_ES_PEER_ACTIVE;
|
||||
attr->es_flags &= ~ATTR_ES_PEER_PROXY;
|
||||
UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE);
|
||||
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 bgp_labels bgp_labels = {};
|
||||
int route_change = 1;
|
||||
uint8_t sticky = 0;
|
||||
const struct prefix_evpn *evp;
|
||||
|
||||
*pi = NULL;
|
||||
|
@ -1972,9 +2001,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
|||
local_attr = *attr;
|
||||
|
||||
/* Extract MAC mobility sequence number, if any. */
|
||||
local_attr.mm_seqnum =
|
||||
bgp_attr_mac_mobility_seqnum(&local_attr, &sticky);
|
||||
local_attr.sticky = sticky;
|
||||
local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(&local_attr);
|
||||
|
||||
/* Add (or update) attribute to hash. */
|
||||
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);
|
||||
|
||||
/* Extract MAC mobility sequence number, if any. */
|
||||
local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(
|
||||
&local_attr, &sticky);
|
||||
local_attr.sticky = sticky;
|
||||
local_attr.mm_seqnum =
|
||||
bgp_attr_mac_mobility_seqnum(&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 &&
|
||||
(curr_select->sub_type == BGP_ROUTE_IMPORTED ||
|
||||
bgp_evpn_attr_is_sync(curr_select->attr))) {
|
||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
|
||||
evpn_zebra_install(bgp, vpn,
|
||||
(const struct prefix_evpn *)
|
||||
bgp_dest_get_prefix(
|
||||
dest),
|
||||
bgp_dest_get_prefix(dest),
|
||||
curr_select);
|
||||
else
|
||||
bgp_zebra_route_install(dest, curr_select, bgp,
|
||||
true, vpn, false);
|
||||
bgp_zebra_route_install(dest, curr_select, bgp, true,
|
||||
vpn, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2204,21 +2226,23 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
|
|||
attr.nexthop = vpn->originator_ip;
|
||||
attr.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0;
|
||||
attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0;
|
||||
attr.router_flag = CHECK_FLAG(flags,
|
||||
ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0;
|
||||
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY))
|
||||
SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_STICKY);
|
||||
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW))
|
||||
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))
|
||||
attr.es_flags |= ATTR_ES_PROXY_ADVERT;
|
||||
SET_FLAG(attr.es_flags, ATTR_ES_PROXY_ADVERT);
|
||||
|
||||
if (esi && bgp_evpn_is_esi_valid(esi)) {
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* these routes.
|
||||
*/
|
||||
add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok(
|
||||
vpn, p, (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL);
|
||||
add_l3_ecomm =
|
||||
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)
|
||||
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.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr.sticky = (local_pi->attr->sticky) ? 1 : 0;
|
||||
attr.router_flag = (local_pi->attr->router_flag) ? 1 : 0;
|
||||
attr.evpn_flags = local_pi->attr->evpn_flags;
|
||||
attr.es_flags = local_pi->attr->es_flags;
|
||||
if (local_pi->attr->default_gw) {
|
||||
attr.default_gw = 1;
|
||||
if (CHECK_FLAG(local_pi->attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) {
|
||||
SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
|
||||
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));
|
||||
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
|
||||
* using L3 VNI for type-2 routes also.
|
||||
*/
|
||||
add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok(
|
||||
vpn, &evp,
|
||||
(attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL);
|
||||
add_l3_ecomm =
|
||||
bgp_evpn_route_add_l3_ecomm_ok(vpn, &evp,
|
||||
CHECK_FLAG(attr.es_flags,
|
||||
ATTR_ES_IS_LOCAL)
|
||||
? &attr.esi
|
||||
: NULL);
|
||||
|
||||
if (bgp->evpn_info)
|
||||
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 is_l3nhg_active = false;
|
||||
char buf1[INET6_ADDRSTRLEN];
|
||||
struct bgp_route_evpn *bre;
|
||||
|
||||
memset(pp, 0, sizeof(struct prefix));
|
||||
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.
|
||||
*/
|
||||
attr = *parent_pi->attr;
|
||||
if (attr.evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP) {
|
||||
if (afi == AFI_IP6)
|
||||
evpn_convert_nexthop_to_ipv6(&attr);
|
||||
else {
|
||||
attr.nexthop = attr.mp_nexthop_global_in;
|
||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
|
||||
}
|
||||
} else {
|
||||
|
||||
bre = bgp_attr_get_evpn_overlay(&attr);
|
||||
if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
|
||||
/*
|
||||
* If gateway IP overlay index is specified in the NLRI of
|
||||
* EVPN RT-5, this gateway IP should be used as the nexthop
|
||||
* for the prefix in the VRF
|
||||
*/
|
||||
if (bgp_debug_zebra(NULL)) {
|
||||
zlog_debug(
|
||||
"Install gateway IP %s as nexthop for prefix %pFX in vrf %s",
|
||||
inet_ntop(pp->family, &attr.evpn_overlay.gw_ip,
|
||||
buf1, sizeof(buf1)), pp,
|
||||
vrf_id_to_name(bgp_vrf->vrf_id));
|
||||
zlog_debug("Install gateway IP %s as nexthop for prefix %pFX in vrf %s",
|
||||
inet_ntop(pp->family, &bre->gw_ip, buf1,
|
||||
sizeof(buf1)),
|
||||
pp, vrf_id_to_name(bgp_vrf->vrf_id));
|
||||
}
|
||||
|
||||
if (afi == AFI_IP6) {
|
||||
memcpy(&attr.mp_nexthop_global,
|
||||
&attr.evpn_overlay.gw_ip.ipaddr_v6,
|
||||
memcpy(&attr.mp_nexthop_global, &bre->gw_ip.ipaddr_v6,
|
||||
sizeof(struct in6_addr));
|
||||
attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
|
||||
} else {
|
||||
attr.nexthop = attr.evpn_overlay.gw_ip.ipaddr_v4;
|
||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
|
||||
attr.nexthop = bre->gw_ip.ipaddr_v4;
|
||||
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,
|
||||
&is_l3nhg_active, NULL);
|
||||
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)
|
||||
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. */
|
||||
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 */
|
||||
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,
|
||||
NULL, 0, NULL))
|
||||
bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
|
||||
else {
|
||||
if (BGP_DEBUG(nht, NHT)) {
|
||||
inet_ntop(pp->family,
|
||||
&attr.evpn_overlay.gw_ip,
|
||||
buf1, sizeof(buf1));
|
||||
inet_ntop(pp->family, &bre->gw_ip, buf1,
|
||||
sizeof(buf1));
|
||||
zlog_debug("%s: gateway IP NH unresolved",
|
||||
buf1);
|
||||
}
|
||||
bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID);
|
||||
}
|
||||
} else {
|
||||
|
||||
/* as it is an importation, change nexthop */
|
||||
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))
|
||||
zlog_debug("VNI %d path %pFX chg to %s es",
|
||||
vpn->vni, &pi->net->rn->p,
|
||||
new_local_es ? "local"
|
||||
: "non-local");
|
||||
new_local_es ? "local" : "non-local");
|
||||
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
|
||||
* to zebra, if appropriate.
|
||||
*/
|
||||
static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
||||
const struct prefix_evpn *evp,
|
||||
int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, const struct prefix_evpn *evp,
|
||||
struct bgp_path_info *parent_pi)
|
||||
{
|
||||
struct bgp_dest *dest;
|
||||
|
@ -3631,7 +3656,7 @@ static int is_route_matching_for_vrf(struct bgp *bgp_vrf,
|
|||
|
||||
assert(attr);
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
/* 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;
|
||||
|
||||
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 */
|
||||
static inline bool
|
||||
bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf,
|
||||
const struct prefix_evpn *evp,
|
||||
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)
|
||||
{
|
||||
esi_t *esi;
|
||||
|
@ -4200,7 +4223,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
|
|||
return 0;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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_evpn p = {};
|
||||
struct bgp_route_evpn evpn = {};
|
||||
uint8_t ipaddr_len;
|
||||
uint8_t macaddr_len;
|
||||
/* 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));
|
||||
|
||||
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
|
||||
attr->es_flags &= ~ATTR_ES_IS_LOCAL;
|
||||
UNSET_FLAG(attr->es_flags, ATTR_ES_IS_LOCAL);
|
||||
} else {
|
||||
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)
|
||||
bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
|
||||
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
|
||||
&label[0], num_labels, 0, &evpn);
|
||||
&label[0], num_labels, 0, NULL);
|
||||
else
|
||||
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label[0],
|
||||
num_labels, &evpn);
|
||||
num_labels);
|
||||
goto done;
|
||||
|
||||
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
|
||||
* doing anything else is better.
|
||||
*/
|
||||
if (attr &&
|
||||
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
|
||||
if (attr && CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
|
||||
enum pta_type pmsi_tnl_type = bgp_attr_get_pmsi_tnl_type(attr);
|
||||
|
||||
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);
|
||||
else
|
||||
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
|
||||
NULL);
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 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_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;
|
||||
uint32_t eth_tag;
|
||||
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,
|
||||
"%u:%s - Rx EVPN Type-5 NLRI with invalid length %d",
|
||||
peer->bgp->vrf_id, peer->host, psize);
|
||||
evpn_overlay_free(evpn);
|
||||
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.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 */
|
||||
if (attr)
|
||||
memcpy(&evpn.eth_s_id, pfx, sizeof(esi_t));
|
||||
memcpy(&evpn->eth_s_id, pfx, sizeof(esi_t));
|
||||
pfx += ESI_BYTES;
|
||||
|
||||
/* 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,
|
||||
"%u:%s - Rx EVPN Type-5 NLRI with invalid IP Prefix length %d",
|
||||
peer->bgp->vrf_id, peer->host, ippfx_len);
|
||||
evpn_overlay_free(evpn);
|
||||
return -1;
|
||||
}
|
||||
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);
|
||||
memcpy(&p.prefix.prefix_addr.ip.ipaddr_v4, pfx, 4);
|
||||
pfx += 4;
|
||||
SET_IPADDR_V4(&evpn.gw_ip);
|
||||
memcpy(&evpn.gw_ip.ipaddr_v4, pfx, 4);
|
||||
SET_IPADDR_V4(&evpn->gw_ip);
|
||||
memcpy(&evpn->gw_ip.ipaddr_v4, pfx, 4);
|
||||
pfx += 4;
|
||||
} else {
|
||||
SET_IPADDR_V6(&p.prefix.prefix_addr.ip);
|
||||
memcpy(&p.prefix.prefix_addr.ip.ipaddr_v6, pfx,
|
||||
IPV6_MAX_BYTELEN);
|
||||
pfx += IPV6_MAX_BYTELEN;
|
||||
SET_IPADDR_V6(&evpn.gw_ip);
|
||||
memcpy(&evpn.gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN);
|
||||
SET_IPADDR_V6(&evpn->gw_ip);
|
||||
memcpy(&evpn->gw_ip.ipaddr_v6, 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
|
||||
* at the same time is should be treated as withdraw
|
||||
*/
|
||||
if (bgp_evpn_is_esi_valid(&evpn.eth_s_id) &&
|
||||
!ipaddr_is_zero(&evpn.gw_ip)) {
|
||||
if (bgp_evpn_is_esi_valid(&evpn->eth_s_id) &&
|
||||
!ipaddr_is_zero(&evpn->gw_ip)) {
|
||||
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
|
||||
"%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.",
|
||||
peer->host);
|
||||
is_valid_update = false;
|
||||
} else if (bgp_evpn_is_esi_valid(&evpn.eth_s_id))
|
||||
evpn.type = OVERLAY_INDEX_ESI;
|
||||
else if (!ipaddr_is_zero(&evpn.gw_ip))
|
||||
evpn.type = OVERLAY_INDEX_GATEWAY_IP;
|
||||
} else if (bgp_evpn_is_esi_valid(&evpn->eth_s_id))
|
||||
evpn->type = OVERLAY_INDEX_ESI;
|
||||
else if (!ipaddr_is_zero(&evpn->gw_ip))
|
||||
evpn->type = OVERLAY_INDEX_GATEWAY_IP;
|
||||
if (attr) {
|
||||
if (is_zero_mac(&attr->rmac) &&
|
||||
!bgp_evpn_is_esi_valid(&evpn.eth_s_id) &&
|
||||
ipaddr_is_zero(&evpn.gw_ip) && label == 0) {
|
||||
!bgp_evpn_is_esi_valid(&evpn->eth_s_id) &&
|
||||
ipaddr_is_zero(&evpn->gw_ip) && label == 0) {
|
||||
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
|
||||
"%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero",
|
||||
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)
|
||||
bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
|
||||
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
|
||||
&label, 1, 0, &evpn);
|
||||
&label, 1, 0, evpn);
|
||||
else {
|
||||
if (!is_valid_update) {
|
||||
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);
|
||||
}
|
||||
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1,
|
||||
&evpn);
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1);
|
||||
evpn_overlay_free(evpn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -5043,12 +5063,16 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
|
|||
int len;
|
||||
char temp[16];
|
||||
const struct evpn_addr *p_evpn_p;
|
||||
struct bgp_route_evpn *bre = NULL;
|
||||
|
||||
memset(&temp, 0, sizeof(temp));
|
||||
if (p->family != AF_EVPN)
|
||||
return;
|
||||
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
|
||||
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 */
|
||||
stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
|
||||
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));
|
||||
else
|
||||
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);
|
||||
else
|
||||
stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16);
|
||||
if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
|
||||
const struct bgp_route_evpn *evpn_overlay =
|
||||
bgp_attr_get_evpn_overlay(attr);
|
||||
|
||||
if (attr && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
|
||||
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
|
||||
stream_put_ipv4(s,
|
||||
evpn_overlay->gw_ip.ipaddr_v4.s_addr);
|
||||
stream_put_ipv4(s, bre->gw_ip.ipaddr_v4.s_addr);
|
||||
else
|
||||
stream_put(s, &(evpn_overlay->gw_ip.ipaddr_v6), 16);
|
||||
stream_put(s, &(bre->gw_ip.ipaddr_v6), 16);
|
||||
} else {
|
||||
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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.
|
||||
* Set nexthop as valid only if it is already L3 reachable
|
||||
*/
|
||||
if (resolve && bnc->flags & BGP_NEXTHOP_EVPN_INCOMPLETE) {
|
||||
bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
|
||||
bnc->flags |= BGP_NEXTHOP_VALID;
|
||||
bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
|
||||
if (resolve && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) {
|
||||
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
|
||||
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
|
||||
SET_FLAG(bnc->change_flags, BGP_NEXTHOP_MACIP_CHANGED);
|
||||
evaluate_paths(bnc);
|
||||
}
|
||||
|
||||
/* MAC/IP route or SVI or tenant vrf being deleted from EVI */
|
||||
if (!resolve && bnc->flags & BGP_NEXTHOP_VALID) {
|
||||
bnc->flags &= ~BGP_NEXTHOP_VALID;
|
||||
bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE;
|
||||
bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
|
||||
if (!resolve && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
|
||||
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
|
||||
SET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
|
||||
SET_FLAG(bnc->change_flags, BGP_NEXTHOP_MACIP_CHANGED);
|
||||
evaluate_paths(bnc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,4 +195,8 @@ extern enum zclient_send_status
|
|||
evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
const struct prefix_evpn *p, struct bgp_path_info *pi,
|
||||
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 */
|
||||
|
|
|
@ -770,8 +770,7 @@ int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi,
|
|||
0, 0, NULL);
|
||||
} else {
|
||||
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
|
||||
NULL);
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 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);
|
||||
} else {
|
||||
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
|
||||
NULL);
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 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;
|
||||
}
|
||||
|
||||
if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
|
||||
flags |= ZAPI_ES_VTEP_FLAG_ESR_RXED;
|
||||
if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
|
||||
SET_FLAG(flags, ZAPI_ES_VTEP_FLAG_ESR_RXED);
|
||||
|
||||
s = zclient->obuf;
|
||||
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)
|
||||
{
|
||||
if ((es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))
|
||||
|| listcount(es->macip_evi_path_list)
|
||||
|| listcount(es->macip_global_path_list))
|
||||
if (CHECK_FLAG(es->flags, (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) ||
|
||||
listcount(es->macip_evi_path_list) ||
|
||||
listcount(es->macip_global_path_list))
|
||||
return;
|
||||
|
||||
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)
|
||||
{
|
||||
return (es->flags & BGP_EVPNES_LOCAL)
|
||||
&& !(es->flags & BGP_EVPNES_BYPASS);
|
||||
return CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL) &&
|
||||
!CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
return (!es || !(es->flags & BGP_EVPNES_LOCAL)
|
||||
|| bgp_evpn_local_es_is_active(es));
|
||||
return (!es || !CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL) ||
|
||||
bgp_evpn_local_es_is_active(es));
|
||||
}
|
||||
|
||||
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;
|
||||
if (is_local)
|
||||
attr_tmp.es_flags |= ATTR_ES_IS_LOCAL;
|
||||
SET_FLAG(attr_tmp.es_flags, ATTR_ES_IS_LOCAL);
|
||||
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);
|
||||
bgp_attr_unintern(&pi->attr);
|
||||
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)) {
|
||||
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));
|
||||
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));
|
||||
|
||||
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",
|
||||
&es_vtep->vtep_ip);
|
||||
if (es_vtep->flags & (BGP_EVPNES_VTEP_ESR |
|
||||
BGP_EVPNES_VTEP_ACTIVE)) {
|
||||
if (CHECK_FLAG(es_vtep->flags,
|
||||
(BGP_EVPNES_VTEP_ESR | BGP_EVPNES_VTEP_ACTIVE))) {
|
||||
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");
|
||||
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_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",
|
||||
es_vtep->df_pref);
|
||||
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)) {
|
||||
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));
|
||||
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));
|
||||
|
||||
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,
|
||||
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",
|
||||
evpn_es_df_alg2str(es_vtep->df_alg, 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",
|
||||
&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();
|
||||
if (es->flags & BGP_EVPNES_LOCAL)
|
||||
if (CHECK_FLAG(es->flags, BGP_EVPNES_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_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];
|
||||
|
||||
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));
|
||||
if (es->flags & BGP_EVPNES_LOCAL)
|
||||
if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
|
||||
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));
|
||||
if (es->inconsistencies)
|
||||
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 */
|
||||
bgp_evpn_es_show_entry(vty, es, json);
|
||||
if (es->flags
|
||||
& (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI
|
||||
| BGP_EVPNES_BYPASS)) {
|
||||
if (CHECK_FLAG(es->flags,
|
||||
(BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI |
|
||||
BGP_EVPNES_BYPASS))) {
|
||||
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");
|
||||
if (es->flags & BGP_EVPNES_ADV_EVI)
|
||||
if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
|
||||
json_array_string_add(json_flags,
|
||||
"advertiseEVI");
|
||||
if (es->flags & BGP_EVPNES_BYPASS)
|
||||
if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS))
|
||||
json_array_string_add(json_flags, "bypass");
|
||||
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));
|
||||
json_object_int_add(json, "inconsistentVniVtepCount",
|
||||
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",
|
||||
es->df_pref);
|
||||
if (listcount(es->es_vtep_list)) {
|
||||
|
@ -2673,7 +2672,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
|
|||
}
|
||||
if (es->inconsistencies) {
|
||||
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,
|
||||
"vni-vtep-mismatch");
|
||||
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];
|
||||
|
||||
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));
|
||||
if (es->flags & BGP_EVPNES_REMOTE)
|
||||
if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
|
||||
strlcat(type_str, "R", sizeof(type_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",
|
||||
es->es_base_frag ? &es->es_base_frag->prd : NULL);
|
||||
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",
|
||||
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, " VNI Count: %d\n", listcount(es->es_evi_list));
|
||||
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);
|
||||
if (es->inconsistencies) {
|
||||
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",
|
||||
sizeof(incons_str));
|
||||
} 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)
|
||||
{
|
||||
if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
|
||||
if (!CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE))
|
||||
return;
|
||||
|
||||
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->nhg_id);
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) {
|
||||
if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE)) {
|
||||
if (!update)
|
||||
return;
|
||||
} 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",
|
||||
es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_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 */
|
||||
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;
|
||||
|
||||
*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;
|
||||
if (es_vrf_p)
|
||||
*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, "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();
|
||||
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_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];
|
||||
|
||||
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));
|
||||
|
||||
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;
|
||||
|
||||
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 */
|
||||
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_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);
|
||||
else
|
||||
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
|
||||
* 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;
|
||||
bgp_evpn_es_frag_evi_del(es_evi, false);
|
||||
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_local_es_evi_unistall_local_routes_in_vrfs(es, es_evi);
|
||||
/* update EAD-ES */
|
||||
if (bgp_evpn_local_es_is_active(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 */
|
||||
for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list, node, nnode,
|
||||
evi_vtep)) {
|
||||
evi_vtep->flags &= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES
|
||||
| BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
|
||||
UNSET_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
|
||||
BGP_EVPN_EVI_VTEP_EAD_PER_EVI));
|
||||
bgp_evpn_es_evi_vtep_re_eval_active(bgp, 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';
|
||||
for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
|
||||
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));
|
||||
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));
|
||||
|
||||
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",
|
||||
&evi_vtep->vtep_ip);
|
||||
if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
|
||||
BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) {
|
||||
if (CHECK_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
|
||||
BGP_EVPN_EVI_VTEP_EAD_PER_EVI))) {
|
||||
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");
|
||||
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_object_object_add(json_vtep_entry,
|
||||
"flags", json_flags);
|
||||
|
@ -4035,12 +4039,12 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
|
|||
if (es_evi->vpn)
|
||||
json_object_int_add(json, "vni", es_evi->vpn->vni);
|
||||
|
||||
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))) {
|
||||
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");
|
||||
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_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];
|
||||
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
|
||||
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",
|
||||
BGP_RD_AS_FORMAT(mode),
|
||||
&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_array_string_add(json_flags, "es-vtep-mismatch");
|
||||
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];
|
||||
|
||||
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));
|
||||
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));
|
||||
|
||||
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, " Inconsistencies: %s\n",
|
||||
(es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
|
||||
"es-vtep-mismatch":"-");
|
||||
CHECK_FLAG(es_evi->flags,
|
||||
BGP_EVPNES_EVI_INCONS_VTEP_LIST)
|
||||
? "es-vtep-mismatch"
|
||||
: "-");
|
||||
vty_out(vty, " VTEPs: %s\n", vtep_str);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
if (!(nh->flags & BGP_EVPN_NH_READY_FOR_ZEBRA))
|
||||
if (!CHECK_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA))
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
* 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)
|
||||
bgp_evpn_path_nh_unlink(nh_info);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_mh_config_ead_export_rt(struct bgp *bgp,
|
||||
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 */
|
||||
|
|
|
@ -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,
|
||||
uint8_t na_flag, bool proxy)
|
||||
bool na_flag, bool proxy)
|
||||
{
|
||||
memset(eval, 0, sizeof(*eval));
|
||||
eval->val[0] = ECOMMUNITY_ENCODE_EVPN;
|
||||
|
|
|
@ -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. */
|
||||
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. */
|
||||
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. */
|
||||
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);
|
||||
|
||||
|
@ -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. */
|
||||
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)
|
||||
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++;
|
||||
}
|
||||
|
||||
if (json && path_cnt) {
|
||||
if (json) {
|
||||
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);
|
||||
} else {
|
||||
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. */
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, dest, bgp_dest_get_prefix(dest), prd,
|
||||
afi, safi, json_prefix, false);
|
||||
route_vty_out_detail_header(vty, bgp, dest,
|
||||
bgp_dest_get_prefix(dest),
|
||||
prd, afi, safi, json_prefix,
|
||||
false, false);
|
||||
|
||||
prefix_cnt++;
|
||||
}
|
||||
|
@ -3042,9 +3043,10 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
|
|||
p->prefixlen);
|
||||
} else
|
||||
/* Prefix and num paths displayed once per prefix. */
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, dest, p, (struct prefix_rd *)rd_destp,
|
||||
AFI_L2VPN, SAFI_EVPN, json_prefix, false);
|
||||
route_vty_out_detail_header(vty, bgp, dest, p,
|
||||
(struct prefix_rd *)rd_destp,
|
||||
AFI_L2VPN, SAFI_EVPN,
|
||||
json_prefix, false, false);
|
||||
|
||||
/* For EVPN, the prefix is displayed for each path (to
|
||||
* 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. */
|
||||
if (detail)
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, dest,
|
||||
bgp_dest_get_prefix(dest),
|
||||
(struct prefix_rd *)rd_destp, AFI_L2VPN,
|
||||
SAFI_EVPN, json_prefix, false);
|
||||
route_vty_out_detail_header(vty, bgp, dest,
|
||||
bgp_dest_get_prefix(
|
||||
dest),
|
||||
(struct prefix_rd *)
|
||||
rd_destp,
|
||||
AFI_L2VPN, SAFI_EVPN,
|
||||
json_prefix, false,
|
||||
false);
|
||||
|
||||
/* For EVPN, the prefix is displayed for each path (to
|
||||
* fit in
|
||||
|
@ -4840,7 +4845,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
|
|||
char *vrf = NULL;
|
||||
char *neighbor = NULL;
|
||||
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;
|
||||
|
||||
if (argv_find(argv, argc, "vrf", &idx_vrf))
|
||||
|
|
|
@ -195,7 +195,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
|
|||
NULL, 0, 0, NULL);
|
||||
} else {
|
||||
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);
|
||||
|
|
|
@ -305,14 +305,14 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
|
|||
break;
|
||||
mval->value = value;
|
||||
if (op[5] == 1)
|
||||
mval->compare_operator |=
|
||||
OPERATOR_COMPARE_LESS_THAN;
|
||||
SET_FLAG(mval->compare_operator,
|
||||
OPERATOR_COMPARE_LESS_THAN);
|
||||
if (op[6] == 1)
|
||||
mval->compare_operator |=
|
||||
OPERATOR_COMPARE_GREATER_THAN;
|
||||
SET_FLAG(mval->compare_operator,
|
||||
OPERATOR_COMPARE_GREATER_THAN);
|
||||
if (op[7] == 1)
|
||||
mval->compare_operator |=
|
||||
OPERATOR_COMPARE_EQUAL_TO;
|
||||
SET_FLAG(mval->compare_operator,
|
||||
OPERATOR_COMPARE_EQUAL_TO);
|
||||
if (op[1] == 1)
|
||||
mval->unary_operator = OPERATOR_UNARY_AND;
|
||||
else
|
||||
|
@ -413,16 +413,16 @@ int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
|
|||
mval->value = value;
|
||||
if (op[6] == 1) {
|
||||
/* different from */
|
||||
mval->compare_operator |=
|
||||
OPERATOR_COMPARE_LESS_THAN;
|
||||
mval->compare_operator |=
|
||||
OPERATOR_COMPARE_GREATER_THAN;
|
||||
SET_FLAG(mval->compare_operator,
|
||||
OPERATOR_COMPARE_LESS_THAN);
|
||||
SET_FLAG(mval->compare_operator,
|
||||
OPERATOR_COMPARE_GREATER_THAN);
|
||||
} else
|
||||
mval->compare_operator |=
|
||||
OPERATOR_COMPARE_EQUAL_TO;
|
||||
SET_FLAG(mval->compare_operator,
|
||||
OPERATOR_COMPARE_EQUAL_TO);
|
||||
if (op[7] == 1)
|
||||
mval->compare_operator |=
|
||||
OPERATOR_COMPARE_EXACT_MATCH;
|
||||
SET_FLAG(mval->compare_operator,
|
||||
OPERATOR_COMPARE_EXACT_MATCH);
|
||||
if (op[1] == 1)
|
||||
mval->unary_operator =
|
||||
OPERATOR_UNARY_AND;
|
||||
|
@ -467,11 +467,11 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
|
|||
case FLOWSPEC_SRC_PREFIX:
|
||||
bitmask = 0;
|
||||
if (type == FLOWSPEC_DEST_PREFIX) {
|
||||
bitmask |= PREFIX_DST_PRESENT;
|
||||
SET_FLAG(bitmask, PREFIX_DST_PRESENT);
|
||||
prefix = &bpem->dst_prefix;
|
||||
prefix_offset = &bpem->dst_prefix_offset;
|
||||
} else {
|
||||
bitmask |= PREFIX_SRC_PRESENT;
|
||||
SET_FLAG(bitmask, PREFIX_SRC_PRESENT);
|
||||
prefix = &bpem->src_prefix;
|
||||
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
|
||||
&& 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
|
||||
&& !memcmp(&prefix->u.prefix6,
|
||||
&in6addr_any,
|
||||
sizeof(struct in6_addr)))
|
||||
bpem->match_bitmask_iprule |= bitmask;
|
||||
SET_FLAG(bpem->match_bitmask_iprule,
|
||||
bitmask);
|
||||
else
|
||||
bpem->match_bitmask |= bitmask;
|
||||
SET_FLAG(bpem->match_bitmask, bitmask);
|
||||
}
|
||||
offset += ret;
|
||||
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_bitmask || bpem->match_flowlabel_num)
|
||||
bpem->type = BGP_PBR_IPSET;
|
||||
else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) ||
|
||||
(bpem->match_bitmask_iprule & PREFIX_DST_PRESENT))
|
||||
else if (CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_SRC_PRESENT) ||
|
||||
CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_DST_PRESENT))
|
||||
/* the extracted policy rule may not need an
|
||||
* iptables/ipset filtering. check this may not be
|
||||
* a standard ip rule : permit any to any ( eg)
|
||||
|
|
433
bgpd/bgp_fsm.c
433
bgpd/bgp_fsm.c
|
@ -602,6 +602,7 @@ const char *const peer_down_str[] = {
|
|||
"Socket Error",
|
||||
"Admin. shutdown (RTT)",
|
||||
"Suppress Fib Turned On or Off",
|
||||
"Password config change",
|
||||
};
|
||||
|
||||
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))
|
||||
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))
|
||||
zlog_debug(
|
||||
"%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;
|
||||
bgp_attr_add_llgr_community(&attr);
|
||||
pi->attr = bgp_attr_intern(&attr);
|
||||
bgp_recalculate_afi_safi_bestpaths(
|
||||
peer->bgp, afi, safi);
|
||||
|
||||
break;
|
||||
bgp_process(peer->bgp, rm, pi, afi,
|
||||
safi);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -715,6 +719,11 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
|
|||
COMMUNITY_NO_LLGR))
|
||||
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))
|
||||
zlog_debug(
|
||||
"%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;
|
||||
bgp_attr_add_llgr_community(&attr);
|
||||
pi->attr = bgp_attr_intern(&attr);
|
||||
bgp_recalculate_afi_safi_bestpaths(peer->bgp,
|
||||
afi, safi);
|
||||
|
||||
break;
|
||||
bgp_process(peer->bgp, dest, pi, afi, safi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1482,7 +1488,7 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection)
|
|||
EVENT_OFF(connection->t_connect);
|
||||
EVENT_OFF(connection->t_holdtime);
|
||||
EVENT_OFF(connection->t_routeadv);
|
||||
EVENT_OFF(peer->connection->t_delayopen);
|
||||
EVENT_OFF(connection->t_delayopen);
|
||||
|
||||
/* Clear input and output buffer. */
|
||||
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)
|
||||
{
|
||||
if (bgp_getsockname(peer) < 0) {
|
||||
if (!peer->su_remote &&
|
||||
!BGP_CONNECTION_SU_UNSPEC(peer->connection)) {
|
||||
bgp_updatesockname(peer);
|
||||
if (!peer->su_remote && !BGP_CONNECTION_SU_UNSPEC(peer->connection)) {
|
||||
/* if connect initiated, then dest port and dest addresses are well known */
|
||||
peer->su_remote = sockunion_dup(&peer->connection->su);
|
||||
if (sockunion_family(peer->su_remote) == AF_INET)
|
||||
peer->su_remote->sin.sin_port =
|
||||
htons(peer->port);
|
||||
peer->su_remote->sin.sin_port = htons(peer->port);
|
||||
else if (sockunion_family(peer->su_remote) == AF_INET6)
|
||||
peer->su_remote->sin6.sin6_port =
|
||||
htons(peer->port);
|
||||
}
|
||||
peer->su_remote->sin6.sin6_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++;
|
||||
/* Send message to RIB indicating route update pending */
|
||||
if (gr_info->af_enabled[afi][safi] == false) {
|
||||
gr_info->af_enabled[afi][safi] = true;
|
||||
/* Send message to RIB */
|
||||
if (gr_info->af_enabled == false) {
|
||||
gr_info->af_enabled = true;
|
||||
gr_info->route_sync = false;
|
||||
bgp->gr_route_sync_pending = true;
|
||||
bgp_zebra_update(bgp, afi, safi,
|
||||
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)
|
||||
&& BGP_PEER_RESTARTING_MODE(peer)) {
|
||||
/* 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]);
|
||||
ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info);
|
||||
}
|
||||
|
@ -2199,8 +2202,7 @@ bgp_establish(struct peer_connection *connection)
|
|||
} else {
|
||||
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
|
||||
BGP_PEER_RESTARTING_MODE(peer) &&
|
||||
CHECK_FLAG(peer->bgp->flags,
|
||||
BGP_FLAG_GR_PRESERVE_FWD))
|
||||
bgp_gr_is_forwarding_preserved(peer->bgp))
|
||||
peer->bgp->gr_info[afi][safi]
|
||||
.eor_required++;
|
||||
}
|
||||
|
@ -2695,33 +2697,11 @@ int bgp_event_update(struct peer_connection *connection,
|
|||
}
|
||||
/* BGP GR Code */
|
||||
|
||||
int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
|
||||
enum global_mode global_new_state,
|
||||
enum global_mode global_old_state)
|
||||
static inline void
|
||||
bgp_peer_inherit_global_gr_mode(struct peer *peer,
|
||||
enum global_mode global_gr_mode)
|
||||
{
|
||||
struct peer *peer = {0};
|
||||
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) {
|
||||
switch (global_gr_mode) {
|
||||
case GLOBAL_HELPER:
|
||||
BGP_PEER_GR_HELPER_ENABLE(peer);
|
||||
break;
|
||||
|
@ -2732,16 +2712,46 @@ int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
|
|||
BGP_PEER_GR_DISABLE(peer);
|
||||
break;
|
||||
case GLOBAL_INVALID:
|
||||
zlog_debug("%s [BGP_GR] GLOBAL_INVALID",
|
||||
__func__);
|
||||
return BGP_ERR_GR_OPERATION_FAILED;
|
||||
}
|
||||
default:
|
||||
zlog_err("Unexpected Global GR mode %d", global_gr_mode);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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_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_new_state = bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd];
|
||||
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("[BGP_GR] global_old_gr_state :%s:",
|
||||
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:",
|
||||
zlog_debug("%s: Handle GR command %s, current GR state %s, new GR state %s",
|
||||
bgp->name_pretty, print_global_gr_cmd(global_gr_cmd),
|
||||
print_global_gr_mode(global_old_state),
|
||||
print_global_gr_mode(global_new_state));
|
||||
} else {
|
||||
zlog_err("%s [BGP_GR] global_old_state == GLOBAL_INVALID",
|
||||
__func__);
|
||||
|
||||
if (global_old_state == GLOBAL_INVALID)
|
||||
return BGP_ERR_GR_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (global_new_state == GLOBAL_INVALID) {
|
||||
zlog_err("%s [BGP_GR] global_new_state == GLOBAL_INVALID",
|
||||
__func__);
|
||||
if (global_new_state == GLOBAL_INVALID)
|
||||
return BGP_ERR_GR_INVALID_CMD;
|
||||
}
|
||||
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));
|
||||
if (global_new_state == global_old_state)
|
||||
return BGP_GR_NO_OPERATION;
|
||||
}
|
||||
|
||||
return bgp_gr_lookup_n_update_all_peer(bgp, global_new_state,
|
||||
global_old_state);
|
||||
/* Update global GR mode and process all peers in instance. */
|
||||
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)
|
||||
|
@ -2903,179 +2894,102 @@ int bgp_neighbor_graceful_restart(struct peer *peer,
|
|||
{
|
||||
enum peer_mode peer_new_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;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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))
|
||||
zlog_debug("%s [BGP_GR] peer_old_state: %d", __func__,
|
||||
peer_old_state);
|
||||
zlog_debug("%pBP: Handle GR command %s, current GR state %s, new GR state %s",
|
||||
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)
|
||||
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)
|
||||
return BGP_ERR_GR_INVALID_CMD;
|
||||
|
||||
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 !");
|
||||
if (peer_new_state == peer_old_state)
|
||||
return BGP_GR_NO_OPERATION;
|
||||
}
|
||||
|
||||
if (result == BGP_GR_SUCCESS) {
|
||||
|
||||
/* 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;
|
||||
}
|
||||
result = gr_fsm.action_fun(peer, peer_old_state, peer_new_state);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state,
|
||||
enum peer_mode new_peer_state)
|
||||
static inline bool gr_mode_matches(enum peer_mode peer_gr_mode,
|
||||
enum global_mode global_gr_mode)
|
||||
{
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug(
|
||||
"%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!",
|
||||
__func__, print_peer_gr_mode(old_peer_state),
|
||||
print_peer_gr_mode(new_peer_state));
|
||||
if ((peer_gr_mode == PEER_HELPER && global_gr_mode == GLOBAL_HELPER) ||
|
||||
(peer_gr_mode == PEER_GR && global_gr_mode == GLOBAL_GR) ||
|
||||
(peer_gr_mode == PEER_DISABLE && global_gr_mode == GLOBAL_DISABLE))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
enum global_mode bgp_gr_global_mode = GLOBAL_INVALID;
|
||||
unsigned int ret = BGP_GR_FAILURE;
|
||||
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_peer_state == new_peer_state) {
|
||||
/* Nothing to do over here as the present and old state is the
|
||||
* same */
|
||||
if (old_state == new_state)
|
||||
return BGP_GR_NO_OPERATION;
|
||||
}
|
||||
if ((old_peer_state == PEER_INVALID)
|
||||
|| (new_peer_state == PEER_INVALID)) {
|
||||
/* something bad happend , print error message */
|
||||
if ((old_state == PEER_INVALID) || (new_state == PEER_INVALID))
|
||||
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
|
||||
*/
|
||||
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 ((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.
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
||||
session_reset = false;
|
||||
} else if ((new_state == PEER_GLOBAL_INHERIT) &&
|
||||
(old_state != PEER_GLOBAL_INHERIT)) {
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
session_reset = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* 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);
|
||||
}
|
||||
|
||||
inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state)
|
||||
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) {
|
||||
case PEER_HELPER:
|
||||
|
@ -3089,57 +3003,38 @@ inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state)
|
|||
break;
|
||||
case PEER_GLOBAL_INHERIT:
|
||||
BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
|
||||
|
||||
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 !!!");
|
||||
}
|
||||
bgp_peer_inherit_global_gr_mode(peer, global_gr_mode);
|
||||
break;
|
||||
case PEER_INVALID:
|
||||
default:
|
||||
zlog_err(
|
||||
"[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!");
|
||||
break;
|
||||
}
|
||||
bgp_peer_gr_flags_update(peer);
|
||||
peer->peer_gr_present_state = new_state;
|
||||
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !",
|
||||
new_state);
|
||||
zlog_debug("%pBP: Peer GR mode changed from %s to %s, GR flags 0x%x peer flags 0x%" PRIx64,
|
||||
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)
|
||||
{
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("%s [BGP_GR] called !", __func__);
|
||||
if (CHECK_FLAG(peer->peer_gr_new_status_flag,
|
||||
PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
|
||||
SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER);
|
||||
else
|
||||
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,
|
||||
PEER_GRACEFUL_RESTART_NEW_STATE_RESTART))
|
||||
SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART);
|
||||
else
|
||||
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,
|
||||
PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT))
|
||||
SET_FLAG(peer->flags,
|
||||
|
@ -3147,28 +3042,28 @@ void bgp_peer_gr_flags_update(struct peer *peer)
|
|||
else
|
||||
UNSET_FLAG(peer->flags,
|
||||
PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT);
|
||||
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug(
|
||||
"[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !",
|
||||
peer->host,
|
||||
(CHECK_FLAG(peer->flags,
|
||||
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);
|
||||
zlog_debug("%pBP: Peer flags updated to 0x%" PRIx64
|
||||
", GR flags 0x%x, GR mode %s",
|
||||
peer, peer->flags, peer->peer_gr_new_status_flag,
|
||||
print_peer_gr_mode(bgp_peer_gr_mode_get(peer)));
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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);
|
||||
zlog_debug(
|
||||
"[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!",
|
||||
peer->host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ int bgp_neighbor_graceful_restart(struct peer *peer,
|
|||
enum peer_gr_command peer_gr_cmd);
|
||||
unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_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_enable(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 peer_mode bgp_get_peer_gr_mode_from_flags(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);
|
||||
const char *print_peer_gr_mode(enum peer_mode pr_mode);
|
||||
const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);
|
||||
|
|
|
@ -38,7 +38,7 @@ static void *bgp_labels_hash_alloc(void *p)
|
|||
struct bgp_labels *new;
|
||||
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;
|
||||
for (i = 0; i < labels->num_labels; i++)
|
||||
|
@ -576,7 +576,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
|
|||
} else {
|
||||
bgp_withdraw(peer, &p, addpath_id, packet->afi,
|
||||
SAFI_UNICAST, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, NULL, &label, 1, NULL);
|
||||
BGP_ROUTE_NORMAL, NULL, &label, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
struct prefix_evpn *pevpn = (struct prefix_evpn *)dest;
|
||||
struct prefix_rd prd;
|
||||
struct bgp_route_evpn *evpn;
|
||||
|
||||
if (pevpn->family == AF_EVPN
|
||||
&& 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;
|
||||
}
|
||||
|
||||
memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
|
||||
sizeof(evpn));
|
||||
bgp_update(peer, p, pi->addpath_rx_id, pi->attr,
|
||||
AFI_L2VPN, SAFI_EVPN, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, &prd, label_pnt,
|
||||
num_labels, 1, evpn);
|
||||
BGP_ROUTE_NORMAL, &prd, label_pnt, num_labels,
|
||||
1, bgp_attr_get_evpn_overlay(pi->attr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,8 +63,7 @@ DEFINE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled),
|
|||
(vrf, enabled));
|
||||
|
||||
/* bgpd options, we use GNU getopt library. */
|
||||
static const struct option longopts[] = {
|
||||
{ "bgp_port", required_argument, NULL, 'p' },
|
||||
static const struct option longopts[] = { { "bgp_port", required_argument, NULL, 'p' },
|
||||
{ "listenon", required_argument, NULL, 'l' },
|
||||
{ "no_kernel", no_argument, NULL, 'n' },
|
||||
{ "skip_runas", no_argument, NULL, 'S' },
|
||||
|
@ -72,9 +71,8 @@ static const struct option longopts[] = {
|
|||
{ "int_num", required_argument, NULL, 'I' },
|
||||
{ "no_zebra", no_argument, NULL, 'Z' },
|
||||
{ "socket_size", required_argument, NULL, 's' },
|
||||
{ "v6-with-v4-nexthops", no_argument, NULL, 'v' },
|
||||
{ 0 }
|
||||
};
|
||||
{ "v6-with-v4-nexthops", no_argument, NULL, 'x' },
|
||||
{ 0 } };
|
||||
|
||||
/* signal definitions */
|
||||
void sighup(void);
|
||||
|
@ -424,11 +422,12 @@ int main(int argc, char **argv)
|
|||
int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
|
||||
char *address;
|
||||
struct listnode *node;
|
||||
bool v6_with_v4_nexthops = false;
|
||||
|
||||
addresses->cmp = (int (*)(void *, void *))strcmp;
|
||||
|
||||
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"
|
||||
" -l, --listenon Listen on specified address (implies -n)\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"
|
||||
" -I, --int_num Set instance number (label-manager)\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. */
|
||||
while (1) {
|
||||
|
@ -499,8 +498,8 @@ int main(int argc, char **argv)
|
|||
case 's':
|
||||
buffer_size = atoi(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
bm->v6_with_v4_nexthops = true;
|
||||
case 'x':
|
||||
v6_with_v4_nexthops = true;
|
||||
break;
|
||||
default:
|
||||
frr_help_exit(1);
|
||||
|
@ -511,13 +510,18 @@ int main(int argc, char **argv)
|
|||
|
||||
/* BGP master init. */
|
||||
bgp_master_init(frr_init(), buffer_size, addresses);
|
||||
bm->startup_time = monotime(NULL);
|
||||
bm->port = bgp_port;
|
||||
bm->v6_with_v4_nexthops = v6_with_v4_nexthops;
|
||||
if (bgp_port == 0)
|
||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||
if (no_fib_flag || no_zebra_flag)
|
||||
bgp_option_set(BGP_OPT_NO_FIB);
|
||||
if (no_zebra_flag)
|
||||
bgp_option_set(BGP_OPT_NO_ZEBRA);
|
||||
if (bgpd_di.graceful_restart)
|
||||
SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART);
|
||||
|
||||
bgp_error_init();
|
||||
/* Initializations. */
|
||||
libagentx_init();
|
||||
|
|
|
@ -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_SOFT_VERSION, "Software Version");
|
||||
|
||||
DEFINE_MTYPE(BGPD, BGP_EVPN_OVERLAY, "BGP EVPN Overlay");
|
||||
|
|
|
@ -134,4 +134,6 @@ DECLARE_MTYPE(BGP_NOTIFICATION);
|
|||
|
||||
DECLARE_MTYPE(BGP_SOFT_VERSION);
|
||||
|
||||
DECLARE_MTYPE(BGP_EVPN_OVERLAY);
|
||||
|
||||
#endif /* _QUAGGA_BGP_MEMORY_H */
|
||||
|
|
426
bgpd/bgp_mpath.c
426
bgpd/bgp_mpath.c
|
@ -2,8 +2,10 @@
|
|||
/*
|
||||
* BGP Multipath
|
||||
* 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>
|
||||
|
@ -190,78 +192,6 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
|
|||
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
|
||||
*
|
||||
|
@ -274,6 +204,7 @@ static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void)
|
|||
new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
|
||||
sizeof(struct bgp_path_info_mpath));
|
||||
|
||||
new_mpath->mp_count = 1;
|
||||
return new_mpath;
|
||||
}
|
||||
|
||||
|
@ -287,6 +218,8 @@ void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath)
|
|||
if (mpath && *mpath) {
|
||||
if ((*mpath)->mp_attr)
|
||||
bgp_attr_unintern(&(*mpath)->mp_attr);
|
||||
(*mpath)->mp_attr = NULL;
|
||||
|
||||
XFREE(MTYPE_BGP_MPATH_INFO, *mpath);
|
||||
}
|
||||
}
|
||||
|
@ -313,49 +246,6 @@ bgp_path_info_mpath_get(struct bgp_path_info *path)
|
|||
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
|
||||
*
|
||||
|
@ -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)
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
if (!path->mpath)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
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
|
||||
*
|
||||
* 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,
|
||||
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 &&
|
||||
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. */
|
||||
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
|
||||
*
|
||||
* Compare and sync up the multipath list with the mp_list generated by
|
||||
* bgp_best_selection
|
||||
* Compare and sync up the multipath flags with what was choosen
|
||||
* in best selection
|
||||
*/
|
||||
void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
|
||||
struct bgp_path_info *new_best,
|
||||
struct bgp_path_info *old_best,
|
||||
struct list *mp_list,
|
||||
struct bgp_maxpaths_cfg *mpath_cfg)
|
||||
struct bgp_path_info *new_best, struct bgp_path_info *old_best,
|
||||
uint32_t num_candidates, struct bgp_maxpaths_cfg *mpath_cfg)
|
||||
{
|
||||
uint16_t maxpaths, mpath_count, old_mpath_count;
|
||||
uint64_t bwval;
|
||||
uint64_t cum_bw, old_cum_bw;
|
||||
struct listnode *mp_node, *mp_next_node;
|
||||
struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
|
||||
int mpath_changed, debug;
|
||||
struct bgp_path_info *cur_iterator = NULL;
|
||||
bool mpath_changed, debug;
|
||||
bool all_paths_lb;
|
||||
char path_buf[PATH_ADDPATH_STR_BUFFER];
|
||||
bool old_mpath, new_mpath;
|
||||
|
||||
mpath_changed = 0;
|
||||
mpath_changed = false;
|
||||
maxpaths = multipath_num;
|
||||
mpath_count = 0;
|
||||
cur_mpath = NULL;
|
||||
old_mpath_count = 0;
|
||||
old_cum_bw = cum_bw = 0;
|
||||
prev_mpath = new_best;
|
||||
mp_node = listhead(mp_list);
|
||||
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) {
|
||||
cur_mpath = bgp_path_info_mpath_first(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);
|
||||
bgp_path_info_mpath_count_set(old_best, 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)
|
||||
zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64,
|
||||
dest, bgp->name_pretty,
|
||||
new_best ? new_best->peer->host : "NONE",
|
||||
mp_list ? listcount(mp_list) : 0, old_mpath_count,
|
||||
old_cum_bw);
|
||||
zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64
|
||||
" maxpaths set %u",
|
||||
dest, bgp->name_pretty, new_best ? new_best->peer->host : "NONE",
|
||||
num_candidates, old_mpath_count, old_cum_bw, maxpaths);
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
* multipath list have been visited (for cleanup purposes) and
|
||||
* the maxpath requirement is fulfulled
|
||||
* If the current mpath count is equal to the number of
|
||||
* maxpaths that can be used then we can bail, after
|
||||
* we clean up the flags associated with the rest of the
|
||||
* bestpaths
|
||||
*/
|
||||
if (!cur_mpath && (mpath_count >= maxpaths))
|
||||
break;
|
||||
if (mpath_count >= maxpaths) {
|
||||
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;
|
||||
next_mpath =
|
||||
cur_mpath ? bgp_path_info_mpath_next(cur_mpath) : NULL;
|
||||
tmp_info = mp_node ? listgetdata(mp_node) : NULL;
|
||||
cur_iterator = cur_iterator->next;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
zlog_debug("%pBD(%s): comparing candidate %s with existing mpath %s",
|
||||
dest, bgp->name_pretty,
|
||||
tmp_info ? tmp_info->peer->host : "NONE",
|
||||
cur_mpath ? cur_mpath->peer->host : "NONE");
|
||||
zlog_debug("%pBD(%s): Mpath count %u is equal to maximum paths allowed, finished comparision for MPATHS",
|
||||
dest, bgp->name_pretty, mpath_count);
|
||||
|
||||
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.
|
||||
* Insert onto new multipath list if maxpaths allows.
|
||||
* There is nothing to do if the cur_iterator is neither a old path
|
||||
* or a new path
|
||||
*/
|
||||
if (mp_node && (listgetdata(mp_node) == cur_mpath)) {
|
||||
list_delete_node(mp_list, mp_node);
|
||||
bgp_path_info_mpath_dequeue(cur_mpath);
|
||||
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;
|
||||
if (!old_mpath && !new_mpath) {
|
||||
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
|
||||
cur_iterator = cur_iterator->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur_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;
|
||||
if (new_mpath) {
|
||||
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) ||
|
||||
ecommunity_linkbw_present(
|
||||
bgp_attr_get_ipv6_ecommunity(
|
||||
new_mpath->attr),
|
||||
ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(
|
||||
cur_iterator->attr),
|
||||
&bwval))
|
||||
cum_bw += bwval;
|
||||
else
|
||||
all_paths_lb = false;
|
||||
|
||||
if (debug) {
|
||||
bgp_path_info_path_with_addpath_rx_str(
|
||||
new_mpath, path_buf,
|
||||
bgp_path_info_path_with_addpath_rx_str(cur_iterator, path_buf,
|
||||
sizeof(path_buf));
|
||||
zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d",
|
||||
dest, path_buf,
|
||||
&new_mpath->attr->nexthop,
|
||||
mpath_count);
|
||||
zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d cum_bw: %" PRIu64
|
||||
" all_paths_lb: %u",
|
||||
dest, path_buf, &cur_iterator->attr->nexthop,
|
||||
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) {
|
||||
bgp_path_info_mpath_count_set(new_best, mpath_count - 1);
|
||||
if (mpath_count <= 1 ||
|
||||
(!ecommunity_linkbw_present(bgp_attr_get_ecommunity(
|
||||
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 (mpath_count > 1 || new_best->mpath) {
|
||||
bgp_path_info_mpath_count_set(new_best, mpath_count);
|
||||
bgp_path_info_mpath_lb_update(new_best, true, all_paths_lb, cum_bw);
|
||||
}
|
||||
if (debug)
|
||||
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,
|
||||
mpath_changed ? "YES" : "NO", all_paths_lb,
|
||||
cum_bw);
|
||||
|
||||
if (mpath_count == 1)
|
||||
UNSET_FLAG(new_best->flags, BGP_PATH_MULTIPATH);
|
||||
if (mpath_changed
|
||||
|| (bgp_path_info_mpath_count(new_best) != old_mpath_count))
|
||||
SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG);
|
||||
if ((mpath_count - 1) != old_mpath_count ||
|
||||
old_cum_bw != cum_bw)
|
||||
if ((mpath_count) != old_mpath_count || old_cum_bw != cum_bw)
|
||||
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
|
||||
*
|
||||
|
@ -816,7 +604,7 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
|
|||
if (!new_best)
|
||||
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))) {
|
||||
bgp_attr_unintern(&new_attr);
|
||||
bgp_path_info_mpath_attr_set(new_best, NULL);
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
/*
|
||||
* BGP Multipath
|
||||
* 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
|
||||
|
@ -13,24 +14,21 @@
|
|||
* multipath selections, lazily allocated to save memory
|
||||
*/
|
||||
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 */
|
||||
struct bgp_path_info *mp_info;
|
||||
|
||||
/* When attached to best path, the number of selected multipaths */
|
||||
uint16_t mp_count;
|
||||
|
||||
/* Flags - relevant as noted. */
|
||||
/* Flags - relevant as noted, attached to bestpath. */
|
||||
uint16_t mp_flags;
|
||||
#define BGP_MP_LB_PRESENT 0x1 /* Link-bandwidth present for >= 1 path */
|
||||
#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;
|
||||
|
||||
/* Cumulative bandiwdth of all multipaths - attached to bestpath. */
|
||||
|
@ -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
|
||||
* multipath selections
|
||||
*/
|
||||
extern int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
|
||||
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 int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, struct bgp_path_info *bpi2);
|
||||
extern void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
|
||||
struct bgp_path_info *new_best,
|
||||
struct bgp_path_info *old_best,
|
||||
struct list *mp_list,
|
||||
struct bgp_path_info *old_best, uint32_t num_candidates,
|
||||
struct bgp_maxpaths_cfg *mpath_cfg);
|
||||
extern void
|
||||
bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
|
||||
struct bgp_path_info *old_best);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Walk list of multipaths associated with a best path */
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "bgpd/bgp_nht.h"
|
||||
#include "bgpd/bgp_evpn.h"
|
||||
#include "bgpd/bgp_memory.h"
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
|
||||
#ifdef ENABLE_BGP_VNC
|
||||
#include "bgpd/rfapi/rfapi_backend.h"
|
||||
|
@ -245,7 +246,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
|
|||
} else {
|
||||
bgp_withdraw(peer, &p, addpath_id, packet->afi,
|
||||
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, &prd, &label, 1, NULL);
|
||||
BGP_ROUTE_NORMAL, &prd, &label, 1);
|
||||
}
|
||||
}
|
||||
/* Packet length consistency check. */
|
||||
|
@ -280,7 +281,8 @@ done:
|
|||
*
|
||||
* 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
|
||||
* 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
|
||||
* 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)
|
||||
{
|
||||
struct interface *ifp;
|
||||
mpls_label_t label = MPLS_LABEL_NONE;
|
||||
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)) {
|
||||
ifp = if_get_vrf_loopback(bgp->vrf_id);
|
||||
if (ifp && if_is_up(ifp))
|
||||
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)
|
||||
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;
|
||||
act = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
|
||||
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
|
||||
|
@ -432,6 +449,12 @@ void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp)
|
|||
if (!vrf)
|
||||
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;
|
||||
act = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
|
||||
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)
|
||||
{
|
||||
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
|
||||
struct srv6_sid_ctx ctx = {};
|
||||
struct seg6local_context seg6localctx = {};
|
||||
|
||||
if (bgp->vrf_id == VRF_UNKNOWN) {
|
||||
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__,
|
||||
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,
|
||||
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,
|
||||
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
|
||||
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)
|
||||
{
|
||||
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
|
||||
struct srv6_sid_ctx ctx = {};
|
||||
struct seg6local_context seg6localctx = {};
|
||||
|
||||
if (bgp->vrf_id == VRF_UNKNOWN) {
|
||||
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__,
|
||||
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,
|
||||
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
|
||||
NULL);
|
||||
&seg6localctx);
|
||||
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct bgp_srv6_function *func;
|
||||
|
@ -631,108 +689,97 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function generates a new SID based on bgp->srv6_locator_chunks and
|
||||
* index. The locator and generated SID are stored in arguments sid_locator
|
||||
* and sid, respectively.
|
||||
/**
|
||||
* Return the SRv6 SID value obtained by composing the LOCATOR and FUNCTION.
|
||||
*
|
||||
* if index != 0: try to allocate as index-mode
|
||||
* else: try to allocate as auto-mode
|
||||
* @param sid_value SRv6 SID value returned
|
||||
* @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,
|
||||
struct srv6_locator_chunk *sid_locator_chunk,
|
||||
struct in6_addr *sid)
|
||||
static bool srv6_sid_compose(struct in6_addr *sid_value,
|
||||
struct srv6_locator *locator, uint32_t sid_func)
|
||||
{
|
||||
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
|
||||
struct listnode *node;
|
||||
struct srv6_locator_chunk *chunk;
|
||||
bool alloced = false;
|
||||
int label = 0;
|
||||
uint8_t offset = 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;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
|
||||
if (chunk->function_bits_length >
|
||||
if (locator->function_bits_length >
|
||||
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
|
||||
if (debug)
|
||||
zlog_debug(
|
||||
"%s: invalid SRv6 Locator chunk (%pFX): Function Length must be less or equal to %d",
|
||||
__func__, &chunk->prefix,
|
||||
zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length must be less or equal to %d",
|
||||
__func__, &locator->prefix,
|
||||
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)
|
||||
zlog_debug(
|
||||
"%s: skipped SRv6 Locator chunk (%pFX): Function Length is too short to support specified index (%u)",
|
||||
__func__, &chunk->prefix, index);
|
||||
continue;
|
||||
zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length is too short to support specified function (%u)",
|
||||
__func__, &locator->prefix, sid_func);
|
||||
return false;
|
||||
}
|
||||
|
||||
*sid = chunk->prefix.prefix;
|
||||
*sid_locator_chunk = *chunk;
|
||||
offset = chunk->block_bits_length + chunk->node_bits_length;
|
||||
func_len = chunk->function_bits_length;
|
||||
/**
|
||||
* Let's build the SID value.
|
||||
* sid_value = LOC:FUNC::
|
||||
*/
|
||||
|
||||
/* 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;
|
||||
|
||||
if (index != 0) {
|
||||
label = index << shift_len;
|
||||
label = sid_func << shift_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;
|
||||
zlog_debug("%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
|
||||
__func__, &locator->prefix, label);
|
||||
return false;
|
||||
}
|
||||
|
||||
transpose_sid(sid, label, offset, func_len);
|
||||
if (sid_exist(bgp, sid))
|
||||
continue;
|
||||
alloced = true;
|
||||
break;
|
||||
if (sid_exist(bgp_get_default(), sid_value)) {
|
||||
zlog_warn("%s: skipped to allocate SRv6 SID (%pFX): SID %pI6 already in use",
|
||||
__func__, &locator->prefix, sid_value);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 1; i < index_max; i++) {
|
||||
label = i << shift_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;
|
||||
}
|
||||
}
|
||||
/* Finally, we put the FUNC in sid_value at the computed offset */
|
||||
transpose_sid(sid_value, label, offset, func_len);
|
||||
|
||||
if (!alloced)
|
||||
return 0;
|
||||
|
||||
sid_register(bgp, sid, bgp->srv6_locator_name);
|
||||
return label;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
|
||||
afi_t afi)
|
||||
{
|
||||
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
||||
struct srv6_locator_chunk *tovpn_sid_locator;
|
||||
struct in6_addr *tovpn_sid;
|
||||
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
|
||||
struct in6_addr tovpn_sid = {};
|
||||
uint32_t tovpn_sid_index = 0;
|
||||
bool tovpn_sid_auto = false;
|
||||
struct srv6_sid_ctx ctx = {};
|
||||
uint32_t sid_func;
|
||||
|
||||
if (debug)
|
||||
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
|
||||
* 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;
|
||||
|
||||
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_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
|
||||
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;
|
||||
}
|
||||
|
||||
tovpn_sid_locator = srv6_locator_chunk_alloc();
|
||||
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
|
||||
|
||||
tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
|
||||
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",
|
||||
if (!tovpn_sid_auto) {
|
||||
if (!srv6_sid_compose(&tovpn_sid, bgp_vpn->srv6_locator,
|
||||
tovpn_sid_index)) {
|
||||
zlog_err("%s: failed to compose sid for vrf %s: afi %s",
|
||||
__func__, bgp_vrf->name_pretty, afi2str(afi));
|
||||
srv6_locator_chunk_free(&tovpn_sid_locator);
|
||||
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
zlog_debug("%s: new sid %pI6 allocated for vrf %s: afi %s",
|
||||
__func__, tovpn_sid, bgp_vrf->name_pretty,
|
||||
afi2str(afi));
|
||||
|
||||
bgp_vrf->vpn_policy[afi].tovpn_sid = tovpn_sid;
|
||||
bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator;
|
||||
bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label =
|
||||
tovpn_sid_transpose_label;
|
||||
ctx.vrf_id = bgp_vrf->vrf_id;
|
||||
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
|
||||
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
|
||||
if (!bgp_zebra_request_srv6_sid(&ctx, &tovpn_sid,
|
||||
bgp_vpn->srv6_locator_name, &sid_func)) {
|
||||
zlog_err("%s: failed to request sid for vrf %s: afi %s",
|
||||
__func__, bgp_vrf->name_pretty, afi2str(afi));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
|
||||
{
|
||||
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
||||
struct srv6_locator_chunk *tovpn_sid_locator;
|
||||
struct in6_addr *tovpn_sid;
|
||||
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
|
||||
struct in6_addr tovpn_sid = {};
|
||||
uint32_t tovpn_sid_index = 0;
|
||||
bool tovpn_sid_auto = false;
|
||||
struct srv6_sid_ctx ctx = {};
|
||||
uint32_t sid_func;
|
||||
|
||||
if (debug)
|
||||
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
|
||||
* 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;
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
tovpn_sid_locator = srv6_locator_chunk_alloc();
|
||||
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
|
||||
|
||||
tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
|
||||
tovpn_sid_locator, tovpn_sid);
|
||||
|
||||
if (tovpn_sid_transpose_label == 0) {
|
||||
if (debug)
|
||||
zlog_debug("%s: not allocated new sid for vrf %s",
|
||||
if (!tovpn_sid_auto) {
|
||||
if (!srv6_sid_compose(&tovpn_sid, bgp_vpn->srv6_locator,
|
||||
bgp_vrf->tovpn_sid_index)) {
|
||||
zlog_err("%s: failed to compose new sid for vrf %s",
|
||||
__func__, bgp_vrf->name_pretty);
|
||||
srv6_locator_chunk_free(&tovpn_sid_locator);
|
||||
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
zlog_debug("%s: new sid %pI6 allocated for vrf %s", __func__,
|
||||
tovpn_sid, bgp_vrf->name_pretty);
|
||||
|
||||
bgp_vrf->tovpn_sid = tovpn_sid;
|
||||
bgp_vrf->tovpn_sid_locator = tovpn_sid_locator;
|
||||
bgp_vrf->tovpn_sid_transpose_label = tovpn_sid_transpose_label;
|
||||
ctx.vrf_id = bgp_vrf->vrf_id;
|
||||
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
|
||||
if (!bgp_zebra_request_srv6_sid(&ctx, &tovpn_sid,
|
||||
bgp_vpn->srv6_locator_name, &sid_func)) {
|
||||
zlog_err("%s: failed to request new sid for vrf %s", __func__,
|
||||
bgp_vrf->name_pretty);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t tovpn_sid_index = 0;
|
||||
bool tovpn_sid_auto = false;
|
||||
struct srv6_sid_ctx ctx = {};
|
||||
|
||||
if (debug)
|
||||
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)
|
||||
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) {
|
||||
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);
|
||||
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);
|
||||
uint32_t tovpn_sid_index = 0;
|
||||
bool tovpn_sid_auto = false;
|
||||
struct srv6_sid_ctx ctx = {};
|
||||
|
||||
if (debug)
|
||||
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)
|
||||
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) {
|
||||
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);
|
||||
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 *new_attr = NULL;
|
||||
safi_t safi = SAFI_MPLS_VPN;
|
||||
mpls_label_t label_val;
|
||||
mpls_label_t label;
|
||||
mpls_label_t label_val = { 0 };
|
||||
mpls_label_t label = { 0 };
|
||||
struct bgp_dest *bn;
|
||||
const char *debugmsg;
|
||||
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 */
|
||||
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;
|
||||
|
||||
encode_label(
|
||||
from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
|
||||
&label);
|
||||
|
@ -1801,8 +1879,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
|
|||
.tovpn_sid_locator->prefix.prefix,
|
||||
sizeof(struct in6_addr));
|
||||
} else if (from_bgp->tovpn_sid_locator) {
|
||||
struct srv6_locator_chunk *locator =
|
||||
from_bgp->tovpn_sid_locator;
|
||||
struct srv6_locator *locator = from_bgp->tovpn_sid_locator;
|
||||
|
||||
encode_label(from_bgp->tovpn_sid_transpose_label, &label);
|
||||
static_attr.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 interface *ifp = NULL;
|
||||
char rd_buf[RD_ADDRSTRLEN];
|
||||
struct aspath *new_aspath;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
zlog_debug("%s: updating RD %s, %pFX to %s", __func__, rd_buf,
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
bgp_attr_flush(&static_attr);
|
||||
|
||||
|
@ -3789,7 +3909,8 @@ void bgp_vpn_leak_unimport(struct bgp *from_bgp)
|
|||
bool is_vrf_leak_bind;
|
||||
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;
|
||||
|
||||
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
|
||||
|
|
|
@ -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,
|
||||
mpls_label_t orig_label);
|
||||
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);
|
||||
|
||||
#endif /* _QUAGGA_BGP_MPLSVPN_H */
|
||||
|
|
|
@ -590,6 +590,11 @@ static int bgp_vrf_check_update_active(struct bgp *bgp, struct interface *ifp)
|
|||
/* add trap in here */
|
||||
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 */
|
||||
if (bgp->snmp_stats->active)
|
||||
trap = MPLSL3VPNVRFUP;
|
||||
|
|
|
@ -861,8 +861,7 @@ int bgp_connect(struct peer_connection *connection)
|
|||
htons(peer->port), ifindex);
|
||||
}
|
||||
|
||||
/* After TCP connection is established. Get local address and port. */
|
||||
int bgp_getsockname(struct peer *peer)
|
||||
void bgp_updatesockname(struct peer *peer)
|
||||
{
|
||||
if (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_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,
|
||||
&peer->nexthop, peer)) {
|
||||
|
|
|
@ -23,6 +23,7 @@ extern void bgp_close_vrf_socket(struct bgp *bgp);
|
|||
extern void bgp_close(void);
|
||||
extern int bgp_connect(struct peer_connection *connection);
|
||||
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,
|
||||
const char *password);
|
||||
|
|
|
@ -1003,7 +1003,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
|
|||
if (bnc->is_evpn_gwip_nexthop)
|
||||
json_object_boolean_true_add(json_nexthop,
|
||||
"isEvpnGatewayIp");
|
||||
json_object_string_addf(json, "resolvedPrefix", "%pFX",
|
||||
json_object_string_addf(json_nexthop, "resolvedPrefix", "%pFX",
|
||||
&bnc->resolved_prefix);
|
||||
} else {
|
||||
vty_out(vty, " %s valid [IGP metric %d], #paths %d",
|
||||
|
|
|
@ -38,7 +38,7 @@ struct bgp_nexthop_cache {
|
|||
uint32_t metric;
|
||||
|
||||
/* 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
|
||||
* nexthop.
|
||||
|
@ -66,6 +66,7 @@ struct bgp_nexthop_cache {
|
|||
#define BGP_STATIC_ROUTE (1 << 4)
|
||||
#define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5)
|
||||
#define BGP_NEXTHOP_LABELED_VALID (1 << 6)
|
||||
#define BGP_NEXTHOP_ULTIMATE (1 << 7)
|
||||
|
||||
/*
|
||||
* This flag is added for EVPN gateway IP nexthops.
|
||||
|
|
|
@ -347,11 +347,10 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
|
|||
&p.u.prefix6))
|
||||
ifindex = pi->peer->connection->su.sin6.sin6_scope_id;
|
||||
|
||||
if (!is_bgp_static_route && orig_prefix
|
||||
&& prefix_same(&p, orig_prefix)) {
|
||||
if (!is_bgp_static_route && orig_prefix && prefix_same(&p, orig_prefix) &&
|
||||
CHECK_FLAG(bgp_route->flags, BGP_FLAG_IMPORT_CHECK)) {
|
||||
if (BGP_DEBUG(nht, NHT)) {
|
||||
zlog_debug(
|
||||
"%s(%pFX): prefix loops through itself",
|
||||
zlog_debug("%s(%pFX): prefix loops through itself (import-check enabled)",
|
||||
__func__, &p);
|
||||
}
|
||||
return 0;
|
||||
|
@ -405,12 +404,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
|
|||
peer);
|
||||
} else {
|
||||
if (BGP_DEBUG(nht, NHT))
|
||||
zlog_debug(
|
||||
"Found existing bnc %pFX(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p",
|
||||
zlog_debug("Found existing bnc %pFX(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p, resolved prefix %pFX",
|
||||
&bnc->prefix, bnc->ifindex_ipv6_ll,
|
||||
bnc->bgp->name_pretty, bnc->flags,
|
||||
bnc->ifindex_ipv6_ll, bnc->path_count,
|
||||
bnc->nht_info);
|
||||
bnc->nht_info, &bnc->resolved_prefix);
|
||||
}
|
||||
|
||||
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;
|
||||
else if (bpi_ultimate->extra)
|
||||
bpi_ultimate->extra->igpmetric = 0;
|
||||
|
||||
SET_FLAG(bnc->flags, BGP_NEXTHOP_ULTIMATE);
|
||||
} else if (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)
|
||||
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 &&
|
||||
pi->sub_type == BGP_ROUTE_IMPORTED &&
|
||||
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)
|
||||
bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
|
||||
SET_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED);
|
||||
|
||||
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 ||
|
||||
!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);
|
||||
|
||||
if (!bnc->is_evpn_gwip_nexthop)
|
||||
bnc->flags |= BGP_NEXTHOP_VALID;
|
||||
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
|
||||
bnc->metric = nhr->metric;
|
||||
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++) {
|
||||
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
|
||||
* to work with v4 routing over v6 nexthops
|
||||
*/
|
||||
if (peer && !peer->ifp
|
||||
&& CHECK_FLAG(peer->flags,
|
||||
PEER_FLAG_CAPABILITY_ENHE)
|
||||
&& nhr->prefix.family == AF_INET6
|
||||
&& nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
|
||||
if (peer && !peer->ifp &&
|
||||
CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE) &&
|
||||
!CHECK_FLAG(bnc->bgp->flags,
|
||||
BGP_FLAG_IPV6_NO_AUTO_RA) &&
|
||||
nhr->prefix.family == AF_INET6 &&
|
||||
nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
|
||||
struct interface *ifp;
|
||||
|
||||
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 */
|
||||
if (nexthop->nh_label &&
|
||||
nexthop->nh_label->num_labels) {
|
||||
|
||||
bnc->flags |= BGP_NEXTHOP_LABELED_VALID;
|
||||
SET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID);
|
||||
num_labels = nexthop->nh_label->num_labels;
|
||||
}
|
||||
|
||||
|
@ -690,7 +695,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
|
|||
* determined
|
||||
* that there has been a change.
|
||||
*/
|
||||
if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
|
||||
if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
|
||||
continue;
|
||||
|
||||
for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
|
||||
|
@ -698,7 +703,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
|
|||
break;
|
||||
|
||||
if (!oldnh)
|
||||
bnc->change_flags |= BGP_NEXTHOP_CHANGED;
|
||||
SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
|
||||
}
|
||||
bnc_nexthop_free(bnc);
|
||||
bnc->nexthop = nhlist_head;
|
||||
|
@ -722,19 +727,22 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
|
|||
: "failed"));
|
||||
|
||||
if (evpn_resolved) {
|
||||
bnc->flags |= BGP_NEXTHOP_VALID;
|
||||
bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
|
||||
bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
|
||||
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
|
||||
UNSET_FLAG(bnc->flags,
|
||||
BGP_NEXTHOP_EVPN_INCOMPLETE);
|
||||
SET_FLAG(bnc->change_flags,
|
||||
BGP_NEXTHOP_MACIP_CHANGED);
|
||||
} else {
|
||||
bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE;
|
||||
bnc->flags &= ~BGP_NEXTHOP_VALID;
|
||||
SET_FLAG(bnc->flags,
|
||||
BGP_NEXTHOP_EVPN_INCOMPLETE);
|
||||
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memset(&bnc->resolved_prefix, 0, sizeof(bnc->resolved_prefix));
|
||||
bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
|
||||
bnc->flags &= ~BGP_NEXTHOP_VALID;
|
||||
bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID;
|
||||
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
|
||||
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
|
||||
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID);
|
||||
bnc->nexthop_num = nhr->nexthop_num;
|
||||
|
||||
/* 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 nexthop *nhop;
|
||||
uint8_t other_nh_count;
|
||||
uint16_t other_nh_count;
|
||||
bool nhop_ll_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)
|
||||
{
|
||||
/* Check if we have already registered */
|
||||
if (bnc->flags & BGP_NEXTHOP_REGISTERED)
|
||||
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
|
||||
return;
|
||||
|
||||
if (bnc->ifindex_ipv6_ll) {
|
||||
|
@ -1305,11 +1313,13 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
|
|||
|
||||
bool bnc_is_valid_nexthop = false;
|
||||
bool path_valid = false;
|
||||
struct bgp_route_evpn *bre =
|
||||
bgp_attr_get_evpn_overlay(path->attr);
|
||||
|
||||
if (safi == SAFI_UNICAST &&
|
||||
path->sub_type == BGP_ROUTE_IMPORTED &&
|
||||
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 =
|
||||
bgp_isvalid_nexthop_for_l3vpn(bnc, path)
|
||||
? true
|
||||
|
@ -1520,6 +1530,10 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
|
|||
return;
|
||||
|
||||
bgp = peer->bgp;
|
||||
|
||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA))
|
||||
return;
|
||||
|
||||
if (!sockunion2hostprefix(&peer->connection->su, &p)) {
|
||||
zlog_warn("%s: Unable to convert sockunion to prefix for %s",
|
||||
__func__, peer->host);
|
||||
|
|
|
@ -519,20 +519,17 @@ static int bgp_capability_restart(struct peer *peer,
|
|||
UNSET_FLAG(restart_flag_time, 0xF000);
|
||||
peer->v_gr_restart = restart_flag_time;
|
||||
|
||||
if (bgp_debug_neighbor_events(peer)) {
|
||||
zlog_debug(
|
||||
"%s Peer has%srestarted. Restart Time: %d, N-bit set: %s",
|
||||
peer->host,
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("%pBP OPEN has GR capability, Restart time %d R-bit %s N-bit %s",
|
||||
peer, peer->v_gr_restart,
|
||||
CHECK_FLAG(peer->cap,
|
||||
PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)
|
||||
? " "
|
||||
: " not ",
|
||||
peer->v_gr_restart,
|
||||
? "SET"
|
||||
: "NOT-SET",
|
||||
CHECK_FLAG(peer->cap,
|
||||
PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV)
|
||||
? "yes"
|
||||
: "no");
|
||||
}
|
||||
? "SET"
|
||||
: "NOT-SET");
|
||||
|
||||
while (stream_get_getp(s) + 4 <= end) {
|
||||
afi_t afi;
|
||||
|
@ -556,14 +553,12 @@ static int bgp_capability_restart(struct peer *peer,
|
|||
iana_safi2str(pkt_safi));
|
||||
} else {
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug(
|
||||
"%s Address family %s is%spreserved",
|
||||
peer->host, get_afi_safi_str(afi, safi, false),
|
||||
CHECK_FLAG(
|
||||
peer->af_cap[afi][safi],
|
||||
zlog_debug("%pBP F-bit %s for %s", peer,
|
||||
CHECK_FLAG(peer->af_cap[afi][safi],
|
||||
PEER_CAP_RESTART_AF_PRESERVE_RCV)
|
||||
? " "
|
||||
: " not ");
|
||||
? "SET"
|
||||
: "NOT-SET",
|
||||
get_afi_safi_str(afi, safi, false));
|
||||
|
||||
SET_FLAG(peer->af_cap[afi][safi],
|
||||
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
|
||||
*/
|
||||
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_OPEN_MALFORMED_ATTR);
|
||||
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 (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_OPEN_ERR,
|
||||
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);
|
||||
} else {
|
||||
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_OPEN_MALFORMED_ATTR);
|
||||
|
@ -1414,7 +1409,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
|
|||
|
||||
/* Option length check. */
|
||||
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);
|
||||
bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR,
|
||||
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;
|
||||
unsigned long capp = 0;
|
||||
unsigned long rcapp = 0;
|
||||
struct bgp *bgp = peer->bgp;
|
||||
|
||||
if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
|
||||
&& !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER))
|
||||
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);
|
||||
stream_putc(s, BGP_OPEN_OPT_CAP);
|
||||
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 */
|
||||
rcapp = stream_get_endp(s);
|
||||
stream_putc(s, 0);
|
||||
restart_time = peer->bgp->restart_time;
|
||||
if (peer->bgp->t_startup) {
|
||||
restart_time = bgp->restart_time;
|
||||
if (peer->bgp->t_startup || bgp_in_graceful_restart()) {
|
||||
SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT);
|
||||
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(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);
|
||||
|
||||
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
|
||||
* only when GR config is present
|
||||
*/
|
||||
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) {
|
||||
bool f_bit = false;
|
||||
|
||||
if (!peer->afc[afi][safi])
|
||||
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
|
||||
* packet.
|
||||
*/
|
||||
|
@ -1648,11 +1639,15 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
|
|||
&pkt_safi);
|
||||
stream_putw(s, pkt_afi);
|
||||
stream_putc(s, pkt_safi);
|
||||
if (CHECK_FLAG(peer->bgp->flags,
|
||||
BGP_FLAG_GR_PRESERVE_FWD))
|
||||
stream_putc(s, GRACEFUL_RESTART_F_BIT);
|
||||
else
|
||||
stream_putc(s, 0);
|
||||
|
||||
f_bit = bgp_gr_is_forwarding_preserved(bgp);
|
||||
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -651,6 +651,7 @@ void bgp_open_send(struct peer_connection *connection)
|
|||
uint16_t send_holdtime;
|
||||
as_t local_as;
|
||||
struct peer *peer = connection->peer;
|
||||
bool ext_opt_params = false;
|
||||
|
||||
if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
|
||||
send_holdtime = peer->holdtime;
|
||||
|
@ -677,15 +678,17 @@ void bgp_open_send(struct peer_connection *connection)
|
|||
|
||||
/* Set capabilities */
|
||||
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 {
|
||||
struct stream *tmp = stream_new(STREAM_SIZE(s));
|
||||
|
||||
stream_copy(tmp, s);
|
||||
if (bgp_open_capability(tmp, peer, false)
|
||||
> BGP_OPEN_NON_EXT_OPT_LEN) {
|
||||
if (bgp_open_capability(tmp, peer, ext_opt_params) >
|
||||
BGP_OPEN_NON_EXT_OPT_LEN) {
|
||||
stream_free(tmp);
|
||||
(void)bgp_open_capability(s, peer, true);
|
||||
ext_opt_params = true;
|
||||
(void)bgp_open_capability(s, peer, ext_opt_params);
|
||||
} else {
|
||||
stream_copy(s, tmp);
|
||||
stream_free(tmp);
|
||||
|
@ -696,10 +699,10 @@ void bgp_open_send(struct peer_connection *connection)
|
|||
bgp_packet_set_size(s);
|
||||
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug(
|
||||
"%s sending OPEN, version %d, my as %u, holdtime %d, id %pI4",
|
||||
peer->host, BGP_VERSION_4, local_as, send_holdtime,
|
||||
&peer->local_id);
|
||||
zlog_debug("%pBP fd %d sending OPEN%s, version %d, my as %u, holdtime %d, id %pI4",
|
||||
peer, peer->connection->fd,
|
||||
ext_opt_params ? " (Extended)" : "", BGP_VERSION_4,
|
||||
local_as, send_holdtime, &peer->local_id);
|
||||
|
||||
/* Dump packet if debug option is set. */
|
||||
/* 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.subcode = bgp_notify.subcode;
|
||||
peer->notify.length = bgp_notify.length;
|
||||
peer->notify.hard_reset = hard_reset;
|
||||
|
||||
if (bgp_notify.length && data) {
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
else
|
||||
bgp_packet_set_marker(s, BGP_MSG_ROUTE_REFRESH_OLD);
|
||||
|
||||
/* Encode Route Refresh message. */
|
||||
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);
|
||||
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(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;
|
||||
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 */
|
||||
if (optlen == BGP_OPEN_NON_EXT_OPT_LEN
|
||||
|| 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,
|
||||
notify_data_remote_as, 2);
|
||||
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) {
|
||||
if (remote_as != peer->bgp->as) {
|
||||
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,
|
||||
sizeof(peer->rcvd_attr_str));
|
||||
|
||||
if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) {
|
||||
peer->stat_upd_7606++;
|
||||
|
||||
if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW)
|
||||
flog_err(
|
||||
EC_BGP_UPDATE_RCV,
|
||||
"%pBP rcvd UPDATE with errors in attr(s)!! Withdrawing route.",
|
||||
peer);
|
||||
}
|
||||
|
||||
if (ret && bgp_debug_update(peer, NULL, NULL, 1) &&
|
||||
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)
|
||||
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,
|
||||
* and it's not a Hard Reset, let's retain the routes.
|
||||
*/
|
||||
|
|
200
bgpd/bgp_pbr.c
200
bgpd/bgp_pbr.c
|
@ -173,33 +173,33 @@ static int snprintf_bgp_pbr_match_val(char *str, int len,
|
|||
ptr += delta;
|
||||
len -= delta;
|
||||
} else {
|
||||
if (mval->unary_operator & OPERATOR_UNARY_OR) {
|
||||
if (CHECK_FLAG(mval->unary_operator, OPERATOR_UNARY_OR)) {
|
||||
delta = snprintf(ptr, len, ", or ");
|
||||
ptr += delta;
|
||||
len -= delta;
|
||||
}
|
||||
if (mval->unary_operator & OPERATOR_UNARY_AND) {
|
||||
if (CHECK_FLAG(mval->unary_operator, OPERATOR_UNARY_AND)) {
|
||||
delta = snprintf(ptr, len, ", and ");
|
||||
ptr += 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, "<");
|
||||
ptr += 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, ">");
|
||||
ptr += 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, "=");
|
||||
ptr += 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");
|
||||
ptr += delta;
|
||||
len -= delta;
|
||||
|
@ -287,9 +287,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite(
|
|||
{
|
||||
if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
|
||||
if (type_entry == FLOWSPEC_TCP_FLAGS) {
|
||||
and_valmask->mask |=
|
||||
TCP_HEADER_ALL_FLAGS &
|
||||
~(value);
|
||||
SET_FLAG(and_valmask->mask, CHECK_FLAG(TCP_HEADER_ALL_FLAGS, ~(value)));
|
||||
} else if (type_entry == FLOWSPEC_DSCP ||
|
||||
type_entry == FLOWSPEC_FLOW_LABEL ||
|
||||
type_entry == FLOWSPEC_PKT_LEN ||
|
||||
|
@ -302,9 +300,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite(
|
|||
sizeof(struct bgp_pbr_val_mask));
|
||||
if (type_entry == FLOWSPEC_TCP_FLAGS) {
|
||||
and_valmask->val = TCP_HEADER_ALL_FLAGS;
|
||||
and_valmask->mask |=
|
||||
TCP_HEADER_ALL_FLAGS &
|
||||
~(value);
|
||||
SET_FLAG(and_valmask->mask, CHECK_FLAG(TCP_HEADER_ALL_FLAGS, ~(value)));
|
||||
} else if (type_entry == FLOWSPEC_DSCP ||
|
||||
type_entry == FLOWSPEC_FLOW_LABEL ||
|
||||
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 !=
|
||||
unary_operator)
|
||||
return false;
|
||||
if (!(list[i].compare_operator &
|
||||
OPERATOR_COMPARE_EQUAL_TO) &&
|
||||
!(list[i].compare_operator &
|
||||
OPERATOR_COMPARE_EXACT_MATCH)) {
|
||||
if ((list[i].compare_operator &
|
||||
OPERATOR_COMPARE_LESS_THAN) &&
|
||||
(list[i].compare_operator &
|
||||
OPERATOR_COMPARE_GREATER_THAN)) {
|
||||
if (!CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_EQUAL_TO) &&
|
||||
!CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_EXACT_MATCH)) {
|
||||
if (CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_LESS_THAN) &&
|
||||
CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_GREATER_THAN)) {
|
||||
ret = bgp_pbr_extract_enumerate_unary_opposite(
|
||||
unary_operator, and_valmask,
|
||||
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 (type_entry == FLOWSPEC_TCP_FLAGS)
|
||||
and_valmask->mask |=
|
||||
TCP_HEADER_ALL_FLAGS & list[i].value;
|
||||
SET_FLAG(and_valmask->mask,
|
||||
CHECK_FLAG(TCP_HEADER_ALL_FLAGS, list[i].value));
|
||||
} else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
|
||||
and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
|
||||
sizeof(struct bgp_pbr_val_mask));
|
||||
if (type_entry == FLOWSPEC_TCP_FLAGS) {
|
||||
and_valmask->val = TCP_HEADER_ALL_FLAGS;
|
||||
and_valmask->mask |=
|
||||
TCP_HEADER_ALL_FLAGS & list[i].value;
|
||||
SET_FLAG(and_valmask->mask,
|
||||
CHECK_FLAG(TCP_HEADER_ALL_FLAGS, list[i].value));
|
||||
} else if (type_entry == FLOWSPEC_DSCP ||
|
||||
type_entry == FLOWSPEC_FLOW_LABEL ||
|
||||
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;
|
||||
bool double_check = false;
|
||||
|
||||
if ((unary_operator & OPERATOR_UNARY_OR) &&
|
||||
(unary_operator & OPERATOR_UNARY_AND)) {
|
||||
if (CHECK_FLAG(unary_operator, OPERATOR_UNARY_OR) &&
|
||||
CHECK_FLAG(unary_operator, OPERATOR_UNARY_AND)) {
|
||||
unary_operator_val = OPERATOR_UNARY_AND;
|
||||
double_check = true;
|
||||
} 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++) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
if (list[i].unary_operator & OPERATOR_UNARY_OR)
|
||||
if (CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_OR))
|
||||
unary_operator = OPERATOR_UNARY_OR;
|
||||
if ((list[i].unary_operator & OPERATOR_UNARY_AND
|
||||
&& unary_operator == OPERATOR_UNARY_OR) ||
|
||||
(list[i].unary_operator & OPERATOR_UNARY_OR
|
||||
&& unary_operator == OPERATOR_UNARY_AND))
|
||||
if ((CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_AND) &&
|
||||
unary_operator == OPERATOR_UNARY_OR) ||
|
||||
(CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_OR) &&
|
||||
unary_operator == OPERATOR_UNARY_AND))
|
||||
return 0;
|
||||
}
|
||||
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) &&
|
||||
!(api->match_bitmask & PREFIX_DST_PRESENT)) {
|
||||
} else if (!CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT) &&
|
||||
!CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) {
|
||||
if (BGP_DEBUG(pbr, PBR)) {
|
||||
bgp_pbr_print_policy_route(api);
|
||||
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];
|
||||
|
||||
if ((ecom_eval->val[1] ==
|
||||
(char)ECOMMUNITY_REDIRECT_VRF) &&
|
||||
(ecom_eval->val[0] ==
|
||||
(char)ECOMMUNITY_ENCODE_TRANS_EXP ||
|
||||
if ((ecom_eval->val[1] == ECOMMUNITY_REDIRECT_VRF) &&
|
||||
(ecom_eval->val[0] == ECOMMUNITY_ENCODE_TRANS_EXP ||
|
||||
ecom_eval->val[0] ==
|
||||
(char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
|
||||
ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
|
||||
ecom_eval->val[0] ==
|
||||
(char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
|
||||
ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
|
||||
struct ecommunity *eckey = ecommunity_new();
|
||||
struct ecommunity_val ecom_copy;
|
||||
|
||||
memcpy(&ecom_copy, ecom_eval,
|
||||
sizeof(struct ecommunity_val));
|
||||
ecom_copy.val[0] &=
|
||||
~ECOMMUNITY_ENCODE_TRANS_EXP;
|
||||
UNSET_FLAG(ecom_copy.val[0], ECOMMUNITY_ENCODE_TRANS_EXP);
|
||||
ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
|
||||
ecommunity_add_val(eckey, &ecom_copy,
|
||||
false, false);
|
||||
|
@ -800,9 +789,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
|
|||
eckey);
|
||||
ecommunity_free(&eckey);
|
||||
} else if ((ecom_eval->val[0] ==
|
||||
(char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
|
||||
ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
|
||||
(ecom_eval->val[1] ==
|
||||
(char)ECOMMUNITY_REDIRECT_IP_NH)) {
|
||||
ECOMMUNITY_REDIRECT_IP_NH)) {
|
||||
/* in case the 2 ecom present,
|
||||
* do not overwrite
|
||||
* draft-ietf-idr-flowspec-redirect
|
||||
|
@ -861,10 +850,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
|
|||
= ecom_eval->val[7];
|
||||
api_action_redirect_ip = api_action;
|
||||
}
|
||||
} else if ((ecom_eval->val[0] ==
|
||||
(char)ECOMMUNITY_ENCODE_IP) &&
|
||||
} else if ((ecom_eval->val[0] == ECOMMUNITY_ENCODE_IP) &&
|
||||
(ecom_eval->val[1] ==
|
||||
(char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) {
|
||||
ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) {
|
||||
/* in case the 2 ecom present,
|
||||
* overwrite simpson draft
|
||||
* update redirect ip fields
|
||||
|
@ -888,7 +876,7 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
|
|||
}
|
||||
} else {
|
||||
if (ecom_eval->val[0] !=
|
||||
(char)ECOMMUNITY_ENCODE_TRANS_EXP)
|
||||
ECOMMUNITY_ENCODE_TRANS_EXP)
|
||||
continue;
|
||||
ret = ecommunity_fill_pbr_action(ecom_eval,
|
||||
api_action,
|
||||
|
@ -920,9 +908,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
|
|||
}
|
||||
api_action = &api->actions[action_count - 1];
|
||||
if ((ipv6_ecom_eval->val[1] ==
|
||||
(char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) &&
|
||||
ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) &&
|
||||
(ipv6_ecom_eval->val[0] ==
|
||||
(char)ECOMMUNITY_ENCODE_TRANS_EXP)) {
|
||||
ECOMMUNITY_ENCODE_TRANS_EXP)) {
|
||||
struct ecommunity *eckey = ecommunity_new();
|
||||
struct ecommunity_val_ipv6 ecom_copy;
|
||||
|
||||
|
@ -958,12 +946,12 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
|
|||
return -1;
|
||||
|
||||
/* 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;
|
||||
afi = family2afi(src->family);
|
||||
valid_prefix = 1;
|
||||
}
|
||||
if (api->match_bitmask & PREFIX_DST_PRESENT) {
|
||||
if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) {
|
||||
dst = &api->dst_prefix;
|
||||
if (valid_prefix && afi != family2afi(dst->family)) {
|
||||
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)
|
||||
return false;
|
||||
|
||||
if ((r1->flags & MATCH_IP_SRC_SET) &&
|
||||
!prefix_same(&r1->src, &r2->src))
|
||||
if (CHECK_FLAG(r1->flags, MATCH_IP_SRC_SET) && !prefix_same(&r1->src, &r2->src))
|
||||
return false;
|
||||
|
||||
if ((r1->flags & MATCH_IP_DST_SET) &&
|
||||
!prefix_same(&r1->dst, &r2->dst))
|
||||
if (CHECK_FLAG(r1->flags, MATCH_IP_DST_SET) && !prefix_same(&r1->dst, &r2->dst))
|
||||
return false;
|
||||
|
||||
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 : ");
|
||||
len -= 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);
|
||||
|
||||
if (api->src_prefix_offset)
|
||||
|
@ -1441,7 +1427,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
|
|||
ptr += delta;
|
||||
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);
|
||||
|
||||
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 ");
|
||||
len -= delta;
|
||||
ptr += delta;
|
||||
if (api->actions[i].u.za.filter
|
||||
& TRAFFIC_ACTION_TERMINATE) {
|
||||
if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_TERMINATE)) {
|
||||
delta = snprintf(ptr, len,
|
||||
" terminate (apply filter(s))");
|
||||
len -= delta;
|
||||
ptr += delta;
|
||||
}
|
||||
if (api->actions[i].u.za.filter
|
||||
& TRAFFIC_ACTION_DISTRIBUTE) {
|
||||
if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_DISTRIBUTE)) {
|
||||
delta = snprintf(ptr, len, " distribute");
|
||||
len -= delta;
|
||||
ptr += delta;
|
||||
}
|
||||
if (api->actions[i].u.za.filter
|
||||
& TRAFFIC_ACTION_SAMPLE) {
|
||||
if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_SAMPLE)) {
|
||||
delta = snprintf(ptr, len, " sample");
|
||||
len -= 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)
|
||||
return HASHWALK_CONTINUE;
|
||||
|
||||
if ((r1->flags & MATCH_IP_SRC_SET) &&
|
||||
!prefix_same(&r1->src, &r2->src))
|
||||
if (CHECK_FLAG(r1->flags, MATCH_IP_SRC_SET) && !prefix_same(&r1->src, &r2->src))
|
||||
return HASHWALK_CONTINUE;
|
||||
|
||||
if ((r1->flags & MATCH_IP_DST_SET) &&
|
||||
!prefix_same(&r1->dst, &r2->dst))
|
||||
if (CHECK_FLAG(r1->flags, MATCH_IP_DST_SET) && !prefix_same(&r1->dst, &r2->dst))
|
||||
return HASHWALK_CONTINUE;
|
||||
|
||||
/* 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;
|
||||
if (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) {
|
||||
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;
|
||||
/* A previous entry may already exist
|
||||
|
@ -1870,32 +1851,32 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
|
|||
|
||||
temp.family = bpf->family;
|
||||
if (bpf->src) {
|
||||
temp.flags |= MATCH_IP_SRC_SET;
|
||||
SET_FLAG(temp.flags, MATCH_IP_SRC_SET);
|
||||
prefix_copy(&temp2.src, bpf->src);
|
||||
} else
|
||||
temp2.src.family = bpf->family;
|
||||
if (bpf->dst) {
|
||||
temp.flags |= MATCH_IP_DST_SET;
|
||||
SET_FLAG(temp.flags, MATCH_IP_DST_SET);
|
||||
prefix_copy(&temp2.dst, bpf->dst);
|
||||
} else
|
||||
temp2.dst.family = bpf->family;
|
||||
if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
|
||||
if (bpf->protocol == IPPROTO_ICMP)
|
||||
temp.flags |= MATCH_ICMP_SET;
|
||||
temp.flags |= MATCH_PORT_SRC_SET;
|
||||
SET_FLAG(temp.flags, MATCH_ICMP_SET);
|
||||
SET_FLAG(temp.flags, MATCH_PORT_SRC_SET);
|
||||
temp2.src_port_min = src_port->min_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;
|
||||
}
|
||||
}
|
||||
if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
|
||||
if (bpf->protocol == IPPROTO_ICMP)
|
||||
temp.flags |= MATCH_ICMP_SET;
|
||||
temp.flags |= MATCH_PORT_DST_SET;
|
||||
SET_FLAG(temp.flags, MATCH_ICMP_SET);
|
||||
SET_FLAG(temp.flags, MATCH_PORT_DST_SET);
|
||||
temp2.dst_port_min = dst_port->min_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;
|
||||
}
|
||||
}
|
||||
|
@ -1907,7 +1888,7 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
|
|||
temp.pkt_len_max = pkt_len->max_port;
|
||||
} else if (bpf->pkt_len_val) {
|
||||
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;
|
||||
}
|
||||
if (bpf->tcp_flags) {
|
||||
|
@ -1916,32 +1897,32 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
|
|||
}
|
||||
if (bpf->dscp) {
|
||||
if (bpf->dscp->mask)
|
||||
temp.flags |= MATCH_DSCP_INVERSE_SET;
|
||||
SET_FLAG(temp.flags, MATCH_DSCP_INVERSE_SET);
|
||||
else
|
||||
temp.flags |= MATCH_DSCP_SET;
|
||||
SET_FLAG(temp.flags, MATCH_DSCP_SET);
|
||||
temp.dscp_value = bpf->dscp->val;
|
||||
}
|
||||
if (bpf->flow_label) {
|
||||
if (bpf->flow_label->mask)
|
||||
temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
|
||||
SET_FLAG(temp.flags, MATCH_FLOW_LABEL_INVERSE_SET);
|
||||
else
|
||||
temp.flags |= MATCH_FLOW_LABEL_SET;
|
||||
SET_FLAG(temp.flags, MATCH_FLOW_LABEL_SET);
|
||||
temp.flow_label = bpf->flow_label->val;
|
||||
}
|
||||
|
||||
if (bpf->fragment) {
|
||||
if (bpf->fragment->mask)
|
||||
temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
|
||||
SET_FLAG(temp.flags, MATCH_FRAGMENT_INVERSE_SET);
|
||||
temp.fragment = bpf->fragment->val;
|
||||
}
|
||||
|
||||
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;
|
||||
else
|
||||
temp.type = IPSET_NET;
|
||||
} 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;
|
||||
else
|
||||
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.priority = 20;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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.family = bpf->family;
|
||||
if (bpf->src)
|
||||
temp.flags |= MATCH_IP_SRC_SET;
|
||||
SET_FLAG(temp.flags, MATCH_IP_SRC_SET);
|
||||
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 (bpf->protocol == IPPROTO_ICMP)
|
||||
temp.flags |= MATCH_ICMP_SET;
|
||||
temp.flags |= MATCH_PORT_SRC_SET;
|
||||
SET_FLAG(temp.flags, MATCH_ICMP_SET);
|
||||
SET_FLAG(temp.flags, MATCH_PORT_SRC_SET);
|
||||
}
|
||||
if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
|
||||
if (bpf->protocol == IPPROTO_ICMP)
|
||||
temp.flags |= MATCH_ICMP_SET;
|
||||
temp.flags |= MATCH_PORT_DST_SET;
|
||||
SET_FLAG(temp.flags, MATCH_ICMP_SET);
|
||||
SET_FLAG(temp.flags, MATCH_PORT_DST_SET);
|
||||
}
|
||||
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)
|
||||
temp.flags |= MATCH_PORT_DST_RANGE_SET;
|
||||
SET_FLAG(temp.flags, MATCH_PORT_DST_RANGE_SET);
|
||||
|
||||
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;
|
||||
else
|
||||
temp.type = IPSET_NET;
|
||||
} 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;
|
||||
else
|
||||
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;
|
||||
} else if (bpf->pkt_len_val) {
|
||||
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;
|
||||
}
|
||||
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->mask)
|
||||
temp.flags |= MATCH_DSCP_INVERSE_SET;
|
||||
SET_FLAG(temp.flags, MATCH_DSCP_INVERSE_SET);
|
||||
else
|
||||
temp.flags |= MATCH_DSCP_SET;
|
||||
SET_FLAG(temp.flags, MATCH_DSCP_SET);
|
||||
temp.dscp_value = bpf->dscp->val;
|
||||
}
|
||||
if (bpf->flow_label) {
|
||||
if (bpf->flow_label->mask)
|
||||
temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
|
||||
SET_FLAG(temp.flags, MATCH_FLOW_LABEL_INVERSE_SET);
|
||||
else
|
||||
temp.flags |= MATCH_FLOW_LABEL_SET;
|
||||
SET_FLAG(temp.flags, MATCH_FLOW_LABEL_SET);
|
||||
temp.flow_label = bpf->flow_label->val;
|
||||
}
|
||||
if (bpf->fragment) {
|
||||
if (bpf->fragment->mask)
|
||||
temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
|
||||
SET_FLAG(temp.flags, MATCH_FRAGMENT_INVERSE_SET);
|
||||
temp.fragment = bpf->fragment->val;
|
||||
}
|
||||
if (bpf->protocol) {
|
||||
temp.protocol = bpf->protocol;
|
||||
temp.flags |= MATCH_PROTOCOL_SET;
|
||||
SET_FLAG(temp.flags, MATCH_PROTOCOL_SET);
|
||||
}
|
||||
temp.action = bpa;
|
||||
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(&bpf, 0, sizeof(bpf));
|
||||
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->match_bitmask_iprule & PREFIX_SRC_PRESENT))
|
||||
CHECK_FLAG(api->match_bitmask_iprule, PREFIX_SRC_PRESENT)))
|
||||
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->match_bitmask_iprule & PREFIX_DST_PRESENT))
|
||||
CHECK_FLAG(api->match_bitmask_iprule, PREFIX_DST_PRESENT)))
|
||||
dst = &api->dst_prefix;
|
||||
if (api->type == BGP_PBR_IPRULE)
|
||||
bpf.type = api->type;
|
||||
|
@ -2812,8 +2793,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
|
|||
}
|
||||
break;
|
||||
case ACTION_TRAFFIC_ACTION:
|
||||
if (api->actions[i].u.za.filter
|
||||
& TRAFFIC_ACTION_SAMPLE) {
|
||||
if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_SAMPLE)) {
|
||||
if (BGP_DEBUG(pbr, PBR)) {
|
||||
bgp_pbr_print_policy_route(api);
|
||||
zlog_warn("PBR: Sample action Ignored");
|
||||
|
|
464
bgpd/bgp_route.c
464
bgpd/bgp_route.c
|
@ -525,8 +525,6 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
|
|||
else
|
||||
bgp_dest_set_bgp_path_info(dest, pi->next);
|
||||
|
||||
bgp_path_info_mpath_dequeue(pi);
|
||||
|
||||
pi->next = 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,
|
||||
struct bgp_path_info *pi)
|
||||
{
|
||||
bgp_path_info_mpath_dequeue(pi);
|
||||
|
||||
pi->next = NULL;
|
||||
pi->prev = NULL;
|
||||
|
||||
|
@ -837,8 +833,13 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
|||
* with the
|
||||
* sticky flag.
|
||||
*/
|
||||
if (newattr->sticky != existattr->sticky) {
|
||||
if (newattr->sticky && !existattr->sticky) {
|
||||
bool new_sticky = CHECK_FLAG(newattr->evpn_flags,
|
||||
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;
|
||||
if (debug)
|
||||
zlog_debug(
|
||||
|
@ -847,7 +848,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!newattr->sticky && existattr->sticky) {
|
||||
if (!new_sticky && exist_sticky) {
|
||||
*reason = bgp_path_selection_evpn_sticky_mac;
|
||||
if (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)) &&
|
||||
CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) &&
|
||||
CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP)) {
|
||||
uint64_t new_aigp = bgp_attr_get_aigp_metric(newattr);
|
||||
uint64_t exist_aigp = bgp_attr_get_aigp_metric(existattr);
|
||||
uint64_t new_aigp = bgp_aigp_metric_total(new);
|
||||
uint64_t exist_aigp = bgp_aigp_metric_total(exist);
|
||||
|
||||
if (new_aigp < exist_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
|
||||
* path compare.
|
||||
*/
|
||||
|
@ -1588,8 +1586,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
|||
if (ret == 1) {
|
||||
*reason = bgp_path_selection_neighbor_ip;
|
||||
if (debug)
|
||||
zlog_debug(
|
||||
"%s: %s loses to %s due to Neighor IP comparison",
|
||||
zlog_debug("%s: %s loses to %s due to Neighbor IP comparison",
|
||||
pfx_buf, new_buf, exist_buf);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1597,8 +1594,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
|||
if (ret == -1) {
|
||||
*reason = bgp_path_selection_neighbor_ip;
|
||||
if (debug)
|
||||
zlog_debug(
|
||||
"%s: %s wins over %s due to Neighor IP comparison",
|
||||
zlog_debug("%s: %s wins over %s due to Neighbor IP comparison",
|
||||
pfx_buf, new_buf, exist_buf);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1780,14 +1776,13 @@ static bool bgp_community_filter(struct peer *peer, struct attr *attr)
|
|||
return true;
|
||||
|
||||
/* NO_EXPORT check. */
|
||||
if (peer->sort == BGP_PEER_EBGP &&
|
||||
community_include(bgp_attr_get_community(attr),
|
||||
COMMUNITY_NO_EXPORT))
|
||||
if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD &&
|
||||
community_include(bgp_attr_get_community(attr), COMMUNITY_NO_EXPORT))
|
||||
return true;
|
||||
|
||||
/* NO_EXPORT_SUBCONFED check. */
|
||||
if (peer->sort == BGP_PEER_EBGP
|
||||
|| peer->sort == BGP_PEER_CONFED)
|
||||
if ((peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD) ||
|
||||
peer->sort == BGP_PEER_CONFED)
|
||||
if (community_include(bgp_attr_get_community(attr),
|
||||
COMMUNITY_NO_EXPORT_SUBCONFED))
|
||||
return true;
|
||||
|
@ -2156,6 +2151,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
|
|||
bool nh_reset = false;
|
||||
uint64_t cum_bw;
|
||||
mpls_label_t label;
|
||||
bool global_and_ll = false;
|
||||
|
||||
if (DISABLE_BGP_ANNOUNCE)
|
||||
return false;
|
||||
|
@ -2170,8 +2166,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
|
|||
from = pi->peer;
|
||||
filter = &peer->filter[afi][safi];
|
||||
bgp = SUBGRP_INST(subgrp);
|
||||
piattr = bgp_path_info_mpath_count(pi) ? bgp_path_info_mpath_attr(pi)
|
||||
: pi->attr;
|
||||
piattr = bgp_path_info_mpath_count(pi) > 1 ? bgp_path_info_mpath_attr(pi) : pi->attr;
|
||||
|
||||
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT) &&
|
||||
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 `::`.
|
||||
*/
|
||||
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)
|
||||
&& IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local))
|
||||
|| (!reflect && !transparent
|
||||
&& IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local)
|
||||
&& peer->shared_network
|
||||
&& (from == bgp->peer_self
|
||||
|| peer->sort == BGP_PEER_EBGP))) {
|
||||
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) {
|
||||
/* nexthop local unchanged: only include the link-local nexthop if it
|
||||
* was already present.
|
||||
*/
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local))
|
||||
global_and_ll = true;
|
||||
} else if (!reflect && !transparent &&
|
||||
IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) && peer->shared_network &&
|
||||
(from == bgp->peer_self || peer->sort == BGP_PEER_EBGP))
|
||||
global_and_ll = true;
|
||||
|
||||
if (global_and_ll) {
|
||||
if (safi == SAFI_MPLS_VPN)
|
||||
attr->mp_nexthop_len =
|
||||
BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL;
|
||||
else
|
||||
attr->mp_nexthop_len =
|
||||
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
|
||||
* needed to
|
||||
* ensure more prefixes share the same attribute for
|
||||
* announcement.
|
||||
*/
|
||||
if (!(CHECK_FLAG(peer->af_flags[afi][safi],
|
||||
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)))
|
||||
if (!(CHECK_FLAG(peer->af_flags[afi][safi], 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);
|
||||
}
|
||||
|
||||
|
@ -2814,6 +2816,21 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -2848,13 +2865,12 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
|
|||
struct bgp_path_info *pi2;
|
||||
int paths_eq, do_mpath;
|
||||
bool debug, any_comparisons;
|
||||
struct list mp_list;
|
||||
char pfx_buf[PREFIX2STR_BUFFER] = {};
|
||||
char path_buf[PATH_ADDPATH_STR_BUFFER];
|
||||
enum bgp_path_selection_reason reason = bgp_path_selection_none;
|
||||
bool unsorted_items = true;
|
||||
uint32_t num_candidates = 0;
|
||||
|
||||
bgp_mp_list_init(&mp_list);
|
||||
do_mpath =
|
||||
(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",
|
||||
dest, bgp->name_pretty,
|
||||
path_buf);
|
||||
bgp_mp_list_add(&mp_list, pi);
|
||||
SET_FLAG(pi->flags, BGP_PATH_MULTIPATH_NEW);
|
||||
num_candidates++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -3242,15 +3259,6 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
|
|||
if (!peer_established(pi->peer->connection))
|
||||
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,
|
||||
mpath_cfg, debug, pfx_buf, afi, safi,
|
||||
&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",
|
||||
dest, bgp->name_pretty,
|
||||
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,
|
||||
mpath_cfg);
|
||||
bgp_path_info_mpath_update(bgp, dest, new_select, old_select, num_candidates, mpath_cfg);
|
||||
bgp_path_info_mpath_aggregate_update(new_select, old_select);
|
||||
bgp_mp_list_clear(&mp_list);
|
||||
|
||||
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;
|
||||
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)
|
||||
debug = bgp_debug_bestpath(dest);
|
||||
if (debug)
|
||||
|
@ -3763,7 +3779,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
|
|||
if (old_select || new_select) {
|
||||
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(
|
||||
bm->master,
|
||||
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;
|
||||
int cnt = 0;
|
||||
struct afi_safi_info *thread_info;
|
||||
bool route_sync_pending = false;
|
||||
|
||||
if (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);
|
||||
}
|
||||
|
||||
if (BGP_DEBUG(update, UPDATE_OUT)) {
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) {
|
||||
zlog_debug("%s: processing route for %s : cnt %d", __func__,
|
||||
get_afi_safi_str(afi, safi, false),
|
||||
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 */
|
||||
bgp_zebra_update(bgp, afi, safi,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -4001,8 +4034,9 @@ static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp)
|
|||
return pqnode;
|
||||
}
|
||||
|
||||
void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
|
||||
struct bgp_path_info *pi, afi_t afi, safi_t safi)
|
||||
static void bgp_process_internal(struct bgp *bgp, struct bgp_dest *dest,
|
||||
struct bgp_path_info *pi, afi_t afi,
|
||||
safi_t safi, bool early_process)
|
||||
{
|
||||
#define ARBITRARY_PROCESS_QLEN 10000
|
||||
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);
|
||||
pqnode = item->data;
|
||||
|
||||
if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)
|
||||
|| pqnode->bgp != bgp
|
||||
|| pqnode->queued >= ARBITRARY_PROCESS_QLEN)
|
||||
if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) ||
|
||||
(pqnode->queued >= ARBITRARY_PROCESS_QLEN && !early_process))
|
||||
pqnode = bgp_processq_alloc(bgp);
|
||||
else
|
||||
pqnode_reuse = 1;
|
||||
|
@ -4081,6 +4114,9 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
|
|||
|
||||
/* can't be enqueued twice */
|
||||
assert(STAILQ_NEXT(dest, pq) == NULL);
|
||||
if (early_process)
|
||||
STAILQ_INSERT_HEAD(&pqnode->pqueue, dest, pq);
|
||||
else
|
||||
STAILQ_INSERT_TAIL(&pqnode->pqueue, dest, pq);
|
||||
pqnode->queued++;
|
||||
|
||||
|
@ -4090,6 +4126,18 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
|
|||
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)
|
||||
{
|
||||
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
|
||||
* attr->evpn_overlay, so that, this can be stored in adj_in.
|
||||
*/
|
||||
if ((afi == AFI_L2VPN) && evpn) {
|
||||
memcpy(&attr->evpn_overlay, evpn,
|
||||
sizeof(struct bgp_route_evpn));
|
||||
}
|
||||
if ((afi == AFI_L2VPN) && evpn)
|
||||
bgp_attr_set_evpn_overlay(attr, evpn);
|
||||
else
|
||||
evpn_overlay_free(evpn);
|
||||
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)
|
||||
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;
|
||||
else
|
||||
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.
|
||||
*/
|
||||
if (soft_reconfig && (afi == AFI_L2VPN) && evpn)
|
||||
memcpy(&new_attr.evpn_overlay, evpn,
|
||||
sizeof(struct bgp_route_evpn));
|
||||
bgp_attr_set_evpn_overlay(&new_attr, evpn);
|
||||
else
|
||||
evpn_overlay_free(evpn);
|
||||
|
||||
/* Apply incoming 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);
|
||||
}
|
||||
|
||||
if (peer->sort == BGP_PEER_EBGP) {
|
||||
|
||||
/* rfc7999:
|
||||
* A BGP speaker receiving an announcement tagged with the
|
||||
* 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))
|
||||
bgp_attr_add_no_export_community(&new_attr);
|
||||
|
||||
if (peer->sort == BGP_PEER_EBGP) {
|
||||
/* If we receive the graceful-shutdown community from an eBGP
|
||||
* peer we must lower local-preference */
|
||||
if (bgp_attr_get_community(&new_attr) &&
|
||||
|
@ -5424,7 +5487,7 @@ filtered:
|
|||
void bgp_withdraw(struct peer *peer, const struct prefix *p,
|
||||
uint32_t addpath_id, afi_t afi, safi_t safi, int type,
|
||||
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;
|
||||
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;
|
||||
uint8_t num_labels;
|
||||
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)
|
||||
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;
|
||||
label_pnt = num_labels ? &ain->labels->label[0] : NULL;
|
||||
|
||||
if (pi)
|
||||
memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
|
||||
sizeof(evpn));
|
||||
else
|
||||
memset(&evpn, 0, sizeof(evpn));
|
||||
bre = bgp_attr_get_evpn_overlay(pi->attr);
|
||||
|
||||
bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id,
|
||||
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,
|
||||
|
@ -6218,7 +6279,6 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
|
|||
vpn_leak_to_vrf_withdraw(pi);
|
||||
|
||||
bgp_rib_remove(rm, pi, peer, afi, safi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -6247,7 +6307,6 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
|
|||
pi);
|
||||
|
||||
bgp_rib_remove(dest, pi, peer, afi, safi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6405,18 +6464,23 @@ void bgp_cleanup_routes(struct bgp *bgp)
|
|||
if (afi != AFI_L2VPN) {
|
||||
safi_t safi;
|
||||
safi = SAFI_MPLS_VPN;
|
||||
for (dest = bgp_table_top(bgp->rib[afi][safi]); dest;
|
||||
dest = bgp_route_next(dest)) {
|
||||
table = bgp_dest_get_bgp_table_info(dest);
|
||||
if (!IS_BGP_INSTANCE_HIDDEN(bgp)) {
|
||||
for (dest = bgp_table_top(bgp->rib[afi][safi]);
|
||||
dest; dest = bgp_route_next(dest)) {
|
||||
table = bgp_dest_get_bgp_table_info(
|
||||
dest);
|
||||
if (table != NULL) {
|
||||
bgp_cleanup_table(bgp, table, afi, safi);
|
||||
bgp_cleanup_table(bgp, table,
|
||||
afi, safi);
|
||||
bgp_table_finish(&table);
|
||||
bgp_dest_set_bgp_table_info(dest, NULL);
|
||||
dest = bgp_dest_unlock_node(dest);
|
||||
|
||||
bgp_dest_set_bgp_table_info(dest,
|
||||
NULL);
|
||||
dest = bgp_dest_unlock_node(
|
||||
dest);
|
||||
assert(dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
safi = SAFI_ENCAP;
|
||||
for (dest = bgp_table_top(bgp->rib[afi][safi]); dest;
|
||||
dest = bgp_route_next(dest)) {
|
||||
|
@ -6588,7 +6652,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
|
|||
else
|
||||
bgp_withdraw(peer, &p, addpath_id, afi, safi,
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
|
||||
NULL, 0, NULL);
|
||||
NULL, 0);
|
||||
|
||||
/* Do not send BGP notification twice when maximum-prefix count
|
||||
* overflow. */
|
||||
|
@ -6698,9 +6762,6 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
|
|||
if (afi == AFI_IP)
|
||||
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)
|
||||
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 (bgp_static->gatewayIp.family == AF_INET) {
|
||||
SET_IPADDR_V4(&attr.evpn_overlay.gw_ip);
|
||||
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4,
|
||||
struct bgp_route_evpn *bre =
|
||||
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,
|
||||
IPV4_MAX_BYTELEN);
|
||||
bgp_attr_set_evpn_overlay(&attr, bre);
|
||||
} else if (bgp_static->gatewayIp.family == AF_INET6) {
|
||||
SET_IPADDR_V6(&attr.evpn_overlay.gw_ip);
|
||||
memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6,
|
||||
struct bgp_route_evpn *bre =
|
||||
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,
|
||||
IPV6_MAX_BYTELEN);
|
||||
bgp_attr_set_evpn_overlay(&attr, bre);
|
||||
}
|
||||
memcpy(&attr.esi, bgp_static->eth_s_id, sizeof(esi_t));
|
||||
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.tag = tag;
|
||||
|
||||
if (metric)
|
||||
bgp_attr_set_aigp_metric(&attr, metric);
|
||||
|
||||
afi = family2afi(p->family);
|
||||
|
||||
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. */
|
||||
attr_new = attr;
|
||||
|
||||
if (red->redist_metric_flag) {
|
||||
if (red->redist_metric_flag)
|
||||
attr_new.med = red->redist_metric;
|
||||
bgp_attr_set_aigp_metric(&attr_new, red->redist_metric);
|
||||
}
|
||||
|
||||
/* Apply route-map. */
|
||||
if (red->rmap.name) {
|
||||
memset(&rmap_path, 0, sizeof(rmap_path));
|
||||
rmap_path.peer = bgp->peer_self;
|
||||
rmap_path.attr = &attr_new;
|
||||
rmap_path.type = type;
|
||||
|
||||
SET_FLAG(bgp->peer_self->rmap_type,
|
||||
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_nexthop = NULL;
|
||||
json_object *json_overlay = NULL;
|
||||
struct bgp_route_evpn *bre = NULL;
|
||||
|
||||
if (!path->extra)
|
||||
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)
|
||||
vty_out(vty, "/%pIA", &eo->gw_ip);
|
||||
vty_out(vty, "/%pIA", &bre->gw_ip);
|
||||
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)) {
|
||||
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;
|
||||
struct bgp_path_info *bpi_ultimate =
|
||||
bgp_get_imported_bpi_ultimate(path);
|
||||
struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr);
|
||||
|
||||
if (json_paths) {
|
||||
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
|
||||
&& attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
|
||||
if (safi == SAFI_EVPN && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
|
||||
char gwip_buf[INET6_ADDRSTRLEN];
|
||||
|
||||
ipaddr2str(&attr->evpn_overlay.gw_ip, gwip_buf,
|
||||
sizeof(gwip_buf));
|
||||
ipaddr2str(&bre->gw_ip, gwip_buf, sizeof(gwip_buf));
|
||||
|
||||
if (json_paths)
|
||||
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");
|
||||
|
||||
|
||||
if (path->extra && path->extra->vrfleak &&
|
||||
path->extra->vrfleak->parent && !json_paths) {
|
||||
if (path->extra && path->extra->vrfleak && path->extra->vrfleak->parent) {
|
||||
struct bgp_path_info *parent_ri;
|
||||
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) {
|
||||
pdest = dest->pdest;
|
||||
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, BGP_RD_AS_FORMAT(bgp->asnotation),
|
||||
(struct prefix_rd *)bgp_dest_get_prefix(
|
||||
vty_out(vty,
|
||||
BGP_RD_AS_FORMAT(bgp->asnotation),
|
||||
(struct prefix_rd *)
|
||||
bgp_dest_get_prefix(
|
||||
pdest));
|
||||
vty_out(vty, ":%pFX, VNI %s",
|
||||
(struct prefix_evpn *)
|
||||
bgp_dest_get_prefix(dest),
|
||||
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",
|
||||
CHECK_FLAG(
|
||||
attr->es_flags,
|
||||
|
@ -10567,15 +10651,36 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
|||
? "active"
|
||||
: "inactive");
|
||||
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 {
|
||||
vty_out(vty, " Imported from ");
|
||||
vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
|
||||
(struct prefix_rd *)bgp_dest_get_prefix(
|
||||
vty_out(vty,
|
||||
BGP_RD_AS_FORMAT(bgp->asnotation),
|
||||
(struct prefix_rd *)
|
||||
bgp_dest_get_prefix(
|
||||
pdest));
|
||||
vty_out(vty, ":%pFX\n",
|
||||
(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);
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH)
|
||||
|| (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)
|
||||
&& bgp_path_info_mpath_count(path))) {
|
||||
if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH) ||
|
||||
(CHECK_FLAG(path->flags, BGP_PATH_SELECTED) && bgp_path_info_mpath_count(path) > 1)) {
|
||||
if (json_paths)
|
||||
json_object_boolean_true_add(json_path, "multipath");
|
||||
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)
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, dest,
|
||||
bgp_dest_get_prefix(
|
||||
dest),
|
||||
bgp_dest_get_prefix(dest),
|
||||
prd, table->afi, safi,
|
||||
NULL, false);
|
||||
NULL, false, false);
|
||||
|
||||
route_vty_out_detail(
|
||||
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);
|
||||
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, dest,
|
||||
bgp_dest_get_prefix(dest), prd,
|
||||
table->afi, safi, json_paths, true);
|
||||
route_vty_out_detail_header(vty, bgp, dest,
|
||||
bgp_dest_get_prefix(
|
||||
dest),
|
||||
prd, table->afi,
|
||||
safi, json_paths,
|
||||
true, false);
|
||||
|
||||
vty_out(vty, "\"paths\": ");
|
||||
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();
|
||||
}
|
||||
|
||||
if (bgp == NULL) {
|
||||
if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) {
|
||||
if (!use_json)
|
||||
vty_out(vty, "No BGP process is configured\n");
|
||||
else
|
||||
|
@ -12115,6 +12220,8 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
|
|||
vty_out(vty, "{\n");
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
|
||||
if (IS_BGP_INSTANCE_HIDDEN(bgp))
|
||||
continue;
|
||||
route_output = true;
|
||||
if (use_json) {
|
||||
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,
|
||||
const struct prefix_rd *prd, afi_t afi,
|
||||
safi_t safi, json_object *json,
|
||||
bool incremental_print)
|
||||
bool incremental_print, bool local_table)
|
||||
{
|
||||
struct bgp_path_info *pi;
|
||||
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);
|
||||
|
||||
has_valid_label = bgp_is_valid_label(&label);
|
||||
has_valid_label = bgp_is_valid_label(&dest->local_label);
|
||||
|
||||
if (safi == SAFI_EVPN) {
|
||||
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_adv_to);
|
||||
} else {
|
||||
if (!json && first)
|
||||
vty_out(vty, " Not advertised to any peer");
|
||||
if (!json && first) {
|
||||
if (!local_table)
|
||||
vty_out(vty,
|
||||
" Not advertised to any peer");
|
||||
else
|
||||
vty_out(vty,
|
||||
" Local BGP table not advertised");
|
||||
}
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
}
|
||||
|
@ -12405,10 +12518,10 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
|
|||
}
|
||||
|
||||
if (header) {
|
||||
route_vty_out_detail_header(
|
||||
vty, bgp, bgp_node,
|
||||
bgp_dest_get_prefix(bgp_node), pfx_rd, AFI_IP,
|
||||
safi, json_header, false);
|
||||
route_vty_out_detail_header(vty, bgp, bgp_node,
|
||||
bgp_dest_get_prefix(bgp_node),
|
||||
pfx_rd, AFI_IP, safi,
|
||||
json_header, false, false);
|
||||
header = 0;
|
||||
}
|
||||
(*display)++;
|
||||
|
@ -12627,7 +12740,7 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str,
|
|||
{
|
||||
if (!bgp) {
|
||||
bgp = bgp_get_default();
|
||||
if (!bgp) {
|
||||
if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) {
|
||||
if (!use_json)
|
||||
vty_out(vty, "No BGP process is configured\n");
|
||||
else
|
||||
|
@ -12878,7 +12991,7 @@ DEFUN (show_ip_bgp_l2vpn_evpn_statistics,
|
|||
struct json_object *json_afi_safi = NULL, *json = NULL;
|
||||
|
||||
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
|
||||
&bgp, false);
|
||||
&bgp, uj);
|
||||
if (!idx)
|
||||
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;
|
||||
|
||||
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
|
||||
&bgp, false);
|
||||
&bgp, uj);
|
||||
if (!idx)
|
||||
return CMD_WARNING;
|
||||
|
||||
|
@ -13579,6 +13692,8 @@ enum bgp_stats {
|
|||
BGP_STATS_ASPATH_MAXSIZE,
|
||||
BGP_STATS_ASPATH_TOTSIZE,
|
||||
BGP_STATS_ASN_HIGHEST,
|
||||
BGP_STATS_REDISTRIBUTED,
|
||||
BGP_STATS_LOCAL_AGGREGATES,
|
||||
BGP_STATS_MAX,
|
||||
};
|
||||
|
||||
|
@ -13608,6 +13723,8 @@ static const char *table_stats_strs[][2] = {
|
|||
[BGP_STATS_ASPATH_TOTSIZE] = {"Average AS-Path size (bytes)",
|
||||
"averageAsPathSizeBytes"},
|
||||
[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}
|
||||
};
|
||||
|
||||
|
@ -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)))
|
||||
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 */
|
||||
if (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;
|
||||
char *network = NULL;
|
||||
struct bgp *bgp = bgp_get_default();
|
||||
if (!bgp) {
|
||||
if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) {
|
||||
vty_out(vty, "Can't find default instance\n");
|
||||
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_dest *dest;
|
||||
struct bgp *bgp;
|
||||
struct attr attr;
|
||||
struct attr attr, attr_unchanged;
|
||||
int ret;
|
||||
struct update_subgroup *subgrp;
|
||||
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_unchanged = *ain->attr;
|
||||
route_filtered = false;
|
||||
|
||||
/* 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,
|
||||
"%pFX", rn_p);
|
||||
} else
|
||||
route_vty_out_tmp(vty, bgp, dest, rn_p,
|
||||
&attr, safi, use_json,
|
||||
json_ar, wide);
|
||||
route_vty_out_tmp(vty, bgp, dest, rn_p, &attr_unchanged,
|
||||
safi, use_json, json_ar, wide);
|
||||
bgp_attr_flush(&attr);
|
||||
(*output_count)++;
|
||||
}
|
||||
|
@ -15774,7 +15900,7 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
|
|||
/* BGP structure lookup. */
|
||||
if (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",
|
||||
view_name);
|
||||
return CMD_WARNING;
|
||||
|
|
|
@ -313,6 +313,11 @@ struct bgp_path_info {
|
|||
#define BGP_PATH_STALE (1 << 8)
|
||||
#define BGP_PATH_REMOVED (1 << 9)
|
||||
#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_CHG (1 << 12)
|
||||
#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_NH_LABEL_BIND (1 << 18)
|
||||
#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. */
|
||||
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,
|
||||
uint32_t addpath_id, afi_t afi, safi_t safi, int type,
|
||||
int sub_type, struct prefix_rd *prd,
|
||||
mpls_label_t *label, uint8_t num_labels,
|
||||
struct bgp_route_evpn *evpn);
|
||||
mpls_label_t *label, uint8_t num_labels);
|
||||
|
||||
/* 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,
|
||||
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
|
||||
* 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_rd *prd, afi_t afi,
|
||||
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,
|
||||
struct bgp_dest *bn, const struct prefix *p,
|
||||
struct bgp_path_info *path, afi_t afi,
|
||||
|
|
|
@ -251,7 +251,7 @@ route_match_peer(void *rule, const struct prefix *prefix, void *object)
|
|||
peer = ((struct bgp_path_info *)object)->peer;
|
||||
|
||||
if (pc->interface) {
|
||||
if (!peer->conf_if || !peer->group)
|
||||
if (!peer->conf_if && !peer->group)
|
||||
return RMAP_NOMATCH;
|
||||
|
||||
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);
|
||||
if (plist == NULL) {
|
||||
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL)))
|
||||
zlog_debug(
|
||||
"%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
|
||||
__func__, (char *)rule);
|
||||
zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH",
|
||||
__func__, (char *)rule, afi2str(afi));
|
||||
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 bgp_path_info *path;
|
||||
struct prefix_evpn *evp;
|
||||
struct bgp_route_evpn *bre = XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
|
||||
sizeof(struct bgp_route_evpn));
|
||||
|
||||
if (prefix->family != AF_EVPN)
|
||||
return RMAP_OKAY;
|
||||
|
@ -1252,9 +1253,9 @@ route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
|
|||
path = object;
|
||||
|
||||
/* Set gateway-ip value. */
|
||||
path->attr->evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
|
||||
memcpy(&path->attr->evpn_overlay.gw_ip, &gw_ip->ip.addr,
|
||||
IPADDRSZ(gw_ip));
|
||||
bre->type = OVERLAY_INDEX_GATEWAY_IP;
|
||||
memcpy(&bre->gw_ip, &gw_ip->ip.addr, IPADDRSZ(gw_ip));
|
||||
bgp_attr_set_evpn_overlay(path->attr, bre);
|
||||
|
||||
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,
|
||||
BATTR_RMAP_NEXTHOP_UNCHANGED);
|
||||
} else if (rins->peer_address) {
|
||||
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_INET) {
|
||||
if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)) &&
|
||||
peer->su_remote &&
|
||||
sockunion_family(peer->su_remote) == AF_INET) {
|
||||
path->attr->nexthop.s_addr =
|
||||
sockunion2ip(peer->su_remote);
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -3451,19 +3451,15 @@ route_set_aigp_metric(void *rule, const struct prefix *pfx, void *object)
|
|||
{
|
||||
const char *aigp_metric = rule;
|
||||
struct bgp_path_info *path = object;
|
||||
uint32_t aigp = 0;
|
||||
uint32_t aigp;
|
||||
|
||||
if (strmatch(aigp_metric, "igp-metric")) {
|
||||
if (!path->nexthop)
|
||||
return RMAP_NOMATCH;
|
||||
|
||||
bgp_attr_set_aigp_metric(path->attr, path->nexthop->metric);
|
||||
} else {
|
||||
/* Note: the metric is stored as MED for a locally redistributed. */
|
||||
if (strmatch(aigp_metric, "igp-metric"))
|
||||
aigp = path->nexthop ? path->nexthop->metric : path->attr->med;
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
@ -3949,8 +3945,7 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
|
|||
path = object;
|
||||
peer = path->peer;
|
||||
|
||||
if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
|
||||
|| CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) {
|
||||
if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)) {
|
||||
/* Set next hop preference to global */
|
||||
SET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL);
|
||||
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;
|
||||
peer = path->peer;
|
||||
|
||||
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) {
|
||||
if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)) &&
|
||||
peer->su_remote && sockunion_family(peer->su_remote) == AF_INET6) {
|
||||
peer_address = peer->su_remote->sin6.sin6_addr;
|
||||
/* Set next hop value and length in attribute. */
|
||||
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 =
|
||||
BGP_ATTR_NHLEN_IPV6_GLOBAL;
|
||||
}
|
||||
|
||||
} else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) {
|
||||
/* The next hop value will be set as part of packet
|
||||
* rewrite.
|
||||
|
@ -7144,7 +7136,7 @@ DEFUN_YANG (no_set_atomic_aggregate,
|
|||
|
||||
DEFPY_YANG (set_aigp_metric,
|
||||
set_aigp_metric_cmd,
|
||||
"set aigp-metric <igp-metric|(1-4294967295)>$aigp_metric",
|
||||
"set aigp-metric <igp-metric|(0-4294967295)>$aigp_metric",
|
||||
SET_STR
|
||||
"BGP AIGP attribute (AIGP Metric TLV)\n"
|
||||
"AIGP Metric value from IGP protocol\n"
|
||||
|
@ -7164,7 +7156,7 @@ DEFPY_YANG (set_aigp_metric,
|
|||
|
||||
DEFPY_YANG (no_set_aigp_metric,
|
||||
no_set_aigp_metric_cmd,
|
||||
"no set aigp-metric [<igp-metric|(1-4294967295)>]",
|
||||
"no set aigp-metric [<igp-metric|(0-4294967295)>]",
|
||||
NO_STR
|
||||
SET_STR
|
||||
"BGP AIGP attribute (AIGP Metric TLV)\n"
|
||||
|
@ -7236,43 +7228,6 @@ DEFUN_YANG (no_set_aggregator_as,
|
|||
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,
|
||||
match_ipv6_next_hop_address_cmd,
|
||||
"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"
|
||||
"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,
|
||||
match_ipv4_next_hop_cmd,
|
||||
"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_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_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_prefix_list_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, &match_ipv4_next_hop_cmd);
|
||||
|
|
|
@ -1920,81 +1920,6 @@ DEFUN (no_rpki_retry_interval,
|
|||
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,
|
||||
"rpki cache tcp <A.B.C.D|WORD>$cache TCPPORT [source <A.B.C.D>$bindaddr] preference (1-255)",
|
||||
RPKI_OUTPUT_STRING
|
||||
|
@ -2820,7 +2745,6 @@ static void install_cli_commands(void)
|
|||
/* Install rpki cache commands */
|
||||
install_element(RPKI_NODE, &rpki_cache_tcp_cmd);
|
||||
install_element(RPKI_NODE, &rpki_cache_ssh_cmd);
|
||||
install_element(RPKI_NODE, &rpki_cache_cmd);
|
||||
install_element(RPKI_NODE, &no_rpki_cache_cmd);
|
||||
|
||||
/* RPKI_VRF_NODE commands */
|
||||
|
@ -2844,7 +2768,6 @@ static void install_cli_commands(void)
|
|||
/* Install rpki cache commands */
|
||||
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_cmd);
|
||||
install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd);
|
||||
|
||||
/* Install show commands */
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#define __BGP_SCRIPT__
|
||||
|
||||
#include <zebra.h>
|
||||
#include "bgpd.h"
|
||||
|
||||
#ifdef HAVE_SCRIPTING
|
||||
|
||||
|
@ -18,6 +17,10 @@
|
|||
*/
|
||||
void bgp_script_init(void);
|
||||
|
||||
/* Forward references */
|
||||
struct peer;
|
||||
struct attr;
|
||||
|
||||
void lua_pushpeer(lua_State *L, const struct peer *peer);
|
||||
|
||||
void lua_pushattr(lua_State *L, const struct attr *attr);
|
||||
|
|
|
@ -50,6 +50,21 @@ DEFPY(bgp_snmp_traps_rfc4273, bgp_snmp_traps_rfc4273_cmd,
|
|||
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,
|
||||
"[no$no] bgp snmp traps bgp4-mibv2",
|
||||
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_bgp4_mibv2_cmd);
|
||||
install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4382_cmd);
|
||||
|
||||
SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273);
|
||||
/* BGP4MIBv2 traps are disabled by default */
|
||||
|
||||
SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382);
|
||||
}
|
||||
|
||||
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");
|
||||
write++;
|
||||
}
|
||||
if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) {
|
||||
vty_out(vty, "no bgp snmp traps rfc4382\n");
|
||||
write++;
|
||||
}
|
||||
|
||||
return write;
|
||||
}
|
||||
|
|
|
@ -933,7 +933,9 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
|
|||
else
|
||||
return SNMP_IPADDRESS(bgp_empty_addr);
|
||||
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:
|
||||
return aspath_snmp_pathseg(path->attr->aspath, var_len);
|
||||
case BGP4V2_NLRI_PATH_ATTR_UNKNOWN:
|
||||
|
|
|
@ -343,7 +343,12 @@ static unsigned int updgrp_hash_key_make(const void *p)
|
|||
|
||||
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->flags & PEER_UPDGRP_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",
|
||||
CHECK_FLAG(updgrp->conf->flags,
|
||||
PEER_FLAG_LOCAL_AS_REPLACE_AS));
|
||||
json_object_boolean_add(json_updgrp, "dualAs",
|
||||
CHECK_FLAG(updgrp->conf->flags,
|
||||
PEER_FLAG_DUAL_AS));
|
||||
} 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,
|
||||
CHECK_FLAG(updgrp->conf->flags,
|
||||
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,
|
||||
PEER_FLAG_LOCAL_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 listnode *node, *nnode;
|
||||
|
||||
peer_flag_set(peer, PEER_FLAG_LONESOUL);
|
||||
|
||||
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
|
||||
peer_lonesoul_or_not(peer, set);
|
||||
if (peer_established(peer->connection))
|
||||
|
|
|
@ -738,9 +738,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
|||
|
||||
/* 5: Encode all the attributes, except MP_REACH_NLRI
|
||||
* attr. */
|
||||
total_attr_len = bgp_packet_attribute(
|
||||
NULL, peer, s, adv->baa->attr, &vecarr, NULL,
|
||||
afi, safi, from, NULL, NULL, 0, 0, 0, path);
|
||||
total_attr_len = bgp_packet_attribute(NULL, peer, s, adv->baa->attr,
|
||||
&vecarr, NULL, afi, safi, from, NULL,
|
||||
NULL, 0, 0, 0);
|
||||
|
||||
space_remaining =
|
||||
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,
|
||||
label_pnt, num_labels,
|
||||
addpath_capable, addpath_tx_id,
|
||||
&adv->baa->attr->evpn_overlay,
|
||||
bgp_attr_get_evpn_overlay(
|
||||
adv->baa->attr),
|
||||
pfx_buf, sizeof(pfx_buf));
|
||||
zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
|
||||
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. */
|
||||
pos = stream_get_endp(s);
|
||||
stream_putw(s, 0);
|
||||
total_attr_len =
|
||||
bgp_packet_attribute(NULL, peer, s, attr, &vecarr, &p, afi,
|
||||
safi, from, NULL, &label, num_labels,
|
||||
addpath_capable,
|
||||
BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE,
|
||||
NULL);
|
||||
total_attr_len = bgp_packet_attribute(NULL, peer, s, attr, &vecarr, &p, afi, safi, from,
|
||||
NULL, &label, num_labels, addpath_capable,
|
||||
BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
|
||||
|
||||
/* Set Total Path Attribute Length. */
|
||||
stream_putw_at(s, pos, total_attr_len);
|
||||
|
|
734
bgpd/bgp_vty.c
734
bgpd/bgp_vty.c
File diff suppressed because it is too large
Load diff
|
@ -60,8 +60,6 @@ struct bgp;
|
|||
|
||||
#define VTY_BGP_GR_ROUTER_DETECT(_bgp, _peer, _peer_list) \
|
||||
do { \
|
||||
if (_peer->bgp->t_startup) \
|
||||
bgp_peer_gr_flags_update(_peer); \
|
||||
for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \
|
||||
if (CHECK_FLAG(peer_loop->flags, \
|
||||
PEER_FLAG_GRACEFUL_RESTART)) \
|
||||
|
@ -84,27 +82,24 @@ struct bgp;
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \
|
||||
_bgp, _peer_list, _ret) \
|
||||
#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(_bgp, \
|
||||
_peer_list, _ret) \
|
||||
do { \
|
||||
struct peer *peer_loop; \
|
||||
bool gr_router_detected = false; \
|
||||
struct listnode *node = { 0 }; \
|
||||
struct listnode *nnode = { 0 }; \
|
||||
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, \
|
||||
PEER_FLAG_GRACEFUL_RESTART)) \
|
||||
gr_router_detected = true; \
|
||||
} \
|
||||
if (gr_router_detected \
|
||||
&& _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
|
||||
if (gr_router_detected && \
|
||||
_bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
|
||||
if (bgp_zebra_send_capabilities(_bgp, false)) \
|
||||
_ret = BGP_ERR_INVALID_VALUE; \
|
||||
} else if (!gr_router_detected \
|
||||
&& _bgp->present_zebra_gr_state \
|
||||
== ZEBRA_GR_ENABLE) { \
|
||||
} else if (!gr_router_detected && \
|
||||
_bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \
|
||||
if (bgp_zebra_send_capabilities(_bgp, true)) \
|
||||
_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 argc, struct bgp **bgp, bool use_json);
|
||||
extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
|
||||
safi_t safi, const char *neighbor, int as_type,
|
||||
as_t as, uint16_t show_flags);
|
||||
safi_t safi, const char *neighbor,
|
||||
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_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
|
||||
uint64_t flag);
|
||||
|
|
515
bgpd/bgp_zebra.c
515
bgpd/bgp_zebra.c
|
@ -195,7 +195,7 @@ static int bgp_ifp_destroy(struct interface *ifp)
|
|||
bgp = ifp->vrf->info;
|
||||
|
||||
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);
|
||||
|
||||
if (bgp) {
|
||||
|
@ -220,8 +220,7 @@ static int bgp_ifp_up(struct interface *ifp)
|
|||
bgp_mac_add_mac_entry(ifp);
|
||||
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf->vrf_id,
|
||||
ifp->name);
|
||||
zlog_debug("Rx Intf up VRF %s IF %s", ifp->vrf->name, ifp->name);
|
||||
|
||||
if (!bgp)
|
||||
return 0;
|
||||
|
@ -235,7 +234,7 @@ static int bgp_ifp_up(struct interface *ifp)
|
|||
hook_call(bgp_vrf_status_changed, bgp, 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_IP6);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (!bgp)
|
||||
|
@ -290,7 +289,7 @@ static int bgp_ifp_down(struct interface *ifp)
|
|||
hook_call(bgp_vrf_status_changed, bgp, 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_IP6);
|
||||
vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP);
|
||||
|
@ -319,8 +318,8 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
|
|||
return 0;
|
||||
|
||||
if (bgp_debug_zebra(ifc->address))
|
||||
zlog_debug("Rx Intf address add VRF %u IF %s addr %pFX", vrf_id,
|
||||
ifc->ifp->name, ifc->address);
|
||||
zlog_debug("Rx Intf address add VRF %s IF %s addr %pFX",
|
||||
ifc->ifp->vrf->name, ifc->ifp->name, ifc->address);
|
||||
|
||||
if (!bgp)
|
||||
return 0;
|
||||
|
@ -398,8 +397,8 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
|
|||
return 0;
|
||||
|
||||
if (bgp_debug_zebra(ifc->address))
|
||||
zlog_debug("Rx Intf address del VRF %u IF %s addr %pFX", vrf_id,
|
||||
ifc->ifp->name, ifc->address);
|
||||
zlog_debug("Rx Intf address del VRF %s IF %s addr %pFX",
|
||||
ifc->ifp->vrf->name, ifc->ifp->name, ifc->address);
|
||||
|
||||
if (bgp && if_is_operative(ifc->ifp)) {
|
||||
bgp_connected_delete(bgp, ifc);
|
||||
|
@ -450,8 +449,8 @@ static int bgp_interface_nbr_address_add(ZAPI_CALLBACK_ARGS)
|
|||
return 0;
|
||||
|
||||
if (bgp_debug_zebra(ifc->address))
|
||||
zlog_debug("Rx Intf neighbor add VRF %u IF %s addr %pFX",
|
||||
vrf_id, ifc->ifp->name, ifc->address);
|
||||
zlog_debug("Rx Intf neighbor add VRF %s IF %s addr %pFX",
|
||||
ifc->ifp->vrf->name, ifc->ifp->name, ifc->address);
|
||||
|
||||
if (if_is_operative(ifc->ifp)) {
|
||||
bgp = bgp_lookup_by_vrf_id(vrf_id);
|
||||
|
@ -473,8 +472,8 @@ static int bgp_interface_nbr_address_delete(ZAPI_CALLBACK_ARGS)
|
|||
return 0;
|
||||
|
||||
if (bgp_debug_zebra(ifc->address))
|
||||
zlog_debug("Rx Intf neighbor del VRF %u IF %s addr %pFX",
|
||||
vrf_id, ifc->ifp->name, ifc->address);
|
||||
zlog_debug("Rx Intf neighbor del VRF %s IF %s addr %pFX",
|
||||
ifc->ifp->vrf->name, ifc->ifp->name, ifc->address);
|
||||
|
||||
if (if_is_operative(ifc->ifp)) {
|
||||
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. */
|
||||
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);
|
||||
} else {
|
||||
bgp_redistribute_delete(bgp, &api.prefix, api.type,
|
||||
|
@ -556,13 +555,14 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS)
|
|||
if (add) {
|
||||
inet_ntop(api.prefix.family, &nexthop, buf,
|
||||
sizeof(buf));
|
||||
zlog_debug(
|
||||
"Rx route ADD VRF %u %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI,
|
||||
vrf_id, zebra_route_string(api.type),
|
||||
api.instance, &api.prefix, buf, nhtype, ifindex,
|
||||
zlog_debug("Rx route ADD %s %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI,
|
||||
bgp->name_pretty,
|
||||
zebra_route_string(api.type), api.instance,
|
||||
&api.prefix, buf, nhtype, ifindex,
|
||||
api.metric, api.distance, api.tag);
|
||||
} 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,
|
||||
&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 zapi_nexthop *api_nh)
|
||||
{
|
||||
struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr);
|
||||
|
||||
api_nh->gate.ipv4 = *nexthop;
|
||||
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
|
||||
* 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;
|
||||
else {
|
||||
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 attr *attr;
|
||||
struct bgp_route_evpn *bre;
|
||||
|
||||
attr = pi->attr;
|
||||
api_nh->vrf_id = nh_bgp->vrf_id;
|
||||
bre = bgp_attr_get_evpn_overlay(attr);
|
||||
|
||||
if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) {
|
||||
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
|
||||
* 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;
|
||||
else {
|
||||
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||
|
@ -1251,6 +1255,7 @@ static void bgp_zebra_announce_parse_nexthop(
|
|||
uint32_t ttl = 0;
|
||||
uint32_t bos = 0;
|
||||
uint32_t exp = 0;
|
||||
struct bgp_route_evpn *bre = NULL;
|
||||
|
||||
/* Determine if we're doing weighted ECMP or not */
|
||||
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);
|
||||
bre = bgp_attr_get_evpn_overlay(mpinfo->attr);
|
||||
|
||||
/* Did we get proper nexthop info to update zebra? */
|
||||
if (!nh_updated)
|
||||
|
@ -1400,9 +1406,7 @@ static void bgp_zebra_announce_parse_nexthop(
|
|||
api_nh->labels[0] = nh_label;
|
||||
}
|
||||
|
||||
if (is_evpn
|
||||
&& mpinfo->attr->evpn_overlay.type
|
||||
!= OVERLAY_INDEX_GATEWAY_IP)
|
||||
if (is_evpn && !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP))
|
||||
memcpy(&api_nh->rmac, &(mpinfo->attr->rmac),
|
||||
sizeof(struct ethaddr));
|
||||
|
||||
|
@ -1526,7 +1530,6 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
|
|||
struct peer *peer;
|
||||
uint32_t metric;
|
||||
route_tag_t tag;
|
||||
bool is_add;
|
||||
uint32_t nhg_id = 0;
|
||||
struct bgp_table *table = bgp_dest_table(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,
|
||||
&metric, &tag, &allow_recursion);
|
||||
|
||||
is_add = (valid_nh_count || nhg_id) ? true : false;
|
||||
|
||||
if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) {
|
||||
if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) {
|
||||
struct bgp_zebra_opaque bzo = {};
|
||||
const char *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)) {
|
||||
zlog_debug(
|
||||
"Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI
|
||||
zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI
|
||||
" 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);
|
||||
bgp_debug_zebra_nh(&api);
|
||||
|
||||
zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)",
|
||||
__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))
|
||||
zlog_debug("Tx route delete VRF %u %pFX", bgp->vrf_id,
|
||||
&api.prefix);
|
||||
zlog_debug("Tx route delete %s (table id %u) %pFX",
|
||||
bgp->name_pretty, api.tableid, &api.prefix);
|
||||
|
||||
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))
|
||||
zlog_debug("BGP %s route %pBD(%s) with dest %p and flags 0x%x to zebra",
|
||||
install ? "announcing" : "withdrawing", dest,
|
||||
zlog_debug("BGP %s%s route %pBD(%s) with dest %p and flags 0x%x to zebra",
|
||||
install ? "announcing" : "withdrawing",
|
||||
is_evpn ? " evpn" : " ", dest,
|
||||
table->bgp->name_pretty, dest, dest->flags);
|
||||
|
||||
if (install) {
|
||||
|
@ -2069,8 +2070,8 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type,
|
|||
return CMD_SUCCESS;
|
||||
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug("Tx redistribute add VRF %u afi %d %s %d",
|
||||
bgp->vrf_id, afi, zebra_route_string(type),
|
||||
zlog_debug("Tx redistribute add %s afi %d %s %d",
|
||||
bgp->name_pretty, afi, zebra_route_string(type),
|
||||
instance);
|
||||
|
||||
/* Send distribute add message to zebra. */
|
||||
|
@ -2090,8 +2091,8 @@ int bgp_redistribute_resend(struct bgp *bgp, afi_t afi, int type,
|
|||
return -1;
|
||||
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug("Tx redistribute del/add VRF %u afi %d %s %d",
|
||||
bgp->vrf_id, afi, zebra_route_string(type),
|
||||
zlog_debug("Tx redistribute del/add %s afi %d %s %d",
|
||||
bgp->name_pretty, afi, zebra_route_string(type),
|
||||
instance);
|
||||
|
||||
/* 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)) {
|
||||
/* Send distribute delete message to zebra. */
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug("Tx redistribute del VRF %u afi %d %s %d",
|
||||
bgp->vrf_id, afi, zebra_route_string(type),
|
||||
instance);
|
||||
zlog_debug("Tx redistribute del %s afi %d %s %d",
|
||||
bgp->name_pretty, afi,
|
||||
zebra_route_string(type), instance);
|
||||
zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi,
|
||||
type, instance, bgp->vrf_id);
|
||||
}
|
||||
|
@ -2290,7 +2291,7 @@ void bgp_zebra_instance_register(struct bgp *bgp)
|
|||
return;
|
||||
|
||||
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. */
|
||||
zclient_send_reg_requests(zclient, bgp->vrf_id);
|
||||
|
@ -2312,7 +2313,7 @@ void bgp_zebra_instance_deregister(struct bgp *bgp)
|
|||
return;
|
||||
|
||||
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. */
|
||||
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;
|
||||
|
||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA))
|
||||
return;
|
||||
|
||||
/* Don't try to initiate if we're not connected to Zebra */
|
||||
if (zclient->sock < 0)
|
||||
return;
|
||||
|
@ -3325,7 +3329,7 @@ static int bgp_ifp_create(struct interface *ifp)
|
|||
struct bgp *bgp;
|
||||
|
||||
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);
|
||||
|
||||
bgp = ifp->vrf->info;
|
||||
|
@ -3378,11 +3382,278 @@ static int bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
|
|||
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, ¬e, 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)
|
||||
{
|
||||
struct srv6_locator loc = {};
|
||||
struct bgp *bgp = bgp_get_default();
|
||||
const char *loc_name = bgp->srv6_locator_name;
|
||||
|
||||
if (!bgp || !bgp->srv6_enabled)
|
||||
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)
|
||||
return -1;
|
||||
|
||||
if (bgp_zebra_srv6_manager_get_locator_chunk(loc_name) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return bgp_zebra_process_srv6_locator_internal(&loc);
|
||||
}
|
||||
|
||||
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 bgp *bgp = bgp_get_default();
|
||||
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 *bgp_vrf;
|
||||
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)
|
||||
return -1;
|
||||
|
||||
// clear SRv6 locator
|
||||
if (bgp->srv6_locator) {
|
||||
srv6_locator_free(bgp->srv6_locator);
|
||||
bgp->srv6_locator = NULL;
|
||||
}
|
||||
|
||||
// refresh chunks
|
||||
for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk))
|
||||
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.prefix = tovpn_sid_locator->prefix.prefix;
|
||||
if (prefix_match((struct prefix *)&loc.prefix,
|
||||
(struct prefix *)&tmp_prefi))
|
||||
srv6_locator_chunk_free(
|
||||
&bgp_vrf->vpn_policy[AFI_IP]
|
||||
(struct prefix *)&tmp_prefi)) {
|
||||
srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP]
|
||||
.tovpn_sid_locator);
|
||||
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator =
|
||||
NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.prefix = tovpn_sid_locator->prefix.prefix;
|
||||
if (prefix_match((struct prefix *)&loc.prefix,
|
||||
(struct prefix *)&tmp_prefi))
|
||||
srv6_locator_chunk_free(
|
||||
&bgp_vrf->vpn_policy[AFI_IP6]
|
||||
(struct prefix *)&tmp_prefi)) {
|
||||
srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP6]
|
||||
.tovpn_sid_locator);
|
||||
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator =
|
||||
NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.prefix = tovpn_sid_locator->prefix.prefix;
|
||||
if (prefix_match((struct prefix *)&loc.prefix,
|
||||
(struct prefix *)&tmp_prefi))
|
||||
srv6_locator_chunk_free(
|
||||
&bgp_vrf->tovpn_sid_locator);
|
||||
(struct prefix *)&tmp_prefi)) {
|
||||
srv6_locator_free(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_MANAGER_GET_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)
|
||||
|
@ -3582,16 +3863,19 @@ void bgp_if_init(void)
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/* Connect to label manager. */
|
||||
|
@ -3963,6 +4247,11 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable)
|
|||
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
|
||||
* 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)
|
||||
== ZCLIENT_SEND_FAILURE) {
|
||||
zlog_err("%s: %s error sending capability", __func__,
|
||||
bgp->name_pretty);
|
||||
zlog_err("%s(%d): Error sending GR capability to zebra",
|
||||
bgp->name_pretty, bgp->vrf_id);
|
||||
ret = BGP_GR_FAILURE;
|
||||
} else {
|
||||
if (disable)
|
||||
|
@ -3987,9 +4276,6 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable)
|
|||
else
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
ifindex_t ifindex, vrf_id_t vrf_id,
|
||||
enum lsp_types_t ltype, struct prefix *p,
|
||||
|
|
|
@ -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_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_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,
|
||||
ifindex_t index, vrf_id_t vrfid,
|
||||
enum lsp_types_t ltype,
|
||||
|
|
448
bgpd/bgpd.c
448
bgpd/bgpd.c
File diff suppressed because it is too large
Load diff
147
bgpd/bgpd.h
147
bgpd/bgpd.h
|
@ -56,10 +56,12 @@ struct bgp_pbr_config;
|
|||
* behavior
|
||||
* in the system.
|
||||
*/
|
||||
enum { AS_UNSPECIFIED = 0,
|
||||
AS_SPECIFIED,
|
||||
AS_INTERNAL,
|
||||
AS_EXTERNAL,
|
||||
enum peer_asn_type {
|
||||
AS_UNSPECIFIED = 1,
|
||||
AS_SPECIFIED = 2,
|
||||
AS_INTERNAL = 4,
|
||||
AS_EXTERNAL = 8,
|
||||
AS_AUTO = 16,
|
||||
};
|
||||
|
||||
/* Zebra Gracaful Restart states */
|
||||
|
@ -129,6 +131,7 @@ struct bgp_master {
|
|||
#define BGP_OPT_NO_ZEBRA (1 << 2)
|
||||
#define BGP_OPT_TRAPS_RFC4273 (1 << 3)
|
||||
#define BGP_OPT_TRAPS_BGP4MIBV2 (1 << 4)
|
||||
#define BGP_OPT_TRAPS_RFC4382 (1 << 5)
|
||||
|
||||
uint64_t updgrp_idspace;
|
||||
uint64_t subgrp_idspace;
|
||||
|
@ -163,6 +166,24 @@ struct bgp_master {
|
|||
uint32_t flags;
|
||||
#define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0)
|
||||
#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 */
|
||||
|
||||
|
@ -250,7 +271,7 @@ struct vpn_policy {
|
|||
*/
|
||||
uint32_t tovpn_sid_index; /* unset => set to 0 */
|
||||
struct in6_addr *tovpn_sid;
|
||||
struct srv6_locator_chunk *tovpn_sid_locator;
|
||||
struct srv6_locator *tovpn_sid_locator;
|
||||
uint32_t tovpn_sid_transpose_label;
|
||||
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
|
||||
};
|
||||
|
@ -293,9 +314,9 @@ struct graceful_restart_info {
|
|||
/* Best route select */
|
||||
struct event *t_route_select;
|
||||
/* AFI, SAFI enabled */
|
||||
bool af_enabled[AFI_MAX][SAFI_MAX];
|
||||
bool af_enabled;
|
||||
/* Route update completed */
|
||||
bool route_sync[AFI_MAX][SAFI_MAX];
|
||||
bool route_sync;
|
||||
};
|
||||
|
||||
enum global_mode {
|
||||
|
@ -470,9 +491,7 @@ struct bgp {
|
|||
uint32_t restarted_peers;
|
||||
uint32_t implicit_eors;
|
||||
uint32_t explicit_eors;
|
||||
#define BGP_UPDATE_DELAY_DEF 0
|
||||
#define BGP_UPDATE_DELAY_MIN 0
|
||||
#define BGP_UPDATE_DELAY_MAX 3600
|
||||
#define BGP_UPDATE_DELAY_DEFAULT 0
|
||||
|
||||
/* Reference bandwidth for BGP link-bandwidth. Used when
|
||||
* 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_DYNAMIC_CAPABILITY (1ULL << 37)
|
||||
#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.
|
||||
* New peers inherit enabled afi/safis from bgp instance.
|
||||
|
@ -547,6 +569,9 @@ struct bgp {
|
|||
*/
|
||||
enum zebra_gr_mode present_zebra_gr_state;
|
||||
|
||||
/* Is deferred path selection still not complete? */
|
||||
bool gr_route_sync_pending;
|
||||
|
||||
/* BGP Per AF flags */
|
||||
uint16_t af_flags[AFI_MAX][SAFI_MAX];
|
||||
#define BGP_CONFIG_DAMPENING (1 << 0)
|
||||
|
@ -815,11 +840,12 @@ struct bgp {
|
|||
/* BGP VPN SRv6 backend */
|
||||
bool srv6_enabled;
|
||||
char srv6_locator_name[SRV6_LOCNAME_SIZE];
|
||||
struct srv6_locator *srv6_locator;
|
||||
struct list *srv6_locator_chunks;
|
||||
struct list *srv6_functions;
|
||||
uint32_t tovpn_sid_index; /* unset => set to 0 */
|
||||
struct in6_addr *tovpn_sid;
|
||||
struct srv6_locator_chunk *tovpn_sid_locator;
|
||||
struct srv6_locator *tovpn_sid_locator;
|
||||
uint32_t tovpn_sid_transpose_label;
|
||||
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
|
||||
|
||||
|
@ -1226,7 +1252,7 @@ struct peer {
|
|||
struct peer_af *peer_af_array[BGP_AF_MAX];
|
||||
|
||||
/* Peer's remote AS number. */
|
||||
int as_type;
|
||||
enum peer_asn_type as_type;
|
||||
as_t as;
|
||||
/* for vty as format */
|
||||
char *as_pretty;
|
||||
|
@ -1485,6 +1511,7 @@ struct peer {
|
|||
#define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */
|
||||
#define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */
|
||||
#define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39)
|
||||
#define PEER_FLAG_DUAL_AS (1ULL << 40)
|
||||
|
||||
/*
|
||||
*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_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */
|
||||
#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
|
||||
* a new value to the last_reset reason
|
||||
|
@ -1805,16 +1833,13 @@ struct peer {
|
|||
struct stream *last_reset_cause;
|
||||
|
||||
/* 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_OUT (1U << 1) /* neighbor route-map out */
|
||||
#define PEER_RMAP_TYPE_NETWORK (1U << 2) /* network 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_NOSET (1U << 5) /* not allow to set commands */
|
||||
#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 */
|
||||
#define PEER_RMAP_TYPE_AGGREGATE (1U << 5) /* aggregate-address route-map */
|
||||
|
||||
/** Peer overwrite configuration. */
|
||||
struct bfd_session_config {
|
||||
|
@ -2132,6 +2157,7 @@ enum bgp_clear_type {
|
|||
enum bgp_create_error_code {
|
||||
BGP_SUCCESS = 0,
|
||||
BGP_CREATED = 1,
|
||||
BGP_INSTANCE_EXISTS = 2,
|
||||
BGP_ERR_INVALID_VALUE = -1,
|
||||
BGP_ERR_INVALID_FLAG = -2,
|
||||
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 struct peer *peer_create(union sockunion *su, const char *conf_if,
|
||||
struct bgp *bgp, as_t local_as, as_t remote_as,
|
||||
int as_type, struct peer_group *group,
|
||||
bool config_node, const char *as_str);
|
||||
enum peer_asn_type as_type,
|
||||
struct peer_group *group, bool config_node,
|
||||
const char *as_str);
|
||||
extern struct peer *peer_create_accept(struct bgp *);
|
||||
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,
|
||||
|
@ -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_configured(struct bgp *);
|
||||
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,
|
||||
const char *as_str);
|
||||
extern void peer_as_change(struct peer *peer, as_t as,
|
||||
enum peer_asn_type as_type, const char *as_str);
|
||||
extern int peer_remote_as(struct bgp *bgp, union sockunion *su,
|
||||
const char *conf_if, as_t *as, int as_type,
|
||||
const char *as_str);
|
||||
const char *conf_if, as_t *as,
|
||||
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,
|
||||
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 void peer_notify_unconfig(struct peer *peer);
|
||||
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_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_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));
|
||||
}
|
||||
|
||||
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 */
|
||||
extern struct peer *peer_new(struct bgp *bgp);
|
||||
|
||||
extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
|
||||
const char *ip_str, bool use_json);
|
||||
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,
|
||||
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 bgp_session_reset_safe(struct peer *peer, struct listnode **nnode);
|
||||
|
||||
#ifdef _FRR_ATTRIBUTE_PRINTFRR
|
||||
/* clang-format off */
|
||||
#pragma FRR printfrr_ext "%pBP" (struct peer *)
|
||||
/* clang-format on */
|
||||
#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 */
|
||||
|
|
|
@ -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 */
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
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)
|
||||
|
@ -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
|
||||
&& 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 */
|
||||
AFI_IP, SAFI_UNICAST,
|
||||
ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast */
|
||||
NULL,
|
||||
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,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast */
|
||||
NULL, 0); /* tag not used for unicast */
|
||||
/*
|
||||
* yuck!
|
||||
* - 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,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast */
|
||||
NULL, 0); /* 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,
|
||||
NULL, /* RD not used for
|
||||
unicast */
|
||||
NULL, 0, NULL); /* tag not
|
||||
NULL, 0); /* tag not
|
||||
used for
|
||||
unicast */
|
||||
}
|
||||
|
@ -1359,7 +1355,7 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
|
|||
0, /* addpath_id */
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
irfd)) {
|
||||
|
||||
bgp_withdraw(irfd->peer,
|
||||
agg_node_get_prefix(rn),
|
||||
0, /* addpath_id */
|
||||
|
@ -1480,7 +1475,7 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt,
|
|||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for
|
||||
unicast */
|
||||
NULL, 0, NULL); /* tag not
|
||||
NULL, 0); /* tag not
|
||||
used for
|
||||
unicast,
|
||||
EVPN
|
||||
|
@ -1715,8 +1710,7 @@ static void vncExportWithdrawTimer(struct event *t)
|
|||
bgp_withdraw(eti->peer, p, 0, /* addpath_id */
|
||||
family2afi(p->family), SAFI_UNICAST, eti->type,
|
||||
eti->subtype, NULL, /* RD not used for unicast */
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast, EVPN neither */
|
||||
NULL, 0); /* tag not used for unicast, EVPN neither */
|
||||
|
||||
/*
|
||||
* 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,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, 0, NULL); /* tag not used for
|
||||
NULL, 0); /* tag not used for
|
||||
unicast, EVPN
|
||||
neither */
|
||||
}
|
||||
|
|
13
configure.ac
13
configure.ac
|
@ -7,7 +7,7 @@
|
|||
##
|
||||
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/"
|
||||
AC_SUBST([PACKAGE_URL])
|
||||
PACKAGE_FULLNAME="FRRouting"
|
||||
|
@ -847,9 +847,12 @@ AC_ARG_WITH([crypto],
|
|||
AC_ARG_WITH([frr-format],
|
||||
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]))
|
||||
|
||||
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
|
||||
AS_IF([test "$with_crypto" = "openssl"], [
|
||||
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([DP_DPDK], [test "$enable_dp_dpdk" = "yes"])
|
||||
|
||||
|
||||
AM_CONDITIONAL([PYTHON_RUNTIME_DEPENDENCY], [test "$enable_python_runtime" != "no"])
|
||||
|
||||
AC_CONFIG_FILES([Makefile],[
|
||||
test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build"
|
||||
${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}
|
||||
make : ${MAKE-make}
|
||||
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}
|
||||
module directory : ${e_moduledir}
|
||||
script directory : ${e_scriptdir}
|
||||
|
|
|
@ -9,3 +9,4 @@ BGPD
|
|||
|
||||
next-hop-tracking
|
||||
bgp-typecodes
|
||||
bmp
|
||||
|
|
|
@ -18,6 +18,7 @@ import re
|
|||
import pygments
|
||||
from sphinx.highlighting import lexers
|
||||
from sphinx.util import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
|
@ -53,18 +54,26 @@ source_suffix = ".rst"
|
|||
master_doc = "index"
|
||||
|
||||
# General information about the project.
|
||||
project = u"FRR"
|
||||
copyright = u"2017, FRR"
|
||||
author = u"FRR authors"
|
||||
project = "FRR"
|
||||
copyright = "2017, FRR"
|
||||
author = "FRR authors"
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
|
||||
# The short X.Y version.
|
||||
version = u"?.?"
|
||||
version = "?.?"
|
||||
# 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
|
||||
# use when building final documents
|
||||
val = re.compile('^S\["([^"]+)"\]="(.*)"$')
|
||||
val = re.compile(r'^S\["([^"]+)"\]="(.*)"$')
|
||||
try:
|
||||
with open("../../config.status", "r") as cfgstatus:
|
||||
for ln in cfgstatus.readlines():
|
||||
|
@ -287,7 +296,7 @@ latex_elements = {
|
|||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
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
|
||||
|
@ -315,7 +324,7 @@ latex_logo = "../figures/frr-logo-medium.png"
|
|||
|
||||
# One entry per manual page. List of tuples
|
||||
# (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.
|
||||
# man_show_urls = False
|
||||
|
@ -330,7 +339,7 @@ texinfo_documents = [
|
|||
(
|
||||
master_doc,
|
||||
"frr",
|
||||
u"FRR Developer's Manual",
|
||||
"FRR Developer's Manual",
|
||||
author,
|
||||
"FRR",
|
||||
"One line description of project.",
|
||||
|
@ -358,27 +367,29 @@ texinfo_documents = [
|
|||
with open("../extra/frrlexer.py", "rb") as lex:
|
||||
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):
|
||||
from sphinx import addnodes
|
||||
|
||||
m = frrfmt_re.match(text)
|
||||
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)
|
||||
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_name(spec + ' ', spec + ' ')
|
||||
node += addnodes.desc_sig_operator("%", "%")
|
||||
node += addnodes.desc_name(spec + " ", spec + " ")
|
||||
plist = addnodes.desc_parameterlist()
|
||||
for typ in types.split(','):
|
||||
for typ in types.split(","):
|
||||
typ = typ.strip()
|
||||
plist += addnodes.desc_parameter(typ, typ)
|
||||
node += plist
|
||||
return '%' + spec
|
||||
return "%" + spec
|
||||
|
||||
|
||||
# custom extensions here
|
||||
def setup(app):
|
||||
|
|
|
@ -147,7 +147,7 @@ Front-End Interface:
|
|||
- change route_map_init() to route_map_init_new(false) and remove from
|
||||
VTYSH_ROUTE_MAP_CONFIG (leave in VTYSH_ROUTE_MAP_SHOW).
|
||||
- remove vrf_cmd_init(NULL) => remove from VTYSH_INTERFACE_SUBSET
|
||||
...
|
||||
|
||||
|
||||
Back-End Interface:
|
||||
|
||||
|
|
69
doc/developer/ospf-ls-retrans.rst
Normal file
69
doc/developer/ospf-ls-retrans.rst
Normal 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.
|
||||
|
|
@ -8,6 +8,7 @@ OSPFD
|
|||
:maxdepth: 2
|
||||
|
||||
ospf-api
|
||||
ospf-ls-retrans
|
||||
ospf-sr
|
||||
cspf
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@ buster.)
|
|||
+----------------+-------------------+-----------------------------------------+
|
||||
| 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
|
||||
|
||||
|
|
|
@ -67,24 +67,27 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24.
|
|||
|
||||
############### FRRouting (FRR) configure options #################
|
||||
# with-feature options
|
||||
%{!?with_pam: %global with_pam 0 }
|
||||
%{!?with_ospfclient: %global with_ospfclient 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_babeld: %global with_babeld 1 }
|
||||
%{!?with_bfdd: %global with_bfdd 1 }
|
||||
%{!?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_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::
|
||||
|
||||
|
|
|
@ -523,6 +523,7 @@ object which contains methods corresponding to each of the ``zlog`` levels:
|
|||
log.error("error")
|
||||
log.notice("notice")
|
||||
log.debug("debug")
|
||||
log.trace("trace")
|
||||
|
||||
The log messages will show up in the daemon's log output.
|
||||
|
||||
|
|
|
@ -33,10 +33,11 @@ Installing Topotest Requirements
|
|||
net-tools \
|
||||
python3-pip \
|
||||
iputils-ping \
|
||||
iptables \
|
||||
tshark \
|
||||
valgrind
|
||||
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 xmltodict
|
||||
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.
|
||||
|
||||
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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -722,8 +731,8 @@ packages.
|
|||
|
||||
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 will cause *.gnco files to be created during the build. When topotests are
|
||||
run the statistics are generated and stored in *.gcda files. Topotest
|
||||
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
|
||||
infrastructure will gather these files, capture the information into a
|
||||
``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
|
||||
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
|
||||
``/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``
|
||||
|
@ -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
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
|
@ -1292,6 +1341,15 @@ Example:
|
|||
router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
|
||||
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
|
||||
|
||||
|
|
|
@ -6,9 +6,10 @@ Process & Workflow
|
|||
|
||||
.. highlight:: none
|
||||
|
||||
FRR is a large project developed by many different groups. This section
|
||||
documents standards for code style & quality, commit messages, pull requests
|
||||
and best practices that all contributors are asked to follow.
|
||||
FRR is a large project developed by many different groups. This
|
||||
section documents standards for code style & quality, commit messages,
|
||||
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
|
||||
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:
|
||||
|
||||
- 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.
|
||||
|
||||
- ensure the stability of the branch, by using and eventually adapting the
|
||||
|
@ -324,11 +325,17 @@ relevant to your work.
|
|||
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
|
||||
``master``. Please ensure your pull request is based on this branch when you
|
||||
submit it.
|
||||
The base branch for new contributions and non-critical bug fixes
|
||||
should be ``master``. Please ensure your pull request targets this
|
||||
branch when you submit it.
|
||||
|
||||
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
|
||||
|
@ -531,6 +538,42 @@ After Submitting Your Changes
|
|||
community members.
|
||||
- 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
|
||||
==========================================
|
||||
|
||||
|
@ -1306,6 +1349,16 @@ MemorySanitizer
|
|||
|
||||
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.
|
||||
AddressSanitizer and ThreadSanitizer are available in recent versions of 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
|
||||
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
|
||||
This is a GCC plugin provided with FRR that does extended type checks for
|
||||
``%pFX``-style printfrr extensions. To use this plugin,
|
||||
|
|
|
@ -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``
|
||||
|
|
|
@ -91,7 +91,7 @@ replace_vars = {
|
|||
|
||||
# extract version information, installation location, other stuff we need to
|
||||
# use when building final documents
|
||||
val = re.compile('^S\["([^"]+)"\]="(.*)"$')
|
||||
val = re.compile(r'^S\["([^"]+)"\]="(.*)"$')
|
||||
try:
|
||||
with open("../../config.status", "r") as cfgstatus:
|
||||
for ln in cfgstatus.readlines():
|
||||
|
|
|
@ -1,47 +1,8 @@
|
|||
.. _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
|
||||
=========
|
||||
*********
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
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 resources needed by FRR are highly dependent on workload. Routing
|
||||
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.
|
||||
|
||||
|
||||
System Architecture
|
||||
-------------------
|
||||
Architecture
|
||||
============
|
||||
|
||||
.. index::
|
||||
pair: architecture; FRR
|
||||
|
@ -146,9 +104,8 @@ routing stack.
|
|||
|
||||
.. _supported-platforms:
|
||||
|
||||
Supported Platforms
|
||||
-------------------
|
||||
|
||||
Platform Support
|
||||
================
|
||||
|
||||
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
|
||||
|
@ -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.`
|
||||
- :rfc:`5668`
|
||||
: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`
|
||||
:t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan. June 2011.`
|
||||
- :rfc:`6472`
|
23
doc/user/basics.rst
Normal file
23
doc/user/basics.rst
Normal file
|
@ -0,0 +1,23 @@
|
|||
.. _basics:
|
||||
|
||||
######
|
||||
Basics
|
||||
######
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
basic
|
||||
extlog
|
||||
vtysh
|
||||
grpc
|
||||
filter
|
||||
routemap
|
||||
affinitymap
|
||||
ipv6
|
||||
kernel
|
||||
snmp
|
||||
scripting
|
||||
nexthop_groups
|
||||
|
||||
|
|
@ -1,12 +1,19 @@
|
|||
.. _bfd:
|
||||
|
||||
**********************************
|
||||
Bidirectional Forwarding Detection
|
||||
**********************************
|
||||
***
|
||||
BFD
|
||||
***
|
||||
|
||||
:abbr:`BFD (Bidirectional Forwarding Detection)` stands for
|
||||
Bidirectional Forwarding Detection and it is described and extended by
|
||||
the following RFCs:
|
||||
:abbr:`BFD (Bidirectional Forwarding Detection)` is:
|
||||
|
||||
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:`5881`
|
||||
|
@ -38,19 +45,6 @@ may also be specified (:ref:`common-invocation-options`).
|
|||
|
||||
.. 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>]
|
||||
|
||||
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
|
||||
|
||||
(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
|
||||
connections). To connect to a data plane server append the letter 'c' to
|
||||
|
|
|
@ -83,7 +83,7 @@ be specified (:ref:`common-invocation-options`).
|
|||
be done to see if this is helping or not at the scale you are running
|
||||
at.
|
||||
|
||||
.. option:: --v6-with-v4-nexthops
|
||||
.. option:: -x, --v6-with-v4-nexthops
|
||||
|
||||
Allow BGP to peer in the V6 afi, when the interface only has v4 addresses.
|
||||
This allows bgp to install the v6 routes with a v6 nexthop that has the
|
||||
|
@ -92,6 +92,12 @@ be specified (:ref:`common-invocation-options`).
|
|||
the operator has turned off communication to zebra and is running bgpd
|
||||
as a complete standalone process.
|
||||
|
||||
.. option:: -K, --graceful_restart
|
||||
|
||||
Bgpd will use this option to denote either a planned FRR graceful
|
||||
restart or a bgpd-only graceful restart, and this will drive the BGP
|
||||
GR restarting router procedures.
|
||||
|
||||
LABEL MANAGER
|
||||
-------------
|
||||
|
||||
|
@ -154,16 +160,16 @@ bottom until one of the factors can be used.
|
|||
|
||||
Prefer higher local preference routes to lower.
|
||||
|
||||
3. **Local route check**
|
||||
|
||||
Prefer local routes (statics, aggregates, redistributed) to received routes.
|
||||
|
||||
If ``bgp bestpath aigp`` is enabled, and both paths that are compared have
|
||||
AIGP attribute, BGP uses AIGP tie-breaking unless both of the paths have the
|
||||
AIGP metric attribute. This means that the AIGP attribute is not evaluated
|
||||
during the best path selection process between two paths when one path does
|
||||
not have the AIGP attribute.
|
||||
|
||||
3. **Local route check**
|
||||
|
||||
Prefer local routes (statics, aggregates, redistributed) to received routes.
|
||||
|
||||
4. **AS path length check**
|
||||
|
||||
Prefer shortest hop-count AS_PATHs.
|
||||
|
@ -1080,6 +1086,52 @@ Default global mode is helper and default peer per mode is inherit from global.
|
|||
If per peer mode is configured, the GR mode of this particular peer will
|
||||
override the global mode.
|
||||
|
||||
.. _bgp-GR-config-mode-cmd:
|
||||
|
||||
BGP GR Config Mode Commands
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. clicmd:: bgp graceful-restart
|
||||
|
||||
This command will enable BGP graceful restart functionality for all BGP instances.
|
||||
|
||||
.. clicmd:: bgp graceful-restart-disable
|
||||
|
||||
This command will disable both the functionality graceful restart and helper
|
||||
mode for all BGP instances
|
||||
|
||||
.. clicmd:: bgp graceful-restart select-defer-time (0-3600)
|
||||
|
||||
This is command, will set deferral time to value specified.
|
||||
|
||||
.. clicmd:: bgp graceful-restart rib-stale-time (1-3600)
|
||||
|
||||
This is command, will set the time for which stale routes are kept in RIB.
|
||||
|
||||
.. clicmd:: bgp graceful-restart restart-time (0-4095)
|
||||
|
||||
Set the time to wait to delete stale routes before a BGP open message
|
||||
is received.
|
||||
|
||||
Using with Long-lived Graceful Restart capability, this is recommended
|
||||
setting this timer to 0 and control stale routes with
|
||||
``bgp long-lived-graceful-restart stale-time``.
|
||||
|
||||
Default value is 120.
|
||||
|
||||
.. clicmd:: bgp graceful-restart stalepath-time (1-4095)
|
||||
|
||||
This is command, will set the max time (in seconds) to hold onto
|
||||
restarting peer's stale paths.
|
||||
|
||||
It also controls Enhanced Route-Refresh timer.
|
||||
|
||||
If this command is configured and the router does not receive a Route-Refresh EoRR
|
||||
message, the router removes the stale routes from the BGP table after the timer
|
||||
expires. The stale path timer is started when the router receives a Route-Refresh
|
||||
BoRR message
|
||||
|
||||
|
||||
.. _bgp-GR-global-mode-cmd:
|
||||
|
||||
BGP GR Global Mode Commands
|
||||
|
@ -1230,6 +1282,13 @@ IPv6 Support
|
|||
address family is enabled by default for all new neighbors.
|
||||
|
||||
|
||||
.. clicmd:: bgp ipv6-auto-ra
|
||||
|
||||
By default, bgpd can ask Zebra to enable sending IPv6 router advertisement
|
||||
messages on interfaces. For example, this happens for unnumbered peers
|
||||
support or when extended-nexthop capability is used. The ``no`` form of this
|
||||
command disables such behaviour.
|
||||
|
||||
.. _bgp-route-aggregation:
|
||||
|
||||
Route Aggregation
|
||||
|
@ -1509,6 +1568,10 @@ Defining Peers
|
|||
peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN`
|
||||
command the connection will be denied.
|
||||
|
||||
.. clicmd:: neighbor PEER remote-as auto
|
||||
|
||||
The neighbor's ASN is detected automatically from the OPEN message.
|
||||
|
||||
.. clicmd:: neighbor PEER oad
|
||||
|
||||
Mark a peer belonging to the One Administrative Domain.
|
||||
|
@ -1647,7 +1710,7 @@ Configuring Peers
|
|||
IPv4 session addresses, see the ``neighbor PEER update-source`` command
|
||||
below.
|
||||
|
||||
.. clicmd:: neighbor PEER interface remote-as <internal|external|ASN>
|
||||
.. clicmd:: neighbor PEER interface remote-as <internal|external|auto|ASN>
|
||||
|
||||
Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The
|
||||
session will be established via IPv6 link locals. Use ``internal`` for iBGP
|
||||
|
@ -1762,7 +1825,7 @@ Configuring Peers
|
|||
Since sent prefix count is managed by update-groups, this option
|
||||
creates a separate update-group for outgoing updates.
|
||||
|
||||
.. clicmd:: neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
|
||||
.. clicmd:: neighbor PEER local-as AS-NUMBER [no-prepend [replace-as [dual-as]]]
|
||||
|
||||
Specify an alternate AS for this BGP process when interacting with the
|
||||
specified peer. With no modifiers, the specified local-as is prepended to
|
||||
|
@ -1778,6 +1841,10 @@ Configuring Peers
|
|||
|
||||
Note that replace-as can only be specified if no-prepend is.
|
||||
|
||||
The ``dual-as`` keyword is used to configure the neighbor to establish a peering
|
||||
session using the real autonomous-system number (``router bgp ASN``) or by using
|
||||
the autonomous system number configured with the ``local-as``.
|
||||
|
||||
This command is only allowed for eBGP peers.
|
||||
|
||||
.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> as-override
|
||||
|
@ -1916,12 +1983,14 @@ Configuring Peers
|
|||
and will not be displayed as part of a `show run`. The no form
|
||||
of the command turns off this ability.
|
||||
|
||||
.. clicmd:: bgp default-originate timer (0-3600)
|
||||
.. clicmd:: bgp default-originate timer (0-65535)
|
||||
|
||||
Set the period to rerun the default-originate route-map scanner process. The
|
||||
default is 5 seconds. With a full routing table, it might be useful to increase
|
||||
this setting to avoid scanning the whole BGP table aggressively.
|
||||
|
||||
Setting to 0 turns off the scanning at all.
|
||||
|
||||
.. clicmd:: bgp default ipv4-unicast
|
||||
|
||||
This command allows the user to specify that the IPv4 Unicast address
|
||||
|
@ -2135,8 +2204,7 @@ and will share updates.
|
|||
.. clicmd:: neighbor PEER solo
|
||||
|
||||
This command is used to indicate that routes advertised by the peer
|
||||
should not be reflected back to the peer. This command only is only
|
||||
meaningful when there is a single peer defined in the peer-group.
|
||||
should not be reflected back to the peer.
|
||||
|
||||
.. clicmd:: show [ip] bgp peer-group [json]
|
||||
|
||||
|
@ -2426,7 +2494,7 @@ is 4 octet long. The following format is used to define the community value.
|
|||
``blackhole``
|
||||
``blackhole`` represents well-known communities value ``BLACKHOLE``
|
||||
``0xFFFF029A`` ``65535:666``. :rfc:`7999` documents sending prefixes to
|
||||
EBGP peers and upstream for the purpose of blackholing traffic.
|
||||
peers and upstream for the purpose of blackholing traffic.
|
||||
Prefixes tagged with the this community should normally not be
|
||||
re-advertised from neighbors of the originating network. Upon receiving
|
||||
``BLACKHOLE`` community from a BGP speaker, ``NO_ADVERTISE`` community
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue