AM_CPPFLAGS += -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/lib \
-I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/lib
-VERSION_TYPE := $(shell if echo $(VERSION) | grep -q '^[0-9\.]*$$'; then echo RELEASE ; else echo DEV ; fi)
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE) -DVERSION_TYPE_$(VERSION_TYPE)
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE)
LIBCAP = @LIBCAP@
EXTRA_DIST =
indent:
tools/indent.py `find sharpd bgpd eigrpd include isisd lib nhrpd ospf6d ospfd pimd qpb ripd vtysh zebra -name '*.[ch]' | grep -v include/linux`
+
+if HAVE_GCOV
+
+coverage: check
+ @ find . -name '*.o' -exec gcov {} \;
+
+yorn:
+ @ echo "OK to upload coverage to https://coverage.io [y/N]:"
+ @ read yn; test "$$yn" = "y"
+
+upload-check-coverage:
+ @ if [ "x${COMMIT}" = "x" ]; then echo "COMMIT required"; exit 1; fi
+ @ if [ "x${TOKEN}" = "x" ]; then echo "TOKEN required"; exit 1; fi
+ curl -s https://codecov.io/bash | bash -s - -C ${COMMIT} -t ${TOKEN}
+
+force-check-coverage: coverage upload-check-coverage
+
+check-coverage: coverage yorn upload-check-coverage
+
+endif
* (only one hop back to ultimate parent for vrf-vpn-vrf scheme).
* Using a loop here supports more complex intra-bgp import-export
* schemes that could be implemented in the future.
- *
+ *
*/
for (bi_ultimate = source_bi;
bi_ultimate->extra && bi_ultimate->extra->parent;
struct bgp_node *prn;
safi_t safi = SAFI_MPLS_VPN;
- if (!bgp_vpn)
- return;
+ assert(bgp_vpn);
/*
* Walk vpn table
}
return VRF_UNKNOWN;
}
+
+/*
+ * The purpose of this function is to process leaks that were deferred
+ * from earlier per-vrf configuration due to not-yet-existing default
+ * vrf, in other words, configuration such as:
+ *
+ * router bgp MMM vrf FOO
+ * address-family ipv4 unicast
+ * rd vpn export 1:1
+ * exit-address-family
+ *
+ * router bgp NNN
+ * ...
+ *
+ * This function gets called when the default instance ("router bgp NNN")
+ * is created.
+ */
+void vpn_leak_postchange_all(void)
+{
+ struct listnode *next;
+ struct bgp *bgp;
+ struct bgp *bgp_default = bgp_get_default();
+
+ assert(bgp_default);
+
+ /* First, do any exporting from VRFs to the single VPN RIB */
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) {
+
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ vpn_leak_postchange(
+ BGP_VPN_POLICY_DIR_TOVPN,
+ AFI_IP,
+ bgp_default,
+ bgp);
+
+ vpn_leak_postchange(
+ BGP_VPN_POLICY_DIR_TOVPN,
+ AFI_IP6,
+ bgp_default,
+ bgp);
+ }
+
+ /* Now, do any importing to VRFs from the single VPN RIB */
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) {
+
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ vpn_leak_postchange(
+ BGP_VPN_POLICY_DIR_FROMVPN,
+ AFI_IP,
+ bgp_default,
+ bgp);
+
+ vpn_leak_postchange(
+ BGP_VPN_POLICY_DIR_FROMVPN,
+ AFI_IP6,
+ bgp_default,
+ bgp);
+ }
+}
afi_t afi, struct bgp *bgp_vpn,
struct bgp *bgp_vrf)
{
+ /* Detect when default bgp instance is not (yet) defined by config */
+ if (!bgp_vpn)
+ return;
+
if ((direction == BGP_VPN_POLICY_DIR_FROMVPN) &&
vpn_leak_from_vpn_active(bgp_vrf, afi, NULL)) {
afi_t afi, struct bgp *bgp_vpn,
struct bgp *bgp_vrf)
{
+ /* Detect when default bgp instance is not (yet) defined by config */
+ if (!bgp_vpn)
+ return;
+
if (direction == BGP_VPN_POLICY_DIR_FROMVPN)
vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi);
if (direction == BGP_VPN_POLICY_DIR_TOVPN) {
extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey);
+extern void vpn_leak_postchange_all(void);
+
#endif /* _QUAGGA_BGP_MPLSVPN_H */
afi_t afi, safi_t safi, enum bgp_show_type type);
static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
- safi_t safi);
+ safi_t safi, uint8_t use_json);
static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
|prefix-list WORD\
|filter-list WORD\
|statistics\
- |community <AA:NN|local-AS|no-advertise|no-export|graceful-shutdown> [exact-match]\
|community-list <(1-500)|WORD> [exact-match]\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes\
"Display routes conforming to the filter-list\n"
"Regular expression access list name\n"
"BGP RIB advertisement statistics\n"
- "Display routes matching the communities\n"
- COMMUNITY_AANN_STR
- "Do not send outside local AS (well-known community)\n"
- "Do not advertise to any peer (well-known community)\n"
- "Do not export to next AS (well-known community)\n"
- "Graceful shutdown (well-known community)\n"
- "Exact match of the communities\n"
"Display routes matching the community-list\n"
"community-list number\n"
"community-list name\n"
int exact_match = 0;
struct bgp *bgp = NULL;
int idx = 0;
- int idx_community_type = 0;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp);
return bgp_show_route_map(vty, bgp, argv[idx + 1]->arg, afi,
safi, bgp_show_type_route_map);
- if (argv_find(argv, argc, "community", &idx)) {
- /* show a specific community */
- if (argv_find(argv, argc, "local-AS", &idx_community_type)
- || argv_find(argv, argc, "no-advertise",
- &idx_community_type)
- || argv_find(argv, argc, "no-export", &idx_community_type)
- || argv_find(argv, argc, "graceful-shutdown",
- &idx_community_type)
- || argv_find(argv, argc, "AA:NN", &idx_community_type)) {
-
- if (argv_find(argv, argc, "exact-match", &idx))
- exact_match = 1;
- return bgp_show_community(vty, bgp,
- argv[idx_community_type]->arg,
- exact_match, afi, safi);
- }
- }
-
if (argv_find(argv, argc, "community-list", &idx)) {
const char *clist_number_or_name = argv[++idx]->arg;
if (++idx < argc && strmatch(argv[idx]->text, "exact-match"))
[<\
cidr-only\
|dampening <flap-statistics|dampened-paths>\
- |community \
+ |community [<AA:NN|local-AS|no-advertise|no-export|graceful-shutdown>] [exact-match]\
>] [json]",
SHOW_STR
IP_STR
"Display flap statistics of routes\n"
"Display paths suppressed due to dampening\n"
"Display routes matching the communities\n"
+ COMMUNITY_AANN_STR
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Graceful shutdown (well-known community)\n"
+ "Exact match of the communities\n"
JSON_STR)
{
afi_t afi = AFI_IP6;
enum bgp_show_type sh_type = bgp_show_type_normal;
struct bgp *bgp = NULL;
int idx = 0;
+ int idx_community_type = 0;
+ int exact_match = 0;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp);
}
if (argv_find(argv, argc, "community", &idx)) {
- /* show all communities */
- return bgp_show(vty, bgp, afi, safi,
- bgp_show_type_community_all, NULL, uj);
+
+ /* show a specific community */
+ if (argv_find(argv, argc, "local-AS", &idx_community_type) ||
+ argv_find(argv, argc, "no-advertise",
+ &idx_community_type) ||
+ argv_find(argv, argc, "no-export",
+ &idx_community_type) ||
+ argv_find(argv, argc, "graceful-shutdown",
+ &idx_community_type) ||
+ argv_find(argv, argc, "AA:NN", &idx_community_type)) {
+ if (argv_find(argv, argc, "exact-match", &idx))
+ exact_match = 1;
+
+ return (bgp_show_community(vty, bgp,
+ argv[idx_community_type]->arg,
+ exact_match, afi, safi, uj));
+ } else {
+
+ /* show all communities */
+ return (bgp_show(vty, bgp, afi, safi,
+ bgp_show_type_community_all, NULL,
+ uj));
+ }
}
+
return bgp_show(vty, bgp, afi, safi, sh_type, NULL, uj);
}
static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
- safi_t safi)
+ safi_t safi, uint8_t use_json)
{
struct community *com;
int ret = 0;
ret = bgp_show(vty, bgp, afi, safi,
(exact ? bgp_show_type_community_exact
: bgp_show_type_community),
- com, 0);
+ com, use_json);
community_free(com);
return ret;
bgp_info->attr->nexthop = *rins->address;
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_IPV4_NHOP_CHANGED);
+ /* case for MP-BGP : MPLS VPN */
+ bgp_info->attr->mp_nexthop_global_in = *rins->address;
+ bgp_info->attr->mp_nexthop_len = sizeof(*rins->address);
}
}
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_route.h"
+#include "lib/thread.h"
#include "rtrlib/rtrlib.h"
#include "rtrlib/rtr_mgr.h"
#include "rtrlib/lib/ip.h"
static route_map_result_t route_match(void *rule, struct prefix *prefix,
route_map_object_t type, void *object);
static void *route_match_compile(const char *arg);
+static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi,
+ safi_t safi);
static struct rtr_mgr_config *rtr_config;
static struct list *cache_list;
static int rtr_is_running;
+static int rtr_is_stopping;
+static int rtr_is_starting;
static int rpki_debug;
static unsigned int polling_period;
static unsigned int expire_interval;
static unsigned int retry_interval;
static unsigned int timeout;
static unsigned int initial_synchronisation_timeout;
+static int rpki_sync_socket_rtr;
+static int rpki_sync_socket_bgpd;
static struct cmd_node rpki_node = {RPKI_NODE, "%s(config-rpki)# ", 1};
static struct route_map_rule_cmd route_match_rpki_cmd = {
static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
struct prefix *prefix);
+static void ipv6_addr_to_network_byte_order(const uint32_t *src, uint32_t *dest)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ dest[i] = htonl(src[i]);
+}
+
static void ipv6_addr_to_host_byte_order(const uint32_t *src, uint32_t *dest)
{
int i;
return rtr_is_running;
}
+static struct prefix *pfx_record_to_prefix(struct pfx_record *record)
+{
+ struct prefix *prefix = prefix_new();
+
+ prefix->prefixlen = record->min_len;
+
+ if (record->prefix.ver == LRTR_IPV4) {
+ prefix->family = AF_INET;
+ prefix->u.prefix4.s_addr = htonl(record->prefix.u.addr4.addr);
+ } else {
+ prefix->family = AF_INET6;
+ ipv6_addr_to_network_byte_order(record->prefix.u.addr6.addr,
+ prefix->u.prefix6.s6_addr32);
+ }
+
+ return prefix;
+}
+
+static int bgpd_sync_callback(struct thread *thread)
+{
+ struct bgp *bgp;
+ struct listnode *node;
+ struct prefix *prefix;
+ struct pfx_record rec;
+
+ thread_add_read(bm->master, bgpd_sync_callback, NULL,
+ rpki_sync_socket_bgpd, NULL);
+ int retval =
+ read(rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record));
+ if (retval != sizeof(struct pfx_record)) {
+ RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd");
+ return retval;
+ }
+ prefix = pfx_record_to_prefix(&rec);
+
+ afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
+
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
+ safi_t safi;
+
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ if (!bgp->rib[afi][safi])
+ continue;
+
+ struct list *matches = list_new();
+
+ matches->del = (void (*)(void *))bgp_unlock_node;
+
+ bgp_table_range_lookup(bgp->rib[afi][safi], prefix,
+ rec.max_len, matches);
+
+
+ struct bgp_node *bgp_node;
+
+ for (ALL_LIST_ELEMENTS_RO(matches, node, bgp_node))
+ revalidate_bgp_node(bgp_node, afi, safi);
+
+ list_delete_and_null(&matches);
+ }
+ }
+
+ prefix_free(prefix);
+ return 0;
+}
+
+static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi,
+ safi_t safi)
+{
+ struct bgp_adj_in *ain;
+
+ for (ain = bgp_node->adj_in; ain; ain = ain->next) {
+ int ret;
+ struct bgp_info *bgp_info = bgp_node->info;
+ mpls_label_t *label = NULL;
+ uint32_t num_labels = 0;
+
+ if (bgp_info && bgp_info->extra) {
+ label = bgp_info->extra->label;
+ num_labels = bgp_info->extra->num_labels;
+ }
+ ret = bgp_update(ain->peer, &bgp_node->p, 0, ain->attr, afi,
+ safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
+ label, num_labels, 1, NULL);
+
+ if (ret < 0) {
+ bgp_unlock_node(bgp_node);
+ return;
+ }
+ }
+}
+
+static void revalidate_all_routes(void)
+{
+ struct bgp *bgp;
+ struct listnode *node;
+ struct bgp_node *bgp_node;
+
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
+ for (size_t i = 0; i < 2; i++) {
+ safi_t safi;
+ afi_t afi = (i == 0) ? AFI_IP : AFI_IP6;
+
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ if (!bgp->rib[afi][safi])
+ continue;
+
+ for (bgp_node =
+ bgp_table_top(bgp->rib[afi][safi]);
+ bgp_node;
+ bgp_node = bgp_route_next(bgp_node)) {
+ if (bgp_node->info != NULL) {
+ revalidate_bgp_node(bgp_node,
+ afi, safi);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)),
+ const struct pfx_record rec,
+ const bool added __attribute__((unused)))
+{
+ if (rtr_is_stopping || rtr_is_starting)
+ return;
+
+ int retval =
+ write(rpki_sync_socket_rtr, &rec, sizeof(struct pfx_record));
+ if (retval != sizeof(struct pfx_record))
+ RPKI_DEBUG("Could not write to rpki_sync_socket_rtr");
+}
+
+static void rpki_init_sync_socket(void)
+{
+ int fds[2];
+
+ RPKI_DEBUG("initializing sync socket");
+ if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fds) != 0) {
+ RPKI_DEBUG("Could not open rpki sync socket");
+ return;
+ }
+ rpki_sync_socket_rtr = fds[0];
+ rpki_sync_socket_bgpd = fds[1];
+ thread_add_read(bm->master, bgpd_sync_callback, NULL,
+ rpki_sync_socket_bgpd, NULL);
+}
+
static int bgp_rpki_init(struct thread_master *master)
{
rpki_debug = 0;
rtr_is_running = 0;
+ rtr_is_stopping = 0;
cache_list = list_new();
cache_list->del = (void (*)(void *)) & free_cache;
initial_synchronisation_timeout =
INITIAL_SYNCHRONISATION_TIMEOUT_DEFAULT;
install_cli_commands();
+ rpki_init_sync_socket();
return 0;
}
stop();
list_delete_and_null(&cache_list);
+ close(rpki_sync_socket_rtr);
+ close(rpki_sync_socket_bgpd);
+
return 0;
}
unsigned int waiting_time = 0;
int ret;
+ rtr_is_stopping = 0;
+ rtr_is_starting = 1;
+
if (list_isempty(cache_list)) {
RPKI_DEBUG(
"No caches were found in config. Prefix validation is off.");
int groups_len = listcount(cache_list);
struct rtr_mgr_group *groups = get_groups();
+ RPKI_DEBUG("Polling period: %d", polling_period);
ret = rtr_mgr_init(&rtr_config, groups, groups_len, polling_period,
- expire_interval, retry_interval, NULL, NULL, NULL,
- NULL);
+ expire_interval, retry_interval,
+ rpki_update_cb_sync_rtr, NULL, NULL, NULL);
if (ret == RTR_ERROR) {
RPKI_DEBUG("Init rtr_mgr failed.");
return ERROR;
}
if (rtr_mgr_conf_in_sync(rtr_config)) {
RPKI_DEBUG("Got synchronisation with at least one RPKI cache!");
+ RPKI_DEBUG("Forcing revalidation.");
+ rtr_is_starting = 0;
+ revalidate_all_routes();
} else {
RPKI_DEBUG(
"Timeout expired! Proceeding without RPKI validation data.");
+ rtr_is_starting = 0;
}
XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups);
static void stop(void)
{
+ rtr_is_stopping = 1;
if (rtr_is_running) {
rtr_mgr_stop(rtr_config);
rtr_mgr_free(rtr_config);
return rt;
}
+
+static struct bgp_node *
+bgp_route_next_until_maxlen(struct bgp_node *node, const struct bgp_node *limit,
+ const uint8_t maxlen)
+{
+ if (node->l_left && node->p.prefixlen < maxlen
+ && node->l_left->p.prefixlen <= maxlen) {
+ return bgp_node_from_rnode(node->l_left);
+ }
+ if (node->l_right && node->p.prefixlen < maxlen
+ && node->l_right->p.prefixlen <= maxlen) {
+ return bgp_node_from_rnode(node->l_right);
+ }
+
+ while (node->parent && node != limit) {
+ if (bgp_node_from_rnode(node->parent->l_left) == node
+ && node->parent->l_right) {
+ return bgp_node_from_rnode(node->parent->l_right);
+ }
+ node = bgp_node_from_rnode(node->parent);
+ }
+ return NULL;
+}
+
+void bgp_table_range_lookup(const struct bgp_table *table, struct prefix *p,
+ uint8_t maxlen, struct list *matches)
+{
+ struct bgp_node *node = bgp_node_from_rnode(table->route_table->top);
+ struct bgp_node *matched = NULL;
+
+ if (node == NULL)
+ return;
+
+ while (node && node->p.prefixlen <= p->prefixlen
+ && prefix_match(&node->p, p)) {
+ if (node->info && node->p.prefixlen == p->prefixlen) {
+ matched = node;
+ break;
+ }
+ node = bgp_node_from_rnode(node->link[prefix_bit(
+ &p->u.prefix, node->p.prefixlen)]);
+ }
+
+ if ((matched == NULL && node->p.prefixlen > maxlen) || !node->parent)
+ return;
+ else if (matched == NULL)
+ matched = node = bgp_node_from_rnode(node->parent);
+
+ if (matched->info) {
+ bgp_lock_node(matched);
+ listnode_add(matches, matched);
+ }
+
+ while ((node = bgp_route_next_until_maxlen(node, matched, maxlen))) {
+ if (prefix_match(p, &node->p)) {
+ if (node->info) {
+ bgp_lock_node(node);
+ listnode_add(matches, node);
+ }
+ }
+ }
+}
#include "mpls.h"
#include "table.h"
#include "queue.h"
+#include "linklist.h"
struct bgp_table {
/* table belongs to this instance */
return table->version;
}
+void bgp_table_range_lookup(const struct bgp_table *table, struct prefix *p,
+ uint8_t maxlen, struct list *matches);
+
#endif /* _QUAGGA_BGP_TABLE_H */
#endif
/* BGP global configuration. */
-#if defined(VERSION_TYPE_DEV) && (CONFDATE > 20190601)
+#if (CONFDATE > 20190601)
CPP_NOTICE("bgpd: time to remove deprecated bgp multiple-instance")
CPP_NOTICE("This includes BGP_OPT_MULTIPLE_INSTANCE")
#endif
return CMD_SUCCESS;
}
-#if defined(VERSION_TYPE_DEV) && (CONFDATE > 20190601)
+#if (CONFDATE > 20190601)
CPP_NOTICE("bgpd: time to remove deprecated cli bgp config-type cisco")
CPP_NOTICE("This includes BGP_OPT_CISCO_CONFIG")
#endif
return CMD_WARNING_CONFIG_FAILED;
}
+ /*
+ * If we just instantiated the default instance, complete
+ * any pending VRF-VPN leaking that was configured via
+ * earlier "router bgp X vrf FOO" blocks.
+ */
+ if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ vpn_leak_postchange_all();
+
/* Pending: handle when user tries to change a view to vrf n vv.
*/
}
}
/* "bgp enforce-first-as" configuration. */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180517
+#if CONFDATE > 20180517
CPP_NOTICE("bgpd: remove deprecated '[no] bgp enforce-first-as' commands")
#endif
json_object_string_add(
json_neigh, "remoteRouterId",
inet_ntop(AF_INET, &p->remote_id, buf1, sizeof(buf1)));
+ json_object_string_add(
+ json_neigh, "localRouterId",
+ inet_ntop(AF_INET, &bgp->router_id, buf1,
+ sizeof(buf1)));
/* Confederation */
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
uptime -= p->uptime;
epoch_tbuf = time(NULL) - uptime;
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20200101
+#if CONFDATE > 20200101
CPP_NOTICE(
"bgpTimerUp should be deprecated and can be removed now");
#endif
}
/* clang-format off */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180517
+#if CONFDATE > 20180517
CPP_NOTICE("bgpd: remove 'bgp enforce-first-as' config migration from bgp_config_write")
#endif
/* clang-format on */
])
dnl if the user has specified any CFLAGS, override our settings
-if test "x${enable_dev_build}" = "xyes"; then
+if test "x${enable_gcov}" = "xyes"; then
+ if test "z$orig_cflags" = "z"; then
+ AC_C_FLAG([-coverage])
+ AC_C_FLAG([-O0])
+ fi
+
+ LDFLAGS="${LDFLAGS} -lgcov"
+elif test "x${enable_dev_build}" = "xyes"; then
AC_DEFINE(DEV_BUILD,,Build for development)
if test "z$orig_cflags" = "z"; then
AC_C_FLAG([-g3])
AS_HELP_STRING([--enable-clippy-only], [Only build clippy]))
AC_ARG_ENABLE([numeric_version],
AS_HELP_STRING([--enable-numeric-version], [Only numeric digits allowed in version (for Alpine)]))
+AC_ARG_ENABLE([gcov],
+ AS_HELP_STRING([--enable-gcov], [Add code coverage information]))
AS_IF([test "${enable_clippy_only}" != "yes"], [
AC_CHECK_HEADERS(json-c/json.h)
AC_DEFINE_UNQUOTED(VTYSH_PAGER, "$VTYSH_PAGER", [What pager to use])
+dnl --------------------
+dnl Enable code coverage
+dnl --------------------
+AM_CONDITIONAL([HAVE_GCOV],[test '!' "$enable_gcov" = no])
+
dnl ------------------------------------
dnl Alpine only accepts numeric versions
dnl ------------------------------------
dnl ----------
dnl configure date
dnl ----------
-CONFDATE=`date '+%Y%m%d'`
+dev_version=`echo $VERSION | grep dev`
+#don't expire deprecated code in non 'dev' branch
+if test "${dev_version}" = ""; then
+ CONFDATE=0
+else
+ CONFDATE=`date '+%Y%m%d'`
+fi
AC_SUBST(CONFDATE)
dnl ------------------------------
developer/ldpd-basic-test-setup.md \
developer/library.rst \
developer/Makefile.in \
+ developer/maintainer-release-build.rst \
developer/memtypes.rst \
developer/modules.rst \
developer/next-hop-tracking.rst \
--- /dev/null
+Release Build Procedure for FRR maintainers
+=========================================================
+
+1. Rename branch (if needed)
+
+.. code-block:: shell
+
+ git clone git@github.com:FRRouting/frr.git
+ cd frr
+ git checkout dev/5.0
+ git push origin :refs/heads/dev/5.0
+ git push origin dev/5.0:refs/heads/stable/5.0
+
+2. Checkout the new stable branch:
+
+.. code-block:: shell
+
+ git checkout stable/5.0
+
+3. Update Changelog for RedHat Package:
+
+ Edit :file:`redhat/frr.spec.in` and look for the ``%changelog`` section:
+
+ - Change last (top of list) entry from ``%{version}`` to previous fixed
+ version number, i.e.::
+
+ * Tue Nov 7 2017 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+
+ to::
+
+ * Tue Nov 7 2017 Martin Winter <mwinter@opensourcerouting.org> - 3.0.2
+
+ - Add new entry to the top of the list with ``%{version}`` tag and changelog
+ for version.
+ Make sure to watch the format, i.e. the day is always 2 characters, with
+ the 1st character being a space if the day is one digit.
+
+4. Update Changelog for Debian Packages:
+
+ Edit :file:`debianpkg/changelog.in`:
+
+ - Change last (top of list) entry from ``@VERSION@`` to previous fixed
+ version number, i.e.::
+
+ frr (@VERSION@) RELEASED; urgency=medium
+
+ to::
+
+ frr (3.0.2) RELEASED; urgency=medium
+
+ - Add a new entry to the top of the list with a ``@VERSION@`` tag and
+ changelog for version.
+
+5. Change main version number:
+
+ - Edit :file:`configure.ac` and change version in the ``AC_INIT`` command
+ - Create a new entry with the version as ``%{version}`` tag
+
+6. Test building at least a Red Hat and Ubuntu package (or create a PR to have
+ the CI system test them)
+
+7. Commit the changes, adding the changelog to the commit message
+
+8. Create a git tag for the version:
+
+ .. code-block:: shell
+
+ git tag -a frr-5.0 -m "FRRouting Release 5.0"
+
+9. Push the commit and tag(s) and watch for errors on CI:
+
+ .. code-block:: shell
+
+ git push
+ git push --tags
+
+10. Kick off the Release build plan on the CI system for the correct release
+
+11. Send a Release Announcement with changes to
+ ``announce@lists.frrouting.org``
+
+12. Kick off the Snapcraft build plan for the correct release
+
+13. After CI plans succeed, release on GitHub by going to
+ https://github.com/FRRouting/frr/releases and selecting "Draft a new
+ release".
+
+14. Deploy Snapcraft release (after CI system finishes the tests for snapcraft
+ testplan)
There's also the ``frr_module`` symbol in modules, pretty much a
standard entry point for loadable modules.
+Command line parameters
+-----------------------
+
+Command line parameters can be passed directly to a module by appending a
+colon to the module name when loading it, e.g. ``-M mymodule:myparameter``.
+The text after the colon will be accessible in the module's code through
+``THIS_MODULE->load_args``. For example, see how the format parameter is
+configured in the ``zfpm_init()`` function inside ``zebra_fpm.c``.
+
Hooks
-----
utilized but pure ReST is preferred where possible. See
:ref:`documentation`.
+Code Reviews
+============
+
+Code quality is paramount for any large program. Consequently we require
+reviews of all submitted patches by at least one person other than the
+submitter before the patch is merged.
+
+Because of the nature of the software, FRR's maintainer list (i.e. those with
+commit permissions) tends to contain employees / members of various
+organizations. In order to prevent conflicts of interest, we use an honor
+system in which submissions from an individual representing one company should
+be merged by someone unaffiliated with that company.
+
+Guidelines for code review
+""""""""""""""""""""""""""
+
+- As a rule of thumb, the depth of the review should be proportional to the
+ scope and / or impact of the patch.
+
+- Anyone may review a patch.
+
+- When using GitHub reviews, marking "Approve" on a code review indicates
+ willingness to merge the PR.
+
+- For individuals with merge rights, marking "Changes requested" is equivalent
+ to a NAK.
+
+- For a PR you marked with "Changes requested", please respond to updates in a
+ timely manner to avoid impeding the flow of development.
+
+
Coding Practices & Style
========================
.. code-block:: c
- #if defined(VERSION_TYPE_DEV) && CONFDATE > 20180403
+ #if CONFDATE > 20180403
CPP_NOTICE("Use of <XYZ> is deprecated, please use <ABC>")
#endif
neighbor 10.0.0.3 remote-as 4
neighbor 10.0.0.4 remote-as 5
-.. index:: show ip bgp view NAME
-.. clicmd:: show ip bgp view NAME
+.. index:: show [ip] bgp view NAME
+.. clicmd:: show [ip] bgp view NAME
Display the routing table of BGP view ``NAME``.
Displaying BGP Information
==========================
+The following four commands display the IPv6 and IPv4 routing tables, depending
+on whether or not the ``ip`` keyword is used.
+Actually, :clicmd:`show ip bgp` command was used on older `Quagga` routing
+daemon project, while :clicmd:`show bgp` command is the new format. The choice
+has been done to keep old format with IPv4 routing table, while new format
+displays IPv6 routing table.
+
.. index:: show ip bgp
.. clicmd:: show ip bgp
.. index:: show ip bgp A.B.C.D
.. clicmd:: show ip bgp A.B.C.D
-.. index:: show ip bgp X:X::X:X
-.. clicmd:: show ip bgp X:X::X:X
+.. index:: show bgp
+.. clicmd:: show bgp
+
+.. index:: show bgp X:X::X:X
+.. clicmd:: show bgp X:X::X:X
These commands display BGP routes. When no route is specified, the default
- is to display all IPv4 BGP routes.
+ is to display all BGP routes.
::
Total number of prefixes 1
-.. index:: show ip bgp regexp LINE
-.. clicmd:: show ip bgp regexp LINE
+Some other commands provide additional options for filtering the output.
+
+.. index:: show [ip] bgp regexp LINE
+.. clicmd:: show [ip] bgp regexp LINE
This command displays BGP routes using AS path regular expression
(:ref:`bgp-regular-expressions`).
-.. index:: show bgp <ipv4|ipv6> summary
-.. clicmd:: show bgp <ipv4|ipv6> summary
+.. index:: show [ip] bgp summary
+.. clicmd:: show [ip] bgp summary
Show a bgp peer summary for the specified address family.
-.. index:: show bgp <ipv4|ipv6> neighbor [PEER]
-.. clicmd:: show bgp <ipv4|ipv6> neighbor [PEER]
+The old command structure :clicmd:`show ip bgp` may be removed in the future
+and should no longer be used. In order to reach the other BGP routing tables
+other than the IPv6 routing table given by :clicmd:`show bgp`, the new command
+structure is extended with :clicmd:`show bgp [afi] [safi]`.
+
+.. index:: show bgp [afi] [safi]
+.. clicmd:: show bgp [afi] [safi]
+
+.. index:: show bgp <ipv4|ipv6> <unicast|multicast|vpn|labeled-unicast>
+.. clicmd:: show bgp <ipv4|ipv6> <unicast|multicast|vpn|labeled-unicast>
+
+ These commands display BGP routes for the specific routing table indicated by
+ the selected afi and the selected safi. If no afi and no safi value is given,
+ the command falls back to the default IPv6 routing table
+
+.. index:: show bgp [afi] [safi] summary
+.. clicmd:: show bgp [afi] [safi] summary
+
+ Show a bgp peer summary for the specified address family, and subsequent
+ address-family.
+
+.. index:: show bgp [afi] [safi] neighbor [PEER]
+.. clicmd:: show bgp [afi] [safi] neighbor [PEER]
- This command shows information on a specific BGP `peer`.
+ This command shows information on a specific BGP peer of the relevant
+ afi and safi selected.
-.. index:: show bgp <ipv4|ipv6> dampening dampened-paths
-.. clicmd:: show bgp <ipv4|ipv6> dampening dampened-paths
+.. index:: show bgp [afi] [safi] dampening dampened-paths
+.. clicmd:: show bgp [afi] [safi] dampening dampened-paths
- Display paths suppressed due to dampening.
+ Display paths suppressed due to dampening of the selected afi and safi
+ selected.
-.. index:: show bgp <ipv4|ipv6> dampening flap-statistics
-.. clicmd:: show bgp <ipv4|ipv6> dampening flap-statistics
+.. index:: show bgp [afi] [safi] dampening flap-statistics
+.. clicmd:: show bgp [afi] [safi] dampening flap-statistics
- Display flap statistics of routes.
+ Display flap statistics of routes of the selected afi and safi selected.
.. _bgp-display-routes-by-community:
This commands displays BGP routes that matches a regular
expression `line` (:ref:`bgp-regular-expressions`).
-.. index:: show ip bgp ipv4 vpn
-.. clicmd:: show ip bgp ipv4 vpn
+.. index:: show [ip] bgp ipv4 vpn
+.. clicmd:: show [ip] bgp ipv4 vpn
-.. index:: show ip bgp ipv6 vpn
-.. clicmd:: show ip bgp ipv6 vpn
+.. index:: show [ip] bgp ipv6 vpn
+.. clicmd:: show [ip] bgp ipv6 vpn
Print active IPV4 or IPV6 routes advertised via the VPN SAFI.
hardcoded arrays that FRR builds towards, so we need to know how big to
make these arrays at build time.
+.. option:: --enable-gcov
+
+ Code coverage reports from gcov require adjustments to the C and LD flags.
+ With this option, gcov instrumentation is added to the build and coverage
+ reports are created during execution. The check-coverage make target is
+ also created to ease report uploading to codecov.io. The upload requires
+ the COMMIT (git hash) and TOKEN (codecov upload token) environment variables
+ be set.
+
You may specify any combination of the above options to the configure
script. By default, the executables are placed in :file:`/usr/local/sbin`
and the configuration files in :file:`/usr/local/etc`. The :file:`/usr/local/`
- Route maps can be configured to match a specific RPKI validation state. This
allows the creation of local policies, which handle BGP routes based on the
outcome of the Prefix Origin Validation.
+- Updates from the RPKI cache servers are directly applied and path selection
+ is updated accordingly. (Soft reconfiguration **must** be enabled for this
+ to work).
.. _enabling-rpki:
.. _configuring-rpki-rtr-cache-servers:
+.. index:: daemons.conf
+
+ When first installing FRR with RPKI support from the pre-packaged binaries. Remember
+ to append '-M rpki' in the /etc/frr/daemons.conf file to the bgpd_options.
+
+ bgpd_options=" --daemon -A 127.0.0.1 -M rpki"
+ instead of the default setting
+ bgpd_options=" --daemon -A 127.0.0.1"
+
+
+ Else you will encounter an error when trying to enter RPKI configuration mode. Because
+ the rpki module is not loaded when the BGP daemon is initialized.
+
+ Examples of the error:
+
+ router(config)# debug rpki
+ % [BGP] Unknown command: debug rpki
+
+ router(config)# rpki
+ % [BGP] Unknown command: rpki
+
+ Note that the rpki commands will be available in vtysh when running 'find rpki'.
+ Even if the RPKI module is NOT loaded.
+ The RPKI commands will be unavailable if you try running the same command in the
+ cli specific to the BGP daemon.
+
Configuring RPKI/RTR Cache Servers
----------------------------------
--- /dev/null
+FROM alpine:3.7
+ARG commit
+ARG token
+ENV COMMIT=${commit}
+ENV TOKEN=${token}
+ADD . /src
+RUN cd /src && \
+ source alpine/APKBUILD.in && \
+ apk add --no-cache alpine-sdk $makedepends $checkdepends && \
+ ./bootstrap.sh && \
+ ./configure --enable-gcov
+ENTRYPOINT [ "/bin/sh", "-c", "cd /src && make && make -j 1 check-coverage" ]
thread_add_timer(master, isis_run_dr_l2, circuit,
2 * circuit->hello_interval[1],
&circuit->u.bc.t_run_dr[1]);
- } else {
+ } else if (circuit->circ_type == CIRCUIT_T_P2P) {
/* initializing the hello send threads
* for a ptp IF
*/
void isis_circuit_down(struct isis_circuit *circuit)
{
- if (circuit->state != C_STATE_UP)
- return;
-
/* Clear the flags for all the lsps of the circuit. */
isis_circuit_update_all_srmflags(circuit, 0);
}
/* send one gratuitous hello to spead up convergence */
- if (circuit->is_type & IS_LEVEL_1)
- send_hello(circuit, IS_LEVEL_1);
- if (circuit->is_type & IS_LEVEL_2)
- send_hello(circuit, IS_LEVEL_2);
+ if (circuit->state == C_STATE_UP) {
+ if (circuit->is_type & IS_LEVEL_1)
+ send_hello(circuit, IS_LEVEL_1);
+ if (circuit->is_type & IS_LEVEL_2)
+ send_hello(circuit, IS_LEVEL_2);
+ }
circuit->upadjcount[0] = 0;
circuit->upadjcount[1] = 0;
#else
#define CPP_WARN(text)
+#define CPP_NOTICE(text)
#endif
#endif /* _FRR_COMPILER_H */
access->remark = NULL;
}
- if (access->head == NULL && access->tail == NULL
- && access->remark == NULL)
+ if (access->head == NULL && access->tail == NULL)
access_list_delete(access);
return CMD_SUCCESS;
struct vrf *vrf;
struct interface if_tmp;
- if (vrf_id == VRF_UNKNOWN) {
- struct interface *ifp;
-
- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
- ifp = if_lookup_by_index(ifindex, vrf->vrf_id);
- if (ifp)
- return ifp;
- }
-
- return NULL;
- }
-
vrf = vrf_lookup_by_id(vrf_id);
if (!vrf)
return NULL;
* and remove list_delete_original and the list_delete #define
* Additionally remove list_free entirely
*/
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20181001
+#if CONFDATE > 20181001
CPP_NOTICE("list_delete without double pointer is deprecated, please fixup")
#endif
*args++ = '\0';
if (!strchr(name, '/')) {
- if (!handle && execname) {
+ if (execname) {
snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", dir,
execname, name);
handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
(nhop); \
(nhop) = nexthop_next(nhop)
+#define ALL_NEXTHOPS_PTR(head, nhop) \
+ (nhop) = ((head)->nexthop); \
+ (nhop); \
+ (nhop) = nexthop_next(nhop)
+
struct nexthop_hold {
char *nhvrf_name;
/* NB: read comments in code for refcounting before using! */
static struct route_node *srcdest_srcnode_get(struct route_node *rn,
- struct prefix_ipv6 *src_p)
+ const struct prefix_ipv6 *src_p)
{
struct srcdest_rnode *srn;
route_unlock_node(rn);
}
- return route_node_get(srn->src_table, (struct prefix *)src_p);
+ return route_node_get(srn->src_table, (const struct prefix *)src_p);
}
-static struct route_node *srcdest_srcnode_lookup(struct route_node *rn,
- struct prefix_ipv6 *src_p)
+static struct route_node *srcdest_srcnode_lookup(
+ struct route_node *rn,
+ const struct prefix_ipv6 *src_p)
{
struct srcdest_rnode *srn;
if (!srn->src_table)
return NULL;
- return route_node_lookup(srn->src_table, (struct prefix *)src_p);
+ return route_node_lookup(srn->src_table, (const struct prefix *)src_p);
}
/* ----- exported functions ----- */
}
struct route_node *srcdest_rnode_get(struct route_table *table,
- union prefixptr dst_pu,
- struct prefix_ipv6 *src_p)
+ union prefixconstptr dst_pu,
+ const struct prefix_ipv6 *src_p)
{
- struct prefix_ipv6 *dst_p = dst_pu.p6;
+ const struct prefix_ipv6 *dst_p = dst_pu.p6;
struct route_node *rn;
- rn = route_node_get(table, (struct prefix *)dst_p);
+ rn = route_node_get(table, (const struct prefix *)dst_p);
return srcdest_srcnode_get(rn, src_p);
}
struct route_node *srcdest_rnode_lookup(struct route_table *table,
- union prefixptr dst_pu,
- struct prefix_ipv6 *src_p)
+ union prefixconstptr dst_pu,
+ const struct prefix_ipv6 *src_p)
{
- struct prefix_ipv6 *dst_p = dst_pu.p6;
+ const struct prefix_ipv6 *dst_p = dst_pu.p6;
struct route_node *rn;
struct route_node *srn;
- rn = route_node_lookup_maynull(table, (struct prefix *)dst_p);
+ rn = route_node_lookup_maynull(table, (const struct prefix *)dst_p);
srn = srcdest_srcnode_lookup(rn, src_p);
if (rn != NULL && rn == srn && !rn->info) {
return srn;
}
-void srcdest_rnode_prefixes(struct route_node *rn, struct prefix **p,
- struct prefix **src_p)
+void srcdest_rnode_prefixes(struct route_node *rn, const struct prefix **p,
+ const struct prefix **src_p)
{
if (rnode_is_srcnode(rn)) {
struct route_node *dst_rn = rn->table->info;
const char *srcdest_rnode2str(struct route_node *rn, char *str, int size)
{
- struct prefix *dst_p, *src_p;
+ const struct prefix *dst_p, *src_p;
char dst_buf[PREFIX_STRLEN], src_buf[PREFIX_STRLEN];
srcdest_rnode_prefixes(rn, &dst_p, &src_p);
extern struct route_table *srcdest_table_init(void);
extern struct route_node *srcdest_rnode_get(struct route_table *table,
- union prefixptr dst_pu,
- struct prefix_ipv6 *src_p);
+ union prefixconstptr dst_pu,
+ const struct prefix_ipv6 *src_p);
extern struct route_node *srcdest_rnode_lookup(struct route_table *table,
- union prefixptr dst_pu,
- struct prefix_ipv6 *src_p);
-extern void srcdest_rnode_prefixes(struct route_node *rn, struct prefix **p,
- struct prefix **src_p);
+ union prefixconstptr dst_pu,
+ const struct prefix_ipv6 *src_p);
+extern void srcdest_rnode_prefixes(struct route_node *rn,
+ const struct prefix **p,
+ const struct prefix **src_p);
extern const char *srcdest_rnode2str(struct route_node *rn, char *str,
int size);
extern struct route_node *srcdest_route_next(struct route_node *rn);
#define STREAM_CONCAT_REMAIN(S1, S2, size) ((size) - (S1)->endp - (S2)->endp)
/* deprecated macros - do not use in new code */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20181128
+#if CONFDATE > 20181128
CPP_NOTICE("lib: time to remove deprecated stream.h macros")
#endif
#define STREAM_PNT(S) stream_pnt((S))
}
if (vrf->ns_ctxt != NULL) {
ns = (struct ns *)vrf->ns_ctxt;
- if (ns && 0 != strcmp(ns->name, pathname)) {
+ if (!strcmp(ns->name, pathname)) {
if (vty)
vty_out(vty,
"VRF %u already configured with NETNS %s\n",
ns->vrf_ctxt = (void *)vrf;
vrf->ns_ctxt = (void *)ns;
/* update VRF netns NAME */
- if (vrf)
- strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ);
+ strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ);
if (!ns_enable(ns, vrf_update_vrf_id)) {
if (vty)
* The usage of work_queue_free is being transitioned to pass
* in the double pointer to remove use after free's.
*/
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20190205
+#if CONFDATE > 20190205
CPP_NOTICE("work_queue_free without double pointer is deprecated, please fixup")
#endif
extern void work_queue_free_and_null(struct work_queue **);
extern struct zclient *zclient_new(struct thread_master *);
/* clang-format off */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20181101
+#if CONFDATE > 20181101
CPP_NOTICE("zclient_new_notify can take over or zclient_new now");
#endif
/* clang-format on */
extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
/* clang-format off */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180823
+#if CONFDATE > 20180823
CPP_NOTICE("zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now");
#endif
/* clang-format on */
return CMD_SUCCESS;
}
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180828
+#if CONFDATE > 20180828
CPP_NOTICE("ospf6: `router-id A.B.C.D` deprecated 2017/08/28")
#endif
ALIAS_HIDDEN(ospf6_router_id, ospf6_router_id_hdn_cmd, "router-id A.B.C.D",
"Configure OSPF6 Router-ID\n" V4NOTATION_STR)
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180828
+#if CONFDATE > 20180828
CPP_NOTICE("ospf6: `no router-id A.B.C.D` deprecated 2017/08/28")
#endif
ALIAS_HIDDEN(no_ospf6_router_id, no_ospf6_router_id_hdn_cmd,
"Source/RP address\n"
"Multicast Group address\n")
{
- struct pim_nexthop_cache pnc;
+ struct pim_nexthop_cache *pnc = NULL;
struct prefix nht_p;
int result = 0;
struct in_addr src_addr, grp_addr;
char grp_str[PREFIX_STRLEN];
int idx = 2;
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ struct pim_rpf rpf;
if (!vrf)
return CMD_WARNING;
grp_addr))
return CMD_SUCCESS;
- memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
nht_p.u.prefix4 = vif_source;
grp.u.prefix4 = grp_addr;
memset(&nexthop, 0, sizeof(nexthop));
- if (pim_find_or_track_nexthop(vrf->info, &nht_p, NULL, NULL, &pnc))
- result = pim_ecmp_nexthop_search(vrf->info, &pnc, &nexthop,
+ memset(&rpf, 0, sizeof(struct pim_rpf));
+ rpf.rpf_addr.family = AF_INET;
+ rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
+ rpf.rpf_addr.u.prefix4 = vif_source;
+
+ pnc = pim_nexthop_cache_find(vrf->info, &rpf);
+ if (pnc)
+ result = pim_ecmp_nexthop_search(vrf->info, pnc, &nexthop,
&nht_p, &grp, 0);
else
- result = pim_ecmp_nexthop_lookup(vrf->info, &nexthop,
- vif_source, &nht_p, &grp, 0);
+ result = pim_ecmp_nexthop_lookup(vrf->info, &nexthop, &nht_p,
+ &grp, 0);
if (!result) {
vty_out(vty,
mask = PIM_OIF_FLAG_PROTO_IGMP;
/* SGRpt entry could have empty oil */
- if (ch->upstream->channel_oil)
- pim_channel_del_oif(ch->upstream->channel_oil,
- ch->interface, mask);
+ pim_channel_del_oif(ch->upstream->channel_oil, ch->interface,
+ mask);
/*
* Do we have any S,G's that are inheriting?
* Nuke from on high too.
socklen_t fromlen = sizeof(from);
socklen_t tolen = sizeof(to);
ifindex_t ifindex = -1;
- int cont = 1;
int len;
- while (cont) {
+ while (1) {
len = pim_socket_recvfromto(igmp->fd, buf, sizeof(buf), &from,
&fromlen, &to, &tolen, &ifindex);
if (len < 0) {
struct pim_nexthop *nexthop, struct prefix *src,
struct prefix *grp, int neighbor_needed)
{
- struct pim_neighbor *nbr = NULL;
+ struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr;
+ struct interface *ifps[MULTIPATH_NUM];
struct nexthop *nh_node = NULL;
ifindex_t first_ifindex;
struct interface *ifp = NULL;
uint32_t hash_val = 0, mod_val = 0;
uint8_t nh_iter = 0, found = 0;
+ uint32_t i, num_nbrs = 0;
if (!pnc || !pnc->nexthop_num || !nexthop)
return 0;
}
}
}
+
+ /*
+ * Look up all interfaces and neighbors,
+ * store for later usage
+ */
+ for (nh_node = pnc->nexthop, i = 0; nh_node;
+ nh_node = nh_node->next, i++) {
+ ifps[i] = if_lookup_by_index(nh_node->ifindex, pim->vrf_id);
+ if (ifps[i]) {
+ nbrs[i] = pim_neighbor_find(ifps[i],
+ nh_node->gate.ipv4);
+ if (nbrs[i] || pim_if_connected_to_source(ifps[i],
+
+ src->u.prefix4))
+ num_nbrs++;
+ }
+ }
if (pim->ecmp_enable) {
+ uint32_t consider = pnc->nexthop_num;
+
+ if (neighbor_needed && num_nbrs < consider)
+ consider = num_nbrs;
+
+ if (consider == 0)
+ return 0;
+
// PIM ECMP flag is enable then choose ECMP path.
hash_val = pim_compute_ecmp_hash(src, grp);
- mod_val = hash_val % pnc->nexthop_num;
+ mod_val = hash_val % consider;
}
for (nh_node = pnc->nexthop; nh_node && (found == 0);
nh_node = nh_node->next) {
first_ifindex = nh_node->ifindex;
- ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
+ ifp = ifps[nh_iter];
if (!ifp) {
if (PIM_DEBUG_PIM_NHT) {
char addr_str[INET_ADDRSTRLEN];
if (neighbor_needed
&& !pim_if_connected_to_source(ifp, src->u.prefix4)) {
- nbr = pim_neighbor_find(ifp, nh_node->gate.ipv4);
+ nbr = nbrs[nh_iter];
if (!nbr && !if_is_loopback(ifp)) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
}
int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
- struct pim_nexthop *nexthop, struct in_addr addr,
- struct prefix *src, struct prefix *grp,
- int neighbor_needed)
+ struct pim_nexthop *nexthop, struct prefix *src,
+ struct prefix *grp, int neighbor_needed)
{
struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
- struct pim_neighbor *nbr = NULL;
+ struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr = NULL;
int num_ifindex;
- struct interface *ifp;
+ struct interface *ifps[MULTIPATH_NUM], *ifp;
int first_ifindex;
int found = 0;
uint8_t i = 0;
uint32_t hash_val = 0, mod_val = 0;
+ uint32_t num_nbrs = 0;
+ char addr_str[PREFIX_STRLEN];
if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+ pim_inet4_dump("<addr?>", src->u.prefix4, addr_str,
+ sizeof(addr_str));
zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
__PRETTY_FUNCTION__, addr_str, pim->vrf->name,
nexthop->last_lookup_time);
memset(nexthop_tab, 0,
sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
- num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
- addr, PIM_NEXTHOP_LOOKUP_MAX);
+ num_ifindex =
+ zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
+ src->u.prefix4, PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_warn(
"%s: could not find nexthop ifindex for address %s(%s)",
__PRETTY_FUNCTION__, addr_str, pim->vrf->name);
- }
return 0;
}
+ /*
+ * Look up all interfaces and neighbors,
+ * store for later usage
+ */
+ for (i = 0; i < num_ifindex; i++) {
+ ifps[i] = if_lookup_by_index(nexthop_tab[i].ifindex,
+ pim->vrf_id);
+ if (ifps[i]) {
+ nbrs[i] = pim_neighbor_find(
+ ifps[i], nexthop_tab[i].nexthop_addr.u.prefix4);
+ if (nbrs[i]
+ || pim_if_connected_to_source(ifps[i],
+ src->u.prefix4))
+ num_nbrs++;
+ }
+ }
+
// If PIM ECMP enable then choose ECMP path.
if (pim->ecmp_enable) {
+ uint32_t consider = num_ifindex;
+
+ if (neighbor_needed && num_nbrs < consider)
+ consider = num_nbrs;
+
+ if (consider == 0)
+ return 0;
+
hash_val = pim_compute_ecmp_hash(src, grp);
- mod_val = hash_val % num_ifindex;
+ mod_val = hash_val % consider;
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("%s: hash_val %u mod_val %u",
__PRETTY_FUNCTION__, hash_val, mod_val);
}
+ i = 0;
while (!found && (i < num_ifindex)) {
first_ifindex = nexthop_tab[i].ifindex;
- ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
+ ifp = ifps[i];
if (!ifp) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s %s: could not find interface for ifindex %d (address %s(%s))",
__FILE__, __PRETTY_FUNCTION__,
first_ifindex, addr_str,
pim->vrf->name);
- }
if (i == mod_val)
mod_val++;
i++;
}
if (!ifp->info) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
__PRETTY_FUNCTION__, ifp->name,
pim->vrf->name, first_ifindex,
addr_str);
- }
if (i == mod_val)
mod_val++;
i++;
continue;
}
- if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) {
- nbr = pim_neighbor_find(
- ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
+ if (neighbor_needed
+ && !pim_if_connected_to_source(ifp, src->u.prefix4)) {
+ nbr = nbrs[i];
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("ifp name: %s(%s), pim nbr: %p",
ifp->name, pim->vrf->name, nbr);
if (i == mod_val)
mod_val++;
i++;
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr,
- addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: NBR not found on input interface %s(%s) (RPF for source %s)",
__PRETTY_FUNCTION__, ifp->name,
pim->vrf->name, addr_str);
- }
continue;
}
}
if (i == mod_val) {
if (PIM_DEBUG_PIM_NHT) {
char nexthop_str[PREFIX_STRLEN];
- char addr_str[INET_ADDRSTRLEN];
+
pim_addr_dump("<nexthop?>",
&nexthop_tab[i].nexthop_addr,
nexthop_str, sizeof(nexthop_str));
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
zlog_debug(
"%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
__PRETTY_FUNCTION__, nexthop_str,
nexthop_tab[i].protocol_distance;
nexthop->mrib_route_metric =
nexthop_tab[i].route_metric;
- nexthop->last_lookup = addr;
+ nexthop->last_lookup = src->u.prefix4;
nexthop->last_lookup_time = pim_time_monotonic_usec();
nexthop->nbr = nbr;
found = 1;
}
int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
- struct in_addr addr, struct prefix *src,
- struct prefix *grp)
+ struct prefix *src, struct prefix *grp)
{
- struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
- int num_ifindex;
+ struct pim_nexthop nhop;
int vif_index;
- ifindex_t first_ifindex;
- uint32_t hash_val = 0, mod_val = 0;
+ ifindex_t ifindex;
+ char addr_str[PREFIX_STRLEN];
- memset(nexthop_tab, 0,
- sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
- num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
- addr, PIM_NEXTHOP_LOOKUP_MAX);
- if (num_ifindex < 1) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
+ pim_inet4_dump("<addr?>", src->u.prefix4, addr_str,
+ sizeof(addr_str));
+ if (!pim_ecmp_nexthop_lookup(pim, &nhop, src, grp, 0)) {
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: could not find nexthop ifindex for address %s(%s)",
__PRETTY_FUNCTION__, addr_str, pim->vrf->name);
- }
return -1;
}
- // If PIM ECMP enable then choose ECMP path.
- if (pim->ecmp_enable) {
- hash_val = pim_compute_ecmp_hash(src, grp);
- mod_val = hash_val % num_ifindex;
- if (PIM_DEBUG_PIM_NHT_DETAIL)
- zlog_debug("%s: hash_val %u mod_val %u",
- __PRETTY_FUNCTION__, hash_val, mod_val);
- }
-
- first_ifindex = nexthop_tab[mod_val].ifindex;
-
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
+ ifindex = nhop.interface->ifindex;
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
- __PRETTY_FUNCTION__, first_ifindex,
- ifindex2ifname(first_ifindex, pim->vrf_id),
+ __PRETTY_FUNCTION__, ifindex,
+ ifindex2ifname(ifindex, pim->vrf_id),
pim->vrf->name, addr_str);
- }
- vif_index = pim_if_find_vifindex_by_ifindex(pim, first_ifindex);
+ vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
if (vif_index < 0) {
if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
zlog_debug(
"%s: low vif_index=%d(%s) < 1 nexthop for address %s",
__PRETTY_FUNCTION__, vif_index, pim->vrf->name,
struct pim_nexthop *nexthop, struct prefix *src,
struct prefix *grp, int neighbor_needed);
int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
- struct pim_nexthop *nexthop, struct in_addr addr,
- struct prefix *src, struct prefix *grp,
- int neighbor_needed);
+ struct pim_nexthop *nexthop, struct prefix *src,
+ struct prefix *grp, int neighbor_needed);
void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
struct pim_nexthop_cache *pnc, int command);
void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p);
int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
- struct in_addr addr, struct prefix *src,
- struct prefix *grp);
+ struct prefix *src, struct prefix *grp);
#endif
&rp_all->group, 1))
return PIM_RP_NO_PATH;
} else {
- if (pim_nexthop_lookup(
+ if (!pim_ecmp_nexthop_lookup(
pim, &rp_all->rp.source_nexthop,
- rp_all->rp.rpf_addr.u.prefix4, 1)
- != 0)
+ &nht_p, &rp_all->group, 1))
return PIM_RP_NO_PATH;
}
pim_rp_check_interfaces(pim, rp_all);
&nht_p, &rp_info->group, 1))
return PIM_RP_NO_PATH;
} else {
- if (pim_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
- rp_info->rp.rpf_addr.u.prefix4, 1)
- != 0)
+ if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1))
return PIM_RP_NO_PATH;
}
"%s: NHT Local Nexthop not found for RP %s ",
__PRETTY_FUNCTION__, buf);
}
- if (pim_nexthop_lookup(
- pim, &rp_info->rp.source_nexthop,
- rp_info->rp.rpf_addr.u.prefix4, 1) < 0)
+ if (!pim_ecmp_nexthop_lookup(pim,
+ &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1))
if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug(
"Unable to lookup nexthop for rp specified");
__PRETTY_FUNCTION__, buf, buf1);
}
pim_rpf_set_refresh_time(pim);
- pim_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
- rp_info->rp.rpf_addr.u.prefix4, 1);
+ pim_ecmp_nexthop_lookup(pim,
+ &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1);
}
return (&rp_info->rp);
}
struct prefix nht_p;
struct pim_nexthop_cache pnc;
struct prefix src, grp;
+ bool neigh_needed = true;
saved.source_nexthop = rpf->source_nexthop;
saved.rpf_addr = rpf->rpf_addr;
grp.prefixlen = IPV4_MAX_BITLEN;
grp.u.prefix4 = up->sg.grp;
memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
+
+ if ((up->sg.src.s_addr == INADDR_ANY && I_am_RP(pim, up->sg.grp)) ||
+ PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
+ neigh_needed = FALSE;
if (pim_find_or_track_nexthop(pim, &nht_p, up, NULL, &pnc)) {
if (pnc.nexthop_num) {
- if (!pim_ecmp_nexthop_search(
- pim, &pnc, &up->rpf.source_nexthop, &src,
- &grp,
- !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)
- && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(
- up->flags)))
+ if (!pim_ecmp_nexthop_search(pim, &pnc,
+ &up->rpf.source_nexthop,
+ &src, &grp, neigh_needed))
return PIM_RPF_FAILURE;
}
} else {
- if (!pim_ecmp_nexthop_lookup(
- pim, &rpf->source_nexthop, up->upstream_addr, &src,
- &grp,
- !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)
- && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(
- up->flags)))
+ if (!pim_ecmp_nexthop_lookup(pim, &rpf->source_nexthop, &src,
+ &grp, neigh_needed))
return PIM_RPF_FAILURE;
}
__PRETTY_FUNCTION__, source_str, group_str);
}
input_iface_vif_index = pim_ecmp_fib_lookup_if_vif_index(
- c_oil->pim, vif_source, &src, &grp);
+ c_oil->pim, &src, &grp);
}
if (input_iface_vif_index < 1) {
}
} else
input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(
- pim, vif_source, &src, &grp);
+ pim_ecmp_fib_lookup_if_vif_index(pim, &src,
+ &grp);
if (PIM_DEBUG_ZEBRA) {
char buf2[INET_ADDRSTRLEN];
/* Register addr with Zebra NHT */
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+ nht_p.u.prefix4 = up->upstream_addr;
grp.family = AF_INET;
grp.prefixlen = IPV4_MAX_BITLEN;
grp.u.prefix4 = up->sg.grp;
}
} else
input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(
- pim, up->upstream_addr, &src, &grp);
+ pim_ecmp_fib_lookup_if_vif_index(pim, &src,
+ &grp);
if (input_iface_vif_index < 1) {
if (PIM_DEBUG_PIM_TRACE) {
%endif
install %{zeb_rh_src}/daemons %{buildroot}%{_sysconfdir}/frr
+# add rpki module to daemon
+%if %{with_rpki}
+ sed -i -e 's/^\(bgpd_options=\)\(.*\)\(".*\)/\1\2 -M rpki\3/' %{buildroot}%{_sysconfdir}/frr/daemons
+%endif
install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr
install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
install -d -m750 %{buildroot}%{rundir}
__pycache__
.pytest_cache
/bgpd/test_aspath
+/bgpd/test_bgp_table
/bgpd/test_capability
/bgpd/test_ecommunity
/bgpd/test_mp_attr
bgpd/test_peer_attr \
bgpd/test_ecommunity \
bgpd/test_mp_attr \
- bgpd/test_mpath
+ bgpd/test_mpath \
+ bgpd/test_bgp_table
else
TESTS_BGPD =
endif
bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c
bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c
bgpd_test_mpath_SOURCES = bgpd/test_mpath.c
+bgpd_test_bgp_table_SOURCES = bgpd/test_bgp_table.c
isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c
nodist_isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv_tests.h
BUILT_SOURCES=isisd/test_fuzz_isis_tlv_tests.h
bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD)
bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD)
bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_bgp_table_LDADD = $(BGP_TEST_LDADD)
isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD)
isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD)
ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD)
--- /dev/null
+/*
+ * BGP Routing table range lookup test
+ * Copyright (C) 2012 OSR.
+ * Copyright (C) 2018 Marcel Röthke (marcel.roethke@haw-hamburg.de), for HAW
+ * Hamburg
+ *
+ * This file is part of FRRouting
+ *
+ * Quagga 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, or (at your option) any
+ * later version.
+ *
+ * Quagga 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 "prefix.h"
+#include "table.h"
+#include "bgpd/bgp_table.h"
+#include "linklist.h"
+
+/*
+ * test_node_t
+ *
+ * Information that is kept for each node in the radix tree.
+ */
+struct test_node_t {
+
+ /*
+ * Human readable representation of the string. Allocated using
+ * malloc()/dup().
+ */
+ char *prefix_str;
+};
+
+/*
+ * add_node
+ *
+ * Add the given prefix (passed in as a string) to the given table.
+ */
+static void add_node(struct bgp_table *table, const char *prefix_str)
+{
+ struct prefix_ipv4 p;
+ struct test_node_t *node;
+ struct bgp_node *rn;
+
+ assert(prefix_str);
+
+ if (str2prefix_ipv4(prefix_str, &p) <= 0)
+ assert(0);
+
+ rn = bgp_node_get(table, (struct prefix *)&p);
+ if (rn->info) {
+ assert(0);
+ return;
+ }
+
+ node = malloc(sizeof(struct test_node_t));
+ assert(node);
+ node->prefix_str = strdup(prefix_str);
+ assert(node->prefix_str);
+ rn->info = node;
+}
+
+static void print_range_result(struct list *list)
+{
+
+ struct listnode *listnode;
+ struct bgp_node *bnode;
+
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, bnode)) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&bnode->p, buf, PREFIX2STR_BUFFER);
+ printf("%s\n", buf);
+ }
+}
+
+static void check_lookup_result(struct list *list, va_list arglist)
+{
+ char *prefix_str;
+ unsigned int prefix_count = 0;
+
+ printf("Searching results\n");
+ while ((prefix_str = va_arg(arglist, char *))) {
+ struct listnode *listnode;
+ struct bgp_node *bnode;
+ struct prefix p;
+ bool found = false;
+
+ prefix_count++;
+ printf("Searching for %s\n", prefix_str);
+
+ if (str2prefix(prefix_str, &p) <= 0)
+ assert(0);
+
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, bnode)) {
+ if (prefix_same(&bnode->p, &p))
+ found = true;
+ }
+
+ assert(found);
+ }
+
+ printf("Checking for unexpected result items\n");
+ printf("Expecting %d found %d\n", prefix_count, listcount(list));
+ assert(prefix_count == listcount(list));
+}
+
+static void do_test(struct bgp_table *table, const char *prefix, uint8_t maxlen,
+ ...)
+{
+ va_list arglist;
+ struct list *list = list_new();
+ struct prefix p;
+
+ list->del = (void (*)(void *))bgp_unlock_node;
+
+ va_start(arglist, maxlen);
+ printf("\nDoing lookup for %s-%d\n", prefix, maxlen);
+ if (str2prefix(prefix, &p) <= 0)
+ assert(0);
+ bgp_table_range_lookup(table, &p, maxlen, list);
+ print_range_result(list);
+
+ check_lookup_result(list, arglist);
+
+ list_delete_and_null(&list);
+
+ va_end(arglist);
+
+ printf("Checks successfull\n");
+}
+
+/*
+ * test_range_lookup
+ */
+static void test_range_lookup(void)
+{
+ struct bgp_table *table = bgp_table_init(NULL, AFI_IP, SAFI_UNICAST);
+
+ printf("Testing bgp_table_range_lookup\n");
+
+ printf("Setup bgp_table");
+ const char *prefixes[] = {"1.16.0.0/16", "1.16.128.0/18",
+ "1.16.192.0/18", "1.16.64.0/19",
+ "1.16.160.0/19", "1.16.32.0/20",
+ "1.16.32.0/21", "16.0.0.0/16"};
+
+ int num_prefixes = sizeof(prefixes) / sizeof(prefixes[0]);
+
+ for (int i = 0; i < num_prefixes; i++)
+ add_node(table, prefixes[i]);
+
+ do_test(table, "1.16.0.0/17", 20, "1.16.64.0/19", "1.16.32.0/20", NULL);
+ do_test(table, "1.16.128.0/17", 20, "1.16.128.0/18", "1.16.192.0/18",
+ "1.16.160.0/19", NULL);
+
+ do_test(table, "1.16.128.0/17", 20, "1.16.128.0/18", "1.16.192.0/18",
+ "1.16.160.0/19", NULL);
+
+ do_test(table, "1.16.0.0/16", 18, "1.16.0.0/16", "1.16.128.0/18",
+ "1.16.192.0/18", NULL);
+
+ do_test(table, "1.16.0.0/16", 21, "1.16.0.0/16", "1.16.128.0/18",
+ "1.16.192.0/18", "1.16.64.0/19", "1.16.160.0/19",
+ "1.16.32.0/20", "1.16.32.0/21", NULL);
+
+ do_test(table, "1.17.0.0/16", 20, NULL);
+
+ do_test(table, "128.0.0.0/8", 16, NULL);
+
+ do_test(table, "16.0.0.0/8", 16, "16.0.0.0/16", NULL);
+
+ do_test(table, "0.0.0.0/3", 21, "1.16.0.0/16", "1.16.128.0/18",
+ "1.16.192.0/18", "1.16.64.0/19", "1.16.160.0/19",
+ "1.16.32.0/20", "1.16.32.0/21", "16.0.0.0/16", NULL);
+}
+
+int main(void)
+{
+ test_range_lookup();
+}
--- /dev/null
+import frrtest
+
+class TestTable(frrtest.TestMultiOut):
+ program = './test_bgp_table'
+
+for i in range(6):
+ TestTable.onesimple('Checks successfull')
}
static void test_failed(struct test_state *test, const char *message,
- struct prefix_ipv6 *dst_p, struct prefix_ipv6 *src_p)
+ const struct prefix_ipv6 *dst_p,
+ const struct prefix_ipv6 *src_p)
{
char *route_id = format_srcdest(dst_p, src_p);
/* Verify that there are no elements in the table which have never
* been added */
for (rn = route_top(test->table); rn; rn = srcdest_route_next(rn)) {
- struct prefix_ipv6 *dst_p, *src_p;
+ const struct prefix_ipv6 *dst_p, *src_p;
/* While we are iterating, we hold a lock on the current
* route_node,
expected_lock++;
if (rn->lock != expected_lock) {
- struct prefix_ipv6 *dst_p, *src_p;
+ const struct prefix_ipv6 *dst_p, *src_p;
srcdest_rnode_prefixes(
- rn, (struct prefix **)&dst_p,
- (struct prefix **)&src_p);
+ rn, (const struct prefix **)&dst_p,
+ (const struct prefix **)&src_p);
test_failed(
test,
assert(rn->info == (void *)0xdeadbeef);
- srcdest_rnode_prefixes(rn, (struct prefix **)&dst_p,
- (struct prefix **)&src_p);
+ srcdest_rnode_prefixes(rn, (const struct prefix **)&dst_p,
+ (const struct prefix **)&src_p);
memcpy(&hash_entry[0], dst_p, sizeof(*dst_p));
if (src_p)
memcpy(&hash_entry[1], src_p, sizeof(*src_p));
which_route = prng_rand(prng) % test->log->count;
struct route_node *rn;
- struct prefix *dst_p, *src_p;
+ const struct prefix *dst_p, *src_p;
struct prefix_ipv6 dst6_p, src6_p;
for (rn = route_top(test->table); rn; rn = srcdest_route_next(rn)) {
self.save_contexts(ctx_keys, current_context_lines)
new_ctx = True
- elif line == "end":
+ elif line in ["end", "exit-vrf"]:
self.save_contexts(ctx_keys, current_context_lines)
log.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys)
if (tb[IFA_LABEL])
label = (char *)RTA_DATA(tb[IFA_LABEL]);
- if (ifp && label && strcmp(ifp->name, label) == 0)
+ if (label && strcmp(ifp->name, label) == 0)
label = NULL;
/* Register interface address to the interface. */
}
}
-int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type, void *data,
- unsigned int alen)
+int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
+ const void *data, unsigned int alen)
{
int len;
struct rtattr *rta;
return 0;
}
-int rta_addattr_l(struct rtattr *rta, unsigned int maxlen, int type, void *data,
- unsigned int alen)
+int rta_addattr_l(struct rtattr *rta, unsigned int maxlen, int type,
+ const void *data, unsigned int alen)
{
unsigned int len;
struct rtattr *subrta;
n->nlmsg_seq = ++nl->seq;
n->nlmsg_pid = nl->snl.nl_pid;
- /* Request an acknowledgement by setting NLM_F_ACK */
- n->nlmsg_flags |= NLM_F_ACK;
-
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
"netlink_talk: %s type %s(%u), len=%d seq=%u flags 0x%x",
snprintf(zns->netlink.name, sizeof(zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);
zns->netlink.sock = -1;
- netlink_socket(&zns->netlink, groups, zns->ns_id);
+ if (netlink_socket(&zns->netlink, groups, zns->ns_id) < 0) {
+ zlog_err("Failure to create %s socket",
+ zns->netlink.name);
+ exit(-1);
+ }
snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name),
"netlink-cmd (NS %u)", zns->ns_id);
zns->netlink_cmd.sock = -1;
- netlink_socket(&zns->netlink_cmd, 0, zns->ns_id);
+ if (netlink_socket(&zns->netlink_cmd, 0, zns->ns_id) < 0) {
+ zlog_err("Failure to create %s socket",
+ zns->netlink_cmd.name);
+ exit(-1);
+ }
/*
* SOL_NETLINK is not available on all platforms yet
#endif
/* Register kernel socket. */
- if (zns->netlink.sock > 0) {
- /* Only want non-blocking on the netlink event socket */
- if (fcntl(zns->netlink.sock, F_SETFL, O_NONBLOCK) < 0)
- zlog_err("Can't set %s socket flags: %s",
- zns->netlink.name, safe_strerror(errno));
-
- /* Set receive buffer size if it's set from command line */
- if (nl_rcvbufsize)
- netlink_recvbuf(&zns->netlink, nl_rcvbufsize);
-
- netlink_install_filter(zns->netlink.sock,
- zns->netlink_cmd.snl.nl_pid);
- zns->t_netlink = NULL;
-
- thread_add_read(zebrad.master, kernel_read, zns,
- zns->netlink.sock, &zns->t_netlink);
- }
+ if (fcntl(zns->netlink.sock, F_SETFL, O_NONBLOCK) < 0)
+ zlog_err("Can't set %s socket error: %s(%d)",
+ zns->netlink.name, safe_strerror(errno), errno);
+
+ if (fcntl(zns->netlink_cmd.sock, F_SETFL, O_NONBLOCK) < 0)
+ zlog_err("Can't set %s socket error: %s(%d)",
+ zns->netlink_cmd.name, safe_strerror(errno), errno);
+
+ /* Set receive buffer size if it's set from command line */
+ if (nl_rcvbufsize)
+ netlink_recvbuf(&zns->netlink, nl_rcvbufsize);
+
+ netlink_install_filter(zns->netlink.sock,
+ zns->netlink_cmd.snl.nl_pid);
+ zns->t_netlink = NULL;
+
+ thread_add_read(zebrad.master, kernel_read, zns,
+ zns->netlink.sock, &zns->t_netlink);
rt_netlink_init();
}
extern void netlink_parse_rtattr(struct rtattr **tb, int max,
struct rtattr *rta, int len);
extern int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
- void *data, unsigned int alen);
+ const void *data, unsigned int alen);
extern int rta_addattr_l(struct rtattr *rta, unsigned int maxlen, int type,
- void *data, unsigned int alen);
+ const void *data, unsigned int alen);
extern int addattr16(struct nlmsghdr *n, unsigned int maxlen, int type,
uint16_t data);
extern int addattr32(struct nlmsghdr *n, unsigned int maxlen, int type,
" -z, --socket Set path of zebra socket\n"
" -e, --ecmp Specify ECMP to use.\n"
" -l, --label_socket Socket to external label manager\n"
- " -k, --keep_kernel Don't delete old routes which installed by zebra.\n"
+ " -k, --keep_kernel Don't delete old routes which were installed by zebra.\n"
" -r, --retain When program terminates, retain added route by zebra.\n"
#ifdef HAVE_NETLINK
- " -n, --vrfwnetns Set VRF with NetNS\n"
+ " -n, --vrfwnetns Use NetNS as VRF backend\n"
" -s, --nl-bufsize Set netlink receive buffer size\n"
" --v6-rr-semantics Use v6 RR semantics\n"
#endif /* HAVE_NETLINK */
#if defined(HANDLE_ZAPI_FUZZING)
- " -c <file> Bypass normal startup use this file for tetsting of zapi"
+ " -c <file> Bypass normal startup and use this file for testing of zapi"
#endif
);
/* For debug purpose. */
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
-#if defined(HANDLE_ZAPI_FUZZING)
- if (fuzzing) {
- zserv_read_file(fuzzing);
- exit(0);
- }
-#endif
-
/* Process the configuration file. Among other configuration
* directives we can meet those installing static routes. Such
* requests will not be executed immediately, but queued in
/* RNH init */
zebra_rnh_init();
+#if defined(HANDLE_ZAPI_FUZZING)
+ if (fuzzing) {
+ zserv_read_file(fuzzing);
+ exit(0);
+ }
+#endif
+
+
frr_run(zebrad.master);
/* Not reached... */
for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
RNODE_FOREACH_RE (rn, newre) {
- struct prefix *dst_p, *src_p;
+ const struct prefix *dst_p, *src_p;
char buf[PREFIX_STRLEN];
srcdest_rnode_prefixes(rn, &dst_p, &src_p);
/* Either advertise a route for redistribution to registered clients or */
/* withdraw redistribution if add cannot be done for client */
-void redistribute_update(struct prefix *p, struct prefix *src_p,
+void redistribute_update(const struct prefix *p, const struct prefix *src_p,
struct route_entry *re, struct route_entry *prev_re)
{
struct listnode *node, *nnode;
}
}
-void redistribute_delete(struct prefix *p, struct prefix *src_p,
+void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
struct route_entry *re)
{
struct listnode *node, *nnode;
extern void zebra_redistribute_default_delete(ZAPI_HANDLER_ARGS);
/* ----------------- */
-extern void redistribute_update(struct prefix *, struct prefix *,
+extern void redistribute_update(const struct prefix *p,
+ const struct prefix *src_p,
struct route_entry *, struct route_entry *);
-extern void redistribute_delete(struct prefix *, struct prefix *,
+extern void redistribute_delete(const struct prefix *p,
+ const struct prefix *src_p,
struct route_entry *);
extern void zebra_interface_up_update(struct interface *);
extern int is_zebra_valid_kernel_table(uint32_t table_id);
extern int is_zebra_main_routing_table(uint32_t table_id);
-extern int zebra_check_addr(struct prefix *p);
+extern int zebra_check_addr(const struct prefix *p);
extern void rib_addnode(struct route_node *rn, struct route_entry *re,
int process);
* a re-add.
*/
extern enum dp_req_result kernel_route_rib(struct route_node *rn,
- struct prefix *p,
- struct prefix *src_p,
+ const struct prefix *p,
+ const struct prefix *src_p,
struct route_entry *old,
struct route_entry *new);
* so let's separate it out and allow the result to
* be passed back up.
*/
-extern void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p,
+extern void kernel_route_rib_pass_fail(struct route_node *rn,
+ const struct prefix *p,
struct route_entry *re,
enum dp_results res);
memcpy(&nh.gate, gate, sz);
if (index) {
- ifp = if_lookup_by_index(index, VRF_UNKNOWN);
+ ifp = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(ns_id),
+ index);
if (ifp)
nh_vrf_id = ifp->vrf_id;
}
* using the last one looked
* up right now
*/
- ifp = if_lookup_by_index(index,
- VRF_UNKNOWN);
+ ifp = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(ns_id),
+ index);
if (ifp)
nh_vrf_id = ifp->vrf_id;
else {
* @param zvrf: The vrf we are in
* @param tableid: The table we are working on
*/
-static void _netlink_route_debug(int cmd, struct prefix *p,
- int family, struct zebra_vrf *zvrf,
+static void _netlink_route_debug(int cmd, const struct prefix *p,
+ int family, vrf_id_t vrfid,
uint32_t tableid)
{
if (IS_ZEBRA_DEBUG_KERNEL) {
"netlink_route_multipath(): %s %s vrf %u(%u)",
nl_msg_type_to_str(cmd),
prefix2str(p, buf, sizeof(buf)),
- zvrf_id(zvrf), tableid);
+ vrfid, tableid);
}
}
/* Routing table change via netlink interface. */
/* Update flag indicates whether this is a "replace" or not. */
-static int netlink_route_multipath(int cmd, struct prefix *p,
- struct prefix *src_p, struct route_entry *re,
+static int netlink_route_multipath(int cmd, const struct prefix *p,
+ const struct prefix *src_p,
+ struct route_entry *re,
int update)
{
int bytelen;
addattr32(&req.n, sizeof req, RTA_TABLE, re->table);
}
- _netlink_route_debug(cmd, p, family, zvrf, re->table);
+ _netlink_route_debug(cmd, p, family, zvrf_id(zvrf), re->table);
/*
* If we are not updating the route and we have received
}
enum dp_req_result kernel_route_rib(struct route_node *rn,
- struct prefix *p,
- struct prefix *src_p,
+ const struct prefix *p,
+ const struct prefix *src_p,
struct route_entry *old,
struct route_entry *new)
{
}
enum dp_req_result kernel_route_rib(struct route_node *rn,
- struct prefix *p,
- struct prefix *src_p,
+ const struct prefix *p,
+ const struct prefix *src_p,
struct route_entry *old,
struct route_entry *new)
{
return zserv_send_message(client, s);
}
-int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
- struct prefix *src_p, struct route_entry *re)
+int zsend_redistribute_route(int cmd, struct zserv *client,
+ const struct prefix *p,
+ const struct prefix *src_p, struct route_entry *re)
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
return zserv_send_message(client, s);
}
-int zsend_route_notify_owner(struct route_entry *re, struct prefix *p,
- enum zapi_route_notify_owner note)
+/*
+ * Common utility send route notification, called from a path using a
+ * route_entry and from a path using a dataplane context.
+ */
+static int route_notify_internal(const struct prefix *p, int type,
+ uint16_t instance, vrf_id_t vrf_id,
+ uint32_t table_id,
+ enum zapi_route_notify_owner note)
{
struct zserv *client;
struct stream *s;
uint8_t blen;
- client = zserv_find_client(re->type, re->instance);
+ client = zserv_find_client(type, instance);
if (!client || !client->notify_owner) {
if (IS_ZEBRA_DEBUG_PACKET) {
char buff[PREFIX_STRLEN];
zlog_debug(
"Not Notifying Owner: %u about prefix %s(%u) %d vrf: %u",
- re->type, prefix2str(p, buff, sizeof(buff)),
- re->table, note, re->vrf_id);
+ type, prefix2str(p, buff, sizeof(buff)),
+ table_id, note, vrf_id);
}
return 0;
}
char buff[PREFIX_STRLEN];
zlog_debug("Notifying Owner: %u about prefix %s(%u) %d vrf: %u",
- re->type, prefix2str(p, buff, sizeof(buff)),
- re->table, note, re->vrf_id);
+ type, prefix2str(p, buff, sizeof(buff)),
+ table_id, note, vrf_id);
}
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
stream_reset(s);
- zclient_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, re->vrf_id);
+ zclient_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, vrf_id);
stream_put(s, ¬e, sizeof(note));
stream_putc(s, p->prefixlen);
stream_put(s, &p->u.prefix, blen);
- stream_putl(s, re->table);
+ stream_putl(s, table_id);
stream_putw_at(s, 0, stream_get_endp(s));
return zserv_send_message(client, s);
}
+int zsend_route_notify_owner(struct route_entry *re, const struct prefix *p,
+ enum zapi_route_notify_owner note)
+{
+ return (route_notify_internal(p, re->type, re->instance, re->vrf_id,
+ re->table, note));
+}
+
void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
enum zapi_rule_notify_owner note)
{
STREAM_GETL(s, ifindex);
if (ifindex) {
- zpr.ifp = if_lookup_by_index(ifindex, VRF_UNKNOWN);
+ zpr.ifp = if_lookup_by_index_per_ns(
+ zvrf->zns,
+ ifindex);
if (!zpr.ifp) {
zlog_debug("Failed to lookup ifindex: %u",
ifindex);
extern int zsend_interface_update(int cmd, struct zserv *client,
struct interface *ifp);
extern int zsend_redistribute_route(int cmd, struct zserv *zclient,
- struct prefix *p, struct prefix *src_p,
+ const struct prefix *p,
+ const struct prefix *src_p,
struct route_entry *re);
extern int zsend_router_id_update(struct zserv *zclient, struct prefix *p,
vrf_id_t vrf_id);
extern int zsend_interface_link_params(struct zserv *zclient,
struct interface *ifp);
extern int zsend_pw_update(struct zserv *client, struct zebra_pw *pw);
-extern int zsend_route_notify_owner(struct route_entry *re, struct prefix *p,
+extern int zsend_route_notify_owner(struct route_entry *re,
+ const struct prefix *p,
enum zapi_route_notify_owner note);
extern void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
#include "zebra/rib.h"
#include "zebra/rt.h"
+#include "zebra/interface.h"
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
{
struct nexthop *nexthop;
struct interface *ifp;
+ struct zebra_ns *zns;
nexthop = nhlfe->nexthop;
if (!nexthop) // unexpected
* which will not be in the default
* VRF. So let's look in all of them
*/
- ifp = if_lookup_by_index(nexthop->ifindex, VRF_UNKNOWN);
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ ifp = if_lookup_by_index_per_ns(zns, nexthop->ifindex);
if (ifp && if_is_operative(ifp))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
switch (nexthop->type) {
case NEXTHOP_TYPE_IFINDEX: {
+ struct zebra_ns *zns;
struct interface *ifp;
- ifp = if_lookup_by_index(
- nexthop->ifindex, VRF_UNKNOWN);
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ ifp = if_lookup_by_index_per_ns(
+ zns,
+ nexthop->ifindex);
vty_out(vty, "%15s", ifp->name);
break;
}
ns_id = zebra_ns_id_get(netnspath);
if (zserv_privs.change(ZPRIVS_LOWER))
zlog_err("Can't lower privileges");
+ if (ns_id == NS_UNKNOWN)
+ return;
ns_id_external = ns_map_nsid_with_external(ns_id, true);
/* if VRF with NS ID already present */
vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);
if (ret != CMD_SUCCESS) {
zlog_warn("NS notify : failed to create NS %s", netnspath);
ns_map_nsid_with_external(ns_id, false);
+ vrf_delete(vrf);
return;
}
zlog_info("NS notify : created VRF %s NS %s", name, netnspath);
int zebra_ptm_sock_read(struct thread *thread)
{
- int sock, done = 0;
+ int sock;
int rc;
errno = 0;
return -1;
/* PTM communicates in CSV format */
- while (!done) {
+ do {
rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data,
ZEBRA_PTM_MAX_SOCKBUF, NULL);
- if (rc <= 0)
- break;
- }
+ } while (rc > 0);
- if (rc <= 0) {
- if (((rc == 0) && !errno)
- || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
- zlog_warn("%s routing socket error: %s(%d) bytes %d",
- __func__, safe_strerror(errno), errno, rc);
-
- close(ptm_cb.ptm_sock);
- ptm_cb.ptm_sock = -1;
- zebra_ptm_reset_status(0);
- ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
- ptm_cb.reconnect_time,
- &ptm_cb.t_timer);
- return (-1);
- }
+ if (((rc == 0) && !errno)
+ || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
+ zlog_warn("%s routing socket error: %s(%d) bytes %d",
+ __func__, safe_strerror(errno), errno, rc);
+
+ close(ptm_cb.ptm_sock);
+ ptm_cb.ptm_sock = -1;
+ zebra_ptm_reset_status(0);
+ ptm_cb.t_timer = NULL;
+ thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ ptm_cb.reconnect_time,
+ &ptm_cb.t_timer);
+ return (-1);
}
ptm_cb.t_read = NULL;
return 0;
}
-int zebra_check_addr(struct prefix *p)
+int zebra_check_addr(const struct prefix *p)
{
if (p->family == AF_INET) {
uint32_t addr;
return nexthop;
}
-static void nexthop_set_resolved(afi_t afi, struct nexthop *newhop,
+static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
struct nexthop *nexthop)
{
struct nexthop *resolved_hop;
route_map_result_t ret = RMAP_MATCH;
int family;
char buf[SRCDEST2STR_BUFFER];
- struct prefix *p, *src_p;
+ const struct prefix *p, *src_p;
srcdest_rnode_prefixes(rn, &p, &src_p);
if (rn->p.family == AF_INET)
return 1;
}
-void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p,
+void kernel_route_rib_pass_fail(struct route_node *rn, const struct prefix *p,
struct route_entry *re,
enum dp_results res)
{
{
struct nexthop *nexthop;
rib_table_info_t *info = srcdest_rnode_table_info(rn);
- struct prefix *p, *src_p;
+ const struct prefix *p, *src_p;
struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
srcdest_rnode_prefixes(rn, &p, &src_p);
{
struct nexthop *nexthop;
rib_table_info_t *info = srcdest_rnode_table_info(rn);
- struct prefix *p, *src_p;
+ const struct prefix *p, *src_p;
struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
srcdest_rnode_prefixes(rn, &p, &src_p);
}
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
- struct prefix *p, *src_p;
+ const struct prefix *p, *src_p;
+
srcdest_rnode_prefixes(rn, &p, &src_p);
redistribute_delete(p, src_p, re);
char buf[SRCDEST2STR_BUFFER];
rib_dest_t *dest;
struct zebra_vrf *zvrf = NULL;
- struct prefix *p, *src_p;
+ const struct prefix *p, *src_p;
+
srcdest_rnode_prefixes(rn, &p, &src_p);
vrf_id_t vrf_id = VRF_UNKNOWN;
}
route_map_result_t zebra_route_map_check(int family, int rib_type,
- uint8_t instance, struct prefix *p,
+ uint8_t instance,
+ const struct prefix *p,
struct nexthop *nexthop,
vrf_id_t vrf_id, route_tag_t tag)
{
rmap = route_map_lookup_by_name(
proto_rm[family][ZEBRA_ROUTE_MAX]);
if (rmap) {
- ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
+ ret = route_map_apply(rmap, (struct prefix *)p,
+ RMAP_ZEBRA, &nh_obj);
}
return (ret);
const char *rmap_name);
extern route_map_result_t
zebra_route_map_check(int family, int rib_type, uint8_t instance,
- struct prefix *p, struct nexthop *nexthop,
+ const struct prefix *p, struct nexthop *nexthop,
vrf_id_t vrf_id, route_tag_t tag);
extern route_map_result_t
zebra_nht_route_map_check(int family, int client_proto, struct prefix *p,
#include "zebra/zebra_memory.h"
/* Install static route into rib. */
-void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
- struct prefix_ipv6 *src_p, struct static_route *si)
+void static_install_route(afi_t afi, safi_t safi, const struct prefix *p,
+ const struct prefix_ipv6 *src_p,
+ struct static_route *si)
{
struct route_entry *re;
struct route_node *rn;
}
/* Uninstall static route from RIB. */
-void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
- struct prefix_ipv6 *src_p, struct static_route *si)
+void static_uninstall_route(afi_t afi, safi_t safi, const struct prefix *p,
+ const struct prefix_ipv6 *src_p,
+ struct static_route *si)
{
struct route_node *rn;
struct route_entry *re;
struct route_table *stable;
struct route_node *rn;
struct static_route *si;
- struct prefix *p, *src_pp;
+ const struct prefix *p, *src_pp;
struct prefix_ipv6 *src_p;
struct vrf *vrf;
uint32_t table_id;
};
-extern void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
- struct prefix_ipv6 *src_p,
+extern void static_install_route(afi_t afi, safi_t safi, const struct prefix *p,
+ const struct prefix_ipv6 *src_p,
struct static_route *si);
-extern void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
- struct prefix_ipv6 *src_p,
+extern void static_uninstall_route(afi_t afi, safi_t safi,
+ const struct prefix *p,
+ const struct prefix_ipv6 *src_p,
struct static_route *si);
extern int static_add_route(afi_t, safi_t safi, uint8_t type, struct prefix *p,
break;
}
- if (re->vrf_id != nexthop->vrf_id) {
+ if ((re->vrf_id != nexthop->vrf_id)
+ && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
struct vrf *vrf =
vrf_lookup_by_id(nexthop->vrf_id);
break;
}
- if (nexthop->vrf_id != re->vrf_id) {
+ if ((nexthop->vrf_id != re->vrf_id)
+ && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
struct vrf *vrf =
vrf_lookup_by_id(nexthop->vrf_id);
break;
}
- if (nexthop->vrf_id != re->vrf_id) {
+ if ((nexthop->vrf_id != re->vrf_id)
+ && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
if (vrf)
json = json_object_new_object();
/* Show all routes. */
- for (rn = route_top(table); rn; rn = route_next(rn)) {
+ for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
dest = rib_dest_from_rnode(rn);
RNODE_FOREACH_RE (rn, re) {
* Client thread events.
*
* These are used almost exclusively by client threads to drive their own event
- * loops. The only exception is in zebra_client_create(), which pushes an
+ * loops. The only exception is in zserv_client_create(), which pushes an
* initial ZSERV_CLIENT_READ event to start the API handler loop.
*/
enum zserv_client_event {
* sock
* client's socket file descriptor
*/
-static void zserv_client_create(int sock)
+static struct zserv *zserv_client_create(int sock)
{
struct zserv *client;
int i;
/* start pthread */
frr_pthread_run(client->pthread, NULL);
+
+ return client;
}
/*
struct zserv *client = NULL;
struct thread t;
- zebra_client_create(-1);
-
- frr_pthread_stop(client->pthread, NULL);
- frr_pthread_destroy(client->pthread);
- client->pthread = NULL;
-
- t.arg = client;
-
fd = open(input, O_RDONLY | O_NONBLOCK);
t.u.fd = fd;
- zserv_read(&t);
-
- close(fd);
+ zserv_client_create(fd);
}
#endif