\
python/xrefstructs.json \
\
- redhat/frr.logrotate \
+ tools/etc/logrotate.d/frr \
redhat/frr.pam \
redhat/frr.spec \
\
libcap-dev libcurl libedit libffi libgcc libgomp libisoburn libisofs
libltdl libressl libssh2 libstdc++ libtool libuuid
linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr4 mtools musl-dev
- ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre
- perl pkgconf python3 python3-dev readline readline-dev sqlite-libs
+ ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre2
+ perl pkgconf python3 python3-dev readline readline-dev sqlite-libs pcre2-dev
squashfs-tools sudo tar texinfo xorriso xz-libs py-pip rtrlib rtrlib-dev
py3-sphinx elfutils elfutils-dev libyang-dev"
checkdepends="pytest py-setuptools"
--enable-multipath=64 \
--enable-vty-group=frrvty \
--enable-user=$_user \
- --enable-group=$_user
- make
+ --enable-group=$_user \
+ --enable-pcre2posix
+ make -j $(nproc)
}
check() {
stream_put(s, &attr->srv6_l3vpn->sid,
sizeof(attr->srv6_l3vpn->sid)); /* sid */
stream_putc(s, 0); /* sid_flags */
- stream_putw(s, 0xffff); /* endpoint */
+ stream_putw(s,
+ attr->srv6_l3vpn
+ ->endpoint_behavior); /* endpoint */
stream_putc(s, 0); /* reserved */
stream_putc(
s,
"AS Set config change",
"Waiting for peer OPEN",
"Reached received prefix count",
- "Socket Error"};
+ "Socket Error",
+ "Admin. shutdown (RTT)"};
static void bgp_graceful_restart_timer_off(struct peer *peer)
{
flog_err(EC_BGP_FSM,
"%s [FSM] Trying to start suppressed peer - this is never supposed to happen!",
peer->host);
- if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN))
+ peer->last_reset = PEER_DOWN_RTT_SHUTDOWN;
+ else if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
else if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN))
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
case -ENOMEM:
ibuf_full = true;
if (!ibuf_full_logged) {
- flog_warn(
- EC_BGP_UPDATE_RCV,
- "%s [Warning] Peer Input-Queue is full: limit (%u)",
- peer->host, bm->inq_limit);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s [Event] Peer Input-Queue is full: limit (%u)",
+ peer->host, bm->inq_limit);
+
ibuf_full_logged = true;
}
break;
/* Set SID for SRv6 VPN */
if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
+ struct srv6_locator_chunk *locator =
+ from_bgp->vpn_policy[afi].tovpn_sid_locator;
encode_label(
from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
&label);
static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
- static_attr.srv6_l3vpn->endpoint_behavior = 0xffff;
+ static_attr.srv6_l3vpn->endpoint_behavior =
+ afi == AFI_IP
+ ? (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
+ ? SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID
+ : SRV6_ENDPOINT_BEHAVIOR_END_DT4)
+ : (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
+ ? SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID
+ : SRV6_ENDPOINT_BEHAVIOR_END_DT6);
static_attr.srv6_l3vpn->loc_block_len =
from_bgp->vpn_policy[afi]
.tovpn_sid_locator->block_bits_length;
.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;
encode_label(from_bgp->tovpn_sid_transpose_label, &label);
static_attr.srv6_l3vpn =
XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
- static_attr.srv6_l3vpn->endpoint_behavior = 0xffff;
+ static_attr.srv6_l3vpn->endpoint_behavior =
+ CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
+ ? SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID
+ : SRV6_ENDPOINT_BEHAVIOR_END_DT46;
static_attr.srv6_l3vpn->loc_block_len =
from_bgp->tovpn_sid_locator->block_bits_length;
static_attr.srv6_l3vpn->loc_node_len =
if (code == BGP_NOTIFY_CEASE) {
if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET)
peer->last_reset = PEER_DOWN_USER_RESET;
- else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
- peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
- else
+ else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) {
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN))
+ peer->last_reset = PEER_DOWN_RTT_SHUTDOWN;
+ else
+ peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
+ } else
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
} else
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
/* If the peer's RTT is higher than expected, shutdown
* the peer automatically.
*/
- if (CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN)
- && peer->rtt > peer->rtt_expected) {
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN))
+ return Receive_KEEPALIVE_message;
+ if (peer->rtt > peer->rtt_expected) {
peer->rtt_keepalive_rcv++;
if (peer->rtt_keepalive_rcv > peer->rtt_keepalive_conf) {
- zlog_warn(
- "%s shutdown due to high round-trip-time (%dms > %dms)",
- peer->host, peer->rtt, peer->rtt_expected);
+ char rtt_shutdown_reason[BUFSIZ] = {};
+
+ snprintfrr(
+ rtt_shutdown_reason,
+ sizeof(rtt_shutdown_reason),
+ "shutdown due to high round-trip-time (%dms > %dms, hit %u times)",
+ peer->rtt, peer->rtt_expected,
+ peer->rtt_keepalive_rcv);
+ zlog_warn("%s %s", peer->host, rtt_shutdown_reason);
+ SET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN);
+ peer_tx_shutdown_message_set(peer, rtt_shutdown_reason);
peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
}
} else {
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef _QUAGGA_BGP_REGEX_H
-#define _QUAGGA_BGP_REGEX_H
+#ifndef _FRR_BGP_REGEX_H
+#define _FRR_BGP_REGEX_H
#include <zebra.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
extern void bgp_regex_free(regex_t *regex);
extern regex_t *bgp_regcomp(const char *str);
extern int bgp_regexec(regex_t *regex, struct aspath *aspath);
-#endif /* _QUAGGA_BGP_REGEX_H */
+#endif /* _FRR_BGP_REGEX_H */
int vnc_implicit_withdraw = 0;
#endif
int same_attr = 0;
+ const struct prefix *bgp_nht_param_prefix;
/* Special case for BGP-LU - map LU safi to ordinary unicast safi */
if (orig_safi == SAFI_LABELED_UNICAST)
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))
+ bgp_nht_param_prefix = NULL;
+ else
+ bgp_nht_param_prefix = p;
+
/* AS path loop check. */
if (do_loop_check) {
if (aspath_loop_check(attr->aspath, bgp->as) > allowas_in ||
if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, nh_afi,
safi, pi, NULL, connected,
- p)
- || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
+ bgp_nht_param_prefix) ||
+ CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
bgp_path_info_set_flag(dest, pi,
BGP_PATH_VALID);
else {
nh_afi = BGP_ATTR_NH_AFI(afi, new->attr);
if (bgp_find_or_add_nexthop(bgp, bgp, nh_afi, safi, new, NULL,
- connected, p)
- || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
+ connected, bgp_nht_param_prefix) ||
+ CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
else {
if (BGP_DEBUG(nht, NHT)) {
#include "log.h"
#include "frrlua.h"
#include "frrscript.h"
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include "buffer.h"
#include "sockunion.h"
#include "hash.h"
return CMD_WARNING_CONFIG_FAILED;
}
- if (!set && flag == PEER_FLAG_SHUTDOWN)
+ if (!set && flag == PEER_FLAG_SHUTDOWN) {
peer_tx_shutdown_message_unset(peer);
+ UNSET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN);
+ }
if (set)
ret = peer_flag_set(peer, flag);
if (use_json) {
json_object_int_add(json_neigh, "connectRetryTimer",
p->v_connect);
- if (peer_established(p) && p->rtt)
+ if (peer_established(p)) {
json_object_int_add(json_neigh, "estimatedRttInMsecs",
p->rtt);
+ if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN)) {
+ json_object_int_add(json_neigh,
+ "shutdownRttInMsecs",
+ p->rtt_expected);
+ json_object_int_add(json_neigh,
+ "shutdownRttAfterCount",
+ p->rtt_keepalive_rcv);
+ }
+ }
if (p->t_start)
json_object_int_add(
json_neigh, "nextStartTimerDueInMsecs",
} else {
vty_out(vty, "BGP Connect Retry Timer in Seconds: %d\n",
p->v_connect);
- if (peer_established(p) && p->rtt)
+ if (peer_established(p)) {
vty_out(vty, "Estimated round trip time: %d ms\n",
p->rtt);
+ if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN))
+ vty_out(vty,
+ "Shutdown when RTT > %dms, count > %u\n",
+ p->rtt_expected, p->rtt_keepalive_rcv);
+ }
if (p->t_start)
vty_out(vty, "Next start timer due in %ld seconds\n",
thread_timer_remain_second(p->t_start));
/* LLGR aware peer */
#define PEER_STATUS_LLGR_WAIT (1U << 11)
#define PEER_STATUS_REFRESH_PENDING (1U << 12) /* refresh request from peer */
+#define PEER_STATUS_RTT_SHUTDOWN (1U << 13) /* In shutdown state due to RTT */
/* Configured timer values. */
_Atomic uint32_t holdtime;
#define PEER_DOWN_WAITING_OPEN 32U /* Waiting for open to succeed */
#define PEER_DOWN_PFX_COUNT 33U /* Reached received prefix count */
#define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */
+#define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */
/*
* Remember to update peer_down_str in bgp_fsm.c when you add
* a new value to the last_reset reason
AS_HELP_STRING([--disable-cpu-time], [disable cpu usage data gathering]))
AC_ARG_ENABLE([pcreposix],
AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions]))
+AC_ARG_ENABLE([pcre2posix],
+ AS_HELP_STRING([--enable-pcre2posix], [enable using PCRE2 Posix libs for regex functions]))
AC_ARG_ENABLE([fpm],
AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support]))
AC_ARG_ENABLE([werror],
fi
AC_SUBST([HAVE_LIBPCREPOSIX])
+dnl ---------------------------
+dnl check system has PCRE2 regexp
+dnl ---------------------------
+if test "$enable_pcre2posix" = "yes"; then
+ AC_CHECK_LIB([pcre2-posix], [regexec], [], [
+ AC_MSG_ERROR([--enable-pcre2posix given but unable to find libpcre2-posix])
+ ])
+fi
+AC_SUBST([HAVE_LIBPCRE2_POSIX])
+
dnl ##########################################################################
dnl test "$enable_clippy_only" != "yes"
fi
debian/frr.conf usr/lib/tmpfiles.d
etc/
tools/etc/frr/frr.conf etc/frr/
+tools/etc/logrotate.d/frr etc/logrotate.d/
tools/frr-reload usr/lib/frr/
usr/bin/mtracebis
usr/bin/vtysh
+++ /dev/null
-/var/log/frr/*.log {
- size 500k
- sharedscripts
- missingok
- compress
- rotate 14
- create 0640 frr frr
-
- postrotate
- pid=$(lsof -t -a -c /syslog/ /var/log/frr/* 2>/dev/null)
- if [ -n "$pid" ]
- then # using syslog
- kill -HUP $pid
- fi
- # in case using file logging; if switching back and forth
- # between file and syslog, rsyslogd might still have file
- # open, as well as the daemons, so always signal the daemons.
- # It's safe, a NOP if (only) syslog is being used.
- for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd sharpd \
- pimd pim6d ripd ripngd zebra pathd pbrd staticd bfdd fabricd vrrpd; do
- if [ -e /var/run/frr/$i.pid ] ; then
- pids="$pids $(cat /var/run/frr/$i.pid)"
- fi
- done
- [ -n "$pids" ] && kill -USR1 $pids || true
- endscript
-}
# Any user may call vtysh but only those belonging to the group frrvty can
# actually connect to the socket and use the program.
auth sufficient pam_permit.so
+account sufficient pam_rootok.so
Turn on the usage of PCRE Posix libs for regex functionality.
+.. option:: --enable-pcre2posix
+
+ Turn on the usage of PCRE2 Posix libs for regex functionality.
+
+ PCRE2 versions <= 10.31 work a bit differently. We suggest using at least
+ >= 10.36.
+
.. option:: --enable-rpath
Set hardcoded rpaths in the executable [default=yes].
.. image:: images/pathd_initiated_multi.png
Starting
-=============
+========
Default configuration file for *pathd* is :file:`pathd.conf`. The typical
location of :file:`pathd.conf` is |INSTALL_PREFIX_ETC|/pathd.conf.
Specify a peer and its precedence in a PCC definition.
+Debugging
+---------
+
+.. clicmd:: debug pathd policy
+
+ Enable or disable Pathd policy information.
Introspection Commands
----------------------
!
...
+.. clicmd:: behavior usid
+
+ Specify the SRv6 locator as a Micro-segment (uSID) locator. When a locator is
+ specified as a uSID locator, all the SRv6 SIDs allocated from the locator by the routing
+ protocols are bound to the SRv6 uSID behaviors. For example, if you configure BGP to use
+ a locator specified as a uSID locator, BGP instantiates and advertises SRv6 uSID behaviors
+ (e.g., ``uDT4`` / ``uDT6`` / ``uDT46``) instead of classic SRv6 behaviors
+ (e.g., ``End.DT4`` / ``End.DT6`` / ``End.DT46``).
+
+::
+
+ router# configure terminal
+ router(config)# segment-routinig
+ router(config-sr)# srv6
+ router(config-srv6)# locators
+ router(config-srv6-locators)# locator loc1
+ router(config-srv6-locator)# prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16
+ router(config-srv6-locator)# behavior usid
+
+ router(config-srv6-locator)# show run
+ ...
+ segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:1::/48
+ behavior usid
+ !
+ ...
+
.. _multicast-rib-commands:
Multicast RIB Commands
# syntax=docker/dockerfile:1
# Create a basic stage set up to build APKs
-FROM alpine:3.15 as alpine-builder
+FROM alpine:3.16 as alpine-builder
RUN apk add \
--update-cache \
abuild \
RUN adduser -D -G abuild builder && su builder -c 'abuild-keygen -a -n'
# This stage builds a dist tarball from the source
-FROM alpine:3.15 as source-builder
+FROM alpine:3.16 as source-builder
RUN mkdir -p /src/alpine
COPY alpine/APKBUILD.in /src/alpine
&& abuild -r -P /pkgs/apk
# This stage installs frr from the apk
-FROM alpine:3.15
+FROM alpine:3.16
RUN mkdir -p /pkgs/apk
COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/
RUN apk add \
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include "frrstr.h"
#include "memory.h"
#include <sys/types.h>
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include <stdbool.h>
#include "vector.h"
#define IPADDRSZ(p) \
(IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr))
+#define IPADDR_STRING_SIZE 46
+
static inline int ipaddr_family(const struct ipaddr *ip)
{
switch (ip->ipa_type) {
json_object_int_add(jo_root, "argumentBitsLength",
loc->argument_bits_length);
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
+ json_object_string_add(jo_root, "behavior", "usid");
+
/* set status_up */
json_object_boolean_add(jo_root, "statusUp",
loc->status_up);
json_object_int_add(jo_root, "argumentBitsLength",
loc->argument_bits_length);
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
+ json_object_string_add(jo_root, "behavior", "usid");
+
/* set algonum */
json_object_int_add(jo_root, "algoNum", loc->algonum);
bool status_up;
struct list *chunks;
+ uint8_t flags;
+#define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(srv6_locator);
uint8_t proto;
uint16_t instance;
uint32_t session_id;
+
+ uint8_t flags;
+};
+
+/*
+ * SRv6 Endpoint Behavior codepoints, as defined by IANA in
+ * https://www.iana.org/assignments/segment-routing/segment-routing.xhtml
+ */
+enum srv6_endpoint_behavior_codepoint {
+ SRV6_ENDPOINT_BEHAVIOR_RESERVED = 0x0000,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT6 = 0x0012,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT4 = 0x0013,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT46 = 0x0014,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID = 0x003E,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID = 0x003F,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID = 0x0040,
+ SRV6_ENDPOINT_BEHAVIOR_OPAQUE = 0xFFFF,
};
struct nexthop_srv6 {
#include <lib/version.h>
#include <sys/types.h>
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include <stdio.h>
#include "linklist.h"
#define _ZEBRA_VTY_H
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include "thread.h"
#include "log.h"
stream_putc(s, c->node_bits_length);
stream_putc(s, c->function_bits_length);
stream_putc(s, c->argument_bits_length);
+ stream_putc(s, c->flags);
return 0;
}
STREAM_GETC(s, c->node_bits_length);
STREAM_GETC(s, c->function_bits_length);
STREAM_GETC(s, c->argument_bits_length);
+ STREAM_GETC(s, c->flags);
return 0;
stream_failure:
*/
if (ospf->router_id.s_addr == INADDR_ANY) {
- if (IS_DEBUG_OSPF_EVENT)
+ if (ei && IS_DEBUG_OSPF_EVENT)
zlog_debug(
"LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero",
&ei->p.prefix);
/* Create new AS-external-LSA instance. */
if ((new = ospf_external_lsa_new(ospf, ei, NULL)) == NULL) {
- if (IS_DEBUG_OSPF_EVENT)
+ if (ei && IS_DEBUG_OSPF_EVENT)
zlog_debug(
"LSA[Type5:%pI4]: Could not originate AS-external-LSA",
&ei->p.prefix);
ttable_rowseps(tt, 0, BOTTOM, true, '-');
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
char binding_sid[16] = "-";
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
vty_out(vty, "\n");
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
struct srte_candidate *candidate;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
char binding_sid[16] = "-";
char *segment_list_info;
static char undefined_info[] = "(undefined)";
"pathd module debugging\n")
{
+ vty_out(vty, "Path debugging status:\n");
+
cmd_show_lib_debugs(vty);
/* nothing to do here */
+ path_ted_show_debugging(vty);
+ path_policy_show_debugging(vty);
+ return CMD_SUCCESS;
+}
+
+DEFPY(debug_path_policy, debug_path_policy_cmd, "[no] debug pathd policy",
+ NO_STR DEBUG_STR
+ "path debugging\n"
+ "policy debugging\n")
+{
+ uint32_t mode = DEBUG_NODE2MODE(vty->node);
+ bool no_debug = no;
+
+ DEBUG_MODE_SET(&path_policy_debug, mode, !no);
+ DEBUG_FLAGS_SET(&path_policy_debug, PATH_POLICY_DEBUG_BASIC, !no_debug);
return CMD_SUCCESS;
}
return 1;
}
+static int path_policy_cli_debug_config_write(struct vty *vty)
+{
+ if (DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_CONF)) {
+ if (DEBUG_FLAGS_CHECK(&path_policy_debug,
+ PATH_POLICY_DEBUG_BASIC))
+ vty_out(vty, "debug pathd policy\n");
+ return 1;
+ }
+ return 0;
+}
+
+static int path_policy_cli_debug_set_all(uint32_t flags, bool set)
+{
+ DEBUG_FLAGS_SET(&path_policy_debug, flags, set);
+
+ /* If all modes have been turned off, don't preserve options. */
+ if (!DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_ALL))
+ DEBUG_CLEAR(&path_policy_debug);
+
+ return 0;
+}
+
void path_cli_init(void)
{
+ hook_register(nb_client_debug_config_write,
+ path_policy_cli_debug_config_write);
+ hook_register(nb_client_debug_set_all, path_policy_cli_debug_set_all);
+
install_node(&segment_routing_node);
install_node(&sr_traffic_eng_node);
install_node(&srte_segment_list_node);
install_element(ENABLE_NODE, &show_srte_policy_cmd);
install_element(ENABLE_NODE, &show_srte_policy_detail_cmd);
+ install_element(ENABLE_NODE, &debug_path_policy_cmd);
+ install_element(CONFIG_NODE, &debug_path_policy_cmd);
+
install_element(CONFIG_NODE, &segment_routing_cmd);
install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd);
install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd);
return 0;
}
+void path_ted_show_debugging(struct vty *vty)
+{
+ if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
+ vty_out(vty, " Path TED debugging is on\n");
+}
+
int path_ted_cli_debug_set_all(uint32_t flags, bool set)
{
DEBUG_FLAGS_SET(&ted_state_g.dbg, flags, set);
/* TED configuration functions */
uint32_t path_ted_config_write(struct vty *vty);
+void path_ted_show_debugging(struct vty *vty);
/* TED util functions */
/* clang-format off */
#include "lib_errors.h"
#include "network.h"
#include "libfrr.h"
+#include <debug.h>
+#include <hook.h>
#include "pathd/pathd.h"
#include "pathd/path_zebra.h"
DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
(candidate));
+struct debug path_policy_debug;
+
+#define PATH_POLICY_DEBUG(fmt, ...) \
+ do { \
+ if (DEBUG_FLAGS_CHECK(&path_policy_debug, \
+ PATH_POLICY_DEBUG_BASIC)) \
+ DEBUGD(&path_policy_debug, "policy: " fmt, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+
static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
static void trigger_pathd_candidate_created_timer(struct thread *thread);
static void trigger_pathd_candidate_updated(struct srte_candidate *candidate);
struct srte_policy_head srte_policies = RB_INITIALIZER(&srte_policies);
+static void srte_policy_status_log(struct srte_policy *policy)
+{
+ char endpoint[ENDPOINT_STR_LENGTH];
+
+ ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+ if (policy->status == SRTE_POLICY_STATUS_DOWN) {
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): policy is DOWN", endpoint,
+ policy->color);
+ } else if (policy->status == SRTE_POLICY_STATUS_UP) {
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): policy is UP", endpoint,
+ policy->color);
+ }
+}
+
/**
* Adds a segment list to pathd.
*
RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol) {
if (CHECK_FLAG(policy->flags, F_POLICY_DELETED)) {
+ if (policy->status != SRTE_POLICY_STATUS_DOWN) {
+ policy->status = SRTE_POLICY_STATUS_DOWN;
+ srte_policy_status_log(policy);
+ }
srte_policy_del(policy);
continue;
}
struct srte_candidate *candidate, *safe;
struct srte_candidate *old_best_candidate;
struct srte_candidate *new_best_candidate;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
new_best_candidate = srte_policy_best_candidate(policy);
if (new_best_candidate != old_best_candidate) {
- /* TODO: add debug guard. */
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): best candidate changed from %s to %s",
endpoint, policy->color,
old_best_candidate ? old_best_candidate->name : "none",
F_SEGMENT_LIST_MODIFIED);
if (candidate_changed || segment_list_changed) {
- /* TODO: add debug guard. */
- zlog_debug("SR-TE(%s, %u): best candidate %s changed",
- endpoint, policy->color,
- new_best_candidate->name);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): best candidate %s changed",
+ endpoint, policy->color,
+ new_best_candidate->name);
path_zebra_add_sr_policy(
policy, new_best_candidate->lsp->segment_list);
float bandwidth, bool required)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s",
endpoint, policy->color, candidate->name,
required ? "required " : "", bandwidth);
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
- endpoint, policy->color, candidate->name,
- required ? "required" : "", bandwidth);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
+ endpoint, policy->color, candidate->name,
+ required ? "required" : "", bandwidth);
SET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
COND_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
lsp->bandwidth = bandwidth;
void srte_candidate_unset_bandwidth(struct srte_candidate *candidate)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s config bandwidth unset",
- endpoint, policy->color, candidate->name);
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): candidate %s config bandwidth unset",
+ endpoint, policy->color, candidate->name);
UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
candidate->bandwidth = 0;
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s lsp bandwidth unset", endpoint,
- policy->color, candidate->name);
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): candidate %s lsp bandwidth unset",
+ endpoint, policy->color, candidate->name);
UNSET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
UNSET_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
bool is_computed)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
endpoint, policy->color, candidate->name,
required ? "required " : "", srte_candidate_metric_name(type),
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
endpoint, policy->color, candidate->name,
required ? "required " : "", srte_candidate_metric_name(type),
enum srte_candidate_metric_type type)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
- endpoint, policy->color, candidate->name,
- srte_candidate_metric_name(type), type);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
+ endpoint, policy->color, candidate->name,
+ srte_candidate_metric_name(type), type);
assert((type > 0) && (type <= MAX_METRIC_TYPE));
srte_unset_metric(&candidate->metrics[type - 1]);
srte_lsp_unset_metric(candidate->lsp, type);
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
- endpoint, policy->color, candidate->name,
- srte_candidate_metric_name(type), type);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
+ endpoint, policy->color, candidate->name,
+ srte_candidate_metric_name(type), type);
assert((type > 0) && (type <= MAX_METRIC_TYPE));
srte_unset_metric(&lsp->metrics[type - 1]);
}
enum objfun_type type)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
candidate->objfun = type;
SET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN, required);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
- zlog_debug("SR-TE(%s, %u): candidate %s %sobjective function set to %s",
- endpoint, policy->color, candidate->name,
- required ? "required " : "", objfun_type_name(type));
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s %sobjective function set to %s",
+ endpoint, policy->color, candidate->name,
+ required ? "required " : "", objfun_type_name(type));
}
/**
void srte_candidate_unset_objfun(struct srte_candidate *candidate)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
candidate->objfun = OBJFUN_UNDEFINED;
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s objective functions preferences unset",
endpoint, policy->color, candidate->name);
}
uint32_t filter)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
assert(type > AFFINITY_FILTER_UNDEFINED);
SET_FLAG(candidate->flags, filter_type_to_flag(type));
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
candidate->affinity_filters[type - 1] = filter;
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s affinity filter %s set to 0x%08x",
endpoint, policy->color, candidate->name,
filter_type_name(type), filter);
enum affinity_filter_type type)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
assert(type > AFFINITY_FILTER_UNDEFINED);
UNSET_FLAG(candidate->flags, filter_type_to_flag(type));
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
candidate->affinity_filters[type - 1] = 0;
- zlog_debug("SR-TE(%s, %u): candidate %s affinity filter %s unset",
- endpoint, policy->color, candidate->name,
- filter_type_name(type));
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s affinity filter %s unset",
+ endpoint, policy->color, candidate->name,
+ filter_type_name(type));
}
/**
void srte_candidate_status_update(struct srte_candidate *candidate, int status)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): zebra updated status to %d", endpoint,
- policy->color, status);
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): zebra updated status to %d", endpoint,
+ policy->color, status);
switch (status) {
case ZEBRA_SR_POLICY_DOWN:
switch (policy->status) {
case SRTE_POLICY_STATUS_DOWN:
return;
default:
- zlog_debug("SR-TE(%s, %u): policy is DOWN", endpoint,
- policy->color);
policy->status = SRTE_POLICY_STATUS_DOWN;
+ srte_policy_status_log(policy);
break;
}
break;
case SRTE_POLICY_STATUS_UP:
return;
default:
- zlog_debug("SR-TE(%s, %u): policy is UP", endpoint,
- policy->color);
policy->status = SRTE_POLICY_STATUS_UP;
+ srte_policy_status_log(policy);
break;
}
break;
return;
}
- zlog_debug("Unset segment lists for originator %s", originator);
+ PATH_POLICY_DEBUG("Unset segment lists for originator %s", originator);
/* Iterate the policies, then iterate each policy's candidate path
* to check the candidate path's segment list originator */
struct srte_policy *policy;
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
- zlog_debug("Unset segment lists checking policy %s",
- policy->name);
+ PATH_POLICY_DEBUG("Unset segment lists checking policy %s",
+ policy->name);
struct srte_candidate *candidate;
RB_FOREACH (candidate, srte_candidate_head,
&policy->candidate_paths) {
- zlog_debug("Unset segment lists checking candidate %s",
- candidate->name);
+ PATH_POLICY_DEBUG(
+ "Unset segment lists checking candidate %s",
+ candidate->name);
if (candidate->lsp == NULL) {
continue;
}
sizeof(segment_list->originator))
== 0
|| force) {
- zlog_debug("Unset segment list %s",
- segment_list->name);
+ PATH_POLICY_DEBUG("Unset segment list %s",
+ segment_list->name);
SET_FLAG(segment_list->flags,
F_SEGMENT_LIST_DELETED);
SET_FLAG(candidate->flags,
}
}
+void path_policy_show_debugging(struct vty *vty)
+{
+ if (DEBUG_FLAGS_CHECK(&path_policy_debug, PATH_POLICY_DEBUG_BASIC))
+ vty_out(vty, " Path policy debugging is on\n");
+}
+
void pathd_shutdown(void)
{
path_ted_teardown();
zlog_warn(" %s: PATHD-TED: SL: ERROR query C : ted-sid (%d)",
__func__, ted_sid);
} else {
- zlog_debug("%s: PATHD-TED: SL: Success query C : ted-sid (%d)",
- __func__, ted_sid);
+ PATH_TED_DEBUG(
+ "%s: PATHD-TED: SL: Success query C : ted-sid (%d)",
+ __func__, ted_sid);
}
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
entry->sid_value)) {
zlog_warn(" %s: PATHD-TED: SL: ERROR query E : ted-sid (%d)",
__func__, ted_sid);
} else {
- zlog_debug("%s: PATHD-TED: SL: Success query E : ted-sid (%d)",
- __func__, ted_sid);
+ PATH_TED_DEBUG(
+ "%s: PATHD-TED: SL: Success query E : ted-sid (%d)",
+ __func__, ted_sid);
}
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
entry->sid_value)) {
zlog_warn("%s:SL: ERROR query F : ted-sid (%d)", __func__,
ted_sid);
} else {
- zlog_debug("%s:SL: Success query F : ted-sid (%d)", __func__,
- ted_sid);
+ PATH_TED_DEBUG("%s:SL: Success query F : ted-sid (%d)",
+ __func__, ted_sid);
}
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
entry->sid_value)) {
SRTE_ORIGIN_LOCAL = 3,
};
+extern struct debug path_policy_debug;
+
+#define PATH_POLICY_DEBUG_BASIC 0x01
+
enum srte_policy_status {
SRTE_POLICY_STATUS_UNKNOWN = 0,
SRTE_POLICY_STATUS_DOWN = 1,
RB_HEAD(srte_candidate_head, srte_candidate);
RB_PROTOTYPE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
+#define ENDPOINT_STR_LENGTH IPADDR_STRING_SIZE
+
struct srte_policy {
RB_ENTRY(srte_policy) entry;
void srte_candidate_unset_segment_list(const char *originator, bool force);
const char *srte_origin2str(enum srte_protocol_origin origin);
void pathd_shutdown(void);
+void path_policy_show_debugging(struct vty *vty);
/* path_cli.c */
void path_cli_init(void);
{
struct pim_interface *pim_ifp = ifc->ifp->info;
- if (ifc->address->family != AF_INET) {
+ if (ifc->address->family != PIM_AF) {
/* non-IPv4 address */
return;
}
for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
struct prefix *p = ifc->address;
- if (p->family != AF_INET)
+ if (p->family != PIM_AF)
continue;
pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
if (ip_hdr->ip_ttl-- <= 1)
return -1;
- ip_hdr->ip_sum = in_cksum(ip_hdr, ip_hdr->ip_hl * 4);
-
- fd = pim_socket_raw(IPPROTO_RAW);
-
- if (fd < 0)
- return -1;
-
- pim_socket_ip_hdr(fd);
-
if (interface == NULL) {
memset(&nexthop, 0, sizeof(nexthop));
if (!pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0)) {
- close(fd);
if (PIM_DEBUG_MTRACE)
zlog_debug(
"Dropping mtrace packet, no route to destination");
if_out = interface;
}
+ ip_hdr->ip_sum = in_cksum(ip_hdr, ip_hdr->ip_hl * 4);
+
+ fd = pim_socket_raw(IPPROTO_RAW);
+
+ if (fd < 0)
+ return -1;
+
+ pim_socket_ip_hdr(fd);
+
ret = pim_socket_bind(fd, if_out);
if (ret < 0) {
#include "lib/northbound_cli.h"
#include "pim_igmpv3.h"
#include "pim_neighbor.h"
+#include "pim_nht.h"
#include "pim_pim.h"
#include "pim_mlag.h"
#include "pim_bfd.h"
pim_ifp->pim_enable = true;
pim_if_addr_add_all(ifp);
+ pim_upstream_nh_if_update(pim_ifp->pim, ifp);
pim_if_membership_refresh(ifp);
pim_if_create_pimreg(pim_ifp->pim);
if (!pim_ifp->gm_enable) {
pim_if_addr_del_all(ifp);
+ pim_upstream_nh_if_update(pim_ifp->pim, ifp);
pim_if_delete(ifp);
}
return 0;
}
+static int pim_upstream_nh_if_update_helper(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct pim_nexthop_cache *pnc = bucket->data;
+ struct pnc_hash_walk_data *pwd = arg;
+ struct pim_instance *pim = pwd->pim;
+ struct interface *ifp = pwd->ifp;
+ struct nexthop *nh_node = NULL;
+ ifindex_t first_ifindex;
+
+ for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
+ first_ifindex = nh_node->ifindex;
+ if (ifp != if_lookup_by_index(first_ifindex, pim->vrf->vrf_id))
+ continue;
+
+ if (pnc->upstream_hash->count) {
+ pim_update_upstream_nh(pim, pnc);
+ break;
+ }
+ }
+
+ return HASHWALK_CONTINUE;
+}
+
+void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp)
+{
+ struct pnc_hash_walk_data pwd;
+
+ pwd.pim = pim;
+ pwd.ifp = ifp;
+
+ hash_walk(pim->rpf_hash, pim_upstream_nh_if_update_helper, &pwd);
+}
+
uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp)
{
uint32_t hash_val;
uint32_t hash_val = 0, mod_val = 0;
uint8_t nh_iter = 0, found = 0;
uint32_t i, num_nbrs = 0;
+ struct pim_interface *pim_ifp;
if (!pnc || !pnc->nexthop_num || !nexthop)
return 0;
nh_iter++;
continue;
}
- if (!ifp->info) {
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp || !pim_ifp->pim_enable) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
+ "%s: pim not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
first_ifindex, &src);
if (nh_iter == mod_val)
uint8_t i = 0;
uint32_t hash_val = 0, mod_val = 0;
uint32_t num_nbrs = 0;
+ struct pim_interface *pim_ifp;
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld",
continue;
}
- if (!ifp->info) {
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp || !pim_ifp->pim_enable) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
+ "%s: pim not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
first_ifindex, &src);
if (i == mod_val)
uint32_t bsr_count;
};
+struct pnc_hash_walk_data {
+ struct pim_instance *pim;
+ struct interface *ifp;
+};
+
int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS);
int pim_find_or_track_nexthop(struct pim_instance *pim, pim_addr addr,
struct pim_upstream *up, struct rp_info *rp,
/* RPF(bsr_addr) == src_ip%src_ifp? */
bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
struct interface *src_ifp, pim_addr src_ip);
-
+void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp);
#endif
ifindex_t first_ifindex = 0;
int found = 0;
int i = 0;
+ struct pim_interface *pim_ifp;
#if PIM_IPV == 4
/*
continue;
}
- if (!ifp->info) {
+ pim_ifp = ifp->info;
+ if (!pim_ifp || !pim_ifp->pim_enable) {
if (PIM_DEBUG_ZEBRA)
zlog_debug(
- "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %pPAs)",
+ "%s: pim not enabled on input interface %s (ifindex=%d, RPF for source %pPAs)",
__func__, ifp->name, first_ifindex,
&addr);
i++;
- } else if (neighbor_needed
- && !pim_if_connected_to_source(ifp, addr)) {
+ } else if (neighbor_needed &&
+ !pim_if_connected_to_source(ifp, addr)) {
nbr = pim_neighbor_find(ifp,
nexthop_tab[i].nexthop_addr);
if (PIM_DEBUG_PIM_TRACE_DETAIL)
# Only allow root (and possibly wheel) to use this because enable access
# is unrestricted.
auth sufficient pam_rootok.so
+account sufficient pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth sufficient pam_wheel.so trust use_uid
install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr
install %{zeb_src}/tools/etc/frr/frr.conf %{buildroot}%{_sysconfdir}/frr/frr.conf.template
install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr
-install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
+install -m644 %{zeb_src}/tools/etc/logrotate.d/frr %{buildroot}%{_sysconfdir}/logrotate.d/frr
install -d -m750 %{buildroot}%{rundir}
%if 0%{?rhel} > 7 || 0%{?fedora} > 29
--- /dev/null
+[
+ {
+ "name": "loc1",
+ "chunks": [
+ "fc00:0:1::/48"
+ ]
+ }
+]
--- /dev/null
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "sharp"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "locators":[
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "statusUp": true,
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "chunks":[
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "locators":[
+ ]
+}
--- /dev/null
+ip link add dummy0 type dummy
+ip link set dummy0 up
--- /dev/null
+hostname r1
+!
+log stdout notifications
+log monitor notifications
+log commands
+log file sharpd.log debugging
+!
--- /dev/null
+hostname r1
+!
+! debug zebra events
+! debug zebra rib detailed
+!
+log stdout notifications
+log monitor notifications
+log commands
+log file zebra.log debugging
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:1::/48 func-bits 16 block-len 32 node-len 16
+ behavior usid
+ !
+ !
+ !
+!
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (c) 2022, University of Rome Tor Vergata
+# Authored by Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_srv6_locator_usid.py:
+Test for SRv6 Locator uSID on zebra
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.sharpd]
+
+
+def open_json_file(filename):
+ try:
+ with open(filename, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(filename)
+
+
+def setup_module(mod):
+ tgen = Topogen({None: "r1"}, mod.__name__)
+ tgen.start_topology()
+ for rname, router in tgen.routers().items():
+ router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(
+ CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_SHARP, os.path.join(
+ CWD, "{}/sharpd.conf".format(rname))
+ )
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def _check_srv6_locator(router, expected_locator_file):
+ logger.info("checking zebra locator status")
+ output = json.loads(
+ router.vtysh_cmd("show segment-routing srv6 locator json")
+ )
+ expected = open_json_file("{}/{}".format(CWD, expected_locator_file))
+ return topotest.json_cmp(output, expected)
+
+
+def _check_sharpd_chunk(router, expected_chunk_file):
+ logger.info("checking sharpd locator chunk status")
+ output = json.loads(
+ router.vtysh_cmd("show sharp segment-routing srv6 json")
+ )
+ expected = open_json_file("{}/{}".format(CWD, expected_chunk_file))
+ return topotest.json_cmp(output, expected)
+
+
+def check_srv6_locator(router, expected_file):
+ func = functools.partial(_check_srv6_locator, router, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=5, wait=3)
+ assert result is None, "Failed"
+
+
+def check_sharpd_chunk(router, expected_file):
+ func = functools.partial(_check_sharpd_chunk, router, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=5, wait=3)
+ assert result is None, "Failed"
+
+
+def test_srv6_usid_locator_configuration():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Verify SRv6 Locators instantiated from config file")
+ check_srv6_locator(router, "expected_locators_1.json")
+ check_sharpd_chunk(router, "expected_chunks_1.json")
+
+
+def test_srv6_usid_locator_get_chunk():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Get chunk for the locator loc1")
+ router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc1")
+ check_srv6_locator(router, "expected_locators_2.json")
+ check_sharpd_chunk(router, "expected_chunks_2.json")
+
+
+def test_srv6_usid_locator_release_chunk():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Release chunk for the locator loc1")
+ router.vtysh_cmd("sharp srv6-manager release-locator-chunk loc1")
+ check_srv6_locator(router, "expected_locators_3.json")
+ check_sharpd_chunk(router, "expected_chunks_3.json")
+
+
+def test_srv6_usid_locator_create_locator():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Create an additional SRv6 Locator")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc2
+ prefix fc00:0:2::/48 func-bits 16 block-len 32 node-len 16
+ """
+ )
+ check_srv6_locator(router, "expected_locators_4.json")
+ check_sharpd_chunk(router, "expected_chunks_4.json")
+
+
+def test_srv6_usid_locator_set_behavior_usid():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info(
+ "Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator"
+ )
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc2
+ behavior usid
+ """
+ )
+ check_srv6_locator(router, "expected_locators_5.json")
+ check_sharpd_chunk(router, "expected_chunks_5.json")
+
+
+def test_srv6_usid_locator_unset_behavior_usid():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Clear Micro-segment (uSID) Locator flag for loc2")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc2
+ no behavior usid
+ """
+ )
+ check_srv6_locator(router, "expected_locators_6.json")
+ check_sharpd_chunk(router, "expected_chunks_6.json")
+
+
+def test_srv6_usid_locator_delete():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info(
+ "Delete locator loc1 and verify that the chunk is released automatically"
+ )
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ no locator loc1
+ """
+ )
+ check_srv6_locator(router, "expected_locators_7.json")
+ check_sharpd_chunk(router, "expected_chunks_7.json")
+
+
+def test_srv6_usid_locator_delete_all():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Delete all the SRv6 configuration")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ no srv6
+ """
+ )
+ check_srv6_locator(router, "expected_locators_8.json")
+ check_sharpd_chunk(router, "expected_chunks_8.json")
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
--- /dev/null
+/var/log/frr/*.log {
+ size 500k
+ sharedscripts
+ missingok
+ compress
+ rotate 14
+ create 0640 frr frr
+
+ postrotate
+ pid=$(lsof -t -a -c /syslog/ /var/log/frr/* 2>/dev/null)
+ if [ -n "$pid" ]
+ then # using syslog
+ kill -HUP $pid
+ fi
+ # in case using file logging; if switching back and forth
+ # between file and syslog, rsyslogd might still have file
+ # open, as well as the daemons, so always signal the daemons.
+ # It's safe, a NOP if (only) syslog is being used.
+ for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd sharpd \
+ pimd pim6d ripd ripngd zebra pathd pbrd staticd bfdd fabricd vrrpd; do
+ if [ -e /var/run/frr/$i.pid ] ; then
+ pids="$pids $(cat /var/run/frr/$i.pid)"
+ fi
+ done
+ [ -n "$pids" ] && kill -USR1 $pids || true
+ endscript
+}
load_old_config "/etc/sysconfig/frr"
fi
-if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then
+if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare -a'; then
log_warning_msg "watchfrr_options contains a bash array value." \
"The configured value is intentionally ignored since it is likely wrong." \
"Please remove or fix the setting."
struct thread *t_read;
struct thread *t_write;
struct thread *t_event;
+ struct thread *t_nhg;
struct thread *t_dequeue;
/* zebra events. */
return CMD_SUCCESS;
thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
- FNE_TOGGLE_NHG, &gfnc->t_event);
+ FNE_TOGGLE_NHG, &gfnc->t_nhg);
return CMD_SUCCESS;
}
return CMD_SUCCESS;
thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
- FNE_TOGGLE_NHG, &gfnc->t_event);
+ FNE_TOGGLE_NHG, &gfnc->t_nhg);
return CMD_SUCCESS;
}
static void fpm_process_event(struct thread *t)
{
struct fpm_nl_ctx *fnc = THREAD_ARG(t);
- int event = THREAD_VAL(t);
+ enum fpm_nl_events event = THREAD_VAL(t);
switch (event) {
case FNE_DISABLE:
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug("%s: LSP walk finished", __func__);
break;
-
- default:
- if (IS_ZEBRA_DEBUG_FPM)
- zlog_debug("%s: unhandled event %d", __func__, event);
- break;
}
}
THREAD_OFF(fnc->t_ribwalk);
THREAD_OFF(fnc->t_rmacreset);
THREAD_OFF(fnc->t_rmacwalk);
+ THREAD_OFF(fnc->t_event);
+ THREAD_OFF(fnc->t_nhg);
thread_cancel_async(fnc->fthread->master, &fnc->t_read, NULL);
thread_cancel_async(fnc->fthread->master, &fnc->t_write, NULL);
thread_cancel_async(fnc->fthread->master, &fnc->t_connect, NULL);
chunk.keep = 0;
chunk.proto = client->proto;
chunk.instance = client->instance;
+ chunk.flags = loc->flags;
zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, vrf_id);
zapi_srv6_locator_chunk_encode(s, &chunk);
if (zif->zif_type == ZEBRA_IF_BOND)
return true;
+ /* relax the checks to allow config to be applied in zebra
+ * before interface is rxed from the kernel
+ */
+ if (zif->ifp->ifindex == IFINDEX_INTERNAL)
+ return true;
+
/* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
return false;
}
return NULL;
}
+void zebra_notify_srv6_locator_add(struct srv6_locator *locator)
+{
+ struct listnode *node;
+ struct zserv *client;
+
+ /*
+ * Notify new locator info to zclients.
+ *
+ * The srv6 locators and their prefixes are managed by zserv(zebra).
+ * And an actual configuration the srv6 sid in the srv6 locator is done
+ * by zclient(bgpd, isisd, etc). The configuration of each locator
+ * allocation and specify it by zserv and zclient should be
+ * asynchronous. For that, zclient should be received the event via
+ * ZAPI when a srv6 locator is added on zebra.
+ * Basically, in SRv6, adding/removing SRv6 locators is performed less
+ * frequently than adding rib entries, so a broad to all zclients will
+ * not degrade the overall performance of FRRouting.
+ */
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+ zsend_zebra_srv6_locator_add(client, locator);
+}
+
+void zebra_notify_srv6_locator_delete(struct srv6_locator *locator)
+{
+ struct listnode *n;
+ struct srv6_locator_chunk *c;
+ struct zserv *client;
+
+ /*
+ * Notify deleted locator info to zclients if needed.
+ *
+ * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
+ * uses it for its own purpose. For example, in the case of BGP L3VPN,
+ * the SID assigned to vpn unicast rib will be given.
+ * And when the locator is deleted by zserv(zebra), those SIDs need to
+ * be withdrawn. The zclient must initiate the withdrawal of the SIDs
+ * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
+ * owner of each chunk.
+ */
+ for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
+ if (c->proto == ZEBRA_ROUTE_SYSTEM)
+ continue;
+ client = zserv_find_client(c->proto, c->instance);
+ if (!client) {
+ zlog_warn("Not found zclient(proto=%u, instance=%u).",
+ c->proto, c->instance);
+ continue;
+ }
+ zsend_zebra_srv6_locator_delete(client, locator);
+ }
+}
+
struct zebra_srv6 *zebra_srv6_get_default(void)
{
static struct zebra_srv6 srv6;
extern void zebra_srv6_locator_delete(struct srv6_locator *locator);
extern struct srv6_locator *zebra_srv6_locator_lookup(const char *name);
+void zebra_notify_srv6_locator_add(struct srv6_locator *locator);
+void zebra_notify_srv6_locator_delete(struct srv6_locator *locator);
+
extern void zebra_srv6_init(void);
extern struct zebra_srv6 *zebra_srv6_get_default(void);
extern bool zebra_srv6_is_enable(void);
vty_out(vty, "Argument-Bit-Len: %u\n",
locator->argument_bits_length);
+ if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ vty_out(vty, "Behavior: uSID\n");
+
vty_out(vty, "Chunks:\n");
for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node,
chunk)) {
return CMD_SUCCESS;
}
+DEFPY (locator_behavior,
+ locator_behavior_cmd,
+ "[no] behavior usid",
+ NO_STR
+ "Configure SRv6 behavior\n"
+ "Specify SRv6 behavior uSID\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_locator, locator);
+
+ if (no && !CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ /* SRv6 locator uSID flag already unset, nothing to do */
+ return CMD_SUCCESS;
+
+ if (!no && CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ /* SRv6 locator uSID flag already set, nothing to do */
+ return CMD_SUCCESS;
+
+ /* Remove old locator from zclients */
+ zebra_notify_srv6_locator_delete(locator);
+
+ /* Set/Unset the SRV6_LOCATOR_USID */
+ if (no)
+ UNSET_FLAG(locator->flags, SRV6_LOCATOR_USID);
+ else
+ SET_FLAG(locator->flags, SRV6_LOCATOR_USID);
+
+ /* Notify the new locator to zclients */
+ zebra_notify_srv6_locator_add(locator);
+
+ return CMD_SUCCESS;
+}
+
static int zebra_sr_config(struct vty *vty)
{
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
if (locator->argument_bits_length)
vty_out(vty, " arg-len %u",
locator->argument_bits_length);
+ if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ vty_out(vty, " behavior usid");
vty_out(vty, "\n");
vty_out(vty, " exit\n");
vty_out(vty, " !\n");
/* Command for configuration */
install_element(SRV6_LOC_NODE, &locator_prefix_cmd);
+ install_element(SRV6_LOC_NODE, &locator_behavior_cmd);
/* Command for operation */
install_element(VIEW_NODE, &show_srv6_locator_cmd);