return 0;
fail:
XFREE(MTYPE_BABEL, babel_routing_process);
- babel_routing_process = NULL;
return -1;
}
distribute_list_delete(&babel_routing_process->distribute_ctx);
XFREE(MTYPE_BABEL, babel_routing_process);
- babel_routing_process = NULL;
}
/* Function used with timeout. */
/*
- * log.c
- *
- * Contains code that does the logging procedures. Might implement multiple
- * backends (e.g. zebra log, syslog or other logging lib).
+ * logging - alias to zebra log
*/
-enum blog_level {
- /* level vs syslog equivalent */
- BLOG_DEBUG = 0, /* LOG_DEBUG */
- BLOG_INFO = 1, /* LOG_INFO */
- BLOG_WARNING = 2, /* LOG_WARNING */
- BLOG_ERROR = 3, /* LOG_ERR */
- BLOG_FATAL = 4, /* LOG_CRIT */
-};
-void log_init(int foreground, enum blog_level level,
- struct frr_daemon_info *fdi);
-void log_info(const char *fmt, ...);
-void log_debug(const char *fmt, ...);
-void log_warning(const char *fmt, ...);
-void log_error(const char *fmt, ...);
-void log_fatal(const char *fmt, ...);
+#define log_debug zlog_debug
+#define log_info zlog_info
+#define log_warning zlog_warn
+#define log_error zlog_err
+
+#define log_fatal(msg, ...) \
+ do { \
+ zlog_err(msg, ## __VA_ARGS__); \
+ assert(!msg); \
+ abort(); \
+ } while (0)
/*
return -1;
}
if (rv < (ssize_t)datalen)
- log_debug("packet-send: send partial", strerror(errno));
+ log_debug("packet-send: send partial: %s", strerror(errno));
return 0;
}
log_debug("udp-send: loopback failure: (%d) %s", errno, strerror(errno));
return -1;
} else if (wlen < (ssize_t)datalen) {
- log_debug("udp-send: partial send: %ld expected %ld", wlen,
+ log_debug("udp-send: partial send: %zd expected %zu", wlen,
datalen);
return -1;
}
parse_config(conf);
#endif
- /* Initialize logging API. */
- log_init(1, BLOG_DEBUG, &bfdd_di);
+ /* Initialize FRR infrastructure. */
+ master = frr_init();
/* Initialize control socket. */
control_init(ctl_path);
- /* Initialize FRR infrastructure. */
- master = frr_init();
-
/* Initialize BFD data structures. */
bfd_initialize();
if (strlcpy(bpc->bpc_localif, sval,
sizeof(bpc->bpc_localif))
> sizeof(bpc->bpc_localif)) {
- log_debug("\tlocal-interface: %s (truncated)");
+ log_debug("\tlocal-interface: %s (truncated)",
+ sval);
error++;
} else {
log_debug("\tlocal-interface: %s", sval);
bpc->bpc_detectmultiplier =
json_object_get_int64(jo_val);
bpc->bpc_has_detectmultiplier = true;
- log_debug("\tdetect-multiplier: %llu",
+ log_debug("\tdetect-multiplier: %u",
bpc->bpc_detectmultiplier);
} else if (strcmp(key, "receive-interval") == 0) {
bpc->bpc_recvinterval = json_object_get_int64(jo_val);
{
/* Get ride of old data. */
XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf);
- bcb->bcb_buf = NULL;
bcb->bcb_pos = 0;
bcb->bcb_left = 0;
}
bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(bcm) + bcb->bcb_left + 1);
if (bcb->bcb_buf == NULL) {
- log_warning("%s: not enough memory for message size: %u",
+ log_warning("%s: not enough memory for message size: %zu",
__func__, bcb->bcb_left);
control_free(bcs);
return 0;
+++ /dev/null
-/*********************************************************************
- * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * 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
- *
- * log.c: implements an abstraction between loggers interface. Implement all
- * log backends in this file.
- *
- * Authors
- * -------
- * Rafael Zalamena <rzalamena@opensourcerouting.org>
- */
-
-#include <zebra.h>
-
-#include "bfd.h"
-
-#include "lib/log_int.h"
-
-void log_msg(int level, const char *fmt, va_list vl);
-
-
-static int log_fg;
-static int log_level = BLOG_DEBUG;
-
-void log_init(int foreground, enum blog_level level,
- struct frr_daemon_info *fdi)
-{
- log_fg = foreground;
- log_level = level;
-
- openzlog(fdi->progname, fdi->logname, 0,
- LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
-}
-
-void log_msg(int level, const char *fmt, va_list vl)
-{
- if (level < log_level)
- return;
-
- switch (level) {
- case BLOG_DEBUG:
- vzlog(LOG_DEBUG, fmt, vl);
- break;
-
- case BLOG_INFO:
- vzlog(LOG_INFO, fmt, vl);
- break;
-
- case BLOG_WARNING:
- vzlog(LOG_WARNING, fmt, vl);
- break;
-
- case BLOG_ERROR:
- vzlog(LOG_ERR, fmt, vl);
- break;
-
- case BLOG_FATAL:
- vzlog(LOG_EMERG, fmt, vl);
- break;
-
- default:
- vfprintf(stderr, fmt, vl);
- break;
- }
-}
-
-void log_info(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_INFO, fmt, vl);
- va_end(vl);
-}
-
-void log_debug(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_DEBUG, fmt, vl);
- va_end(vl);
-}
-
-void log_error(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_ERROR, fmt, vl);
- va_end(vl);
-}
-
-void log_warning(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_WARNING, fmt, vl);
- va_end(vl);
-}
-
-void log_fatal(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_FATAL, fmt, vl);
- va_end(vl);
-
- exit(1);
-}
bfdd/config.c \
bfdd/control.c \
bfdd/event.c \
- bfdd/log.c \
bfdd/ptm_adapter.c \
# end
FOREACH_AFI_SAFI (afi, safi) {
XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
- peer->sync[afi][safi] = NULL;
}
}
#include "table.h"
#include "filter.h"
#include "command.h"
+#include "srv6.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
#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)
{
}
}
+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;
&& 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;
}
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)
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;
}
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)
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);
}
/*
case BGP_ATTR_NHLEN_IPV4:
stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
/* Probably needed for RFC 2283 */
- if (attr->nexthop.s_addr == 0)
+ if (attr->nexthop.s_addr == INADDR_ANY)
memcpy(&attr->nexthop.s_addr,
&attr->mp_nexthop_global_in, IPV4_MAX_BYTELEN);
break;
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
}
}
- /*
- * 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(
/* 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);
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;
}
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);
}
}
}
+ /* 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
cluster_init();
transit_init();
encap_init();
+ srv6_init();
}
void bgp_attr_finish(void)
cluster_finish();
transit_finish();
encap_finish();
+ srv6_finish();
}
/* Make attribute packet. */
#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 : \
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 */
/* 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 */
#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;
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,
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,
/* 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);
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);
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);
}
/* 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;
/* 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);
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);
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);
}
/* 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;
/* 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;
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);
}
* 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;
#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. */
/* Any match. */
uint8_t any;
+ /* Sequence number. */
+ int64_t seq;
+
/* Community structure. */
union {
struct community *com;
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);
com->val, com_length(com));
else {
XFREE(MTYPE_COMMUNITY_VAL, com->val);
- com->val = NULL;
}
return;
}
unsigned long conf_bgp_debug_flowspec;
unsigned long conf_bgp_debug_labelpool;
unsigned long conf_bgp_debug_pbr;
+unsigned long conf_bgp_debug_graceful_restart;
unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_neighbor_events;
unsigned long term_bgp_debug_flowspec;
unsigned long term_bgp_debug_labelpool;
unsigned long term_bgp_debug_pbr;
+unsigned long term_bgp_debug_graceful_restart;
struct list *bgp_debug_neighbor_events_peers = NULL;
struct list *bgp_debug_keepalive_peers = NULL;
return CMD_SUCCESS;
}
+DEFUN (debug_bgp_graceful_restart,
+ debug_bgp_graceful_restart_cmd,
+ "debug bgp graceful-restart",
+ DEBUG_STR
+ BGP_STR
+ GR_DEBUG)
+{
+ if (vty->node == CONFIG_NODE) {
+ DEBUG_ON(graceful_restart, GRACEFUL_RESTART);
+ } else {
+ TERM_DEBUG_ON(graceful_restart, GRACEFUL_RESTART);
+ vty_out(vty, "BGP Graceful Restart debugging is on\n");
+ }
+ return CMD_SUCCESS;
+}
+
+
DEFUN (debug_bgp_zebra_prefix,
debug_bgp_zebra_prefix_cmd,
"debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
return CMD_SUCCESS;
}
+DEFUN (no_debug_bgp_graceful_restart,
+ no_debug_bgp_graceful_restart_cmd,
+ "no debug bgp graceful-restart",
+ DEBUG_STR
+ BGP_STR
+ GR_DEBUG
+ NO_STR)
+{
+ if (vty->node == CONFIG_NODE) {
+ DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
+ } else {
+ TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
+ vty_out(vty, "BGP Graceful Restart debugging is off\n");
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_bgp_zebra_prefix,
no_debug_bgp_zebra_prefix_cmd,
"no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
TERM_DEBUG_OFF(labelpool, LABELPOOL);
TERM_DEBUG_OFF(pbr, PBR);
TERM_DEBUG_OFF(pbr, PBR_ERROR);
+ TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
+
vty_out(vty, "All possible debugging has been turned off\n");
return CMD_SUCCESS;
bgp_debug_list_print(vty, " BGP zebra debugging is on",
bgp_debug_zebra_prefixes);
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ vty_out(vty, " BGP graceful-restart debugging is on");
+
if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
vty_out(vty, " BGP allow martian next hop debugging is on\n");
vty_out(vty, "debug bgp pbr error\n");
write++;
}
+
+ if (CONF_BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) {
+ vty_out(vty, "debug bgp graceful-restart\n");
+ write++;
+ }
return write;
}
install_element(ENABLE_NODE, &debug_bgp_bestpath_prefix_cmd);
install_element(CONFIG_NODE, &debug_bgp_bestpath_prefix_cmd);
+ install_element(ENABLE_NODE, &debug_bgp_graceful_restart_cmd);
+ install_element(CONFIG_NODE, &debug_bgp_graceful_restart_cmd);
+
/* debug bgp updates (in|out) */
install_element(ENABLE_NODE, &debug_bgp_update_direct_cmd);
install_element(CONFIG_NODE, &debug_bgp_update_direct_cmd);
install_element(ENABLE_NODE, &no_debug_bgp_bestpath_prefix_cmd);
install_element(CONFIG_NODE, &no_debug_bgp_bestpath_prefix_cmd);
+ install_element(ENABLE_NODE, &no_debug_bgp_graceful_restart_cmd);
+ install_element(CONFIG_NODE, &no_debug_bgp_graceful_restart_cmd);
+
install_element(ENABLE_NODE, &debug_bgp_vpn_cmd);
install_element(CONFIG_NODE, &debug_bgp_vpn_cmd);
install_element(ENABLE_NODE, &no_debug_bgp_vpn_cmd);
extern unsigned long conf_bgp_debug_flowspec;
extern unsigned long conf_bgp_debug_labelpool;
extern unsigned long conf_bgp_debug_pbr;
+extern unsigned long conf_bgp_debug_graceful_restart;
extern unsigned long term_bgp_debug_as4;
extern unsigned long term_bgp_debug_neighbor_events;
extern unsigned long term_bgp_debug_flowspec;
extern unsigned long term_bgp_debug_labelpool;
extern unsigned long term_bgp_debug_pbr;
+extern unsigned long term_bgp_debug_graceful_restart;
extern struct list *bgp_debug_neighbor_events_peers;
extern struct list *bgp_debug_keepalive_peers;
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
+#define BGP_DEBUG_GRACEFUL_RESTART 0x01
+
#define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b))
#define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b))
static int bgp_dump_unset(struct bgp_dump *bgp_dump)
{
/* Removing file name. */
- if (bgp_dump->filename) {
- XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
- bgp_dump->filename = NULL;
- }
+ XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
/* Closing file. */
if (bgp_dump->fp) {
bgp_dump->interval = 0;
/* Removing interval string. */
- if (bgp_dump->interval_str) {
- XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
- bgp_dump->interval_str = NULL;
- }
+ XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
return CMD_SUCCESS;
}
add_prefix_to_json = 1;
}
- if (json && add_prefix_to_json) {
- json_object_string_add(json_prefix, "prefix",
- prefix_str);
- json_object_int_add(json_prefix, "prefixLen",
- rn->p.prefixlen);
- json_object_object_add(json_prefix, "paths",
- json_paths);
- json_object_object_add(json, prefix_str, json_prefix);
+ if (json) {
+ if (add_prefix_to_json) {
+ json_object_string_add(json_prefix, "prefix",
+ prefix_str);
+ json_object_int_add(json_prefix, "prefixLen",
+ rn->p.prefixlen);
+ json_object_object_add(json_prefix, "paths",
+ json_paths);
+ json_object_object_add(json, prefix_str,
+ json_prefix);
+ } else {
+ json_object_free(json_paths);
+ json_object_free(json_prefix);
+ json_paths = NULL;
+ json_prefix = NULL;
+ }
}
}
for (; pi; pi = pi->next) {
json_object *json_path = NULL;
- if (vtep_ip.s_addr
+ if (vtep_ip.s_addr != INADDR_ANY
&& !IPV4_ADDR_SAME(&(vtep_ip),
&(pi->attr->nexthop)))
continue;
add_prefix_to_json = 1;
}
- if (json && add_prefix_to_json) {
- json_object_string_add(json_prefix, "prefix",
- prefix_str);
- json_object_int_add(json_prefix, "prefixLen",
- rn->p.prefixlen);
- json_object_object_add(json_prefix, "paths",
- json_paths);
- json_object_object_add(json, prefix_str, json_prefix);
+ if (json) {
+ if (add_prefix_to_json) {
+ json_object_string_add(json_prefix, "prefix",
+ prefix_str);
+ json_object_int_add(json_prefix, "prefixLen",
+ rn->p.prefixlen);
+ json_object_object_add(json_prefix, "paths",
+ json_paths);
+ json_object_object_add(json, prefix_str,
+ json_prefix);
+ } else {
+ json_object_free(json_paths);
+ json_object_free(json_prefix);
+ json_paths = NULL;
+ json_prefix = NULL;
+ }
}
}
add_rd_to_json = 1;
}
- if (json && add_prefix_to_json) {
- json_object_object_add(json_prefix, "paths",
- json_paths);
- json_object_object_add(json_rd, prefix_str,
- json_prefix);
+ if (json) {
+ if (add_prefix_to_json) {
+ json_object_object_add(json_prefix, "paths",
+ json_paths);
+ json_object_object_add(json_rd, prefix_str,
+ json_prefix);
+ } else {
+ json_object_free(json_paths);
+ json_object_free(json_prefix);
+ json_paths = NULL;
+ json_prefix = NULL;
+ }
}
}
- if (json && add_rd_to_json)
- json_object_object_add(json, rd_str, json_rd);
-
if (json) {
+ if (add_rd_to_json)
+ json_object_object_add(json, rd_str, json_rd);
+ else {
+ json_object_free(json_rd);
+ json_rd = NULL;
+ }
+
json_object_int_add(json, "numPrefix", prefix_cnt);
json_object_int_add(json, "numPaths", path_cnt);
} else {
json_path);
}
- if (json && add_prefix_to_json) {
- json_object_object_add(json_prefix, "paths",
- json_paths);
- json_object_object_add(json_rd, prefix_str,
- json_prefix);
+ if (json) {
+ if (add_prefix_to_json) {
+ json_object_object_add(json_prefix,
+ "paths",
+ json_paths);
+ json_object_object_add(json_rd,
+ prefix_str,
+ json_prefix);
+ } else {
+ json_object_free(json_prefix);
+ json_object_free(json_paths);
+ json_prefix = NULL;
+ json_paths = NULL;
+ }
}
}
- if (json && add_rd_to_json)
- json_object_object_add(json, rd_str, json_rd);
+ if (json) {
+ if (add_rd_to_json)
+ json_object_object_add(json, rd_str, json_rd);
+ else {
+ json_object_free(json_rd);
+ json_rd = NULL;
+ }
+ }
}
if (json) {
static void as_list_free(struct as_list *aslist)
{
- if (aslist->name) {
- XFREE(MTYPE_AS_STR, aslist->name);
- aslist->name = NULL;
- }
+ XFREE(MTYPE_AS_STR, aslist->name);
XFREE(MTYPE_AS_LIST, aslist);
}
* ignore that rule
*/
if (prefix->family == AF_INET
- && prefix->u.prefix4.s_addr == 0)
+ && prefix->u.prefix4.s_addr == INADDR_ANY)
bpem->match_bitmask_iprule |= bitmask;
else
bpem->match_bitmask |= bitmask;
#include "filter.h"
#include "command.h"
#include "lib_errors.h"
-
+#include "zclient.h"
#include "lib/json.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer))
-
+extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
/* Definition of display strings corresponding to FSM events. This should be
* kept consistent with the events defined in bgpd.h
*/
peer->remote_id = from_peer->remote_id;
peer->last_reset = from_peer->last_reset;
+ peer->peer_gr_present_state = from_peer->peer_gr_present_state;
+ peer->peer_gr_new_status_flag = from_peer->peer_gr_new_status_flag;
+ bgp_peer_gr_flags_update(peer);
+
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
+ peer->bgp->peer);
+
+ if (bgp_peer_gr_mode_get(peer) == PEER_DISABLE) {
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) {
+ peer_nsf_stop(peer);
+ }
+ }
+
if (from_peer->hostname != NULL) {
if (peer->hostname) {
XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
return 0;
}
+/* Selection deferral timer processing function */
+static int bgp_graceful_deferral_timer_expire(struct thread *thread)
+{
+ struct afi_safi_info *info;
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+
+ info = THREAD_ARG(thread);
+ afi = info->afi;
+ safi = info->safi;
+ bgp = info->bgp;
+
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug(
+ "afi %d, safi %d : graceful restart deferral timer expired",
+ afi, safi);
+
+ bgp->gr_info[afi][safi].t_select_deferral = NULL;
+
+ bgp->gr_info[afi][safi].eor_required = 0;
+ bgp->gr_info[afi][safi].eor_received = 0;
+ XFREE(MTYPE_TMP, info);
+
+ /* Best path selection */
+ return bgp_best_path_select_defer(bgp, afi, safi);
+}
+
static int bgp_update_delay_applicable(struct bgp *bgp)
{
/* update_delay_over flag should be reset (set to 0) for any new
safi_t safi;
char orf_name[BUFSIZ];
int ret = 0;
+ struct bgp *bgp = peer->bgp;
+ struct graceful_restart_info *gr_info = NULL;
+
+ peer->nsf_af_count = 0;
if (peer_dynamic_neighbor(peer)
&& !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
/* bgp log-neighbor-changes of neighbor Down */
if (bgp_flag_check(peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) {
struct vrf *vrf = vrf_lookup_by_id(peer->bgp->vrf_id);
+
zlog_info(
"%%ADJCHANGE: neighbor %s(%s) in vrf %s Down %s",
peer->host,
peer->nsf[afi][safi] = 0;
}
+ /* If peer reset before receiving EOR, decrement EOR count and
+ * cancel the selection deferral timer if there are no
+ * pending EOR messages to be received
+ */
+ 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))
+ 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;
+ }
+ }
+ }
+
/* set last reset time */
peer->resettime = peer->uptime = bgp_clock();
} else {
bgp_peer_conf_if_to_su_update(peer);
}
-
return ret;
}
}
/* Clear remote router-id. */
- peer->remote_id.s_addr = 0;
+ peer->remote_id.s_addr = INADDR_ANY;
/* Clear peer capability flag. */
peer->cap = 0;
if (bgp_stop(peer) < 0)
return -1;
+ /* Send graceful restart capabilty */
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
+ peer->bgp->peer);
+
bgp_start(peer);
return 0;
}
return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 0);
}
+/* Start the selection deferral timer thread for the specified AFI, SAFI */
+static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi,
+ struct graceful_restart_info *gr_info)
+{
+ struct afi_safi_info *thread_info;
+
+ /* If the deferral timer is active, then increment eor count */
+ if (gr_info->t_select_deferral) {
+ gr_info->eor_required++;
+ return 0;
+ }
+
+ /* Start the deferral timer when the first peer enabled for the graceful
+ * restart is established
+ */
+ if (gr_info->eor_required == 0) {
+ thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
+
+ 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);
+ }
+ gr_info->eor_required++;
+ /* Send message to RIB indicating route update pending */
+ if (gr_info->af_enabled[afi][safi] == false) {
+ gr_info->af_enabled[afi][safi] = true;
+ /* Send message to RIB */
+ bgp_zebra_update(afi, safi, bgp->vrf_id,
+ ZEBRA_CLIENT_ROUTE_UPDATE_PENDING);
+ }
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("Started the deferral timer for %s eor_required %d",
+ get_afi_safi_str(afi, safi, false),
+ gr_info->eor_required);
+ return 0;
+}
+
+/* Update the graceful restart information for the specified AFI, SAFI */
+static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct graceful_restart_info *gr_info;
+ struct bgp *bgp = peer->bgp;
+ int ret = 0;
+
+ if ((afi < AFI_IP) || (afi >= AFI_MAX)) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("%s : invalid afi %d", __func__, afi);
+ return -1;
+ }
+
+ if ((safi < SAFI_UNICAST) || (safi > SAFI_MPLS_VPN)) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("%s : invalid safi %d", __func__, safi);
+ return -1;
+ }
+
+ /* Restarting router */
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)
+ && BGP_PEER_RESTARTING_MODE(peer)) {
+ /* Check if the forwarding state is preserved */
+ if (bgp_flag_check(bgp, BGP_FLAG_GR_PRESERVE_FWD)) {
+ gr_info = &(bgp->gr_info[afi][safi]);
+ ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info);
+ }
+ }
+ return ret;
+}
+
/**
* Transition to Established state.
*
int nsf_af_count = 0;
int ret = 0;
struct peer *other;
+ int status;
other = peer->doppelganger;
peer = peer_xfer_conn(peer);
/* graceful restart */
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
+ if (bgp_debug_neighbor_events(peer)) {
+ if (BGP_PEER_RESTARTING_MODE(peer))
+ zlog_debug("peer %s BGP_RESTARTING_MODE", peer->host);
+ else if (BGP_PEER_HELPER_MODE(peer))
+ zlog_debug("peer %s BGP_HELPER_MODE", peer->host);
+ }
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
if (peer->afc_nego[afi][safi]
bgp_clear_stale_route(peer, afi, safi);
peer->nsf[afi][safi] = 0;
}
+ /* Update the graceful restart information */
+ if (peer->afc_nego[afi][safi]) {
+ if (!BGP_SELECT_DEFER_DISABLE(peer->bgp)) {
+ status = bgp_update_gr_info(peer, afi,
+ safi);
+ if (status < 0)
+ zlog_err(
+ "Error in updating graceful restart for %s",
+ get_afi_safi_str(
+ afi, safi,
+ false));
+ } else {
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(
+ peer)
+ && BGP_PEER_RESTARTING_MODE(peer)
+ && bgp_flag_check(
+ peer->bgp,
+ BGP_FLAG_GR_PRESERVE_FWD))
+ peer->bgp->gr_info[afi][safi]
+ .eor_required++;
+ }
+ }
}
+ peer->nsf_af_count = nsf_af_count;
+
if (nsf_af_count)
SET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
else {
return ret;
}
+/* BGP GR Code */
+
+int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
+ enum global_mode global_new_state,
+ enum global_mode global_old_state)
+{
+ struct peer *peer = {0};
+ struct listnode *node = {0};
+ struct listnode *nnode = {0};
+ enum peer_mode peer_old_state = PEER_INVALID;
+
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%s [BGP_GR] Peer: (%s) :", __func__,
+ peer->host);
+
+ peer_old_state = bgp_peer_gr_mode_get(peer);
+
+ if (peer_old_state == PEER_GLOBAL_INHERIT) {
+
+ /*
+ *Reset only these peers and send a
+ *new open message with the change capabilities.
+ *Considering the mode to be "global_new_state" and
+ *do all operation accordingly
+ */
+
+ switch (global_new_state) {
+ case GLOBAL_HELPER:
+ BGP_PEER_GR_HELPER_ENABLE(peer);
+ break;
+ case GLOBAL_GR:
+ BGP_PEER_GR_ENABLE(peer);
+ break;
+ case GLOBAL_DISABLE:
+ BGP_PEER_GR_DISABLE(peer);
+ break;
+ case GLOBAL_INVALID:
+ zlog_debug("%s [BGP_GR] GLOBAL_INVALID",
+ __func__);
+ return BGP_ERR_GR_OPERATION_FAILED;
+ }
+ }
+ }
+
+ bgp->global_gr_present_state = global_new_state;
+
+ return BGP_GR_SUCCESS;
+}
+
+int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd)
+{
+ enum global_mode global_new_state = GLOBAL_INVALID;
+ enum global_mode global_old_state = GLOBAL_INVALID;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%s [BGP_GR]START: global_gr_cmd :%s:", __func__,
+ print_global_gr_cmd(global_gr_cmd));
+
+ global_old_state = bgp_global_gr_mode_get(bgp);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] global_old_gr_state :%s:",
+ print_global_gr_mode(global_old_state));
+
+ if (global_old_state != GLOBAL_INVALID) {
+ global_new_state =
+ bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd];
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] global_new_gr_state :%s:",
+ print_global_gr_mode(global_new_state));
+ } else {
+ zlog_err("%s [BGP_GR] global_old_state == GLOBAL_INVALID",
+ __func__);
+ return BGP_ERR_GR_OPERATION_FAILED;
+ }
+
+ if (global_new_state == GLOBAL_INVALID) {
+ zlog_err("%s [BGP_GR] global_new_state == GLOBAL_INVALID",
+ __func__);
+ return BGP_ERR_GR_INVALID_CMD;
+ }
+ if (global_new_state == global_old_state) {
+ /* Trace msg */
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "%s [BGP_GR] global_new_state == global_old_state :%s",
+ __func__,
+ print_global_gr_mode(global_new_state));
+ return BGP_GR_NO_OPERATION;
+ }
+
+ return bgp_gr_lookup_n_update_all_peer(bgp, global_new_state,
+ global_old_state);
+}
+
+const char *print_peer_gr_mode(enum peer_mode pr_mode)
+{
+ const char *peer_gr_mode = NULL;
+
+ switch (pr_mode) {
+ case PEER_HELPER:
+ peer_gr_mode = "PEER_HELPER";
+ break;
+ case PEER_GR:
+ peer_gr_mode = "PEER_GR";
+ break;
+ case PEER_DISABLE:
+ peer_gr_mode = "PEER_DISABLE";
+ break;
+ case PEER_INVALID:
+ peer_gr_mode = "PEER_INVALID";
+ break;
+ case PEER_GLOBAL_INHERIT:
+ peer_gr_mode = "PEER_GLOBAL_INHERIT";
+ break;
+ }
+
+ return peer_gr_mode;
+}
+
+const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd)
+{
+ const char *peer_gr_cmd = NULL;
+
+ switch (pr_gr_cmd) {
+ case PEER_GR_CMD:
+ peer_gr_cmd = "PEER_GR_CMD";
+ break;
+ case NO_PEER_GR_CMD:
+ peer_gr_cmd = "NO_PEER_GR_CMD";
+ break;
+ case PEER_DISABLE_CMD:
+ peer_gr_cmd = "PEER_GR_CMD";
+ break;
+ case NO_PEER_DISABLE_CMD:
+ peer_gr_cmd = "NO_PEER_GR_CMD";
+ break;
+ case PEER_HELPER_CMD:
+ peer_gr_cmd = "PEER_HELPER_CMD";
+ break;
+ case NO_PEER_HELPER_CMD:
+ peer_gr_cmd = "NO_PEER_HELPER_CMD";
+ break;
+ }
+
+ return peer_gr_cmd;
+}
+
+const char *print_global_gr_mode(enum global_mode gl_mode)
+{
+ const char *global_gr_mode = NULL;
+
+ switch (gl_mode) {
+ case GLOBAL_HELPER:
+ global_gr_mode = "GLOBAL_HELPER";
+ break;
+ case GLOBAL_GR:
+ global_gr_mode = "GLOBAL_GR";
+ break;
+ case GLOBAL_DISABLE:
+ global_gr_mode = "GLOBAL_DISABLE";
+ break;
+ case GLOBAL_INVALID:
+ global_gr_mode = "GLOBAL_INVALID";
+ break;
+ }
+
+ return global_gr_mode;
+}
+
+const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd)
+{
+ const char *global_gr_cmd = NULL;
+
+ switch (gl_gr_cmd) {
+ case GLOBAL_GR_CMD:
+ global_gr_cmd = "GLOBAL_GR_CMD";
+ break;
+ case NO_GLOBAL_GR_CMD:
+ global_gr_cmd = "NO_GLOBAL_GR_CMD";
+ break;
+ case GLOBAL_DISABLE_CMD:
+ global_gr_cmd = "GLOBAL_DISABLE_CMD";
+ break;
+ case NO_GLOBAL_DISABLE_CMD:
+ global_gr_cmd = "NO_GLOBAL_DISABLE_CMD";
+ break;
+ }
+
+ return global_gr_cmd;
+}
+
+enum global_mode bgp_global_gr_mode_get(struct bgp *bgp)
+{
+ return bgp->global_gr_present_state;
+}
+
+enum peer_mode bgp_peer_gr_mode_get(struct peer *peer)
+{
+ return peer->peer_gr_present_state;
+}
+
+int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd)
+{
+ enum peer_mode peer_new_state = PEER_INVALID;
+ enum peer_mode peer_old_state = PEER_INVALID;
+ struct bgp_peer_gr peer_state;
+ int result = BGP_GR_FAILURE;
+
+ /*
+ * fetch peer_old_state from peer structure also
+ * fetch global_old_state from bgp structure,
+ * peer had a back pointer to bgpo struct ;
+ */
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:",
+ __func__, peer->host,
+ print_peer_gr_cmd(peer_gr_cmd));
+
+ peer_old_state = bgp_peer_gr_mode_get(peer);
+
+ if (peer_old_state == PEER_INVALID) {
+ zlog_debug("[BGP_GR] peer_old_state == Invalid state !");
+ return BGP_ERR_GR_OPERATION_FAILED;
+ }
+
+ peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd];
+ peer_new_state = peer_state.next_state;
+
+ if (peer_new_state == PEER_INVALID) {
+ zlog_debug(
+ "[BGP_GR] Invalid bgp graceful restart command used !");
+ return BGP_ERR_GR_INVALID_CMD;
+ }
+
+ if (peer_new_state != peer_old_state) {
+ result = peer_state.action_fun(peer, peer_old_state,
+ peer_new_state);
+ } else {
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] peer_old_state == peer_new_state !");
+ return BGP_GR_NO_OPERATION;
+ }
+
+ if (result == BGP_GR_SUCCESS) {
+
+ /* Update the mode i.e peer_new_state into the peer structure */
+ peer->peer_gr_present_state = peer_new_state;
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Succesfully change the state of the peer to : %s : !",
+ print_peer_gr_mode(peer_new_state));
+
+ return BGP_GR_SUCCESS;
+ }
+
+ return result;
+}
+
+unsigned int bgp_peer_gr_action(struct peer *peer, int old_peer_state,
+ int new_peer_state)
+{
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!",
+ __func__, print_peer_gr_mode(old_peer_state),
+ print_peer_gr_mode(new_peer_state));
+
+ int bgp_gr_global_mode = GLOBAL_INVALID;
+ unsigned int ret = BGP_GR_FAILURE;
+
+ if (old_peer_state == new_peer_state) {
+ /* Nothing to do over here as the present and old state is the
+ * same */
+ return BGP_GR_NO_OPERATION;
+ }
+ if ((old_peer_state == PEER_INVALID)
+ || (new_peer_state == PEER_INVALID)) {
+ /* something bad happend , print error message */
+ return BGP_ERR_GR_INVALID_CMD;
+ }
+
+ bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp);
+
+ if ((old_peer_state == PEER_GLOBAL_INHERIT)
+ && (new_peer_state != PEER_GLOBAL_INHERIT)) {
+
+ /* fetch the Mode running in the Global state machine
+ *from the bgp structure into a variable called
+ *bgp_gr_global_mode
+ */
+
+ /* Here we are checking if the
+ *1. peer_new_state == global_mode == helper_mode
+ *2. peer_new_state == global_mode == GR_mode
+ *3. peer_new_state == global_mode == disabled_mode
+ */
+
+ BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer);
+
+ if (new_peer_state == bgp_gr_global_mode) {
+ /*This is incremental updates i.e no tear down
+ *of the existing session
+ *as the peer is already working in the same mode.
+ */
+ ret = BGP_GR_SUCCESS;
+ } else {
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Peer state changed from :%s ",
+ print_peer_gr_mode(old_peer_state));
+
+ bgp_peer_move_to_gr_mode(peer, new_peer_state);
+
+ ret = BGP_GR_SUCCESS;
+ }
+ }
+ /* In the case below peer is going into Global inherit mode i.e.
+ * the peer would work as the mode configured at the global level
+ */
+ else if ((new_peer_state == PEER_GLOBAL_INHERIT)
+ && (old_peer_state != PEER_GLOBAL_INHERIT)) {
+ /* Here in this case it would be destructive
+ * in all the cases except one case when,
+ * Global GR is configured Disabled
+ * and present_peer_state is not disable
+ */
+
+ BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
+
+ if (old_peer_state == bgp_gr_global_mode) {
+
+ /* This is incremental updates
+ *i.e no tear down of the existing session
+ *as the peer is already working in the same mode.
+ */
+ ret = BGP_GR_SUCCESS;
+ } else {
+ /* Destructive always */
+ /* Tear down the old session
+ * and send the new capability
+ * as per the bgp_gr_global_mode
+ */
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Peer state changed from :%s",
+ print_peer_gr_mode(old_peer_state));
+
+ bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode);
+
+ ret = BGP_GR_SUCCESS;
+ }
+ } else {
+ /*
+ *This else case, it include all the cases except -->
+ *(new_peer_state != Peer_Global) &&
+ *( old_peer_state != Peer_Global )
+ */
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] Peer state changed from :%s",
+ print_peer_gr_mode(old_peer_state));
+
+ bgp_peer_move_to_gr_mode(peer, new_peer_state);
+
+ ret = BGP_GR_SUCCESS;
+ }
+
+ return ret;
+}
+
+inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state)
+
+{
+ int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp);
+
+ switch (new_state) {
+ case PEER_HELPER:
+ BGP_PEER_GR_HELPER_ENABLE(peer);
+ break;
+ case PEER_GR:
+ BGP_PEER_GR_ENABLE(peer);
+ break;
+ case PEER_DISABLE:
+ BGP_PEER_GR_DISABLE(peer);
+ break;
+ case PEER_GLOBAL_INHERIT:
+ BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
+
+ if (bgp_global_gr_mode == GLOBAL_HELPER) {
+ BGP_PEER_GR_HELPER_ENABLE(peer);
+ } else if (bgp_global_gr_mode == GLOBAL_GR) {
+ BGP_PEER_GR_ENABLE(peer);
+ } else if (bgp_global_gr_mode == GLOBAL_DISABLE) {
+ BGP_PEER_GR_DISABLE(peer);
+ } else {
+ zlog_err(
+ "[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!");
+ }
+ break;
+ default:
+ zlog_err(
+ "[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!");
+ break;
+ }
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !",
+ new_state);
+}
+
+void bgp_peer_gr_flags_update(struct peer *peer)
+{
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%s [BGP_GR] called !", __func__);
+ if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
+ SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER);
+ else
+ UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER);
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !",
+ peer->host,
+ (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER)
+ ? "Set"
+ : "UnSet"));
+ if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART))
+ SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART);
+ else
+ UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART);
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !",
+ peer->host,
+ (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
+ ? "Set"
+ : "UnSet"));
+ if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT))
+ SET_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT);
+ else
+ UNSET_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT);
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !",
+ peer->host,
+ (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT)
+ ? "Set"
+ : "UnSet"));
+
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
+ && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) {
+ zlog_debug("[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!",
+ peer->host);
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) {
+
+ peer_nsf_stop(peer);
+ zlog_debug(
+ "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!",
+ peer->host);
+ }
+ }
+}
#define FSM_PEER_TRANSFERRED 2
#define FSM_PEER_TRANSITIONED 3
+#define BGP_PEER_GR_HELPER_ENABLE(peer) \
+ do { \
+ UNSET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART); \
+ SET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER);\
+ } while (0)
+
+#define BGP_PEER_GR_ENABLE(peer)\
+ do { \
+ SET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART); \
+ UNSET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER);\
+ } while (0)
+
+#define BGP_PEER_GR_DISABLE(peer)\
+ do { \
+ UNSET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART);\
+ UNSET_FLAG(\
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER);\
+ } while (0)
+
+#define BGP_PEER_GR_GLOBAL_INHERIT_SET(peer) \
+ SET_FLAG(peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)
+
+#define BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer) \
+ UNSET_FLAG(peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)
+
+#define BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) \
+ (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) \
+ && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))
+
+#define BGP_PEER_RESTARTING_MODE(peer) \
+ (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) \
+ && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV) \
+ && !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV))
+
+#define BGP_PEER_HELPER_MODE(peer) \
+ (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER) \
+ && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV) \
+ && !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV))
+
/* Prototypes. */
extern void bgp_fsm_event_update(struct peer *peer, int valid);
extern int bgp_event(struct thread *);
extern void bgp_adjust_routeadv(struct peer *);
#include "hook.h"
-DECLARE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
+DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer))
+DECLARE_HOOK(peer_established, (struct peer *peer), (peer))
+int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd);
+int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd);
+unsigned int bgp_peer_gr_action(struct peer *peer,
+ int old_peer_state, int new_peer_state);
+void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state);
+unsigned int bgp_peer_gr_helper_enable(struct peer *peer);
+unsigned int bgp_peer_gr_enable(struct peer *peer);
+unsigned int bgp_peer_gr_global_inherit(struct peer *peer);
+unsigned int bgp_peer_gr_disable(struct peer *peer);
+enum peer_mode bgp_peer_gr_mode_get(struct peer *peer);
+enum global_mode bgp_global_gr_mode_get(struct bgp *bgp);
+enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer);
+unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer);
+int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
+ enum global_mode global_new_state,
+ enum global_mode global_old_state);
+void bgp_peer_gr_flags_update(struct peer *peer);
+const char *print_peer_gr_mode(enum peer_mode pr_mode);
+const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);
+const char *print_global_gr_mode(enum global_mode gl_mode);
+const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd);
#endif /* _QUAGGA_BGP_FSM_H */
safe_strerror(errno));
if (peer->status == Established) {
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
+ if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
+ || CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER))
+ && CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
} else
peer->host, peer->fd);
if (peer->status == Established) {
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
+ if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
+ || CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER))
+ && CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
} else
lcom->val, lcom_length(lcom));
else {
XFREE(MTYPE_LCOMMUNITY_VAL, lcom->val);
- lcom->val = NULL;
}
return;
}
if (bgp && bgp->vrf_id != vrf->vrf_id) {
if (bgp->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
XFREE(MTYPE_BGP, bgp->name);
- bgp->name = NULL;
XFREE(MTYPE_BGP, bgp->name_pretty);
bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default");
bgp->inst_type = BGP_INSTANCE_TYPE_DEFAULT;
}
static const struct frr_yang_module_info *const bgpd_yang_modules[] = {
+ &frr_interface_info,
+ &frr_route_map_info,
};
FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT,
frr_config_fork();
/* must be called after fork() */
+ bgp_gr_apply_running_config();
bgp_pthreads_run();
frr_run(bm->master);
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")
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 */
if ((*mpath)->mp_attr)
bgp_attr_unintern(&(*mpath)->mp_attr);
XFREE(MTYPE_BGP_MPATH_INFO, *mpath);
- *mpath = NULL;
}
}
}
/* Zap multipath attr nexthop so we set nexthop to self */
- attr.nexthop.s_addr = 0;
+ attr.nexthop.s_addr = INADDR_ANY;
memset(&attr.mp_nexthop_global, 0, sizeof(struct in6_addr));
/* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
peer_xfer_config(peer, peer1);
+ bgp_peer_gr_flags_update(peer);
+
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
+ peer->bgp->peer);
+
+ if (bgp_peer_gr_mode_get(peer) == PEER_DISABLE) {
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) {
+ peer_nsf_stop(peer);
+ }
+ }
+
UNSET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
peer->doppelganger = peer1;
BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */
SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
-
/* Make dummy peer until read Open packet. */
if (peer1->status == Established
&& CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) {
* existing established connection and move state to connect.
*/
peer1->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
- SET_FLAG(peer1->sflags, PEER_STATUS_NSF_WAIT);
+
+ if (CHECK_FLAG(peer1->flags, PEER_FLAG_GRACEFUL_RESTART)
+ || CHECK_FLAG(peer1->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER))
+ SET_FLAG(peer1->sflags, PEER_STATUS_NSF_WAIT);
+
bgp_event_update(peer1, TCP_connection_closed);
}
restart_flag_time = stream_getw(s);
if (CHECK_FLAG(restart_flag_time, RESTART_R_BIT))
SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV);
+ else
+ UNSET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV);
UNSET_FLAG(restart_flag_time, 0xF000);
peer->v_gr_restart = restart_flag_time;
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,
if (len) {
str[len] = '\0';
- if (peer->hostname != NULL) {
- XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
- peer->hostname = NULL;
- }
-
- if (peer->domainname != NULL) {
- XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
- peer->domainname = NULL;
- }
+ XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
peer->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
}
if (len) {
str[len] = '\0';
- if (peer->domainname != NULL) {
- XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
- peer->domainname = NULL;
- }
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
}
int ret;
struct stream *s = BGP_INPUT(peer);
size_t end = stream_get_getp(s) + length;
+ uint16_t restart_flag_time = 0;
assert(STREAM_READABLE(s) >= length);
caphdr.length);
stream_set_getp(s, start + caphdr.length);
}
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+ UNSET_FLAG(restart_flag_time, 0xF000);
+ peer->v_gr_restart = restart_flag_time;
+ }
}
return 0;
}
stream_putc_at(s, capp, cap_len);
}
+static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
+ unsigned long cp)
+{
+ int len;
+ iana_afi_t pkt_afi;
+ afi_t afi;
+ safi_t safi;
+ iana_safi_t pkt_safi;
+ uint32_t restart_time;
+ 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))
+ 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 R-Bit for Peer :%s :",
+ peer->host);
+ }
+
+ 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 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);
+ }
+ }
+
+ /* 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. */
void bgp_open_capability(struct stream *s, struct peer *peer)
{
safi_t safi;
iana_safi_t pkt_safi;
as_t local_as;
- uint32_t restart_time;
uint8_t afi_safi_count = 0;
int adv_addpath_tx = 0;
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
*/
cmd_domainname_get());
}
- /* Sending base graceful-restart capability irrespective of the config
- */
- 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);
- rcapp = stream_get_endp(s); /* Set Restart Capability Len Pointer */
- 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 (bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) {
- FOREACH_AFI_SAFI (afi, safi) {
- if (peer->afc[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);
- }
- }
- }
-
- /* 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);
+ bgp_peer_send_gr_capability(s, peer, cp);
/* Total Opt Parm Len. */
len = stream_get_endp(s) - cp - 1;
&& peer->afc_nego[afi][safi]
&& peer->synctime
&& !CHECK_FLAG(
- peer->af_sflags[afi]
- [safi],
- PEER_STATUS_EOR_SEND)) {
- SET_FLAG(peer->af_sflags[afi]
+ peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_SEND)) {
+ /* If EOR is disabled,
+ * the message is not sent
+ */
+ if (BGP_SEND_EOR(peer->bgp, afi,
+ safi)) {
+ SET_FLAG(
+ peer->af_sflags
+ [afi]
[safi],
- PEER_STATUS_EOR_SEND);
-
- if ((s = bgp_update_packet_eor(
- peer, afi,
- safi))) {
- bgp_packet_add(peer, s);
+ PEER_STATUS_EOR_SEND);
+
+ /* Update EOR
+ * send time
+ */
+ peer->eor_stime[afi]
+ [safi] =
+ monotime(NULL);
+
+ BGP_UPDATE_EOR_PKT(
+ peer, afi, safi,
+ s);
}
}
}
continue;
}
+ /* Update packet send time */
+ peer->pkt_stime[afi][safi] = monotime(NULL);
/* Found a packet template to send, overwrite
* packet with appropriate attributes from peer
if (first) {
snprintf(c, sizeof(c), " %02x",
data[i]);
+
strlcat(bgp_notify.data, c,
bgp_notify.length);
+
} else {
first = 1;
snprintf(c, sizeof(c), "%02x", data[i]);
+
strlcpy(bgp_notify.data, c,
bgp_notify.length);
}
if (bgp_notify.data) {
XFREE(MTYPE_TMP, bgp_notify.data);
- bgp_notify.data = NULL;
bgp_notify.length = 0;
}
}
/* Add packet to peer's output queue */
stream_fifo_push(peer->obuf, s);
+ bgp_peer_gr_flags_update(peer);
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
+ peer->bgp->peer);
+
bgp_write_notify(peer);
}
}
/* remote router-id check. */
- if (remote_id.s_addr == 0 || IPV4_CLASS_DE(ntohl(remote_id.s_addr))
+ if (remote_id.s_addr == INADDR_ANY
+ || IPV4_CLASS_DE(ntohl(remote_id.s_addr))
|| ntohl(peer->local_id.s_addr) == ntohl(remote_id.s_addr)) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s bad OPEN, wrong router identifier %s",
|| peer->afc_nego[AFI_IP][SAFI_MULTICAST]
|| peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
|| peer->afc_nego[AFI_IP][SAFI_ENCAP]) {
- if (!peer->nexthop.v4.s_addr) {
+ if (peer->nexthop.v4.s_addr == INADDR_ANY) {
#if defined(HAVE_CUMULUS)
flog_err(
EC_BGP_SND_FAIL,
bgp_size_t attribute_len;
bgp_size_t update_len;
bgp_size_t withdraw_len;
+ bool restart = false;
enum NLRI_TYPES {
NLRI_UPDATE,
|| (attr_parse_ret == BGP_ATTR_PARSE_EOR)) {
afi_t afi = 0;
safi_t safi;
+ struct graceful_restart_info *gr_info;
+
+ /* Restarting router */
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)
+ && BGP_PEER_RESTARTING_MODE(peer))
+ restart = true;
/* Non-MP IPv4/Unicast is a completely emtpy UPDATE - already
* checked
SET_FLAG(peer->af_sflags[afi][safi],
PEER_STATUS_EOR_RECEIVED);
bgp_update_explicit_eors(peer);
+ /* Update graceful restart information */
+ gr_info = &(peer->bgp->gr_info[afi][safi]);
+ if (restart)
+ gr_info->eor_received++;
+ /* If EOR received from all peers and selection
+ * deferral timer is running, cancel the timer
+ * and invoke the best path calculation
+ */
+ if (gr_info->eor_required
+ == gr_info->eor_received) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s %d, %s %d",
+ "EOR REQ",
+ gr_info->eor_required,
+ "EOR RCV",
+ gr_info->eor_received);
+ BGP_TIMER_OFF(
+ gr_info->t_select_deferral);
+ gr_info->eor_required = 0;
+ gr_info->eor_received = 0;
+ /* Best path selection */
+ if (bgp_best_path_select_defer(
+ peer->bgp, afi, safi)
+ < 0)
+ return BGP_Stop;
+ }
}
/* NSF delete stale route */
if (peer->notify.data) {
XFREE(MTYPE_TMP, peer->notify.data);
- peer->notify.data = NULL;
peer->notify.length = 0;
}
if (first) {
snprintf(c, sizeof(c), " %02x",
stream_getc(peer->curr));
+
strlcat(bgp_notify.data, c,
- bgp_notify.length);
+ bgp_notify.length * 3);
+
} else {
first = 1;
snprintf(c, sizeof(c), "%02x",
stream_getc(peer->curr));
+
strlcpy(bgp_notify.data, c,
- bgp_notify.length);
+ bgp_notify.length * 3);
}
bgp_notify.raw_data = (uint8_t *)peer->notify.data;
}
bgp_notify_print(peer, &bgp_notify, "received");
if (bgp_notify.data) {
XFREE(MTYPE_TMP, bgp_notify.data);
- bgp_notify.data = NULL;
bgp_notify.length = 0;
}
}
&& bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM)
UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+ bgp_peer_gr_flags_update(peer);
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
+ peer->bgp->peer);
+
return Receive_NOTIFICATION_message;
}
return 0;
}
+
+/* Send EOR when routes are processed by selection deferral timer */
+void bgp_send_delayed_eor(struct bgp *bgp)
+{
+ struct peer *peer;
+ struct listnode *node, *nnode;
+
+ /* EOR message sent in bgp_write_proceed_actions */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
+ bgp_write_proceed_actions(peer);
+}
#define ORF_COMMON_PART_PERMIT 0x00
#define ORF_COMMON_PART_DENY 0x20
+#define BGP_UPDATE_EOR_PKT(_peer, _afi, _safi, _s) \
+ do { \
+ _s = bgp_update_packet_eor(_peer, _afi, _safi); \
+ if (_s) { \
+ bgp_packet_add(_peer, _s); \
+ } \
+ } while (0)
+
/* Packet send and receive function prototypes. */
extern void bgp_keepalive_send(struct peer *);
extern void bgp_open_send(struct peer *);
extern int bgp_generate_updgrp_packets(struct thread *);
extern int bgp_process_packet(struct thread *);
+extern void bgp_send_delayed_eor(struct bgp *bgp);
#endif /* _QUAGGA_BGP_PACKET_H */
* draft-ietf-idr-flowspec-redirect
*/
if (api_action_redirect_ip) {
- if (api_action_redirect_ip->u
- .zr.redirect_ip_v4.s_addr)
+ if (api_action_redirect_ip->u.zr
+ .redirect_ip_v4.s_addr
+ != INADDR_ANY)
continue;
- if (!path->attr->nexthop.s_addr)
+ if (path->attr->nexthop.s_addr
+ == INADDR_ANY)
continue;
- api_action_redirect_ip->u
- .zr.redirect_ip_v4.s_addr =
+ api_action_redirect_ip->u.zr
+ .redirect_ip_v4.s_addr =
path->attr->nexthop.s_addr;
api_action_redirect_ip->u.zr.duplicate
= ecom_eval->val[7];
return;
bgp_pbr_reset(bgp, AFI_IP);
XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
- bgp->bgp_pbr_cfg = NULL;
}
void bgp_pbr_init(struct bgp *bgp)
#include "workqueue.h"
#include "queue.h"
#include "memory.h"
+#include "srv6.h"
#include "lib/json.h"
#include "lib_errors.h"
-
+#include "zclient.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
extern const char *bgp_origin_long_str[];
-
+const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
/* PMSI strings. */
#define PMSI_TNLTYPE_STR_NO_INFO "No info"
#define PMSI_TNLTYPE_STR_DEFAULT PMSI_TNLTYPE_STR_NO_INFO
if ((*extra)->bgp_fs_pbr)
list_delete(&((*extra)->bgp_fs_pbr));
XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra);
-
- *extra = NULL;
}
/* Get bgp_path_info extra information for the given bgp_path_info, lazy
return path;
}
+/* This function sets flag BGP_NODE_SELECT_DEFER based on condition */
+static int bgp_node_set_defer_flag(struct bgp_node *rn, bool delete)
+{
+ struct peer *peer;
+ struct bgp_path_info *old_pi, *nextpi;
+ bool set_flag = 0;
+ struct bgp *bgp = NULL;
+ struct bgp_table *table = NULL;
+ afi_t afi = 0;
+ safi_t safi = 0;
+ char buf[PREFIX2STR_BUFFER];
+
+ /* If the flag BGP_NODE_SELECT_DEFER is set and new path is added
+ * then the route selection is deferred
+ */
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER) && (!delete))
+ return 0;
+
+ if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED)) {
+ if (BGP_DEBUG(update, UPDATE_OUT)) {
+ prefix2str(&rn->p, buf, PREFIX2STR_BUFFER);
+ zlog_debug(
+ "Route %s is in workqueue and being processed, not deferred.",
+ buf);
+ }
+ return 0;
+ }
+
+ table = bgp_node_table(rn);
+ if (table) {
+ bgp = table->bgp;
+ afi = table->afi;
+ safi = table->safi;
+ }
+
+ for (old_pi = bgp_node_get_bgp_path_info(rn);
+ (old_pi != NULL) && (nextpi = old_pi->next, 1); old_pi = nextpi) {
+ if (CHECK_FLAG(old_pi->flags, BGP_PATH_SELECTED))
+ continue;
+
+ /* Route selection is deferred if there is a stale path which
+ * which indicates peer is in restart mode
+ */
+ if (CHECK_FLAG(old_pi->flags, BGP_PATH_STALE)
+ && (old_pi->sub_type == BGP_ROUTE_NORMAL)) {
+ set_flag = 1;
+ } else {
+ /* If the peer is graceful restart capable and peer is
+ * restarting mode, set the flag BGP_NODE_SELECT_DEFER
+ */
+ peer = old_pi->peer;
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)
+ && BGP_PEER_RESTARTING_MODE(peer)
+ && (old_pi
+ && old_pi->sub_type == BGP_ROUTE_NORMAL)) {
+ set_flag = 1;
+ }
+ }
+ if (set_flag)
+ break;
+ }
+
+ /* Set the flag BGP_NODE_SELECT_DEFER if route selection deferral timer
+ * is active
+ */
+ if (set_flag && table) {
+ if (bgp && (bgp->gr_info[afi][safi].t_select_deferral)) {
+ SET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
+ prefix2str(&rn->p, buf, PREFIX2STR_BUFFER);
+ if (rn->rt_node == NULL)
+ rn->rt_node = listnode_add(
+ bgp->gr_info[afi][safi].route_list, rn);
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("DEFER route %s, rn %p, node %p",
+ buf, rn, rn->rt_node);
+ return 0;
+ }
+ }
+ return -1;
+}
+
void bgp_path_info_add(struct bgp_node *rn, struct bgp_path_info *pi)
{
struct bgp_path_info *top;
bgp_path_info_lock(pi);
bgp_lock_node(rn);
peer_lock(pi->peer); /* bgp_path_info peer reference */
+ bgp_node_set_defer_flag(rn, false);
}
/* Do the actual removal of info from RIB, for use by bgp_process
static void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr)
{
if (family == AF_INET) {
- attr->nexthop.s_addr = 0;
- attr->mp_nexthop_global_in.s_addr = 0;
+ attr->nexthop.s_addr = INADDR_ANY;
+ attr->mp_nexthop_global_in.s_addr = INADDR_ANY;
}
if (family == AF_INET6)
memset(&attr->mp_nexthop_global, 0, IPV6_MAX_BYTELEN);
return 1;
}
+static int bgp_route_select_timer_expire(struct thread *thread)
+{
+ struct afi_safi_info *info;
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+
+ info = THREAD_ARG(thread);
+ afi = info->afi;
+ safi = info->safi;
+ bgp = info->bgp;
+
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("afi %d, safi %d : route select timer expired", afi,
+ safi);
+
+ bgp->gr_info[afi][safi].t_route_select = NULL;
+
+ XFREE(MTYPE_TMP, info);
+
+ /* Best path selection */
+ return bgp_best_path_select_defer(bgp, afi, safi);
+}
+
void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn,
struct bgp_maxpaths_cfg *mpath_cfg,
struct bgp_path_info_pair *result, afi_t afi,
afi2str(afi), safi2str(safi));
}
+ /* The best path calculation for the route is deferred if
+ * BGP_NODE_SELECT_DEFER is set
+ */
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("SELECT_DEFER falg set for route %p", rn);
+ return;
+ }
+
/* Best path selection. */
bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
afi, safi);
return;
}
+/* Process the routes with the flag BGP_NODE_SELECT_DEFER set */
+int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ struct bgp_node *rn;
+ int cnt = 0;
+ struct afi_safi_info *thread_info;
+ struct listnode *node = NULL, *nnode = NULL;
+
+ if (bgp->gr_info[afi][safi].t_route_select)
+ BGP_TIMER_OFF(bgp->gr_info[afi][safi].t_route_select);
+
+ if (BGP_DEBUG(update, UPDATE_OUT)) {
+ zlog_debug("%s: processing route for %s : cnt %d", __func__,
+ get_afi_safi_str(afi, safi, false),
+ listcount(bgp->gr_info[afi][safi].route_list));
+ }
+
+ /* Process the route list */
+ node = listhead(bgp->gr_info[afi][safi].route_list);
+ while (node) {
+ rn = listgetdata(node);
+ nnode = node->next;
+ list_delete_node(bgp->gr_info[afi][safi].route_list, node);
+ rn->rt_node = NULL;
+
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+ UNSET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
+ bgp_process_main_one(bgp, rn, afi, safi);
+ cnt++;
+ if (cnt >= BGP_MAX_BEST_ROUTE_SELECT)
+ break;
+ }
+ node = nnode;
+ }
+
+ /* Send EOR message when all routes are processed */
+ if (list_isempty(bgp->gr_info[afi][safi].route_list)) {
+ bgp_send_delayed_eor(bgp);
+ /* Send route processing complete message to RIB */
+ bgp_zebra_update(afi, safi, bgp->vrf_id,
+ ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
+ return 0;
+ }
+
+ thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
+
+ thread_info->afi = afi;
+ thread_info->safi = safi;
+ thread_info->bgp = bgp;
+
+ /* If there are more routes to be processed, start the
+ * selection timer
+ */
+ thread_add_timer(bm->master, bgp_route_select_timer_expire, thread_info,
+ BGP_ROUTE_SELECT_DELAY,
+ &bgp->gr_info[afi][safi].t_route_select);
+ return 0;
+}
+
static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
{
struct bgp_process_queue *pqnode = data;
if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED))
return;
+ /* If the flag BGP_NODE_SELECT_DEFER is set, do not add route to
+ * the workqueue
+ */
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("BGP_NODE_SELECT_DEFER set for route %p",
+ rn);
+ return;
+ }
+
if (wq == NULL)
return;
void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
struct peer *peer, afi_t afi, safi_t safi)
{
+
+ struct bgp *bgp = NULL;
+ bool delete_route = false;
+
bgp_aggregate_decrement(peer->bgp, &rn->p, pi, afi, safi);
- if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
+ if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
bgp_path_info_delete(rn, pi); /* keep historical info */
- hook_call(bgp_process, peer->bgp, afi, safi, rn, peer, true);
+ /* If the selected path is removed, reset BGP_NODE_SELECT_DEFER
+ * flag
+ */
+ if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
+ delete_route = true;
+ else if (bgp_node_set_defer_flag(rn, true) < 0)
+ delete_route = true;
+ if (delete_route) {
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+ UNSET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
+ bgp = pi->peer->bgp;
+ if ((rn->rt_node)
+ && (bgp->gr_info[afi][safi].route_list)) {
+ list_delete_node(bgp->gr_info[afi][safi]
+ .route_list,
+ rn->rt_node);
+ rn->rt_node = NULL;
+ }
+ }
+ }
+ }
+ hook_call(bgp_process, peer->bgp, afi, safi, rn, peer, true);
bgp_process(peer->bgp, rn, afi, safi);
}
/* If NEXT_HOP is present, validate it. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
- if (attr->nexthop.s_addr == 0
+ if (attr->nexthop.s_addr == INADDR_ANY
|| IPV4_CLASS_DE(ntohl(attr->nexthop.s_addr))
- || bgp_nexthop_self(bgp, afi, type, stype,
- attr, rn))
+ || bgp_nexthop_self(bgp, afi, type, stype, attr, rn))
return 1;
}
switch (attr->mp_nexthop_len) {
case BGP_ATTR_NHLEN_IPV4:
case BGP_ATTR_NHLEN_VPNV4:
- ret = (attr->mp_nexthop_global_in.s_addr == 0
- || IPV4_CLASS_DE(ntohl(
- attr->mp_nexthop_global_in.s_addr))
- || bgp_nexthop_self(bgp, afi, type, stype,
- attr, rn));
+ ret = (attr->mp_nexthop_global_in.s_addr == INADDR_ANY
+ || IPV4_CLASS_DE(
+ ntohl(attr->mp_nexthop_global_in.s_addr))
+ || bgp_nexthop_self(bgp, afi, type, stype, attr,
+ rn));
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL:
if (CHECK_FLAG(pi->flags, BGP_PATH_STALE)) {
bgp_path_info_unset_flag(
rn, pi, BGP_PATH_STALE);
+ bgp_node_set_defer_flag(rn, false);
bgp_process(bgp, rn, afi, safi);
}
}
}
/* graceful restart STALE flag unset. */
- if (CHECK_FLAG(pi->flags, BGP_PATH_STALE))
+ if (CHECK_FLAG(pi->flags, BGP_PATH_STALE)) {
bgp_path_info_unset_flag(rn, pi, BGP_PATH_STALE);
+ bgp_node_set_defer_flag(rn, false);
+ }
/* The attribute is changed. */
bgp_path_info_set_flag(rn, pi, BGP_PATH_ATTR_CHANGED);
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)) {
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,
bgp_static->rmap.name);
route_map_counter_decrement(
bgp_static->rmap.map);
- bgp_static->rmap.name = NULL;
bgp_static->rmap.map = NULL;
bgp_static->valid = 0;
}
bgp_static->backdoor = backdoor;
bgp_static->valid = 0;
bgp_static->igpmetric = 0;
- bgp_static->igpnexthop.s_addr = 0;
+ bgp_static->igpnexthop.s_addr = INADDR_ANY;
bgp_static->label_index = label_index;
if (rmap) {
bgp_static->backdoor = 0;
bgp_static->valid = 0;
bgp_static->igpmetric = 0;
- bgp_static->igpnexthop.s_addr = 0;
+ bgp_static->igpnexthop.s_addr = INADDR_ANY;
bgp_static->label = label;
bgp_static->prd = prd;
} else {
XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
route_map_counter_decrement(rmap->map);
- rmap->name = NULL;
rmap->map = NULL;
}
rmap = &bgp->table_map[afi][safi];
XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
route_map_counter_decrement(rmap->map);
- rmap->name = NULL;
rmap->map = NULL;
if (bgp_fibupd_safi(safi))
: inet_ntoa(attr->nexthop),
vrf_id_str);
} else if (safi == SAFI_FLOWSPEC) {
- if (attr->nexthop.s_addr != 0) {
+ if (attr->nexthop.s_addr != INADDR_ANY) {
if (json_paths) {
json_nexthop_global = json_object_new_object();
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)
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);
}
bdistance->distance = distance;
/* Reset access-list configuration. */
- if (bdistance->access_list) {
- XFREE(MTYPE_AS_LIST, bdistance->access_list);
- bdistance->access_list = NULL;
- }
+ XFREE(MTYPE_AS_LIST, bdistance->access_list);
if (access_list_str)
bdistance->access_list =
XSTRDUP(MTYPE_AS_LIST, access_list_str);
*/
#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
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 {
struct bgp_table *table, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg,
bool use_json);
+extern int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi);
#endif /* _QUAGGA_BGP_ROUTE_H */
*/
SET_FLAG(path->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_PEER_ADDRESS);
- path->attr->nexthop.s_addr = 0;
+ path->attr->nexthop.s_addr = INADDR_ANY;
}
} else {
/* Set next hop value. */
oid2in_addr(offset, len, &paddr);
} else
- paddr.s_addr = 0;
+ paddr.s_addr = INADDR_ANY;
if (!rn)
return NULL;
return min;
}
- paddr.s_addr = 0;
+ paddr.s_addr = INADDR_ANY;
} while ((rn = bgp_route_next(rn)) != NULL);
}
return NULL;
return rt;
}
+/* Delete the route node from the selection deferral route list */
+void bgp_delete_listnode(struct bgp_node *node)
+{
+ struct route_node *rn = NULL;
+ struct bgp_table *table = NULL;
+ struct bgp *bgp = NULL;
+ afi_t afi;
+ safi_t safi;
+
+ /* If the route to be deleted is selection pending, update the
+ * route node in gr_info
+ */
+ if (CHECK_FLAG(node->flags, BGP_NODE_SELECT_DEFER)) {
+ table = bgp_node_table(node);
+
+ if (table) {
+ bgp = table->bgp;
+ afi = table->afi;
+ safi = table->safi;
+ } else
+ return;
+
+ rn = bgp_node_to_rnode(node);
+
+ if (bgp && rn && rn->lock == 1) {
+ /* Delete the route from the selection pending list */
+ if ((node->rt_node)
+ && (bgp->gr_info[afi][safi].route_list)) {
+ list_delete_node(
+ bgp->gr_info[afi][safi].route_list,
+ node->rt_node);
+ node->rt_node = NULL;
+ }
+ }
+ }
+}
+
static struct bgp_node *
bgp_route_next_until_maxlen(struct bgp_node *node, const struct bgp_node *limit,
const uint8_t maxlen)
#include "bgpd.h"
#include "bgp_advertise.h"
+extern void bgp_delete_listnode(struct bgp_node *node);
+
struct bgp_table {
/* table belongs to this instance */
struct bgp *bgp;
#define BGP_NODE_USER_CLEAR (1 << 1)
#define BGP_NODE_LABEL_CHANGED (1 << 2)
#define BGP_NODE_REGISTERED_FOR_LABEL (1 << 3)
-
+#define BGP_NODE_SELECT_DEFER (1 << 4)
+ /* list node pointer */
+ struct listnode *rt_node;
struct bgp_addpath_node_data tx_addpath;
enum bgp_path_selection_reason reason;
*/
static inline void bgp_unlock_node(struct bgp_node *node)
{
+ bgp_delete_listnode(node);
route_unlock_node(bgp_node_to_rnode(node));
}
static void sync_delete(struct update_subgroup *subgrp)
{
XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync);
- subgrp->sync = NULL;
if (subgrp->hash)
hash_free(subgrp->hash);
subgrp->hash = NULL;
XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name);
XFREE(MTYPE_BGP_PEER_HOST, src->host);
- src->host = NULL;
}
static void peer2_updgrp_copy(struct update_group *updgrp, struct peer_af *paf)
conf_release(updgrp->conf, updgrp->afi, updgrp->safi);
XFREE(MTYPE_BGP_PEER_HOST, updgrp->conf->host);
- updgrp->conf->host = NULL;
XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname);
mod_v4nh = &peer->nexthop.v4;
nh_modified = 1;
}
- } else if (!v4nh.s_addr) {
+ } else if (v4nh.s_addr == INADDR_ANY) {
mod_v4nh = &peer->nexthop.v4;
nh_modified = 1;
- } else if (
- peer->sort == BGP_PEER_EBGP
- && (bgp_multiaccess_check_v4(v4nh, peer) == 0)
- && !CHECK_FLAG(
+ } else if (peer->sort == BGP_PEER_EBGP
+ && (bgp_multiaccess_check_v4(v4nh, peer)
+ == 0)
+ && !CHECK_FLAG(
vec->flags,
BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED)
- && !peer_af_flag_check(
+ && !peer_af_flag_check(
peer, paf->afi, paf->safi,
PEER_FLAG_NEXTHOP_UNCHANGED)) {
/* NOTE: not handling case where NH has new AFI
mod_v4nh = &v4nh;
/* No route-map changes allowed for EVPN nexthops. */
- if (!v4nh.s_addr) {
+ if (v4nh.s_addr == INADDR_ANY) {
mod_v4nh = &peer->nexthop.v4;
nh_modified = 1;
}
(struct bgp *bgp, struct vty *vty),
(bgp, vty))
+#define GR_NO_OPER \
+ "The Graceful Restart No Operation was executed as cmd same as previous one."
+#define GR_INVALID \
+ "The Graceful Restart command used is not valid at this moment."
static struct peer_group *listen_range_exists(struct bgp *bgp,
struct prefix *range, int exact);
+/* Show BGP peer's information. */
+enum show_type {
+ show_all,
+ show_peer,
+ show_ipv4_all,
+ show_ipv6_all,
+ show_ipv4_peer,
+ show_ipv6_peer
+};
+
+static struct peer_group *listen_range_exists(struct bgp *bgp,
+ struct prefix *range, int exact);
+
+static void bgp_show_global_graceful_restart_mode_vty(struct vty *vty,
+ struct bgp *bgp,
+ bool use_json,
+ json_object *json);
+
+static int bgp_show_neighbor_graceful_restart_afi_all(struct vty *vty,
+ enum show_type type,
+ const char *ip_str,
+ afi_t afi, bool use_json);
+
static enum node_type bgp_node_type(afi_t afi, safi_t safi)
{
switch (afi) {
str = "Operation not allowed on a directly connected neighbor";
break;
case BGP_ERR_PEER_SAFI_CONFLICT:
- str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'";
+ str = GR_INVALID;
+ break;
+ case BGP_ERR_GR_INVALID_CMD:
+ str = "The Graceful Restart command used is not valid at this moment.";
+ break;
+ case BGP_ERR_GR_OPERATION_FAILED:
+ str = "The Graceful Restart Operation failed due to an err.";
+ break;
+ case BGP_GR_NO_OPERATION:
+ str = GR_NO_OPER;
break;
}
if (str) {
int ret = 0;
bool found = false;
struct peer *peer;
- struct listnode *node, *nnode;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
/* Clear all neighbors. */
/*
*/
if (sort == clear_all) {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+
+ bgp_peer_gr_flags_update(peer);
+
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART))
+ gr_router_detected = true;
+
ret = bgp_peer_clear(peer, afi, safi, nnode,
stype);
bgp_clear_vty_error(vty, peer, afi, safi, ret);
}
+ if (gr_router_detected
+ && bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+ bgp_zebra_send_capabilities(bgp, false);
+ } else if (!gr_router_detected
+ && bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+ bgp_zebra_send_capabilities(bgp, true);
+ }
+
/* This is to apply read-only mode on this clear. */
if (stype == BGP_CLEAR_SOFT_NONE)
bgp->update_delay_over = 0;
}
}
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
ret = bgp_peer_clear(peer, afi, safi, NULL, stype);
/* if afi/safi not defined for this peer, let caller know */
if (peer->sort == BGP_PEER_IBGP)
continue;
+ bgp_peer_gr_flags_update(peer);
+
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART))
+ gr_router_detected = true;
+
ret = bgp_peer_clear(peer, afi, safi, nnode, stype);
if (ret < 0)
found = true;
}
+ if (gr_router_detected
+ && bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+ bgp_zebra_send_capabilities(bgp, false);
+ } else if (!gr_router_detected
+ && bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+ bgp_zebra_send_capabilities(bgp, true);
+ }
+
if (!found)
vty_out(vty,
"%%BGP: No external %s peer is configured\n",
if (peer->as != as)
continue;
+ bgp_peer_gr_flags_update(peer);
+
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART))
+ gr_router_detected = true;
+
ret = bgp_peer_clear(peer, afi, safi, nnode, stype);
if (ret < 0)
found = true;
}
+ if (gr_router_detected
+ && bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+ bgp_zebra_send_capabilities(bgp, false);
+ } else if (!gr_router_detected
+ && bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+ bgp_zebra_send_capabilities(bgp, true);
+ }
+
if (!found)
vty_out(vty,
"%%BGP: No %s peer is configured with AS %s\n",
return CMD_SUCCESS;
}
-/* "bgp graceful-restart" configuration. */
+/* "bgp graceful-restart mode" configuration. */
DEFUN (bgp_graceful_restart,
- bgp_graceful_restart_cmd,
- "bgp graceful-restart",
- "BGP specific commands\n"
- "Graceful restart capability parameters\n")
+ bgp_graceful_restart_cmd,
+ "bgp graceful-restart",
+ "BGP specific commands\n"
+ GR_CMD
+ )
{
+ int ret = BGP_GR_FAILURE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : START ");
+
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp_flag_set(bgp, BGP_FLAG_GRACEFUL_RESTART);
- return CMD_SUCCESS;
+
+ ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer,
+ ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+ return bgp_vty_return(vty, ret);
}
DEFUN (no_bgp_graceful_restart,
- no_bgp_graceful_restart_cmd,
- "no bgp graceful-restart",
- NO_STR
- "BGP specific commands\n"
- "Graceful restart capability parameters\n")
+ no_bgp_graceful_restart_cmd,
+ "no bgp graceful-restart",
+ NO_STR
+ "BGP specific commands\n"
+ NO_GR_CMD
+ )
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp_flag_unset(bgp, BGP_FLAG_GRACEFUL_RESTART);
- return CMD_SUCCESS;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : START ");
+
+ int ret = BGP_GR_FAILURE;
+
+ ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer,
+ ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+
+ return bgp_vty_return(vty, ret);
}
DEFUN (bgp_graceful_restart_stalepath_time,
- bgp_graceful_restart_stalepath_time_cmd,
- "bgp graceful-restart stalepath-time (1-4095)",
- "BGP specific commands\n"
- "Graceful restart capability parameters\n"
- "Set the max time to hold onto restarting peer's stale paths\n"
- "Delay value (seconds)\n")
+ bgp_graceful_restart_stalepath_time_cmd,
+ "bgp graceful-restart stalepath-time (1-4095)",
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the max time to hold onto restarting peer's stale paths\n"
+ "Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_number = 3;
}
DEFUN (bgp_graceful_restart_restart_time,
- bgp_graceful_restart_restart_time_cmd,
- "bgp graceful-restart restart-time (1-4095)",
- "BGP specific commands\n"
- "Graceful restart capability parameters\n"
- "Set the time to wait to delete stale routes before a BGP open message is received\n"
- "Delay value (seconds)\n")
+ bgp_graceful_restart_restart_time_cmd,
+ "bgp graceful-restart restart-time (1-4095)",
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the time to wait to delete stale routes before a BGP open message is received\n"
+ "Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_number = 3;
return CMD_SUCCESS;
}
-DEFUN (no_bgp_graceful_restart_stalepath_time,
- no_bgp_graceful_restart_stalepath_time_cmd,
- "no bgp graceful-restart stalepath-time [(1-4095)]",
- NO_STR
+DEFUN (bgp_graceful_restart_select_defer_time,
+ bgp_graceful_restart_select_defer_time_cmd,
+ "bgp graceful-restart select-defer-time (0-3600)",
"BGP specific commands\n"
"Graceful restart capability parameters\n"
- "Set the max time to hold onto restarting peer's stale paths\n"
- "Delay value (seconds)\n")
+ "Set the time to defer the BGP route selection after restart\n"
+ "Delay value (seconds, 0 - disable)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int idx_number = 3;
+ uint32_t defer_time;
+
+ defer_time = strtoul(argv[idx_number]->arg, NULL, 10);
+ bgp->select_defer_time = defer_time;
+ if (defer_time == 0)
+ bgp_flag_set(bgp, BGP_FLAG_SELECT_DEFER_DISABLE);
+ else
+ bgp_flag_unset(bgp, BGP_FLAG_SELECT_DEFER_DISABLE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_stalepath_time,
+ no_bgp_graceful_restart_stalepath_time_cmd,
+ "no bgp graceful-restart stalepath-time [(1-4095)]",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the max time to hold onto restarting peer's stale paths\n"
+ "Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
}
DEFUN (no_bgp_graceful_restart_restart_time,
- no_bgp_graceful_restart_restart_time_cmd,
- "no bgp graceful-restart restart-time [(1-4095)]",
+ no_bgp_graceful_restart_restart_time_cmd,
+ "no bgp graceful-restart restart-time [(1-4095)]",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the time to wait to delete stale routes before a BGP open message is received\n"
+ "Delay value (seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_select_defer_time,
+ no_bgp_graceful_restart_select_defer_time_cmd,
+ "no bgp graceful-restart select-defer-time [(0-3600)]",
NO_STR
"BGP specific commands\n"
"Graceful restart capability parameters\n"
- "Set the time to wait to delete stale routes before a BGP open message is received\n"
+ "Set the time to defer the BGP route selection after restart\n"
"Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
+ bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME;
+ bgp_flag_unset(bgp, BGP_FLAG_SELECT_DEFER_DISABLE);
+
return CMD_SUCCESS;
}
DEFUN (bgp_graceful_restart_preserve_fw,
- bgp_graceful_restart_preserve_fw_cmd,
- "bgp graceful-restart preserve-fw-state",
- "BGP specific commands\n"
- "Graceful restart capability parameters\n"
- "Sets F-bit indication that fib is preserved while doing Graceful Restart\n")
+ bgp_graceful_restart_preserve_fw_cmd,
+ "bgp graceful-restart preserve-fw-state",
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Sets F-bit indication that fib is preserved while doing Graceful Restart\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, BGP_FLAG_GR_PRESERVE_FWD);
}
DEFUN (no_bgp_graceful_restart_preserve_fw,
- no_bgp_graceful_restart_preserve_fw_cmd,
- "no bgp graceful-restart preserve-fw-state",
+ no_bgp_graceful_restart_preserve_fw_cmd,
+ "no bgp graceful-restart preserve-fw-state",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bgp_flag_unset(bgp, BGP_FLAG_GR_PRESERVE_FWD);
+ return CMD_SUCCESS;
+}
+
+DEFUN (bgp_graceful_restart_disable,
+ bgp_graceful_restart_disable_cmd,
+ "bgp graceful-restart-disable",
+ "BGP specific commands\n"
+ GR_DISABLE)
+{
+ int ret = BGP_GR_FAILURE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_graceful_restart_disable_cmd : START ");
+
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+ bgp->peer, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_graceful_restart_disable_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_graceful_restart_disable,
+ no_bgp_graceful_restart_disable_cmd,
+ "no bgp graceful-restart-disable",
+ NO_STR
+ "BGP specific commands\n"
+ NO_GR_DISABLE
+ )
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_graceful_restart_disable_cmd : START ");
+
+ int ret = BGP_GR_FAILURE;
+
+ ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer,
+ ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_graceful_restart_disable_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (bgp_neighbor_graceful_restart_set,
+ bgp_neighbor_graceful_restart_set_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ GR_NEIGHBOR_CMD
+ )
+{
+ int idx_peer = 1;
+ struct peer *peer;
+ int ret = BGP_GR_FAILURE;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : START ");
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_neighbor_graceful_restart,
+ no_bgp_neighbor_graceful_restart_set_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ NO_GR_NEIGHBOR_CMD
+ )
+{
+ int idx_peer = 2;
+ int ret = BGP_GR_FAILURE;
+ struct peer *peer;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START ");
+
+ ret = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (bgp_neighbor_graceful_restart_helper_set,
+ bgp_neighbor_graceful_restart_helper_set_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-helper",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ GR_NEIGHBOR_HELPER_CMD
+ )
+{
+ int idx_peer = 1;
+ struct peer *peer;
+ int ret = BGP_GR_FAILURE;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : START ");
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+
+ ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_neighbor_graceful_restart_helper,
+ no_bgp_neighbor_graceful_restart_helper_set_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-helper",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ NO_GR_NEIGHBOR_HELPER_CMD
+ )
+{
+ int idx_peer = 2;
+ int ret = BGP_GR_FAILURE;
+ struct peer *peer;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START ");
+
+ ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (bgp_neighbor_graceful_restart_disable_set,
+ bgp_neighbor_graceful_restart_disable_set_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-disable",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ GR_NEIGHBOR_DISABLE_CMD
+ )
+{
+ int idx_peer = 1;
+ struct peer *peer;
+ int ret = BGP_GR_FAILURE;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_disable_set_cmd : START ");
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD);
+
+ if (peer->bgp->t_startup)
+ bgp_peer_gr_flags_update(peer);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_neighbor_graceful_restart_disable,
+ no_bgp_neighbor_graceful_restart_disable_set_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-disable",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ NO_GR_NEIGHBOR_DISABLE_CMD
+ )
+{
+ int idx_peer = 2;
+ int ret = BGP_GR_FAILURE;
+ struct peer *peer;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START ");
+
+ ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN_HIDDEN (bgp_graceful_restart_disable_eor,
+ bgp_graceful_restart_disable_eor_cmd,
+ "bgp graceful-restart disable-eor",
+ "BGP specific commands\n"
+ "Graceful restart configuration parameters\n"
+ "Disable EOR Check\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bgp_flag_set(bgp, BGP_FLAG_GR_DISABLE_EOR);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (no_bgp_graceful_restart_disable_eor,
+ no_bgp_graceful_restart_disable_eor_cmd,
+ "no bgp graceful-restart disable-eor",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart configuration parameters\n"
+ "Disable EOR Check\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bgp_flag_unset(bgp, BGP_FLAG_GR_DISABLE_EOR);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (bgp_graceful_restart_rib_stale_time,
+ bgp_graceful_restart_rib_stale_time_cmd,
+ "bgp graceful-restart rib-stale-time (1-3600)",
+ "BGP specific commands\n"
+ "Graceful restart configuration parameters\n"
+ "Specify the stale route removal timer in rib\n"
+ "Delay value (seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int idx_number = 3;
+ uint32_t stale_time;
+
+ stale_time = strtoul(argv[idx_number]->arg, NULL, 10);
+ bgp->rib_stale_time = stale_time;
+ /* Send the stale timer update message to RIB */
+ if (bgp_zebra_stale_timer_update(bgp))
+ return CMD_WARNING;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_rib_stale_time,
+ no_bgp_graceful_restart_rib_stale_time_cmd,
+ "no bgp graceful-restart rib-stale-time [(1-3600)]",
NO_STR
"BGP specific commands\n"
- "Graceful restart capability parameters\n"
- "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n")
+ "Graceful restart configuration parameters\n"
+ "Specify the stale route removal timer in rib\n"
+ "Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp_flag_unset(bgp, BGP_FLAG_GR_PRESERVE_FWD);
+
+ bgp->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME;
+ /* Send the stale timer update message to RIB */
+ if (bgp_zebra_stale_timer_update(bgp))
+ return CMD_WARNING;
+
return CMD_SUCCESS;
}
return get_afi_safi_vty_str(afi, safi);
}
-/* Show BGP peer's information. */
-enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer };
static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
afi_t afi, safi_t safi,
}
}
-static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
- safi_t safi, bool use_json,
- json_object *json_neigh)
+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_BIT_RCV))
+ rbit_status = 1;
+ else
+ rbit_status = 0;
+ }
+
+ if (rbit_status) {
+ if (use_json)
+ json_object_boolean_true_add(json, "rBit");
+ else
+ vty_out(vty, "True\n");
+ } else {
+ if (use_json)
+ 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)
+{
+ 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 ((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)) {
+
+ mode = "Helper";
+
+ } 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);
+ } 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)
+{
+ const char *mode = "Invalid";
+
+ if (!use_json)
+ vty_out(vty, " Local GR Mode : ");
+
+ if (bgp_peer_gr_mode_get(p) == PEER_HELPER)
+ mode = "Helper";
+ else if (bgp_peer_gr_mode_get(p) == PEER_GR)
+ mode = "Restart";
+ else if (bgp_peer_gr_mode_get(p) == PEER_DISABLE)
+ mode = "Disable";
+ else if (bgp_peer_gr_mode_get(p) == PEER_GLOBAL_INHERIT) {
+ if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_HELPER)
+ mode = "Helper*";
+ else if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_GR)
+ mode = "Restart*";
+ else if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_DISABLE)
+ mode = "Disable*";
+ else
+ mode = "Invalid*";
+ }
+
+ if (use_json) {
+ 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)
+{
+ afi_t afi;
+ safi_t safi;
+ json_object *json_afi_safi = NULL;
+ json_object *json_timer = NULL;
+ json_object *json_endofrib_status = NULL;
+ bool eor_flag = false;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
+ || !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))
+ continue;
+
+ 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->eor_stime[afi][safi]
+ >= peer->pkt_stime[afi][safi])
+ eor_flag = true;
+ else
+ eor_flag = false;
+
+ if (!use_json) {
+ vty_out(vty, " %s :\n",
+ get_afi_safi_str(afi, safi, false));
+
+ vty_out(vty, " F bit : ");
+ }
+
+ if (peer->nsf[afi][safi]
+ && CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_RESTART_AF_PRESERVE_RCV)) {
+
+ if (use_json) {
+ json_object_boolean_true_add(
+ json_afi_safi, "fBit");
+ } 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 (!use_json)
+ vty_out(vty, " End-of-RIB Received : ");
+
+ 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(
+ json_endofrib_status,
+ "endOfRibRecv");
+ else
+ vty_out(vty, "No\n");
+ }
+
+ 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(
+ json_endofrib_status,
+ "endOfRibSend");
+
+ 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(
+ json_endofrib_status,
+ "endOfRibSend");
+ json_object_boolean_false_add(
+ json_endofrib_status,
+ "endOfRibSentAfterUpdate");
+ } else {
+ vty_out(vty, "No\n");
+ vty_out(vty,
+ " EoRSentAfterUpdate : ");
+ 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) {
+ 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)) {
+ json_object_int_add(
+ json_timer,
+ "selectionDeferralTimer",
+ peer->bgp->stalepath_time);
+ }
+
+ if (peer->bgp->gr_info[afi][safi]
+ .t_select_deferral
+ != NULL) {
+
+ json_object_int_add(
+ json_timer,
+ "selectionDeferralTimerRemaining",
+ thread_timer_remain_second(
+ peer->bgp
+ ->gr_info[afi]
+ [safi]
+ .t_select_deferral));
+ }
+ } else {
+ 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,
+ "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,
+ "Configured Selection Deferral Time(sec): %u\n",
+ peer->bgp->select_defer_time);
+ }
+
+ if (peer->bgp->gr_info[afi][safi]
+ .t_select_deferral
+ != NULL) {
+
+ 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);
+ }
+ }
+ }
+}
+
+static void bgp_show_neighbor_graceful_restart_time(struct vty *vty,
+ struct peer *p,
+ bool use_json,
+ json_object *json)
+{
+ if (use_json) {
+ json_object *json_timer = NULL;
+
+ json_timer = json_object_new_object();
+
+ json_object_int_add(json_timer, "configuredRestartTimer",
+ p->bgp->restart_time);
+
+ 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));
+
+ 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, " 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));
+ if (p->t_gr_restart != NULL) {
+ vty_out(vty,
+ " Restart Time Remaining(sec) : %ld\n",
+ thread_timer_remain_second(p->t_gr_restart));
+ }
+ }
+}
+
+static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p,
+ bool use_json, json_object *json)
+{
+ char buf[SU_ADDRSTRLEN] = {0};
+ char dn_flag[2] = {0};
+ char neighborAddr[INET6_ADDRSTRLEN] = {0};
+
+ if (!p->conf_if && peer_dynamic_neighbor(p))
+ dn_flag[0] = '*';
+
+ if (p->conf_if) {
+ if (use_json)
+ json_object_string_add(
+ json, "neighborAddr",
+ BGP_PEER_SU_UNSPEC(p)
+ ? "none"
+ : sockunion2str(&p->su, buf,
+ SU_ADDRSTRLEN));
+ else
+ vty_out(vty, "BGP neighbor on %s: %s\n", p->conf_if,
+ BGP_PEER_SU_UNSPEC(p)
+ ? "none"
+ : sockunion2str(&p->su, buf,
+ SU_ADDRSTRLEN));
+ } else {
+ sprintf(neighborAddr, "%s%s", dn_flag, p->host);
+
+ if (use_json)
+ json_object_string_add(json, "neighborAddr",
+ neighborAddr);
+ else
+ vty_out(vty, "BGP neighbor is %s\n", neighborAddr);
+ }
+
+ /* more gr info in new format */
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json);
+}
+
+static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
+ safi_t safi, bool use_json,
+ json_object *json_neigh)
{
struct bgp_filter *filter;
struct peer_af *paf;
"prefixAllowedRestartIntervalMsecs",
p->pmax_restart[afi][safi] * 60000);
}
- json_object_object_add(json_neigh, get_afi_safi_str(afi, safi, true),
+ json_object_object_add(json_neigh,
+ get_afi_safi_str(afi, safi, true),
json_addr);
} else {
vty_out(vty, "none");
vty_out(vty, "\n");
}
- }
+ } /* Gracefull Restart */
}
}
}
/* graceful restart information */
- if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || p->t_gr_restart
- || p->t_gr_stale) {
json_object *json_grace = NULL;
json_object *json_grace_send = NULL;
json_object *json_grace_recv = NULL;
json_grace_send = json_object_new_object();
json_grace_recv = json_object_new_object();
- if (p->status == Established) {
+ if ((p->status == Established)
+ && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(p->af_sflags[afi][safi],
PEER_STATUS_EOR_SEND)) {
}
}
}
-
json_object_object_add(json_grace, "endOfRibSend",
json_grace_send);
json_object_object_add(json_grace, "endOfRibRecv",
json_grace_recv);
+
if (p->t_gr_restart)
json_object_int_add(json_grace,
"gracefulRestartTimerMsecs",
thread_timer_remain_second(
p->t_gr_stale)
* 1000);
-
+ /* more gr info in new format */
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json,
+ json_grace);
json_object_object_add(
json_neigh, "gracefulRestartInfo", json_grace);
} else {
- vty_out(vty, " Graceful restart information:\n");
- if (p->status == Established) {
+ vty_out(vty, " Graceful restart informations:\n");
+ if ((p->status == Established)
+ && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
+
vty_out(vty, " End-of-RIB send: ");
FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(p->af_sflags[afi][safi],
vty_out(vty, "%s%s",
eor_send_af_count ? ", "
: "",
- get_afi_safi_str(afi,
- safi,
- false));
+ get_afi_safi_str(
+ afi, safi,
+ false));
eor_send_af_count++;
}
}
" The remaining time of stalepath timer is %ld\n",
thread_timer_remain_second(
p->t_gr_stale));
+
+ /* more gr info in new format */
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, NULL);
}
- }
+
if (use_json) {
json_object *json_stat = NULL;
json_stat = json_object_new_object();
}
}
+static int bgp_show_neighbor_graceful_restart(struct vty *vty, struct bgp *bgp,
+ enum show_type type,
+ union sockunion *su,
+ const char *conf_if, afi_t afi,
+ bool use_json, json_object *json)
+{
+ struct listnode *node, *nnode;
+ struct peer *peer;
+ int find = 0;
+ safi_t safi = SAFI_UNICAST;
+ json_object *json_neighbor = NULL;
+
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ continue;
+
+ if ((peer->afc[afi][safi]) == 0)
+ continue;
+
+ if (use_json)
+ json_neighbor = json_object_new_object();
+
+ if (type == show_all) {
+ bgp_show_peer_gr_status(vty, peer, use_json,
+ json_neighbor);
+
+ if (use_json)
+ 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->hostname, conf_if))) {
+ find = 1;
+ 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);
+ }
+ }
+ if (use_json && find)
+ json_object_object_add(json, peer->host,
+ json_neighbor);
+ }
+
+ if (find)
+ break;
+ }
+
+ if (type == show_peer && !find) {
+ if (use_json)
+ 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));
+ } else {
+ vty_out(vty, "\n");
+ }
+
+ return CMD_SUCCESS;
+}
+
static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
enum show_type type, union sockunion *su,
const char *conf_if, bool use_json,
return CMD_SUCCESS;
}
+static void bgp_show_neighbor_graceful_restart_vty(struct vty *vty,
+ enum show_type type,
+ const char *ip_str,
+ afi_t afi, bool use_json)
+{
+
+ int ret;
+ struct bgp *bgp;
+ union sockunion su;
+ json_object *json = NULL;
+
+ bgp = bgp_get_default();
+
+ if (!bgp)
+ return;
+
+ 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,
enum show_type type,
const char *ip_str,
return CMD_SUCCESS;
}
+
+
+/* "show [ip] bgp neighbors graceful-restart" commands. */
+DEFUN (show_ip_bgp_neighbors_gracrful_restart,
+ show_ip_bgp_neighbors_graceful_restart_cmd,
+ "show bgp [<ipv4|ipv6>] neighbors [<A.B.C.D|X:X::X:X|WORD>] graceful-restart [json]",
+ SHOW_STR
+ BGP_STR
+ IP_STR
+ IPV6_STR
+ NEIGHBOR_STR
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on BGP configured interface\n"
+ GR_SHOW
+ JSON_STR)
+{
+ char *sh_arg = NULL;
+ enum show_type sh_type;
+ int idx = 0;
+ afi_t afi = AFI_MAX;
+ bool uj = use_json(argc, argv);
+
+ if (!argv_find_and_parse_afi(argv, argc, &idx, &afi))
+ afi = AFI_MAX;
+
+ idx++;
+
+ if (argv_find(argv, argc, "A.B.C.D", &idx)
+ || argv_find(argv, argc, "X:X::X:X", &idx)
+ || argv_find(argv, argc, "WORD", &idx)) {
+ sh_type = show_peer;
+ sh_arg = argv[idx]->arg;
+ } else
+ sh_type = show_all;
+
+ if (!argv_find(argv, argc, "graceful-restart", &idx))
+ return CMD_SUCCESS;
+
+
+ return bgp_show_neighbor_graceful_restart_afi_all(vty, sh_type, sh_arg,
+ afi, uj);
+}
+
/* "show [ip] bgp neighbors" commands. */
DEFUN (show_ip_bgp_neighbors,
show_ip_bgp_neighbors_cmd,
return CMD_SUCCESS;
}
+/* Graceful Restart */
+
+static void bgp_show_global_graceful_restart_mode_vty(struct vty *vty,
+ struct bgp *bgp,
+ bool use_json,
+ json_object *json)
+{
+
+
+ vty_out(vty, "\n%s", SHOW_GR_HEADER);
+
+ 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");
+ break;
+
+ case GLOBAL_GR:
+ vty_out(vty, "Global BGP GR Mode : Restart\n");
+ break;
+
+ case GLOBAL_DISABLE:
+ vty_out(vty, "Global BGP GR Mode : Disable\n");
+ break;
+
+ case GLOBAL_INVALID:
+ vty_out(vty,
+ "Global BGP GR Mode Invalid\n");
+ break;
+ }
+ vty_out(vty, "\n");
+}
+
+static int bgp_show_neighbor_graceful_restart_afi_all(struct vty *vty,
+ enum show_type type,
+ const char *ip_str,
+ afi_t afi, bool use_json)
+{
+ if ((afi == AFI_MAX) && (ip_str == NULL)) {
+ afi = AFI_IP;
+
+ while ((afi != AFI_L2VPN) && (afi < AFI_MAX)) {
+ bgp_show_neighbor_graceful_restart_vty(
+ vty, type, ip_str, afi, use_json);
+ afi++;
+ }
+ } else if (afi != AFI_MAX) {
+ bgp_show_neighbor_graceful_restart_vty(vty, type, ip_str, afi,
+ use_json);
+ } else {
+ return CMD_ERR_INCOMPLETE;
+ }
+
+ return CMD_SUCCESS;
+}
+/* Graceful Restart */
DEFUN (show_ip_bgp_attr_info,
show_ip_bgp_attr_info_cmd,
if (peer->as_path_loop_detection)
vty_out(vty, " neighbor %s sender-as-path-loop-detection\n",
addr);
+
+ if (!CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) {
+
+ if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+ 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)) {
+ 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);
+ }
+ }
}
/* BGP peer configuration display function. */
vty_out(vty,
" bgp graceful-restart stalepath-time %u\n",
bgp->stalepath_time);
+
if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME)
vty_out(vty, " bgp graceful-restart restart-time %u\n",
bgp->restart_time);
- if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_RESTART))
+
+ if (bgp->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME)
+ vty_out(vty,
+ " bgp graceful-restart select-defer-time %u\n",
+ bgp->select_defer_time);
+
+ if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR)
vty_out(vty, " bgp graceful-restart\n");
+ if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE)
+ vty_out(vty, " bgp graceful-restart-disable\n");
+
/* BGP graceful-shutdown */
if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
vty_out(vty, " bgp graceful-shutdown\n");
vty_out(vty,
" bgp graceful-restart preserve-fw-state\n");
+ /* Stale timer for RIB */
+ if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME)
+ vty_out(vty,
+ " bgp graceful-restart rib-stale-time %u\n",
+ bgp->rib_stale_time);
+
/* BGP bestpath method. */
if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_IGNORE))
vty_out(vty, " bgp bestpath as-path ignore\n");
install_element(BGP_NODE, &bgp_deterministic_med_cmd);
install_element(BGP_NODE, &no_bgp_deterministic_med_cmd);
- /* "bgp graceful-restart" commands */
+ /* "bgp graceful-restart" command */
install_element(BGP_NODE, &bgp_graceful_restart_cmd);
install_element(BGP_NODE, &no_bgp_graceful_restart_cmd);
+
+ /* "bgp graceful-restart-disable" command */
+ install_element(BGP_NODE, &bgp_graceful_restart_disable_cmd);
+ install_element(BGP_NODE, &no_bgp_graceful_restart_disable_cmd);
+
+ /* "neighbor a:b:c:d graceful-restart" command */
+ install_element(BGP_NODE, &bgp_neighbor_graceful_restart_set_cmd);
+ install_element(BGP_NODE, &no_bgp_neighbor_graceful_restart_set_cmd);
+
+ /* "neighbor a:b:c:d graceful-restart-disable" command */
+ install_element(BGP_NODE,
+ &bgp_neighbor_graceful_restart_disable_set_cmd);
+ install_element(BGP_NODE,
+ &no_bgp_neighbor_graceful_restart_disable_set_cmd);
+
+ /* "neighbor a:b:c:d graceful-restart-helper" command */
+ install_element(BGP_NODE,
+ &bgp_neighbor_graceful_restart_helper_set_cmd);
+ install_element(BGP_NODE,
+ &no_bgp_neighbor_graceful_restart_helper_set_cmd);
+
install_element(BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd);
install_element(BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd);
install_element(BGP_NODE, &bgp_graceful_restart_restart_time_cmd);
install_element(BGP_NODE, &no_bgp_graceful_restart_restart_time_cmd);
-
+ install_element(BGP_NODE, &bgp_graceful_restart_select_defer_time_cmd);
+ install_element(BGP_NODE,
+ &no_bgp_graceful_restart_select_defer_time_cmd);
install_element(BGP_NODE, &bgp_graceful_restart_preserve_fw_cmd);
install_element(BGP_NODE, &no_bgp_graceful_restart_preserve_fw_cmd);
+ install_element(BGP_NODE, &bgp_graceful_restart_disable_eor_cmd);
+ install_element(BGP_NODE, &no_bgp_graceful_restart_disable_eor_cmd);
+ install_element(BGP_NODE, &bgp_graceful_restart_rib_stale_time_cmd);
+ install_element(BGP_NODE, &no_bgp_graceful_restart_rib_stale_time_cmd);
+
/* "bgp graceful-shutdown" commands */
install_element(BGP_NODE, &bgp_graceful_shutdown_cmd);
install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd);
/* "show [ip] bgp neighbors" commands. */
install_element(VIEW_NODE, &show_ip_bgp_neighbors_cmd);
+ install_element(VIEW_NODE, &show_ip_bgp_neighbors_graceful_restart_cmd);
+
/* "show [ip] bgp peer-group" commands. */
install_element(VIEW_NODE, &show_ip_bgp_peer_groups_cmd);
/*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;
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);
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)
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);
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);
/*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;
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);
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);
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);
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;
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(). */
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);
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
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)
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")
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)
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")
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
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",
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)
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")
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)
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")
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)
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);
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")
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);
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)
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
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);
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")
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);
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);
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++;
}
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++;
}
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++;
}
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);
#define _QUAGGA_BGP_VTY_H
#include "bgpd/bgpd.h"
-
+#include "stream.h"
struct bgp;
#define BGP_INSTANCE_HELP_STR "BGP view\nBGP VRF\nView/VRF name\n"
"Address Family modifier\n" \
"Address Family modifier\n"
+#define SHOW_GR_HEADER \
+ "Codes: GR - Graceful Restart," \
+ " * - Inheriting Global GR Config,\n" \
+ " Restart - GR Mode-Restarting," \
+ " Helper - GR Mode-Helper,\n" \
+ " Disable - GR Mode-Disable.\n\n"
+
+#define BGP_SHOW_PEER_GR_CAPABILITY( \
+ vty, p, use_json, json) \
+ do { \
+ bgp_show_neighbor_graceful_restart_local_mode( \
+ vty, p, use_json, json); \
+ bgp_show_neighbor_graceful_restart_remote_mode( \
+ vty, p, use_json, json); \
+ bgp_show_neighnor_graceful_restart_rbit( \
+ vty, p, use_json, json); \
+ bgp_show_neighbor_graceful_restart_time( \
+ vty, p, use_json, json); \
+ bgp_show_neighbor_graceful_restart_capability_per_afi_safi(\
+ vty, p, use_json, json); \
+ } while (0)
+
+#define VTY_BGP_GR_DEFINE_LOOP_VARIABLE \
+ struct peer *peer_loop = NULL; \
+ struct listnode *node = NULL; \
+ struct listnode *nnode = NULL; \
+ bool gr_router_detected = false
+
+#define VTY_BGP_GR_ROUTER_DETECT(_bgp, _peer, _peer_list) \
+ do { \
+ if (_peer->bgp->t_startup) \
+ bgp_peer_gr_flags_update(_peer); \
+ for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \
+ if (CHECK_FLAG(peer_loop->flags, \
+ PEER_FLAG_GRACEFUL_RESTART)) \
+ gr_router_detected = true; \
+ } \
+ } while (0)
+
+
+#define VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(_bgp, _ret) \
+ do { \
+ if (gr_router_detected \
+ && _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
+ if (bgp_zebra_send_capabilities(_bgp, false)) \
+ _ret = BGP_ERR_INVALID_VALUE; \
+ } else if (!gr_router_detected \
+ && _bgp->present_zebra_gr_state \
+ == ZEBRA_GR_ENABLE) { \
+ if (bgp_zebra_send_capabilities(_bgp, true)) \
+ _ret = BGP_ERR_INVALID_VALUE; \
+ } \
+ } while (0)
+
+#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \
+ _bgp, _peer_list, _ret) \
+ do { \
+ struct peer *peer_loop; \
+ bool gr_router_detected = false; \
+ struct listnode *node = {0}; \
+ struct listnode *nnode = {0}; \
+ for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \
+ if (peer_loop->bgp->t_startup) \
+ bgp_peer_gr_flags_update(peer_loop); \
+ if (CHECK_FLAG(peer_loop->flags, \
+ PEER_FLAG_GRACEFUL_RESTART)) \
+ gr_router_detected = true; \
+ } \
+ if (gr_router_detected \
+ && _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
+ if (bgp_zebra_send_capabilities(_bgp, false)) \
+ _ret = BGP_ERR_INVALID_VALUE; \
+ } else if (!gr_router_detected \
+ && _bgp->present_zebra_gr_state \
+ == ZEBRA_GR_ENABLE) { \
+ if (bgp_zebra_send_capabilities(_bgp, true)) \
+ _ret = BGP_ERR_INVALID_VALUE; \
+ } \
+ } while (0)
+
+
+#define PRINT_EOR(_eor_flag) \
+ do { \
+ if (eor_flag) \
+ vty_out(vty, "Yes\n"); \
+ else \
+ vty_out(vty, "No\n"); \
+ } while (0)
+
+#define PRINT_EOR_JSON(_eor_flag) \
+ do { \
+ if (eor_flag) \
+ json_object_boolean_true_add( \
+ json_endofrib_status, \
+ "endOfRibSentAfterUpdate"); \
+ else \
+ json_object_boolean_false_add( \
+ json_endofrib_status, \
+ "endOfRibSentAfterUpdate"); \
+ } while (0)
+
extern void bgp_vty_init(void);
extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
/* IPv4 nexthop. */
ret = if_get_ipv4_address(ifp, &nexthop->v4);
- if (!ret && peer->local_id.s_addr)
+ if (!ret && peer->local_id.s_addr != INADDR_ANY)
nexthop->v4 = peer->local_id;
/* Global address*/
/* Unset route-map. */
XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name);
route_map_counter_decrement(red->rmap.map);
- red->rmap.name = NULL;
red->rmap.map = NULL;
/* Unset metric. */
/* TODO - What if we have peers and networks configured, do we have to
* kick-start them?
*/
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer);
}
static int bgp_zebra_process_local_es(ZAPI_CALLBACK_ARGS)
if (cmd == ZEBRA_VNI_ADD)
return bgp_evpn_local_vni_add(
- bgp, vni, vtep_ip.s_addr ? vtep_ip : bgp->router_id,
+ bgp, vni,
+ vtep_ip.s_addr != INADDR_ANY ? vtep_ip : bgp->router_id,
tenant_vrf_id, mcast_grp);
else
return bgp_evpn_local_vni_del(bgp, vni);
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
/* redirect IP */
- if (nh->gate.ipv4.s_addr) {
+ if (nh->gate.ipv4.s_addr != INADDR_ANY) {
char buff[PREFIX_STRLEN];
api_nh->vrf_id = nh->vrf_id;
return;
}
}
+
+/* Send capabilities to RIB */
+int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable)
+{
+ struct zapi_cap api;
+ int ret = BGP_GR_SUCCESS;
+
+ if (zclient == NULL) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("zclient invalid");
+ return BGP_GR_FAILURE;
+ }
+
+ /* Check if the client is connected */
+ if ((zclient->sock < 0) || (zclient->t_connect)) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("client not connected");
+ return BGP_GR_FAILURE;
+ }
+
+ /* Check if capability is already sent. If the flag force is set
+ * send the capability since this can be initial bgp configuration
+ */
+ memset(&api, 0, sizeof(struct zapi_cap));
+ if (disable) {
+ api.cap = ZEBRA_CLIENT_GR_DISABLE;
+ api.vrf_id = bgp->vrf_id;
+ } else {
+ api.cap = ZEBRA_CLIENT_GR_CAPABILITIES;
+ api.stale_removal_time = bgp->rib_stale_time;
+ api.vrf_id = bgp->vrf_id;
+ }
+
+ if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api)
+ < 0) {
+ zlog_err("error sending capability");
+ ret = BGP_GR_FAILURE;
+ } else {
+ if (disable)
+ bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE;
+ else
+ bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE;
+
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("send capabilty success");
+ ret = BGP_GR_SUCCESS;
+ }
+ return ret;
+}
+
+/* Send route update pesding or completed status to RIB for the
+ * specific AFI, SAFI
+ */
+int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type)
+{
+ struct zapi_cap api = {0};
+
+ if (zclient == NULL) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("zclient == NULL, invalid");
+ return BGP_GR_FAILURE;
+ }
+
+ /* Check if the client is connected */
+ if ((zclient->sock < 0) || (zclient->t_connect)) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("client not connected");
+ return BGP_GR_FAILURE;
+ }
+
+ api.afi = afi;
+ api.safi = safi;
+ api.vrf_id = vrf_id;
+ api.cap = type;
+
+ if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api)
+ < 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("error sending capability");
+ return BGP_GR_FAILURE;
+ }
+ return BGP_GR_SUCCESS;
+}
+
+
+/* Send RIB stale timer update */
+int bgp_zebra_stale_timer_update(struct bgp *bgp)
+{
+ struct zapi_cap api;
+
+ if (zclient == NULL) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("zclient invalid");
+ return BGP_GR_FAILURE;
+ }
+
+ /* Check if the client is connected */
+ if ((zclient->sock < 0) || (zclient->t_connect)) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("client not connected");
+ return BGP_GR_FAILURE;
+ }
+
+ memset(&api, 0, sizeof(struct zapi_cap));
+ api.cap = ZEBRA_CLIENT_RIB_STALE_TIME;
+ api.stale_removal_time = bgp->rib_stale_time;
+ api.vrf_id = bgp->vrf_id;
+ if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api)
+ < 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("error sending capability");
+ return BGP_GR_FAILURE;
+ }
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("send capabilty success");
+ return BGP_GR_SUCCESS;
+}
extern bool bgp_zebra_nexthop_set(union sockunion *, union sockunion *,
struct bgp_nexthop *, struct peer *);
-
struct bgp_pbr_action;
struct bgp_pbr_match;
struct bgp_pbr_rule;
struct bgp_pbr_match_entry;
+
extern void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra,
struct bgp_pbr_rule *pbr,
bool install);
extern void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
afi_t afi, uint32_t table_id, bool announce);
-
+extern int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable);
+extern int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type);
+extern int bgp_zebra_stale_timer_update(struct bgp *bgp);
#endif /* _QUAGGA_BGP_ZEBRA_H */
int bgp_router_id_static_set(struct bgp *bgp, struct in_addr id)
{
bgp->router_id_static = id;
- bgp_router_id_set(bgp, id.s_addr ? &id : &bgp->router_id_zebra,
+ bgp_router_id_set(bgp,
+ id.s_addr != INADDR_ANY ? &id : &bgp->router_id_zebra,
true /* is config */);
return 0;
}
XFREE(MTYPE_PEER_TX_SHUTDOWN_MSG, peer->tx_shutdown_message);
- if (peer->desc) {
- XFREE(MTYPE_PEER_DESC, peer->desc);
- peer->desc = NULL;
- }
-
- /* Free allocated host character. */
- if (peer->host) {
- XFREE(MTYPE_BGP_PEER_HOST, peer->host);
- peer->host = NULL;
- }
-
- if (peer->domainname) {
- XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
- peer->domainname = NULL;
- }
-
- if (peer->ifname) {
- XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
- peer->ifname = NULL;
- }
+ XFREE(MTYPE_PEER_DESC, peer->desc);
+ XFREE(MTYPE_BGP_PEER_HOST, peer->host);
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+ XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
/* Update source configuration. */
if (peer->update_source) {
peer->update_source = NULL;
}
- if (peer->update_if) {
- XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
XFREE(MTYPE_TMP, peer->notify.data);
memset(&peer->notify, 0, sizeof(struct bgp_notify));
bgp_sync_delete(peer);
- if (peer->conf_if) {
- XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
- peer->conf_if = NULL;
- }
+ XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
bfd_info_free(&(peer->bfd_info));
return peer;
}
+/* BGP GR changes */
+
+int bgp_global_gr_init(struct bgp *bgp)
+{
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%s called ..", __func__);
+
+ int local_GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE][BGP_GLOBAL_GR_EVENT_CMD] = {
+ /* GLOBAL_HELPER Mode */
+ {
+ /*Event -> */
+ /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/
+ GLOBAL_GR, GLOBAL_INVALID,
+ /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
+ GLOBAL_DISABLE, GLOBAL_INVALID
+ },
+ /* GLOBAL_GR Mode */
+ {
+ /*Event -> */
+ /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/
+ GLOBAL_INVALID, GLOBAL_HELPER,
+ /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
+ GLOBAL_DISABLE, GLOBAL_INVALID
+ },
+ /* GLOBAL_DISABLE Mode */
+ {
+ /*Event -> */
+ /*GLOBAL_GR_cmd */ /*no_Global_GR_cmd*/
+ GLOBAL_GR, GLOBAL_INVALID,
+ /*GLOBAL_DISABLE_cmd*//*no_Global_Disable_cmd*/
+ GLOBAL_INVALID, GLOBAL_HELPER
+ },
+ /* GLOBAL_INVALID Mode */
+ {
+ /*Event -> */
+ /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/
+ GLOBAL_INVALID, GLOBAL_INVALID,
+ /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
+ GLOBAL_INVALID, GLOBAL_INVALID
+ }
+ };
+ memcpy(bgp->GLOBAL_GR_FSM, local_GLOBAL_GR_FSM,
+ sizeof(local_GLOBAL_GR_FSM));
+
+ bgp->global_gr_present_state = GLOBAL_HELPER;
+ bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE;
+
+ return BGP_GR_SUCCESS;
+}
+
+int bgp_peer_gr_init(struct peer *peer)
+{
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%s called ..", __func__);
+
+ struct bgp_peer_gr local_Peer_GR_FSM[BGP_PEER_GR_MODE]
+ [BGP_PEER_GR_EVENT_CMD] = {
+ {
+ /* PEER_HELPER Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_GR, bgp_peer_gr_action }, {PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ {PEER_DISABLE, bgp_peer_gr_action }, {PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_INVALID, NULL }, {PEER_GLOBAL_INHERIT,
+ bgp_peer_gr_action }
+ },
+ {
+ /* PEER_GR Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT,
+ bgp_peer_gr_action },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ {PEER_DISABLE, bgp_peer_gr_action }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
+ },
+ {
+ /* PEER_DISABLE Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT,
+ bgp_peer_gr_action },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
+ },
+ {
+ /* PEER_INVALID Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_INVALID, NULL }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ { PEER_INVALID, NULL }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_INVALID, NULL }, { PEER_INVALID, NULL },
+ },
+ {
+ /* PEER_GLOBAL_INHERIT Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ { PEER_DISABLE, bgp_peer_gr_action}, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
+ }
+ };
+ memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM,
+ sizeof(local_Peer_GR_FSM));
+ peer->peer_gr_present_state = PEER_GLOBAL_INHERIT;
+ bgp_peer_move_to_gr_mode(peer, PEER_GLOBAL_INHERIT);
+
+ return BGP_GR_SUCCESS;
+}
/* Allocate new peer object, implicitely locked. */
struct peer *peer_new(struct bgp *bgp)
SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+ /* Initialize per peer bgp GR FSM */
+ bgp_peer_gr_init(peer);
+
/* Create buffers. */
peer->ibuf = stream_fifo_new();
peer->obuf = stream_fifo_new();
peer_dst->flags = peer_src->flags;
peer_dst->cap = peer_src->cap;
+ peer_dst->peer_gr_present_state = peer_src->peer_gr_present_state;
+ peer_dst->peer_gr_new_status_flag = peer_src->peer_gr_new_status_flag;
+
peer_dst->local_as = peer_src->local_as;
peer_dst->port = peer_src->port;
(void)peer_sort(peer_dst);
if (peer_src->update_source) {
if (peer_dst->update_source)
sockunion_free(peer_dst->update_source);
- if (peer_dst->update_if) {
- XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
- peer_dst->update_if = NULL;
- }
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
peer_dst->update_source =
sockunion_dup(peer_src->update_source);
} else if (peer_src->update_if) {
else if (!active && peer_active(peer))
bgp_timer_set(peer);
+ bgp_peer_gr_flags_update(peer);
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer);
+
return peer;
}
return peer_deactivate(peer, afi, safi);
}
-static void peer_nsf_stop(struct peer *peer)
+void peer_nsf_stop(struct peer *peer)
{
afi_t afi;
safi_t safi;
filter = &peer->filter[afi][safi];
for (i = FILTER_IN; i < FILTER_MAX; i++) {
- if (filter->dlist[i].name) {
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->dlist[i].name);
- filter->dlist[i].name = NULL;
- }
-
- if (filter->plist[i].name) {
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->plist[i].name);
- filter->plist[i].name = NULL;
- }
-
- if (filter->aslist[i].name) {
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->aslist[i].name);
- filter->aslist[i].name = NULL;
- }
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[i].name);
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[i].name);
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[i].name);
}
for (i = RMAP_IN; i < RMAP_MAX; i++) {
- if (filter->map[i].name) {
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->map[i].name);
- filter->map[i].name = NULL;
- }
- }
-
- if (filter->usmap.name) {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- filter->usmap.name = NULL;
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->map[i].name);
}
- if (peer->default_rmap[afi][safi].name) {
- XFREE(MTYPE_ROUTE_MAP_NAME,
- peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name = NULL;
- }
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name);
}
FOREACH_AFI_SAFI (afi, safi)
peer_af_delete(peer, afi, safi);
- if (peer->hostname) {
- XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
- peer->hostname = NULL;
- }
-
- if (peer->domainname) {
- XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
- peer->domainname = NULL;
- }
+ XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
peer_unlock(peer); /* initial reference */
XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host);
bgp->peer_self->host =
XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
- if (bgp->peer_self->hostname != NULL) {
- XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname);
- bgp->peer_self->hostname = NULL;
- }
+ XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname);
if (cmd_hostname_get())
bgp->peer_self->hostname =
XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_hostname_get());
- if (bgp->peer_self->domainname != NULL) {
- XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname);
- bgp->peer_self->domainname = NULL;
- }
+ XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname);
if (cmd_domainname_get())
bgp->peer_self->domainname =
XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_domainname_get());
multipath_num, 0);
bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_IBGP,
multipath_num, 0);
+ /* Initialize graceful restart info */
+ bgp->gr_info[afi][safi].eor_required = 0;
+ bgp->gr_info[afi][safi].eor_received = 0;
+ bgp->gr_info[afi][safi].t_select_deferral = NULL;
+ bgp->gr_info[afi][safi].t_route_select = NULL;
+ bgp->gr_info[afi][safi].route_list = list_new();
}
bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
bgp_timers_unset(bgp);
bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
+ bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME;
+ bgp->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME;
bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
bgp->dynamic_neighbors_count = 0;
bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED;
bgp->vpn_policy[afi].export_vrf->del =
bgp_vrf_string_name_delete;
}
- if (name) {
+ if (name)
bgp->name = XSTRDUP(MTYPE_BGP, name);
- } else {
- /* TODO - The startup timer needs to be run for the whole of BGP
- */
- thread_add_timer(bm->master, bgp_startup_timer_expire, bgp,
- bgp->restart_time, &bgp->t_startup);
- }
+
+ thread_add_timer(bm->master, bgp_startup_timer_expire, bgp,
+ bgp->restart_time, &bgp->t_startup);
/* printable name we can use in debug messages */
if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
bgp_evpn_init(bgp);
bgp_pbr_init(bgp);
+
+ /*initilize global GR FSM */
+ bgp_global_gr_init(bgp);
return bgp;
}
struct listnode *node, *next;
struct vrf *vrf;
afi_t afi;
+ safi_t safi;
int i;
+ struct graceful_restart_info *gr_info;
assert(bgp);
/* Set flag indicating bgp instance delete in progress */
bgp_flag_set(bgp, BGP_FLAG_DELETE_IN_PROGRESS);
+ /* Delete the graceful restart info */
+ FOREACH_AFI_SAFI (afi, safi) {
+ gr_info = &bgp->gr_info[afi][safi];
+ 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)) {
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
zlog_debug("Deleting Default VRF");
{
XFREE(MTYPE_PEER_DESC, peer->desc);
- peer->desc = NULL;
-
return 0;
}
void peer_interface_unset(struct peer *peer)
{
XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
- peer->ifname = NULL;
}
/* Allow-as in. */
return peer;
}
+void bgp_gr_apply_running_config(void)
+{
+ struct peer *peer = NULL;
+ struct bgp *bgp = NULL;
+ struct listnode *node, *nnode;
+ bool gr_router_detected = false;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] %s called !", __func__);
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ bgp_peer_gr_flags_update(peer);
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART))
+ gr_router_detected = true;
+ }
+
+ if (gr_router_detected
+ && bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+ bgp_zebra_send_capabilities(bgp, true);
+ } else if (!gr_router_detected
+ && bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+ bgp_zebra_send_capabilities(bgp, false);
+ }
+
+ gr_router_detected = false;
+ }
+}
AS_EXTERNAL,
};
+/* Zebra Gracaful Restart states */
+enum zebra_gr_mode {
+ ZEBRA_GR_DISABLE = 0,
+ ZEBRA_GR_ENABLE
+};
+
/* Typedef BGP specific types. */
typedef uint32_t as_t;
typedef uint16_t as16_t; /* we may still encounter 16 Bit asnums */
BGP_INSTANCE_TYPE_VIEW
};
+#define BGP_SEND_EOR(bgp, afi, safi) \
+ (!bgp_flag_check(bgp, BGP_FLAG_GR_DISABLE_EOR) \
+ && ((bgp->gr_info[afi][safi].t_select_deferral == NULL) \
+ || (bgp->gr_info[afi][safi].eor_required \
+ == bgp->gr_info[afi][safi].eor_received)))
+
+/* BGP GR Global ds */
+
+#define BGP_GLOBAL_GR_MODE 4
+#define BGP_GLOBAL_GR_EVENT_CMD 4
+
+/* Graceful restart selection deferral timer info */
+struct graceful_restart_info {
+ /* Count of EOR message expected */
+ uint32_t eor_required;
+ /* Count of EOR received */
+ uint32_t eor_received;
+ /* Deferral Timer */
+ struct thread *t_select_deferral;
+ /* Route list */
+ struct list *route_list;
+ /* Best route select */
+ struct thread *t_route_select;
+ /* AFI, SAFI enabled */
+ bool af_enabled[AFI_MAX][SAFI_MAX];
+ /* Route update completed */
+ bool route_sync[AFI_MAX][SAFI_MAX];
+};
+
+enum global_mode {
+ GLOBAL_HELPER = 0, /* This is the default mode */
+ GLOBAL_GR,
+ GLOBAL_DISABLE,
+ GLOBAL_INVALID
+};
+
+enum global_gr_command {
+ GLOBAL_GR_CMD = 0,
+ NO_GLOBAL_GR_CMD,
+ GLOBAL_DISABLE_CMD,
+ NO_GLOBAL_DISABLE_CMD
+};
+
+#define BGP_GR_SUCCESS 0
+#define BGP_GR_FAILURE 1
+
/* BGP instance structure. */
struct bgp {
/* AS number of this BGP instance. */
#define BGP_FLAG_IMPORT_CHECK (1 << 9)
#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1 << 10)
#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 11)
+
+/* This flag is set when we have full BGP Graceful-Restart mode enable */
#define BGP_FLAG_GRACEFUL_RESTART (1 << 12)
+
#define BGP_FLAG_ASPATH_CONFED (1 << 13)
#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14)
#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 15)
#define BGP_FLAG_GR_PRESERVE_FWD (1 << 20)
#define BGP_FLAG_GRACEFUL_SHUTDOWN (1 << 21)
#define BGP_FLAG_DELETE_IN_PROGRESS (1 << 22)
+#define BGP_FLAG_SELECT_DEFER_DISABLE (1 << 23)
+#define BGP_FLAG_GR_DISABLE_EOR (1 << 24)
+
+ enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
+ [BGP_GLOBAL_GR_EVENT_CMD];
+ enum global_mode global_gr_present_state;
+
+ /* This variable stores the current Graceful Restart state of Zebra
+ * - ZEBRA_GR_ENABLE / ZEBRA_GR_DISABLE
+ */
+ enum zebra_gr_mode present_zebra_gr_state;
/* BGP Per AF flags */
uint16_t af_flags[AFI_MAX][SAFI_MAX];
/* BGP graceful restart */
uint32_t restart_time;
uint32_t stalepath_time;
+ uint32_t select_defer_time;
+ struct graceful_restart_info gr_info[AFI_MAX][SAFI_MAX];
+ uint32_t rib_stale_time;
+#define BGP_ROUTE_SELECT_DELAY 1
+#define BGP_MAX_BEST_ROUTE_SELECT 10000
/* Maximum-paths configuration */
struct bgp_maxpaths_cfg {
uint16_t maxpaths_ebgp;
#define BGP_VRF_RD_CFGD (1 << 3)
#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 4)
-
/* unique ID for auto derivation of RD for this vrf */
uint16_t vrf_rd_id;
(struct bgp *bgp, struct vty *vty),
(bgp, vty))
+/* Thread callback information */
+struct afi_safi_info {
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+};
+
#define BGP_ROUTE_ADV_HOLD(bgp) (bgp->main_peers_update_hold)
#define IS_BGP_INST_KNOWN_TO_ZEBRA(bgp) \
|| (bgp->inst_type == BGP_INSTANCE_TYPE_VRF \
&& bgp->vrf_id != VRF_UNKNOWN))
+#define BGP_SELECT_DEFER_DISABLE(bgp) \
+ (bgp_flag_check(bgp, BGP_FLAG_SELECT_DEFER_DISABLE))
+
/* BGP peer-group support. */
struct peer_group {
/* Name of the peer-group. */
safi_t safi;
int afid;
};
+/* BGP GR per peer ds */
+
+#define BGP_PEER_GR_MODE 5
+#define BGP_PEER_GR_EVENT_CMD 6
+
+enum peer_mode {
+ PEER_HELPER = 0,
+ PEER_GR,
+ PEER_DISABLE,
+ PEER_INVALID,
+ PEER_GLOBAL_INHERIT /* This is the default mode */
+
+};
+
+enum peer_gr_command {
+ PEER_GR_CMD = 0,
+ NO_PEER_GR_CMD,
+ PEER_DISABLE_CMD,
+ NO_PEER_DISABLE_CMD,
+ PEER_HELPER_CMD,
+ NO_PEER_HELPER_CMD
+};
+
+typedef unsigned int (*bgp_peer_gr_action_ptr)(struct peer *, int, int);
+
+struct bgp_peer_gr {
+ enum peer_mode next_state;
+ bgp_peer_gr_action_ptr action_fun;
+};
+
/* BGP neighbor structure. */
struct peer {
#define PEER_FLAG_LOCAL_AS (1 << 21) /* local-as */
#define PEER_FLAG_UPDATE_SOURCE (1 << 22) /* update-source */
+ /* BGP-GR Peer related flags */
+#define PEER_FLAG_GRACEFUL_RESTART_HELPER (1 << 23) /* Helper */
+#define PEER_FLAG_GRACEFUL_RESTART (1 << 24) /* Graceful Restart */
+#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1 << 25) /* Global-Inherit */
+
+ /*
+ *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
+ *& PEER_FLAG_GRACEFUL_RESTART_HELPER
+ *and PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT
+ */
+
+ struct bgp_peer_gr PEER_GR_FSM[BGP_PEER_GR_MODE][BGP_PEER_GR_EVENT_CMD];
+ enum peer_mode peer_gr_present_state;
+ /* Non stop forwarding afi-safi count for BGP gr feature*/
+ uint8_t nsf_af_count;
+
+ uint8_t peer_gr_new_status_flag;
+#define PEER_GRACEFUL_RESTART_NEW_STATE_HELPER (1 << 0)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_RESTART (1 << 1)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT (1 << 2)
+
/* outgoing message sent in CEASE_ADMIN_SHUTDOWN notify */
char *tx_shutdown_message;
/* NSF mode (graceful restart) */
uint8_t nsf[AFI_MAX][SAFI_MAX];
+ /* EOR Send time */
+ time_t eor_stime[AFI_MAX][SAFI_MAX];
+ /* Last update packet sent time */
+ time_t pkt_stime[AFI_MAX][SAFI_MAX];
/* Peer Per AF flags */
/*
((peer)->attr = (group)->conf->attr)
#define PEER_STR_ATTR_INHERIT(peer, group, attr, mt) \
do { \
- if ((peer)->attr) \
- XFREE(mt, (peer)->attr); \
+ XFREE(mt, (peer)->attr); \
if ((group)->conf->attr) \
(peer)->attr = XSTRDUP(mt, (group)->conf->attr); \
else \
/* BGP graceful restart */
#define BGP_DEFAULT_RESTART_TIME 120
#define BGP_DEFAULT_STALEPATH_TIME 360
+#define BGP_DEFAULT_SELECT_DEFERRAL_TIME 360
+#define BGP_DEFAULT_RIB_STALE_TIME 500
/* BGP uptime string length. */
#define BGP_UPTIME_LEN 25
#define BGP_ERR_INVALID_FOR_DIRECT_PEER -34
#define BGP_ERR_PEER_SAFI_CONFLICT -35
+/* BGP GR ERRORS */
+#define BGP_ERR_GR_INVALID_CMD -36
+#define BGP_ERR_GR_OPERATION_FAILED -37
+#define BGP_GR_NO_OPERATION -38
+
/*
* Enumeration of different policy kinds a peer can be configured with.
*/
extern void bgp_close(void);
extern void bgp_free(struct bgp *);
+void bgp_gr_apply_running_config(void);
+
+/* BGP GR */
+int bgp_global_gr_init(struct bgp *bgp);
+int bgp_peer_gr_init(struct peer *peer);
+
+
+#define BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(_bgp, _peer_list) \
+ do { \
+ struct peer *peer_loop; \
+ bool gr_router_detected = false; \
+ struct listnode *node = {0}; \
+ for (ALL_LIST_ELEMENTS_RO(_peer_list, node, peer_loop)) { \
+ if (CHECK_FLAG(peer_loop->flags, \
+ PEER_FLAG_GRACEFUL_RESTART)) \
+ gr_router_detected = true; \
+ } \
+ if (gr_router_detected \
+ && _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
+ bgp_zebra_send_capabilities(_bgp, false); \
+ } else if (!gr_router_detected \
+ && _bgp->present_zebra_gr_state \
+ == ZEBRA_GR_ENABLE) { \
+ bgp_zebra_send_capabilities(_bgp, true); \
+ } \
+ } while (0)
static inline struct bgp *bgp_lock(struct bgp *bgp)
{
/* Hooks */
DECLARE_HOOK(peer_status_changed, (struct peer * peer), (peer))
+void peer_nsf_stop(struct peer *peer);
#endif /* _QUAGGA_BGPD_H */
while (p) {
next = p->next;
- if (p->value) {
- XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE, p->value);
- p->value = NULL;
- }
+ XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE, p->value);
XFREE(MTYPE_BGP_TEA_OPTIONS, p);
p = next;
}
if (rc) {
XFREE(MTYPE_RFAPI_UN_OPTION, uo);
- uo = NULL;
}
return uo;
}
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)) {
yum install systemd-devel
+ For CentOS 7 and CentOS 8, the package will be built using python3
+ and requires additional python3 packages::
+
+ yum install python3-devel python3-sphinx
+
.. note::
For CentOS 8 you need to install ``platform-python-devel`` package
yum install platform-python-devel
- .. warning::
-
- ``python2-sphinx`` is not shipped for CentOS 8.
- Development reached the end of life for Python 2.
- We need to install it using ```pip``::
-
- pip2 install sphinx
If ``yum`` is not present on your system, use ``dnf`` instead.
+------------------------------------+-------+
| 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 |
+------------------------------------+-------+
MED as an intra-AS metric to steer equal-length AS_PATH routes to, e.g.,
desired exit points.
+
+.. _bgp-graceful-restart:
+
+Graceful Restart
+----------------
+
+BGP graceful restart functionality as defined in
+`RFC-4724 <https://tools.ietf.org/html/rfc4724/>`_ defines the mechanisms that
+allows BGP speaker to continue to forward data packets along known routes
+while the routing protocol information is being restored.
+
+
+Usually, when BGP on a router restarts, all the BGP peers detect that the
+session went down and then came up. This "down/up" transition results in a
+"routing flap" and causes BGP route re-computation, generation of BGP routing
+updates, and unnecessary churn to the forwarding tables.
+
+The following functionality is provided by graceful restart:
+
+1. The feature allows the restarting router to indicate to the helping peer the
+ routes it can preserve in its forwarding plane during control plane restart
+ by sending graceful restart capability in the OPEN message sent during
+ session establishment.
+2. The feature allows helping router to advertise to all other peers the routes
+ received from the restarting router which are preserved in the forwarding
+ plane of the restarting router during control plane restart.
+
+
+::
+
+
+
+ (R1)-----------------------------------------------------------------(R2)
+
+ 1. BGP Graceful Restart Capability exchanged between R1 & R2.
+
+ <--------------------------------------------------------------------->
+
+ 2. Kill BGP Process at R1.
+
+ ---------------------------------------------------------------------->
+
+ 3. R2 Detects the above BGP Restart & verifies BGP Restarting
+ Capability of R1.
+
+ 4. Start BGP Process at R1.
+
+ 5. Re-establish the BGP session between R1 & R2.
+
+ <--------------------------------------------------------------------->
+
+ 6. R2 Send initial route updates, followed by End-Of-Rib.
+
+ <----------------------------------------------------------------------
+
+ 7. R1 was waiting for End-Of-Rib from R2 & which has been received
+ now.
+
+ 8. R1 now runs BGP Best-Path algorithm. Send Initial BGP Update,
+ followed by End-Of Rib
+
+ <--------------------------------------------------------------------->
+
+
+.. _bgp-end-of-rib-message:
+
+End-of-RIB (EOR) message
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+An UPDATE message with no reachable Network Layer Reachability Information
+(NLRI) and empty withdrawn NLRI is specified as the End-of-RIB marker that can
+be used by a BGP speaker to indicate to its peer the completion of the initial
+routing update after the session is established.
+
+For the IPv4 unicast address family, the End-of-RIB marker is an UPDATE message
+with the minimum length. For any other address family, it is an UPDATE message
+that contains only the MP_UNREACH_NLRI attribute with no withdrawn routes for
+that <AFI, SAFI>.
+
+Although the End-of-RIB marker is specified for the purpose of BGP graceful
+restart, it is noted that the generation of such a marker upon completion of
+the initial update would be useful for routing convergence in general, and thus
+the practice is recommended.
+
+.. _bgp-route-selection-deferral-timer:
+
+Route Selection Deferral Timer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Specifies the time the restarting router defers the route selection process
+after restart.
+
+Restarting Router : The usage of route election deferral timer is specified
+in https://tools.ietf.org/html/rfc4724#section-4.1
+
+Once the session between the Restarting Speaker and the Receiving Speaker is
+re-established, the Restarting Speaker will receive and process BGP messages
+from its peers.
+
+However, it MUST defer route selection for an address family until it either.
+
+1. Receives the End-of-RIB marker from all its peers (excluding the ones with
+ the "Restart State" bit set in the received capability and excluding the ones
+ that do not advertise the graceful restart capability).
+2. The Selection_Deferral_Timer timeout.
+
+.. index:: bgp graceful-restart select-defer-time (0-3600)
+.. clicmd:: bgp graceful-restart select-defer-time (0-3600)
+
+ This is command, will set deferral time to value specified.
+
+
+.. index:: bgp graceful-restart rib-stale-time (1-3600)
+.. clicmd:: bgp graceful-restart rib-stale-time (1-3600)
+
+ This is command, will set the time for which stale routes are kept in RIB.
+
+.. _bgp-per-peer-graceful-restart:
+
+BGP Per Peer Graceful Restart
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Ability to enable and disable graceful restart, helper and no GR at all mode
+functionality at peer level.
+
+So bgp graceful restart can be enabled at modes global BGP level or at per
+peer level. There are two FSM, one for BGP GR global mode and other for peer
+per GR.
+
+Default global mode is helper and default peer per mode is inherit from global.
+If per peer mode is configured, the GR mode of this particular peer will
+override the global mode.
+
+.. _bgp-GR-global-mode-cmd:
+
+BGP GR Global Mode Commands
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. index:: bgp graceful-restart
+.. clicmd:: bgp graceful-restart
+
+ This command will enable BGP graceful restart ifunctionality at the global
+ level.
+
+.. index:: bgp graceful-restart disable
+.. clicmd:: bgp graceful-restart disable
+
+ This command will disable both the functionality graceful restart and helper
+ mode.
+
+
+.. _bgp-GR-peer-mode-cmd:
+
+BGP GR Peer Mode Commands
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. index:: neighbor A.B.C.D graceful-restart
+.. clicmd:: neighbor A.B.C.D graceful-restart
+
+ This command will enable BGP graceful restart ifunctionality at the peer
+ level.
+
+.. index:: neighbor A.B.C.D graceful-restart-helper
+.. clicmd:: neighbor A.B.C.D graceful-restart-helper
+
+ This command will enable BGP graceful restart helper only functionality
+ at the peer level.
+
+.. index:: neighbor A.B.C.D graceful-restart-disable
+.. clicmd:: neighbor A.B.C.D graceful-restart-disable
+
+ This command will disable the entire BGP graceful restart functionality
+ at the peer level.
+
+
.. _bgp-network:
Networks
Set explicitly network type for specified interface.
+OSPF6 route-map
+===============
+
+Usage of *ospfd6*'s route-map support.
+
+.. index:: set metric [+|-](0-4294967295)
+.. clicmd:: set metric [+|-](0-4294967295)
+
+ Set a metric for matched route when sending announcement. Use plus (+) sign
+ to add a metric value to an existing metric. Use minus (-) sign to
+ substract a metric value from an existing metric.
+
.. _redistribute-routes-to-ospf6:
Redistribute routes to OSPF6
Enable ospf on an interface and set associated area.
+OSPF route-map
+==============
+
+Usage of *ospfd*'s route-map support.
+
+.. index:: set metric [+|-](0-4294967295)
+.. clicmd:: set metric [+|-](0-4294967295)
+
+ Set a metric for matched route when sending announcement. Use plus (+) sign
+ to add a metric value to an existing metric. Use minus (-) sign to
+ substract a metric value from an existing metric.
+
.. _redistribute-routes-to-ospf:
Redistribution
This command is available under interface sub-mode. This turns
on the PBR map NAME and allows it to work properly.
+.. note::
+ This will not dynamically create PBR maps on sub-interfaces (i.e. vlans)
+ even if one is on the master. Each must have the PBR map explicitly added
+ to the interface.
+
.. _pbr-details:
PBR Details
have effect for vtysh) need to be manually updated in :file:`vtysh.conf`.
+.. index:: copy FILENAME running-config
+.. clicmd:: copy FILENAME running-config
+
+ Process and load a configuration file manually; each line in the
+ file is read and processed as if it were being typed (or piped) to
+ vtysh.
+
+
Pager usage
===========
Reset statistics related to the zebra code that interacts with the
optional Forwarding Plane Manager (FPM) component.
-.. index:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]
-.. clicmd:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]
-
- Display nexthop groups created by zebra.
+.. index:: show nexthop-group rib [ID] [vrf NAME] [singleton [ip|ip6]]
+.. clicmd:: show nexthop-group rib [ID] [vrf NAME]
+
+ Display nexthop groups created by zebra. The [vrf NAME] option
+ is only meaningful if you have started zebra with the --vrfwnetns
+ option as that nexthop groups are per namespace in linux.
+ If you specify singleton you would like to see the singleton
+ nexthop groups that do have an afi.
Router-id
eigrp_fifo_free(ei->obuf);
XFREE(MTYPE_EIGRP_IF_INFO, ifp->info);
- ifp->info = NULL;
return 0;
}
static const struct frr_yang_module_info *const eigrpd_yang_modules[] = {
&frr_eigrpd_info,
&frr_interface_info,
+ &frr_route_map_info,
};
FRR_DAEMON_INFO(eigrpd, EIGRP, .vty_port = EIGRP_VTY_PORT,
rn->info = (void *)pref;
/* Schedule Router ID Update. */
- if (eigrp->router_id.s_addr == 0)
+ if (eigrp->router_id.s_addr == INADDR_ANY)
eigrp_router_id_update(eigrp);
/* Run network config now. */
/* Get target interface. */
break;
case NB_EV_APPLY:
eigrp = nb_running_get_entry(dnode, NULL, true);
- eigrp->router_id_static.s_addr = 0;
+ eigrp->router_id_static.s_addr = INADDR_ANY;
break;
}
router_id_old = eigrp->router_id;
- if (eigrp->router_id_static.s_addr != 0)
+ if (eigrp->router_id_static.s_addr != INADDR_ANY)
router_id = eigrp->router_id_static;
- else if (eigrp->router_id.s_addr != 0)
+ else if (eigrp->router_id.s_addr != INADDR_ANY)
router_id = eigrp->router_id;
else
eigrp->vrf_id = vrf_id;
eigrp->vrid = 0;
eigrp->AS = as;
- eigrp->router_id.s_addr = 0;
- eigrp->router_id_static.s_addr = 0;
+ eigrp->router_id.s_addr = INADDR_ANY;
+ eigrp->router_id_static.s_addr = INADDR_ANY;
eigrp->sequence_number = 1;
/*Configure default K Values for EIGRP Process*/
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/*
+ * 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
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
return;
XFREE(MTYPE_BFD_SESSION, *session);
- *session = NULL;
}
static bool bfd_session_same(const struct bfd_session *session, int family,
#include "vrf.h"
#include "qobj.h"
#include "libfrr.h"
+#include "routemap.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
#ifndef FABRICD
&frr_isisd_info,
#endif /* ifndef FABRICD */
+ &frr_route_map_info,
};
#ifdef FABRICD
vty_out (vty, "mpls ldp\n");
- if (ldpd_conf->rtr_id.s_addr != 0)
- vty_out (vty, " router-id %s\n",
- inet_ntoa(ldpd_conf->rtr_id));
+ if (ldpd_conf->rtr_id.s_addr != INADDR_ANY)
+ vty_out(vty, " router-id %s\n", inet_ntoa(ldpd_conf->rtr_id));
if (ldpd_conf->lhello_holdtime != LINK_DFLT_HOLDTIME &&
ldpd_conf->lhello_holdtime != 0)
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();
*/
void bfd_info_free(struct bfd_info **bfd_info)
{
- if (*bfd_info) {
- XFREE(MTYPE_BFD_INFO, *bfd_info);
- *bfd_info = NULL;
- }
+ XFREE(MTYPE_BFD_INFO, *bfd_info);
}
/*
zlog_reset_file();
XFREE(MTYPE_HOST, host.logfile);
-
- host.logfile = NULL;
}
DEFUN (no_config_log_file,
void cmd_banner_motd_line(const char *line)
{
- if (host.motd)
- XFREE(MTYPE_HOST, host.motd);
+ XFREE(MTYPE_HOST, host.motd);
host.motd = XSTRDUP(MTYPE_HOST, line);
}
#define DAEMONS_LIST \
"<zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd|fabricd|pimd|staticd|sharpd|vrrpd|ldpd>"
+/* Graceful Restart cli help strings */
+#define GR_CMD "Global Graceful Restart command\n"
+#define NO_GR_CMD "Undo Global Graceful Restart command\n"
+#define GR "Global Graceful Restart - GR Mode\n"
+#define GR_DISABLE "Global Graceful Restart - Disable Mode\n"
+#define NO_GR_DISABLE "Undo Global Graceful Restart - Disable Mode\n"
+#define GR_DEBUG "Graceful Restart - Enable Debug Logs\n"
+#define GR_SHOW "Graceful Restart - Show command for Global and all neighbor mode\n"
+#define GR_NEIGHBOR_CMD "Graceful Restart command for a neighbor\n"
+#define NO_GR_NEIGHBOR_CMD "Undo Graceful Restart command for a neighbor\n"
+#define GR_NEIGHBOR_DISABLE_CMD "Graceful Restart Disable command for a neighbor\n"
+#define NO_GR_NEIGHBOR_DISABLE_CMD "Undo Graceful Restart Disable command for a neighbor\n"
+#define GR_NEIGHBOR_HELPER_CMD "Graceful Restart Helper command for a neighbor\n"
+#define NO_GR_NEIGHBOR_HELPER_CMD "Undo Graceful Restart Helper command for a neighbor\n"
+
/* Prototypes. */
-extern void install_node(struct cmd_node *, int (*)(struct vty *));
+extern void install_node(struct cmd_node *node, int (*)(struct vty *));
extern void install_default(enum node_type);
extern void install_element(enum node_type, const struct cmd_element *);
return 0;
XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
- dist->list[type] = NULL;
/* Apply this distribute-list to the interface. */
(ctx->distribute_delete_hook)(ctx, dist);
return 0;
XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
- dist->prefix[type] = NULL;
/* Apply this distribute-list to the interface. */
(ctx->distribute_delete_hook)(ctx, dist);
return CMD_WARNING_CONFIG_FAILED;
}
- if (access->remark) {
- XFREE(MTYPE_TMP, access->remark);
- access->remark = NULL;
- }
+ XFREE(MTYPE_TMP, access->remark);
if (access->head == NULL && access->tail == NULL)
access_list_delete(access);
else {
vty_out(vty, " %s",
inet_ntoa(filter->addr));
- if (filter->addr_mask.s_addr != 0)
+ if (filter->addr_mask.s_addr
+ != INADDR_ANY)
vty_out(vty,
", wildcard bits %s",
inet_ntoa(
else {
vty_out(vty, " %s",
inet_ntoa(filter->addr));
- if (filter->addr_mask.s_addr != 0)
+ if (filter->addr_mask.s_addr
+ != INADDR_ANY)
vty_out(vty,
", wildcard bits %s",
inet_ntoa(
vty_out(vty, " ip");
if (filter->addr_mask.s_addr == 0xffffffff)
vty_out(vty, " any");
- else if (filter->addr_mask.s_addr == 0)
+ else if (filter->addr_mask.s_addr == INADDR_ANY)
vty_out(vty, " host %s", inet_ntoa(filter->addr));
else {
vty_out(vty, " %s", inet_ntoa(filter->addr));
if (filter->mask_mask.s_addr == 0xffffffff)
vty_out(vty, " any");
- else if (filter->mask_mask.s_addr == 0)
+ else if (filter->mask_mask.s_addr == INADDR_ANY)
vty_out(vty, " host %s", inet_ntoa(filter->mask));
else {
vty_out(vty, " %s", inet_ntoa(filter->mask));
vty_out(vty, " any\n");
else {
vty_out(vty, " %s", inet_ntoa(filter->addr));
- if (filter->addr_mask.s_addr != 0)
+ if (filter->addr_mask.s_addr != INADDR_ANY)
vty_out(vty, " %s",
inet_ntoa(filter->addr_mask));
vty_out(vty, "\n");
if (ifp->link_params == NULL)
return;
XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params);
- ifp->link_params = NULL;
}
/* ----------- CLI commands ----------- */
return 0;
XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
- if_rmap->routemap[IF_RMAP_IN] = NULL;
}
if (type == IF_RMAP_OUT) {
return 0;
XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
- if_rmap->routemap[IF_RMAP_OUT] = NULL;
}
if (ctx->if_rmap_delete_hook)
zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
XFREE(MTYPE_ZLOG, zl->filename);
- zl->filename = NULL;
return 1;
}
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", '?'};
void ns_disable(struct ns *ns)
{
- return ns_disable_internal(ns);
+ ns_disable_internal(ns);
}
struct ns *ns_lookup(ns_id_t ns_id)
for (; depth > 0; depth--)
if (trie_table_empty(*tables[depth])) {
XFREE(MTYPE_PREFIX_LIST_TRIE, *tables[depth]);
- *tables[depth] = NULL;
}
}
return CMD_WARNING_CONFIG_FAILED;
}
- if (plist->desc) {
- XFREE(MTYPE_TMP, plist->desc);
- plist->desc = NULL;
- }
+ XFREE(MTYPE_TMP, plist->desc);
if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
prefix_list_delete(plist);
/* If prefix is 0.0.0.0/0 then return 1 else return 0. */
int prefix_ipv4_any(const struct prefix_ipv4 *p)
{
- return (p->prefix.s_addr == 0 && p->prefixlen == 0);
+ return (p->prefix.s_addr == INADDR_ANY && p->prefixlen == 0);
}
/* Allocate a new ip version 6 route */
void prefix_free(struct prefix **p)
{
XFREE(MTYPE_PREFIX, *p);
- *p = NULL;
}
/* Utility function to convert ipv4 prefixes to Classful prefixes */
masklen2ip(masklen, &mask);
return (masklen != IPV4_MAX_PREFIXLEN - 1) ?
- /* normal case */
- (hostaddr | ~mask.s_addr)
- :
- /* special case for /31 */
- (hostaddr ^ ~mask.s_addr);
+ /* normal case */
+ (hostaddr | ~mask.s_addr)
+ :
+ /* For prefix 31 return 255.255.255.255 (RFC3021) */
+ htonl(0xFFFFFFFF);
}
/* Utility function to convert ipv4 netmask to prefixes
} else {
destination = ntohl(network.s_addr);
- if (network.s_addr == 0)
+ if (network.s_addr == INADDR_ANY)
prefixlen = 0;
else if (IN_CLASSC(destination))
prefixlen = 24;
extern void masklen2ip(const int, struct in_addr *);
/* given the address of a host on a network and the network mask length,
* calculate the broadcast address for that network;
- * special treatment for /31: returns the address of the other host
- * on the network by flipping the host bit */
+ * special treatment for /31 according to RFC3021 section 3.3 */
extern in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen);
extern int netmask_str2prefix_str(const char *, const char *, char *);
/* Vector for route set rules. */
static vector route_set_vec;
-struct route_map_match_set_hooks {
- /* match interface */
- int (*match_interface)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* no match interface */
- int (*no_match_interface)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* match ip address */
- int (*match_ip_address)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* no match ip address */
- int (*no_match_ip_address)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* match ip address prefix list */
- int (*match_ip_address_prefix_list)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
-
- /* no match ip address prefix list */
- int (*no_match_ip_address_prefix_list)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
-
- /* match ip next hop */
- int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* no match ip next hop */
- int (*no_match_ip_next_hop)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* match ip next hop prefix list */
- int (*match_ip_next_hop_prefix_list)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
-
- /* no match ip next hop prefix list */
- int (*no_match_ip_next_hop_prefix_list)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
-
- /* match ip next-hop type */
- int (*match_ip_next_hop_type)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
-
- /* no match ip next-hop type */
- int (*no_match_ip_next_hop_type)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
-
- /* match ipv6 address */
- int (*match_ipv6_address)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* no match ipv6 address */
- int (*no_match_ipv6_address)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
-
- /* match ipv6 address prefix list */
- int (*match_ipv6_address_prefix_list)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
-
- /* no match ipv6 address prefix list */
- int (*no_match_ipv6_address_prefix_list)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
-
- /* match ipv6 next-hop type */
- int (*match_ipv6_next_hop_type)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
-
- /* no match ipv6 next-hop type */
- int (*no_match_ipv6_next_hop_type)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* match metric */
- int (*match_metric)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* no match metric */
- int (*no_match_metric)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* match tag */
- int (*match_tag)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* no match tag */
- int (*no_match_tag)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg,
- route_map_event_t type);
-
- /* set ip nexthop */
- int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
-
- /* no set ip nexthop */
- int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
-
- /* set ipv6 nexthop local */
- int (*set_ipv6_nexthop_local)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg);
-
- /* no set ipv6 nexthop local */
- int (*no_set_ipv6_nexthop_local)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg);
-
- /* set metric */
- int (*set_metric)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
-
- /* no set metric */
- int (*no_set_metric)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
-
- /* set tag */
- int (*set_tag)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
-
- /* no set tag */
- int (*no_set_tag)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
-};
-
-static struct route_map_match_set_hooks rmap_match_set_hook;
+struct route_map_match_set_hooks rmap_match_set_hook;
/* match interface */
void route_map_match_interface_hook(int (*func)(
ret = route_map_add_match(index, command, arg, type);
switch (ret) {
case RMAP_RULE_MISSING:
- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+ if (vty)
+ vty_out(vty, "%% [%s] Can't find rule.\n",
+ frr_protonameinst);
+ else
+ zlog_warn("Can't find rule: %s", command);
return CMD_WARNING_CONFIG_FAILED;
- break;
case RMAP_COMPILE_ERROR:
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
+ if (vty)
+ vty_out(vty,
+ "%% [%s] Argument form is unsupported or malformed.\n",
+ frr_protonameinst);
+ else
+ zlog_warn("Argument form is unsupported or malformed: "
+ "%s %s", command, arg);
return CMD_WARNING_CONFIG_FAILED;
- break;
case RMAP_COMPILE_SUCCESS:
/*
* Nothing to do here move along
ret = route_map_delete_match(index, command, dep_name, type);
switch (ret) {
case RMAP_RULE_MISSING:
- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+ if (vty)
+ vty_out(vty, "%% [%s] Can't find rule.\n",
+ frr_protonameinst);
+ else
+ zlog_warn("Can't find rule: %s", command);
retval = CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_ERROR:
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
+ if (vty)
+ vty_out(vty,
+ "%% [%s] Argument form is unsupported or malformed.\n",
+ frr_protonameinst);
+ else
+ zlog_warn("Argument form is unsupported or malformed: "
+ "%s %s", command, arg);
retval = CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_SUCCESS:
ret = route_map_add_set(index, command, arg);
switch (ret) {
case RMAP_RULE_MISSING:
- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+ if (vty)
+ vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+ else
+ zlog_warn("Can't find rule: %s", command);
return CMD_WARNING_CONFIG_FAILED;
- break;
case RMAP_COMPILE_ERROR:
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
+ if (vty)
+ vty_out(vty,
+ "%% [%s] Argument form is unsupported or malformed.\n",
+ frr_protonameinst);
+ else
+ zlog_warn("Argument form is unsupported or malformed: "
+ "%s %s", command, arg);
return CMD_WARNING_CONFIG_FAILED;
- break;
case RMAP_COMPILE_SUCCESS:
break;
}
ret = route_map_delete_set(index, command, arg);
switch (ret) {
case RMAP_RULE_MISSING:
- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+ if (vty)
+ vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+ else
+ zlog_warn("Can't find rule: %s", command);
return CMD_WARNING_CONFIG_FAILED;
- break;
case RMAP_COMPILE_ERROR:
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
+ if (vty)
+ vty_out(vty,
+ "%% [%s] Argument form is unsupported or malformed.\n",
+ frr_protonameinst);
+ else
+ zlog_warn("Argument form is unsupported or malformed: "
+ "%s %s", command, arg);
return CMD_WARNING_CONFIG_FAILED;
- break;
case RMAP_COMPILE_SUCCESS:
break;
}
}
-/* Route map rule. This rule has both `match' rule and `set' rule. */
-struct route_map_rule {
- /* Rule type. */
- const struct route_map_rule_cmd *cmd;
-
- /* For pretty printing. */
- char *rule_str;
-
- /* Pre-compiled match rule. */
- void *value;
-
- /* Linked list. */
- struct route_map_rule *next;
- struct route_map_rule *prev;
-};
-
-/* Making route map list. */
-struct route_map_list {
- struct route_map *head;
- struct route_map *tail;
-
- void (*add_hook)(const char *);
- void (*delete_hook)(const char *);
- void (*event_hook)(const char *);
-};
-
/* Master list of route map. */
-static struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
-static struct hash *route_map_master_hash = NULL;
+struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
+struct hash *route_map_master_hash = NULL;
static unsigned int route_map_hash_key_make(const void *p)
{
struct route_map_rule *);
static bool rmap_debug;
-static void route_map_index_delete(struct route_map_index *, int);
-
/* New route map allocation. Please note route map's name must be
specified. */
static struct route_map *route_map_new(const char *name)
}
/* Route map delete from list. */
-static void route_map_delete(struct route_map *map)
+void route_map_delete(struct route_map *map)
{
struct route_map_index *index;
char *name;
/* Lookup route map. If there isn't route map create one and return
it. */
-static struct route_map *route_map_get(const char *name)
+struct route_map *route_map_get(const char *name)
{
struct route_map *map;
return "invalid";
}
-static int route_map_empty(struct route_map *map)
-{
- if (map->head == NULL && map->tail == NULL)
- return 1;
- else
- return 0;
-}
-
/* show route-map */
static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
{
new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
+ TAILQ_INIT(&new->rhclist);
QOBJ_REG(new, route_map_index);
return new;
}
/* Free route map index. */
-static void route_map_index_delete(struct route_map_index *index, int notify)
+void route_map_index_delete(struct route_map_index *index, int notify)
{
struct route_map_rule *rule;
zlog_debug("Deleting route-map %s sequence %d",
index->map->name, index->pref);
+ /* Free route map northbound hook contexts. */
+ while (!TAILQ_EMPTY(&index->rhclist))
+ routemap_hook_context_free(TAILQ_FIRST(&index->rhclist));
+
/* Free route match. */
while ((rule = index->match_list.head) != NULL)
route_map_rule_delete(&index->match_list, rule);
}
/* Get route map index. */
-static struct route_map_index *
+struct route_map_index *
route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
{
struct route_map_index *index;
hash_free(dep->dep_rmap_hash);
XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
XFREE(MTYPE_ROUTE_MAP_DEP, dep);
- dep = NULL;
}
break;
case RMAP_EVENT_SET_ADDED:
/* VTY related functions. */
-DEFUN (match_interface,
- match_interface_cmd,
- "match interface WORD",
- MATCH_STR
- "match first hop interface of route\n"
- "Interface name\n")
-{
- int idx_word = 2;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_interface)
- return rmap_match_set_hook.match_interface(
- vty, index, "interface", argv[idx_word]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_match_interface,
- no_match_interface_cmd,
- "no match interface [WORD]",
- NO_STR
- MATCH_STR
- "Match first hop interface of route\n"
- "Interface name\n")
-{
- char *iface = (argc == 4) ? argv[3]->arg : NULL;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_interface)
- return rmap_match_set_hook.no_match_interface(
- vty, index, "interface", iface,
- RMAP_EVENT_MATCH_DELETED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_address,
- match_ip_address_cmd,
- "match ip address <(1-199)|(1300-2699)|WORD>",
- MATCH_STR
- IP_STR
- "Match address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
- "IP Access-list name\n")
-{
- int idx_acl = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_address)
- return rmap_match_set_hook.match_ip_address(
- vty, index, "ip address", argv[idx_acl]->arg,
- RMAP_EVENT_FILTER_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_ip_address,
- no_match_ip_address_cmd,
- "no match ip address [<(1-199)|(1300-2699)|WORD>]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
- "IP Access-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_address) {
- if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_address(
- vty, index, "ip address", NULL,
- RMAP_EVENT_FILTER_DELETED);
- return rmap_match_set_hook.no_match_ip_address(
- vty, index, "ip address", argv[idx_word]->arg,
- RMAP_EVENT_FILTER_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_address_prefix_list,
- match_ip_address_prefix_list_cmd,
- "match ip address prefix-list WORD",
- MATCH_STR
- IP_STR
- "Match address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_address_prefix_list)
- return rmap_match_set_hook.match_ip_address_prefix_list(
- vty, index, "ip address prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_ip_address_prefix_list,
- no_match_ip_address_prefix_list_cmd,
- "no match ip address prefix-list [WORD]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
- if (argc <= idx_word)
- return rmap_match_set_hook
- .no_match_ip_address_prefix_list(
- vty, index, "ip address prefix-list",
- NULL, RMAP_EVENT_PLIST_DELETED);
- return rmap_match_set_hook.no_match_ip_address_prefix_list(
- vty, index, "ip address prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_next_hop,
- match_ip_next_hop_cmd,
- "match ip next-hop <(1-199)|(1300-2699)|WORD>",
- MATCH_STR
- IP_STR
- "Match next-hop address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
- "IP Access-list name\n")
-{
- int idx_acl = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_next_hop)
- return rmap_match_set_hook.match_ip_next_hop(
- vty, index, "ip next-hop", argv[idx_acl]->arg,
- RMAP_EVENT_FILTER_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_ip_next_hop,
- no_match_ip_next_hop_cmd,
- "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match next-hop address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
- "IP Access-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_next_hop) {
- if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop", NULL,
- RMAP_EVENT_FILTER_DELETED);
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop", argv[idx_word]->arg,
- RMAP_EVENT_FILTER_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_next_hop_prefix_list,
- match_ip_next_hop_prefix_list_cmd,
- "match ip next-hop prefix-list WORD",
- MATCH_STR
- IP_STR
- "Match next-hop address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
- return rmap_match_set_hook.match_ip_next_hop_prefix_list(
- vty, index, "ip next-hop prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_match_ip_next_hop_prefix_list,
- no_match_ip_next_hop_prefix_list_cmd,
- "no match ip next-hop prefix-list [WORD]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match next-hop address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_next_hop) {
- if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop prefix-list", NULL,
- RMAP_EVENT_PLIST_DELETED);
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd,
- "match ip next-hop type <blackhole>",
- MATCH_STR IP_STR
- "Match next-hop address of route\n"
- "Match entries by type\n"
- "Blackhole\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_next_hop_type)
- return rmap_match_set_hook.match_ip_next_hop_type(
- vty, index, "ip next-hop type", argv[idx_word]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
- "no match ip next-hop type [<blackhole>]",
- NO_STR MATCH_STR IP_STR
- "Match next-hop address of route\n"
- "Match entries by type\n"
- "Blackhole\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_next_hop) {
- if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop type", NULL,
- RMAP_EVENT_MATCH_DELETED);
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop type", argv[idx_word]->arg,
- RMAP_EVENT_MATCH_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ipv6_address,
- match_ipv6_address_cmd,
- "match ipv6 address WORD",
- MATCH_STR
- IPV6_STR
- "Match IPv6 address of route\n"
- "IPv6 access-list name\n")
-{
- int idx_word = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ipv6_address)
- return rmap_match_set_hook.match_ipv6_address(
- vty, index, "ipv6 address", argv[idx_word]->arg,
- RMAP_EVENT_FILTER_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_match_ipv6_address,
- no_match_ipv6_address_cmd,
- "no match ipv6 address WORD",
- NO_STR
- MATCH_STR
- IPV6_STR
- "Match IPv6 address of route\n"
- "IPv6 access-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ipv6_address)
- return rmap_match_set_hook.no_match_ipv6_address(
- vty, index, "ipv6 address", argv[idx_word]->arg,
- RMAP_EVENT_FILTER_DELETED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ipv6_address_prefix_list,
- match_ipv6_address_prefix_list_cmd,
- "match ipv6 address prefix-list WORD",
- MATCH_STR
- IPV6_STR
- "Match address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ipv6_address_prefix_list)
- return rmap_match_set_hook.match_ipv6_address_prefix_list(
- vty, index, "ipv6 address prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_match_ipv6_address_prefix_list,
- no_match_ipv6_address_prefix_list_cmd,
- "no match ipv6 address prefix-list WORD",
- NO_STR
- MATCH_STR
- IPV6_STR
- "Match address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
- return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
- vty, index, "ipv6 address prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
- return CMD_SUCCESS;
-}
-
-DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
- "match ipv6 next-hop type <blackhole>",
- MATCH_STR IPV6_STR
- "Match next-hop address of route\n"
- "Match entries by type\n"
- "Blackhole\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ipv6_next_hop_type)
- return rmap_match_set_hook.match_ipv6_next_hop_type(
- vty, index, "ipv6 next-hop type", argv[idx_word]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
- "no match ipv6 next-hop type [<blackhole>]",
- NO_STR MATCH_STR IPV6_STR
- "Match address of route\n"
- "Match entries by type\n"
- "Blackhole\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ipv6_next_hop_type)
- return rmap_match_set_hook.no_match_ipv6_next_hop_type(
- vty, index, "ipv6 next-hop type",
- (argc <= idx_word) ? NULL : argv[idx_word]->arg,
- RMAP_EVENT_MATCH_DELETED);
- return CMD_SUCCESS;
-}
-
-DEFUN (match_metric,
- match_metric_cmd,
- "match metric (0-4294967295)",
- MATCH_STR
- "Match metric of route\n"
- "Metric value\n")
-{
- int idx_number = 2;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_metric)
- return rmap_match_set_hook.match_metric(vty, index, "metric",
- argv[idx_number]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_metric,
- no_match_metric_cmd,
- "no match metric [(0-4294967295)]",
- NO_STR
- MATCH_STR
- "Match metric of route\n"
- "Metric value\n")
-{
- int idx_number = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_metric) {
- if (argc <= idx_number)
- return rmap_match_set_hook.no_match_metric(
- vty, index, "metric", NULL,
- RMAP_EVENT_MATCH_DELETED);
- return rmap_match_set_hook.no_match_metric(
- vty, index, "metric", argv[idx_number]->arg,
- RMAP_EVENT_MATCH_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_tag,
- match_tag_cmd,
- "match tag (1-4294967295)",
- MATCH_STR
- "Match tag of route\n"
- "Tag value\n")
-{
- int idx_number = 2;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_tag)
- return rmap_match_set_hook.match_tag(vty, index, "tag",
- argv[idx_number]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_tag,
- no_match_tag_cmd,
- "no match tag [(1-4294967295)]",
- NO_STR
- MATCH_STR
- "Match tag of route\n"
- "Tag value\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- int idx = 0;
- char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
- ? argv[idx]->arg
- : NULL;
-
- if (rmap_match_set_hook.no_match_tag)
- return rmap_match_set_hook.no_match_tag(
- vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (set_ip_nexthop,
- set_ip_nexthop_cmd,
- "set ip next-hop A.B.C.D",
- SET_STR
- IP_STR
- "Next hop address\n"
- "IP address of next hop\n")
-{
- int idx_ipv4 = 3;
- union sockunion su;
- int ret;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- ret = str2sockunion(argv[idx_ipv4]->arg, &su);
- if (ret < 0) {
- vty_out(vty, "%% Malformed nexthop address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (su.sin.sin_addr.s_addr == 0
- || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
- vty_out(vty,
- "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (rmap_match_set_hook.set_ip_nexthop)
- return rmap_match_set_hook.set_ip_nexthop(
- vty, index, "ip next-hop", argv[idx_ipv4]->arg);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_ip_nexthop,
- no_set_ip_nexthop_cmd,
- "no set ip next-hop [A.B.C.D]",
- NO_STR
- SET_STR
- IP_STR
- "Next hop address\n"
- "IP address of next hop\n")
-{
- int idx = 0;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- const char *arg = NULL;
-
- if (argv_find(argv, argc, "A.B.C.D", &idx))
- arg = argv[idx]->arg;
-
- if (rmap_match_set_hook.no_set_ip_nexthop)
- return rmap_match_set_hook.no_set_ip_nexthop(
- vty, index, "ip next-hop", arg);
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN (set_ipv6_nexthop_local,
- set_ipv6_nexthop_local_cmd,
- "set ipv6 next-hop local X:X::X:X",
- SET_STR
- IPV6_STR
- "IPv6 next-hop address\n"
- "IPv6 local address\n"
- "IPv6 address of next hop\n")
-{
- int idx_ipv6 = 4;
- struct in6_addr addr;
- int ret;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
- if (!ret) {
- vty_out(vty, "%% Malformed nexthop address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
- vty_out(vty, "%% Invalid link-local nexthop address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (rmap_match_set_hook.set_ipv6_nexthop_local)
- return rmap_match_set_hook.set_ipv6_nexthop_local(
- vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_ipv6_nexthop_local,
- no_set_ipv6_nexthop_local_cmd,
- "no set ipv6 next-hop local [X:X::X:X]",
- NO_STR
- SET_STR
- IPV6_STR
- "IPv6 next-hop address\n"
- "IPv6 local address\n"
- "IPv6 address of next hop\n")
-{
- int idx_ipv6 = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
- if (argc <= idx_ipv6)
- return rmap_match_set_hook.no_set_ipv6_nexthop_local(
- vty, index, "ipv6 next-hop local", NULL);
- return rmap_match_set_hook.no_set_ipv6_nexthop_local(
- vty, index, "ipv6 next-hop local", argv[5]->arg);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (set_metric,
- set_metric_cmd,
- "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
- SET_STR
- "Metric value for destination routing protocol\n"
- "Metric value\n"
- "Assign round trip time\n"
- "Add round trip time\n"
- "Subtract round trip time\n"
- "Add metric\n"
- "Subtract metric\n")
-{
- int idx_number = 2;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- const char *pass = (argv[idx_number]->type == RANGE_TKN)
- ? argv[idx_number]->arg
- : argv[idx_number]->text;
-
- if (rmap_match_set_hook.set_metric)
- return rmap_match_set_hook.set_metric(vty, index, "metric",
- pass);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_metric,
- no_set_metric_cmd,
- "no set metric [(0-4294967295)]",
- NO_STR
- SET_STR
- "Metric value for destination routing protocol\n"
- "Metric value\n")
-{
- int idx_number = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_set_metric) {
- if (argc <= idx_number)
- return rmap_match_set_hook.no_set_metric(
- vty, index, "metric", NULL);
- return rmap_match_set_hook.no_set_metric(vty, index, "metric",
- argv[idx_number]->arg);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (set_tag,
- set_tag_cmd,
- "set tag (1-4294967295)",
- SET_STR
- "Tag value for routing protocol\n"
- "Tag value\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- int idx_number = 2;
- if (rmap_match_set_hook.set_tag)
- return rmap_match_set_hook.set_tag(vty, index, "tag",
- argv[idx_number]->arg);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_tag,
- no_set_tag_cmd,
- "no set tag [(1-4294967295)]",
- NO_STR
- SET_STR
- "Tag value for routing protocol\n"
- "Tag value\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- int idx_number = 3;
- if (rmap_match_set_hook.no_set_tag) {
- if (argc <= idx_number)
- return rmap_match_set_hook.no_set_tag(vty, index, "tag",
- NULL);
- return rmap_match_set_hook.no_set_tag(vty, index, "tag",
- argv[idx_number]->arg);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN_NOSH (route_map,
- route_map_cmd,
- "route-map WORD <deny|permit> (1-65535)",
- "Create route-map or enter route-map command mode\n"
- "Route map tag\n"
- "Route map denies set operations\n"
- "Route map permits set operations\n"
- "Sequence to insert to/delete from existing route-map entry\n")
-{
- int idx_word = 1;
- int idx_permit_deny = 2;
- int idx_number = 3;
- struct route_map *map;
- struct route_map_index *index;
- char *endptr = NULL;
- int permit =
- argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
- unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
- const char *mapname = argv[idx_word]->arg;
-
- /* Get route map. */
- map = route_map_get(mapname);
- index = route_map_index_get(map, permit, pref);
-
- VTY_PUSH_CONTEXT(RMAP_NODE, index);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_route_map_all,
- no_route_map_all_cmd,
- "no route-map WORD",
- NO_STR
- "Create route-map or enter route-map command mode\n"
- "Route map tag\n")
-{
- int idx_word = 2;
- const char *mapname = argv[idx_word]->arg;
- struct route_map *map;
-
- map = route_map_lookup_by_name(mapname);
- if (map == NULL) {
- vty_out(vty, "%% Could not find route-map %s\n", mapname);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- route_map_delete(map);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_route_map,
- no_route_map_cmd,
- "no route-map WORD <deny|permit> (1-65535)",
- NO_STR
- "Create route-map or enter route-map command mode\n"
- "Route map tag\n"
- "Route map denies set operations\n"
- "Route map permits set operations\n"
- "Sequence to insert to/delete from existing route-map entry\n")
-{
- int idx_word = 2;
- int idx_permit_deny = 3;
- int idx_number = 4;
- struct route_map *map;
- struct route_map_index *index;
- char *endptr = NULL;
- int permit = strmatch(argv[idx_permit_deny]->text, "permit")
- ? RMAP_PERMIT
- : RMAP_DENY;
- const char *prefstr = argv[idx_number]->arg;
- const char *mapname = argv[idx_word]->arg;
- unsigned long pref = strtoul(prefstr, &endptr, 10);
-
- /* Existence check. */
- map = route_map_lookup_by_name(mapname);
- if (map == NULL) {
- vty_out(vty, "%% Could not find route-map %s\n", mapname);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- /* Lookup route map index. */
- index = route_map_index_lookup(map, permit, pref);
- if (index == NULL) {
- vty_out(vty, "%% Could not find route-map entry %s %s\n",
- mapname, prefstr);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- /* Delete index from route map. */
- route_map_index_delete(index, 1);
-
- /* If this route rule is the last one, delete route map itself. */
- if (route_map_empty(map))
- route_map_delete(map);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (rmap_onmatch_next,
- rmap_onmatch_next_cmd,
- "on-match next",
- "Exit policy on matches\n"
- "Next clause\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index) {
- if (index->type == RMAP_DENY) {
- /* Under a deny clause, match means it's finished. No
- * need to set next */
- vty_out(vty,
- "on-match next not supported under route-map deny\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- index->exitpolicy = RMAP_NEXT;
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_onmatch_next,
- no_rmap_onmatch_next_cmd,
- "no on-match next",
- NO_STR
- "Exit policy on matches\n"
- "Next clause\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index)
- index->exitpolicy = RMAP_EXIT;
-
- return CMD_SUCCESS;
-}
-
-DEFUN (rmap_onmatch_goto,
- rmap_onmatch_goto_cmd,
- "on-match goto (1-65535)",
- "Exit policy on matches\n"
- "Goto Clause number\n"
- "Number\n")
-{
- int idx = 0;
- char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
- : NULL;
-
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
- int d = 0;
-
- if (index) {
- if (index->type == RMAP_DENY) {
- /* Under a deny clause, match means it's finished. No
- * need to go anywhere */
- vty_out(vty,
- "on-match goto not supported under route-map deny\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (num)
- d = strtoul(num, NULL, 10);
- else
- d = index->pref + 1;
-
- if (d <= index->pref) {
- /* Can't allow you to do that, Dave */
- vty_out(vty, "can't jump backwards in route-maps\n");
- return CMD_WARNING_CONFIG_FAILED;
- } else {
- index->exitpolicy = RMAP_GOTO;
- index->nextpref = d;
- }
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_onmatch_goto,
- no_rmap_onmatch_goto_cmd,
- "no on-match goto",
- NO_STR
- "Exit policy on matches\n"
- "Goto Clause number\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index)
- index->exitpolicy = RMAP_EXIT;
-
- return CMD_SUCCESS;
-}
-
-/* Cisco/GNU Zebra compatibility aliases */
-/* ALIAS_FIXME */
-DEFUN (rmap_continue,
- rmap_continue_cmd,
- "continue (1-65535)",
- "Continue on a different entry within the route-map\n"
- "Route-map entry sequence number\n")
-{
- return rmap_onmatch_goto(self, vty, argc, argv);
-}
-
-/* ALIAS_FIXME */
-DEFUN (no_rmap_continue,
- no_rmap_continue_cmd,
- "no continue [(1-65535)]",
- NO_STR
- "Continue on a different entry within the route-map\n"
- "Route-map entry sequence number\n")
-{
- return no_rmap_onmatch_goto(self, vty, argc, argv);
-}
-
static void clear_route_map_helper(struct route_map *map)
{
struct route_map_index *index;
return vty_show_unused_route_map(vty);
}
-DEFUN (rmap_call,
- rmap_call_cmd,
- "call WORD",
- "Jump to another Route-Map after match+set\n"
- "Target route-map name\n")
-{
- int idx_word = 1;
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
- const char *rmap = argv[idx_word]->arg;
-
- assert(index);
-
- /* If "call" is invoked with the same route-map name as
- * the one previously configured then, ignore the duplicate
- * configuration.
- */
- if (index->nextrm && (strcmp(index->nextrm, rmap) == 0))
- return CMD_SUCCESS;
-
- if (index->nextrm) {
- route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
- index->nextrm, index->map->name);
- XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
- }
- index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
-
- /* Execute event hook. */
- route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
- index->map->name);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_call,
- no_rmap_call_cmd,
- "no call",
- NO_STR
- "Jump to another Route-Map after match+set\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index->nextrm) {
- route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
- index->nextrm, index->map->name);
- XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
- index->nextrm = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (rmap_description,
- rmap_description_cmd,
- "description LINE...",
- "Route-map comment\n"
- "Comment describing this route-map rule\n")
-{
- int idx_line = 1;
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index) {
- if (index->description)
- XFREE(MTYPE_TMP, index->description);
- index->description = argv_concat(argv, argc, idx_line);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_description,
- no_rmap_description_cmd,
- "no description",
- NO_STR
- "Route-map comment\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index) {
- if (index->description)
- XFREE(MTYPE_TMP, index->description);
- index->description = NULL;
- }
- return CMD_SUCCESS;
-}
-
DEFUN (debug_rmap,
debug_rmap_cmd,
"debug route-map",
static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1};
/* Configuration write function. */
-static int route_map_config_write(struct vty *vty)
-{
- struct route_map *map;
- struct route_map_index *index;
- struct route_map_rule *rule;
- int first = 1;
- int write = 0;
- struct listnode *ln;
- struct list *maplist = list_new();
-
- for (map = route_map_master.head; map; map = map->next)
- listnode_add(maplist, map);
-
- list_sort(maplist, sort_route_map);
-
- for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
- for (index = map->head; index; index = index->next) {
- if (!first)
- vty_out(vty, "!\n");
- else
- first = 0;
-
- vty_out(vty, "route-map %s %s %d\n", map->name,
- route_map_type_str(index->type), index->pref);
-
- if (index->description)
- vty_out(vty, " description %s\n",
- index->description);
-
- for (rule = index->match_list.head; rule;
- rule = rule->next)
- vty_out(vty, " match %s %s\n", rule->cmd->str,
- rule->rule_str ? rule->rule_str : "");
-
- for (rule = index->set_list.head; rule;
- rule = rule->next)
- vty_out(vty, " set %s %s\n", rule->cmd->str,
- rule->rule_str ? rule->rule_str : "");
- if (index->nextrm)
- vty_out(vty, " call %s\n", index->nextrm);
- if (index->exitpolicy == RMAP_GOTO)
- vty_out(vty, " on-match goto %d\n",
- index->nextpref);
- if (index->exitpolicy == RMAP_NEXT)
- vty_out(vty, " on-match next\n");
-
- write++;
- }
-
- list_delete(&maplist);
- return write;
-}
-
static int rmap_config_write_debug(struct vty *vty)
{
int write = 0;
return write;
}
-/* Route map node structure. */
-static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
-
/* Common route map rules */
void *route_map_rule_tag_compile(const char *arg)
route_map_master_hash = NULL;
}
-static void rmap_autocomplete(vector comps, struct cmd_token *token)
-{
- struct route_map *map;
-
- for (map = route_map_master.head; map; map = map->next)
- vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
-}
-
/* Increment the use_count counter while attaching the route map */
void route_map_counter_increment(struct route_map *map)
{
}
}
-static const struct cmd_variable_handler rmap_var_handlers[] = {
- {/* "route-map WORD" */
- .varname = "route_map",
- .completions = rmap_autocomplete},
- {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
- {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
- {.completions = NULL}};
-
/* Initialization of route map vector. */
void route_map_init(void)
{
8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
"Route Map Dep Hash");
- cmd_variable_handler_register(rmap_var_handlers);
-
rmap_debug = false;
- /* Install route map top node. */
- install_node(&rmap_node, route_map_config_write);
+ route_map_cli_init();
+ /* Install route map top node. */
install_node(&rmap_debug_node, rmap_config_write_debug);
/* Install route map commands. */
- install_default(RMAP_NODE);
- install_element(CONFIG_NODE, &route_map_cmd);
- install_element(CONFIG_NODE, &no_route_map_cmd);
- install_element(CONFIG_NODE, &no_route_map_all_cmd);
-
install_element(CONFIG_NODE, &debug_rmap_cmd);
install_element(CONFIG_NODE, &no_debug_rmap_cmd);
- /* Install the on-match stuff */
- install_element(RMAP_NODE, &route_map_cmd);
- install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
- install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
- install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
- install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
- install_element(RMAP_NODE, &rmap_continue_cmd);
- install_element(RMAP_NODE, &no_rmap_continue_cmd);
-
- /* Install the continue stuff (ALIAS of on-match). */
-
- /* Install the call stuff. */
- install_element(RMAP_NODE, &rmap_call_cmd);
- install_element(RMAP_NODE, &no_rmap_call_cmd);
-
- /* Install description commands. */
- install_element(RMAP_NODE, &rmap_description_cmd);
- install_element(RMAP_NODE, &no_rmap_description_cmd);
-
/* Install show command */
install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
install_element(ENABLE_NODE, &debug_rmap_cmd);
install_element(ENABLE_NODE, &no_debug_rmap_cmd);
-
- install_element(RMAP_NODE, &match_interface_cmd);
- install_element(RMAP_NODE, &no_match_interface_cmd);
-
- install_element(RMAP_NODE, &match_ip_address_cmd);
- install_element(RMAP_NODE, &no_match_ip_address_cmd);
-
- install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
- install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
-
- install_element(RMAP_NODE, &match_ip_next_hop_cmd);
- install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
-
- install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
- install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
-
- install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
- install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
-
- install_element(RMAP_NODE, &match_ipv6_address_cmd);
- install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
-
- install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
- install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
-
- install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
- install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
-
- install_element(RMAP_NODE, &match_metric_cmd);
- install_element(RMAP_NODE, &no_match_metric_cmd);
-
- install_element(RMAP_NODE, &match_tag_cmd);
- install_element(RMAP_NODE, &no_match_tag_cmd);
-
- install_element(RMAP_NODE, &set_ip_nexthop_cmd);
- install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
-
- install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
- install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
-
- install_element(RMAP_NODE, &set_metric_cmd);
- install_element(RMAP_NODE, &no_set_metric_cmd);
-
- install_element(RMAP_NODE, &set_tag_cmd);
- install_element(RMAP_NODE, &no_set_tag_cmd);
}
};
+/* Route map rule. This rule has both `match' rule and `set' rule. */
+struct route_map_rule {
+ /* Rule type. */
+ const struct route_map_rule_cmd *cmd;
+
+ /* For pretty printing. */
+ char *rule_str;
+
+ /* Pre-compiled match rule. */
+ void *value;
+
+ /* Linked list. */
+ struct route_map_rule *next;
+ struct route_map_rule *prev;
+};
+
/* Route map rule list. */
struct route_map_rule_list {
struct route_map_rule *head;
struct route_map_rule *tail;
};
+/* Forward struct declaration: the complete can be found later this file. */
+struct routemap_hook_context;
+
/* Route map index structure. */
struct route_map_index {
struct route_map *map;
uint64_t applied;
uint64_t applied_clear;
+ /* List of match/sets contexts. */
+ TAILQ_HEAD(, routemap_hook_context) rhclist;
+
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(route_map_index)
/* Decrement the route-map used counter */
extern void route_map_counter_decrement(struct route_map *map);
+/* Route map hooks data structure. */
+struct route_map_match_set_hooks {
+ /* match interface */
+ int (*match_interface)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* no match interface */
+ int (*no_match_interface)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* match ip address */
+ int (*match_ip_address)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* no match ip address */
+ int (*no_match_ip_address)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* match ip address prefix list */
+ int (*match_ip_address_prefix_list)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* no match ip address prefix list */
+ int (*no_match_ip_address_prefix_list)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* match ip next hop */
+ int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* no match ip next hop */
+ int (*no_match_ip_next_hop)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* match ip next hop prefix list */
+ int (*match_ip_next_hop_prefix_list)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* no match ip next hop prefix list */
+ int (*no_match_ip_next_hop_prefix_list)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* match ip next-hop type */
+ int (*match_ip_next_hop_type)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* no match ip next-hop type */
+ int (*no_match_ip_next_hop_type)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* match ipv6 address */
+ int (*match_ipv6_address)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* no match ipv6 address */
+ int (*no_match_ipv6_address)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+
+ /* match ipv6 address prefix list */
+ int (*match_ipv6_address_prefix_list)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* no match ipv6 address prefix list */
+ int (*no_match_ipv6_address_prefix_list)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* match ipv6 next-hop type */
+ int (*match_ipv6_next_hop_type)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* no match ipv6 next-hop type */
+ int (*no_match_ipv6_next_hop_type)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* match metric */
+ int (*match_metric)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* no match metric */
+ int (*no_match_metric)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* match tag */
+ int (*match_tag)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* no match tag */
+ int (*no_match_tag)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
+ /* set ip nexthop */
+ int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg);
+
+ /* no set ip nexthop */
+ int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg);
+
+ /* set ipv6 nexthop local */
+ int (*set_ipv6_nexthop_local)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command, const char *arg);
+
+ /* no set ipv6 nexthop local */
+ int (*no_set_ipv6_nexthop_local)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command, const char *arg);
+
+ /* set metric */
+ int (*set_metric)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg);
+
+ /* no set metric */
+ int (*no_set_metric)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg);
+
+ /* set tag */
+ int (*set_tag)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg);
+
+ /* no set tag */
+ int (*no_set_tag)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg);
+};
+
+extern struct route_map_match_set_hooks rmap_match_set_hook;
+
+/* Making route map list. */
+struct route_map_list {
+ struct route_map *head;
+ struct route_map *tail;
+
+ void (*add_hook)(const char *);
+ void (*delete_hook)(const char *);
+ void (*event_hook)(const char *);
+};
+
+extern struct route_map_list route_map_master;
+
+extern struct route_map *route_map_get(const char *name);
+extern void route_map_delete(struct route_map *map);
+extern struct route_map_index *route_map_index_get(struct route_map *map,
+ enum route_map_type type,
+ int pref);
+extern void route_map_index_delete(struct route_map_index *index, int notify);
+
+/* routemap_northbound.c */
+typedef int (*routemap_match_hook_fun)(struct vty *vty,
+ struct route_map_index *rmi,
+ const char *command, const char *arg,
+ route_map_event_t event);
+
+typedef int (*routemap_set_hook_fun)(struct vty *vty,
+ struct route_map_index *rmi,
+ const char *command, const char *arg);
+
+struct routemap_hook_context {
+ struct route_map_index *rhc_rmi;
+ const char *rhc_rule;
+ route_map_event_t rhc_event;
+ routemap_set_hook_fun rhc_shook;
+ routemap_match_hook_fun rhc_mhook;
+ TAILQ_ENTRY(routemap_hook_context) rhc_entry;
+};
+
+int lib_route_map_entry_match_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_route_map_entry_set_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+
+struct routemap_hook_context *
+routemap_hook_context_insert(struct route_map_index *rmi);
+void routemap_hook_context_free(struct routemap_hook_context *rhc);
+
+extern const struct frr_yang_module_info frr_route_map_info;
+
+/* routemap_cli.c */
+extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void route_map_instance_show_end(struct vty *vty,
+ struct lyd_node *dnode);
+extern void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void route_map_description_show(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void route_map_cli_init(void);
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+/*
+ * Route map northbound CLI implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/command.h"
+#include "lib/northbound_cli.h"
+#include "lib/routemap.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "lib/routemap_cli_clippy.c"
+#endif /* VTYSH_EXTRACT_PL */
+
+#define ROUTE_MAP_CMD_STR \
+ "Create route-map or enter route-map command mode\n" \
+ "Route map tag\n"
+#define ROUTE_MAP_OP_CMD_STR \
+ "Route map denies set operations\n" \
+ "Route map permits set operations\n"
+#define ROUTE_MAP_SEQUENCE_CMD_STR \
+ "Sequence to insert to/delete from existing route-map entry\n"
+
+DEFPY_NOSH(
+ route_map, route_map_cmd,
+ "route-map WORD$name <deny|permit>$action (1-65535)$sequence",
+ ROUTE_MAP_CMD_STR
+ ROUTE_MAP_OP_CMD_STR
+ ROUTE_MAP_SEQUENCE_CMD_STR)
+{
+ struct route_map_index *rmi;
+ struct route_map *rm;
+ int action_type;
+ char xpath_action[XPATH_MAXLEN + 64];
+ char xpath_index[XPATH_MAXLEN + 32];
+ char xpath[XPATH_MAXLEN];
+ int rv;
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-route-map:lib/route-map[name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_index, sizeof(xpath_index), "%s/entry[sequence='%lu']",
+ xpath, sequence);
+ nb_cli_enqueue_change(vty, xpath_index, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_action, sizeof(xpath_action), "%s/action", xpath_index);
+ nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action);
+
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS) {
+ VTY_PUSH_XPATH(RMAP_NODE, xpath_index);
+
+ /* Add support for non-migrated route map users. */
+ rm = route_map_get(name);
+ action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY;
+ rmi = route_map_index_get(rm, action_type, sequence);
+ VTY_PUSH_CONTEXT(RMAP_NODE, rmi);
+ }
+
+ return rv;
+}
+
+DEFPY(
+ no_route_map_all, no_route_map_all_cmd,
+ "no route-map WORD$name",
+ NO_STR
+ ROUTE_MAP_CMD_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-route-map:lib/route-map[name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_route_map, no_route_map_cmd,
+ "no route-map WORD$name <deny|permit>$action (1-65535)$sequence",
+ NO_STR
+ ROUTE_MAP_CMD_STR
+ ROUTE_MAP_OP_CMD_STR
+ ROUTE_MAP_SEQUENCE_CMD_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']",
+ name, sequence);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const struct route_map_rule *rmr;
+ const struct route_map_index *rmi;
+ const char *name = yang_dnode_get_string(dnode, "../name");
+ const char *action = yang_dnode_get_string(dnode, "./action");
+ const char *sequence = yang_dnode_get_string(dnode, "./sequence");
+
+ vty_out(vty, "route-map %s %s %s\n", name, action, sequence);
+
+ rmi = nb_running_get_entry(dnode, NULL, false);
+ if (rmi == NULL) {
+ /*
+ * We can't have outdated rules if route map hasn't
+ * been created yet.
+ */
+ return;
+ }
+
+#define SKIP_RULE(name) if (strcmp((name), rmr->cmd->str) == 0) continue
+
+ /* Print route map `match` for old CLI users. */
+ for (rmr = rmi->match_list.head; rmr; rmr = rmr->next) {
+ /* Skip all matches implemented by northbound. */
+ SKIP_RULE("interface");
+ SKIP_RULE("ip address");
+ SKIP_RULE("ip address prefix-list");
+ SKIP_RULE("ip next-hop");
+ SKIP_RULE("ip next-hop prefix-list");
+ SKIP_RULE("ip next-hop type");
+ SKIP_RULE("ipv6 address");
+ SKIP_RULE("ipv6 address prefix-list");
+ SKIP_RULE("ipv6 next-hop type");
+ SKIP_RULE("metric");
+ SKIP_RULE("tag");
+
+ vty_out(vty, " match %s %s\n", rmr->cmd->str,
+ rmr->rule_str ? rmr->rule_str : "");
+ }
+
+ /* Print route map `set` for old CLI users. */
+ for (rmr = rmi->set_list.head; rmr; rmr = rmr->next) {
+ /* Skip all sets implemented by northbound. */
+ SKIP_RULE("metric");
+ SKIP_RULE("tag");
+
+ vty_out(vty, " set %s %s\n", rmr->cmd->str,
+ rmr->rule_str ? rmr->rule_str : "");
+ }
+
+#undef SKIP_RULE
+}
+
+void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode)
+{
+ vty_out(vty, "!\n");
+}
+
+DEFPY(
+ match_interface, match_interface_cmd,
+ "match interface IFNAME",
+ MATCH_STR
+ "Match first hop interface of route\n"
+ INTERFACE_STR)
+{
+ const char *xpath = "./match-condition[condition='interface']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/interface", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ifname);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_interface, no_match_interface_cmd,
+ "no match interface [IFNAME]",
+ NO_STR
+ MATCH_STR
+ "Match first hop interface of route\n"
+ INTERFACE_STR)
+{
+ const char *xpath = "./match-condition[condition='interface']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_address, match_ip_address_cmd,
+ "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-address-list']";
+ char xpath_value[XPATH_MAXLEN + 32];
+ int acln = acll ? acll : aclh;
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (name) {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+ } else /* if (acll || aclh) */ {
+ if ((acln >= 1 && acln <= 99)
+ || (acln >= 1300 && acln <= 1999)) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/access-list-num", xpath);
+ } else {
+ /*
+ * if ((acln >= 100 && acln <= 199)
+ * || (acln >= 2000 && acln <= 2699))
+ */
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/access-list-num-extended", xpath);
+ }
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+ acll_str ? acll_str : aclh_str);
+ }
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_address, no_match_ip_address_cmd,
+ "no match ip address [<(1-199)|(1300-2699)|WORD>]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-address-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_address_prefix_list,
+ match_ip_address_prefix_list_cmd,
+ "match ip address prefix-list WORD$name",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd,
+ "no match ip address prefix-list [WORD]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_next_hop, match_ip_next_hop_cmd,
+ "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
+ char xpath_value[XPATH_MAXLEN + 32];
+ int acln = acll ? acll : aclh;
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (name) {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+ } else /* if (acll || aclh) */ {
+ if ((acln >= 1 && acln <= 99)
+ || (acln >= 1300 && acln <= 1999)) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/access-list-num", xpath);
+ } else {
+ /*
+ * if ((acln >= 100 && acln <= 199)
+ * || (acln >= 2000 && acln <= 2699))
+ */
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/access-list-num-extended", xpath);
+ }
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+ acll_str ? acll_str : aclh_str);
+ }
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_next_hop, no_match_ip_next_hop_cmd,
+ "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_next_hop_prefix_list,
+ match_ip_next_hop_prefix_list_cmd,
+ "match ip next-hop prefix-list WORD$name",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath =
+ "./match-condition[condition='ipv4-next-hop-prefix-list']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_cmd,
+ "no match ip next-hop prefix-list [WORD]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath =
+ "./match-condition[condition='ipv4-next-hop-prefix-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_next_hop_type, match_ip_next_hop_type_cmd,
+ "match ip next-hop type <blackhole>$type",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-next-hop-type",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
+ "no match ip next-hop type [<blackhole>]",
+ NO_STR MATCH_STR IP_STR
+ "Match next-hop address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ipv6_address, match_ipv6_address_cmd,
+ "match ipv6 address WORD$name",
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-address-list']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ipv6_address, no_match_ipv6_address_cmd,
+ "no match ipv6 address [WORD]",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-address-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd,
+ "match ipv6 address prefix-list WORD$name",
+ MATCH_STR
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ipv6_address_prefix_list,
+ no_match_ipv6_address_prefix_list_cmd,
+ "no match ipv6 address prefix-list [WORD]",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
+ "match ipv6 next-hop type <blackhole>$type",
+ MATCH_STR IPV6_STR
+ "Match next-hop address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-next-hop-type",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
+ "no match ipv6 next-hop type [<blackhole>]",
+ NO_STR MATCH_STR IPV6_STR
+ "Match address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_metric, match_metric_cmd,
+ "match metric (0-4294967295)$metric",
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+{
+ const char *xpath = "./match-condition[condition='metric']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/metric", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, metric_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_metric, no_match_metric_cmd,
+ "no match metric [(0-4294967295)]",
+ NO_STR
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+{
+ const char *xpath = "./match-condition[condition='metric']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_tag, match_tag_cmd,
+ "match tag (1-4294967295)$tag",
+ MATCH_STR
+ "Match tag of route\n"
+ "Tag value\n")
+{
+ const char *xpath = "./match-condition[condition='tag']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_tag, no_match_tag_cmd,
+ "no match tag [(1-4294967295)]",
+ NO_STR
+ MATCH_STR
+ "Match tag of route\n"
+ "Tag value\n")
+{
+ const char *xpath = "./match-condition[condition='tag']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int condition = yang_dnode_get_enum(dnode, "./condition");
+ struct lyd_node *ln;
+ const char *acl;
+
+ switch (condition) {
+ case 0: /* interface */
+ vty_out(vty, " match interface %s\n",
+ yang_dnode_get_string(dnode, "./interface"));
+ break;
+ case 1: /* ipv4-address-list */
+ case 3: /* ipv4-next-hop-list */
+ acl = NULL;
+ if ((ln = yang_dnode_get(dnode, "./list-name")) != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+ else if ((ln = yang_dnode_get(dnode, "./access-list-num"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+ else if ((ln = yang_dnode_get(dnode,
+ "./access-list-num-extended"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+
+ assert(acl);
+
+ switch (condition) {
+ case 1:
+ vty_out(vty, " match ip address %s\n", acl);
+ break;
+ case 3:
+ vty_out(vty, " match ip next-hop %s\n", acl);
+ break;
+ }
+ break;
+ case 2: /* ipv4-prefix-list */
+ vty_out(vty, " match ip address prefix-list %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
+ break;
+ case 4: /* ipv4-next-hop-prefix-list */
+ vty_out(vty, " match ip next-hop prefix-list %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
+ break;
+ case 5: /* ipv4-next-hop-type */
+ vty_out(vty, " match ip next-hop type %s\n",
+ yang_dnode_get_string(dnode, "./ipv4-next-hop-type"));
+ break;
+ case 6: /* ipv6-address-list */
+ vty_out(vty, " match ipv6 address %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
+ break;
+ case 7: /* ipv6-prefix-list */
+ vty_out(vty, " match ipv6 address prefix-list %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
+ break;
+ case 8: /* ipv6-next-hop-type */
+ vty_out(vty, " match ipv6 next-hop type %s\n",
+ yang_dnode_get_string(dnode, "./ipv6-next-hop-type"));
+ break;
+ case 9: /* metric */
+ vty_out(vty, " match metric %s\n",
+ yang_dnode_get_string(dnode, "./metric"));
+ break;
+ case 10: /* tag */
+ vty_out(vty, " match tag %s\n",
+ yang_dnode_get_string(dnode, "./tag"));
+ break;
+ case 100:
+ /* NOTHING: custom field, should be handled by daemon. */
+ break;
+ }
+}
+
+DEFPY(
+ set_ip_nexthop, set_ip_nexthop_cmd,
+ "set ip next-hop A.B.C.D$addr",
+ SET_STR
+ IP_STR
+ "Next hop address\n"
+ "IP address of next hop\n")
+{
+ const char *xpath = "./set-action[action='ipv4-next-hop']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-address", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_set_ip_nexthop, no_set_ip_nexthop_cmd,
+ "no set ip next-hop [A.B.C.D]",
+ NO_STR
+ SET_STR
+ IP_STR
+ "Next hop address\n"
+ "IP address of next hop\n")
+{
+ const char *xpath = "./set-action[action='ipv4-next-hop']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd,
+ "set ipv6 next-hop local X:X::X:X$addr",
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 address of next hop\n")
+{
+ const char *xpath = "./set-action[action='ipv6-next-hop']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-address", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd,
+ "no set ipv6 next-hop local [X:X::X:X]",
+ NO_STR
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 address of next hop\n")
+{
+ const char *xpath = "./set-action[action='ipv6-next-hop']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ set_metric, set_metric_cmd,
+ "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>",
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n"
+ "Assign round trip time\n"
+ "Add round trip time\n"
+ "Subtract round trip time\n"
+ "Add metric\n"
+ "Subtract metric\n")
+{
+ const char *xpath = "./set-action[action='metric']";
+ char xpath_value[XPATH_MAXLEN];
+ char value[64];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (rtt) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/use-round-trip-time", xpath);
+ snprintf(value, sizeof(value), "true");
+ } else if (artt) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/add-round-trip-time", xpath);
+ snprintf(value, sizeof(value), "true");
+ } else if (srtt) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/subtract-round-trip-time", xpath);
+ snprintf(value, sizeof(value), "true");
+ } else if (ametric) {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/add-metric",
+ xpath);
+ snprintf(value, sizeof(value), "true");
+ } else if (smetric) {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/subtract-metric",
+ xpath);
+ snprintf(value, sizeof(value), "true");
+ } else {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/value", xpath);
+ snprintf(value, sizeof(value), "%lu", metric);
+ }
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_set_metric, no_set_metric_cmd,
+ "no set metric [(0-4294967295)]",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+{
+ const char *xpath = "./set-action[action='metric']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ set_tag, set_tag_cmd,
+ "set tag (1-4294967295)$tag",
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+{
+ const char *xpath = "./set-action[action='tag']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_set_tag, no_set_tag_cmd,
+ "no set tag [(1-4294967295)]",
+ NO_STR
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+{
+ const char *xpath = "./set-action[action='tag']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int action = yang_dnode_get_enum(dnode, "./action");
+
+ switch (action) {
+ case 0: /* ipv4-next-hop */
+ vty_out(vty, " set ip next-hop %s\n",
+ yang_dnode_get_string(dnode, "./ipv4-address"));
+ break;
+ case 1: /* ipv6-next-hop */
+ vty_out(vty, " set ipv6 next-hop local %s\n",
+ yang_dnode_get_string(dnode, "./ipv6-address"));
+ break;
+ case 2: /* metric */
+ if (yang_dnode_get(dnode, "./use-round-trip-time")) {
+ vty_out(vty, " set metric rtt\n");
+ } else if (yang_dnode_get(dnode, "./add-round-trip-time")) {
+ vty_out(vty, " set metric +rtt\n");
+ } else if (yang_dnode_get(dnode, "./subtract-round-trip-time")) {
+ vty_out(vty, " set metric -rtt\n");
+ } else if (yang_dnode_get(dnode, "./add-metric")) {
+ vty_out(vty, " set metric +metric\n");
+ } else if (yang_dnode_get(dnode, "./subtract-metric")) {
+ vty_out(vty, " set metric -metric\n");
+ } else {
+ vty_out(vty, " set metric %s\n",
+ yang_dnode_get_string(dnode, "./value"));
+ }
+ break;
+ case 3: /* tag */
+ vty_out(vty, " set tag %s\n",
+ yang_dnode_get_string(dnode, "./tag"));
+ break;
+ case 100:
+ /* NOTHING: custom field, should be handled by daemon. */
+ break;
+ }
+}
+
+DEFPY(
+ rmap_onmatch_next, rmap_onmatch_next_cmd,
+ "on-match next",
+ "Exit policy on matches\n"
+ "Next clause\n")
+{
+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "next");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_rmap_onmatch_next,
+ no_rmap_onmatch_next_cmd,
+ "no on-match next",
+ NO_STR
+ "Exit policy on matches\n"
+ "Next clause\n")
+{
+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ rmap_onmatch_goto, rmap_onmatch_goto_cmd,
+ "on-match goto (1-65535)$rm_num",
+ "Exit policy on matches\n"
+ "Goto Clause number\n"
+ "Number\n")
+{
+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "goto");
+ nb_cli_enqueue_change(vty, "./goto-value", NB_OP_MODIFY, rm_num_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd,
+ "no on-match goto",
+ NO_STR
+ "Exit policy on matches\n"
+ "Goto Clause number\n")
+{
+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+/* Cisco/GNU Zebra compatibility aliases */
+ALIAS(
+ rmap_onmatch_goto, rmap_continue_cmd,
+ "continue (1-65535)$rm_num",
+ "Continue on a different entry within the route-map\n"
+ "Route-map entry sequence number\n")
+
+ALIAS(
+ no_rmap_onmatch_goto, no_rmap_continue_cmd,
+ "no continue [(1-65535)]",
+ NO_STR
+ "Continue on a different entry within the route-map\n"
+ "Route-map entry sequence number\n")
+
+void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int exit_policy = yang_dnode_get_enum(dnode, NULL);
+
+ switch (exit_policy) {
+ case 0: /* permit-or-deny */
+ /* NOTHING: default option. */
+ break;
+ case 1: /* next */
+ vty_out(vty, " on-match next\n");
+ break;
+ case 2: /* goto */
+ vty_out(vty, " on-match goto %s\n",
+ yang_dnode_get_string(dnode, "../goto-value"));
+ break;
+ }
+}
+
+DEFPY(
+ rmap_call, rmap_call_cmd,
+ "call WORD$name",
+ "Jump to another Route-Map after match+set\n"
+ "Target route-map name\n")
+{
+ nb_cli_enqueue_change(vty, "./call", NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_rmap_call, no_rmap_call_cmd,
+ "no call",
+ NO_STR
+ "Jump to another Route-Map after match+set\n")
+{
+ nb_cli_enqueue_change(vty, "./call", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL));
+}
+
+DEFPY(
+ rmap_description, rmap_description_cmd,
+ "description LINE...",
+ "Route-map comment\n"
+ "Comment describing this route-map rule\n")
+{
+ char *desc;
+ int rv;
+
+ desc = argv_concat(argv, argc, 1);
+ nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc);
+ rv = nb_cli_apply_changes(vty, NULL);
+ XFREE(MTYPE_TMP, desc);
+
+ return rv;
+}
+
+DEFUN (no_rmap_description,
+ no_rmap_description_cmd,
+ "no description",
+ NO_STR
+ "Route-map comment\n")
+{
+ nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_description_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
+}
+
+static int route_map_config_write(struct vty *vty)
+{
+ struct lyd_node *dnode;
+ int written = 0;
+
+ dnode = yang_dnode_get(running_config->dnode,
+ "/frr-route-map:lib");
+ if (dnode) {
+ nb_cli_show_dnode_cmds(vty, dnode, false);
+ written = 1;
+ }
+
+ return written;
+}
+
+/* Route map node structure. */
+static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
+
+static void rmap_autocomplete(vector comps, struct cmd_token *token)
+{
+ struct route_map *map;
+
+ for (map = route_map_master.head; map; map = map->next)
+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
+}
+
+static const struct cmd_variable_handler rmap_var_handlers[] = {
+ {.varname = "route_map", .completions = rmap_autocomplete},
+ {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
+ {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
+ {.completions = NULL}
+};
+
+void route_map_cli_init(void)
+{
+ /* Auto complete handler. */
+ cmd_variable_handler_register(rmap_var_handlers);
+
+ /* CLI commands. */
+ install_node(&rmap_node, route_map_config_write);
+ install_default(RMAP_NODE);
+ install_element(CONFIG_NODE, &route_map_cmd);
+ install_element(CONFIG_NODE, &no_route_map_cmd);
+ install_element(CONFIG_NODE, &no_route_map_all_cmd);
+
+ /* Install the on-match stuff */
+ install_element(RMAP_NODE, &route_map_cmd);
+ install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
+ install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
+ install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
+ install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
+ install_element(RMAP_NODE, &rmap_continue_cmd);
+ install_element(RMAP_NODE, &no_rmap_continue_cmd);
+
+ /* Install the call stuff. */
+ install_element(RMAP_NODE, &rmap_call_cmd);
+ install_element(RMAP_NODE, &no_rmap_call_cmd);
+
+ /* Install description commands. */
+ install_element(RMAP_NODE, &rmap_description_cmd);
+ install_element(RMAP_NODE, &no_rmap_description_cmd);
+
+ /* Install 'match' commands. */
+ install_element(RMAP_NODE, &match_interface_cmd);
+ install_element(RMAP_NODE, &no_match_interface_cmd);
+
+ install_element(RMAP_NODE, &match_ip_address_cmd);
+ install_element(RMAP_NODE, &no_match_ip_address_cmd);
+
+ install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
+ install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+
+ install_element(RMAP_NODE, &match_ip_next_hop_cmd);
+ install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
+
+ install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+ install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+
+ install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
+ install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
+
+ install_element(RMAP_NODE, &match_ipv6_address_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
+
+ install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
+
+ install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
+
+ install_element(RMAP_NODE, &match_metric_cmd);
+ install_element(RMAP_NODE, &no_match_metric_cmd);
+
+ install_element(RMAP_NODE, &match_tag_cmd);
+ install_element(RMAP_NODE, &no_match_tag_cmd);
+
+ /* Install 'set' commands. */
+ install_element(RMAP_NODE, &set_ip_nexthop_cmd);
+ install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
+
+ install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
+ install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
+
+ install_element(RMAP_NODE, &set_metric_cmd);
+ install_element(RMAP_NODE, &no_set_metric_cmd);
+
+ install_element(RMAP_NODE, &set_tag_cmd);
+ install_element(RMAP_NODE, &no_set_tag_cmd);
+}
--- /dev/null
+/*
+ * Route map northbound implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/command.h"
+#include "lib/log.h"
+#include "lib/northbound.h"
+#include "lib/routemap.h"
+
+/*
+ * Auxiliary functions to avoid code duplication:
+ *
+ * lib_route_map_entry_set_destroy: unset `set` commands.
+ * lib_route_map_entry_match_destroy: unset `match` commands.
+ */
+int lib_route_map_entry_match_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct routemap_hook_context *rhc;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ if (rhc->rhc_mhook == NULL)
+ return NB_OK;
+
+ rv = rhc->rhc_mhook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL,
+ rhc->rhc_event);
+ if (rv != CMD_SUCCESS)
+ return NB_ERR_INCONSISTENCY;
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct routemap_hook_context *rhc;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ if (rhc->rhc_shook == NULL)
+ return NB_OK;
+
+ rv = rhc->rhc_shook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL);
+ if (rv != CMD_SUCCESS)
+ return NB_ERR_INCONSISTENCY;
+
+ return NB_OK;
+}
+
+/*
+ * Auxiliary hook context list manipulation functions.
+ */
+struct routemap_hook_context *
+routemap_hook_context_insert(struct route_map_index *rmi)
+{
+ struct routemap_hook_context *rhc;
+
+ rhc = XCALLOC(MTYPE_TMP, sizeof(*rhc));
+ rhc->rhc_rmi = rmi;
+ TAILQ_INSERT_TAIL(&rmi->rhclist, rhc, rhc_entry);
+
+ return rhc;
+}
+
+void
+routemap_hook_context_free(struct routemap_hook_context *rhc)
+{
+ struct route_map_index *rmi = rhc->rhc_rmi;
+
+ TAILQ_REMOVE(&rmi->rhclist, rhc, rhc_entry);
+ XFREE(MTYPE_TMP, rhc);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map
+ */
+static int lib_route_map_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct route_map *rm;
+ const char *rm_name;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rm_name = yang_dnode_get_string(dnode, "./name");
+ rm = route_map_get(rm_name);
+ nb_running_set_entry(dnode, rm);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct route_map *rm;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rm = nb_running_unset_entry(dnode);
+ route_map_delete(rm);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry
+ */
+static int lib_route_map_entry_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct route_map_index *rmi;
+ struct route_map *rm;
+ uint16_t sequence;
+ int action;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ sequence = yang_dnode_get_uint16(dnode, "./sequence");
+ action = yang_dnode_get_enum(dnode, "./action") == 0
+ ? RMAP_PERMIT
+ : RMAP_DENY;
+ rm = nb_running_get_entry(dnode, NULL, true);
+ rmi = route_map_index_get(rm, action, sequence);
+ nb_running_set_entry(dnode, rmi);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct route_map_index *rmi;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_unset_entry(dnode);
+ route_map_index_delete(rmi, 1);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/description
+ */
+static int lib_route_map_entry_description_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct route_map_index *rmi;
+ const char *description;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* NOTHING */
+ break;
+ case NB_EV_PREPARE:
+ description = yang_dnode_get_string(dnode, NULL);
+ resource->ptr = XSTRDUP(MTYPE_TMP, description);
+ if (resource->ptr == NULL)
+ return NB_ERR_RESOURCE;
+ break;
+ case NB_EV_ABORT:
+ XFREE(MTYPE_TMP, resource->ptr);
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_get_entry(dnode, NULL, true);
+ if (rmi->description != NULL)
+ XFREE(MTYPE_TMP, rmi->description);
+ rmi->description = resource->ptr;
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_description_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct route_map_index *rmi;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_get_entry(dnode, NULL, true);
+ if (rmi->description != NULL)
+ XFREE(MTYPE_TMP, rmi->description);
+ rmi->description = NULL;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/action
+ */
+static int lib_route_map_entry_action_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct route_map_index *rmi;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_get_entry(dnode, NULL, true);
+ rmi->type = yang_dnode_get_enum(dnode, NULL);
+ /* TODO: notify? */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/call
+ */
+static int lib_route_map_entry_call_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct route_map_index *rmi;
+ const char *rm_name, *rmn_name;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ rm_name = yang_dnode_get_string(dnode, "../../name");
+ rmn_name = yang_dnode_get_string(dnode, NULL);
+ /* Don't allow to jump to the same route map instance. */
+ if (strcmp(rm_name, rmn_name) == 0)
+ return NB_ERR_VALIDATION;
+
+ /* TODO: detect circular route map sequences. */
+ break;
+ case NB_EV_PREPARE:
+ rmn_name = yang_dnode_get_string(dnode, NULL);
+ resource->ptr = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmn_name);
+ break;
+ case NB_EV_ABORT:
+ XFREE(MTYPE_ROUTE_MAP_NAME, resource->ptr);
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_get_entry(dnode, NULL, true);
+ if (rmi->nextrm) {
+ route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
+ rmi->nextrm, rmi->map->name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm);
+ }
+ rmi->nextrm = resource->ptr;
+ route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, rmi->nextrm,
+ rmi->map->name);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_call_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct route_map_index *rmi;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_get_entry(dnode, NULL, true);
+ route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, rmi->nextrm,
+ rmi->map->name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm);
+ rmi->nextrm = NULL;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/exit-policy
+ */
+static int lib_route_map_entry_exit_policy_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct route_map_index *rmi;
+ int rm_action;
+ int policy;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ policy = yang_dnode_get_enum(dnode, NULL);
+ switch (policy) {
+ case 0: /* permit-or-deny */
+ break;
+ case 1: /* next */
+ /* FALLTHROUGH */
+ case 2: /* goto */
+ rm_action = yang_dnode_get_enum(dnode, "../action");
+ if (rm_action == 1 /* deny */) {
+ /*
+ * On deny it is not possible to 'goto'
+ * anywhere.
+ */
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_get_entry(dnode, NULL, true);
+ policy = yang_dnode_get_enum(dnode, NULL);
+
+ switch (policy) {
+ case 0: /* permit-or-deny */
+ rmi->exitpolicy = RMAP_EXIT;
+ break;
+ case 1: /* next */
+ rmi->exitpolicy = RMAP_NEXT;
+ break;
+ case 2: /* goto */
+ rmi->exitpolicy = RMAP_GOTO;
+ break;
+ }
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/goto-value
+ */
+static int lib_route_map_entry_goto_value_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct route_map_index *rmi;
+ uint16_t rmi_index;
+ uint16_t rmi_next;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ rmi_index = yang_dnode_get_uint16(dnode, "../sequence");
+ rmi_next = yang_dnode_get_uint16(dnode, NULL);
+ if (rmi_next <= rmi_index) {
+ /* Can't jump backwards on a route map. */
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_get_entry(dnode, NULL, true);
+ rmi->nextpref = yang_dnode_get_uint16(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_goto_value_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct route_map_index *rmi;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_get_entry(dnode, NULL, true);
+ rmi->nextpref = 0;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition
+ */
+static int
+lib_route_map_entry_match_condition_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ struct route_map_index *rmi;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rmi = nb_running_get_entry(dnode, NULL, true);
+ rhc = routemap_hook_context_insert(rmi);
+ nb_running_set_entry(dnode, rhc);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+lib_route_map_entry_match_condition_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct routemap_hook_context *rhc;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rv = lib_route_map_entry_match_destroy(event, dnode);
+ rhc = nb_running_unset_entry(dnode);
+ routemap_hook_context_free(rhc);
+
+ return rv;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/interface
+ */
+static int lib_route_map_entry_match_condition_interface_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *ifname;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.match_interface == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_interface;
+ rhc->rhc_rule = "interface";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = rmap_match_set_hook.match_interface(NULL, rhc->rhc_rmi,
+ "interface", ifname,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_interface_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/access-list-num
+ */
+static int lib_route_map_entry_match_condition_access_list_num_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *acl;
+ int condition, rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook function. */
+ rv = CMD_SUCCESS;
+ acl = yang_dnode_get_string(dnode, NULL);
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ condition = yang_dnode_get_enum(dnode, "../condition");
+ switch (condition) {
+ case 1: /* ipv4-address-list */
+ if (rmap_match_set_hook.match_ip_address == NULL)
+ break;
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address;
+ rhc->rhc_rule = "ip address";
+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+ rv = rmap_match_set_hook.match_ip_address(
+ NULL, rhc->rhc_rmi, "ip address", acl,
+ RMAP_EVENT_FILTER_ADDED);
+ break;
+ case 3: /* ipv4-next-hop-list */
+ if (rmap_match_set_hook.match_ip_next_hop == NULL)
+ break;
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop;
+ rhc->rhc_rule = "ip next-hop";
+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+ rv = rmap_match_set_hook.match_ip_next_hop(
+ NULL, rhc->rhc_rmi, "ip next-hop", acl,
+ RMAP_EVENT_FILTER_ADDED);
+ break;
+ }
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_access_list_num_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended
+ */
+static int lib_route_map_entry_match_condition_access_list_num_extended_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return lib_route_map_entry_match_condition_access_list_num_modify(
+ event, dnode, resource);
+}
+
+static int lib_route_map_entry_match_condition_access_list_num_extended_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_condition_access_list_num_destroy(
+ event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/list-name
+ */
+static int lib_route_map_entry_match_condition_list_name_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *acl;
+ int condition;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook installation, otherwise we can just stop. */
+ acl = yang_dnode_get_string(dnode, NULL);
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ condition = yang_dnode_get_enum(dnode, "../condition");
+ switch (condition) {
+ case 1: /* ipv4-address-list */
+ if (rmap_match_set_hook.match_ip_address == NULL)
+ return NB_OK;
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address;
+ rhc->rhc_rule = "ip address";
+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+ rv = rmap_match_set_hook.match_ip_address(
+ NULL, rhc->rhc_rmi, "ip address", acl,
+ RMAP_EVENT_FILTER_ADDED);
+ break;
+ case 2: /* ipv4-prefix-list */
+ if (rmap_match_set_hook.match_ip_address_prefix_list == NULL)
+ return NB_OK;
+ rhc->rhc_mhook =
+ rmap_match_set_hook.no_match_ip_address_prefix_list;
+ rhc->rhc_rule = "ip address prefix-list";
+ rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
+ rv = rmap_match_set_hook.match_ip_address_prefix_list(
+ NULL, rhc->rhc_rmi, "ip address prefix-list", acl,
+ RMAP_EVENT_PLIST_ADDED);
+ break;
+ case 3: /* ipv4-next-hop-list */
+ if (rmap_match_set_hook.match_ip_next_hop == NULL)
+ return NB_OK;
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop;
+ rhc->rhc_rule = "ip next-hop";
+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+ rv = rmap_match_set_hook.match_ip_next_hop(
+ NULL, rhc->rhc_rmi, "ip next-hop", acl,
+ RMAP_EVENT_FILTER_ADDED);
+ break;
+ case 4: /* ipv4-next-hop-prefix-list */
+ if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL)
+ return NB_OK;
+ rhc->rhc_mhook =
+ rmap_match_set_hook.no_match_ip_next_hop_prefix_list;
+ rhc->rhc_rule = "ip next-hop prefix-list";
+ rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
+ rv = rmap_match_set_hook.match_ip_next_hop_prefix_list(
+ NULL, rhc->rhc_rmi, "ip next-hop prefix-list", acl,
+ RMAP_EVENT_PLIST_ADDED);
+ break;
+ case 6: /* ipv6-address-list */
+ if (rmap_match_set_hook.match_ipv6_address == NULL)
+ return NB_OK;
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_address;
+ rhc->rhc_rule = "ipv6 address";
+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+ rv = rmap_match_set_hook.match_ipv6_address(
+ NULL, rhc->rhc_rmi, "ipv6 address", acl,
+ RMAP_EVENT_FILTER_ADDED);
+ break;
+ case 7: /* ipv6-prefix-list */
+ if (rmap_match_set_hook.match_ipv6_address_prefix_list == NULL)
+ return NB_OK;
+ rhc->rhc_mhook =
+ rmap_match_set_hook.no_match_ipv6_address_prefix_list;
+ rhc->rhc_rule = "ipv6 address prefix-list";
+ rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
+ rv = rmap_match_set_hook.match_ipv6_address_prefix_list(
+ NULL, rhc->rhc_rmi, "ipv6 address prefix-list", acl,
+ RMAP_EVENT_PLIST_ADDED);
+ break;
+ default:
+ rv = CMD_ERR_NO_MATCH;
+ break;
+ }
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_list_name_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type
+ */
+static int lib_route_map_entry_match_condition_ipv4_next_hop_type_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.match_ip_next_hop_type == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop_type;
+ rhc->rhc_rule = "ip next-hop type";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = rmap_match_set_hook.match_ip_next_hop_type(
+ NULL, rhc->rhc_rmi, "ip next-hop type", type,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type
+ */
+static int lib_route_map_entry_match_condition_ipv6_next_hop_type_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.match_ipv6_next_hop_type == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop_type;
+ rhc->rhc_rule = "ipv6 next-hop type";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = rmap_match_set_hook.match_ipv6_next_hop_type(
+ NULL, rhc->rhc_rmi, "ipv6 next-hop type", type,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/metric
+ */
+static int
+lib_route_map_entry_match_condition_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.match_metric == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_metric;
+ rhc->rhc_rule = "metric";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = rmap_match_set_hook.match_metric(NULL, rhc->rhc_rmi, "metric",
+ type, RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int
+lib_route_map_entry_match_condition_metric_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/tag
+ */
+static int
+lib_route_map_entry_match_condition_tag_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *tag;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.match_tag == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ tag = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_tag;
+ rhc->rhc_rule = "tag";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = rmap_match_set_hook.match_tag(NULL, rhc->rhc_rmi, "tag", tag,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int
+lib_route_map_entry_match_condition_tag_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action
+ */
+static int lib_route_map_entry_set_action_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return lib_route_map_entry_match_condition_create(event, dnode,
+ resource);
+}
+
+static int lib_route_map_entry_set_action_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct routemap_hook_context *rhc;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rv = lib_route_map_entry_set_destroy(event, dnode);
+ rhc = nb_running_unset_entry(dnode);
+ routemap_hook_context_free(rhc);
+
+ return rv;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv4-address
+ */
+static int
+lib_route_map_entry_set_action_ipv4_address_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *address;
+ struct in_addr ia;
+ int rv;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /*
+ * NOTE: validate if 'action' is 'ipv4-next-hop',
+ * currently it is not necessary because this is the
+ * only implemented action.
+ */
+ yang_dnode_get_ipv4(&ia, dnode, NULL);
+ if (ia.s_addr == INADDR_ANY || IPV4_CLASS_DE(ntohl(ia.s_addr)))
+ return NB_ERR_VALIDATION;
+ /* FALLTHROUGH */
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ return NB_OK;
+ case NB_EV_APPLY:
+ break;
+ }
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.set_ip_nexthop == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ address = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = rmap_match_set_hook.no_set_ip_nexthop;
+ rhc->rhc_rule = "ip next-hop";
+
+ rv = rmap_match_set_hook.set_ip_nexthop(NULL, rhc->rhc_rmi,
+ "ip next-hop", address);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_set_action_ipv4_address_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv6-address
+ */
+static int
+lib_route_map_entry_set_action_ipv6_address_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *address;
+ struct in6_addr i6a;
+ int rv;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /*
+ * NOTE: validate if 'action' is 'ipv6-next-hop',
+ * currently it is not necessary because this is the
+ * only implemented action. Other actions might have
+ * different validations.
+ */
+ yang_dnode_get_ipv6(&i6a, dnode, NULL);
+ if (!IN6_IS_ADDR_LINKLOCAL(&i6a))
+ return NB_ERR_VALIDATION;
+ /* FALLTHROUGH */
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ return NB_OK;
+ case NB_EV_APPLY:
+ break;
+ }
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.set_ipv6_nexthop_local == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ address = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = rmap_match_set_hook.no_set_ipv6_nexthop_local;
+ rhc->rhc_rule = "ipv6 next-hop local";
+
+ rv = rmap_match_set_hook.set_ipv6_nexthop_local(
+ NULL, rhc->rhc_rmi, "ipv6 next-hop local", address);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_set_action_ipv6_address_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/value
+ */
+static int set_action_modify(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource, const char *value)
+{
+ struct routemap_hook_context *rhc;
+ int rv;
+
+ /*
+ * NOTE: validate if 'action' is 'metric', currently it is not
+ * necessary because this is the only implemented action. Other
+ * actions might have different validations.
+ */
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.set_metric == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = rmap_match_set_hook.no_set_metric;
+ rhc->rhc_rule = "metric";
+
+ rv = rmap_match_set_hook.set_metric(NULL, rhc->rhc_rmi, "metric",
+ value);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int
+lib_route_map_entry_set_action_value_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ const char *metric = yang_dnode_get_string(dnode, NULL);
+
+ return set_action_modify(event, dnode, resource, metric);
+}
+
+static int
+lib_route_map_entry_set_action_value_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/add-metric
+ */
+static int
+lib_route_map_entry_set_action_add_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return set_action_modify(event, dnode, resource, "+metric");
+}
+
+static int
+lib_route_map_entry_set_action_add_metric_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-metric
+ */
+static int lib_route_map_entry_set_action_subtract_metric_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return set_action_modify(event, dnode, resource, "-metric");
+}
+
+static int lib_route_map_entry_set_action_subtract_metric_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/use-round-trip-time
+ */
+static int lib_route_map_entry_set_action_use_round_trip_time_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return set_action_modify(event, dnode, resource, "rtt");
+}
+
+static int lib_route_map_entry_set_action_use_round_trip_time_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/add-round-trip-time
+ */
+static int lib_route_map_entry_set_action_add_round_trip_time_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return set_action_modify(event, dnode, resource, "+rtt");
+}
+
+static int lib_route_map_entry_set_action_add_round_trip_time_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time
+ */
+static int lib_route_map_entry_set_action_subtract_round_trip_time_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return set_action_modify(event, dnode, resource, "-rtt");
+}
+
+static int lib_route_map_entry_set_action_subtract_round_trip_time_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/tag
+ */
+static int
+lib_route_map_entry_set_action_tag_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *tag;
+ int rv;
+
+ /*
+ * NOTE: validate if 'action' is 'tag', currently it is not
+ * necessary because this is the only implemented action. Other
+ * actions might have different validations.
+ */
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.set_tag == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ tag = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = rmap_match_set_hook.no_set_tag;
+ rhc->rhc_rule = "tag";
+
+ rv = rmap_match_set_hook.set_tag(NULL, rhc->rhc_rmi, "tag", tag);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int
+lib_route_map_entry_set_action_tag_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/* clang-format off */
+#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__)
+/*
+ * gcc versions before 5.x miscalculate the size for structs with variable
+ * length arrays (they just count it as size 0)
+ */
+struct frr_yang_module_info_sizen {
+ /* YANG module name. */
+ const char *name;
+
+ /* Northbound callbacks. */
+ const struct {
+ /* Data path of this YANG node. */
+ const char *xpath;
+
+ /* Callbacks implemented for this node. */
+ struct nb_callbacks cbs;
+
+ /* Priority - lower priorities are processed first. */
+ uint32_t priority;
+ } nodes[28];
+};
+
+const struct frr_yang_module_info_sizen frr_route_map_info_sizen asm("frr_route_map_info") = {
+#else
+const struct frr_yang_module_info frr_route_map_info = {
+#endif
+ .name = "frr-route-map",
+ .nodes = {
+ {
+ .xpath = "/frr-route-map:lib/route-map",
+ .cbs = {
+ .create = lib_route_map_create,
+ .destroy = lib_route_map_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry",
+ .cbs = {
+ .create = lib_route_map_entry_create,
+ .destroy = lib_route_map_entry_destroy,
+ .cli_show = route_map_instance_show,
+ .cli_show_end = route_map_instance_show_end,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/description",
+ .cbs = {
+ .modify = lib_route_map_entry_description_modify,
+ .destroy = lib_route_map_entry_description_destroy,
+ .cli_show = route_map_description_show,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/action",
+ .cbs = {
+ .modify = lib_route_map_entry_action_modify,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/call",
+ .cbs = {
+ .modify = lib_route_map_entry_call_modify,
+ .destroy = lib_route_map_entry_call_destroy,
+ .cli_show = route_map_call_show,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/exit-policy",
+ .cbs = {
+ .modify = lib_route_map_entry_exit_policy_modify,
+ .cli_show = route_map_exit_policy_show,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/goto-value",
+ .cbs = {
+ .modify = lib_route_map_entry_goto_value_modify,
+ .destroy = lib_route_map_entry_goto_value_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition",
+ .cbs = {
+ .create = lib_route_map_entry_match_condition_create,
+ .destroy = lib_route_map_entry_match_condition_destroy,
+ .cli_show = route_map_condition_show,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/interface",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_interface_modify,
+ .destroy = lib_route_map_entry_match_condition_interface_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_access_list_num_modify,
+ .destroy = lib_route_map_entry_match_condition_access_list_num_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_access_list_num_extended_modify,
+ .destroy = lib_route_map_entry_match_condition_access_list_num_extended_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/list-name",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_list_name_modify,
+ .destroy = lib_route_map_entry_match_condition_list_name_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_ipv4_next_hop_type_modify,
+ .destroy = lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_ipv6_next_hop_type_modify,
+ .destroy = lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/metric",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_metric_modify,
+ .destroy = lib_route_map_entry_match_condition_metric_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/tag",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_tag_modify,
+ .destroy = lib_route_map_entry_match_condition_tag_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action",
+ .cbs = {
+ .create = lib_route_map_entry_set_action_create,
+ .destroy = lib_route_map_entry_set_action_destroy,
+ .cli_show = route_map_action_show,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv4-address",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_ipv4_address_modify,
+ .destroy = lib_route_map_entry_set_action_ipv4_address_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv6-address",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_ipv6_address_modify,
+ .destroy = lib_route_map_entry_set_action_ipv6_address_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/value",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_value_modify,
+ .destroy = lib_route_map_entry_set_action_value_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-metric",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_add_metric_modify,
+ .destroy = lib_route_map_entry_set_action_add_metric_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-metric",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_subtract_metric_modify,
+ .destroy = lib_route_map_entry_set_action_subtract_metric_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/use-round-trip-time",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_use_round_trip_time_modify,
+ .destroy = lib_route_map_entry_set_action_use_round_trip_time_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-round-trip-time",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_add_round_trip_time_modify,
+ .destroy = lib_route_map_entry_set_action_add_round_trip_time_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_subtract_round_trip_time_modify,
+ .destroy = lib_route_map_entry_set_action_subtract_round_trip_time_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/tag",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_tag_modify,
+ .destroy = lib_route_map_entry_set_action_tag_destroy,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
lib/mlag.c \
lib/module.c \
lib/mpls.c \
+ lib/srv6.c \
lib/network.c \
lib/nexthop.c \
lib/netns_linux.c \
lib/qobj.c \
lib/ringbuf.c \
lib/routemap.c \
+ lib/routemap_cli.c \
+ lib/routemap_northbound.c \
lib/sbuf.c \
lib/seqlock.c \
lib/sha256.c \
# end
nodist_lib_libfrr_la_SOURCES = \
+ yang/frr-filter.yang.c \
yang/frr-interface.yang.c \
+ yang/frr-route-map.yang.c \
yang/frr-route-types.yang.c \
yang/ietf/ietf-routing-types.yang.c \
yang/frr-module-translator.yang.c \
$(top_srcdir)/lib/nexthop_group.c \
$(top_srcdir)/lib/plist.c \
$(top_srcdir)/lib/routemap.c \
+ $(top_srcdir)/lib/routemap_cli.c \
$(top_srcdir)/lib/vrf.c \
$(top_srcdir)/lib/vty.c \
# end
lib/nexthop_group.lo: lib/nexthop_group_clippy.c
lib/northbound_cli_clippy.c: $(CLIPPY_DEPS)
lib/northbound_cli.lo: lib/northbound_cli_clippy.c
+lib/routemap_cli_clippy.c: $(CLIPPY_DEPS)
+lib/routemap_cli.lo: lib/routemap_cli_clippy.c
lib/vty_clippy.c: $(CLIPPY_DEPS)
lib/vty.lo: lib/vty_clippy.c
lib/log_vty_clippy.c: $(CLIPPY_DEPS)
lib/module.h \
lib/monotime.h \
lib/mpls.h \
+ lib/srv6.h \
lib/network.h \
lib/nexthop.h \
lib/nexthop_group.h \
vty_timeout_val = VTY_TIMEOUT_DEFAULT;
- if (vty_accesslist_name) {
- XFREE(MTYPE_VTY, vty_accesslist_name);
- vty_accesslist_name = NULL;
- }
-
- if (vty_ipv6_accesslist_name) {
- XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
- vty_ipv6_accesslist_name = NULL;
- }
+ XFREE(MTYPE_VTY, vty_accesslist_name);
+ XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
}
static void vty_save_cwd(void)
stream_putw_at(s, 0, stream_get_endp(s));
zclient_send_message(client);
}
+
+/*
+ * 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;
+ 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;
+ case ZEBRA_CLIENT_GR_DISABLE:
+ STREAM_GETL(s, api->vrf_id);
+ break;
+ }
+stream_failure:
+ return 0;
+}
#define ZEBRA_FEC_REGISTER_LABEL 0x1
#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x2
+/* 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;
ZEBRA_MLAG_CLIENT_UNREGISTER,
ZEBRA_MLAG_FORWARD_MSG,
ZEBRA_ERROR,
+ ZEBRA_CLIENT_CAPABILITIES
} 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 */
};
enum mlag_role role;
};
+/* Graceful Restart Capabilities message */
+struct zapi_cap {
+ 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. */
struct zclient {
/* The thread master we schedule ourselves on */
/* 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)
{
&nifp->linkidx, &saddr);
debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name,
nifp->grekey, nifp->linkidx, saddr.s_addr);
- if (saddr.s_addr)
+ if (saddr.s_addr != INADDR_ANY)
sockunion_set(&nbma, AF_INET, (uint8_t *)&saddr.s_addr,
sizeof(saddr.s_addr));
else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL)
if (!ri->ifp && !ri->nhrp_ifp
&& sockunion_family(&ri->via) == AF_UNSPEC) {
XFREE(MTYPE_NHRP_ROUTE, rn->info);
- rn->info = NULL;
route_unlock_node(rn);
}
route_unlock_node(rn);
rn = route_node_lookup(shortcut_rib[afi], s->p);
if (rn) {
XFREE(MTYPE_NHRP_SHORTCUT, rn->info);
- rn->info = NULL;
route_unlock_node(rn);
route_unlock_node(rn);
}
static const struct frr_yang_module_info *const ospf6d_yang_modules[] = {
&frr_interface_info,
+ &frr_route_map_info,
};
FRR_DAEMON_INFO(ospf6d, OSPF6, .vty_port = OSPF6_VTY_PORT,
void ospf6_message_terminate(void)
{
- if (recvbuf) {
- XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
- recvbuf = NULL;
- }
-
- if (sendbuf) {
- XFREE(MTYPE_OSPF6_MESSAGE, sendbuf);
- sendbuf = NULL;
- }
+ XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
+ XFREE(MTYPE_OSPF6_MESSAGE, sendbuf);
iobuflen = 0;
}
tmp = SET_OPAQUE_LSID(opaque_type, opaque_id);
lsah->id.s_addr = htonl(tmp);
- lsah->adv_router.s_addr = 0;
+ lsah->adv_router.s_addr = INADDR_ANY;
lsah->ls_seqnum = 0;
lsah->checksum = 0;
lsah->length = htons(sizeof(struct lsa_header) + opaquelen);
ospf_schedule_abr_task(ospf);
UNSET_FLAG(range->flags, OSPF_AREA_RANGE_SUBSTITUTE);
- range->subst_addr.s_addr = 0;
+ range->subst_addr.s_addr = INADDR_ANY;
range->subst_masklen = 0;
return 1;
ospf->vrf_id, inet_ntoa(p.prefix),
p.prefixlen, inetbuf);
XFREE(MTYPE_OSPF_EXTERNAL_INFO, rn->info);
- rn->info = NULL;
}
/* Create new External info instance. */
external-LSA. This indicates the IP address to which
packets for the destination should be forwarded. */
- if (al->e[0].fwd_addr.s_addr == 0) {
+ if (al->e[0].fwd_addr.s_addr == INADDR_ANY) {
/* If the forwarding address is set to 0.0.0.0, packets should
be sent to the ASBR itself. Among the multiple routing table
entries for the ASBR, select the preferred entry as follows.
ospf_route_add(ospf->new_external_route, &p, new, asbr_route);
- if (al->e[0].fwd_addr.s_addr)
+ if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
ospf_ase_complete_direct_routes(new, al->e[0].fwd_addr);
return 0;
} else {
zlog_debug(
"Route[External]: New route is better");
ospf_route_subst(rn, new, asbr_route);
- if (al->e[0].fwd_addr.s_addr)
+ if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
ospf_ase_complete_direct_routes(
new, al->e[0].fwd_addr);
or = new;
if (IS_DEBUG_OSPF(lsa, LSA))
zlog_debug("Route[External]: Routes are equal");
ospf_route_copy_nexthops(or, asbr_route->paths);
- if (al->e[0].fwd_addr.s_addr)
+ if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
ospf_ase_complete_direct_routes(
or, al->e[0].fwd_addr);
}
ospf_del_if_params((struct ospf_if_params *)IF_DEF_PARAMS(ifp));
XFREE(MTYPE_OSPF_IF_INFO, ifp->info);
- ifp->info = NULL;
return rc;
}
p = prefix_ipv4_new();
p->family = AF_INET;
- p->prefix.s_addr = 0;
+ p->prefix.s_addr = INADDR_ANY;
p->prefixlen = 0;
co->address = (struct prefix *)p;
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("ospf_vl_new(): set if->name to %s", vi->name);
- area_id.s_addr = 0;
+ area_id.s_addr = INADDR_ANY;
area = ospf_area_get(ospf, area_id);
voi->area = area;
{
struct interface *ifp = vl_data->vl_oi->ifp;
- vl_data->vl_oi->address->u.prefix4.s_addr = 0;
+ vl_data->vl_oi->address->u.prefix4.s_addr = INADDR_ANY;
vl_data->vl_oi->address->prefixlen = 0;
ospf_if_free(vl_data->vl_oi);
if_delete(&ifp);
if ((oi = vl_data->vl_oi) == NULL)
return;
- oi->address->u.prefix4.s_addr = 0;
+ oi->address->u.prefix4.s_addr = INADDR_ANY;
oi->address->prefixlen = 0;
UNSET_FLAG(oi->ifp->flags, IFF_UP);
for (rn = route_top(nbrs); rn; rn = route_next(rn))
if ((nbr = rn->info) != NULL)
/* Ignore 0.0.0.0 node*/
- if (nbr->router_id.s_addr != 0)
+ if (nbr->router_id.s_addr != INADDR_ANY)
/* Is neighbor eligible? */
if (nbr->priority > 0)
/* Is neighbor upper 2-Way? */
for (rn = route_top(nbrs); rn; rn = route_next(rn))
if ((nbr = rn->info) != NULL)
/* Ignore 0.0.0.0 node*/
- if (nbr->router_id.s_addr != 0)
+ if (nbr->router_id.s_addr != INADDR_ANY)
/* Is neighbor upper 2-Way? */
if (nbr->state >= NSM_TwoWay)
/* Ignore myself. */
}
/* Sanity check. */
- if (new->data->adv_router.s_addr == 0) {
+ if (new->data->adv_router.s_addr == INADDR_ANY) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("LSA[Type1]: AdvRouter is 0, discard");
ospf_lsa_discard(new);
{
struct in_addr fwd;
- fwd.s_addr = 0;
+ fwd.s_addr = INADDR_ANY;
if (if_is_operative(oi->ifp))
return oi->address->u.prefix4;
struct prefix_ipv4 q;
q.family = AF_INET;
- q.prefix.s_addr = 0;
+ q.prefix.s_addr = INADDR_ANY;
q.prefixlen = 0;
return prefix_same((struct prefix *)p, (struct prefix *)&q);
*/
- if (ospf->router_id.s_addr == 0) {
+ if (ospf->router_id.s_addr == INADDR_ANY) {
if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero",
- &ei->p.prefix);
+ zlog_debug(
+ "LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero",
+ &ei->p.prefix);
return NULL;
}
p.family = AF_INET;
p.prefixlen = 0;
- p.prefix.s_addr = 0;
+ p.prefix.s_addr = INADDR_ANY;
ei = ospf_default_external_info(ospf);
lsa = ospf_external_info_find_lsa(ospf, &p);
#include "zclient.h"
#include "vrf.h"
#include "libfrr.h"
+#include "routemap.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h"
static const struct frr_yang_module_info *const ospfd_yang_modules[] = {
&frr_interface_info,
+ &frr_route_map_info,
};
FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT,
int main(int argc, char **argv)
{
unsigned short instance = 0;
+ bool created = false;
#ifdef SUPPORT_OSPF_API
/* OSPF apiserver is disabled by default. */
/* OSPF errors init */
ospf_error_init();
+ /*
+ * Need to initialize the default ospf structure, so the interface mode
+ * commands can be duly processed if they are received before 'router
+ * ospf', when ospfd is restarted
+ */
+ if (instance && !ospf_get_instance(instance, &created)) {
+ flog_err(EC_OSPF_INIT_FAIL, "OSPF instance init failed: %s",
+ strerror(errno));
+ exit(1);
+ }
+
frr_config_fork();
frr_run(master);
/* If neighbor itself declares DR and no BDR exists,
cause event BackupSeen */
if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->d_router))
- if (hello->bd_router.s_addr == 0 && oi->state == ISM_Waiting)
+ if (hello->bd_router.s_addr == INADDR_ANY
+ && oi->state == ISM_Waiting)
OSPF_ISM_EVENT_SCHEDULE(oi, ISM_BackupSeen);
/* neighbor itself declares BDR. */
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
if ((nbr = rn->info))
if (nbr->router_id.s_addr
- != 0) /* Ignore 0.0.0.0 node. */
+ != INADDR_ANY) /* Ignore 0.0.0.0 node. */
if (nbr->state
!= NSM_Attempt) /* Ignore Down neighbor. */
if (nbr->state
/* Check neighbor is
* sane? */
if (nbr->d_router.s_addr
- != 0
+ != INADDR_ANY
&& IPV4_ADDR_SAME(
- &nbr->d_router,
- &oi->address
- ->u
- .prefix4)
+ &nbr->d_router,
+ &oi->address
+ ->u
+ .prefix4)
&& IPV4_ADDR_SAME(
- &nbr->bd_router,
- &oi->address
- ->u
- .prefix4))
+ &nbr->bd_router,
+ &oi->address
+ ->u
+ .prefix4))
flag = 1;
/* Hello packet overflows interface MTU. */
IF_NAME(oi));
path = ospf_path_new();
- path->nexthop.s_addr = 0;
+ path->nexthop.s_addr = INADDR_ANY;
path->ifindex = oi->ifp->ifindex;
if (CHECK_FLAG(oi->connected->flags,
ZEBRA_IFA_UNNUMBERED))
new_or = ospf_route_new();
new_or->type = OSPF_DESTINATION_DISCARD;
- new_or->id.s_addr = 0;
+ new_or->id.s_addr = INADDR_ANY;
new_or->cost = 0;
new_or->u.std.area_id = area->area_id;
new_or->u.std.external_routing = area->external_routing;
}
/* Show DR information. */
- if (DR(oi).s_addr == 0) {
+ if (DR(oi).s_addr == INADDR_ANY) {
if (!use_json)
vty_out(vty,
" No backup designated router on this network\n");
}
if (nbr->state == NSM_Attempt
- && nbr->router_id.s_addr == 0)
+ && nbr->router_id.s_addr == INADDR_ANY)
strlcpy(neigh_str, "neighbor",
sizeof(neigh_str));
else
ospf_nbr_state_message(nbr, msgbuf, 16);
if (nbr->state == NSM_Attempt
- && nbr->router_id.s_addr == 0)
+ && nbr->router_id.s_addr == INADDR_ANY)
vty_out(vty, "%-15s %3d %-15s ", "-",
nbr->priority, msgbuf);
else
json_neigh_array = NULL;
}
- if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0)
+ if (nbr->state == NSM_Attempt
+ && nbr->router_id.s_addr == INADDR_ANY)
strlcpy(neigh_str, "noNbrId", sizeof(neigh_str));
else
strlcpy(neigh_str, inet_ntoa(nbr->router_id),
} else {
/* Show neighbor ID. */
- if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0)
+ if (nbr->state == NSM_Attempt
+ && nbr->router_id.s_addr == INADDR_ANY)
vty_out(vty, " Neighbor %s,", "-");
else
vty_out(vty, " Neighbor %s,",
int cur_originate = ospf->default_originate;
const char *type_str = NULL;
- nexthop.s_addr = 0;
+ nexthop.s_addr = INADDR_ANY;
p.family = AF_INET;
- p.prefix.s_addr = 0;
+ p.prefix.s_addr = INADDR_ANY;
p.prefixlen = 0;
ospf->default_originate = originate;
/* Nothing has changed, so nothing to do; return */
return 0;
}
- if (ospf->router_id.s_addr != 0) {
+ if (ospf->router_id.s_addr != INADDR_ANY) {
if (ei) {
if (is_prefix_default(&p))
ospf_external_lsa_refresh_default(ospf);
static int ospf_is_ready(struct ospf *ospf)
{
/* OSPF must be on and Router-ID must be configured. */
- if (!ospf || ospf->router_id.s_addr == 0)
+ if (!ospf || ospf->router_id.s_addr == INADDR_ANY)
return 0;
return 1;
ospf = ospf_new(instance, name);
ospf_add(ospf);
- if (ospf->router_id_static.s_addr == 0)
+ if (ospf->router_id_static.s_addr == INADDR_ANY)
ospf_router_id_update(ospf);
ospf_opaque_type11_lsa_init(ospf);
ospf = ospf_new(instance, NULL /* VRF_DEFAULT*/);
ospf_add(ospf);
- if (ospf->router_id_static.s_addr == 0)
+ if (ospf->router_id_static.s_addr == INADDR_ANY)
ospf_router_id_update(ospf);
ospf_opaque_type11_lsa_init(ospf);
* ospf_router_id_update() will call ospf_if_update
* whenever r-id is configured instead.
*/
- if ((area->ospf->router_id.s_addr != 0) && if_is_operative(co->ifp))
+ if ((area->ospf->router_id.s_addr != INADDR_ANY)
+ && if_is_operative(co->ifp))
ospf_if_up(oi);
}
struct interface *ifp;
/* Schedule Router ID Update. */
- if (area->ospf->router_id.s_addr == 0)
+ if (area->ospf->router_id.s_addr == INADDR_ANY)
ospf_router_id_update(area->ospf);
/* Get target interface. */
exit(EXIT_FAILURE);
}
- mc_group.s_addr = 0;
+ mc_group.s_addr = INADDR_ANY;
not_group = false;
if (argc == 3) {
static void pim_bsm_node_free(struct bsm_info *bsm)
{
- if (bsm->bsm)
- XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM, bsm->bsm);
+ XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM, bsm->bsm);
XFREE(MTYPE_PIM_BSM_INFO, bsm);
}
continue;
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
- if (sg->grp.s_addr != 0
+ if (sg->grp.s_addr != INADDR_ANY
&& sg->grp.s_addr != ch->sg.grp.s_addr)
continue;
- if (sg->src.s_addr != 0
+ if (sg->src.s_addr != INADDR_ANY
&& sg->src.s_addr != ch->sg.src.s_addr)
- continue;
+ continue;
pim_show_join_helper(vty, pim_ifp, ch, json, now, uj);
} /* scan interface channels */
}
char msdp_reg_timer[10];
char state_str[PIM_REG_STATE_STR_LEN];
- if (sg->grp.s_addr != 0 && sg->grp.s_addr != up->sg.grp.s_addr)
+ if (sg->grp.s_addr != INADDR_ANY
+ && sg->grp.s_addr != up->sg.grp.s_addr)
continue;
- if (sg->src.s_addr != 0 && sg->src.s_addr != up->sg.src.s_addr)
+ if (sg->src.s_addr != INADDR_ANY
+ && sg->src.s_addr != up->sg.src.s_addr)
continue;
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval(ch);
- ch->ifassert_winner.s_addr = 0;
+ ch->ifassert_winner.s_addr = INADDR_ANY;
/* Assert state */
ch->t_ifassert_timer = NULL;
struct in_addr nh_addr;
char nexthop_str[INET_ADDRSTRLEN];
- nh_addr.s_addr = 0;
+ nh_addr.s_addr = INADDR_ANY;
memset(&nexthop, 0, sizeof(nexthop));
up = pim_upstream_find(pim, &sg);
if (!up) {
- sg.src.s_addr = 0;
+ sg.src.s_addr = INADDR_ANY;
up = pim_upstream_find(pim, &sg);
}
rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
/* 6.2.2. 4. Fill in ... S, and Src Mask */
- if (sg.src.s_addr) {
+ if (sg.src.s_addr != INADDR_ANY) {
rspp->s = 1;
rspp->src_mask = MTRACE_SRC_MASK_SOURCE;
} else {
static void mtrace_rsp_init(struct igmp_mtrace_rsp *mtrace_rspp)
{
mtrace_rspp->arrival = 0;
- mtrace_rspp->incoming.s_addr = 0;
- mtrace_rspp->outgoing.s_addr = 0;
- mtrace_rspp->prev_hop.s_addr = 0;
+ mtrace_rspp->incoming.s_addr = INADDR_ANY;
+ mtrace_rspp->outgoing.s_addr = INADDR_ANY;
+ mtrace_rspp->prev_hop.s_addr = INADDR_ANY;
mtrace_rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
mtrace_rspp->out_count = htonl(MTRACE_UNKNOWN_COUNT);
mtrace_rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
/* 6.2.2. 2. Attempt to determine the forwarding information... */
- if (mtracep->grp_addr.s_addr)
+ if (mtracep->grp_addr.s_addr != INADDR_ANY)
fwd_info = mtrace_fwd_info(pim, mtracep, rspp, &out_ifp);
else
fwd_info = mtrace_fwd_info_weak(pim, mtracep, rspp, &out_ifp);
reached_source = false;
- if (nh_addr.s_addr == 0) {
+ if (nh_addr.s_addr == INADDR_ANY) {
/* no pim? i.e. 7.5.3. No Previous Hop */
if (!out_ifp->info) {
if (PIM_DEBUG_MTRACE)
struct prefix_sg *sg)
{
struct in_addr rp;
- rp.s_addr = 0;
+ rp.s_addr = INADDR_ANY;
pim_msdp_sa_ref(pim, NULL /* mp */, sg, rp);
}
stream_fifo_free(mp->obuf);
}
- if (mp->mesh_group_name) {
- XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name);
- }
+ XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name);
mp->pim = NULL;
XFREE(MTYPE_PIM_MSDP_PEER, mp);
%endif
%endif
+# Check for python version - use python2.7 on CentOS 6, otherwise python3
+%if 0%{?rhel} && 0%{?rhel} < 7
+ %global use_python2 1
+%else
+ %global use_python2 0
+%endif
+
# If init system is systemd, then always enable watchfrr
%if "%{initsystem}" == "systemd"
%global with_watchfrr 1
BuildRequires: python27-devel
BuildRequires: python27-sphinx
%else
-%if 0%{?rhel} && 0%{?rhel} > 7
-BuildRequires: python2-devel
-#platform-python-devel is needed for /usr/bin/pathfix.py
-BuildRequires: platform-python-devel
-%else
+%if %{use_python2}
BuildRequires: python-devel >= 2.7
BuildRequires: python-sphinx
+%else
+BuildRequires: python3-devel
+BuildRequires: python3-sphinx
%endif
%endif
+%if 0%{?rhel} > 7
+#platform-python-devel is needed for /usr/bin/pathfix.py
+BuildRequires: platform-python-devel
+%endif
Requires: initscripts
%if %{with_pam}
BuildRequires: pam-devel
%package pythontools
Summary: python tools for frr
-%if 0%{?rhel} && 0%{?rhel} > 7
-BuildRequires: python2
-Requires: python2-ipaddress
+%if 0%{?rhel} && 0%{?rhel} < 7
+#python27 is available from ius community repo for RedHat/CentOS 6
+BuildRequires: python27
+Requires: python27-ipaddress
+%else
+%if %{use_python2}
+BuildRequires: python2
+Requires: python2-ipaddress
%else
-BuildRequires: python
-Requires: python-ipaddress
+BuildRequires: python3
+%endif
%endif
Group: System Environment/Daemons
make %{?_smp_mflags} MAKEINFO="makeinfo --no-split"
+%if %{use_python2}
+# Change frr-reload.py to use python2.7
+sed -e '1c #!/usr/bin/python2.7' -i %{zeb_src}/tools/frr-reload.py
+sed -e '1c #!/usr/bin/python2.7' -i %{zeb_src}/tools/generate_support_bundle.py
+%else
+# Change frr-reload.py to use python3
+sed -e '1c #!/usr/bin/python3' -i %{zeb_src}/tools/frr-reload.py
+sed -e '1c #!/usr/bin/python3' -i %{zeb_src}/tools/generate_support_bundle.py
+%endif
+
pushd doc
make info
popd
install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
install -d -m750 %{buildroot}%{rundir}
-%if 0%{?rhel} && 0%{?rhel} > 7
+%if 0%{?rhel} > 7 || 0%{?fedora} > 29
# avoid `ERROR: ambiguous python shebang in` errors
-pathfix.py -pni "%{__python2} %{py2_shbang_opts}" %{buildroot}/usr/lib/frr/*.py
-%py_byte_compile %{__python2} %{buildroot}/usr/lib/frr/*.py
+pathfix.py -pni "%{__python3} %{py3_shbang_opts}" %{buildroot}/usr/lib/frr/*.py
+%py_byte_compile %{__python3} %{buildroot}/usr/lib/frr/*.py
%endif
%pre
%files pythontools
%{_sbindir}/generate_support_bundle.py
+%{_sbindir}/frr-reload.py
+%if 0%{?rhel} > 7 || 0%{?fedora} > 29
+%{_sbindir}/__pycache__/*
+%else
%{_sbindir}/generate_support_bundle.pyc
%{_sbindir}/generate_support_bundle.pyo
%{_sbindir}/frr-reload.py
%{_sbindir}/frr-reload.pyc
%{_sbindir}/frr-reload.pyo
+%endif
%files devel
{
rip_interface_reset(ifp->info);
XFREE(MTYPE_RIP_INTERFACE, ifp->info);
- ifp->info = NULL;
return 0;
}
#include "vrf.h"
#include "if_rmap.h"
#include "libfrr.h"
+#include "routemap.h"
#include "ripd/ripd.h"
#include "ripd/rip_nb.h"
static const struct frr_yang_module_info *const ripd_yang_modules[] = {
&frr_interface_info,
&frr_ripd_info,
+ &frr_route_map_info,
};
FRR_DAEMON_INFO(ripd, RIP, .vty_port = RIP_VTY_PORT,
if (type == RMAP_RIP) {
rinfo = object;
p.family = AF_INET;
- p.prefix = (rinfo->nh.gate.ipv4.s_addr) ? rinfo->nh.gate.ipv4
- : rinfo->from;
+ p.prefix = (rinfo->nh.gate.ipv4.s_addr != INADDR_ANY)
+ ? rinfo->nh.gate.ipv4
+ : rinfo->from;
p.prefixlen = IPV4_MAX_BITLEN;
alist = access_list_lookup(AFI_IP, (char *)rule);
if (type == RMAP_RIP) {
rinfo = object;
p.family = AF_INET;
- p.prefix = (rinfo->nh.gate.ipv4.s_addr) ? rinfo->nh.gate.ipv4
- : rinfo->from;
+ p.prefix = (rinfo->nh.gate.ipv4.s_addr != INADDR_ANY)
+ ? rinfo->nh.gate.ipv4
+ : rinfo->from;
p.prefixlen = IPV4_MAX_BITLEN;
plist = prefix_list_lookup(AFI_IP, (char *)rule);
}
/* RIPv1 does not have nexthop value. */
- if (packet->version == RIPv1 && rte->nexthop.s_addr != 0) {
+ if (packet->version == RIPv1
+ && rte->nexthop.s_addr != INADDR_ANY) {
zlog_info("RIPv1 packet with nexthop value %s",
inet_ntoa(rte->nexthop));
rip_peer_bad_route(rip, from);
sub-optimal, but absolutely valid, route may be taken. If
the received Next Hop is not directly reachable, it should be
treated as 0.0.0.0. */
- if (packet->version == RIPv2 && rte->nexthop.s_addr != 0) {
+ if (packet->version == RIPv2
+ && rte->nexthop.s_addr != INADDR_ANY) {
uint32_t addrval;
/* Multicast address check. */
"Next hop %s is not directly reachable. Treat it as 0.0.0.0",
inet_ntoa(
rte->nexthop));
- rte->nexthop.s_addr = 0;
+ rte->nexthop.s_addr =
+ INADDR_ANY;
}
route_unlock_node(rn);
"Next hop %s is not directly reachable. Treat it as 0.0.0.0",
inet_ntoa(
rte->nexthop));
- rte->nexthop.s_addr = 0;
+ rte->nexthop.s_addr = INADDR_ANY;
}
}
}
(/16 for class B's) except when the RIP packet does to inside
the classful network in question. */
- if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
+ if ((packet->version == RIPv1
+ && rte->prefix.s_addr != INADDR_ANY)
|| (packet->version == RIPv2
- && (rte->prefix.s_addr != 0
- && rte->mask.s_addr == 0))) {
+ && (rte->prefix.s_addr != INADDR_ANY
+ && rte->mask.s_addr == INADDR_ANY))) {
uint32_t destination;
if (subnetted == -1) {
/* In case of RIPv2, if prefix in RTE is not netmask applied one
ignore the entry. */
- if ((packet->version == RIPv2) && (rte->mask.s_addr != 0)
+ if ((packet->version == RIPv2)
+ && (rte->mask.s_addr != INADDR_ANY)
&& ((rte->prefix.s_addr & rte->mask.s_addr)
!= rte->prefix.s_addr)) {
zlog_warn(
}
/* Default route's netmask is ignored. */
- if (packet->version == RIPv2 && (rte->prefix.s_addr == 0)
- && (rte->mask.s_addr != 0)) {
+ if (packet->version == RIPv2
+ && (rte->prefix.s_addr == INADDR_ANY)
+ && (rte->mask.s_addr != INADDR_ANY)) {
if (IS_RIP_DEBUG_EVENT)
zlog_debug(
"Default route with non-zero netmask. Set zero to netmask");
- rte->mask.s_addr = 0;
+ rte->mask.s_addr = INADDR_ANY;
}
/* Routing table updates. */
running_config->version++;
}
}
- if (old_vrf_name)
- XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name);
+ XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name);
}
if (!rip || rip->enabled)
return 0;
static int ripng_if_delete_hook(struct interface *ifp)
{
XFREE(MTYPE_RIPNG_IF, ifp->info);
- ifp->info = NULL;
return 0;
}
#include "vrf.h"
#include "if_rmap.h"
#include "libfrr.h"
+#include "routemap.h"
#include "ripngd/ripngd.h"
#include "ripngd/ripng_nb.h"
static const struct frr_yang_module_info *const ripngd_yang_modules[] = {
&frr_interface_info,
&frr_ripngd_info,
+ &frr_route_map_info,
};
FRR_DAEMON_INFO(ripngd, RIPNG, .vty_port = RIPNG_VTY_PORT,
running_config->version++;
}
}
- if (old_vrf_name)
- XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
+ XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
}
if (ripng->enabled)
--- /dev/null
+@@
+expression e;
+@@
+
+(
+- e.s_addr == 0
++ e.s_addr == INADDR_ANY
+|
+- e.s_addr != 0
++ e.s_addr != INADDR_ANY
+|
+- e.s_addr = 0
++ e.s_addr = INADDR_ANY
+)
--- /dev/null
+@@
+identifier data;
+constant x;
+@@
+
+(
+- data = data + x
++ data += x
+|
+- data = data - x
++ data -= x
+)
--- /dev/null
+@@
+identifier f;
+expression e;
+@@
+void f(...) {
+ ...
+- return
+ e;
+}
static int setup_bgp_path_info_mpath_update(testcase_t *t)
{
int i;
+ struct bgp *bgp;
+ struct bgp_table *rt;
+ struct route_node *rt_node;
+ as_t asn = 1;
+
+ t->tmp_data = bgp_create_fake(&asn, NULL);
+ if (!t->tmp_data)
+ return -1;
+
+ bgp = t->tmp_data;
+ rt = bgp->rib[AFI_IP][SAFI_UNICAST];
+
+ if (!rt)
+ return -1;
+
str2prefix("42.1.1.0/24", &test_rn.p);
+ rt_node = bgp_node_to_rnode(&test_rn);
+ memcpy((struct route_table *)&rt_node->table, &rt->route_table,
+ sizeof(struct route_table));
setup_bgp_mp_list(t);
for (i = 0; i < test_mp_list_info_count; i++)
bgp_path_info_add(&test_rn, &test_mp_list_info[i]);
for (i = 0; i < test_mp_list_peer_count; i++)
sockunion_free(test_mp_list_peer[i].su_remote);
- return 0;
+ return bgp_delete((struct bgp *)t->tmp_data);
}
testcase_t test_bgp_path_info_mpath_update = {
assert(hn && hn->str);
printf("%s: %s\n", __func__, hn->str);
XFREE(MTYPE_WQ_NODE_STR, hn->str);
- hn->str = NULL;
XFREE(MTYPE_WQ_NODE, hn);
}
oldFile = LOG_DIR + fileName
cpFileCmd = "cp " + oldFile + " " + oldFile + ".prev"
rmFileCmd = "rm -rf " + oldFile
- print "Making backup of " + oldFile
+ print("Making backup of " + oldFile)
os.system(cpFileCmd)
- print "Removing " + oldFile
+ print("Removing " + oldFile)
os.system(rmFileCmd)
return fileName
# Open the output file for this process
def openOutputFile(fileName):
crt_file_cmd = LOG_DIR + fileName
- print crt_file_cmd
+ print(crt_file_cmd)
try:
outputFile = open(crt_file_cmd, "w")
return outputFile
outputFile.write("########################################################\n")
outputFile.write('\n')
except:
- print "Writing to ouptut file Failed"
+ print("Writing to ouptut file Failed")
except subprocess.CalledProcessError as e:
dateTime = datetime.datetime.now()
outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n")
outputFile.write(e.output)
outputFile.write("########################################################\n")
outputFile.write('\n')
- print "Error:" + e.output
+ print("Error:" + e.output)
# Process the support bundle configuration file
if cmd_line[0] == "PROC_NAME":
outputFileName = createOutputFile(cmd_line[1])
if outputFileName:
- print outputFileName, "created for", cmd_line[1]
+ print(outputFileName, "created for", cmd_line[1])
elif cmd_line[0] == "CMD_LIST_START":
outputFile = openOutputFile(outputFileName)
if outputFile:
- print outputFileName, "opened"
+ print(outputFileName, "opened")
else:
- print outputFileName, "open failed"
- return FAIL
+ print(outputFileName, "open failed")
+ return FAIL
elif cmd_line[0] == "CMD_LIST_END":
if closeOutputFile(outputFile):
- print outputFileName, "closed"
+ print(outputFileName, "closed")
else:
- print outputFileName, "close failed"
+ print(outputFileName, "close failed")
else:
- print "Execute:" , cmd_line[0]
+ print("Execute:" , cmd_line[0])
executeCommand(cmd_line[0], outputFile)
# Main Function
lines = openConfFile(inputFile)
if not lines:
- print "File support_bundle_commands.conf not present in /etc/frr/ directory"
+ print("File support_bundle_commands.conf not present in /etc/frr/ directory")
else:
processConfFile(lines)
if ($file =~ /lib\/keychain\.c$/) {
$protocol = "VTYSH_RIPD|VTYSH_EIGRPD";
}
- elsif ($file =~ /lib\/routemap\.c$/) {
+ elsif ($file =~ /lib\/routemap\.c$/ || $file =~ /lib\/routemap_cli\.c$/) {
$protocol = "VTYSH_RMAP";
}
elsif ($file =~ /lib\/vrf\.c$/) {
return matched[index++];
XFREE(MTYPE_TMP, matched);
- matched = NULL;
return NULL;
}
return vtysh_write_memory(self, vty, argc, argv);
}
+DEFUN (vtysh_copy_to_running,
+ vtysh_copy_to_running_cmd,
+ "copy FILENAME running-config",
+ "Apply a configuration file\n"
+ "Configuration file to read\n"
+ "Apply to current configuration\n")
+{
+ int ret;
+ const char *fname = argv[1]->arg;
+
+ ret = vtysh_read_config(fname);
+
+ /* Return to enable mode - the 'read_config' api leaves us up a level */
+ vtysh_execute_no_pager("enable");
+
+ return ret;
+}
+
DEFUN (vtysh_terminal_paginate,
vtysh_terminal_paginate_cmd,
"[no] terminal paginate",
install_element(INTERFACE_NODE, &vtysh_link_params_cmd);
install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
+ install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd);
install_element(CONFIG_NODE, &vtysh_vrf_cmd);
install_element(VRF_NODE, &vtysh_vrf_netns_cmd);
import frr-filter {
prefix filter;
}
+ import frr-interface {
+ prefix frr-interface;
+ }
organization "Free Range Routing";
contact
/*
* Operational data.
*/
- container route-map {
- list instance {
+ container lib {
+ list route-map {
description "Route map instance";
- key "name sequence";
+ key "name";
leaf name {
description "Route map instance name";
type route-map-name;
}
- leaf sequence {
- description
- "Route map instance priority (low number means higher priority)";
- type route-map-sequence;
- }
+ list entry {
+ description "Route map entry";
- leaf description {
- description "Route map description";
- type string;
- }
+ key "sequence";
- leaf action {
- description
- "Route map actions: permit (executes action), deny (quits evaluation)";
- mandatory true;
- type enumeration {
- enum permit {
- description
- "Executes configured action and permits the prefix/route
- if the conditions matched. An alternative exit action can
- be configured to continue processing the route map list
- or jump to process another route map.";
- value 0;
- }
- enum deny {
- description
- "If all conditions are met the prefix/route is denied and
- route map processing stops.";
- value 1;
- }
+ leaf sequence {
+ description
+ "Route map instance priority (low number means higher priority)";
+ type route-map-sequence;
}
- }
-
- list match-condition {
- description "Route map match conditions";
- key "condition";
+ leaf description {
+ description "Route map description";
+ type string;
+ }
- leaf condition {
- description "Match condition";
+ leaf action {
+ description
+ "Route map actions: permit (executes action), deny (quits evaluation)";
+ mandatory true;
type enumeration {
- enum interface {
- description "Match interface";
+ enum permit {
+ description
+ "Executes configured action and permits the prefix/route
+ if the conditions matched. An alternative exit action can
+ be configured to continue processing the route map list
+ or jump to process another route map.";
value 0;
}
- enum ipv4-address-list {
- description "Match an IPv4 access-list";
+ enum deny {
+ description
+ "If all conditions are met the prefix/route is denied and
+ route map processing stops.";
value 1;
}
- enum ipv4-prefix-list {
- description "Match an IPv4 prefix-list";
- value 2;
- }
- enum ipv4-prefix-length {
- description "Match an IPv4 prefix length";
- value 3;
- }
- enum ipv4-next-hop-list {
- description "Match an IPv4 next-hop";
- value 4;
- }
- enum ipv4-next-hop-prefix-list {
- description "Match an IPv4 next-hop prefix list";
- value 5;
- }
- enum ipv4-next-hop-prefix-length {
- description "Match an IPv4 next-hop prefix length";
- value 6;
- }
- enum ipv4-next-hop-type {
- description "Match an IPv4 next-hop type";
- value 7;
- }
- enum ipv6-address-list {
- description "Match an IPv6 access-list";
- value 8;
- }
- enum ipv6-prefix-list {
- description "Match an IPv6 prefix-list";
- value 9;
- }
- enum ipv6-prefix-length {
- description "Match an IPv6 prefix length";
- value 10;
- }
- enum ipv6-next-hop {
- description "Match an IPv6 next-hop";
- value 11;
- }
- enum ipv6-next-hop-type {
- description "Match an IPv6 next-hop type";
- value 12;
- }
- enum metric {
- description "Match a route metric";
- value 13;
+ }
+ }
+
+ leaf call {
+ description
+ "Call another route map before calling `exit-policy`. If the
+ called route map returns deny then this route map will also
+ return deny";
+ type route-map-name;
+ }
+
+ leaf exit-policy {
+ description "What do to after route map successful match, set and call";
+ type enumeration {
+ enum permit-or-deny {
+ description "End route map evaluation and return";
+ value 0;
}
- enum tag {
- description "Match a route tag";
- value 14;
+ enum next {
+ description
+ "Proceed evaluating next route map entry per sequence";
+ value 1;
}
-
- /*
- * Protocol YANG models should augment the parent node to
- * contain the routing protocol specific value. The protocol
- * must also augment `condition-value` to include its specific
- * values or expand the `when` statement on the existing cases.
- */
- enum routing-protocol-specific {
- description "Match a routing protocol specific type";
- value 100;
+ enum goto {
+ description
+ "Go to route map entry with the provided sequence number";
+ value 2;
}
}
+ default "permit-or-deny";
}
- choice condition-value {
+ leaf goto-value {
+ when "../exit-policy = 'goto'";
description
- "Value to match (interpretation depends on condition type)";
- case access-list-num {
- when "./condition = 'ipv4-address-list' or
- ./condition = 'ipv4-next-hop-list'";
- leaf access-list-num {
- type filter:access-list-standard;
- }
- }
- case access-list-num-extended {
- when "./condition = 'ipv4-address-list' or
- ./condition = 'ipv4-next-hop-list'";
- leaf access-list-num-extended {
- type filter:access-list-extended;
+ "Sequence number to jump (when using `goto` exit policy)";
+ mandatory true;
+ type route-map-sequence;
+ }
+
+ list match-condition {
+ description "Route map match conditions";
+
+ key "condition";
+
+ leaf condition {
+ description "Match condition";
+ type enumeration {
+ enum interface {
+ description "Match interface";
+ value 0;
+ }
+ enum ipv4-address-list {
+ description "Match an IPv4 access-list";
+ value 1;
+ }
+ enum ipv4-prefix-list {
+ description "Match an IPv4 prefix-list";
+ value 2;
+ }
+ enum ipv4-next-hop-list {
+ description "Match an IPv4 next-hop";
+ value 3;
+ }
+ enum ipv4-next-hop-prefix-list {
+ description "Match an IPv4 next-hop prefix list";
+ value 4;
+ }
+ enum ipv4-next-hop-type {
+ description "Match an IPv4 next-hop type";
+ value 5;
+ }
+ enum ipv6-address-list {
+ description "Match an IPv6 access-list";
+ value 6;
+ }
+ enum ipv6-prefix-list {
+ description "Match an IPv6 prefix-list";
+ value 7;
+ }
+ enum ipv6-next-hop-type {
+ description "Match an IPv6 next-hop type";
+ value 8;
+ }
+ enum metric {
+ description "Match a route metric";
+ value 9;
+ }
+ enum tag {
+ description "Match a route tag";
+ value 10;
+ }
+
+ /*
+ * Protocol YANG models should augment the parent node to
+ * contain the routing protocol specific value. The protocol
+ * must also augment `condition-value` to include its specific
+ * values or expand the `when` statement on the existing cases.
+ */
+ enum routing-protocol-specific {
+ description "Match a routing protocol specific type";
+ value 100;
+ }
}
}
- case list-name {
- when "./condition = 'ipv4-address-list' or
- ./condition = 'ipv4-prefix-list' or
- ./condition = 'ipv4-next-hop-list' or
- ./condition = 'ipv4-next-hop-prefix-list' or
- ./condition = 'ipv6-address-list' or
- ./condition = 'ipv6-prefix-list'";
- leaf list-name {
- type filter:access-list-name;
+
+ choice condition-value {
+ description
+ "Value to match (interpretation depends on condition type)";
+ mandatory true;
+ case interface {
+ when "./condition = 'interface'";
+ leaf interface {
+ type frr-interface:interface-ref;
+ }
}
- }
- case ipv6-address {
- when "./condition = 'ipv6-next-hop'";
- leaf ipv6-address {
- type inet:ipv6-address;
+ case access-list-num {
+ when "./condition = 'ipv4-address-list' or
+ ./condition = 'ipv4-next-hop-list'";
+ leaf access-list-num {
+ type filter:access-list-standard;
+ }
}
- }
- case ipv4-prefix-length {
- when "./condition = 'ipv4-prefix-length' or
- ./condition = 'ipv4-next-hop-prefix-length'";
- leaf ipv4-prefix-length {
- type uint8 {
- range "0..32";
+ case access-list-num-extended {
+ when "./condition = 'ipv4-address-list' or
+ ./condition = 'ipv4-next-hop-list'";
+ leaf access-list-num-extended {
+ type filter:access-list-extended;
}
}
- }
- case ipv6-prefix-length {
- when "./condition = 'ipv6-prefix-length'";
- leaf ipv6-prefix-length {
- type uint8 {
- range "0..128";
+ case list-name {
+ when "./condition = 'ipv4-address-list' or
+ ./condition = 'ipv4-prefix-list' or
+ ./condition = 'ipv4-next-hop-list' or
+ ./condition = 'ipv4-next-hop-prefix-list' or
+ ./condition = 'ipv6-address-list' or
+ ./condition = 'ipv6-prefix-list'";
+ leaf list-name {
+ type filter:access-list-name;
}
}
- }
- case ipv4-next-hop-type {
- when "./condition = 'ipv4-next-hop-type'";
- leaf ipv4-next-hop-type {
- type enumeration {
- enum blackhole {
- value 0;
+ case ipv4-next-hop-type {
+ when "./condition = 'ipv4-next-hop-type'";
+ leaf ipv4-next-hop-type {
+ type enumeration {
+ enum blackhole {
+ value 0;
+ }
}
}
}
- }
- case ipv6-next-hop-type {
- when "./condition = 'ipv6-next-hop-type'";
- leaf ipv6-next-hop-type {
- type enumeration {
- enum blackhole {
- value 0;
+ case ipv6-next-hop-type {
+ when "./condition = 'ipv6-next-hop-type'";
+ leaf ipv6-next-hop-type {
+ type enumeration {
+ enum blackhole {
+ value 0;
+ }
}
}
}
- }
- case metric {
- when "./condition = 'metric'";
- leaf metric {
- type uint32 {
- range "1..4294967295";
+ case metric {
+ when "./condition = 'metric'";
+ leaf metric {
+ type uint32 {
+ range "1..4294967295";
+ }
}
}
- }
- case tag {
- when "./condition = 'tag'";
- leaf tag {
- type uint32 {
- range "1..4294967295";
+ case tag {
+ when "./condition = 'tag'";
+ leaf tag {
+ type uint32 {
+ range "1..4294967295";
+ }
}
}
}
}
- }
- list set-action {
- description "Route map set actions";
+ list set-action {
+ description "Route map set actions";
- key "action";
+ key "action";
- leaf action {
- description "Action to do when the route map matches";
- type enumeration {
- enum ipv4-next-hop {
- description "Set IPv4 address of the next hop";
- value 0;
- }
- enum ipv6-next-hop {
- description "Set IPv6 address of the next hop";
- value 1;
- }
- enum metric {
- description "Set prefix/route metric";
- value 2;
- }
- enum tag {
- description "Set tag";
- value 3;
- }
+ leaf action {
+ description "Action to do when the route map matches";
+ type enumeration {
+ enum ipv4-next-hop {
+ description "Set IPv4 address of the next hop";
+ value 0;
+ }
+ enum ipv6-next-hop {
+ description "Set IPv6 address of the next hop";
+ value 1;
+ }
+ enum metric {
+ description "Set prefix/route metric";
+ value 2;
+ }
+ enum tag {
+ description "Set tag";
+ value 3;
+ }
- /*
- * Protocol YANG models should augment the parent node to
- * contain the routing protocol specific value. The protocol
- * must also augment `action-value` to include its specific
- * values or expand the `when` statement on the existing cases.
- */
- enum routing-protocol-specific {
- description "Set a routing protocol specific action";
- value 100;
+ /*
+ * Protocol YANG models should augment the parent node to
+ * contain the routing protocol specific value. The protocol
+ * must also augment `action-value` to include its specific
+ * values or expand the `when` statement on the existing cases.
+ */
+ enum routing-protocol-specific {
+ description "Set a routing protocol specific action";
+ value 100;
+ }
}
}
- }
- choice action-value {
- description
- "Value to set (interpretation depends on action-type)";
- case ipv4-address {
- when "./action = 'ipv4-next-hop'";
- leaf ipv4-address {
- description "IPv4 address";
- type inet:ipv4-address;
+ choice action-value {
+ description
+ "Value to set (interpretation depends on action-type)";
+ case ipv4-address {
+ when "./action = 'ipv4-next-hop'";
+ leaf ipv4-address {
+ description "IPv4 address";
+ type inet:ipv4-address;
+ }
}
- }
- case ipv6-address {
- when "./action = 'ipv6-next-hop'";
- leaf ipv6-address {
- description "IPv6 address";
- type inet:ipv6-address;
+ case ipv6-address {
+ when "./action = 'ipv6-next-hop'";
+ leaf ipv6-address {
+ description "IPv6 address";
+ type inet:ipv6-address;
+ }
}
- }
- case metric {
- when "./action = 'metric'";
- choice metric-value {
- description "Metric to set or use";
- case value {
- leaf value {
- description "Use the following metric value";
- type uint32 {
- range "0..4294967295";
+ case metric {
+ when "./action = 'metric'";
+ choice metric-value {
+ description "Metric to set or use";
+ case value {
+ leaf value {
+ description "Use the following metric value";
+ type uint32 {
+ range "0..4294967295";
+ }
}
}
- }
- case add-metric {
- leaf add-metric {
- description "Add unit to metric";
- type boolean;
+ case add-metric {
+ leaf add-metric {
+ description "Add unit to metric";
+ type boolean;
+ }
}
- }
- case subtract-metric {
- leaf subtract-metric {
- description "Subtract unit from metric";
- type boolean;
+ case subtract-metric {
+ leaf subtract-metric {
+ description "Subtract unit from metric";
+ type boolean;
+ }
}
- }
- case use-round-trip-time {
- leaf use-round-trip-time {
- description "Use the round trip time as metric";
- type boolean;
+ case use-round-trip-time {
+ leaf use-round-trip-time {
+ description "Use the round trip time as metric";
+ type boolean;
+ }
}
- }
- case add-round-trip-time {
- leaf add-round-trip-time {
- description "Add round trip time to metric";
- type boolean;
+ case add-round-trip-time {
+ leaf add-round-trip-time {
+ description "Add round trip time to metric";
+ type boolean;
+ }
}
- }
- case subtract-round-trip-time {
- leaf subtract-round-trip-time {
- description "Subtract round trip time to metric";
- type boolean;
+ case subtract-round-trip-time {
+ leaf subtract-round-trip-time {
+ description "Subtract round trip time to metric";
+ type boolean;
+ }
}
}
}
- }
- case tag {
- leaf tag {
- description "Tag value";
- type uint32 {
- range "0..4294967295";
+ case tag {
+ when "./action = 'tag'";
+ leaf tag {
+ description "Tag value";
+ type uint32 {
+ range "0..4294967295";
+ }
}
}
}
}
}
-
- leaf call {
- description
- "Call another route map before calling `exit-policy`. If the
- called route map returns deny then this route map will also
- return deny";
- type string;
- }
-
- leaf exit-policy {
- description "What do to after route map successful match, set and call";
- type enumeration {
- enum permit-or-deny {
- description "End route map evaluation and return";
- value 0;
- }
- enum next {
- description
- "Proceed evaluating next route map entry per sequence";
- value 1;
- }
- enum goto {
- description
- "Go to route map entry with the provided sequence number";
- value 2;
- }
- }
- default "permit-or-deny";
- }
-
- leaf goto-value {
- when "../exit-policy = 'goto'";
- description
- "Sequence number to jump (when using `goto` exit policy)";
- type route-map-sequence;
- }
}
}
}
# global symbols :(. Just put it in the daemon. Dynamic libraries.so work
# without problems, as seen in libfrr.
+dist_yangmodels_DATA += yang/frr-filter.yang
dist_yangmodels_DATA += yang/frr-module-translator.yang
dist_yangmodels_DATA += yang/frr-test-module.yang
dist_yangmodels_DATA += yang/frr-interface.yang
+dist_yangmodels_DATA += yang/frr-route-map.yang
dist_yangmodels_DATA += yang/frr-route-types.yang
dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang
if (IS_ZEBRA_DEBUG_MLAG)
vty_out(vty, " Zebra mlag debugging is on\n");
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- vty_out(vty, "Zebra detailed nexthop debugging is on\n");
+ vty_out(vty, " Zebra detailed nexthop debugging is on\n");
else if (IS_ZEBRA_DEBUG_NHG)
- vty_out(vty, "Zebra nexthop debugging is on\n");
+ vty_out(vty, " Zebra nexthop debugging is on\n");
hook_call(zebra_debug_show_debugging, vty);
return CMD_SUCCESS;
write++;
}
+ if (CHECK_FLAG(zebra_debug_nexthop, ZEBRA_DEBUG_NHG_DETAILED)) {
+ vty_out(vty, "debug zebra nexthop detail\n");
+ write++;
+ } else if (CHECK_FLAG(zebra_debug_nexthop, ZEBRA_DEBUG_NHG)) {
+ vty_out(vty, "debug zebra nexthop\n");
+ write++;
+ }
+
return write;
}
* 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. */
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);
static const struct frr_yang_module_info *const zebra_yang_modules[] = {
&frr_interface_info,
+ &frr_route_map_info,
};
FRR_DAEMON_INFO(
struct connected *c;
struct zebra_vrf *zvrf = vrf_info_get(vrf_id);
- p->u.prefix4.s_addr = 0;
+ p->u.prefix4.s_addr = INADDR_ANY;
p->family = AF_INET;
p->prefixlen = 32;
- if (zvrf->rid_user_assigned.u.prefix4.s_addr)
+ if (zvrf->rid_user_assigned.u.prefix4.s_addr != INADDR_ANY)
p->u.prefix4.s_addr = zvrf->rid_user_assigned.u.prefix4.s_addr;
else if (!list_isempty(zvrf->rid_lo_sorted_list)) {
node = listtail(zvrf->rid_lo_sorted_list);
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
if ((zvrf = vrf->info) != NULL)
- if (zvrf->rid_user_assigned.u.prefix4.s_addr) {
+ if (zvrf->rid_user_assigned.u.prefix4.s_addr
+ != INADDR_ANY) {
if (zvrf_id(zvrf) == VRF_DEFAULT)
vty_out(vty, "router-id %s\n",
inet_ntoa(
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 {
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
addattr_l(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4);
addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
- if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
+ if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY
+ && (cmd == RTM_NEWROUTE))
addattr_l(nlmsg, req_size, RTA_PREFSRC,
&nexthop->rmap_src.ipv4, bytelen);
- else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
+ else if (nexthop->src.ipv4.s_addr != INADDR_ANY
+ && (cmd == RTM_NEWROUTE))
addattr_l(nlmsg, req_size, RTA_PREFSRC,
&nexthop->src.ipv4, bytelen);
bytelen, nexthop);
if (cmd == RTM_NEWROUTE) {
- if (nexthop->rmap_src.ipv4.s_addr)
+ if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
addattr_l(nlmsg, req_size, RTA_PREFSRC,
&nexthop->rmap_src.ipv4, bytelen);
- else if (nexthop->src.ipv4.s_addr)
+ else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
addattr_l(nlmsg, req_size, RTA_PREFSRC,
&nexthop->src.ipv4, bytelen);
}
if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
if (cmd == RTM_NEWROUTE) {
- if (nexthop->rmap_src.ipv4.s_addr)
+ if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
addattr_l(nlmsg, req_size, RTA_PREFSRC,
&nexthop->rmap_src.ipv4, bytelen);
- else if (nexthop->src.ipv4.s_addr)
+ else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
addattr_l(nlmsg, req_size, RTA_PREFSRC,
&nexthop->src.ipv4, bytelen);
}
rtnh->rtnh_len += sizeof(struct rtattr) + bytelen;
rtnh->rtnh_ifindex = nexthop->ifindex;
- if (nexthop->rmap_src.ipv4.s_addr)
+ if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
*src = &nexthop->rmap_src;
- else if (nexthop->src.ipv4.s_addr)
+ else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
_netlink_route_rta_add_gateway_info(rtmsg->rtm_family, AF_INET,
rta, rtnh, NL_PKT_BUF_SIZE,
bytelen, nexthop);
- if (nexthop->rmap_src.ipv4.s_addr)
+ if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
*src = &nexthop->rmap_src;
- else if (nexthop->src.ipv4.s_addr)
+ else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
/* ifindex */
if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
- if (nexthop->rmap_src.ipv4.s_addr)
+ if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
*src = &nexthop->rmap_src;
- else if (nexthop->src.ipv4.s_addr)
+ else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
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));
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';
nhm = NLMSG_DATA(h);
+ if (ns_id)
+ vrf_id = ns_id;
+
if (startup && h->nlmsg_type != RTM_NEWNEXTHOP)
return 0;
return -1;
} else if (h->nlmsg_type == RTM_DELNEXTHOP)
- zebra_nhg_kernel_del(id);
+ zebra_nhg_kernel_del(id, vrf_id);
return 0;
}
* 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;
}
$(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
zebra/table_manager.c \
zebra/zapi_msg.c \
zebra/zebra_errors.c \
+ zebra/zebra_gr.c \
# end
zebra/debug_clippy.c: $(CLIPPY_DEPS)
api_nh = &api.nexthops[i];
ifindex_t ifindex = 0;
+ nexthop = NULL;
+
if (IS_ZEBRA_DEBUG_RECV)
zlog_debug("nh type %d", api_nh->type);
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:
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) = {
[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)
}
XFREE(MTYPE_DP_CTX, *pctx);
- *pctx = NULL;
}
/*
if (nexthop->type == NEXTHOP_TYPE_IPV4
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
nhi.gateway = &nexthop->gate;
- if (nexthop->src.ipv4.s_addr)
+ if (nexthop->src.ipv4.s_addr != INADDR_ANY)
src = &nexthop->src;
}
}
if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
- if (nexthop->src.ipv4.s_addr)
+ if (nexthop->src.ipv4.s_addr != INADDR_ANY)
src = &nexthop->src;
}
if (nexthop->type == NEXTHOP_TYPE_IPV4
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
gateway = &nexthop->gate;
- if (nexthop->src.ipv4.s_addr)
+ if (nexthop->src.ipv4.s_addr != INADDR_ANY)
src = &nexthop->src;
}
}
if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
- if (nexthop->src.ipv4.s_addr)
+ if (nexthop->src.ipv4.s_addr != INADDR_ANY)
src = &nexthop->src;
}
--- /dev/null
+/*
+ * 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);
+ }
+}
}
for (i = 0; i < mlag_msg.msg_cnt; i++) {
- if (pay_load[i]->vrf_name)
- XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
+ XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
&& pay_load[i]->intf_name)
XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
- if (pay_load[i])
- XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
+ XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
}
XFREE(MTYPE_MLAG_PBUF, pay_load);
if (cleanup == true)
}
for (i = 0; i < mlag_msg.msg_cnt; i++) {
- if (pay_load[i]->vrf_name)
- XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
+ XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
&& pay_load[i]->intf_name)
XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
- if (pay_load[i])
- XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
+ XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
}
XFREE(MTYPE_MLAG_PBUF, pay_load);
if (cleanup)
mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
sizeof(buf)),
len);
- if (hdr.data.data)
- XFREE(MTYPE_MLAG_PBUF, hdr.data.data);
+ XFREE(MTYPE_MLAG_PBUF, hdr.data.data);
return len;
}
/* 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,
return nhg_connected_tree_first(head);
}
-void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
- struct nhg_hash_entry *depend)
+struct nhg_hash_entry *
+nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *depend)
{
struct nhg_connected lookup = {};
struct nhg_connected *remove = NULL;
+ struct nhg_hash_entry *removed_nhe;
lookup.nhe = depend;
/* Lookup to find the element, then remove it */
remove = nhg_connected_tree_find(head, &lookup);
- remove = nhg_connected_tree_del(head, remove);
-
if (remove)
+ /* Re-returning here just in case this API changes..
+ * the _del list api's are a bit undefined at the moment.
+ *
+ * So hopefully returning here will make it fail if the api
+ * changes to something different than currently expected.
+ */
+ remove = nhg_connected_tree_del(head, remove);
+
+ /* If the entry was sucessfully removed, free the 'connected` struct */
+ if (remove) {
+ removed_nhe = remove->nhe;
nhg_connected_free(remove);
+ return removed_nhe;
+ }
+
+ return NULL;
}
-void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
- struct nhg_hash_entry *depend)
+/* Assuming UNIQUE RB tree. If this changes, assumptions here about
+ * insertion need to change.
+ */
+struct nhg_hash_entry *
+nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *depend)
{
struct nhg_connected *new = NULL;
new = nhg_connected_new(depend);
- if (new)
- nhg_connected_tree_add(head, new);
+ /* On success, NULL will be returned from the
+ * RB code.
+ */
+ if (new && (nhg_connected_tree_add(head, new) == NULL))
+ return NULL;
+
+ /* If it wasn't successful, it must be a duplicate. We enforce the
+ * unique property for the `nhg_connected` tree.
+ */
+ nhg_connected_free(new);
+
+ return depend;
}
static void
struct interface *ifp = NULL;
ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex,
- nhe->vrf_id);
+ nhe->nhg->nexthop->vrf_id);
if (ifp)
zebra_nhg_set_if(nhe, ifp);
else
flog_err(
EC_ZEBRA_IF_LOOKUP_FAILED,
"Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
- nhe->nhg->nexthop->ifindex, nhe->vrf_id,
- nhe->id);
+ nhe->nhg->nexthop->ifindex,
+ nhe->nhg->nexthop->vrf_id, nhe->id);
}
}
resolved_ng.nexthop = nh;
depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
- depends_add(nhg_depends, depend);
+
+ if (depend)
+ depends_add(nhg_depends, depend);
}
static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
lookup.type = type ? type : ZEBRA_ROUTE_NHG;
lookup.nhg = nhg;
+ lookup.vrf_id = vrf_id;
if (lookup.nhg->nexthop->next) {
/* Groups can have all vrfs and AF's in them */
lookup.afi = AFI_UNSPEC;
- lookup.vrf_id = VRF_DEFAULT;
} else {
switch (lookup.nhg->nexthop->type) {
case (NEXTHOP_TYPE_IFINDEX):
lookup.afi = AFI_IP6;
break;
}
-
- lookup.vrf_id = vrf_id;
}
if (id)
{
struct nhg_hash_entry *nhe = NULL;
struct nexthop_group nhg = {};
+ vrf_id_t vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nh->vrf_id;
nexthop_group_add_sorted(&nhg, nh);
- zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, type);
+ zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type);
return nhe;
}
done:
XFREE(MTYPE_NHG_CTX, *ctx);
- *ctx = NULL;
}
static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
}
/* Kernel-side, received delete message */
-int zebra_nhg_kernel_del(uint32_t id)
+int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
{
struct nhg_ctx *ctx = NULL;
- ctx = nhg_ctx_init(id, NULL, NULL, 0, 0, 0, 0);
+ ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0);
nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
static void depends_add(struct nhg_connected_tree_head *head,
struct nhg_hash_entry *depend)
{
- nhg_connected_tree_add_nhe(head, depend);
- zebra_nhg_increment_ref(depend);
+ /* If NULL is returned, it was successfully added and
+ * needs to have its refcnt incremented.
+ *
+ * Else the NHE is already present in the tree and doesn't
+ * need to increment the refcnt.
+ */
+ if (nhg_connected_tree_add_nhe(head, depend) == NULL)
+ zebra_nhg_increment_ref(depend);
}
static struct nhg_hash_entry *
zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
{
struct nhg_hash_entry *nhe = NULL;
+ vrf_id_t vrf_id;
+
+ /*
+ * CLANG SA is complaining that nexthop may be NULL
+ * Make it happy but this is ridonc
+ */
+ assert(nhg->nexthop);
+ vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
if (!(nhg && nhg->nexthop)) {
flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
return NULL;
}
- zebra_nhg_find(&nhe, id, nhg, NULL, nhg->nexthop->vrf_id, rt_afi, 0);
+ zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
return nhe;
}
* 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)
{
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;
+}
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.
vrf_id_t vrf_id, afi_t afi, int type,
int startup);
/* Del via kernel */
-extern int zebra_nhg_kernel_del(uint32_t id);
+extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
/* Find via route creation */
extern struct nhg_hash_entry *
/* 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__ */
nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head);
extern struct nhg_connected *
nhg_connected_tree_root(struct nhg_connected_tree_head *head);
-extern void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
- struct nhg_hash_entry *nhe);
-extern void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
- struct nhg_hash_entry *nhe);
+
+/* I realize _add/_del returns are backwords.
+ *
+ * Currently the list APIs are not standardized for what happens in
+ * the _del() function when the item isn't present.
+ *
+ * We are choosing to return NULL if not found in the _del case for now.
+ */
+
+/* Delete NHE from the tree. On success, return the NHE, otherwise NULL. */
+extern struct nhg_hash_entry *
+nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *nhe);
+/* ADD NHE to the tree. On success, return NULL, otherwise return the NHE. */
+extern struct nhg_hash_entry *
+nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *nhe);
#endif /* __ZEBRA_NHG_PRIVATE_H__ */
int *sock = data;
if (ipset->sock == *sock) {
- hook_call(zebra_pbr_ipset_update, 0, ipset);
- hash_release(zrouter.ipset_hash, ipset);
+ if (hash_release(zrouter.ipset_hash, ipset))
+ zebra_pbr_ipset_free(ipset);
+ else
+ hook_call(zebra_pbr_ipset_update, 0, ipset);
}
}
int *sock = data;
if (ipset->sock == *sock) {
- hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
- hash_release(zrouter.ipset_entry_hash, ipset);
+ if (hash_release(zrouter.ipset_entry_hash, ipset))
+ zebra_pbr_ipset_entry_free(ipset);
+ else
+ hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
}
}
int *sock = data;
if (iptable->sock == *sock) {
- hook_call(zebra_pbr_iptable_update, 0, iptable);
- hash_release(zrouter.iptable_hash, iptable);
+ if (hash_release(zrouter.iptable_hash, iptable))
+ zebra_pbr_iptable_free(iptable);
+ else
+ hook_call(zebra_pbr_iptable_update, 0, iptable);
}
}
static void rib_update_ctx_fini(struct rib_update_ctx **ctx)
{
XFREE(MTYPE_RIB_UPDATE_CTX, *ctx);
-
- *ctx = NULL;
}
static int rib_update_handler(struct thread *thread)
/* 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 */
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");
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);
+
+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;
- list_delete(&list);
+ hash_walk(zrouter.nhgs_id, nhe_show_walker, &ctx);
}
static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp)
DEFPY (show_nexthop_group,
show_nexthop_group_cmd,
- "show nexthop-group rib <(0-4294967295)$id|[<ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
+ "show nexthop-group rib <(0-4294967295)$id|[singleton <ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
SHOW_STR
"Show Nexthop Groups\n"
"RIB information\n"
"Nexthop Group ID\n"
+ "Show Singleton Nexthop-Groups\n"
IP_STR
IP6_STR
VRF_FULL_CMD_HELP_STR)
{
struct zebra_vrf *zvrf = NULL;
- afi_t afi = 0;
+ afi_t afi = AFI_UNSPEC;
if (id)
return show_nexthop_group_id_cmd_helper(vty, id);
else if (v6)
afi = AFI_IP6;
+ if (vrf_is_backend_netns() && (vrf_name || vrf_all)) {
+ vty_out(vty, "VRF subcommand does not make any sense in l3mdev based vrf's");
+ return CMD_WARNING;
+ }
+
if (vrf_all) {
struct vrf *vrf;
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;
}
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",
/* 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;
}
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);
vtep_ip = n->r_vtep_ip;
/* Mark appropriately */
UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
- n->r_vtep_ip.s_addr = 0;
+ n->r_vtep_ip.s_addr = INADDR_ANY;
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
n->ifindex = ifp->ifindex;
}
* 2. the XG entry is used by pimd to setup the
* vxlan-termination-mroute
*/
- if (sg->src.s_addr) {
+ if (sg->src.s_addr != INADDR_ANY) {
memset(&sip, 0, sizeof(sip));
parent = zebra_vxlan_sg_do_ref(zvrf, sip, sg->grp);
if (!parent)
/* On SG entry deletion remove the reference to its parent XG
* entry
*/
- if (vxlan_sg->sg.src.s_addr) {
+ if (vxlan_sg->sg.src.s_addr != INADDR_ANY) {
memset(&sip, 0, sizeof(sip));
zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp);
}
{
struct zebra_vrf *zvrf;
- if (!local_vtep_ip.s_addr || !mcast_grp.s_addr)
+ if (local_vtep_ip.s_addr == INADDR_ANY
+ || mcast_grp.s_addr == INADDR_ANY)
return;
zvrf = vrf_info_lookup(VRF_DEFAULT);
{
struct zebra_vrf *zvrf;
- if (!local_vtep_ip.s_addr || !mcast_grp.s_addr)
+ if (local_vtep_ip.s_addr == INADDR_ANY
+ || mcast_grp.s_addr == INADDR_ANY)
return;
zvrf = vrf_info_lookup(VRF_DEFAULT);
*/
static void zserv_client_free(struct zserv *client)
{
+ if (client == NULL)
+ return;
+
hook_call(zserv_client_close, client);
/* Close file descriptor. */
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;
}
}
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)
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);
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)
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;
}
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;
}
{
/* Client list init. */
zrouter.client_list = list_new();
+ zrouter.stale_client_list = list_new();
/* Misc init. */
zsock = -1;
#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 */
_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 \
*/
extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance);
-
/*
* Close a client.
*
*/
extern void zserv_close_client(struct zserv *client);
-
/*
* Log a ZAPI message hexdump.
*
/* 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