summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c337
-rw-r--r--bgpd/bgp_attr.h32
-rw-r--r--bgpd/bgp_clist.c136
-rw-r--r--bgpd/bgp_clist.h27
-rw-r--r--bgpd/bgp_fsm.c71
-rw-r--r--bgpd/bgp_memory.c3
-rw-r--r--bgpd/bgp_memory.h3
-rw-r--r--bgpd/bgp_open.c128
-rw-r--r--bgpd/bgp_route.c52
-rw-r--r--bgpd/bgp_route.h7
-rw-r--r--bgpd/bgp_vty.c738
-rw-r--r--bgpd/bgp_zebra.c37
-rw-r--r--bgpd/bgpd.c15
-rw-r--r--bgpd/rfapi/rfapi_vty.c8
-rw-r--r--doc/developer/zebra.rst198
-rw-r--r--include/linux/seg6.h55
-rw-r--r--include/linux/seg6_genl.h33
-rw-r--r--include/linux/seg6_hmac.h23
-rw-r--r--include/linux/seg6_iptunnel.h41
-rw-r--r--include/linux/seg6_local.h80
-rw-r--r--include/subdir.am5
-rw-r--r--lib/agentx.c24
-rw-r--r--lib/log.c2
-rw-r--r--lib/netns_linux.c2
-rw-r--r--lib/srv6.c116
-rw-r--r--lib/srv6.h133
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/zclient.c68
-rw-r--r--lib/zclient.h38
-rw-r--r--scripts/coccinelle/shorthand_operator.cocci12
-rw-r--r--scripts/coccinelle/void_no_return.cocci9
-rw-r--r--zebra/kernel_socket.c2
-rw-r--r--zebra/main.c4
-rw-r--r--zebra/rt_netlink.c20
-rw-r--r--zebra/subdir.am2
-rw-r--r--zebra/zapi_msg.c7
-rw-r--r--zebra/zebra_gr.c684
-rw-r--r--zebra/zebra_nhg.c20
-rw-r--r--zebra/zebra_nhg.h10
-rw-r--r--zebra/zebra_router.h3
-rw-r--r--zebra/zebra_vty.c72
-rw-r--r--zebra/zserv.c134
-rw-r--r--zebra/zserv.h61
43 files changed, 2738 insertions, 716 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 16de59b72c..47da8fcb88 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -32,6 +32,7 @@
#include "table.h"
#include "filter.h"
#include "command.h"
+#include "srv6.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@@ -201,6 +202,8 @@ static struct hash *encap_hash = NULL;
#if ENABLE_BGP_VNC
static struct hash *vnc_hash = NULL;
#endif
+static struct hash *srv6_l3vpn_hash;
+static struct hash *srv6_vpn_hash;
struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
{
@@ -434,6 +437,158 @@ static void transit_unintern(struct transit **transit)
}
}
+static void *srv6_l3vpn_hash_alloc(void *p)
+{
+ return p;
+}
+
+static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn *l3vpn)
+{
+ XFREE(MTYPE_BGP_SRV6_L3VPN, l3vpn);
+}
+
+static struct bgp_attr_srv6_l3vpn *
+srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn *l3vpn)
+{
+ struct bgp_attr_srv6_l3vpn *find;
+
+ find = hash_get(srv6_l3vpn_hash, l3vpn, srv6_l3vpn_hash_alloc);
+ if (find != l3vpn)
+ srv6_l3vpn_free(l3vpn);
+ find->refcnt++;
+ return find;
+}
+
+static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn **l3vpnp)
+{
+ struct bgp_attr_srv6_l3vpn *l3vpn = *l3vpnp;
+
+ if (l3vpn->refcnt)
+ l3vpn->refcnt--;
+
+ if (l3vpn->refcnt == 0) {
+ hash_release(srv6_l3vpn_hash, l3vpn);
+ srv6_l3vpn_free(l3vpn);
+ *l3vpnp = NULL;
+ }
+}
+
+static void *srv6_vpn_hash_alloc(void *p)
+{
+ return p;
+}
+
+static void srv6_vpn_free(struct bgp_attr_srv6_vpn *vpn)
+{
+ XFREE(MTYPE_BGP_SRV6_VPN, vpn);
+}
+
+static struct bgp_attr_srv6_vpn *srv6_vpn_intern(struct bgp_attr_srv6_vpn *vpn)
+{
+ struct bgp_attr_srv6_vpn *find;
+
+ find = hash_get(srv6_vpn_hash, vpn, srv6_vpn_hash_alloc);
+ if (find != vpn)
+ srv6_vpn_free(vpn);
+ find->refcnt++;
+ return find;
+}
+
+static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn **vpnp)
+{
+ struct bgp_attr_srv6_vpn *vpn = *vpnp;
+
+ if (vpn->refcnt)
+ vpn->refcnt--;
+
+ if (vpn->refcnt == 0) {
+ hash_release(srv6_vpn_hash, vpn);
+ srv6_vpn_free(vpn);
+ *vpnp = NULL;
+ }
+}
+
+static uint32_t srv6_l3vpn_hash_key_make(const void *p)
+{
+ const struct bgp_attr_srv6_l3vpn *l3vpn = p;
+ uint32_t key = 0;
+
+ key = jhash(&l3vpn->sid, 16, key);
+ key = jhash_1word(l3vpn->sid_flags, key);
+ key = jhash_1word(l3vpn->endpoint_behavior, key);
+ return key;
+}
+
+static bool srv6_l3vpn_hash_cmp(const void *p1, const void *p2)
+{
+ const struct bgp_attr_srv6_l3vpn *l3vpn1 = p1;
+ const struct bgp_attr_srv6_l3vpn *l3vpn2 = p2;
+
+ return sid_same(&l3vpn1->sid, &l3vpn2->sid)
+ && l3vpn1->sid_flags == l3vpn2->sid_flags
+ && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior;
+}
+
+static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn *h1,
+ const struct bgp_attr_srv6_l3vpn *h2)
+{
+ if (h1 == h2)
+ return true;
+ else if (h1 == NULL || h2 == NULL)
+ return false;
+ else
+ return srv6_l3vpn_hash_cmp((const void *)h1, (const void *)h2);
+}
+
+static unsigned int srv6_vpn_hash_key_make(const void *p)
+{
+ const struct bgp_attr_srv6_vpn *vpn = p;
+ uint32_t key = 0;
+
+ key = jhash(&vpn->sid, 16, key);
+ key = jhash_1word(vpn->sid_flags, key);
+ return key;
+}
+
+static bool srv6_vpn_hash_cmp(const void *p1, const void *p2)
+{
+ const struct bgp_attr_srv6_vpn *vpn1 = p1;
+ const struct bgp_attr_srv6_vpn *vpn2 = p2;
+
+ return sid_same(&vpn1->sid, &vpn2->sid)
+ && vpn1->sid_flags == vpn2->sid_flags;
+}
+
+static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn *h1,
+ const struct bgp_attr_srv6_vpn *h2)
+{
+ if (h1 == h2)
+ return true;
+ else if (h1 == NULL || h2 == NULL)
+ return false;
+ else
+ return srv6_vpn_hash_cmp((const void *)h1, (const void *)h2);
+}
+
+static void srv6_init(void)
+{
+ srv6_l3vpn_hash =
+ hash_create(srv6_l3vpn_hash_key_make, srv6_l3vpn_hash_cmp,
+ "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
+ srv6_vpn_hash = hash_create(srv6_vpn_hash_key_make, srv6_vpn_hash_cmp,
+ "BGP Prefix-SID SRv6-VPN-Service-TLV");
+}
+
+static void srv6_finish(void)
+{
+ hash_clean(srv6_l3vpn_hash, (void (*)(void *))srv6_l3vpn_free);
+ hash_free(srv6_l3vpn_hash);
+ srv6_l3vpn_hash = NULL;
+ hash_clean(srv6_vpn_hash, (void (*)(void *))srv6_vpn_free);
+ hash_free(srv6_vpn_hash);
+ srv6_vpn_hash = NULL;
+}
+
static unsigned int transit_hash_key_make(const void *p)
{
const struct transit *transit = p;
@@ -557,7 +712,9 @@ bool attrhash_cmp(const void *p1, const void *p2)
&& overlay_index_same(attr1, attr2)
&& attr1->nh_ifindex == attr2->nh_ifindex
&& attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
- && attr1->distance == attr2->distance)
+ && attr1->distance == attr2->distance
+ && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
+ && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn))
return true;
}
@@ -588,12 +745,22 @@ static void attrhash_finish(void)
static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty)
{
struct attr *attr = bucket->data;
+ char sid_str[BUFSIZ];
vty_out(vty, "attr[%ld] nexthop %s\n", attr->refcnt,
inet_ntoa(attr->nexthop));
- vty_out(vty, "\tflags: %" PRIu64 " med: %u local_pref: %u origin: %u weight: %u label: %u\n",
+
+ sid_str[0] = '\0';
+ if (attr->srv6_l3vpn)
+ inet_ntop(AF_INET6, &attr->srv6_l3vpn->sid, sid_str, BUFSIZ);
+ else if (attr->srv6_vpn)
+ inet_ntop(AF_INET6, &attr->srv6_vpn->sid, sid_str, BUFSIZ);
+
+ vty_out(vty,
+ "\tflags: %" PRIu64
+ " med: %u local_pref: %u origin: %u weight: %u label: %u sid: %s\n",
attr->flag, attr->med, attr->local_pref, attr->origin,
- attr->weight, attr->label);
+ attr->weight, attr->label, sid_str);
}
void attr_show_all(struct vty *vty)
@@ -618,6 +785,11 @@ static void *bgp_attr_hash_alloc(void *p)
val->vnc_subtlvs = NULL;
}
#endif
+ if (val->srv6_l3vpn)
+ val->srv6_l3vpn = NULL;
+ if (val->srv6_vpn)
+ val->srv6_vpn = NULL;
+
attr->refcnt = 0;
return attr;
}
@@ -672,6 +844,18 @@ struct attr *bgp_attr_intern(struct attr *attr)
else
attr->encap_subtlvs->refcnt++;
}
+ if (attr->srv6_l3vpn) {
+ if (!attr->srv6_l3vpn->refcnt)
+ attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
+ else
+ attr->srv6_l3vpn->refcnt++;
+ }
+ if (attr->srv6_vpn) {
+ if (!attr->srv6_vpn->refcnt)
+ attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn);
+ else
+ attr->srv6_vpn->refcnt++;
+ }
#if ENABLE_BGP_VNC
if (attr->vnc_subtlvs) {
if (!attr->vnc_subtlvs->refcnt)
@@ -862,6 +1046,12 @@ void bgp_attr_unintern_sub(struct attr *attr)
if (attr->vnc_subtlvs)
encap_unintern(&attr->vnc_subtlvs, VNC_SUBTLV_TYPE);
#endif
+
+ if (attr->srv6_l3vpn)
+ srv6_l3vpn_unintern(&attr->srv6_l3vpn);
+
+ if (attr->srv6_vpn)
+ srv6_vpn_unintern(&attr->srv6_vpn);
}
/*
@@ -2147,6 +2337,9 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
uint32_t srgb_base;
uint32_t srgb_range;
int srgb_count;
+ uint8_t sid_type, sid_flags;
+ uint16_t endpoint_behavior;
+ char buf[BUFSIZ];
if (type == BGP_PREFIX_SID_LABEL_INDEX) {
if (STREAM_READABLE(peer->curr) < length
@@ -2268,13 +2461,81 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
}
}
- /*
- * Placeholder code for Unsupported TLV
- * - SRv6 L3 Service TLV (type5)
- * - SRv6 L2 Service TLV (type6)
- */
- else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE
- || type == BGP_PREFIX_SID_SRV6_L2_SERVICE) {
+ /* Placeholder code for the VPN-SID Service type */
+ else if (type == BGP_PREFIX_SID_VPN_SID) {
+ if (STREAM_READABLE(peer->curr) < length
+ || length != BGP_PREFIX_SID_VPN_SID_LENGTH) {
+ flog_err(EC_BGP_ATTR_LEN,
+ "Prefix SID VPN SID length is %" PRIu16
+ " instead of %u",
+ length, BGP_PREFIX_SID_VPN_SID_LENGTH);
+ return bgp_attr_malformed(args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ /* Parse VPN-SID Sub-TLV */
+ stream_getc(peer->curr); /* reserved */
+ sid_type = stream_getc(peer->curr); /* sid_type */
+ sid_flags = stream_getc(peer->curr); /* sid_flags */
+ stream_get(&ipv6_sid, peer->curr,
+ sizeof(ipv6_sid)); /* sid_value */
+
+ /* Log VPN-SID Sub-TLV */
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
+ inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+ zlog_debug(
+ "%s: vpn-sid: sid %s, sid-type 0x%02x sid-flags 0x%02x",
+ __func__, buf, sid_type, sid_flags);
+ }
+
+ /* Configure from Info */
+ attr->srv6_vpn = XMALLOC(MTYPE_BGP_SRV6_VPN,
+ sizeof(struct bgp_attr_srv6_vpn));
+ attr->srv6_vpn->refcnt = 0;
+ attr->srv6_vpn->sid_flags = sid_flags;
+ sid_copy(&attr->srv6_vpn->sid, &ipv6_sid);
+ }
+
+ /* Placeholder code for the SRv6 L3 Service type */
+ else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) {
+ if (STREAM_READABLE(peer->curr) < length
+ || length != BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH) {
+ flog_err(EC_BGP_ATTR_LEN,
+ "Prefix SID SRv6 L3-Service length is %" PRIu16
+ " instead of %u",
+ length, BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH);
+ return bgp_attr_malformed(args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ /* Parse L3-SERVICE Sub-TLV */
+ stream_getc(peer->curr); /* reserved */
+ stream_get(&ipv6_sid, peer->curr,
+ sizeof(ipv6_sid)); /* sid_value */
+ sid_flags = stream_getc(peer->curr); /* sid_flags */
+ endpoint_behavior = stream_getw(peer->curr); /* endpoint */
+ stream_getc(peer->curr); /* reserved */
+
+ /* Log L3-SERVICE Sub-TLV */
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
+ inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+ zlog_debug(
+ "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
+ __func__, buf, sid_flags, endpoint_behavior);
+ }
+
+ /* Configure from Info */
+ attr->srv6_l3vpn = XMALLOC(MTYPE_BGP_SRV6_L3VPN,
+ sizeof(struct bgp_attr_srv6_l3vpn));
+ attr->srv6_l3vpn->sid_flags = sid_flags;
+ attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
+ sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
+ }
+
+ /* Placeholder code for Unsupported TLV */
+ else {
if (STREAM_READABLE(peer->curr) < length) {
flog_err(
@@ -2966,10 +3227,11 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
/* Nexthop AFI */
if (afi == AFI_IP
- && (safi == SAFI_UNICAST ||
- safi == SAFI_LABELED_UNICAST ||
- safi == SAFI_MULTICAST))
+ && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST
+ || safi == SAFI_MPLS_VPN || safi == SAFI_MULTICAST))
nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP;
+ else if (safi == SAFI_FLOWSPEC)
+ nh_afi = afi;
else
nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
@@ -2996,7 +3258,12 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
stream_put(s, &attr->mp_nexthop_global_in, 4);
break;
case SAFI_FLOWSPEC:
- stream_putc(s, 0); /* no nexthop for flowspec */
+ if (attr->mp_nexthop_len == 0)
+ stream_putc(s, 0); /* no nexthop for flowspec */
+ else {
+ stream_putc(s, attr->mp_nexthop_len);
+ stream_put_ipv4(s, attr->nexthop.s_addr);
+ }
default:
break;
}
@@ -3090,13 +3357,9 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
stream_put_labeled_prefix(s, p, label, addpath_encode,
addpath_tx_id);
} else if (safi == SAFI_FLOWSPEC) {
- if (PSIZE (p->prefixlen)+2 < FLOWSPEC_NLRI_SIZELIMIT)
- stream_putc(s, PSIZE (p->prefixlen)+2);
- else
- stream_putw(s, (PSIZE (p->prefixlen)+2)|(0xf<<12));
- stream_putc(s, 2);/* Filter type */
- stream_putc(s, p->prefixlen);/* Prefix length */
- stream_put(s, &p->u.prefix, PSIZE (p->prefixlen));
+ stream_putc(s, p->u.prefix_flowspec.prefixlen);
+ stream_put(s, (const void *)p->u.prefix_flowspec.ptr,
+ p->u.prefix_flowspec.prefixlen);
} else
stream_put_prefix_addpath(s, p, addpath_encode, addpath_tx_id);
}
@@ -3610,6 +3873,36 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
}
+ /* SRv6 Service Information Attribute. */
+ if (afi == AFI_IP && safi == SAFI_MPLS_VPN) {
+ if (attr->srv6_l3vpn) {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_PREFIX_SID);
+ stream_putc(s, 24); /* tlv len */
+ stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE);
+ stream_putw(s, 21); /* sub-tlv len */
+ stream_putc(s, 0); /* reserved */
+ stream_put(s, &attr->srv6_l3vpn->sid,
+ sizeof(attr->srv6_l3vpn->sid)); /* sid */
+ stream_putc(s, 0); /* sid_flags */
+ stream_putw(s, 0xffff); /* endpoint */
+ stream_putc(s, 0); /* reserved */
+ } else if (attr->srv6_vpn) {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_PREFIX_SID);
+ stream_putc(s, 22); /* tlv len */
+ stream_putc(s, BGP_PREFIX_SID_VPN_SID);
+ stream_putw(s, 0x13); /* tlv len */
+ stream_putc(s, 0x00); /* reserved */
+ stream_putc(s, 0x01); /* sid_type */
+ stream_putc(s, 0x00); /* sif_flags */
+ stream_put(s, &attr->srv6_vpn->sid,
+ sizeof(attr->srv6_vpn->sid)); /* sid */
+ }
+ }
+
if (send_as4_path) {
/* If the peer is NOT As4 capable, AND */
/* there are ASnums > 65535 in path THEN
@@ -3738,6 +4031,7 @@ void bgp_attr_init(void)
cluster_init();
transit_init();
encap_init();
+ srv6_init();
}
void bgp_attr_finish(void)
@@ -3750,6 +4044,7 @@ void bgp_attr_finish(void)
cluster_finish();
transit_finish();
encap_finish();
+ srv6_finish();
}
/* Make attribute packet. */
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 8bd527c0ff..2e91f56df5 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -62,12 +62,15 @@
#define BGP_PREFIX_SID_LABEL_INDEX 1
#define BGP_PREFIX_SID_IPV6 2
#define BGP_PREFIX_SID_ORIGINATOR_SRGB 3
+#define BGP_PREFIX_SID_VPN_SID 4
#define BGP_PREFIX_SID_SRV6_L3_SERVICE 5
#define BGP_PREFIX_SID_SRV6_L2_SERVICE 6
#define BGP_PREFIX_SID_LABEL_INDEX_LENGTH 7
#define BGP_PREFIX_SID_IPV6_LENGTH 19
#define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6
+#define BGP_PREFIX_SID_VPN_SID_LENGTH 19
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH 21
#define BGP_ATTR_NH_AFI(afi, attr) \
((afi != AFI_L2VPN) ? afi : \
@@ -111,6 +114,29 @@ enum pta_type {
PMSI_TNLTYPE_MAX = PMSI_TNLTYPE_MLDP_MP2MP
};
+/*
+ * Prefix-SID type-4
+ * SRv6-VPN-SID-TLV
+ * draft-dawra-idr-srv6-vpn-04
+ */
+struct bgp_attr_srv6_vpn {
+ unsigned long refcnt;
+ uint8_t sid_flags;
+ struct in6_addr sid;
+};
+
+/*
+ * Prefix-SID type-5
+ * SRv6-L3VPN-Service-TLV
+ * draft-dawra-idr-srv6-vpn-05
+ */
+struct bgp_attr_srv6_l3vpn {
+ unsigned long refcnt;
+ uint8_t sid_flags;
+ uint16_t endpoint_behavior;
+ struct in6_addr sid;
+};
+
/* BGP core attribute structure. */
struct attr {
/* AS Path structure */
@@ -198,6 +224,12 @@ struct attr {
/* MPLS label */
mpls_label_t label;
+ /* SRv6 VPN SID */
+ struct bgp_attr_srv6_vpn *srv6_vpn;
+
+ /* SRv6 L3VPN SID */
+ struct bgp_attr_srv6_l3vpn *srv6_l3vpn;
+
uint16_t encap_tunneltype; /* grr */
struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 29e668d179..7ca48a5bea 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -37,6 +37,37 @@
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h"
+/* Calculate new sequential number. */
+static int64_t bgp_clist_new_seq_get(struct community_list *list)
+{
+ int64_t maxseq;
+ int64_t newseq;
+ struct community_entry *entry;
+
+ maxseq = newseq = 0;
+
+ for (entry = list->head; entry; entry = entry->next) {
+ if (maxseq < entry->seq)
+ maxseq = entry->seq;
+ }
+
+ newseq = ((maxseq / 5) * 5) + 5;
+
+ return (newseq > UINT_MAX) ? UINT_MAX : newseq;
+}
+
+/* Return community-list entry which has same seq number. */
+static struct community_entry *bgp_clist_seq_check(struct community_list *list,
+ int64_t seq)
+{
+ struct community_entry *entry;
+
+ for (entry = list->head; entry; entry = entry->next)
+ if (entry->seq == seq)
+ return entry;
+ return NULL;
+}
+
static uint32_t bgp_clist_hash_key_community_list(const void *data)
{
struct community_list *cl = (struct community_list *) data;
@@ -285,20 +316,6 @@ static int community_list_empty_p(struct community_list *list)
return (list->head == NULL && list->tail == NULL) ? 1 : 0;
}
-/* Add community-list entry to the list. */
-static void community_list_entry_add(struct community_list *list,
- struct community_entry *entry)
-{
- entry->next = NULL;
- entry->prev = list->tail;
-
- if (list->tail)
- list->tail->next = entry;
- else
- list->head = entry;
- list->tail = entry;
-}
-
/* Delete community-list entry from the list. */
static void community_list_entry_delete(struct community_list_master *cm,
struct community_list *list,
@@ -320,6 +337,57 @@ static void community_list_entry_delete(struct community_list_master *cm,
community_list_delete(cm, list);
}
+/* Add community-list entry to the list. */
+static void community_list_entry_add(struct community_list *list,
+ struct community_entry *entry,
+ struct community_list_handler *ch,
+ int master)
+{
+ struct community_list_master *cm = NULL;
+ struct community_entry *replace;
+ struct community_entry *point;
+
+ cm = community_list_master_lookup(ch, master);
+
+ /* Automatic assignment of seq no. */
+ if (entry->seq == COMMUNITY_SEQ_NUMBER_AUTO)
+ entry->seq = bgp_clist_new_seq_get(list);
+
+ if (list->tail && entry->seq > list->tail->seq)
+ point = NULL;
+ else {
+ replace = bgp_clist_seq_check(list, entry->seq);
+ if (replace)
+ community_list_entry_delete(cm, list, entry);
+
+ /* Check insert point. */
+ for (point = list->head; point; point = point->next)
+ if (point->seq >= entry->seq)
+ break;
+ }
+
+ /* In case of this is the first element of the list. */
+ entry->next = point;
+
+ if (point) {
+ if (point->prev)
+ point->prev->next = entry;
+ else
+ list->head = entry;
+
+ entry->prev = point->prev;
+ point->prev = entry;
+ } else {
+ if (list->tail)
+ list->tail->next = entry;
+ else
+ list->head = entry;
+
+ entry->prev = list->tail;
+ list->tail = entry;
+ }
+}
+
/* Lookup community-list entry from the list. */
static struct community_entry *
community_list_entry_lookup(struct community_list *list, const void *arg,
@@ -878,12 +946,16 @@ static int community_list_dup_check(struct community_list *list,
/* Set community-list. */
int community_list_set(struct community_list_handler *ch, const char *name,
- const char *str, int direct, int style)
+ const char *str, const char *seq, int direct, int style)
{
struct community_entry *entry = NULL;
struct community_list *list;
struct community *com = NULL;
regex_t *regex = NULL;
+ int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
+
+ if (seq)
+ seqnum = (int64_t)atol(seq);
/* Get community list. */
list = community_list_get(ch, name, COMMUNITY_LIST_MASTER);
@@ -919,6 +991,7 @@ int community_list_set(struct community_list_handler *ch, const char *name,
entry->any = (str ? 0 : 1);
entry->u.com = com;
entry->reg = regex;
+ entry->seq = seqnum;
entry->config =
(regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
@@ -926,7 +999,8 @@ int community_list_set(struct community_list_handler *ch, const char *name,
if (community_list_dup_check(list, entry))
community_entry_free(entry);
else {
- community_list_entry_add(list, entry);
+ community_list_entry_add(list, entry, ch,
+ COMMUNITY_LIST_MASTER);
route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED);
}
@@ -935,7 +1009,8 @@ int community_list_set(struct community_list_handler *ch, const char *name,
/* Unset community-list */
int community_list_unset(struct community_list_handler *ch, const char *name,
- const char *str, int direct, int style)
+ const char *str, const char *seq, int direct,
+ int style)
{
struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
@@ -1057,12 +1132,16 @@ static int lcommunity_list_valid(const char *community)
/* Set lcommunity-list. */
int lcommunity_list_set(struct community_list_handler *ch, const char *name,
- const char *str, int direct, int style)
+ const char *str, const char *seq, int direct, int style)
{
struct community_entry *entry = NULL;
struct community_list *list;
struct lcommunity *lcom = NULL;
regex_t *regex = NULL;
+ int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
+
+ if (seq)
+ seqnum = (int64_t)atol(seq);
/* Get community list. */
list = community_list_get(ch, name, LARGE_COMMUNITY_LIST_MASTER);
@@ -1101,6 +1180,7 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
entry->any = (str ? 0 : 1);
entry->u.lcom = lcom;
entry->reg = regex;
+ entry->seq = seqnum;
entry->config =
(regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
@@ -1108,7 +1188,8 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
if (community_list_dup_check(list, entry))
community_entry_free(entry);
else {
- community_list_entry_add(list, entry);
+ community_list_entry_add(list, entry, ch,
+ LARGE_COMMUNITY_LIST_MASTER);
route_map_notify_dependencies(name, RMAP_EVENT_LLIST_ADDED);
}
@@ -1118,7 +1199,8 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
/* Unset community-list. When str is NULL, delete all of
community-list entry belongs to the specified name. */
int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
- const char *str, int direct, int style)
+ const char *str, const char *seq, int direct,
+ int style)
{
struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
@@ -1168,12 +1250,17 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
/* Set extcommunity-list. */
int extcommunity_list_set(struct community_list_handler *ch, const char *name,
- const char *str, int direct, int style)
+ const char *str, const char *seq, int direct,
+ int style)
{
struct community_entry *entry = NULL;
struct community_list *list;
struct ecommunity *ecom = NULL;
regex_t *regex = NULL;
+ int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
+
+ if (seq)
+ seqnum = (int64_t)atol(seq);
if (str == NULL)
return COMMUNITY_LIST_ERR_MALFORMED_VAL;
@@ -1220,12 +1307,14 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
entry->u.ecom = ecom;
entry->reg = regex;
+ entry->seq = seqnum;
/* Do not put duplicated community entry. */
if (community_list_dup_check(list, entry))
community_entry_free(entry);
else {
- community_list_entry_add(list, entry);
+ community_list_entry_add(list, entry, ch,
+ EXTCOMMUNITY_LIST_MASTER);
route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED);
}
@@ -1238,7 +1327,8 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
* specified name.
*/
int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
- const char *str, int direct, int style)
+ const char *str, const char *seq, int direct,
+ int style)
{
struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
index 87b29ac3be..c5718aecac 100644
--- a/bgpd/bgp_clist.h
+++ b/bgpd/bgp_clist.h
@@ -36,6 +36,8 @@
#define COMMUNITY_LIST_STRING 0
#define COMMUNITY_LIST_NUMBER 1
+#define COMMUNITY_SEQ_NUMBER_AUTO -1
+
/* Community-list entry types. */
#define COMMUNITY_LIST_STANDARD 0 /* Standard community-list. */
#define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */
@@ -81,6 +83,9 @@ struct community_entry {
/* Any match. */
uint8_t any;
+ /* Sequence number. */
+ int64_t seq;
+
/* Community structure. */
union {
struct community *com;
@@ -135,23 +140,23 @@ extern struct community_list_handler *community_list_init(void);
extern void community_list_terminate(struct community_list_handler *);
extern int community_list_set(struct community_list_handler *ch,
- const char *name, const char *str, int direct,
- int style);
+ const char *name, const char *str,
+ const char *seq, int direct, int style);
extern int community_list_unset(struct community_list_handler *ch,
- const char *name, const char *str, int direct,
- int style);
+ const char *name, const char *str,
+ const char *seq, int direct, int style);
extern int extcommunity_list_set(struct community_list_handler *ch,
- const char *name, const char *str, int direct,
- int style);
+ const char *name, const char *str,
+ const char *seq, int direct, int style);
extern int extcommunity_list_unset(struct community_list_handler *ch,
const char *name, const char *str,
- int direct, int style);
+ const char *seq, int direct, int style);
extern int lcommunity_list_set(struct community_list_handler *ch,
- const char *name, const char *str, int direct,
- int style);
+ const char *name, const char *str,
+ const char *seq, int direct, int style);
extern int lcommunity_list_unset(struct community_list_handler *ch,
- const char *name, const char *str, int direct,
- int style);
+ const char *name, const char *str,
+ const char *seq, int direct, int style);
extern struct community_list_master *
community_list_master_lookup(struct community_list_handler *, int);
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index c5b46487a5..da8e6a907b 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -646,8 +646,9 @@ static int bgp_graceful_deferral_timer_expire(struct thread *thread)
bgp = info->bgp;
if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("afi %d, safi %d : graceful restart deferral timer expired",
- afi, safi);
+ zlog_debug(
+ "afi %d, safi %d : graceful restart deferral timer expired",
+ afi, safi);
bgp->gr_info[afi][safi].t_select_deferral = NULL;
@@ -1198,28 +1199,28 @@ int bgp_stop(struct peer *peer)
*/
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) {
FOREACH_AFI_SAFI (afi, safi) {
- if (peer->afc_nego[afi][safi] &&
- !CHECK_FLAG(peer->af_sflags[afi][safi],
- PEER_STATUS_EOR_RECEIVED)) {
- gr_info = &bgp->gr_info[afi][safi];
-
- if (gr_info && (gr_info->eor_required))
- gr_info->eor_required--;
-
- if (gr_info && BGP_DEBUG(update,
- UPDATE_OUT))
- zlog_debug(
- "peer %s, EOR_required %d",
- peer->host,
- gr_info->eor_required);
-
- /* There is no pending EOR message */
- if (gr_info && gr_info->eor_required
- == 0) {
- BGP_TIMER_OFF(
+ if (!peer->afc_nego[afi][safi]
+ || CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED))
+ continue;
+
+ gr_info = &bgp->gr_info[afi][safi];
+ if (!gr_info)
+ continue;
+
+ if (gr_info->eor_required)
+ gr_info->eor_required--;
+
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("peer %s, EOR_required %d",
+ peer->host,
+ gr_info->eor_required);
+
+ /* There is no pending EOR message */
+ if (gr_info->eor_required == 0) {
+ BGP_TIMER_OFF(
gr_info->t_select_deferral);
- gr_info->eor_received = 0;
- }
+ gr_info->eor_received = 0;
}
}
}
@@ -1677,27 +1678,14 @@ static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi,
*/
if (gr_info->eor_required == 0) {
thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
- if (thread_info == NULL) {
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("%s : Error allocating thread info",
- __func__);
- return -1;
- }
thread_info->afi = afi;
thread_info->safi = safi;
thread_info->bgp = bgp;
- thread_add_timer(bm->master,
- bgp_graceful_deferral_timer_expire,
- thread_info, bgp->select_defer_time,
- &gr_info->t_select_deferral);
- if (gr_info->t_select_deferral == NULL) {
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("Error starting deferral timer for %s",
- get_afi_safi_str(afi, safi, false));
- return -1;
- }
+ thread_add_timer(bm->master, bgp_graceful_deferral_timer_expire,
+ thread_info, bgp->select_defer_time,
+ &gr_info->t_select_deferral);
}
gr_info->eor_required++;
/* Send message to RIB indicating route update pending */
@@ -2308,11 +2296,6 @@ int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
"%s [BGP_GR] GLOBAL_INVALID",
__func__);
return BGP_ERR_GR_OPERATION_FAILED;
- default:
- zlog_debug(
- "%s [BGP_GR] Global unknown ERROR",
- __func__);
- return BGP_ERR_GR_OPERATION_FAILED;
}
}
}
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index 3e4dfb11ad..41c4108c0a 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -128,3 +128,6 @@ DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str")
DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled")
DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name")
DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index")
+
+DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie")
+DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service")
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index 03715f5621..5428022551 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -126,4 +126,7 @@ DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED)
DECLARE_MTYPE(BGP_FLOWSPEC_NAME)
DECLARE_MTYPE(BGP_FLOWSPEC_INDEX)
+DECLARE_MTYPE(BGP_SRV6_L3VPN)
+DECLARE_MTYPE(BGP_SRV6_VPN)
+
#endif /* _QUAGGA_BGP_MEMORY_H */
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 2d3dc13557..54d785e26b 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -658,7 +658,7 @@ static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr)
nh_afi = afi_iana2int(pkt_nh_afi);
if (afi != AFI_IP || nh_afi != AFI_IP6
- || !(safi == SAFI_UNICAST
+ || !(safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN
|| safi == SAFI_LABELED_UNICAST)) {
flog_warn(
EC_BGP_CAPABILITY_INVALID_DATA,
@@ -1310,82 +1310,72 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
unsigned long capp = 0;
unsigned long rcapp = 0;
- if ((CHECK_FLAG(peer->flags,
- PEER_FLAG_GRACEFUL_RESTART)) ||
- (CHECK_FLAG(peer->flags,
- PEER_FLAG_GRACEFUL_RESTART_HELPER))) {
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
+ && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER))
+ return;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] Sending helper Capability for Peer :%s :",
+ peer->host);
+
+ SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
+ stream_putc(s, BGP_OPEN_OPT_CAP);
+ capp = stream_get_endp(s); /* Set Capability Len Pointer */
+ stream_putc(s, 0); /* Capability Length */
+ stream_putc(s, CAPABILITY_CODE_RESTART);
+ /* Set Restart Capability Len Pointer */
+ rcapp = stream_get_endp(s);
+ stream_putc(s, 0);
+ restart_time = peer->bgp->restart_time;
+ if (peer->bgp->t_startup) {
+ SET_FLAG(restart_time, RESTART_R_BIT);
+ SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV);
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
- zlog_debug(
- "[BGP_GR] Sending helper Capability for Peer :%s :",
- peer->host);
+ zlog_debug("[BGP_GR] Sending R-Bit for Peer :%s :",
+ peer->host);
+ }
- SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
- stream_putc(s, BGP_OPEN_OPT_CAP);
- capp = stream_get_endp(s); /* Set Capability Len Pointer */
- stream_putc(s, 0); /* Capability Length */
- stream_putc(s, CAPABILITY_CODE_RESTART);
- /* Set Restart Capability Len Pointer */
- rcapp = stream_get_endp(s);
- stream_putc(s, 0);
- restart_time = peer->bgp->restart_time;
- if (peer->bgp->t_startup) {
- SET_FLAG(restart_time, RESTART_R_BIT);
- SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV);
+ stream_putw(s, restart_time);
+
+ /* Send address-family specific graceful-restart capability
+ * only when GR config is present
+ */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) {
+ if (bgp_flag_check(peer->bgp, BGP_FLAG_GR_PRESERVE_FWD)
+ && BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] F bit Set");
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
- "[BGP_GR] Sending R-Bit for Peer :%s :",
- peer->host);
- }
+ "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:",
+ afi, safi);
- stream_putw(s, restart_time);
-
- /* Send address-family specific graceful-restart capability
- * only when GR config is present
- */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) {
-
- if (bgp_flag_check(peer->bgp,
- BGP_FLAG_GR_PRESERVE_FWD) &&
- BGP_DEBUG(graceful_restart,
- GRACEFUL_RESTART))
- zlog_debug("[BGP_GR] F bit Set");
-
- FOREACH_AFI_SAFI (afi, safi) {
- if (peer->afc[afi][safi]) {
- if (BGP_DEBUG(graceful_restart,
- GRACEFUL_RESTART))
- zlog_debug(
- "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:",
- afi, safi);
-
- /* Convert AFI, SAFI to values for
- * packet.
- */
- bgp_map_afi_safi_int2iana(afi,
- safi, &pkt_afi,
- &pkt_safi);
- stream_putw(s, pkt_afi);
- stream_putc(s, pkt_safi);
- if (bgp_flag_check(peer->bgp,
- BGP_FLAG_GR_PRESERVE_FWD)) {
- stream_putc(s, RESTART_F_BIT);
-
- } else {
- stream_putc(s, 0);
- }
- }
- }
+ /* Convert AFI, SAFI to values for
+ * packet.
+ */
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
+ &pkt_safi);
+ stream_putw(s, pkt_afi);
+ stream_putc(s, pkt_safi);
+ if (bgp_flag_check(peer->bgp, BGP_FLAG_GR_PRESERVE_FWD))
+ stream_putc(s, RESTART_F_BIT);
+ else
+ stream_putc(s, 0);
}
- /* Total Graceful restart capability Len. */
- len = stream_get_endp(s) - rcapp - 1;
- stream_putc_at(s, rcapp, len);
-
- /* Total Capability Len. */
- len = stream_get_endp(s) - capp - 1;
- stream_putc_at(s, capp, len);
}
+
+ /* Total Graceful restart capability Len. */
+ len = stream_get_endp(s) - rcapp - 1;
+ stream_putc_at(s, rcapp, len);
+
+ /* Total Capability Len. */
+ len = stream_get_endp(s) - capp - 1;
+ stream_putc_at(s, capp, len);
}
/* Fill in capability open option to the packet. */
@@ -1435,7 +1425,7 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)
&& peer->su.sa.sa_family == AF_INET6
&& afi == AFI_IP
- && (safi == SAFI_UNICAST
+ && (safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN
|| safi == SAFI_LABELED_UNICAST)) {
/* RFC 5549 Extended Next Hop Encoding
*/
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 954f524ec7..983b0184a5 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -38,6 +38,7 @@
#include "workqueue.h"
#include "queue.h"
#include "memory.h"
+#include "srv6.h"
#include "lib/json.h"
#include "lib_errors.h"
#include "zclient.h"
@@ -2760,12 +2761,6 @@ int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
}
thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
- if (thread_info == NULL) {
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("%s : error allocating thread info",
- __func__);
- return -1;
- }
thread_info->afi = afi;
thread_info->safi = safi;
@@ -2777,13 +2772,6 @@ int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
thread_add_timer(bm->master, bgp_route_select_timer_expire, thread_info,
BGP_ROUTE_SELECT_DELAY,
&bgp->gr_info[afi][safi].t_route_select);
- if (bgp->gr_info[afi][safi].t_route_select == NULL) {
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("%s : error starting selection thread for %s",
- __func__, get_afi_safi_str(afi,
- safi, false));
- return -1;
- }
return 0;
}
@@ -3656,6 +3644,22 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
bgp_set_valid_label(&extra->label[0]);
}
+ /* Update SRv6 SID */
+ if (attr->srv6_l3vpn) {
+ extra = bgp_path_info_extra_get(pi);
+ if (sid_diff(&extra->sid[0], &attr->srv6_l3vpn->sid)) {
+ sid_copy(&extra->sid[0],
+ &attr->srv6_l3vpn->sid);
+ extra->num_sids = 1;
+ }
+ } else if (attr->srv6_vpn) {
+ extra = bgp_path_info_extra_get(pi);
+ if (sid_diff(&extra->sid[0], &attr->srv6_vpn->sid)) {
+ sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
+ extra->num_sids = 1;
+ }
+ }
+
#if ENABLE_BGP_VNC
if ((afi == AFI_IP || afi == AFI_IP6)
&& (safi == SAFI_UNICAST)) {
@@ -3835,6 +3839,18 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
bgp_set_valid_label(&extra->label[0]);
}
+ /* Update SRv6 SID */
+ if (safi == SAFI_MPLS_VPN) {
+ extra = bgp_path_info_extra_get(new);
+ if (attr->srv6_l3vpn) {
+ sid_copy(&extra->sid[0], &attr->srv6_l3vpn->sid);
+ extra->num_sids = 1;
+ } else if (attr->srv6_vpn) {
+ sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
+ extra->num_sids = 1;
+ }
+ }
+
/* Update Overlay Index */
if (afi == AFI_L2VPN) {
overlay_index_update(new->attr,
@@ -9216,6 +9232,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
vty_out(vty, " Remote label: %d\n", label);
}
+ /* Remote SID */
+ if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) {
+ inet_ntop(AF_INET6, &path->extra->sid, buf, sizeof(buf));
+ if (json_paths)
+ json_object_string_add(json_path, "remoteSid", buf);
+ else
+ vty_out(vty, " Remote SID: %s\n", buf);
+ }
+
/* Label Index */
if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
if (json_paths)
@@ -10716,6 +10741,7 @@ DEFUN (show_ip_bgp_regexp,
if (argv_find(argv, argc, "REGEX", &idx))
regstr = argv[idx]->arg;
+ assert(regstr);
return bgp_show_regexp(vty, bgp, (const char *)regstr, afi, safi,
bgp_show_type_regexp, uj);
}
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index e335c39fb1..8f31cd38dc 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -78,6 +78,9 @@ enum bgp_show_adj_route_type {
*/
#define BGP_MAX_LABELS 2
+/* Maximum number of sids we can process or send with a prefix. */
+#define BGP_MAX_SIDS 6
+
/* Error codes for handling NLRI */
#define BGP_NLRI_PARSE_OK 0
#define BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW -1
@@ -118,6 +121,10 @@ struct bgp_path_info_extra {
uint16_t af_flags;
#define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0)
+ /* SRv6 SID(s) for SRv6-VPN */
+ struct in6_addr sid[BGP_MAX_SIDS];
+ uint32_t num_sids;
+
#if ENABLE_BGP_VNC
union {
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index eff5b3b7bc..696233e7a0 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -9454,20 +9454,19 @@ static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
}
}
-static void bgp_show_neighnor_graceful_restart_rbit(
- struct vty *vty,
- struct peer *p,
- bool use_json,
- json_object *json)
+static void bgp_show_neighnor_graceful_restart_rbit(struct vty *vty,
+ struct peer *p,
+ bool use_json,
+ json_object *json)
{
bool rbit_status = 0;
if (!use_json)
vty_out(vty, "\n R bit : ");
- if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) &&
- (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) &&
- (p->status == Established)) {
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)
+ && (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
+ && (p->status == Established)) {
if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_BIT_RCV))
rbit_status = 1;
@@ -9477,62 +9476,57 @@ static void bgp_show_neighnor_graceful_restart_rbit(
if (rbit_status) {
if (use_json)
- json_object_boolean_true_add(
- json, "rBit");
+ json_object_boolean_true_add(json, "rBit");
else
vty_out(vty, "True\n");
} else {
if (use_json)
- json_object_boolean_false_add(
- json, "rBit");
+ json_object_boolean_false_add(json, "rBit");
else
vty_out(vty, "False\n");
}
}
-static void bgp_show_neighbor_graceful_restart_remote_mode(
- struct vty *vty,
- struct peer *peer,
- bool use_json,
- json_object *json)
+static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty,
+ struct peer *peer,
+ bool use_json,
+ json_object *json)
{
const char *mode = "NotApplicable";
if (!use_json)
vty_out(vty, "\n Remote GR Mode : ");
- if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) &&
- (peer->status == Established)) {
+ if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
+ && (peer->status == Established)) {
- if ((peer->nsf_af_count == 0) &&
- !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+ if ((peer->nsf_af_count == 0)
+ && !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
mode = "Disable";
- } else if (peer->nsf_af_count == 0 &&
- CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+ } else if (peer->nsf_af_count == 0
+ && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
mode = "Helper";
- } else if (peer->nsf_af_count != 0 &&
- CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+ } else if (peer->nsf_af_count != 0
+ && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
mode = "Restart";
-
}
}
if (use_json) {
- json_object_string_add(json,
- "remoteGrMode", mode);
+ json_object_string_add(json, "remoteGrMode", mode);
} else
vty_out(vty, mode, "\n");
}
-static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
- struct peer *p,
- bool use_json,
- json_object *json)
+static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
+ struct peer *p,
+ bool use_json,
+ json_object *json)
{
const char *mode = "Invalid";
@@ -9557,16 +9551,14 @@ static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
}
if (use_json) {
- json_object_string_add(json,
- "localGrMode", mode);
+ json_object_string_add(json, "localGrMode", mode);
} else {
vty_out(vty, mode, "\n");
}
}
-static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
- struct vty *vty, struct peer *peer,
- bool use_json, json_object *json)
+static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
+ struct vty *vty, struct peer *peer, bool use_json, json_object *json)
{
afi_t afi;
safi_t safi;
@@ -9577,215 +9569,193 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
- if (peer->afc[afi][safi]
- && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
- && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)
- ) {
- if (use_json) {
- json_afi_safi =
- json_object_new_object();
- json_endofrib_status =
- json_object_new_object();
- json_timer =
- json_object_new_object();
- }
+ if (!peer->afc[afi][safi])
+ continue;
- if (peer->eor_stime[afi][safi] >=
- peer->pkt_stime[afi][safi])
- eor_flag = true;
- else
- eor_flag = false;
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
+ || !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))
+ continue;
- if (!use_json) {
- vty_out(vty, " %s :\n",
- get_afi_safi_str(afi, safi, false));
+ if (use_json) {
+ json_afi_safi = json_object_new_object();
+ json_endofrib_status = json_object_new_object();
+ json_timer = json_object_new_object();
+ }
- vty_out(vty,
- " F bit : ");
- } else
- get_afi_safi_str(afi, safi, true);
+ if (peer->eor_stime[afi][safi]
+ >= peer->pkt_stime[afi][safi])
+ eor_flag = true;
+ else
+ eor_flag = false;
- if (peer->nsf[afi][safi]
- && CHECK_FLAG(
- peer->af_cap[afi][safi],
- PEER_CAP_RESTART_AF_PRESERVE_RCV)) {
+ if (!use_json) {
+ vty_out(vty, " %s :\n",
+ get_afi_safi_str(afi, safi, false));
- if (use_json) {
- json_object_boolean_true_add(
- json_afi_safi, "fBit");
- } else {
- vty_out(vty,
- "True\n");
- }
+ vty_out(vty, " F bit : ");
+ }
- } else {
+ if (peer->nsf[afi][safi]
+ && CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_RESTART_AF_PRESERVE_RCV)) {
- if (use_json) {
- json_object_boolean_false_add(
+ if (use_json) {
+ json_object_boolean_true_add(
json_afi_safi, "fBit");
- } else {
- vty_out(vty,
- "False\n");
- }
-
- }
-
- if (!use_json)
- vty_out(vty,
- " End-of-RIB Received : ");
+ } else
+ vty_out(vty, "True\n");
+ } else {
+ if (use_json)
+ json_object_boolean_false_add(
+ json_afi_safi, "fBit");
+ else
+ vty_out(vty, "False\n");
+ }
- if (CHECK_FLAG(peer->af_sflags[afi][safi],
- PEER_STATUS_EOR_RECEIVED)) {
+ if (!use_json)
+ vty_out(vty, " End-of-RIB Received : ");
- if (use_json) {
- json_object_boolean_true_add(
+ if (CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED)) {
+ if (use_json)
+ json_object_boolean_true_add(
json_endofrib_status,
- "endOfRibRecv");
- } else {
- vty_out(vty, "Yes\n");
- }
-
- } else {
- if (use_json) {
- json_object_boolean_false_add(
+ "endOfRibRecv");
+ else
+ vty_out(vty, "Yes\n");
+ } else {
+ if (use_json)
+ json_object_boolean_false_add(
json_endofrib_status,
- "endOfRibRecv");
- } else {
- vty_out(vty, "No\n");
- }
- }
+ "endOfRibRecv");
+ else
+ vty_out(vty, "No\n");
+ }
- if (!use_json)
- vty_out(vty,
- " End-of-RIB Send : ");
+ if (!use_json)
+ vty_out(vty, " End-of-RIB Send : ");
- if (CHECK_FLAG(peer->af_sflags[afi][safi],
- PEER_STATUS_EOR_SEND)) {
- if (use_json) {
- json_object_boolean_true_add(
+ if (CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_SEND)) {
+ if (use_json) {
+ json_object_boolean_true_add(
json_endofrib_status,
- "endOfRibSend");
+ "endOfRibSend");
- PRINT_EOR_JSON(eor_flag);
- } else {
- vty_out(vty, "Yes\n");
- vty_out(vty,
+ PRINT_EOR_JSON(eor_flag);
+ } else {
+ vty_out(vty, "Yes\n");
+ vty_out(vty,
" EoRSentAfterUpdate : ");
- PRINT_EOR(eor_flag);
- }
- } else {
- if (use_json) {
- json_object_boolean_false_add(
+ PRINT_EOR(eor_flag);
+ }
+ } else {
+ if (use_json) {
+ json_object_boolean_false_add(
json_endofrib_status,
- "endOfRibSend");
- json_object_boolean_false_add(
+ "endOfRibSend");
+ json_object_boolean_false_add(
json_endofrib_status,
- "endOfRibSentAfterUpdate");
- } else {
- vty_out(vty, "No\n");
- vty_out(vty,
+ "endOfRibSentAfterUpdate");
+ } else {
+ vty_out(vty, "No\n");
+ vty_out(vty,
" EoRSentAfterUpdate : ");
- vty_out(vty, "No\n");
- }
+ vty_out(vty, "No\n");
}
+ }
- if (use_json) {
-
- json_object_int_add(json_timer,
- "stalePathTimer",
- peer->bgp->stalepath_time);
-
- if (peer->t_gr_stale != NULL) {
+ if (use_json) {
+ json_object_int_add(json_timer,
+ "stalePathTimer",
+ peer->bgp->stalepath_time);
- json_object_int_add(
+ if (peer->t_gr_stale != NULL) {
+ json_object_int_add(
json_timer,
"stalePathTimerRemaining",
thread_timer_remain_second(
- peer->t_gr_stale));
- }
-
- /* Display Configured Selection
- * Deferral only when when
- * Gr mode is enabled.
- */
- if (CHECK_FLAG(peer->flags,
- PEER_FLAG_GRACEFUL_RESTART)) {
+ peer->t_gr_stale));
+ }
- json_object_int_add(
+ /* Display Configured Selection
+ * Deferral only when when
+ * Gr mode is enabled.
+ */
+ if (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART)) {
+ json_object_int_add(
json_timer,
"selectionDeferralTimer",
peer->bgp->stalepath_time);
- }
+ }
- if (peer->bgp->gr_info[afi][safi]
- .t_select_deferral != NULL) {
+ if (peer->bgp->gr_info[afi][safi]
+ .t_select_deferral
+ != NULL) {
- json_object_int_add(
+ json_object_int_add(
json_timer,
"selectionDeferralTimerRemaining",
thread_timer_remain_second(
- peer->bgp
- ->gr_info[afi][safi]
- .t_select_deferral));
- }
-
- } else {
+ peer->bgp
+ ->gr_info[afi]
+ [safi]
+ .t_select_deferral));
+ }
+ } else {
+ vty_out(vty, " Timers:\n");
- vty_out(vty, " Timers:\n");
+ vty_out(vty, "%*s", 6, "");
+ vty_out(vty,
+ "Configured Stale Path Time(sec)%*s: %u\n",
+ 8, "", peer->bgp->stalepath_time);
+ if (peer->t_gr_stale != NULL) {
vty_out(vty, "%*s", 6, "");
vty_out(vty,
- "Configured Stale Path Time(sec)%*s: %u\n",
- 8, "",
- peer->bgp->stalepath_time);
-
- if (peer->t_gr_stale != NULL) {
- vty_out(vty, "%*s", 6, "");
- vty_out(vty,
"Stale Path Remaining(sec)%*s: %ld\n",
14, "",
thread_timer_remain_second(
- peer->t_gr_stale));
- }
- /* Display Configured Selection
- * Deferral only when when
- * Gr mode is enabled.
- */
- if (CHECK_FLAG(peer->flags,
- PEER_FLAG_GRACEFUL_RESTART)) {
- vty_out(vty, "%*s", 6, "");
- vty_out(vty,
+ peer->t_gr_stale));
+ }
+ /* Display Configured Selection
+ * Deferral only when when
+ * Gr mode is enabled.
+ */
+ if (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART)) {
+ vty_out(vty, "%*s", 6, "");
+ vty_out(vty,
"Configured Selection Deferral Time(sec): %u\n",
peer->bgp->select_defer_time);
- }
+ }
- if (peer->bgp
- ->gr_info[afi][safi]
- .t_select_deferral != NULL) {
+ if (peer->bgp->gr_info[afi][safi]
+ .t_select_deferral
+ != NULL) {
- vty_out(vty, "%*s", 6, "");
- vty_out(vty,
+ vty_out(vty, "%*s", 6, "");
+ vty_out(vty,
"Selection Deferral Time Remaining(sec) : %ld\n",
thread_timer_remain_second(
- peer->bgp
- ->gr_info[afi][safi]
- .t_select_deferral));
- }
-
- }
- if (use_json) {
- json_object_object_add(json_afi_safi,
- "endOfRibStatus",
- json_endofrib_status);
- json_object_object_add(json_afi_safi,
- "timers",
- json_timer);
- json_object_object_add(json,
- get_afi_safi_str(afi, safi, true),
- json_afi_safi);
+ peer->bgp
+ ->gr_info[afi]
+ [safi]
+ .t_select_deferral));
}
}
+ if (use_json) {
+ json_object_object_add(json_afi_safi,
+ "endOfRibStatus",
+ json_endofrib_status);
+ json_object_object_add(json_afi_safi, "timers",
+ json_timer);
+ json_object_object_add(
+ json, get_afi_safi_str(afi, safi, true),
+ json_afi_safi);
+ }
}
}
}
@@ -9800,39 +9770,30 @@ static void bgp_show_neighbor_graceful_restart_time(struct vty *vty,
json_timer = json_object_new_object();
- json_object_int_add(json_timer,
- "configuredRestartTimer",
- p->bgp->restart_time);
+ json_object_int_add(json_timer, "configuredRestartTimer",
+ p->bgp->restart_time);
- json_object_int_add(json_timer,
- "receivedRestartTimer",
- p->v_gr_restart);
+ json_object_int_add(json_timer, "receivedRestartTimer",
+ p->v_gr_restart);
- if (p->t_gr_restart != NULL) {
- json_object_int_add(json_timer,
- "restartTimerRemaining",
- thread_timer_remain_second(
- p->t_gr_restart)
- );
- }
+ if (p->t_gr_restart != NULL)
+ json_object_int_add(
+ json_timer, "restartTimerRemaining",
+ thread_timer_remain_second(p->t_gr_restart));
json_object_object_add(json, "timers", json_timer);
} else {
vty_out(vty, " Timers :\n");
- vty_out(vty,
- " Configured Restart Time(sec) : %u\n",
- p->bgp->restart_time);
+ vty_out(vty, " Configured Restart Time(sec) : %u\n",
+ p->bgp->restart_time);
- vty_out(vty,
- " Received Restart Time(sec) : %u\n",
- p->v_gr_restart);
- if (p->t_gr_restart != NULL) {
+ vty_out(vty, " Received Restart Time(sec) : %u\n",
+ p->v_gr_restart);
+ if (p->t_gr_restart != NULL)
vty_out(vty,
- " Restart Time Remaining(sec) : %ld\n",
- thread_timer_remain_second(
- p->t_gr_restart));
- }
+ " Restart Time Remaining(sec) : %ld\n",
+ thread_timer_remain_second(p->t_gr_restart));
}
}
@@ -9849,14 +9810,14 @@ static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p,
if (p->conf_if) {
if (use_json)
- json_object_string_add(json, "neighborAddr",
+ json_object_string_add(
+ json, "neighborAddr",
BGP_PEER_SU_UNSPEC(p)
- ? "none"
- : sockunion2str(&p->su, buf,
- SU_ADDRSTRLEN));
+ ? "none"
+ : sockunion2str(&p->su, buf,
+ SU_ADDRSTRLEN));
else
- vty_out(vty, "BGP neighbor on %s: %s\n",
- p->conf_if,
+ vty_out(vty, "BGP neighbor on %s: %s\n", p->conf_if,
BGP_PEER_SU_UNSPEC(p)
? "none"
: sockunion2str(&p->su, buf,
@@ -12194,35 +12155,34 @@ static int bgp_show_neighbor_graceful_restart(struct vty *vty,
if (type == show_all) {
bgp_show_peer_gr_status(vty, peer, use_json,
- json_neighbor);
+ json_neighbor);
if (use_json)
- json_object_object_add(json,
- peer->host, json_neighbor);
+ json_object_object_add(json, peer->host,
+ json_neighbor);
} else if (type == show_peer) {
if (conf_if) {
if ((peer->conf_if
- && !strcmp(peer->conf_if, conf_if))
- || (peer->hostname
+ && !strcmp(peer->conf_if, conf_if))
+ || (peer->hostname
&& !strcmp(peer->hostname, conf_if))) {
find = 1;
- bgp_show_peer_gr_status(vty,
- peer, use_json,
- json_neighbor);
+ bgp_show_peer_gr_status(vty, peer,
+ use_json,
+ json_neighbor);
}
} else {
if (sockunion_same(&peer->su, su)) {
find = 1;
- bgp_show_peer_gr_status(vty,
- peer, use_json,
- json_neighbor);
+ bgp_show_peer_gr_status(vty, peer,
+ use_json,
+ json_neighbor);
}
}
- if (use_json && find) {
- json_object_object_add(json,
- peer->host, json_neighbor);
- }
+ if (use_json && find)
+ json_object_object_add(json, peer->host,
+ json_neighbor);
}
if (find)
@@ -12231,14 +12191,14 @@ static int bgp_show_neighbor_graceful_restart(struct vty *vty,
if (type == show_peer && !find) {
if (use_json)
- json_object_boolean_true_add(json,
- "bgpNoSuchNeighbor");
+ json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
else
vty_out(vty, "%% No such neighbor\n");
}
if (use_json) {
- vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
} else {
vty_out(vty, "\n");
}
@@ -12363,32 +12323,27 @@ static void bgp_show_neighbor_graceful_restart_vty(struct vty *vty,
bgp = bgp_get_default();
- if (bgp) {
-
- if (!use_json) {
- bgp_show_global_graceful_restart_mode_vty(vty, bgp,
- use_json, NULL);
- }
+ if (!bgp)
+ return;
- json = json_object_new_object();
- if (ip_str) {
- ret = str2sockunion(ip_str, &su);
- if (ret < 0)
- bgp_show_neighbor_graceful_restart(vty,
- bgp, type, NULL, ip_str,
- afi, use_json, json);
- else
- bgp_show_neighbor_graceful_restart(vty,
- bgp, type, &su, NULL,
- afi, use_json, json);
- } else {
- bgp_show_neighbor_graceful_restart(vty, bgp,
- type, NULL, NULL, afi,
- use_json, json);
- }
- json_object_free(json);
- }
+ if (!use_json)
+ bgp_show_global_graceful_restart_mode_vty(vty, bgp, use_json,
+ NULL);
+ json = json_object_new_object();
+ if (ip_str) {
+ ret = str2sockunion(ip_str, &su);
+ if (ret < 0)
+ bgp_show_neighbor_graceful_restart(vty, bgp, type, NULL,
+ ip_str, afi,
+ use_json, json);
+ else
+ bgp_show_neighbor_graceful_restart(
+ vty, bgp, type, &su, NULL, afi, use_json, json);
+ } else
+ bgp_show_neighbor_graceful_restart(vty, bgp, type, NULL, NULL,
+ afi, use_json, json);
+ json_object_free(json);
}
static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
@@ -12722,27 +12677,23 @@ static void bgp_show_global_graceful_restart_mode_vty(struct vty *vty,
vty_out(vty, "\n%s", SHOW_GR_HEADER);
- int bgp_global_gr_mode = bgp_global_gr_mode_get(bgp);
+ enum global_mode bgp_global_gr_mode = bgp_global_gr_mode_get(bgp);
switch (bgp_global_gr_mode) {
case GLOBAL_HELPER:
- vty_out(vty,
- "Global BGP GR Mode : Helper\n");
+ vty_out(vty, "Global BGP GR Mode : Helper\n");
break;
case GLOBAL_GR:
- vty_out(vty,
- "Global BGP GR Mode : Restart\n");
+ vty_out(vty, "Global BGP GR Mode : Restart\n");
break;
case GLOBAL_DISABLE:
- vty_out(vty,
- "Global BGP GR Mode : Disable\n");
+ vty_out(vty, "Global BGP GR Mode : Disable\n");
break;
case GLOBAL_INVALID:
- default:
vty_out(vty,
"Global BGP GR Mode Invalid\n");
break;
@@ -14606,23 +14557,25 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
addr);
if (!CHECK_FLAG(peer->peer_gr_new_status_flag,
- PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) {
+ PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) {
if (CHECK_FLAG(peer->peer_gr_new_status_flag,
- PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) {
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) {
vty_out(vty,
" neighbor %s graceful-restart-helper\n", addr);
- } else if (CHECK_FLAG(peer->peer_gr_new_status_flag,
- PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) {
+ } else if (CHECK_FLAG(
+ peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) {
vty_out(vty,
" neighbor %s graceful-restart\n", addr);
- } else if ((!(CHECK_FLAG(peer->peer_gr_new_status_flag,
- PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
- && !(CHECK_FLAG(peer->peer_gr_new_status_flag,
- PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)))) {
- vty_out(vty,
- " neighbor %s graceful-restart-disable\n",
- addr);
+ } else if (
+ (!(CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
+ && !(CHECK_FLAG(
+ peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)))) {
+ vty_out(vty, " neighbor %s graceful-restart-disable\n",
+ addr);
}
}
}
@@ -16753,21 +16706,29 @@ static void community_list_perror(struct vty *vty, int ret)
/*community-list standard */
DEFUN (community_list_standard,
bgp_community_list_standard_cmd,
- "bgp community-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
+ "bgp community-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
BGP_STR
COMMUNITY_LIST_STR
"Community list number (standard)\n"
"Add an standard community-list entry\n"
"Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify community to reject\n"
"Specify community to accept\n"
COMMUNITY_VAL_STR)
{
char *cl_name_or_number = NULL;
+ char *seq = NULL;
int direct = 0;
int style = COMMUNITY_LIST_STANDARD;
int idx = 0;
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
argv_find(argv, argc, "(1-99)", &idx);
argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg;
@@ -16776,8 +16737,8 @@ DEFUN (community_list_standard,
argv_find(argv, argc, "AA:NN", &idx);
char *str = argv_concat(argv, argc, idx);
- int ret = community_list_set(bgp_clist, cl_name_or_number, str, direct,
- style);
+ int ret = community_list_set(bgp_clist, cl_name_or_number, str, seq,
+ direct, style);
XFREE(MTYPE_TMP, str);
@@ -16792,13 +16753,15 @@ DEFUN (community_list_standard,
DEFUN (no_community_list_standard_all,
no_bgp_community_list_standard_all_cmd,
- "no bgp community-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
+ "no bgp community-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
NO_STR
BGP_STR
COMMUNITY_LIST_STR
"Community list number (standard)\n"
"Add an standard community-list entry\n"
"Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify community to reject\n"
"Specify community to accept\n"
COMMUNITY_VAL_STR)
@@ -16807,9 +16770,14 @@ DEFUN (no_community_list_standard_all,
char *str = NULL;
int direct = 0;
int style = COMMUNITY_LIST_STANDARD;
-
+ char *seq = NULL;
int idx = 0;
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
@@ -16828,7 +16796,7 @@ DEFUN (no_community_list_standard_all,
argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg;
- int ret = community_list_unset(bgp_clist, cl_name_or_number, str,
+ int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
direct, style);
XFREE(MTYPE_TMP, str);
@@ -16851,22 +16819,30 @@ ALIAS(no_community_list_standard_all, no_bgp_community_list_standard_all_list_cm
/*community-list expanded */
DEFUN (community_list_expanded_all,
bgp_community_list_expanded_all_cmd,
- "bgp community-list <(100-500)|expanded WORD> <deny|permit> AA:NN...",
+ "bgp community-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
BGP_STR
COMMUNITY_LIST_STR
"Community list number (expanded)\n"
"Add an expanded community-list entry\n"
"Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify community to reject\n"
"Specify community to accept\n"
COMMUNITY_VAL_STR)
{
char *cl_name_or_number = NULL;
+ char *seq = NULL;
int direct = 0;
int style = COMMUNITY_LIST_EXPANDED;
-
int idx = 0;
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+
argv_find(argv, argc, "(100-500)", &idx);
argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg;
@@ -16875,8 +16851,8 @@ DEFUN (community_list_expanded_all,
argv_find(argv, argc, "AA:NN", &idx);
char *str = argv_concat(argv, argc, idx);
- int ret = community_list_set(bgp_clist, cl_name_or_number, str, direct,
- style);
+ int ret = community_list_set(bgp_clist, cl_name_or_number, str, seq,
+ direct, style);
XFREE(MTYPE_TMP, str);
@@ -16891,24 +16867,31 @@ DEFUN (community_list_expanded_all,
DEFUN (no_community_list_expanded_all,
no_bgp_community_list_expanded_all_cmd,
- "no bgp community-list <(100-500)|expanded WORD> <deny|permit> AA:NN...",
+ "no bgp community-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
NO_STR
BGP_STR
COMMUNITY_LIST_STR
"Community list number (expanded)\n"
"Add an expanded community-list entry\n"
"Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify community to reject\n"
"Specify community to accept\n"
COMMUNITY_VAL_STR)
{
char *cl_name_or_number = NULL;
+ char *seq = NULL;
char *str = NULL;
int direct = 0;
int style = COMMUNITY_LIST_EXPANDED;
-
int idx = 0;
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
@@ -16927,7 +16910,7 @@ DEFUN (no_community_list_expanded_all,
argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg;
- int ret = community_list_unset(bgp_clist, cl_name_or_number, str,
+ int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
direct, style);
XFREE(MTYPE_TMP, str);
@@ -17054,7 +17037,13 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc,
char *str;
int idx = 0;
char *cl_name;
+ char *seq = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+ idx = 0;
direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
: COMMUNITY_DENY;
@@ -17078,7 +17067,7 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc,
else
str = NULL;
- ret = lcommunity_list_set(bgp_clist, cl_name, str, direct, style);
+ ret = lcommunity_list_set(bgp_clist, cl_name, str, seq, direct, style);
/* Free temporary community list string allocated by
argv_concat(). */
@@ -17098,7 +17087,13 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
int direct = 0;
char *str = NULL;
int idx = 0;
+ char *seq = NULL;
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
@@ -17122,7 +17117,7 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
argv_find(argv, argc, "WORD", &idx);
/* Unset community list. */
- ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, direct,
+ ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct,
style);
/* Free temporary community list string allocated by
@@ -17143,10 +17138,12 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
DEFUN (lcommunity_list_standard,
bgp_lcommunity_list_standard_cmd,
- "bgp large-community-list (1-99) <deny|permit> AA:BB:CC...",
+ "bgp large-community-list (1-99) [seq (1-4294967295)] <deny|permit> AA:BB:CC...",
BGP_STR
LCOMMUNITY_LIST_STR
"Large Community list number (standard)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
LCOMMUNITY_VAL_STR)
@@ -17157,10 +17154,12 @@ DEFUN (lcommunity_list_standard,
DEFUN (lcommunity_list_expanded,
bgp_lcommunity_list_expanded_cmd,
- "bgp large-community-list (100-500) <deny|permit> LINE...",
+ "bgp large-community-list (100-500) [seq (1-4294967295)] <deny|permit> LINE...",
BGP_STR
LCOMMUNITY_LIST_STR
"Large Community list number (expanded)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
"An ordered list as a regular-expression\n")
@@ -17171,11 +17170,13 @@ DEFUN (lcommunity_list_expanded,
DEFUN (lcommunity_list_name_standard,
bgp_lcommunity_list_name_standard_cmd,
- "bgp large-community-list standard WORD <deny|permit> AA:BB:CC...",
+ "bgp large-community-list standard WORD [seq (1-4294967295)] <deny|permit> AA:BB:CC...",
BGP_STR
LCOMMUNITY_LIST_STR
"Specify standard large-community-list\n"
"Large Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
LCOMMUNITY_VAL_STR)
@@ -17186,11 +17187,13 @@ DEFUN (lcommunity_list_name_standard,
DEFUN (lcommunity_list_name_expanded,
bgp_lcommunity_list_name_expanded_cmd,
- "bgp large-community-list expanded WORD <deny|permit> LINE...",
+ "bgp large-community-list expanded WORD [seq (1-4294967295)] <deny|permit> LINE...",
BGP_STR
LCOMMUNITY_LIST_STR
"Specify expanded large-community-list\n"
"Large Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
"An ordered list as a regular-expression\n")
@@ -17199,8 +17202,8 @@ DEFUN (lcommunity_list_name_expanded,
LARGE_COMMUNITY_LIST_EXPANDED, 1);
}
-DEFUN (no_lcommunity_list_standard_all,
- no_bgp_lcommunity_list_standard_all_cmd,
+DEFUN (no_lcommunity_list_all,
+ no_bgp_lcommunity_list_all_cmd,
"no bgp large-community-list <(1-99)|(100-500)|WORD>",
NO_STR
BGP_STR
@@ -17213,6 +17216,19 @@ DEFUN (no_lcommunity_list_standard_all,
LARGE_COMMUNITY_LIST_STANDARD);
}
+DEFUN (no_lcommunity_list_name_standard_all,
+ no_bgp_lcommunity_list_name_standard_all_cmd,
+ "no bgp large-community-list standard WORD",
+ NO_STR
+ BGP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify standard large-community-list\n"
+ "Large Community list name\n")
+{
+ return lcommunity_list_unset_vty(vty, argc, argv,
+ LARGE_COMMUNITY_LIST_STANDARD);
+}
+
DEFUN (no_lcommunity_list_name_expanded_all,
no_bgp_lcommunity_list_name_expanded_all_cmd,
"no bgp large-community-list expanded WORD",
@@ -17228,11 +17244,13 @@ DEFUN (no_lcommunity_list_name_expanded_all,
DEFUN (no_lcommunity_list_standard,
no_bgp_lcommunity_list_standard_cmd,
- "no bgp large-community-list (1-99) <deny|permit> AA:AA:NN...",
+ "no bgp large-community-list (1-99) [seq (1-4294967295)] <deny|permit> AA:AA:NN...",
NO_STR
BGP_STR
LCOMMUNITY_LIST_STR
"Large Community list number (standard)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
LCOMMUNITY_VAL_STR)
@@ -17243,11 +17261,13 @@ DEFUN (no_lcommunity_list_standard,
DEFUN (no_lcommunity_list_expanded,
no_bgp_lcommunity_list_expanded_cmd,
- "no bgp large-community-list (100-500) <deny|permit> LINE...",
+ "no bgp large-community-list (100-500) [seq (1-4294967295)] <deny|permit> LINE...",
NO_STR
BGP_STR
LCOMMUNITY_LIST_STR
"Large Community list number (expanded)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
"An ordered list as a regular-expression\n")
@@ -17258,12 +17278,14 @@ DEFUN (no_lcommunity_list_expanded,
DEFUN (no_lcommunity_list_name_standard,
no_bgp_lcommunity_list_name_standard_cmd,
- "no bgp large-community-list standard WORD <deny|permit> AA:AA:NN...",
+ "no bgp large-community-list standard WORD [seq (1-4294967295)] <deny|permit> AA:AA:NN...",
NO_STR
BGP_STR
LCOMMUNITY_LIST_STR
"Specify standard large-community-list\n"
"Large Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
LCOMMUNITY_VAL_STR)
@@ -17274,12 +17296,14 @@ DEFUN (no_lcommunity_list_name_standard,
DEFUN (no_lcommunity_list_name_expanded,
no_bgp_lcommunity_list_name_expanded_cmd,
- "no bgp large-community-list expanded WORD <deny|permit> LINE...",
+ "no bgp large-community-list expanded WORD [seq (1-4294967295)] <deny|permit> LINE...",
NO_STR
BGP_STR
LCOMMUNITY_LIST_STR
"Specify expanded large-community-list\n"
"Large community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
"An ordered list as a regular-expression\n")
@@ -17374,12 +17398,14 @@ DEFUN (show_lcommunity_list_arg,
DEFUN (extcommunity_list_standard,
bgp_extcommunity_list_standard_cmd,
- "bgp extcommunity-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
+ "bgp extcommunity-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
BGP_STR
EXTCOMMUNITY_LIST_STR
"Extended Community list number (standard)\n"
"Specify standard extcommunity-list\n"
"Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify community to reject\n"
"Specify community to accept\n"
EXTCOMMUNITY_VAL_STR)
@@ -17387,18 +17413,24 @@ DEFUN (extcommunity_list_standard,
int style = EXTCOMMUNITY_LIST_STANDARD;
int direct = 0;
char *cl_number_or_name = NULL;
+ char *seq = NULL;
int idx = 0;
argv_find(argv, argc, "(1-99)", &idx);
argv_find(argv, argc, "WORD", &idx);
cl_number_or_name = argv[idx]->arg;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
: COMMUNITY_DENY;
argv_find(argv, argc, "AA:NN", &idx);
char *str = argv_concat(argv, argc, idx);
- int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str,
+ int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, seq,
direct, style);
XFREE(MTYPE_TMP, str);
@@ -17413,12 +17445,14 @@ DEFUN (extcommunity_list_standard,
DEFUN (extcommunity_list_name_expanded,
bgp_extcommunity_list_name_expanded_cmd,
- "bgp extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...",
+ "bgp extcommunity-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> LINE...",
BGP_STR
EXTCOMMUNITY_LIST_STR
"Extended Community list number (expanded)\n"
"Specify expanded extcommunity-list\n"
"Extended Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify community to reject\n"
"Specify community to accept\n"
"An ordered list as a regular-expression\n")
@@ -17426,17 +17460,23 @@ DEFUN (extcommunity_list_name_expanded,
int style = EXTCOMMUNITY_LIST_EXPANDED;
int direct = 0;
char *cl_number_or_name = NULL;
+ char *seq = NULL;
int idx = 0;
argv_find(argv, argc, "(100-500)", &idx);
argv_find(argv, argc, "WORD", &idx);
cl_number_or_name = argv[idx]->arg;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
: COMMUNITY_DENY;
argv_find(argv, argc, "LINE", &idx);
char *str = argv_concat(argv, argc, idx);
- int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str,
+ int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, seq,
direct, style);
XFREE(MTYPE_TMP, str);
@@ -17451,13 +17491,15 @@ DEFUN (extcommunity_list_name_expanded,
DEFUN (no_extcommunity_list_standard_all,
no_bgp_extcommunity_list_standard_all_cmd,
- "no bgp extcommunity-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
+ "no bgp extcommunity-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
NO_STR
BGP_STR
EXTCOMMUNITY_LIST_STR
"Extended Community list number (standard)\n"
"Specify standard extcommunity-list\n"
"Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify community to reject\n"
"Specify community to accept\n"
EXTCOMMUNITY_VAL_STR)
@@ -17466,11 +17508,16 @@ DEFUN (no_extcommunity_list_standard_all,
int direct = 0;
char *cl_number_or_name = NULL;
char *str = NULL;
+ char *seq = NULL;
int idx = 0;
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
-
if (idx) {
direct = argv_find(argv, argc, "permit", &idx)
? COMMUNITY_PERMIT
@@ -17487,7 +17534,7 @@ DEFUN (no_extcommunity_list_standard_all,
cl_number_or_name = argv[idx]->arg;
int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
- direct, style);
+ seq, direct, style);
XFREE(MTYPE_TMP, str);
@@ -17509,13 +17556,15 @@ ALIAS(no_extcommunity_list_standard_all,
DEFUN (no_extcommunity_list_expanded_all,
no_bgp_extcommunity_list_expanded_all_cmd,
- "no bgp extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...",
+ "no bgp extcommunity-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> LINE...",
NO_STR
BGP_STR
EXTCOMMUNITY_LIST_STR
"Extended Community list number (expanded)\n"
"Specify expanded extcommunity-list\n"
"Extended Community list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify community to reject\n"
"Specify community to accept\n"
"An ordered list as a regular-expression\n")
@@ -17524,8 +17573,14 @@ DEFUN (no_extcommunity_list_expanded_all,
int direct = 0;
char *cl_number_or_name = NULL;
char *str = NULL;
+ char *seq = NULL;
int idx = 0;
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
@@ -17545,7 +17600,7 @@ DEFUN (no_extcommunity_list_expanded_all,
cl_number_or_name = argv[idx]->arg;
int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
- direct, style);
+ seq, direct, style);
XFREE(MTYPE_TMP, str);
@@ -17656,18 +17711,22 @@ static int community_list_config_write(struct vty *vty)
for (list = cm->num.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) {
- vty_out(vty, "bgp community-list %s %s %s\n", list->name,
+ vty_out(vty,
+ "bgp community-list %s seq %" PRId64 " %s %s\n",
+ list->name, entry->seq,
community_direct_str(entry->direct),
community_list_config_str(entry));
write++;
}
for (list = cm->str.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) {
- vty_out(vty, "bgp community-list %s %s %s %s\n",
+ vty_out(vty,
+ "bgp community-list %s %s seq %" PRId64 " %s %s\n",
entry->style == COMMUNITY_LIST_STANDARD
? "standard"
: "expanded",
- list->name, community_direct_str(entry->direct),
+ list->name, entry->seq,
+ community_direct_str(entry->direct),
community_list_config_str(entry));
write++;
}
@@ -17677,18 +17736,23 @@ static int community_list_config_write(struct vty *vty)
for (list = cm->num.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) {
- vty_out(vty, "bgp extcommunity-list %s %s %s\n",
- list->name, community_direct_str(entry->direct),
+ vty_out(vty,
+ "bgp extcommunity-list %s seq %" PRId64 " %s %s\n",
+ list->name, entry->seq,
+ community_direct_str(entry->direct),
community_list_config_str(entry));
write++;
}
for (list = cm->str.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) {
- vty_out(vty, "bgp extcommunity-list %s %s %s %s\n",
+ vty_out(vty,
+ "bgp extcommunity-list %s %s seq %" PRId64
+ " %s %s\n",
entry->style == EXTCOMMUNITY_LIST_STANDARD
? "standard"
: "expanded",
- list->name, community_direct_str(entry->direct),
+ list->name, entry->seq,
+ community_direct_str(entry->direct),
community_list_config_str(entry));
write++;
}
@@ -17700,18 +17764,24 @@ static int community_list_config_write(struct vty *vty)
for (list = cm->num.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) {
- vty_out(vty, "bgp large-community-list %s %s %s\n",
- list->name, community_direct_str(entry->direct),
+ vty_out(vty,
+ "bgp large-community-list %s seq %" PRId64
+ " %s %s\n",
+ list->name, entry->seq,
+ community_direct_str(entry->direct),
community_list_config_str(entry));
write++;
}
for (list = cm->str.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) {
- vty_out(vty, "bgp large-community-list %s %s %s %s\n",
+ vty_out(vty,
+ "bgp large-community-list %s %s seq %" PRId64
+ " %s %s\n",
+
entry->style == LARGE_COMMUNITY_LIST_STANDARD
? "standard"
: "expanded",
- list->name, community_direct_str(entry->direct),
+ list->name, entry->seq, community_direct_str(entry->direct),
community_list_config_str(entry));
write++;
}
@@ -17754,7 +17824,9 @@ static void community_list_vty(void)
install_element(CONFIG_NODE, &bgp_lcommunity_list_expanded_cmd);
install_element(CONFIG_NODE, &bgp_lcommunity_list_name_standard_cmd);
install_element(CONFIG_NODE, &bgp_lcommunity_list_name_expanded_cmd);
- install_element(CONFIG_NODE, &no_bgp_lcommunity_list_standard_all_cmd);
+ install_element(CONFIG_NODE, &no_bgp_lcommunity_list_all_cmd);
+ install_element(CONFIG_NODE,
+ &no_bgp_lcommunity_list_name_standard_all_cmd);
install_element(CONFIG_NODE,
&no_bgp_lcommunity_list_name_expanded_all_cmd);
install_element(CONFIG_NODE, &no_bgp_lcommunity_list_standard_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index d2b8f5d790..0e7a361edc 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -3101,43 +3101,6 @@ int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type)
}
-int zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
- struct zapi_cap *api)
-{
- struct stream *s;
-
- if (zclient == NULL)
- return -1;
-
- s = zclient->obuf;
- stream_reset(s);
- zclient_create_header(s, cmd, 0);
- stream_putl(s, api->cap);
- switch (api->cap) {
- case ZEBRA_CLIENT_GR_CAPABILITIES:
- case ZEBRA_CLIENT_RIB_STALE_TIME:
- stream_putl(s, api->stale_removal_time);
- stream_putl(s, api->vrf_id);
- break;
- case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
- case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
- stream_putl(s, api->afi);
- stream_putl(s, api->safi);
- stream_putl(s, api->vrf_id);
- break;
- case ZEBRA_CLIENT_GR_DISABLE:
- stream_putl(s, api->vrf_id);
- break;
- default:
- break;
- }
-
- /* Put length at the first point of the stream */
- stream_putw_at(s, 0, stream_get_endp(s));
-
- return zclient_send_message(zclient);
-}
-
/* Send RIB stale timer update */
int bgp_zebra_stale_timer_update(struct bgp *bgp)
{
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 7c2d60c515..2117baf835 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -3320,14 +3320,13 @@ int bgp_delete(struct bgp *bgp)
/* Delete the graceful restart info */
FOREACH_AFI_SAFI (afi, safi) {
gr_info = &bgp->gr_info[afi][safi];
- if (gr_info) {
- BGP_TIMER_OFF(gr_info->t_select_deferral);
- gr_info->t_select_deferral = NULL;
- BGP_TIMER_OFF(gr_info->t_route_select);
- gr_info->t_route_select = NULL;
- if (gr_info->route_list)
- list_delete(&gr_info->route_list);
- }
+ if (!gr_info)
+ continue;
+
+ BGP_TIMER_OFF(gr_info->t_select_deferral);
+ BGP_TIMER_OFF(gr_info->t_route_select);
+ if (gr_info->route_list)
+ list_delete(&gr_info->route_list);
}
if (BGP_DEBUG(zebra, ZEBRA)) {
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 5ad822211b..77fcf909c8 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -431,6 +431,14 @@ void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p,
else
vty_out(vty, " label=%u",
decode_label(&bpi->extra->label[0]));
+
+ if (bpi->extra->num_sids) {
+ char buf[BUFSIZ];
+
+ vty_out(vty, " sid=%s",
+ inet_ntop(AF_INET6, &bpi->extra->sid[0], buf,
+ sizeof(buf)));
+ }
}
if (!rfapiGetVncLifetime(bpi->attr, &lifetime)) {
diff --git a/doc/developer/zebra.rst b/doc/developer/zebra.rst
index 74a8605bf2..e3526d1843 100644
--- a/doc/developer/zebra.rst
+++ b/doc/developer/zebra.rst
@@ -169,175 +169,201 @@ Zebra Protocol Commands
+------------------------------------+-------+
| ZEBRA_INTERFACE_SET_MASTER | 6 |
+------------------------------------+-------+
-| ZEBRA_ROUTE_ADD | 7 |
+| ZEBRA_INTERFACE_SET_PROTODOWN | 7 |
+------------------------------------+-------+
-| ZEBRA_ROUTE_DELETE | 8 |
+| ZEBRA_ROUTE_ADD | 8 |
+------------------------------------+-------+
-| ZEBRA_ROUTE_NOTIFY_OWNER | 9 |
+| ZEBRA_ROUTE_DELETE | 9 |
+------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_ADD | 10 |
+| ZEBRA_ROUTE_NOTIFY_OWNER | 10 |
+------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_DELETE | 11 |
+| ZEBRA_REDISTRIBUTE_ADD | 11 |
+------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_DEFAULT_ADD | 12 |
+| ZEBRA_REDISTRIBUTE_DELETE | 12 |
+------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_DEFAULT_DELETE | 13 |
+| ZEBRA_REDISTRIBUTE_DEFAULT_ADD | 13 |
+------------------------------------+-------+
-| ZEBRA_ROUTER_ID_ADD | 14 |
+| ZEBRA_REDISTRIBUTE_DEFAULT_DELETE | 14 |
+------------------------------------+-------+
-| ZEBRA_ROUTER_ID_DELETE | 15 |
+| ZEBRA_ROUTER_ID_ADD | 15 |
+------------------------------------+-------+
-| ZEBRA_ROUTER_ID_UPDATE | 16 |
+| ZEBRA_ROUTER_ID_DELETE | 16 |
+------------------------------------+-------+
-| ZEBRA_HELLO | 17 |
+| ZEBRA_ROUTER_ID_UPDATE | 17 |
+------------------------------------+-------+
-| ZEBRA_CAPABILITIES | 18 |
+| ZEBRA_HELLO | 18 |
+------------------------------------+-------+
-| ZEBRA_NEXTHOP_REGISTER | 19 |
+| ZEBRA_CAPABILITIES | 19 |
+------------------------------------+-------+
-| ZEBRA_NEXTHOP_UNREGISTER | 20 |
+| ZEBRA_NEXTHOP_REGISTER | 20 |
+------------------------------------+-------+
-| ZEBRA_NEXTHOP_UPDATE | 21 |
+| ZEBRA_NEXTHOP_UNREGISTER | 21 |
+------------------------------------+-------+
-| ZEBRA_INTERFACE_NBR_ADDRESS_ADD | 22 |
+| ZEBRA_NEXTHOP_UPDATE | 22 |
+------------------------------------+-------+
-| ZEBRA_INTERFACE_NBR_ADDRESS_DELETE | 23 |
+| ZEBRA_INTERFACE_NBR_ADDRESS_ADD | 23 |
+------------------------------------+-------+
-| ZEBRA_INTERFACE_BFD_DEST_UPDATE | 24 |
+| ZEBRA_INTERFACE_NBR_ADDRESS_DELETE | 24 |
+------------------------------------+-------+
-| ZEBRA_IMPORT_ROUTE_REGISTER | 25 |
+| ZEBRA_INTERFACE_BFD_DEST_UPDATE | 25 |
+------------------------------------+-------+
-| ZEBRA_IMPORT_ROUTE_UNREGISTER | 26 |
+| ZEBRA_IMPORT_ROUTE_REGISTER | 26 |
+------------------------------------+-------+
-| ZEBRA_IMPORT_CHECK_UPDATE | 27 |
+| ZEBRA_IMPORT_ROUTE_UNREGISTER | 27 |
+------------------------------------+-------+
-| ZEBRA_BFD_DEST_REGISTER | 28 |
+| ZEBRA_IMPORT_CHECK_UPDATE | 28 |
+------------------------------------+-------+
-| ZEBRA_BFD_DEST_DEREGISTER | 29 |
+| ZEBRA_BFD_DEST_REGISTER | 29 |
+------------------------------------+-------+
-| ZEBRA_BFD_DEST_UPDATE | 30 |
+| ZEBRA_BFD_DEST_DEREGISTER | 30 |
+------------------------------------+-------+
-| ZEBRA_BFD_DEST_REPLAY | 31 |
+| ZEBRA_BFD_DEST_UPDATE | 31 |
+------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_ROUTE_ADD | 32 |
+| ZEBRA_BFD_DEST_REPLAY | 32 |
+------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_ROUTE_DEL | 33 |
+| ZEBRA_REDISTRIBUTE_ROUTE_ADD | 33 |
+------------------------------------+-------+
-| ZEBRA_VRF_UNREGISTER | 34 |
+| ZEBRA_REDISTRIBUTE_ROUTE_DEL | 34 |
+------------------------------------+-------+
-| ZEBRA_VRF_ADD | 35 |
+| ZEBRA_VRF_UNREGISTER | 35 |
+------------------------------------+-------+
-| ZEBRA_VRF_DELETE | 36 |
+| ZEBRA_VRF_ADD | 36 |
+------------------------------------+-------+
-| ZEBRA_VRF_LABEL | 37 |
+| ZEBRA_VRF_DELETE | 37 |
+------------------------------------+-------+
-| ZEBRA_INTERFACE_VRF_UPDATE | 38 |
+| ZEBRA_VRF_LABEL | 38 |
+------------------------------------+-------+
-| ZEBRA_BFD_CLIENT_REGISTER | 39 |
+| ZEBRA_INTERFACE_VRF_UPDATE | 39 |
+------------------------------------+-------+
-| ZEBRA_BFD_CLIENT_DEREGISTER | 40 |
+| ZEBRA_BFD_CLIENT_REGISTER | 40 |
+------------------------------------+-------+
-| ZEBRA_INTERFACE_ENABLE_RADV | 41 |
+| ZEBRA_BFD_CLIENT_DEREGISTER | 41 |
+------------------------------------+-------+
-| ZEBRA_INTERFACE_DISABLE_RADV | 42 |
+| ZEBRA_INTERFACE_ENABLE_RADV | 42 |
+------------------------------------+-------+
-| ZEBRA_IPV3_NEXTHOP_LOOKUP_MRIB | 43 |
+| ZEBRA_INTERFACE_DISABLE_RADV | 43 |
+------------------------------------+-------+
-| ZEBRA_INTERFACE_LINK_PARAMS | 44 |
+| ZEBRA_IPV3_NEXTHOP_LOOKUP_MRIB | 44 |
+------------------------------------+-------+
-| ZEBRA_MPLS_LABELS_ADD | 45 |
+| ZEBRA_INTERFACE_LINK_PARAMS | 45 |
+------------------------------------+-------+
-| ZEBRA_MPLS_LABELS_DELETE | 46 |
+| ZEBRA_MPLS_LABELS_ADD | 46 |
+------------------------------------+-------+
-| ZEBRA_IPMR_ROUTE_STATS | 47 |
+| ZEBRA_MPLS_LABELS_DELETE | 47 |
+------------------------------------+-------+
-| ZEBRA_LABEL_MANAGER_CONNECT | 48 |
+| ZEBRA_MPLS_LABELS_REPLACE | 48 |
+------------------------------------+-------+
-| ZEBRA_LABEL_MANAGER_CONNECT_ASYNC | 49 |
+| ZEBRA_IPMR_ROUTE_STATS | 49 |
+------------------------------------+-------+
-| ZEBRA_GET_LABEL_CHUNK | 50 |
+| ZEBRA_LABEL_MANAGER_CONNECT | 50 |
+------------------------------------+-------+
-| ZEBRA_RELEASE_LABEL_CHUNK | 51 |
+| ZEBRA_LABEL_MANAGER_CONNECT_ASYNC | 51 |
+------------------------------------+-------+
-| ZEBRA_FEC_REGISTER | 52 |
+| ZEBRA_GET_LABEL_CHUNK | 52 |
+------------------------------------+-------+
-| ZEBRA_FEC_UNREGISTER | 53 |
+| ZEBRA_RELEASE_LABEL_CHUNK | 53 |
+------------------------------------+-------+
-| ZEBRA_FEC_UPDATE | 54 |
+| ZEBRA_FEC_REGISTER | 54 |
+------------------------------------+-------+
-| ZEBRA_ADVERTISE_DEFAULT_GW | 55 |
+| ZEBRA_FEC_UNREGISTER | 55 |
+------------------------------------+-------+
-| ZEBRA_ADVERTISE_SUBNET | 56 |
+| ZEBRA_FEC_UPDATE | 56 |
+------------------------------------+-------+
-| ZEBRA_ADVERTISE_ALL_VNI | 57 |
+| ZEBRA_ADVERTISE_DEFAULT_GW | 57 |
+------------------------------------+-------+
-| ZEBRA_LOCAL_ES_ADD | 58 |
+| ZEBRA_ADVERTISE_SVI_MACIP | 58 |
+------------------------------------+-------+
-| ZEBRA_LOCAL_ES_DEL | 59 |
+| ZEBRA_ADVERTISE_SUBNET | 59 |
+------------------------------------+-------+
-| ZEBRA_VNI_ADD | 60 |
+| ZEBRA_ADVERTISE_ALL_VNI | 60 |
+------------------------------------+-------+
-| ZEBRA_VNI_DEL | 61 |
+| ZEBRA_LOCAL_ES_ADD | 61 |
+------------------------------------+-------+
-| ZEBRA_L3VNI_ADD | 62 |
+| ZEBRA_LOCAL_ES_DEL | 62 |
+------------------------------------+-------+
-| ZEBRA_L3VNI_DEL | 63 |
+| ZEBRA_VNI_ADD | 63 |
+------------------------------------+-------+
-| ZEBRA_REMOTE_VTEP_ADD | 64 |
+| ZEBRA_VNI_DEL | 64 |
+------------------------------------+-------+
-| ZEBRA_REMOTE_VTEP_DEL | 65 |
+| ZEBRA_L3VNI_ADD | 65 |
+------------------------------------+-------+
-| ZEBRA_MACIP_ADD | 66 |
+| ZEBRA_L3VNI_DEL | 66 |
+------------------------------------+-------+
-| ZEBRA_MACIP_DEL | 67 |
+| ZEBRA_REMOTE_VTEP_ADD | 67 |
+------------------------------------+-------+
-| ZEBRA_IP_PREFIX_ROUTE_ADD | 68 |
+| ZEBRA_REMOTE_VTEP_DEL | 68 |
+------------------------------------+-------+
-| ZEBRA_IP_PREFIX_ROUTE_DEL | 69 |
+| ZEBRA_MACIP_ADD | 69 |
+------------------------------------+-------+
-| ZEBRA_REMOTE_MACIP_ADD | 70 |
+| ZEBRA_MACIP_DEL | 70 |
+------------------------------------+-------+
-| ZEBRA_REMOTE_MACIP_DEL | 71 |
+| ZEBRA_IP_PREFIX_ROUTE_ADD | 71 |
+------------------------------------+-------+
-| ZEBRA_PW_ADD | 72 |
+| ZEBRA_IP_PREFIX_ROUTE_DEL | 72 |
+------------------------------------+-------+
-| ZEBRA_PW_DELETE | 73 |
+| ZEBRA_REMOTE_MACIP_ADD | 73 |
+------------------------------------+-------+
-| ZEBRA_PW_SET | 74 |
+| ZEBRA_REMOTE_MACIP_DEL | 74 |
+------------------------------------+-------+
-| ZEBRA_PW_UNSET | 75 |
+| ZEBRA_DUPLICATE_ADDR_DETECTION | 75 |
+------------------------------------+-------+
-| ZEBRA_PW_STATUS_UPDATE | 76 |
+| ZEBRA_PW_ADD | 76 |
+------------------------------------+-------+
-| ZEBRA_RULE_ADD | 77 |
+| ZEBRA_PW_DELETE | 77 |
+------------------------------------+-------+
-| ZEBRA_RULE_DELETE | 78 |
+| ZEBRA_PW_SET | 78 |
+------------------------------------+-------+
-| ZEBRA_RULE_NOTIFY_OWNER | 79 |
+| ZEBRA_PW_UNSET | 79 |
+------------------------------------+-------+
-| ZEBRA_TABLE_MANAGER_CONNECT | 80 |
+| ZEBRA_PW_STATUS_UPDATE | 80 |
+------------------------------------+-------+
-| ZEBRA_GET_TABLE_CHUNK | 81 |
+| ZEBRA_RULE_ADD | 81 |
+------------------------------------+-------+
-| ZEBRA_RELEASE_TABLE_CHUNK | 82 |
+| ZEBRA_RULE_DELETE | 82 |
+------------------------------------+-------+
-| ZEBRA_IPSET_CREATE | 83 |
+| ZEBRA_RULE_NOTIFY_OWNER | 83 |
+------------------------------------+-------+
-| ZEBRA_IPSET_DESTROY | 84 |
+| ZEBRA_TABLE_MANAGER_CONNECT | 84 |
+------------------------------------+-------+
-| ZEBRA_IPSET_ENTRY_ADD | 85 |
+| ZEBRA_GET_TABLE_CHUNK | 85 |
+------------------------------------+-------+
-| ZEBRA_IPSET_ENTRY_DELETE | 86 |
+| ZEBRA_RELEASE_TABLE_CHUNK | 86 |
+------------------------------------+-------+
-| ZEBRA_IPSET_NOTIFY_OWNER | 87 |
+| ZEBRA_IPSET_CREATE | 87 |
+------------------------------------+-------+
-| ZEBRA_IPSET_ENTRY_NOTIFY_OWNER | 88 |
+| ZEBRA_IPSET_DESTROY | 88 |
+------------------------------------+-------+
-| ZEBRA_IPTABLE_ADD | 89 |
+| ZEBRA_IPSET_ENTRY_ADD | 89 |
+------------------------------------+-------+
-| ZEBRA_IPTABLE_DELETE | 90 |
+| ZEBRA_IPSET_ENTRY_DELETE | 90 |
+------------------------------------+-------+
-| ZEBRA_IPTABLE_NOTIFY_OWNER | 91 |
+| ZEBRA_IPSET_NOTIFY_OWNER | 91 |
+------------------------------------+-------+
-| ZEBRA_VXLAN_FLOOD_CONTROL | 92 |
+| ZEBRA_IPSET_ENTRY_NOTIFY_OWNER | 92 |
++------------------------------------+-------+
+| ZEBRA_IPTABLE_ADD | 93 |
++------------------------------------+-------+
+| ZEBRA_IPTABLE_DELETE | 94 |
++------------------------------------+-------+
+| ZEBRA_IPTABLE_NOTIFY_OWNER | 95 |
++------------------------------------+-------+
+| ZEBRA_VXLAN_FLOOD_CONTROL | 96 |
++------------------------------------+-------+
+| ZEBRA_VXLAN_SG_ADD | 97 |
++------------------------------------+-------+
+| ZEBRA_VXLAN_SG_DEL | 98 |
++------------------------------------+-------+
+| ZEBRA_VXLAN_SG_REPLAY | 99 |
++------------------------------------+-------+
+| ZEBRA_MLAG_PROCESS_UP | 100 |
++------------------------------------+-------+
+| ZEBRA_MLAG_PROCESS_DOWN | 101 |
++------------------------------------+-------+
+| ZEBRA_MLAG_CLIENT_REGISTER | 102 |
++------------------------------------+-------+
+| ZEBRA_MLAG_CLIENT_UNREGISTER | 103 |
++------------------------------------+-------+
+| ZEBRA_MLAG_FORWARD_MSG | 104 |
++------------------------------------+-------+
+| ZEBRA_CLIENT_CAPABILITIES | 105 |
+------------------------------------+-------+
diff --git a/include/linux/seg6.h b/include/linux/seg6.h
new file mode 100644
index 0000000000..329163e4a0
--- /dev/null
+++ b/include/linux/seg6.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * SR-IPv6 implementation
+ *
+ * Author:
+ * David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_SEG6_H
+#define _LINUX_SEG6_H
+
+#include <linux/types.h>
+#include <linux/in6.h> /* For struct in6_addr. */
+
+/*
+ * SRH
+ */
+struct ipv6_sr_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ __u8 type;
+ __u8 segments_left;
+ __u8 first_segment; /* Represents the last_entry field of SRH */
+ __u8 flags;
+ __u16 tag;
+
+ struct in6_addr segments[0];
+};
+
+#define SR6_FLAG1_PROTECTED (1 << 6)
+#define SR6_FLAG1_OAM (1 << 5)
+#define SR6_FLAG1_ALERT (1 << 4)
+#define SR6_FLAG1_HMAC (1 << 3)
+
+#define SR6_TLV_INGRESS 1
+#define SR6_TLV_EGRESS 2
+#define SR6_TLV_OPAQUE 3
+#define SR6_TLV_PADDING 4
+#define SR6_TLV_HMAC 5
+
+#define sr_has_hmac(srh) ((srh)->flags & SR6_FLAG1_HMAC)
+
+struct sr6_tlv {
+ __u8 type;
+ __u8 len;
+ __u8 data[0];
+};
+
+#endif
diff --git a/include/linux/seg6_genl.h b/include/linux/seg6_genl.h
new file mode 100644
index 0000000000..0c230524e0
--- /dev/null
+++ b/include/linux/seg6_genl.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_SEG6_GENL_H
+#define _LINUX_SEG6_GENL_H
+
+#define SEG6_GENL_NAME "SEG6"
+#define SEG6_GENL_VERSION 0x1
+
+enum {
+ SEG6_ATTR_UNSPEC,
+ SEG6_ATTR_DST,
+ SEG6_ATTR_DSTLEN,
+ SEG6_ATTR_HMACKEYID,
+ SEG6_ATTR_SECRET,
+ SEG6_ATTR_SECRETLEN,
+ SEG6_ATTR_ALGID,
+ SEG6_ATTR_HMACINFO,
+ __SEG6_ATTR_MAX,
+};
+
+#define SEG6_ATTR_MAX (__SEG6_ATTR_MAX - 1)
+
+enum {
+ SEG6_CMD_UNSPEC,
+ SEG6_CMD_SETHMAC,
+ SEG6_CMD_DUMPHMAC,
+ SEG6_CMD_SET_TUNSRC,
+ SEG6_CMD_GET_TUNSRC,
+ __SEG6_CMD_MAX,
+};
+
+#define SEG6_CMD_MAX (__SEG6_CMD_MAX - 1)
+
+#endif
diff --git a/include/linux/seg6_hmac.h b/include/linux/seg6_hmac.h
new file mode 100644
index 0000000000..3fb3412e1e
--- /dev/null
+++ b/include/linux/seg6_hmac.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_SEG6_HMAC_H
+#define _LINUX_SEG6_HMAC_H
+
+#include <linux/types.h>
+#include <linux/seg6.h>
+
+#define SEG6_HMAC_SECRET_LEN 64
+#define SEG6_HMAC_FIELD_LEN 32
+
+struct sr6_tlv_hmac {
+ struct sr6_tlv tlvhdr;
+ __u16 reserved;
+ __be32 hmackeyid;
+ __u8 hmac[SEG6_HMAC_FIELD_LEN];
+};
+
+enum {
+ SEG6_HMAC_ALGO_SHA1 = 1,
+ SEG6_HMAC_ALGO_SHA256 = 2,
+};
+
+#endif
diff --git a/include/linux/seg6_iptunnel.h b/include/linux/seg6_iptunnel.h
new file mode 100644
index 0000000000..3004e982c2
--- /dev/null
+++ b/include/linux/seg6_iptunnel.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * SR-IPv6 implementation
+ *
+ * Author:
+ * David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_SEG6_IPTUNNEL_H
+#define _LINUX_SEG6_IPTUNNEL_H
+
+#include <linux/seg6.h> /* For struct ipv6_sr_hdr. */
+
+enum {
+ SEG6_IPTUNNEL_UNSPEC,
+ SEG6_IPTUNNEL_SRH,
+ __SEG6_IPTUNNEL_MAX,
+};
+#define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1)
+
+struct seg6_iptunnel_encap {
+ int mode;
+ struct ipv6_sr_hdr srh[0];
+};
+
+#define SEG6_IPTUN_ENCAP_SIZE(x) ((sizeof(*x)) + (((x)->srh->hdrlen + 1) << 3))
+
+enum {
+ SEG6_IPTUN_MODE_INLINE,
+ SEG6_IPTUN_MODE_ENCAP,
+ SEG6_IPTUN_MODE_L2ENCAP,
+};
+
+
+#endif
diff --git a/include/linux/seg6_local.h b/include/linux/seg6_local.h
new file mode 100644
index 0000000000..5312de80bc
--- /dev/null
+++ b/include/linux/seg6_local.h
@@ -0,0 +1,80 @@
+/*
+ * SR-IPv6 implementation
+ *
+ * Author:
+ * David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_SEG6_LOCAL_H
+#define _LINUX_SEG6_LOCAL_H
+
+#include <linux/seg6.h>
+
+enum {
+ SEG6_LOCAL_UNSPEC,
+ SEG6_LOCAL_ACTION,
+ SEG6_LOCAL_SRH,
+ SEG6_LOCAL_TABLE,
+ SEG6_LOCAL_NH4,
+ SEG6_LOCAL_NH6,
+ SEG6_LOCAL_IIF,
+ SEG6_LOCAL_OIF,
+ SEG6_LOCAL_BPF,
+ __SEG6_LOCAL_MAX,
+};
+#define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
+
+enum {
+ SEG6_LOCAL_ACTION_UNSPEC = 0,
+ /* node segment */
+ SEG6_LOCAL_ACTION_END = 1,
+ /* adjacency segment (IPv6 cross-connect) */
+ SEG6_LOCAL_ACTION_END_X = 2,
+ /* lookup of next seg NH in table */
+ SEG6_LOCAL_ACTION_END_T = 3,
+ /* decap and L2 cross-connect */
+ SEG6_LOCAL_ACTION_END_DX2 = 4,
+ /* decap and IPv6 cross-connect */
+ SEG6_LOCAL_ACTION_END_DX6 = 5,
+ /* decap and IPv4 cross-connect */
+ SEG6_LOCAL_ACTION_END_DX4 = 6,
+ /* decap and lookup of DA in v6 table */
+ SEG6_LOCAL_ACTION_END_DT6 = 7,
+ /* decap and lookup of DA in v4 table */
+ SEG6_LOCAL_ACTION_END_DT4 = 8,
+ /* binding segment with insertion */
+ SEG6_LOCAL_ACTION_END_B6 = 9,
+ /* binding segment with encapsulation */
+ SEG6_LOCAL_ACTION_END_B6_ENCAP = 10,
+ /* binding segment with MPLS encap */
+ SEG6_LOCAL_ACTION_END_BM = 11,
+ /* lookup last seg in table */
+ SEG6_LOCAL_ACTION_END_S = 12,
+ /* forward to SR-unaware VNF with static proxy */
+ SEG6_LOCAL_ACTION_END_AS = 13,
+ /* forward to SR-unaware VNF with masquerading */
+ SEG6_LOCAL_ACTION_END_AM = 14,
+ /* custom BPF action */
+ SEG6_LOCAL_ACTION_END_BPF = 15,
+
+ __SEG6_LOCAL_ACTION_MAX,
+};
+
+#define SEG6_LOCAL_ACTION_MAX (__SEG6_LOCAL_ACTION_MAX - 1)
+
+enum {
+ SEG6_LOCAL_BPF_PROG_UNSPEC,
+ SEG6_LOCAL_BPF_PROG,
+ SEG6_LOCAL_BPF_PROG_NAME,
+ __SEG6_LOCAL_BPF_PROG_MAX,
+};
+
+#define SEG6_LOCAL_BPF_PROG_MAX (__SEG6_LOCAL_BPF_PROG_MAX - 1)
+
+#endif
diff --git a/include/subdir.am b/include/subdir.am
index b1ca1be54f..86129c4d68 100644
--- a/include/subdir.am
+++ b/include/subdir.am
@@ -11,4 +11,9 @@ noinst_HEADERS += \
include/linux/socket.h \
include/linux/net_namespace.h \
include/linux/fib_rules.h \
+ include/linux/seg6.h \
+ include/linux/seg6_genl.h \
+ include/linux/seg6_hmac.h \
+ include/linux/seg6_iptunnel.h \
+ include/linux/seg6_local.h \
# end
diff --git a/lib/agentx.c b/lib/agentx.c
index 2c6a43d1a7..b479b5ea4c 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -55,28 +55,42 @@ static int agentx_timeout(struct thread *t)
static int agentx_read(struct thread *t)
{
fd_set fds;
- int flags;
+ int flags, new_flags = 0;
int nonblock = false;
struct listnode *ln = THREAD_ARG(t);
list_delete_node(events, ln);
/* fix for non blocking socket */
flags = fcntl(THREAD_FD(t), F_GETFL, 0);
- if (-1 == flags)
+ if (-1 == flags) {
+ flog_err(EC_LIB_SYSTEM_CALL, "Failed to get FD settings fcntl: %s(%d)",
+ strerror(errno), errno);
return -1;
+ }
if (flags & O_NONBLOCK)
nonblock = true;
else
- fcntl(THREAD_FD(t), F_SETFL, flags | O_NONBLOCK);
+ new_flags = fcntl(THREAD_FD(t), F_SETFL, flags | O_NONBLOCK);
+
+ if (new_flags == -1)
+ flog_err(EC_LIB_SYSTEM_CALL, "Failed to set snmp fd non blocking: %s(%d)",
+ strerror(errno), errno);
FD_ZERO(&fds);
FD_SET(THREAD_FD(t), &fds);
snmp_read(&fds);
/* Reset the flag */
- if (!nonblock)
- fcntl(THREAD_FD(t), F_SETFL, flags);
+ if (!nonblock) {
+ new_flags = fcntl(THREAD_FD(t), F_SETFL, flags);
+
+ if (new_flags == -1)
+ flog_err(
+ EC_LIB_SYSTEM_CALL,
+ "Failed to set snmp fd back to original settings: %s(%d)",
+ strerror(errno), errno);
+ }
netsnmp_check_outstanding_agent_requests();
agentx_events_update();
diff --git a/lib/log.c b/lib/log.c
index 3bb01a3f6e..7bf16a8212 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -1093,7 +1093,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_VXLAN_SG_DEL),
DESC_ENTRY(ZEBRA_VXLAN_SG_REPLAY),
DESC_ENTRY(ZEBRA_ERROR),
-};
+ DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES)};
#undef DESC_ENTRY
static const struct zebra_desc_table unknown = {0, "unknown", '?'};
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index d1a31ae35f..4d4376250f 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -371,7 +371,7 @@ int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *))
void ns_disable(struct ns *ns)
{
- return ns_disable_internal(ns);
+ ns_disable_internal(ns);
}
struct ns *ns_lookup(ns_id_t ns_id)
diff --git a/lib/srv6.c b/lib/srv6.c
new file mode 100644
index 0000000000..be340f13f5
--- /dev/null
+++ b/lib/srv6.c
@@ -0,0 +1,116 @@
+/*
+ * SRv6 definitions
+ * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "srv6.h"
+#include "log.h"
+
+const char *seg6local_action2str(uint32_t action)
+{
+ switch (action) {
+ case ZEBRA_SEG6_LOCAL_ACTION_END:
+ return "End";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_X:
+ return "End.X";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_T:
+ return "End.T";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
+ return "End.DX2";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
+ return "End.DX6";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
+ return "End.DX4";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
+ return "End.DT6";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
+ return "End.DT4";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
+ return "End.B6";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
+ return "End.B6.Encap";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
+ return "End.BM";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_S:
+ return "End.S";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
+ return "End.AS";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
+ return "End.AM";
+ case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
+ return "unspec";
+ default:
+ return "unknown";
+ }
+}
+
+int snprintf_seg6_segs(char *str,
+ size_t size, const struct seg6_segs *segs)
+{
+ str[0] = '\0';
+ for (size_t i = 0; i < segs->num_segs; i++) {
+ char addr[INET6_ADDRSTRLEN];
+ bool not_last = (i + 1) < segs->num_segs;
+
+ inet_ntop(AF_INET6, &segs->segs[i], addr, sizeof(addr));
+ strlcat(str, addr, size);
+ strlcat(str, not_last ? "," : "", size);
+ }
+ return strlen(str);
+}
+
+const char *seg6local_context2str(char *str, size_t size,
+ struct seg6local_context *ctx, uint32_t action)
+{
+ char b0[128];
+
+ switch (action) {
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END:
+ snprintf(str, size, "USP");
+ return str;
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END_X:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
+ inet_ntop(AF_INET6, &ctx->nh6, b0, 128);
+ snprintf(str, size, "nh6 %s", b0);
+ return str;
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
+ inet_ntop(AF_INET, &ctx->nh4, b0, 128);
+ snprintf(str, size, "nh4 %s", b0);
+ return str;
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END_T:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
+ snprintf(str, size, "table %u", ctx->table);
+ return str;
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_S:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
+ case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
+ default:
+ snprintf(str, size, "unknown(%s)", __func__);
+ return str;
+ }
+}
diff --git a/lib/srv6.h b/lib/srv6.h
new file mode 100644
index 0000000000..24c7ffc3a2
--- /dev/null
+++ b/lib/srv6.h
@@ -0,0 +1,133 @@
+/*
+ * SRv6 definitions
+ * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_SRV6_H
+#define _FRR_SRV6_H
+
+#include <zebra.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define SRV6_MAX_SIDS 16
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define sid2str(sid, str, size) \
+ inet_ntop(AF_INET6, sid, str, size)
+
+enum seg6_mode_t {
+ INLINE,
+ ENCAP,
+ L2ENCAP,
+};
+
+enum seg6local_action_t {
+ ZEBRA_SEG6_LOCAL_ACTION_UNSPEC = 0,
+ ZEBRA_SEG6_LOCAL_ACTION_END = 1,
+ ZEBRA_SEG6_LOCAL_ACTION_END_X = 2,
+ ZEBRA_SEG6_LOCAL_ACTION_END_T = 3,
+ ZEBRA_SEG6_LOCAL_ACTION_END_DX2 = 4,
+ ZEBRA_SEG6_LOCAL_ACTION_END_DX6 = 5,
+ ZEBRA_SEG6_LOCAL_ACTION_END_DX4 = 6,
+ ZEBRA_SEG6_LOCAL_ACTION_END_DT6 = 7,
+ ZEBRA_SEG6_LOCAL_ACTION_END_DT4 = 8,
+ ZEBRA_SEG6_LOCAL_ACTION_END_B6 = 9,
+ ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP = 10,
+ ZEBRA_SEG6_LOCAL_ACTION_END_BM = 11,
+ ZEBRA_SEG6_LOCAL_ACTION_END_S = 12,
+ ZEBRA_SEG6_LOCAL_ACTION_END_AS = 13,
+ ZEBRA_SEG6_LOCAL_ACTION_END_AM = 14,
+ ZEBRA_SEG6_LOCAL_ACTION_END_BPF = 15,
+};
+
+struct seg6_segs {
+ size_t num_segs;
+ struct in6_addr segs[256];
+};
+
+struct seg6local_context {
+ struct in_addr nh4;
+ struct in6_addr nh6;
+ uint32_t table;
+};
+
+static inline const char *seg6_mode2str(enum seg6_mode_t mode)
+{
+ switch (mode) {
+ case INLINE:
+ return "INLINE";
+ case ENCAP:
+ return "ENCAP";
+ case L2ENCAP:
+ return "L2ENCAP";
+ default:
+ return "unknown";
+ }
+}
+
+static inline bool sid_same(
+ const struct in6_addr *a,
+ const struct in6_addr *b)
+{
+ if (!a && !b)
+ return true;
+ else if (!(a && b))
+ return false;
+ else
+ return memcmp(a, b, sizeof(struct in6_addr)) == 0;
+}
+
+static inline bool sid_diff(
+ const struct in6_addr *a,
+ const struct in6_addr *b)
+{
+ return !sid_same(a, b);
+}
+
+static inline bool sid_zero(
+ const struct in6_addr *a)
+{
+ struct in6_addr zero = {};
+
+ return sid_same(a, &zero);
+}
+
+static inline void *sid_copy(struct in6_addr *dst,
+ const struct in6_addr *src)
+{
+ return memcpy(dst, src, sizeof(struct in6_addr));
+}
+
+const char *
+seg6local_action2str(uint32_t action);
+
+const char *
+seg6local_context2str(char *str, size_t size,
+ struct seg6local_context *ctx, uint32_t action);
+
+int snprintf_seg6_segs(char *str,
+ size_t size, const struct seg6_segs *segs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/subdir.am b/lib/subdir.am
index cb6fa7a3b8..d804d839db 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -51,6 +51,7 @@ lib_libfrr_la_SOURCES = \
lib/mlag.c \
lib/module.c \
lib/mpls.c \
+ lib/srv6.c \
lib/network.c \
lib/nexthop.c \
lib/netns_linux.c \
@@ -193,6 +194,7 @@ pkginclude_HEADERS += \
lib/module.h \
lib/monotime.h \
lib/mpls.h \
+ lib/srv6.h \
lib/network.h \
lib/nexthop.h \
lib/nexthop_group.h \
diff --git a/lib/zclient.c b/lib/zclient.c
index 7ddf0085de..d879063460 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -3300,31 +3300,71 @@ void zclient_interface_set_master(struct zclient *client,
zclient_send_message(client);
}
-/* Process capabilities message from zebra */
-int zapi_capabilities_decode(struct stream *s, struct zapi_cap *api)
+/*
+ * Send capabilities message to zebra
+ */
+int32_t zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
+ struct zapi_cap *api)
{
+
+ struct stream *s;
+
+ if (zclient == NULL)
+ return -1;
+
+ s = zclient->obuf;
+ stream_reset(s);
+ zclient_create_header(s, cmd, 0);
+ stream_putl(s, api->cap);
+
+ switch (api->cap) {
+ case ZEBRA_CLIENT_GR_CAPABILITIES:
+ case ZEBRA_CLIENT_RIB_STALE_TIME:
+ stream_putl(s, api->stale_removal_time);
+ stream_putl(s, api->vrf_id);
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+ case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+ stream_putl(s, api->afi);
+ stream_putl(s, api->safi);
+ stream_putl(s, api->vrf_id);
+ break;
+ case ZEBRA_CLIENT_GR_DISABLE:
+ stream_putl(s, api->vrf_id);
+ break;
+ }
+
+ /* Put length at the first point of the stream */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return zclient_send_message(zclient);
+}
+
+/*
+ * Process capabilities message from zebra
+ */
+int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api)
+{
+
memset(api, 0, sizeof(*api));
STREAM_GETL(s, api->cap);
switch (api->cap) {
case ZEBRA_CLIENT_GR_CAPABILITIES:
case ZEBRA_CLIENT_RIB_STALE_TIME:
- STREAM_GETL(s, api->stale_removal_time);
- STREAM_GETL(s, api->vrf_id);
- break;
+ STREAM_GETL(s, api->stale_removal_time);
+ STREAM_GETL(s, api->vrf_id);
+ break;
case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
- STREAM_GETL(s, api->afi);
- STREAM_GETL(s, api->safi);
- STREAM_GETL(s, api->vrf_id);
- break;
+ STREAM_GETL(s, api->afi);
+ STREAM_GETL(s, api->safi);
+ STREAM_GETL(s, api->vrf_id);
+ break;
case ZEBRA_CLIENT_GR_DISABLE:
- STREAM_GETL(s, api->vrf_id);
- break;
- default:
- break;
+ STREAM_GETL(s, api->vrf_id);
+ break;
}
-
stream_failure:
return 0;
}
diff --git a/lib/zclient.h b/lib/zclient.h
index bbc70c3835..9a230d3f34 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -73,13 +73,17 @@ typedef uint16_t zebra_size_t;
#define ZEBRA_FEC_REGISTER_LABEL 0x1
#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x2
-/* Client Graceful Restart */
-#define ZEBRA_CLIENT_GR_CAPABILITIES 0x1
-#define ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE 0x2
-#define ZEBRA_CLIENT_ROUTE_UPDATE_PENDING 0x3
-#define ZEBRA_CLIENT_GR_DISABLE 0x4
-#define ZEBRA_CLIENT_RIB_STALE_TIME 0x5
-#define ZEBRA_CLIENT_GR_ENABLED(X) (X & ZEBRA_CLIENT_GR_CAPABILITIES)
+/* Client capabilities */
+enum zserv_client_capabilities {
+ ZEBRA_CLIENT_GR_CAPABILITIES = 1,
+ ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE = 2,
+ ZEBRA_CLIENT_ROUTE_UPDATE_PENDING = 3,
+ ZEBRA_CLIENT_GR_DISABLE = 4,
+ ZEBRA_CLIENT_RIB_STALE_TIME
+};
+
+/* Macro to check if there GR enabled. */
+#define ZEBRA_CLIENT_GR_ENABLED(X) (X == ZEBRA_CLIENT_GR_CAPABILITIES)
extern struct sockaddr_storage zclient_addr;
extern socklen_t zclient_addr_len;
@@ -196,7 +200,7 @@ typedef enum {
} zebra_message_types_t;
enum zebra_error_types {
- ZEBRA_UNKNOWN_ERROR, /* Error of unknown type */
+ ZEBRA_UNKNOWN_ERROR, /* Error of unknown type */
ZEBRA_NO_VRF, /* Vrf in header was not found */
ZEBRA_INVALID_MSG_TYPE, /* No handler found for msg type */
};
@@ -233,11 +237,11 @@ struct zclient_capabilities {
/* Graceful Restart Capabilities message */
struct zapi_cap {
- uint32_t cap;
- uint32_t stale_removal_time;
- afi_t afi;
- safi_t safi;
- vrf_id_t vrf_id;
+ enum zserv_client_capabilities cap;
+ uint32_t stale_removal_time;
+ afi_t afi;
+ safi_t safi;
+ vrf_id_t vrf_id;
};
/* Structure for the zebra client. */
@@ -777,6 +781,11 @@ extern bool zapi_nexthop_update_decode(struct stream *s,
/* Decode the zebra error message */
extern bool zapi_error_decode(struct stream *s, enum zebra_error_types *error);
+/* Encode and decode restart capabilities */
+extern int32_t zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
+ struct zapi_cap *api);
+extern int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api);
+
static inline void zapi_route_set_blackhole(struct zapi_route *api,
enum blackhole_type bh_type)
{
@@ -794,7 +803,4 @@ extern void zclient_send_mlag_deregister(struct zclient *client);
extern void zclient_send_mlag_data(struct zclient *client,
struct stream *client_s);
-extern int zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
- struct zapi_cap *api);
-extern int zapi_capabilities_decode(struct stream *s, struct zapi_cap *api);
#endif /* _ZEBRA_ZCLIENT_H */
diff --git a/scripts/coccinelle/shorthand_operator.cocci b/scripts/coccinelle/shorthand_operator.cocci
new file mode 100644
index 0000000000..f7019d4040
--- /dev/null
+++ b/scripts/coccinelle/shorthand_operator.cocci
@@ -0,0 +1,12 @@
+@@
+identifier data;
+constant x;
+@@
+
+(
+- data = data + x
++ data += x
+|
+- data = data - x
++ data -= x
+)
diff --git a/scripts/coccinelle/void_no_return.cocci b/scripts/coccinelle/void_no_return.cocci
new file mode 100644
index 0000000000..7da9e73933
--- /dev/null
+++ b/scripts/coccinelle/void_no_return.cocci
@@ -0,0 +1,9 @@
+@@
+identifier f;
+expression e;
+@@
+void f(...) {
+ ...
+- return
+ e;
+}
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index c2812aa47b..7cdd6ef84e 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -556,7 +556,7 @@ int ifm_read(struct if_msghdr *ifm)
* is 12 bytes larger than the 32 bit version.
*/
if (((struct sockaddr *)cp)->sa_family == AF_UNSPEC)
- cp = cp + 12;
+ cp += 12;
#endif
/* Look up for RTA_IFP and skip others. */
diff --git a/zebra/main.c b/zebra/main.c
index 75f825e507..f23702d878 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -151,6 +151,10 @@ static void sigint(void)
zebra_dplane_pre_finish();
+ /* Clean up GR related info. */
+ zebra_gr_stale_client_cleanup(zrouter.stale_client_list);
+ list_delete_all_node(zrouter.stale_client_list);
+
for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client))
zserv_close_client(client);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index fe1c26a34f..b1c679e066 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -75,6 +75,10 @@
static vlanid_t filter_vlan = 0;
+/* We capture whether the current kernel supports nexthop ids; by
+ * default, we'll use them if possible. There's also a configuration
+ * available to _disable_ use of kernel nexthops.
+ */
static bool supports_nh;
struct gw_family_t {
@@ -86,6 +90,12 @@ struct gw_family_t {
static const char ipv4_ll_buf[16] = "169.254.0.1";
static struct in_addr ipv4_ll;
+/* Helper to control use of kernel-level nexthop ids */
+static bool kernel_nexthops_supported(void)
+{
+ return (supports_nh && zebra_nhg_kernel_nexthops_enabled());
+}
+
/*
* The ipv4_ll data structure is used for all 5549
* additions to the kernel. Let's figure out the
@@ -1628,7 +1638,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
RTA_PAYLOAD(rta));
}
- if (supports_nh) {
+ if (kernel_nexthops_supported()) {
/* Kernel supports nexthop objects */
addattr32(&req.n, sizeof(req), RTA_NH_ID,
dplane_ctx_get_nhe_id(ctx));
@@ -1943,7 +1953,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
size_t req_size = sizeof(req);
/* Nothing to do if the kernel doesn't support nexthop objects */
- if (!supports_nh)
+ if (!kernel_nexthops_supported())
return 0;
label_buf[0] = '\0';
@@ -2504,8 +2514,10 @@ int netlink_nexthop_read(struct zebra_ns *zns)
* this kernel must support them.
*/
supports_nh = true;
- else if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Nexthop objects not supported on this kernel");
+
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
+ zlog_debug("Nexthop objects %ssupported on this kernel",
+ supports_nh ? "" : "not ");
return ret;
}
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 77ed5a6caa..1d49de5410 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -17,6 +17,7 @@ vtysh_scan += \
$(top_srcdir)/zebra/zebra_routemap.c \
$(top_srcdir)/zebra/zebra_vty.c \
$(top_srcdir)/zebra/zserv.c \
+ $(top_srcdir)/zebra/zebra_gr.c \
# end
# can be loaded as DSO - always include for vtysh
@@ -101,6 +102,7 @@ zebra_zebra_SOURCES = \
zebra/table_manager.c \
zebra/zapi_msg.c \
zebra/zebra_errors.c \
+ zebra/zebra_gr.c \
# end
zebra/debug_clippy.c: $(CLIPPY_DEPS)
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 4fa7a3c164..4d0e34561a 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1775,6 +1775,8 @@ static void zread_hello(ZAPI_HANDLER_ARGS)
client->instance = instance;
}
+ /* Graceful restart processing for client connect */
+ zebra_gr_client_reconnect(client);
zsend_capabilities(client, zvrf);
zebra_vrf_update_all(client);
stream_failure:
@@ -2584,14 +2586,14 @@ static void zserv_error_no_vrf(ZAPI_HANDLER_ARGS)
zlog_debug("ZAPI message specifies unknown VRF: %d",
hdr->vrf_id);
- return zsend_error_msg(client, ZEBRA_NO_VRF, hdr);
+ zsend_error_msg(client, ZEBRA_NO_VRF, hdr);
}
static void zserv_error_invalid_msg_type(ZAPI_HANDLER_ARGS)
{
zlog_info("Zebra received unknown command %d", hdr->command);
- return zsend_error_msg(client, ZEBRA_INVALID_MSG_TYPE, hdr);
+ zsend_error_msg(client, ZEBRA_INVALID_MSG_TYPE, hdr);
}
void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
@@ -2668,6 +2670,7 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_MLAG_CLIENT_REGISTER] = zebra_mlag_client_register,
[ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister,
[ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg,
+ [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities
};
#if defined(HANDLE_ZAPI_FUZZING)
diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c
new file mode 100644
index 0000000000..e8c7304f44
--- /dev/null
+++ b/zebra/zebra_gr.c
@@ -0,0 +1,684 @@
+/*
+ * Zebra GR related helper functions.
+ *
+ * Portions:
+ * Copyright (C) 2019 VMware, Inc.
+ * et al.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include <libgen.h>
+
+#include "lib/prefix.h"
+#include "lib/command.h"
+#include "lib/if.h"
+#include "lib/thread.h"
+#include "lib/stream.h"
+#include "lib/memory.h"
+#include "lib/table.h"
+#include "lib/network.h"
+#include "lib/sockunion.h"
+#include "lib/log.h"
+#include "lib/zclient.h"
+#include "lib/privs.h"
+#include "lib/network.h"
+#include "lib/buffer.h"
+#include "lib/nexthop.h"
+#include "lib/vrf.h"
+#include "lib/libfrr.h"
+#include "lib/sockopt.h"
+
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
+#include "zebra/zapi_msg.h"
+
+
+/*
+ * Forward declaration.
+ */
+static struct zserv *zebra_gr_find_stale_client(struct zserv *client);
+static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread);
+static int32_t zebra_gr_delete_stale_routes(struct client_gr_info *info);
+static void zebra_gr_process_client_stale_routes(struct zserv *client,
+ vrf_id_t vrf_id);
+
+/*
+ * Debug macros.
+ */
+#define LOG_GR(msg, ...) \
+ do { \
+ if (IS_ZEBRA_DEBUG_EVENT) \
+ zlog_debug(msg, ##__VA_ARGS__); \
+ } while (0)
+
+
+/*
+ * Client connection functions
+ */
+
+/*
+ * Function to clean all the stale clients,
+ * function will also clean up all per instance
+ * capabilities that are exchanged.
+ */
+void zebra_gr_stale_client_cleanup(struct list *client_list)
+{
+ struct listnode *node, *nnode;
+ struct zserv *s_client = NULL;
+ struct client_gr_info *info, *ninfo;
+
+ /* Find the stale client */
+ for (ALL_LIST_ELEMENTS(client_list, node, nnode, s_client)) {
+
+ LOG_GR("%s: Stale client %s is being deleted", __func__,
+ zebra_route_string(s_client->proto));
+
+ TAILQ_FOREACH_SAFE (info, &s_client->gr_info_queue, gr_info,
+ ninfo) {
+
+ /* Cancel the stale timer */
+ if (info->t_stale_removal != NULL) {
+ THREAD_OFF(info->t_stale_removal);
+ info->t_stale_removal = NULL;
+ /* Process the stale routes */
+ thread_execute(
+ zrouter.master,
+ zebra_gr_route_stale_delete_timer_expiry,
+ info, 1);
+ }
+ }
+ }
+}
+
+/*
+ * A helper function to create client info.
+ */
+static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client)
+{
+ struct client_gr_info *info;
+
+ info = XCALLOC(MTYPE_TMP, sizeof(struct client_gr_info));
+
+ TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info);
+ return info;
+}
+
+/*
+ * A helper function to delte and destory client info.
+ */
+static void zebra_gr_client_info_delte(struct zserv *client,
+ struct client_gr_info *info)
+{
+ TAILQ_REMOVE(&(client->gr_info_queue), info, gr_info);
+
+ THREAD_OFF(info->t_stale_removal);
+
+ if (info->current_prefix)
+ XFREE(MTYPE_TMP, info->current_prefix);
+
+ LOG_GR("%s: Instance info is being deleted for client %s", __func__,
+ zebra_route_string(client->proto));
+
+ /* Delete all the stale routes. */
+ info->delete = true;
+ zebra_gr_delete_stale_routes(info);
+
+ XFREE(MTYPE_TMP, info);
+}
+
+/*
+ * Function to handle client when it disconnect.
+ */
+int32_t zebra_gr_client_disconnect(struct zserv *client)
+{
+ struct zserv *stale_client;
+ struct timeval tv;
+ struct client_gr_info *info = NULL;
+
+ /* Find the stale client */
+ stale_client = zebra_gr_find_stale_client(client);
+
+ /*
+ * We should never be here.
+ */
+ if (stale_client) {
+ LOG_GR("%s: Stale client %s exist, we should not be here!",
+ __func__, zebra_route_string(client->proto));
+ assert(0);
+ }
+
+ client->restart_time = monotime(&tv);
+
+ /* For all the GR instance start the starle removal timer. */
+ TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+ if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)
+ && (info->t_stale_removal == NULL)) {
+ thread_add_timer(
+ zrouter.master,
+ zebra_gr_route_stale_delete_timer_expiry, info,
+ info->stale_removal_time,
+ &info->t_stale_removal);
+ info->current_afi = AFI_IP;
+ info->stale_client_ptr = client;
+ info->stale_client = true;
+ LOG_GR("%s: Client %s Stale timer update to %d",
+ __func__, zebra_route_string(client->proto),
+ info->stale_removal_time);
+ }
+ }
+
+ listnode_add(zrouter.stale_client_list, client);
+
+ return 0;
+}
+
+/*
+ * Function to delete stale client
+ */
+static void zebra_gr_delete_stale_client(struct client_gr_info *info)
+{
+ struct client_gr_info *bgp_info;
+ struct zserv *s_client = NULL;
+
+ s_client = info->stale_client_ptr;
+
+ if (!s_client || !info->stale_client)
+ return;
+
+ /*
+ * If there are bgp instances with the stale delete timer pending
+ * then stale client is not deleted
+ */
+ if ((s_client->gr_instance_count > 0) && info->gr_enable)
+ s_client->gr_instance_count--;
+
+ TAILQ_REMOVE(&(s_client->gr_info_queue), info, gr_info);
+
+ LOG_GR("%s: Client %s gr count %d", __func__,
+ zebra_route_string(s_client->proto),
+ s_client->gr_instance_count);
+
+ TAILQ_FOREACH (bgp_info, &s_client->gr_info_queue, gr_info) {
+ if (bgp_info->t_stale_removal != NULL)
+ return;
+ }
+
+ LOG_GR("%s: Client %s is being deleted", __func__,
+ zebra_route_string(s_client->proto));
+
+ TAILQ_INIT(&(s_client->gr_info_queue));
+ listnode_delete(zrouter.stale_client_list, s_client);
+ if (info->stale_client)
+ XFREE(MTYPE_TMP, s_client);
+ XFREE(MTYPE_TMP, info);
+}
+
+/*
+ * Function to find stale client.
+ */
+static struct zserv *zebra_gr_find_stale_client(struct zserv *client)
+{
+ struct listnode *node, *nnode;
+ struct zserv *stale_client;
+
+ /* Find the stale client */
+ for (ALL_LIST_ELEMENTS(zrouter.stale_client_list, node, nnode,
+ stale_client)) {
+ if (client->proto == stale_client->proto
+ && client->instance == stale_client->instance) {
+ return stale_client;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Function to handle reconnect of client post restart.
+ */
+void zebra_gr_client_reconnect(struct zserv *client)
+{
+ struct listnode *node, *nnode;
+ struct zserv *old_client = NULL;
+ struct client_gr_info *info = NULL;
+
+ /* Find the stale client */
+ for (ALL_LIST_ELEMENTS(zrouter.stale_client_list, node, nnode,
+ old_client)) {
+ if (client->proto == old_client->proto
+ && client->instance == old_client->instance)
+ break;
+ }
+
+ /* Copy the timers */
+ if (old_client) {
+ client->gr_instance_count = old_client->gr_instance_count;
+ client->restart_time = old_client->restart_time;
+
+ LOG_GR("%s : old client %s, gr_instance_count %d", __func__,
+ zebra_route_string(old_client->proto),
+ old_client->gr_instance_count);
+
+ if (TAILQ_FIRST(&old_client->gr_info_queue)) {
+ TAILQ_CONCAT(&client->gr_info_queue,
+ &old_client->gr_info_queue, gr_info);
+ TAILQ_INIT(&old_client->gr_info_queue);
+ }
+
+ TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+ info->stale_client_ptr = client;
+ info->stale_client = false;
+ }
+
+ /* Delete the stale client */
+ listnode_delete(zrouter.stale_client_list, old_client);
+ /* Delete old client */
+ XFREE(MTYPE_TMP, old_client);
+ }
+}
+
+/*
+ * Functions to deal with capabilities
+ */
+
+/*
+ * Update the graceful restart information
+ * for the client instance.
+ * This function handles all the capabilties that are received.
+ */
+static void zebra_client_update_info(struct zserv *client, struct zapi_cap *api)
+{
+ struct client_gr_info *info = NULL;
+
+ /* Find the bgp information for the specified vrf id */
+ TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+ if (info->vrf_id == api->vrf_id)
+ break;
+ }
+
+
+ /*
+ * If the command is delete, then cancel the stale timer and
+ * delete the bgp info
+ */
+ switch (api->cap) {
+ case ZEBRA_CLIENT_GR_DISABLE:
+ if (!info)
+ return;
+
+ LOG_GR("%s: Client %s instance GR disabled count %d", __func__,
+ zebra_route_string(client->proto),
+ client->gr_instance_count);
+
+ if ((info->gr_enable) && (client->gr_instance_count > 0))
+ client->gr_instance_count--;
+
+ zebra_gr_client_info_delte(client, info);
+ break;
+ case ZEBRA_CLIENT_GR_CAPABILITIES:
+ /* Allocate bgp info */
+ if (!info)
+ info = zebra_gr_client_info_create(client);
+
+ /* Udpate other parameters */
+ if (!info->gr_enable) {
+ client->gr_instance_count++;
+
+ LOG_GR("%s: Cient %s GR enabled count %d", __func__,
+ zebra_route_string(client->proto),
+ client->gr_instance_count);
+
+ info->capabilities = api->cap;
+ info->stale_removal_time = api->stale_removal_time;
+ info->vrf_id = api->vrf_id;
+ info->gr_enable = true;
+ }
+ break;
+ case ZEBRA_CLIENT_RIB_STALE_TIME:
+ LOG_GR("%s: Client %s stale time update event", __func__,
+ zebra_route_string(client->proto));
+
+ /* Update the stale removal timer */
+ if (info && info->t_stale_removal == NULL) {
+
+ LOG_GR("%s: Stale time: %d is now update to: %d",
+ __func__, info->stale_removal_time,
+ api->stale_removal_time);
+
+ info->stale_removal_time = api->stale_removal_time;
+ }
+
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+ LOG_GR(
+ "%s: Client %s route update complete for AFI %d, SAFI %d",
+ __func__, zebra_route_string(client->proto), api->afi,
+ api->safi);
+ if (info)
+ info->route_sync[api->afi][api->safi] = true;
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+ LOG_GR("%s: Client %s route update pending for AFI %d, SAFI %d",
+ __func__, zebra_route_string(client->proto), api->afi,
+ api->safi);
+ if (info)
+ info->af_enabled[api->afi][api->safi] = true;
+ break;
+ }
+}
+
+/*
+ * Handler for capabilities that are received from client.
+ */
+static void zebra_client_capabilities_handler(struct zserv *client,
+ struct zapi_cap *api)
+{
+ switch (api->cap) {
+ case ZEBRA_CLIENT_GR_CAPABILITIES:
+ case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+ case ZEBRA_CLIENT_GR_DISABLE:
+ case ZEBRA_CLIENT_RIB_STALE_TIME:
+ /*
+ * For all the cases we need to update the client info.
+ */
+ zebra_client_update_info(client, api);
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+ /*
+ * After client info has been updated delete all
+ * stale routes
+ */
+ zebra_client_update_info(client, api);
+ zebra_gr_process_client_stale_routes(client, api->vrf_id);
+ break;
+ }
+}
+
+/*
+ * Function to decode and call appropriate functions
+ * to handle client capabilities.
+ */
+void zread_client_capabilities(ZAPI_HANDLER_ARGS)
+{
+ struct zapi_cap api;
+ struct stream *s;
+
+ s = msg;
+
+ if (zapi_capabilities_decode(s, &api)) {
+ LOG_GR("%s: Error in reading capabilities for client %s",
+ __func__, zebra_route_string(client->proto));
+ return;
+ }
+
+ /* Call the capabilities handler */
+ zebra_client_capabilities_handler(client, &api);
+}
+
+
+/*
+ * Stale route handling
+ */
+
+/*
+ * Delete all the stale routes that have not been refreshed
+ * post restart.
+ */
+static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread)
+{
+ struct client_gr_info *info;
+ int32_t cnt = 0;
+ struct zserv *client;
+
+ info = THREAD_ARG(thread);
+ info->t_stale_removal = NULL;
+ client = (struct zserv *)info->stale_client_ptr;
+
+ /* Set the flag to indicate all stale route deletion */
+ if (thread->u.val == 1)
+ info->delete = true;
+
+ cnt = zebra_gr_delete_stale_routes(info);
+
+ /* Retsart the timer */
+ if (cnt > 0) {
+ LOG_GR("%s: Client %s processed %d routes. Start timer again",
+ __func__, zebra_route_string(client->proto), cnt);
+
+ thread_add_timer(zrouter.master,
+ zebra_gr_route_stale_delete_timer_expiry, info,
+ ZEBRA_DEFAULT_STALE_UPDATE_DELAY,
+ &info->t_stale_removal);
+ } else {
+ /* No routes to delete for the VRF */
+ LOG_GR("%s: Client %s all starle routes processed", __func__,
+ zebra_route_string(client->proto));
+
+ if (info->current_prefix != NULL)
+ XFREE(MTYPE_TMP, info->current_prefix);
+ info->current_prefix = NULL;
+ info->current_afi = 0;
+ zebra_gr_delete_stale_client(info);
+ }
+ return 0;
+}
+
+
+/*
+ * Function to process to check if route entry is stale
+ * or has been updated.
+ */
+static void zebra_gr_process_route_entry(struct zserv *client,
+ struct route_node *rn,
+ struct route_entry *re)
+{
+ char buf[PREFIX2STR_BUFFER];
+
+ if ((client == NULL) || (rn == NULL) || (re == NULL))
+ return;
+
+ /* If the route is not refreshed after restart, delete the entry */
+ if (re->uptime < client->restart_time) {
+ if (IS_ZEBRA_DEBUG_RIB) {
+ prefix2str(&rn->p, buf, sizeof(buf));
+ zlog_debug("%s: Client %s stale route %s is deleted",
+ __func__, zebra_route_string(client->proto),
+ buf);
+ }
+ rib_delnode(rn, re);
+ }
+}
+
+/*
+ * This function walks through the route table for all vrf and deletes
+ * the stale routes for the restarted client specified by the protocol
+ * type
+ */
+static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info,
+ struct zebra_vrf *zvrf)
+{
+ struct route_node *rn, *curr;
+ struct route_entry *re;
+ struct route_entry *next;
+ struct route_table *table;
+ int32_t n = 0;
+ struct prefix *p;
+ afi_t afi, curr_afi;
+ uint8_t proto;
+ uint16_t instance;
+ struct zserv *s_client;
+
+ if ((info == NULL) || (zvrf == NULL))
+ return -1;
+
+ s_client = info->stale_client_ptr;
+ if (s_client == NULL) {
+ LOG_GR("%s: Stale client not present", __func__);
+ return -1;
+ }
+
+ proto = s_client->proto;
+ instance = s_client->instance;
+ curr_afi = info->current_afi;
+
+ LOG_GR("%s: Client %s stale routes are being deleted", __func__,
+ zebra_route_string(proto));
+
+ /* Process routes for all AFI */
+ for (afi = curr_afi; afi < AFI_MAX; afi++) {
+ table = zvrf->table[afi][SAFI_UNICAST];
+ p = info->current_prefix;
+
+ if (table) {
+ /*
+ * If the current prefix is NULL then get the first
+ * route entry in the table
+ */
+ if (p == NULL) {
+ rn = route_top(table);
+ if (rn == NULL)
+ continue;
+ p = XCALLOC(MTYPE_TMP, sizeof(struct prefix));
+ if (p == NULL)
+ return -1;
+ curr = rn;
+ prefix_copy(p, &rn->p);
+ } else
+ /* Get the next route entry */
+ curr = route_table_get_next(table, p);
+
+ for (rn = curr; rn; rn = srcdest_route_next(rn)) {
+ RNODE_FOREACH_RE_SAFE (rn, re, next) {
+ if (CHECK_FLAG(re->status,
+ ROUTE_ENTRY_REMOVED))
+ continue;
+ /* If the route refresh is received
+ * after restart then do not delete
+ * the route
+ */
+ if (re->type == proto
+ && re->instance == instance) {
+ zebra_gr_process_route_entry(
+ s_client, rn, re);
+ n++;
+ }
+
+ /* If the max route count is reached
+ * then timer thread will be restarted
+ * Store the current prefix and afi
+ */
+ if ((n >= ZEBRA_MAX_STALE_ROUTE_COUNT)
+ && (info->delete == false)) {
+ prefix_copy(p, &rn->p);
+ info->current_afi = afi;
+ info->current_prefix = p;
+ return n;
+ }
+ }
+ }
+ }
+ /*
+ * Reset the current prefix to indicate processing completion
+ * of the current AFI
+ */
+ if (info->current_prefix) {
+ XFREE(MTYPE_TMP, info->current_prefix);
+ info->current_prefix = NULL;
+ }
+ continue;
+ }
+ return 0;
+}
+
+/*
+ * Delete the stale routes when client is restarted and routes are not
+ * refreshed within the stale timeout
+ */
+static int32_t zebra_gr_delete_stale_routes(struct client_gr_info *info)
+{
+ struct vrf *vrf;
+ struct zebra_vrf *zvrf;
+ uint64_t cnt = 0;
+
+ if (info == NULL)
+ return -1;
+
+ /* Get the current VRF */
+ vrf = vrf_lookup_by_id(info->vrf_id);
+ if (vrf == NULL) {
+ LOG_GR("%s: Invalid VRF %d", __func__, info->vrf_id);
+ return -1;
+ }
+
+ zvrf = vrf->info;
+ if (zvrf == NULL) {
+ LOG_GR("%s: Invalid VRF entry %d", __func__, info->vrf_id);
+ return -1;
+ }
+
+ cnt = zebra_gr_delete_stale_route(info, zvrf);
+ return cnt;
+}
+
+/*
+ * This function checks if route update for all AFI, SAFI is completed
+ * and cancels the stale timer
+ */
+static void zebra_gr_process_client_stale_routes(struct zserv *client,
+ vrf_id_t vrf_id)
+{
+ struct client_gr_info *info = NULL;
+ afi_t afi;
+ safi_t safi;
+
+ TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+ if (info->vrf_id == vrf_id)
+ break;
+ }
+
+ if (info == NULL)
+ return;
+
+ /* Check if route update completed for all AFI, SAFI */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
+ if (info->af_enabled[afi][safi]) {
+ if (!info->route_sync[afi][safi]) {
+ LOG_GR(
+ "%s: Client %s route update not completed for AFI %d, SAFI %d",
+ __func__, zebra_route_string(
+ client->proto),
+ afi, safi);
+ return;
+ }
+ }
+ }
+
+ /*
+ * Route update completed for all AFI, SAFI
+ * Cancel the stale timer and process the routes
+ */
+ if (info->t_stale_removal) {
+ LOG_GR("%s: Client %s cancled stale delete timer vrf %d",
+ __func__, zebra_route_string(client->proto),
+ info->vrf_id);
+ THREAD_OFF(info->t_stale_removal);
+ thread_execute(zrouter.master,
+ zebra_gr_route_stale_delete_timer_expiry, info,
+ 0);
+ }
+}
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index e05db5ffae..bb95e72382 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -49,6 +49,9 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
/* id counter to keep in sync with kernel */
uint32_t id_counter;
+/* */
+static bool g_nexthops_enabled = true;
+
static struct nhg_hash_entry *depends_find(const struct nexthop *nh,
afi_t afi);
static void depends_add(struct nhg_connected_tree_head *head,
@@ -1485,7 +1488,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
* resolved by a route NH1. The exception is if the route is a
* host route.
*/
- if (top && rn == top)
+ if (rn == top)
if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
|| ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
@@ -2028,3 +2031,18 @@ void zebra_nhg_sweep_table(struct hash *hash)
{
hash_iterate(hash, zebra_nhg_sweep_entry, NULL);
}
+
+/* Global control to disable use of kernel nexthops, if available. We can't
+ * force the kernel to support nexthop ids, of course, but we can disable
+ * zebra's use of them, for testing e.g. By default, if the kernel supports
+ * nexthop ids, zebra uses them.
+ */
+void zebra_nhg_enable_kernel_nexthops(bool set)
+{
+ g_nexthops_enabled = set;
+}
+
+bool zebra_nhg_kernel_nexthops_enabled(void)
+{
+ return g_nexthops_enabled;
+}
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index c2e173e094..4d001944b7 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -153,6 +153,13 @@ struct nhg_ctx {
enum nhg_ctx_status status;
};
+/* Global control to disable use of kernel nexthops, if available. We can't
+ * force the kernel to support nexthop ids, of course, but we can disable
+ * zebra's use of them, for testing e.g. By default, if the kernel supports
+ * nexthop ids, zebra uses them.
+ */
+void zebra_nhg_enable_kernel_nexthops(bool set);
+bool zebra_nhg_kernel_nexthops_enabled(void);
/**
* NHE abstracted tree functions.
@@ -227,4 +234,5 @@ extern void zebra_nhg_sweep_table(struct hash *hash);
/* Nexthop resolution processing */
struct route_entry; /* Forward ref to avoid circular includes */
extern int nexthop_active_update(struct route_node *rn, struct route_entry *re);
-#endif
+
+#endif /* __ZEBRA_NHG_H__ */
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index d8ad8a6864..59bd0e55f0 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -117,6 +117,9 @@ struct zebra_router {
/* Lists of clients who have connected to us */
struct list *client_list;
+ /* List of clients in GR */
+ struct list *stale_client_list;
+
struct zebra_router_table_head tables;
/* L3-VNI hash table (for EVPN). Only in default instance */
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 78001da170..86ec2ffef3 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1123,9 +1123,11 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
vty_out(vty, " RefCnt: %d\n", nhe->refcnt);
if (nhe_vrf)
- vty_out(vty, " VRF: %s\n", nhe_vrf->name);
+ vty_out(vty, " VRF: %s AFI: %s\n", nhe_vrf->name,
+ afi2str(nhe->afi));
else
- vty_out(vty, " VRF: UNKNOWN\n");
+ vty_out(vty, " VRF: UNKNOWN AFI: %s\n",
+ afi2str(nhe->afi));
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
vty_out(vty, " Duplicate - from kernel not hashable\n");
@@ -1276,25 +1278,44 @@ static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id)
return CMD_SUCCESS;
}
-static void show_nexthop_group_cmd_helper(struct vty *vty,
- struct zebra_vrf *zvrf, afi_t afi)
+/* Helper function for iteration through the hash of nexthop-groups/nhe-s */
+
+struct nhe_show_context {
+ struct vty *vty;
+ vrf_id_t vrf_id;
+ afi_t afi;
+};
+
+static int nhe_show_walker(struct hash_bucket *bucket, void *arg)
{
- struct list *list = hash_to_list(zrouter.nhgs);
- struct nhg_hash_entry *nhe = NULL;
- struct listnode *node = NULL;
+ struct nhe_show_context *ctx = arg;
+ struct nhg_hash_entry *nhe;
- for (ALL_LIST_ELEMENTS_RO(list, node, nhe)) {
+ nhe = bucket->data; /* We won't be offered NULL buckets */
- if (afi && nhe->afi != afi)
- continue;
+ if (ctx->afi && nhe->afi != ctx->afi)
+ goto done;
- if (nhe->vrf_id != zvrf->vrf->vrf_id)
- continue;
+ if (ctx->vrf_id && nhe->vrf_id != ctx->vrf_id)
+ goto done;
- show_nexthop_group_out(vty, nhe);
- }
+ show_nexthop_group_out(ctx->vty, nhe);
- list_delete(&list);
+done:
+ return HASHWALK_CONTINUE;
+}
+
+static void show_nexthop_group_cmd_helper(struct vty *vty,
+ struct zebra_vrf *zvrf,
+ afi_t afi)
+{
+ struct nhe_show_context ctx;
+
+ ctx.vty = vty;
+ ctx.afi = afi;
+ ctx.vrf_id = zvrf->vrf->vrf_id;
+
+ hash_walk(zrouter.nhgs_id, nhe_show_walker, &ctx);
}
static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp)
@@ -1401,7 +1422,8 @@ DEFPY (show_nexthop_group,
zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
if (!zvrf) {
- vty_out(vty, "VRF %s specified does not exist", vrf_name);
+ vty_out(vty, "%% VRF '%s' specified does not exist\n",
+ vrf_name);
return CMD_WARNING;
}
@@ -1410,6 +1432,19 @@ DEFPY (show_nexthop_group,
return CMD_SUCCESS;
}
+DEFPY_HIDDEN(nexthop_group_use_enable,
+ nexthop_group_use_enable_cmd,
+ "[no] zebra nexthop kernel enable",
+ NO_STR
+ ZEBRA_STR
+ "Nexthop configuration \n"
+ "Configure use of kernel nexthops\n"
+ "Enable kernel nexthops\n")
+{
+ zebra_nhg_enable_kernel_nexthops(!no);
+ return CMD_SUCCESS;
+}
+
DEFUN (no_ip_nht_default_route,
no_ip_nht_default_route_cmd,
"no ip nht resolve-via-default",
@@ -3121,6 +3156,10 @@ static int config_write_protocol(struct vty *vty)
/* Include dataplane info */
dplane_config_write_helper(vty);
+ /* Include nexthop-group config */
+ if (!zebra_nhg_kernel_nexthops_enabled())
+ vty_out(vty, "no zebra nexthop kernel enable\n");
+
return 1;
}
@@ -3492,6 +3531,7 @@ void zebra_vty_init(void)
install_element(CONFIG_NODE, &no_zebra_workqueue_timer_cmd);
install_element(CONFIG_NODE, &zebra_packet_process_cmd);
install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
+ install_element(CONFIG_NODE, &nexthop_group_use_enable_cmd);
install_element(VIEW_NODE, &show_nexthop_group_cmd);
install_element(VIEW_NODE, &show_interface_nexthop_group_cmd);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index cca926f3b0..2a5352a1da 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -557,6 +557,9 @@ DEFINE_KOOH(zserv_client_close, (struct zserv *client), (client));
*/
static void zserv_client_free(struct zserv *client)
{
+ if (client == NULL)
+ return;
+
hook_call(zserv_client_close, client);
/* Close file descriptor. */
@@ -565,11 +568,14 @@ static void zserv_client_free(struct zserv *client)
close(client->sock);
- nroutes = rib_score_proto(client->proto, client->instance);
- zlog_notice(
- "client %d disconnected. %lu %s routes removed from the rib",
- client->sock, nroutes,
- zebra_route_string(client->proto));
+ if (!client->gr_instance_count) {
+ nroutes = rib_score_proto(client->proto,
+ client->instance);
+ zlog_notice(
+ "client %d disconnected %lu %s routes removed from the rib",
+ client->sock, nroutes,
+ zebra_route_string(client->proto));
+ }
client->sock = -1;
}
@@ -600,7 +606,25 @@ static void zserv_client_free(struct zserv *client)
}
vrf_bitmap_free(client->ridinfo);
- XFREE(MTYPE_TMP, client);
+ /*
+ * If any instance are graceful restart enabled,
+ * client is not deleted
+ */
+ if (!client->gr_instance_count) {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: Deleting client %s", __func__,
+ zebra_route_string(client->proto));
+ XFREE(MTYPE_TMP, client);
+ } else {
+ /* Handle cases where client has GR instance. */
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: client %s restart enabled", __func__,
+ zebra_route_string(client->proto));
+ if (zebra_gr_client_disconnect(client) < 0)
+ zlog_err(
+ "%s: GR enabled but could not handle disconnect event",
+ __func__);
+ }
}
void zserv_close_client(struct zserv *client)
@@ -670,6 +694,7 @@ static struct zserv *zserv_client_create(int sock)
pthread_mutex_init(&client->ibuf_mtx, NULL);
pthread_mutex_init(&client->obuf_mtx, NULL);
client->wb = buffer_new(0);
+ TAILQ_INIT(&(client->gr_info_queue));
atomic_store_explicit(&client->connect_time, (uint32_t) monotime(NULL),
memory_order_relaxed);
@@ -861,12 +886,14 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen)
return buf;
}
+/* Display client info details */
static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
{
char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF];
time_t connect_time, last_read_time, last_write_time;
uint32_t last_read_cmd, last_write_cmd;
+ struct client_gr_info *info = NULL;
vty_out(vty, "Client: %s", zebra_route_string(client->proto));
if (client->instance)
@@ -945,12 +972,100 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt);
vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt);
+ TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+ vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));
+ vty_out(vty, "Capabilities : ");
+ switch (info->capabilities) {
+ case ZEBRA_CLIENT_GR_CAPABILITIES:
+ vty_out(vty, "Graceful Restart\n");
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+ case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+ case ZEBRA_CLIENT_GR_DISABLE:
+ case ZEBRA_CLIENT_RIB_STALE_TIME:
+ vty_out(vty, "None\n");
+ break;
+ }
+ }
+
#if defined DEV_BUILD
vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n",
client->ibuf_fifo->count, client->ibuf_fifo->max_count,
client->obuf_fifo->count, client->obuf_fifo->max_count);
#endif
vty_out(vty, "\n");
+}
+
+/* Display stale client information */
+static void zebra_show_stale_client_detail(struct vty *vty,
+ struct zserv *client)
+{
+ char buf[PREFIX2STR_BUFFER];
+ struct tm *tm;
+ struct timeval tv;
+ time_t uptime;
+ struct client_gr_info *info = NULL;
+ struct zserv *s = NULL;
+
+ if (client->instance)
+ vty_out(vty, " Instance: %d", client->instance);
+
+ TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+ vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));
+ vty_out(vty, "Capabilities : ");
+ switch (info->capabilities) {
+ case ZEBRA_CLIENT_GR_CAPABILITIES:
+ vty_out(vty, "Graceful Restart\n");
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+ case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+ case ZEBRA_CLIENT_GR_DISABLE:
+ case ZEBRA_CLIENT_RIB_STALE_TIME:
+ vty_out(vty, "None\n");
+ break;
+ }
+
+ if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)) {
+ if (info->stale_client_ptr) {
+ s = (struct zserv *)(info->stale_client_ptr);
+ uptime = monotime(&tv);
+ uptime -= s->restart_time;
+ tm = gmtime(&uptime);
+ vty_out(vty, "Last restart time : ");
+ if (uptime < ONE_DAY_SECOND)
+ vty_out(vty, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min,
+ tm->tm_sec);
+ else if (uptime < ONE_WEEK_SECOND)
+ vty_out(vty, "%dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour,
+ tm->tm_min);
+ else
+ vty_out(vty, "%02dw%dd%02dh",
+ tm->tm_yday / 7,
+ tm->tm_yday - ((tm->tm_yday / 7)
+ * 7),
+ tm->tm_hour);
+ vty_out(vty, " ago\n");
+
+ vty_out(vty, "Stalepath removal time: %d sec\n",
+ info->stale_removal_time);
+ if (info->t_stale_removal) {
+ vty_out(vty,
+ "Stale delete timer: %ld sec\n",
+ thread_timer_remain_second(
+ info->t_stale_removal));
+ }
+ }
+ vty_out(vty, "Current AFI : %d\n", info->current_afi);
+ if (info->current_prefix) {
+ prefix2str(info->current_prefix, buf,
+ sizeof(buf));
+ vty_out(vty, "Current prefix : %s\n", buf);
+ }
+ }
+ }
+ vty_out(vty, "\n");
return;
}
@@ -1002,8 +1117,12 @@ DEFUN (show_zebra_client,
struct listnode *node;
struct zserv *client;
- for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
zebra_show_client_detail(vty, client);
+ vty_out(vty, "Stale Client Information\n");
+ vty_out(vty, "------------------------\n");
+ zebra_show_stale_client_detail(vty, client);
+ }
return CMD_SUCCESS;
}
@@ -1047,6 +1166,7 @@ void zserv_init(void)
{
/* Client list init. */
zrouter.client_list = list_new();
+ zrouter.stale_client_list = list_new();
/* Misc init. */
zsock = -1;
diff --git a/zebra/zserv.h b/zebra/zserv.h
index d8d82a52ec..77ea19202f 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -52,6 +52,42 @@ extern "C" {
#define ZEBRA_RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
+
+/* Stale route marker timer */
+#define ZEBRA_DEFAULT_STALE_UPDATE_DELAY 1
+
+/* Count of stale routes processed in timer context */
+#define ZEBRA_MAX_STALE_ROUTE_COUNT 50000
+
+/* Graceful Restart information */
+struct client_gr_info {
+ /* VRF for which GR enabled */
+ vrf_id_t vrf_id;
+
+ /* AFI */
+ afi_t current_afi;
+
+ /* Stale time and GR cap */
+ uint32_t stale_removal_time;
+ enum zserv_client_capabilities capabilities;
+
+ /* GR commands */
+ bool delete;
+ bool gr_enable;
+ bool stale_client;
+
+ /* Route sync and enable flags for AFI/SAFI */
+ bool af_enabled[AFI_MAX][SAFI_MAX];
+ bool route_sync[AFI_MAX][SAFI_MAX];
+
+ /* Book keeping */
+ struct prefix *current_prefix;
+ void *stale_client_ptr;
+ struct thread *t_stale_removal;
+
+ TAILQ_ENTRY(client_gr_info) gr_info;
+};
+
/* Client structure. */
struct zserv {
/* Client pthread */
@@ -170,6 +206,19 @@ struct zserv {
_Atomic uint32_t last_read_cmd;
/* command code of last message written */
_Atomic uint32_t last_write_cmd;
+
+ /*
+ * Number of instances configured with
+ * graceful restart
+ */
+ uint32_t gr_instance_count;
+ time_t restart_time;
+
+ /*
+ * Graceful restart information for
+ * each instance
+ */
+ TAILQ_HEAD(info_list, client_gr_info) gr_info_queue;
};
#define ZAPI_HANDLER_ARGS \
@@ -230,7 +279,6 @@ extern int zserv_send_message(struct zserv *client, struct stream *msg);
*/
extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance);
-
/*
* Close a client.
*
@@ -242,7 +290,6 @@ extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance);
*/
extern void zserv_close_client(struct zserv *client);
-
/*
* Log a ZAPI message hexdump.
*
@@ -265,6 +312,16 @@ extern void zserv_read_file(char *input);
/* TODO */
int zebra_finalize(struct thread *event);
+/*
+ * Graceful restart functions.
+ */
+extern int zebra_gr_client_disconnect(struct zserv *client);
+extern void zebra_gr_client_reconnect(struct zserv *client);
+extern void zebra_gr_stale_client_cleanup(struct list *client_list);
+extern void zread_client_capabilities(struct zserv *client, struct zmsghdr *hdr,
+ struct stream *msg,
+ struct zebra_vrf *zvrf);
+
#ifdef __cplusplus
}
#endif