summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--bfdd/bfdd_cli.c41
-rw-r--r--bgpd/bgp_attr.c10
-rw-r--r--bgpd/bgp_attr.h12
-rw-r--r--bgpd/bgp_bmp.c8
-rw-r--r--bgpd/bgp_clist.c2
-rw-r--r--bgpd/bgp_clist.h4
-rw-r--r--bgpd/bgp_evpn_vty.c4
-rw-r--r--bgpd/bgp_fsm.c32
-rw-r--r--bgpd/bgp_main.c32
-rw-r--r--bgpd/bgp_mplsvpn.c38
-rw-r--r--bgpd/bgp_network.c4
-rw-r--r--bgpd/bgp_nht.c15
-rw-r--r--bgpd/bgp_route.c124
-rw-r--r--bgpd/bgp_routemap.c100
-rw-r--r--bgpd/bgp_snmp_bgp4v2.c4
-rw-r--r--bgpd/bgp_vty.c39
-rw-r--r--bgpd/bgp_zebra.c10
-rw-r--r--bgpd/bgpd.c9
-rw-r--r--bgpd/bgpd.h3
-rw-r--r--configure.ac2
-rw-r--r--debian/changelog6
-rw-r--r--doc/user/bgp.rst17
-rw-r--r--doc/user/ipv6.rst3
-rw-r--r--doc/user/routemap.rst2
-rw-r--r--lib/frrscript.c10
-rw-r--r--lib/frrscript.h2
-rw-r--r--lib/plist.c4
-rw-r--r--lib/routemap_cli.c73
-rw-r--r--lib/srv6.h4
-rw-r--r--pimd/pim_nht.c28
-rw-r--r--pimd/pimd.c2
-rw-r--r--redhat/frr.spec.in57
-rw-r--r--tests/topotests/bgp_aigp/r1/ospfd.conf2
-rw-r--r--tests/topotests/bgp_aigp/r2/bgpd.conf2
-rw-r--r--tests/topotests/bgp_aigp/r2/ospfd.conf2
-rw-r--r--tests/topotests/bgp_aigp/r3/bgpd.conf2
-rw-r--r--tests/topotests/bgp_aigp/r3/ospfd.conf2
-rw-r--r--tests/topotests/bgp_aigp/r4/bgpd.conf23
-rw-r--r--tests/topotests/bgp_aigp/r4/ospfd.conf2
-rw-r--r--tests/topotests/bgp_aigp/r5/bgpd.conf16
-rw-r--r--tests/topotests/bgp_aigp/r5/ospfd.conf2
-rw-r--r--tests/topotests/bgp_aigp/r6/bgpd.conf8
-rw-r--r--tests/topotests/bgp_aigp/r6/ospfd.conf2
-rw-r--r--tests/topotests/bgp_aigp/r6/zebra.conf1
-rw-r--r--tests/topotests/bgp_aigp/test_bgp_aigp.py95
-rw-r--r--vrrpd/vrrp_packet.c2
-rw-r--r--zebra/dplane_fpm_nl.c2
-rw-r--r--zebra/main.c5
-rw-r--r--zebra/zebra_rnh.c3
-rw-r--r--zebra/zebra_snmp.c30
-rw-r--r--zebra/zebra_vty.c4
-rw-r--r--zebra/zserv.c32
-rw-r--r--zebra/zserv.h15
54 files changed, 644 insertions, 311 deletions
diff --git a/.clang-format b/.clang-format
index 3971384a36..160617804b 100644
--- a/.clang-format
+++ b/.clang-format
@@ -54,7 +54,7 @@ BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
-ColumnLimit: 80
+ColumnLimit: 100
# Linux: CommentPragmas: '^ IWYU pragma:'
CommentPragmas: '\$(FRR|clippy)'
CompactNamespaces: false
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index 44439c6756..514ab10cbe 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -356,14 +356,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 +380,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 +389,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 +438,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 +452,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 +476,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 +491,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"
@@ -504,9 +509,9 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "0");
else
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);
}
@@ -576,12 +581,14 @@ ALIAS_YANG(bfd_peer_mult, bfd_profile_mult_cmd,
"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")
@@ -618,14 +625,16 @@ ALIAS_YANG(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd,
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"
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index a835a6df90..bb56ac8be1 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -479,16 +479,6 @@ 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)
{
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index d30155e6db..0282818931 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -592,9 +592,17 @@ 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;
+ 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 (aigp)
- SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP));
+ if (bpi->nexthop)
+ return aigp + bpi->nexthop->metric;
+ else
+ return aigp;
}
static inline struct cluster_list *bgp_attr_get_cluster(const struct attr *attr)
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 7270802915..4e18b21d72 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -2143,8 +2143,11 @@ DEFPY(bmp_connect,
}
ba = bmp_active_get(bt, hostname, port);
- if (srcif)
+ if (srcif) {
+ if (ba->ifsrc)
+ XFREE(MTYPE_TMP, ba->ifsrc);
ba->ifsrc = XSTRDUP(MTYPE_TMP, srcif);
+ }
if (min_retry_str)
ba->minretry = min_retry;
if (max_retry_str)
@@ -2509,8 +2512,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",
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index e522307134..634775cfd3 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -181,7 +181,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. */
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
index a435b92ce1..f0ca90bdef 100644
--- a/bgpd/bgp_clist.h
+++ b/bgpd/bgp_clist.h
@@ -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
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index eb9f34ef02..c553d2e32e 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -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",
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 4f519dc197..33e5c3a743 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -685,6 +685,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,8 +700,6 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
pi->attr = bgp_attr_intern(&attr);
bgp_recalculate_afi_safi_bestpaths(
peer->bgp, afi, safi);
-
- break;
}
}
} else {
@@ -713,6 +716,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,8 +731,6 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
pi->attr = bgp_attr_intern(&attr);
bgp_recalculate_afi_safi_bestpaths(peer->bgp,
afi, safi);
-
- break;
}
}
}
@@ -1794,6 +1800,22 @@ bgp_connect_fail(struct peer_connection *connection)
return bgp_stop(connection);
}
+/* after connect is called(), getpeername is able to return
+ * port and address on non established streams
+ */
+static void bgp_connect_in_progress_update_connection(struct peer *peer)
+{
+ bgp_getsockname(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);
+ else if (sockunion_family(peer->su_remote) == AF_INET6)
+ peer->su_remote->sin6.sin6_port = htons(peer->port);
+ }
+}
+
/* This function is the first starting point of all BGP connection. It
* try to connect to remote peer with non-blocking IO.
*/
@@ -1890,6 +1912,8 @@ static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection)
__func__, peer->connection->fd);
return BGP_FSM_FAILURE;
}
+ bgp_connect_in_progress_update_connection(peer);
+
/*
* - when the socket becomes ready, poll() will signify POLLOUT
* - if it fails to connect, poll() will signify POLLHUP
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 11917c6c4a..785a56736d 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -56,18 +56,16 @@
#endif
/* bgpd options, we use GNU getopt library. */
-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' },
- { "ecmp", required_argument, NULL, 'e' },
- { "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 }
-};
+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' },
+ { "ecmp", required_argument, NULL, 'e' },
+ { "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, 'x' },
+ { 0 } };
/* signal definitions */
void sighup(void);
@@ -385,11 +383,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"
@@ -398,7 +397,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) {
@@ -460,8 +459,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);
@@ -473,6 +472,7 @@ int main(int argc, char **argv)
/* BGP master init. */
bgp_master_init(frr_init(), buffer_size, addresses);
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)
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 1fe5ef2a1d..2b42becb95 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -381,6 +381,12 @@ 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 +438,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 +482,7 @@ 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 seg6local_context seg6localctx = {};
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
@@ -482,9 +495,16 @@ 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);
- zclient_send_localsid(zclient,
- bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent,
- bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL);
+ 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, &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;
@@ -497,6 +517,7 @@ 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 seg6local_context seg6localctx = {};
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
@@ -510,9 +531,14 @@ 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);
- zclient_send_localsid(zclient, bgp->tovpn_zebra_vrf_sid_last_sent,
- bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
- NULL);
+ 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, &seg6localctx);
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
bgp->tovpn_zebra_vrf_sid_last_sent = NULL;
}
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index b874e7211f..f08881512a 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -876,11 +876,7 @@ int bgp_getsockname(struct peer *peer)
}
peer->su_local = sockunion_getsockname(peer->connection->fd);
- if (!peer->su_local)
- return -1;
peer->su_remote = sockunion_getpeername(peer->connection->fd);
- if (!peer->su_remote)
- return -1;
if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote,
&peer->nexthop, peer)) {
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index b0157e8fea..30cf02e099 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -635,11 +635,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,
@@ -1494,6 +1495,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);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index a60ba6a3e2..b6cc5ba4b1 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -953,12 +953,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;
@@ -983,34 +1008,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.
*/
@@ -3992,7 +3989,7 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
uint8_t type, uint8_t stype, struct attr *attr,
struct bgp_dest *dest)
{
- bool ret = false;
+ bool nh_invalid = false;
bool is_bgp_static_route =
(type == ZEBRA_ROUTE_BGP && stype == BGP_ROUTE_STATIC) ? true
: false;
@@ -4014,13 +4011,15 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
(safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != SAFI_EVPN))
return false;
- /* If NEXT_HOP is present, validate it. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
- if (attr->nexthop.s_addr == INADDR_ANY ||
- !ipv4_unicast_valid(&attr->nexthop) ||
- bgp_nexthop_self(bgp, afi, type, stype, attr, dest))
- return true;
- }
+ /* If NEXT_HOP is present, validate it:
+ * The route can have both nexthop + mp_nexthop encoded as multiple NLRIs,
+ * and we MUST check if at least one of them is valid.
+ * E.g.: IPv6 prefix can be with nexthop: 0.0.0.0, and mp_nexthop: fc00::1.
+ */
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)))
+ nh_invalid = (attr->nexthop.s_addr == INADDR_ANY ||
+ !ipv4_unicast_valid(&attr->nexthop) ||
+ bgp_nexthop_self(bgp, afi, type, stype, attr, dest));
/* If MP_NEXTHOP is present, validate it. */
/* Note: For IPv6 nexthops, we only validate the global (1st) nexthop;
@@ -4035,39 +4034,31 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
switch (attr->mp_nexthop_len) {
case BGP_ATTR_NHLEN_IPV4:
case BGP_ATTR_NHLEN_VPNV4:
- ret = (attr->mp_nexthop_global_in.s_addr ==
- INADDR_ANY ||
- !ipv4_unicast_valid(
- &attr->mp_nexthop_global_in) ||
- bgp_nexthop_self(bgp, afi, type, stype, attr,
- dest));
+ nh_invalid = (attr->mp_nexthop_global_in.s_addr == INADDR_ANY ||
+ !ipv4_unicast_valid(&attr->mp_nexthop_global_in) ||
+ bgp_nexthop_self(bgp, afi, type, stype, attr, dest));
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL:
case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
- ret = (IN6_IS_ADDR_UNSPECIFIED(
- &attr->mp_nexthop_global)
- || IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global)
- || IN6_IS_ADDR_MULTICAST(
- &attr->mp_nexthop_global)
- || bgp_nexthop_self(bgp, afi, type, stype, attr,
- dest));
+ nh_invalid = (IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global) ||
+ IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) ||
+ IN6_IS_ADDR_MULTICAST(&attr->mp_nexthop_global) ||
+ bgp_nexthop_self(bgp, afi, type, stype, attr, dest));
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- ret = (IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global)
- || IN6_IS_ADDR_MULTICAST(
- &attr->mp_nexthop_global)
- || bgp_nexthop_self(bgp, afi, type, stype, attr,
- dest));
+ nh_invalid = (IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) ||
+ IN6_IS_ADDR_MULTICAST(&attr->mp_nexthop_global) ||
+ bgp_nexthop_self(bgp, afi, type, stype, attr, dest));
break;
default:
- ret = true;
+ nh_invalid = true;
break;
}
}
- return ret;
+ return nh_invalid;
}
static void bgp_attr_add_no_export_community(struct attr *attr)
@@ -5859,7 +5850,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 {
@@ -5888,7 +5878,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;
}
}
}
@@ -6334,9 +6323,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);
@@ -8591,9 +8577,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);
@@ -8603,16 +8586,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);
@@ -11800,7 +11782,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) {
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 556f820db0..fe94b961a3 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -3452,19 +3452,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;
}
@@ -7126,7 +7122,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"
@@ -7146,7 +7142,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"
@@ -7218,43 +7214,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",
@@ -7312,45 +7271,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",
@@ -8023,12 +7943,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);
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c
index bfad01f66e..8862838e02 100644
--- a/bgpd/bgp_snmp_bgp4v2.c
+++ b/bgpd/bgp_snmp_bgp4v2.c
@@ -887,7 +887,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:
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 31d1704113..12135457c0 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -4819,6 +4819,27 @@ DEFUN(no_bgp_fast_convergence, no_bgp_fast_convergence_cmd,
return CMD_SUCCESS;
}
+DEFPY (bgp_ipv6_auto_ra,
+ bgp_ipv6_auto_ra_cmd,
+ "[no] bgp ipv6-auto-ra",
+ NO_STR
+ BGP_STR
+ "Allow enabling IPv6 ND RA sending\n")
+{
+ if (vty->node == CONFIG_NODE) {
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ COND_FLAG(bm->flags, BM_FLAG_IPV6_NO_AUTO_RA, no);
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ COND_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA, no);
+ } else {
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ COND_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA, no);
+ }
+ return CMD_SUCCESS;
+}
+
static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
int v6only,
const char *peer_group_name,
@@ -5021,7 +5042,7 @@ DEFUN (neighbor_peer_group,
DEFUN (no_neighbor,
no_neighbor_cmd,
- "no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <(1-4294967295)|internal|external>]>",
+ "no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <ASNUM|internal|external>]>",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
@@ -5088,7 +5109,7 @@ DEFUN (no_neighbor,
DEFUN (no_neighbor_interface_config,
no_neighbor_interface_config_cmd,
- "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external>]",
+ "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <ASNUM|internal|external>]",
NO_STR
NEIGHBOR_STR
"Interface name\n"
@@ -18461,6 +18482,9 @@ int bgp_config_write(struct vty *vty)
if (bm->tcp_dscp != IPTOS_PREC_INTERNETCONTROL)
vty_out(vty, "bgp session-dscp %u\n", bm->tcp_dscp >> 2);
+ if (CHECK_FLAG(bm->flags, BM_FLAG_IPV6_NO_AUTO_RA))
+ vty_out(vty, "no bgp ipv6-auto-ra\n");
+
/* BGP InQ limit */
if (bm->inq_limit != BM_DEFAULT_Q_LIMIT)
vty_out(vty, "bgp input-queue-limit %u\n", bm->inq_limit);
@@ -18843,6 +18867,11 @@ int bgp_config_write(struct vty *vty)
if (CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN))
vty_out(vty, " bgp shutdown\n");
+ /* Automatic RA enabling by BGP */
+ if (!CHECK_FLAG(bm->flags, BM_FLAG_IPV6_NO_AUTO_RA))
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA))
+ vty_out(vty, " no bgp ipv6-auto-ra\n");
+
if (bgp->allow_martian)
vty_out(vty, " bgp allow-martian-nexthop\n");
@@ -19383,6 +19412,12 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_fast_convergence_cmd);
install_element(BGP_NODE, &no_bgp_fast_convergence_cmd);
+ /* global bgp ipv6-auto-ra command */
+ install_element(CONFIG_NODE, &bgp_ipv6_auto_ra_cmd);
+
+ /* bgp ipv6-auto-ra command */
+ install_element(BGP_NODE, &bgp_ipv6_auto_ra_cmd);
+
/* global bgp update-delay command */
install_element(CONFIG_NODE, &bgp_global_update_delay_cmd);
install_element(CONFIG_NODE, &no_bgp_global_update_delay_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index bc51d14b39..bcec12051e 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1179,9 +1179,10 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
ifindex =
pi->peer->nexthop.ifp->ifindex;
if (!ifindex) {
- if (pi->peer->conf_if)
- ifindex = pi->peer->ifp->ifindex;
- else if (pi->peer->ifname)
+ if (pi->peer->conf_if) {
+ if (pi->peer->ifp)
+ ifindex = pi->peer->ifp->ifindex;
+ } else if (pi->peer->ifname)
ifindex = ifname2ifindex(
pi->peer->ifname,
pi->peer->bgp->vrf_id);
@@ -2146,6 +2147,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;
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 492092bac4..4de5964c39 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1394,6 +1394,9 @@ int bgp_global_gr_init(struct bgp *bgp)
bgp->global_gr_present_state = GLOBAL_HELPER;
bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE;
+ if (CHECK_FLAG(bm->flags, BM_FLAG_IPV6_NO_AUTO_RA))
+ SET_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA);
+
return BGP_GR_SUCCESS;
}
@@ -8610,6 +8613,12 @@ static ssize_t printfrr_bp(struct fbuf *buf, struct printfrr_eargs *ea,
if (!peer)
return bputs(buf, "(null)");
+ if (!peer->host) {
+ if (peer->conf_if)
+ return bprintfrr(buf, "%s", peer->conf_if);
+ return bprintfrr(buf, "%pSU", &peer->connection->su);
+ }
+
return bprintfrr(buf, "%s(%s)", peer->host,
peer->hostname ? peer->hostname : "Unknown");
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index dda108bcf6..b139b2c1b4 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -155,6 +155,7 @@ 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_IPV6_NO_AUTO_RA (1 << 8)
bool terminating; /* global flag that sigint terminate seen */
@@ -514,6 +515,8 @@ struct bgp {
/* For BGP-LU, force IPv6 local prefixes to use ipv6-explicit-null label */
#define BGP_FLAG_LU_IPV6_EXPLICIT_NULL (1ULL << 34)
#define BGP_FLAG_SOFT_VERSION_CAPABILITY (1ULL << 35)
+/* 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.
diff --git a/configure.ac b/configure.ac
index 3e2aa02983..c52a19aa5b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@
##
AC_PREREQ([2.69])
-AC_INIT([frr], [9.1.2], [https://github.com/frrouting/frr/issues])
+AC_INIT([frr], [9.1.3], [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/"
AC_SUBST([PACKAGE_URL])
PACKAGE_FULLNAME="FRRouting"
diff --git a/debian/changelog b/debian/changelog
index 7441ee8a3c..dd89268de2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+frr (9.1.3-0) unstable; urgency=medium
+
+ * New upstream release FRR 9.1.3
+
+ -- Donatas Abraitis <donatas@opensourcerouting.org> Mon, 23 Dec 2024 22:35:00 +0300
+
frr (9.1.2-0) unstable; urgency=medium
* New upstream release FRR 9.1.2
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 03b150659d..e7dad99a85 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -86,7 +86,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
@@ -157,16 +157,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.
@@ -1186,6 +1186,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
diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst
index 4f01061e7b..18aae00bdb 100644
--- a/doc/user/ipv6.rst
+++ b/doc/user/ipv6.rst
@@ -25,7 +25,8 @@ Router Advertisement
.. clicmd:: ipv6 nd suppress-ra
Don't send router advertisement messages. The ``no`` form of this command
- enables sending RA messages.
+ enables sending RA messages. Note that while being suppressed, RA messages
+ might still be enabled by other daemons, such as bgpd or vrrpd.
.. clicmd:: ipv6 nd prefix ipv6prefix [valid-lifetime] [preferred-lifetime] [off-link] [no-autoconfig] [router-address]
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index 3d43e74744..fd87f29d46 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -318,7 +318,7 @@ Route Map Set Command
Set the maximum meric for the route.
-.. clicmd:: set aigp-metric <igp-metric|(1-4294967295)>
+.. clicmd:: set aigp-metric <igp-metric|(0-4294967295)>
Set the BGP attribute AIGP to a specific value. If ``igp-metric`` is specified,
then the value is taken from the IGP protocol, otherwise an arbitrary value.
diff --git a/lib/frrscript.c b/lib/frrscript.c
index 50410fb58b..ec2f47899a 100644
--- a/lib/frrscript.c
+++ b/lib/frrscript.c
@@ -25,6 +25,16 @@ DEFINE_MTYPE_STATIC(LIB, SCRIPT, "Scripting");
struct frrscript_names_head frrscript_names_hash;
+void frrscript_names_config_write(struct vty *vty)
+{
+ struct frrscript_names_entry *lua_script_entry;
+
+ frr_each (frrscript_names, &frrscript_names_hash, lua_script_entry)
+ if (lua_script_entry->script_name[0] != '\0')
+ vty_out(vty, "zebra on-rib-process script %s\n",
+ lua_script_entry->script_name);
+}
+
/*
* Wrapper for frrscript_names_add
* Use this to register hook calls when a daemon starts up
diff --git a/lib/frrscript.h b/lib/frrscript.h
index df49b5718c..ddc1fecc86 100644
--- a/lib/frrscript.h
+++ b/lib/frrscript.h
@@ -44,6 +44,8 @@ struct frrscript_names_entry {
extern struct frrscript_names_head frrscript_names_hash;
+extern void frrscript_names_config_write(struct vty *vty);
+
int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1,
const struct frrscript_names_entry *snhe2);
uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe);
diff --git a/lib/plist.c b/lib/plist.c
index 2f5827cf43..5f52e27d18 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -1140,8 +1140,10 @@ static int vty_show_prefix_list_prefix(struct vty *vty, afi_t afi,
match = 0;
if (type == normal_display || type == first_match_display)
- if (prefix_same(&p, &pentry->prefix))
+ if (prefix_list_entry_match(pentry, &p, false)) {
+ pentry->hitcnt++;
match = 1;
+ }
if (type == longer_display) {
if ((p.family == pentry->prefix.family)
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 20a157e955..9ea27787f5 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -417,6 +417,74 @@ DEFPY_YANG(
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_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_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
"match ipv6 next-hop type <blackhole>$type",
@@ -1644,6 +1712,11 @@ void route_map_cli_init(void)
install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
+ install_element(RMAP_NODE, &match_ipv6_next_hop_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_prefix_list_cmd);
+
install_element(RMAP_NODE, &match_metric_cmd);
install_element(RMAP_NODE, &no_match_metric_cmd);
diff --git a/lib/srv6.h b/lib/srv6.h
index 433c5c14fd..b5ae3890aa 100644
--- a/lib/srv6.h
+++ b/lib/srv6.h
@@ -104,6 +104,10 @@ struct seg6local_context {
struct in6_addr nh6;
uint32_t table;
struct seg6local_flavors_info flv;
+ uint8_t block_len;
+ uint8_t node_len;
+ uint8_t function_len;
+ uint8_t argument_len;
};
struct srv6_locator {
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 4e8e5f0df7..76027af56d 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -313,7 +313,19 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
if (!nbr)
continue;
- return znh->ifindex == src_ifp->ifindex;
+ /* Are we on the correct interface? */
+ if (znh->ifindex == src_ifp->ifindex) {
+ /* Do we have the correct NH ? */
+ if (!pim_addr_cmp(znh->nexthop_addr, src_ip))
+ return true;
+ /*
+ * check If the packet came from the neighbor,
+ * and the dst is a secondary address on the connected interface
+ */
+ return (!pim_addr_cmp(nbr->source_addr, src_ip) &&
+ pim_if_connected_to_source(ifp, znh->nexthop_addr));
+ }
+ return false;
}
return false;
}
@@ -380,7 +392,19 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
if (!nbr)
continue;
- return nh->ifindex == src_ifp->ifindex;
+ /* Are we on the correct interface? */
+ if (nh->ifindex == src_ifp->ifindex) {
+ /* Do we have the correct NH ? */
+ if (!pim_addr_cmp(nhaddr, src_ip))
+ return true;
+ /*
+ * check If the packet came from the neighbor,
+ * and the dst is a secondary address on the connected interface
+ */
+ return (!pim_addr_cmp(nbr->source_addr, src_ip) &&
+ pim_if_connected_to_source(ifp, nhaddr));
+ }
+ return false;
}
return false;
}
diff --git a/pimd/pimd.c b/pimd/pimd.c
index db61974800..1a9ef0ce41 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -17,6 +17,7 @@
#include "vrf.h"
#include "lib_errors.h"
#include "bfd.h"
+#include "filter.h"
#include "pimd.h"
#if PIM_IPV == 4
@@ -143,6 +144,7 @@ void pim_terminate(void)
prefix_list_add_hook(NULL);
prefix_list_delete_hook(NULL);
prefix_list_reset();
+ access_list_reset();
pim_vxlan_terminate();
pim_vrf_terminate();
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 46ec467d35..d434085ad8 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -799,7 +799,62 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
%changelog
-* Wed Sep 11 2024 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+* Mon Dec 23 2024 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+
+* Mon Dec 23 2024 Donatas Abraitis <donatas@opensourcerouting.org> - 9.1.3
+- bfdd
+- Add no variants to interval configurations
+- bgpd
+- Actually make ` --v6-with-v4-nexthops` it work
+- Add `bgp ipv6-auto-ra` command
+- Allow value 0 in aigp-metric setting
+- Clear all paths including addpath once GR expires
+- Compare aigp after local route check in bgp_path_info_cmp()
+- EVPN fix per rd specific type-2 json output
+- Fix addressing information of non established outgoing sessions
+- Fix bgp core with a possible Intf delete
+- Fix blank line in running-config with bmp listener cmd
+- Fix crash when polling bgp4v2PathAttrTable
+- Fix display of local label in show bgp
+- Fix for match source-protocol in route-map for redistribute cmd
+- Fix memory leak when creating BMP connection with a source interface
+- Fix printfrr_bp for non initialized peers
+- Fix route selection with AIGP
+- Fix several issues in sourcing AIGP attribute
+- Fix unconfigure asdot neighbor
+- Include structure when installing End.DT4/6 SID
+- Include structure when installing End.DT46 SID
+- Include structure when removing End.DT4/6 SID
+- Include structure when removing End.DT46 SID
+- Move some non BGP-specific route-map functions to lib
+- Remove useless control checks about TCP connection
+- Set LLGR stale routes for all the paths including addpath
+- Treat numbered community-list only if it's in a range 1-500
+- Validate both nexthop information (NEXTHOP and NLRI)
+- isisd
+- Fix rcap tlv double-free crash
+- lib
+- Include SID structure in seg6local nexthop
+- Take ge/le into consideration when checking the prefix with the prefix-list
+- Keep `zebra on-rib-process script` in frr.conf
+- nhrpd
+- Fixes duplicate auth extension
+- ospfd
+- Fix missing '[no]ip ospf graceful-restart hello-delay <N>' commands
+- pimd
+- Allow resolving bsr via directly connected secondary address
+- Fix access-list memory leak in pimd
+- vrrpd
+- Iterate over all ancillary messages
+- zebra
+- Add missing new line for help string
+- Add missing proto translations
+- Correctly report metrics
+- Fix crash during reconnect
+- Fix snmp walk of zebra rib
+- Let's use memset instead of walking bytes and setting to 0
+- Separate zebra ZAPI server open and accept
+- Unlock node only after operation in zebra_free_rnh()
* Wed Sep 11 2024 Donatas Abraitis <donatas@opensourcerouting.org> - 9.1.2
- bgpd
diff --git a/tests/topotests/bgp_aigp/r1/ospfd.conf b/tests/topotests/bgp_aigp/r1/ospfd.conf
index 38aa11d036..098bf57b03 100644
--- a/tests/topotests/bgp_aigp/r1/ospfd.conf
+++ b/tests/topotests/bgp_aigp/r1/ospfd.conf
@@ -1,6 +1,6 @@
!
interface lo
- ip ospf cost 10
+ ip ospf passive
!
interface r1-eth0
ip ospf dead-interval 4
diff --git a/tests/topotests/bgp_aigp/r2/bgpd.conf b/tests/topotests/bgp_aigp/r2/bgpd.conf
index 4db4687536..4539016f91 100644
--- a/tests/topotests/bgp_aigp/r2/bgpd.conf
+++ b/tests/topotests/bgp_aigp/r2/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65001
no bgp ebgp-requires-policy
no bgp network import-check
+ bgp route-reflector allow-outbound-policy
neighbor 10.0.0.1 remote-as internal
neighbor 10.0.0.1 timers 1 3
neighbor 10.0.0.1 timers connect 1
@@ -11,5 +12,6 @@ router bgp 65001
neighbor 192.168.24.4 aigp
address-family ipv4
redistribute connected
+ neighbor 10.0.0.1 next-hop-self force
exit-address-family
!
diff --git a/tests/topotests/bgp_aigp/r2/ospfd.conf b/tests/topotests/bgp_aigp/r2/ospfd.conf
index ed31941f65..106a46251d 100644
--- a/tests/topotests/bgp_aigp/r2/ospfd.conf
+++ b/tests/topotests/bgp_aigp/r2/ospfd.conf
@@ -1,6 +1,6 @@
!
interface lo
- ip ospf cost 10
+ ip ospf passive
!
interface r2-eth0
ip ospf dead-interval 4
diff --git a/tests/topotests/bgp_aigp/r3/bgpd.conf b/tests/topotests/bgp_aigp/r3/bgpd.conf
index 5ab712eaba..bdaa5cf55d 100644
--- a/tests/topotests/bgp_aigp/r3/bgpd.conf
+++ b/tests/topotests/bgp_aigp/r3/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65001
no bgp ebgp-requires-policy
no bgp network import-check
+ bgp route-reflector allow-outbound-policy
neighbor 10.0.0.1 remote-as internal
neighbor 10.0.0.1 timers 1 3
neighbor 10.0.0.1 timers connect 1
@@ -11,5 +12,6 @@ router bgp 65001
neighbor 192.168.35.5 aigp
address-family ipv4
redistribute connected
+ neighbor 10.0.0.1 next-hop-self force
exit-address-family
!
diff --git a/tests/topotests/bgp_aigp/r3/ospfd.conf b/tests/topotests/bgp_aigp/r3/ospfd.conf
index f971ad6f89..9ede3a1fab 100644
--- a/tests/topotests/bgp_aigp/r3/ospfd.conf
+++ b/tests/topotests/bgp_aigp/r3/ospfd.conf
@@ -1,6 +1,6 @@
!
interface lo
- ip ospf cost 10
+ ip ospf passive
!
interface r3-eth0
ip ospf dead-interval 4
diff --git a/tests/topotests/bgp_aigp/r4/bgpd.conf b/tests/topotests/bgp_aigp/r4/bgpd.conf
index aa88bac913..2cdf84a1b3 100644
--- a/tests/topotests/bgp_aigp/r4/bgpd.conf
+++ b/tests/topotests/bgp_aigp/r4/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65001
no bgp ebgp-requires-policy
no bgp network import-check
+ bgp route-reflector allow-outbound-policy
neighbor 192.168.24.2 remote-as internal
neighbor 192.168.24.2 timers 1 3
neighbor 192.168.24.2 timers connect 1
@@ -11,7 +12,25 @@ router bgp 65001
neighbor 10.0.0.6 timers connect 1
neighbor 10.0.0.6 update-source lo
address-family ipv4
- redistribute connected
- redistribute ospf
+ redistribute connected route-map connected-to-bgp
+ redistribute ospf route-map ospf-to-bgp
+ neighbor 192.168.24.2 route-map set-nexthop out
exit-address-family
!
+ip prefix-list p66 seq 5 permit 10.0.6.6/32
+!
+route-map ospf-to-bgp permit 10
+ match ip address prefix-list p66
+ set aigp igp-metric
+!
+! Two OSPF domains should be isolated - otherwise the connected routes
+! on r4 would be advertised to r3 (via r4 -> r6 -> r5 -> r3), and can
+! mess up bgp bestpath calculation (igp metrics for the BGP nexthops).
+!
+route-map connected-to-bgp permit 10
+ set community no-advertise
+!
+route-map set-nexthop permit 10
+ set ip next-hop peer-address
+exit
+!
diff --git a/tests/topotests/bgp_aigp/r4/ospfd.conf b/tests/topotests/bgp_aigp/r4/ospfd.conf
index c9e6796f6e..237b5e18ab 100644
--- a/tests/topotests/bgp_aigp/r4/ospfd.conf
+++ b/tests/topotests/bgp_aigp/r4/ospfd.conf
@@ -1,6 +1,6 @@
!
interface lo
- ip ospf cost 10
+ ip ospf passive
!
interface r4-eth1
ip ospf dead-interval 4
diff --git a/tests/topotests/bgp_aigp/r5/bgpd.conf b/tests/topotests/bgp_aigp/r5/bgpd.conf
index 4fde262053..3d1f5e8572 100644
--- a/tests/topotests/bgp_aigp/r5/bgpd.conf
+++ b/tests/topotests/bgp_aigp/r5/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65001
no bgp ebgp-requires-policy
no bgp network import-check
+ bgp route-reflector allow-outbound-policy
neighbor 192.168.35.3 remote-as internal
neighbor 192.168.35.3 timers 1 3
neighbor 192.168.35.3 timers connect 1
@@ -11,7 +12,18 @@ router bgp 65001
neighbor 10.0.0.6 timers connect 1
neighbor 10.0.0.6 update-source lo
address-family ipv4
- redistribute connected
- redistribute ospf
+ redistribute connected route-map connected-to-bgp
+ neighbor 192.168.35.3 route-map set-nexthop out
exit-address-family
!
+! Two OSPF domains should be isolated - otherwise the connected routes
+! on r5 would be advertised to r2 (via r5 -> r6 -> r4 -> r2), and can
+! mess up bgp bestpath calculation (igp metrics for the BGP nexthops).
+!
+route-map connected-to-bgp permit 10
+ set community no-advertise
+!
+route-map set-nexthop permit 10
+ set ip next-hop peer-address
+exit
+!
diff --git a/tests/topotests/bgp_aigp/r5/ospfd.conf b/tests/topotests/bgp_aigp/r5/ospfd.conf
index b853c74102..65a213df17 100644
--- a/tests/topotests/bgp_aigp/r5/ospfd.conf
+++ b/tests/topotests/bgp_aigp/r5/ospfd.conf
@@ -1,6 +1,6 @@
!
interface lo
- ip ospf cost 10
+ ip ospf passive
!
interface r5-eth1
ip ospf dead-interval 4
diff --git a/tests/topotests/bgp_aigp/r6/bgpd.conf b/tests/topotests/bgp_aigp/r6/bgpd.conf
index 2faae7720c..2d5f7a89ba 100644
--- a/tests/topotests/bgp_aigp/r6/bgpd.conf
+++ b/tests/topotests/bgp_aigp/r6/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65001
no bgp ebgp-requires-policy
no bgp network import-check
+ bgp route-reflector allow-outbound-policy
neighbor 10.0.0.4 remote-as internal
neighbor 10.0.0.4 timers 1 3
neighbor 10.0.0.4 timers connect 1
@@ -15,6 +16,11 @@ router bgp 65001
neighbor 192.168.67.7 timers 1 3
neighbor 192.168.67.7 timers connect 1
address-family ipv4
- redistribute ospf
+ neighbor 10.0.0.4 route-map set-nexthop out
+ neighbor 10.0.0.5 route-map set-nexthop out
exit-address-family
!
+route-map set-nexthop permit 10
+ set ip next-hop peer-address
+exit
+!
diff --git a/tests/topotests/bgp_aigp/r6/ospfd.conf b/tests/topotests/bgp_aigp/r6/ospfd.conf
index 46b2933178..89cbefa895 100644
--- a/tests/topotests/bgp_aigp/r6/ospfd.conf
+++ b/tests/topotests/bgp_aigp/r6/ospfd.conf
@@ -1,6 +1,6 @@
!
interface lo
- ip ospf cost 10
+ ip ospf passive
!
interface r6-eth0
ip ospf dead-interval 4
diff --git a/tests/topotests/bgp_aigp/r6/zebra.conf b/tests/topotests/bgp_aigp/r6/zebra.conf
index f8ca5f8b82..b6456cacc5 100644
--- a/tests/topotests/bgp_aigp/r6/zebra.conf
+++ b/tests/topotests/bgp_aigp/r6/zebra.conf
@@ -1,6 +1,7 @@
!
interface lo
ip address 10.0.0.6/32
+ ip address 10.0.6.6/32
!
interface r6-eth0
ip address 192.168.46.6/24
diff --git a/tests/topotests/bgp_aigp/test_bgp_aigp.py b/tests/topotests/bgp_aigp/test_bgp_aigp.py
index 655e9ad184..27a4d9ec74 100644
--- a/tests/topotests/bgp_aigp/test_bgp_aigp.py
+++ b/tests/topotests/bgp_aigp/test_bgp_aigp.py
@@ -12,9 +12,9 @@ r7 sets aigp-metric for 10.0.0.71/32 to 71, and 72 for 10.0.0.72/32.
r6 receives those routes with aigp-metric TLV.
r2 and r3 receives those routes with aigp-metric TLV increased by 20,
-and 30 appropriately.
+and 10 appropriately.
-r1 receives routes with aigp-metric TLV 111,131 and 112,132 appropriately.
+r1 receives routes with aigp-metric TLV 81, 91 and 82, 92 respectively.
"""
import os
@@ -109,15 +109,29 @@ def test_bgp_aigp():
expected = {
"paths": [
{
- "aigpMetric": 111,
+ "aigpMetric": 81,
"valid": True,
- "nexthops": [{"hostname": "r3", "accessible": True}],
+ "nexthops": [
+ {
+ "ip": "10.0.0.3",
+ "hostname": "r3",
+ "metric": 30,
+ "accessible": True,
+ }
+ ],
},
{
- "aigpMetric": 131,
+ "aigpMetric": 91,
"valid": True,
- "bestpath": {"selectionReason": "Neighbor IP"},
- "nexthops": [{"hostname": "r2", "accessible": True}],
+ "bestpath": {"selectionReason": "IGP Metric"},
+ "nexthops": [
+ {
+ "ip": "10.0.0.2",
+ "hostname": "r2",
+ "metric": 10,
+ "accessible": True,
+ }
+ ],
},
]
}
@@ -141,30 +155,58 @@ def test_bgp_aigp():
"10.0.0.71/32": {
"paths": [
{
- "aigpMetric": 111,
- "bestpath": {"selectionReason": "AIGP"},
+ "aigpMetric": 81,
"valid": True,
- "nexthops": [{"hostname": "r3", "accessible": True}],
+ "nexthops": [
+ {
+ "ip": "10.0.0.3",
+ "hostname": "r3",
+ "metric": 30,
+ "accessible": True,
+ }
+ ],
},
{
- "aigpMetric": 131,
+ "aigpMetric": 91,
"valid": True,
- "nexthops": [{"hostname": "r2", "accessible": True}],
+ "bestpath": {"selectionReason": "AIGP"},
+ "nexthops": [
+ {
+ "ip": "10.0.0.2",
+ "hostname": "r2",
+ "metric": 10,
+ "accessible": True,
+ }
+ ],
},
],
},
"10.0.0.72/32": {
"paths": [
{
- "aigpMetric": 112,
- "bestpath": {"selectionReason": "AIGP"},
+ "aigpMetric": 82,
"valid": True,
- "nexthops": [{"hostname": "r3", "accessible": True}],
+ "nexthops": [
+ {
+ "ip": "10.0.0.3",
+ "hostname": "r3",
+ "metric": 30,
+ "accessible": True,
+ }
+ ],
},
{
- "aigpMetric": 132,
+ "aigpMetric": 92,
"valid": True,
- "nexthops": [{"hostname": "r2", "accessible": True}],
+ "bestpath": {"selectionReason": "AIGP"},
+ "nexthops": [
+ {
+ "ip": "10.0.0.2",
+ "hostname": "r2",
+ "metric": 10,
+ "accessible": True,
+ }
+ ],
},
],
},
@@ -186,6 +228,11 @@ def test_bgp_aigp():
"""
)
+ # r4, 10.0.6.6/32 with aigp-metric 20
+ test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.6.6/32", 20)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assert result is None, "aigp-metric for 10.0.6.6/32 is not 20"
+
# r4, 10.0.0.71/32 with aigp-metric 71
test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.0.71/32", 71)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
@@ -196,17 +243,17 @@ def test_bgp_aigp():
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assert result is None, "aigp-metric for 10.0.0.72/32 is not 72"
- # r2, 10.0.0.71/32 with aigp-metric 101 (71 + 30)
- test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.0.71/32", 101)
+ # r2, 10.0.0.71/32 with aigp-metric 101 (71 + 20)
+ test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.0.71/32", 91)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
- assert result is None, "aigp-metric for 10.0.0.71/32 is not 101"
+ assert result is None, "aigp-metric for 10.0.0.71/32 is not 91"
- # r3, 10.0.0.72/32 with aigp-metric 92 (72 + 20)
- test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.0.72/32", 92)
+ # r3, 10.0.0.72/32 with aigp-metric 92 (72 + 10)
+ test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.0.72/32", 82)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
- assert result is None, "aigp-metric for 10.0.0.72/32 is not 92"
+ assert result is None, "aigp-metric for 10.0.0.72/32 is not 82"
- # r1, check if AIGP is considered in best-path selection (lowest wins)
+ # r1, check if AIGP is considered in best-path selection (lowest wins: aigp + nexthop-metric)
test_func = functools.partial(_bgp_check_aigp_metric_bestpath)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assert result is None, "AIGP attribute is not considered in best-path selection"
diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c
index 36494c7df8..a2fb2bc321 100644
--- a/vrrpd/vrrp_packet.c
+++ b/vrrpd/vrrp_packet.c
@@ -234,7 +234,7 @@ ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph,
} else if (family == AF_INET6) {
struct cmsghdr *c;
- for (c = CMSG_FIRSTHDR(m); c != NULL; CMSG_NXTHDR(m, c)) {
+ for (c = CMSG_FIRSTHDR(m); c != NULL; c = CMSG_NXTHDR(m, c)) {
if (c->cmsg_level == IPPROTO_IPV6
&& c->cmsg_type == IPV6_HOPLIMIT)
break;
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 2a87925231..cf473f9318 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -1249,7 +1249,7 @@ static void fpm_enqueue_l3vni_table(struct hash_bucket *bucket, void *arg)
struct zebra_l3vni *zl3vni = bucket->data;
fra->zl3vni = zl3vni;
- hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, zl3vni);
+ hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, fra);
}
static void fpm_rmac_send(struct event *t)
diff --git a/zebra/main.c b/zebra/main.c
index b660118824..24b2f3e9d6 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -320,7 +320,7 @@ int main(int argc, char **argv)
" -r, --retain When program terminates, retain added route by zebra.\n"
" -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n"
" -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n"
- " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops"
+ " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops\n"
#ifdef HAVE_NETLINK
" -s, --nl-bufsize Set netlink receive buffer size\n"
" -n, --vrfwnetns Use NetNS as VRF backend\n"
@@ -418,6 +418,9 @@ int main(int argc, char **argv)
zebra_if_init();
zebra_debug_init();
+ /* Open Zebra API server socket */
+ zserv_open(zserv_path);
+
/*
* Initialize NS( and implicitly the VRF module), and make kernel
* routing socket. */
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index aeb7ae35b6..0bfa2b9776 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -220,10 +220,9 @@ void zebra_free_rnh(struct rnh *rnh)
if (rern) {
rib_dest_t *dest;
- route_unlock_node(rern);
-
dest = rib_dest_from_rnode(rern);
rnh_list_del(&dest->nht, rnh);
+ route_unlock_node(rern);
}
}
free_state(rnh->vrf_id, rnh->state, rnh->node);
diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c
index 8cab184953..a87f1bbbf7 100644
--- a/zebra/zebra_snmp.c
+++ b/zebra/zebra_snmp.c
@@ -227,6 +227,8 @@ static int proto_trans(int type)
return 3; /* static route */
case ZEBRA_ROUTE_RIP:
return 8; /* rip */
+ case ZEBRA_ROUTE_ISIS:
+ return 9;
case ZEBRA_ROUTE_RIPNG:
return 1; /* shouldn't happen */
case ZEBRA_ROUTE_OSPF:
@@ -235,6 +237,8 @@ static int proto_trans(int type)
return 1; /* shouldn't happen */
case ZEBRA_ROUTE_BGP:
return 14; /* bgp */
+ case ZEBRA_ROUTE_EIGRP:
+ return 16;
default:
return 1; /* other */
}
@@ -251,9 +255,11 @@ static void check_replace(struct route_node *np2, struct route_entry *re2,
return;
}
- if (prefix_cmp(&(*np)->p, &np2->p) < 0)
+ if (in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4,
+ (uint8_t *)&np2->p.u.prefix4) < 0)
return;
- if (prefix_cmp(&(*np)->p, &np2->p) > 0) {
+ if (in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4,
+ (uint8_t *)&np2->p.u.prefix4) > 0) {
*np = np2;
*re = re2;
return;
@@ -296,14 +302,8 @@ static void get_fwtable_route_node(struct variable *v, oid objid[],
int i;
/* Init index variables */
-
- pnt = (uint8_t *)&dest;
- for (i = 0; i < 4; i++)
- *pnt++ = 0;
-
- pnt = (uint8_t *)&nexthop;
- for (i = 0; i < 4; i++)
- *pnt++ = 0;
+ memset(&dest, 0, sizeof(dest));
+ memset(&nexthop, 0, sizeof(nexthop));
proto = 0;
policy = 0;
@@ -495,23 +495,23 @@ static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len,
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC1:
- result = 0;
+ result = re->metric;
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC2:
- result = 0;
+ result = -1;
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC3:
- result = 0;
+ result = -1;
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC4:
- result = 0;
+ result = -1;
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC5:
- result = 0;
+ result = -1;
*val_len = sizeof(int);
return (uint8_t *)&result;
default:
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index d36c2f81c7..a7d983142f 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -4017,6 +4017,10 @@ static int config_write_protocol(struct vty *vty)
if (!zebra_nhg_recursive_use_backups())
vty_out(vty, "no zebra nexthop resolve-via-backup\n");
+#ifdef HAVE_SCRIPTING
+ frrscript_names_config_write(vty);
+#endif
+
if (rnh_get_hide_backups())
vty_out(vty, "ip nht hide-backup-events\n");
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 2db228b158..d45e33899f 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -57,6 +57,7 @@ extern struct zebra_privs_t zserv_privs;
/* The listener socket for clients connecting to us */
static int zsock;
+static bool started_p;
/* The lock that protects access to zapi client objects */
static pthread_mutex_t client_mutex;
@@ -890,9 +891,16 @@ void zserv_close(void)
/* Free client list's mutex */
pthread_mutex_destroy(&client_mutex);
+
+ started_p = false;
}
-void zserv_start(char *path)
+
+/*
+ * Open zebra's ZAPI listener socket. This is done early during startup,
+ * before zebra is ready to listen and accept client connections.
+ */
+void zserv_open(const char *path)
{
int ret;
mode_t old_mask;
@@ -934,6 +942,26 @@ void zserv_start(char *path)
path, safe_strerror(errno));
close(zsock);
zsock = -1;
+ }
+
+ umask(old_mask);
+}
+
+/*
+ * Start listening for ZAPI client connections.
+ */
+void zserv_start(const char *path)
+{
+ int ret;
+
+ /* This may be called more than once during startup - potentially once
+ * per netns - but only do this work once.
+ */
+ if (started_p)
+ return;
+
+ if (zsock <= 0) {
+ flog_err_sys(EC_LIB_SOCKET, "Zserv socket open failed");
return;
}
@@ -947,7 +975,7 @@ void zserv_start(char *path)
return;
}
- umask(old_mask);
+ started_p = true;
zserv_event(NULL, ZSERV_ACCEPT);
}
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 90aa4d53f4..c6ad902339 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -255,15 +255,24 @@ extern void zserv_init(void);
extern void zserv_close(void);
/*
+ * Open Zebra API server socket.
+ *
+ * Create and open the server socket.
+ *
+ * path
+ * where to place the Unix domain socket
+ */
+extern void zserv_open(const char *path);
+
+/*
* Start Zebra API server.
*
- * Allocates resources, creates the server socket and begins listening on the
- * socket.
+ * Allocates resources and begins listening on the server socket.
*
* path
* where to place the Unix domain socket
*/
-extern void zserv_start(char *path);
+extern void zserv_start(const char *path);
/*
* Send a message to a connected Zebra API client.