/* Install EVPN route into zebra. */
static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
- struct prefix_evpn *p,
- struct in_addr remote_vtep_ip, uint8_t flags,
- uint32_t seq)
+ struct prefix_evpn *p, struct bgp_path_info *pi)
{
int ret;
+ uint8_t flags;
- if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
- ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip,
- 1, flags, seq);
- else
+ if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ flags = 0;
+ if (pi->attr->sticky)
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ if (pi->attr->default_gw)
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+ if (is_evpn_prefix_ipaddr_v6(p) &&
+ pi->attr->router_flag)
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
+ ret = bgp_zebra_send_remote_macip(
+ bgp, vpn, p, pi->attr->nexthop, 1, flags,
+ mac_mobility_seqnum(pi->attr));
+ } else {
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1);
+ }
return ret;
}
{
struct bgp_path_info *old_select, *new_select;
struct bgp_path_info_pair old_and_new;
- struct prefix_evpn *evp;
afi_t afi = AFI_L2VPN;
safi_t safi = SAFI_EVPN;
int ret = 0;
- uint8_t flags = 0;
/* Compute the best path. */
bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
old_select = old_and_new.old;
new_select = old_and_new.new;
- evp = (struct prefix_evpn *)&rn->p;
/* If the best path hasn't changed - see if there is still something to
* update
* to zebra RIB.
&& !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
&& !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
&& !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
- if (bgp_zebra_has_route_changed(rn, old_select)) {
- if (old_select->attr->sticky)
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
- if (old_select->attr->default_gw)
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
- if (is_evpn_prefix_ipaddr_v6(evp) &&
- old_select->attr->router_flag)
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
-
+ if (bgp_zebra_has_route_changed(rn, old_select))
ret = evpn_zebra_install(
bgp, vpn, (struct prefix_evpn *)&rn->p,
- old_select->attr->nexthop, flags,
- mac_mobility_seqnum(old_select->attr));
- }
+ old_select);
UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
bgp_zebra_clear_route_change_flags(rn);
return ret;
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_IMPORTED) {
- flags = 0;
- if (new_select->attr->sticky)
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
- if (new_select->attr->default_gw)
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
- if (is_evpn_prefix_ipaddr_v6(evp) &&
- new_select->attr->router_flag)
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
-
ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
- new_select->attr->nexthop, flags,
- mac_mobility_seqnum(new_select->attr));
+ new_select);
+
/* If an old best existed and it was a "local" route, the only
* reason
* it would be supplanted is due to MAC mobility procedures. So,
return route_change;
}
+static void evpn_zebra_reinstall_best_route(struct bgp *bgp,
+ struct bgpevpn *vpn, struct bgp_node *rn)
+{
+ struct bgp_path_info *tmp_ri;
+ struct bgp_path_info *curr_select = NULL;
+
+ for (tmp_ri = bgp_node_get_bgp_path_info(rn);
+ tmp_ri; tmp_ri = tmp_ri->next) {
+ if (CHECK_FLAG(tmp_ri->flags, BGP_PATH_SELECTED)) {
+ curr_select = tmp_ri;
+ break;
+ }
+ }
+
+ if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP
+ && curr_select->sub_type == BGP_ROUTE_IMPORTED)
+ evpn_zebra_install(bgp, vpn,
+ (struct prefix_evpn *)&rn->p,
+ curr_select);
+}
+
/*
* If the local route was not selected evict it and tell zebra to re-add
* the best remote dest.
struct bgp_node *rn,
struct bgp_path_info *local_pi)
{
- struct bgp_path_info *tmp_pi;
- struct bgp_path_info *curr_select = NULL;
- uint8_t flags = 0;
char buf[PREFIX_STRLEN];
/* local path was not picked as the winner; kick it out */
bgp_path_info_reap(rn, local_pi);
/* tell zebra to re-add the best remote path */
- for (tmp_pi = bgp_node_get_bgp_path_info(rn);
- tmp_pi; tmp_pi = tmp_pi->next) {
- if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_SELECTED)) {
- curr_select = tmp_pi;
- break;
- }
- }
- if (curr_select &&
- curr_select->type == ZEBRA_ROUTE_BGP
- && curr_select->sub_type == BGP_ROUTE_IMPORTED) {
- if (curr_select->attr->sticky)
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
- if (curr_select->attr->default_gw)
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
- evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
- curr_select->attr->nexthop, flags,
- mac_mobility_seqnum(curr_select->attr));
- }
+ evpn_zebra_reinstall_best_route(bgp, vpn, rn);
}
/*
* Handle del of a local MACIP.
*/
int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
- struct ipaddr *ip)
+ struct ipaddr *ip, int state)
{
struct bgpevpn *vpn;
struct prefix_evpn p;
+ struct bgp_node *rn;
/* Lookup VNI hash - should exist. */
vpn = bgp_evpn_lookup_vni(bgp, vni);
return -1;
}
- /* Remove EVPN type-2 route and schedule for processing. */
build_evpn_type2_prefix(&p, mac, ip);
- delete_evpn_route(bgp, vpn, &p);
+ if (state == ZEBRA_NEIGH_ACTIVE) {
+ /* Remove EVPN type-2 route and schedule for processing. */
+ delete_evpn_route(bgp, vpn, &p);
+ } else {
+ /* Re-instate the current remote best path if any */
+ rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
+ if (rn)
+ evpn_zebra_reinstall_best_route(bgp, vpn, rn);
+ }
return 0;
}
struct prefix *p, struct bgp_path_info *ri);
extern int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp);
extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
- struct ethaddr *mac, struct ipaddr *ip);
+ struct ethaddr *mac, struct ipaddr *ip,
+ int state);
extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip,
uint8_t flags, uint32_t seq);
!= 0)
continue;
+ /* Make sure the route-map is populated here if not already done */
+ bgp->adv_cmd_rmap[afi][safi].map = map;
+
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug(
"Processing route_map %s update on advertise type5 route command",
rmap_name);
- bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
- bgp_evpn_advertise_type5_routes(bgp, afi, safi);
+
+ if (route_update) {
+ bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
+ bgp_evpn_advertise_type5_routes(bgp, afi, safi);
+ }
}
}
#include "command.h"
#include "lib/json.h"
+#include "lib/zclient.h"
#include "prefix.h"
#include "plist.h"
#include "buffer.h"
return CMD_WARNING;
}
- rv = bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
+ rv = bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, ZEBRA_NEIGH_ACTIVE);
if (rv < 0) {
vty_out(vty, "Internal error\n");
return CMD_WARNING;
switch (ret) {
case BGP_ERR_PEER_GROUP_MEMBER:
vty_out(vty,
- "%% Peer-group AS %u. Cannot configure remote-as for member\n",
- as);
+ "%% Peer-group member cannot override remote-as of peer-group\n");
return CMD_WARNING_CONFIG_FAILED;
case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT:
vty_out(vty,
- "%% The AS# can not be changed from %u to %s, peer-group members must be all internal or all external\n",
- as, as_str);
+ "%% Peer-group members must be all internal or all external\n");
return CMD_WARNING_CONFIG_FAILED;
}
return bgp_vty_return(vty, ret);
if (!CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE)) {
SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE);
SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE);
- UNSET_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE);
+ SET_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE);
}
if (peer_group_name) {
? " replace-as"
: "");
}
- /* peer type internal, external, confed-internal or confed-external */
- if (p->as == p->local_as) {
+ /* peer type internal or confed-internal */
+ if ((p->as == p->local_as) || (p->as_type == AS_INTERNAL)) {
if (use_json) {
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
json_object_boolean_true_add(
else
vty_out(vty, "internal link\n");
}
- } else {
+ /* peer type external or confed-external */
+ } else if (p->as || (p->as_type == AS_EXTERNAL)) {
if (use_json) {
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
json_object_boolean_true_add(
else
vty_out(vty, "external link\n");
}
+ } else {
+ if (use_json)
+ json_object_boolean_true_add(json_neigh,
+ "nbrUnspecifiedLink");
+ else
+ vty_out(vty, "unspecified link\n");
}
/* Description. */
bgp_show_neighbor(vty, bgp, show_all, NULL, NULL,
use_json, json);
}
+ json_object_free(json);
}
if (use_json) {
char buf1[INET6_ADDRSTRLEN];
uint8_t flags = 0;
uint32_t seqnum = 0;
+ int state = 0;
memset(&ip, 0, sizeof(ip));
s = zclient->ibuf;
if (command == ZEBRA_MACIP_ADD) {
flags = stream_getc(s);
seqnum = stream_getl(s);
+ } else {
+ state = stream_getl(s);
}
bgp = bgp_lookup_by_vrf_id(vrf_id);
return 0;
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u seq %u",
+ zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u seq %u state %d",
vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
flags, prefix_mac2str(&mac, buf, sizeof(buf)),
- ipaddr2str(&ip, buf1, sizeof(buf1)), vni, seqnum);
+ ipaddr2str(&ip, buf1, sizeof(buf1)), vni, seqnum,
+ state);
if (command == ZEBRA_MACIP_ADD)
return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip,
flags, seqnum);
else
- return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
+ return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, state);
}
static void bgp_zebra_process_local_ip_prefix(int cmd, struct zclient *zclient,
return BGP_PEER_EBGP;
} else {
- if (peer->as_type != AS_SPECIFIED)
+ if (peer->as_type == AS_UNSPECIFIED) {
+ /* check if in peer-group with AS information */
+ if (peer->group
+ && (peer->group->conf->as_type != AS_UNSPECIFIED)) {
+ if (peer->group->conf->as_type
+ == AS_SPECIFIED) {
+ if (peer->local_as
+ == peer->group->conf->as)
+ return BGP_PEER_IBGP;
+ else
+ return BGP_PEER_EBGP;
+ } else if (peer->group->conf->as_type
+ == AS_INTERNAL)
+ return BGP_PEER_IBGP;
+ else
+ return BGP_PEER_EBGP;
+ }
+ /* no AS information anywhere, let caller know */
+ return BGP_PEER_UNSPECIFIED;
+ } else if (peer->as_type != AS_SPECIFIED)
return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP
: BGP_PEER_EBGP);
/* When this peer is a member of peer-group. */
if (peer->group) {
- if (peer->group->conf->as) {
+ /* peer-group already has AS number/internal/external */
+ if (peer->group->conf->as
+ || peer->group->conf->as_type) {
/* Return peer group's AS number. */
*as = peer->group->conf->as;
return BGP_ERR_PEER_GROUP_MEMBER;
}
- if (peer_sort(peer->group->conf) == BGP_PEER_IBGP) {
- if ((as_type != AS_INTERNAL)
- && (bgp->as != *as)) {
+
+ bgp_peer_sort_t peer_sort_type =
+ peer_sort(peer->group->conf);
+
+ /* Explicit AS numbers used, compare AS numbers */
+ if (as_type == AS_SPECIFIED) {
+ if (((peer_sort_type == BGP_PEER_IBGP)
+ && (bgp->as != *as))
+ || ((peer_sort_type == BGP_PEER_EBGP)
+ && (bgp->as == *as))) {
*as = peer->as;
return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
}
} else {
- if ((as_type != AS_EXTERNAL)
- && (bgp->as == *as)) {
+ /* internal/external used, compare as-types */
+ if (((peer_sort_type == BGP_PEER_IBGP)
+ && (as_type != AS_INTERNAL))
+ || ((peer_sort_type == BGP_PEER_EBGP)
+ && (as_type != AS_EXTERNAL))) {
*as = peer->as;
return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
}
if (peer->as_type == AS_UNSPECIFIED) {
peer->as_type = group->conf->as_type;
peer->as = group->conf->as;
+ peer->sort = group->conf->sort;
}
if (!group->conf->as) {
/* capability extended-nexthop */
if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) {
- if (CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE))
- vty_out(vty,
- " no neighbor %s capability extended-nexthop\n",
- addr);
- else
- vty_out(vty,
- " neighbor %s capability extended-nexthop\n",
- addr);
+ if (!peer->conf_if) {
+ if (CHECK_FLAG(peer->flags_invert,
+ PEER_FLAG_CAPABILITY_ENHE))
+ vty_out(vty,
+ " no neighbor %s capability extended-nexthop\n",
+ addr);
+ else
+ vty_out(vty,
+ " neighbor %s capability extended-nexthop\n",
+ addr);
+ }
}
/* dont-capability-negotiation */
/* IBGP/EBGP identifier. We also have a CONFED peer, which is to say,
a peer who's AS is part of our Confederation. */
typedef enum {
- BGP_PEER_IBGP = 1,
+ BGP_PEER_UNSPECIFIED,
+ BGP_PEER_IBGP,
BGP_PEER_EBGP,
BGP_PEER_INTERNAL,
BGP_PEER_CONFED,
])
], [[#include <libyang/libyang.h>]])
+ac_ld_flag_save="$LDFLAGS"
+LDFLAGS="$LDFLAGS $libyang_LIBS"
+AC_CHECK_FUNC([ly_register_types], [
+ libyang_ext_builtin=true
+ AC_DEFINE([LIBYANG_EXT_BUILTIN], [1], [have ly_register_types()])
+], [
+ libyang_ext_builtin=false
+ AC_MSG_WARN([===== old libyang (before 0.16.74) detected =====])
+ AC_MSG_WARN([The available version of libyang does not seem to support])
+ AC_MSG_WARN([built-in YANG extension modules. This will cause "make check"])
+ AC_MSG_WARN([to fail and may create installation and version mismatch issues.])
+ AC_MSG_WARN([Support for the old mechanism will be removed at some point.])
+ AC_MSG_WARN([Please update libyang to version 0.16.74 or newer.])
+ AC_MSG_WARN([===== old libyang (before 0.16.74) detected =====])
+])
+AM_CONDITIONAL([LIBYANG_EXT_BUILTIN], [$libyang_ext_builtin])
+LDFLAGS="$ac_ld_flag_save"
+
dnl ---------------
dnl configuration rollbacks
dnl ---------------
Note: the libyang dev/devel packages need to be installed in addition
to the libyang core package in order to build FRR successfully.
+.. warning::
+ libyang ABI version 0.16.74 or newer will be required to build FRR in the
+ near future since it significantly eases build and installation
+ considerations. "0.16-r3" is equal to 0.16.105 and will work, "0.16-r2"
+ is equal to 0.16.52 and will stop working. The CI artifacts will be
+ updated shortly.
+
For example, for CentOS 7.x:
.. code-block:: shell
sudo apt install libpcre3-dev
sudo dpkg -i libyang-dev_0.16.46_amd64.deb libyang_0.16.46_amd64.deb
+.. note::
+ For Debian-based systems, the official libyang package requires recent
+ versions of swig (3.0.12) and debhelper (11) which are only available in
+ Debian buster (10). However, libyang packages built on Debian buster can
+ be installed on both Debian jessie (8) and Debian stretch (9), as well as
+ various Ubuntu systems. The python3-yang package will not work, but the
+ other packages (libyang-dev is the one needed for FRR) will.
+
Alternatively, libyang can be built and installed manually by following
the steps below:
#include "hook.h"
#include "module.h"
+ #include "libfrr.h"
+ #include "thread.h"
+
+ static int module_late_init(struct thread_master *master)
+ {
+ /* Do initialization stuff here */
+ return 0;
+ }
static int
module_init (void)
Look for libyang plugins in `dir` [`prefix`/lib/frr/libyang_plugins].
Note that the FRR libyang plugins will be installed here.
+ This option is meaningless with libyang 0.16.74 or newer and will be
+ removed once support for older libyang versions is dropped.
+
When it's desired to run FRR without installing it in the system, it's possible
to configure it as follows to look for YANG modules and libyang plugins in the
compile directory:
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_IF_ADDR_H
+#define __LINUX_IF_ADDR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ifaddrmsg {
+ __u8 ifa_family;
+ __u8 ifa_prefixlen; /* The prefix length */
+ __u8 ifa_flags; /* Flags */
+ __u8 ifa_scope; /* Address scope */
+ __u32 ifa_index; /* Link index */
+};
+
+/*
+ * Important comment:
+ * IFA_ADDRESS is prefix address, rather than local interface address.
+ * It makes no difference for normally configured broadcast interfaces,
+ * but for point-to-point IFA_ADDRESS is DESTINATION address,
+ * local address is supplied in IFA_LOCAL attribute.
+ *
+ * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
+ * If present, the value from struct ifaddrmsg will be ignored.
+ */
+enum {
+ IFA_UNSPEC,
+ IFA_ADDRESS,
+ IFA_LOCAL,
+ IFA_LABEL,
+ IFA_BROADCAST,
+ IFA_ANYCAST,
+ IFA_CACHEINFO,
+ IFA_MULTICAST,
+ IFA_FLAGS,
+ IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */
+ __IFA_MAX,
+};
+
+#define IFA_MAX (__IFA_MAX - 1)
+
+/* ifa_flags */
+#define IFA_F_SECONDARY 0x01
+#define IFA_F_TEMPORARY IFA_F_SECONDARY
+
+#define IFA_F_NODAD 0x02
+#define IFA_F_OPTIMISTIC 0x04
+#define IFA_F_DADFAILED 0x08
+#define IFA_F_HOMEADDRESS 0x10
+#define IFA_F_DEPRECATED 0x20
+#define IFA_F_TENTATIVE 0x40
+#define IFA_F_PERMANENT 0x80
+#define IFA_F_MANAGETEMPADDR 0x100
+#define IFA_F_NOPREFIXROUTE 0x200
+#define IFA_F_MCAUTOJOIN 0x400
+#define IFA_F_STABLE_PRIVACY 0x800
+
+struct ifa_cacheinfo {
+ __u32 ifa_prefered;
+ __u32 ifa_valid;
+ __u32 cstamp; /* created timestamp, hundredths of seconds */
+ __u32 tstamp; /* updated timestamp, hundredths of seconds */
+};
+
+/* backwards compatibility for userspace */
+#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
+#endif
noinst_HEADERS += \
+ include/linux/if_addr.h \
include/linux/if_bridge.h \
include/linux/if_link.h \
include/linux/lwtunnel.h \
DECLARE_HOOK(if_add, (struct interface * ifp), (ifp))
DECLARE_KOOH(if_del, (struct interface * ifp), (ifp))
+#define METRIC_MAX (~0)
+
/* Connected address structure. */
struct connected {
/* Attached interface. */
/* Label for Linux 2.2.X and upper. */
char *label;
+
+ /*
+ * Used for setting the connected route's cost. If the metric
+ * here is set to METRIC_MAX the connected route falls back to
+ * "struct interface"
+ */
+ uint32_t metric;
};
/* Nbr Connected address structure. */
}
$str =~ s/ $//;
push @lines, $str . "\\n\" \\\n";
- push @lines, " \" > - selected route, * - FIB route\\n\\n\"";
+ push @lines, " \" > - selected route, * - FIB route, q - queued route, f - failed route\\n\\n\"";
return join("", @lines);
}
orig = res;
- while (res) {
+ while (res && col < tt->ncols) {
section = strsep(&res, "|");
row[col].text = XSTRDUP(MTYPE_TTABLE, section);
row[col].style = tt->style.cell;
#include "yang_translator.h"
#include "northbound.h"
+#include <libyang/user_types.h>
+
DEFINE_MTYPE(LIB, YANG_MODULE, "YANG module")
DEFINE_MTYPE(LIB, YANG_DATA, "YANG data structure")
zlog(priority, "libyang: %s", msg);
}
+#if CONFDATE > 20190401
+CPP_NOTICE("lib/yang: time to remove non-LIBYANG_EXT_BUILTIN support")
+#endif
+
+#ifdef LIBYANG_EXT_BUILTIN
+extern struct lytype_plugin_list frr_user_types[];
+#endif
+
void yang_init(void)
{
+#ifndef LIBYANG_EXT_BUILTIN
+CPP_NOTICE("lib/yang: deprecated libyang <0.16.74 extension loading in use!")
static char ly_plugin_dir[PATH_MAX];
const char *const *ly_loaded_plugins;
const char *ly_plugin;
snprintf(ly_plugin_dir, sizeof(ly_plugin_dir), "%s=%s",
"LIBYANG_USER_TYPES_PLUGINS_DIR", LIBYANG_PLUGINS_PATH);
putenv(ly_plugin_dir);
+#endif
/* Initialize libyang global parameters that affect all containers. */
ly_set_log_clb(ly_log_cb, 1);
ly_log_options(LY_LOLOG | LY_LOSTORE);
+#ifdef LIBYANG_EXT_BUILTIN
+ if (ly_register_types(frr_user_types, "frr_user_types")) {
+ flog_err(EC_LIB_LIBYANG_PLUGIN_LOAD,
+ "ly_register_types() failed");
+ exit(1);
+ }
+#endif
+
/* Initialize libyang container for native models. */
ly_native_ctx =
ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD);
ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL);
ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
+#ifndef LIBYANG_EXT_BUILTIN
/* Detect if the required libyang plugin(s) were loaded successfully. */
ly_loaded_plugins = ly_get_loaded_plugins();
for (size_t i = 0; (ly_plugin = ly_loaded_plugins[i]); i++) {
"%s: failed to load frr_user_types.so", __func__);
exit(1);
}
+#endif
yang_translator_init();
}
#define ZEBRA_MACIP_TYPE_ROUTER_FLAG 0x04 /* Router Flag - proxy NA */
#define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG 0x08 /* Override Flag */
+enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
+
struct zclient_options {
bool receive_notify;
};
THREAD_OFF(oi->thread_send_hello);
THREAD_OFF(oi->thread_send_lsupdate);
THREAD_OFF(oi->thread_send_lsack);
+ THREAD_OFF(oi->thread_sso);
ospf6_lsdb_remove_all(oi->lsdb);
ospf6_lsdb_remove_all(oi->lsupdate_list);
THREAD_OFF(oi->thread_send_hello);
THREAD_OFF(oi->thread_send_lsupdate);
THREAD_OFF(oi->thread_send_lsack);
+ THREAD_OFF(oi->thread_sso);
THREAD_OFF(oi->thread_network_lsa);
THREAD_OFF(oi->thread_link_lsa);
if (if_is_operative(ifp)
&& (ospf6_interface_get_linklocal_address(oi->interface)
|| if_is_loopback(oi->interface)))
- thread_add_event(master, interface_up, oi, 0, NULL);
+ thread_execute(master, interface_up, oi, 0);
else
- thread_add_event(master, interface_down, oi, 0, NULL);
+ thread_execute(master, interface_down, oi, 0);
return;
}
oi = (struct ospf6_interface *)THREAD_ARG(thread);
assert(oi && oi->interface);
+ /*
+ * Remove old pointer. If this thread wasn't a timer this
+ * operation won't make a difference, because it is already NULL.
+ */
+ oi->thread_sso = NULL;
+
if (IS_OSPF6_DEBUG_INTERFACE)
zlog_debug("Interface Event %s: [InterfaceUp]",
oi->interface->name);
return 0;
}
+#ifdef __FreeBSD__
+ /*
+ * XXX: Schedule IPv6 group join for later, otherwise we might
+ * lose the multicast group registration caused by IPv6 group
+ * leave race.
+ */
+ if (oi->sso_try_cnt == 0) {
+ oi->sso_try_cnt++;
+ zlog_info("Scheduling %s for sso", oi->interface->name);
+ thread_add_timer(master, interface_up, oi,
+ OSPF6_INTERFACE_SSO_RETRY_INT,
+ &oi->thread_sso);
+ return 0;
+ }
+#endif /* __FreeBSD__ */
+
/* Join AllSPFRouters */
if (ospf6_sso(oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP)
< 0) {
"Scheduling %s for sso retry, trial count: %d",
oi->interface->name, oi->sso_try_cnt);
thread_add_timer(master, interface_up, oi,
- OSPF6_INTERFACE_SSO_RETRY_INT, NULL);
+ OSPF6_INTERFACE_SSO_RETRY_INT,
+ &oi->thread_sso);
}
return 0;
}
/* Stop Hellos */
THREAD_OFF(oi->thread_send_hello);
+ /* Stop trying to set socket options. */
+ THREAD_OFF(oi->thread_sso);
+
/* Leave AllSPFRouters */
if (oi->state > OSPF6_INTERFACE_DOWN)
ospf6_sso(oi->interface->ifindex, &allspfrouters6,
SET_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE);
THREAD_OFF(oi->thread_send_hello);
+ THREAD_OFF(oi->thread_sso);
for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
THREAD_OFF(on->inactivity_timer);
UNSET_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE);
THREAD_OFF(oi->thread_send_hello);
- oi->thread_send_hello = NULL;
+ THREAD_OFF(oi->thread_sso);
thread_add_event(master, ospf6_hello_send, oi, 0,
&oi->thread_send_hello);
}
/* Reset the interface */
- thread_add_event(master, interface_down, oi, 0, NULL);
- thread_add_event(master, interface_up, oi, 0, NULL);
+ thread_execute(master, interface_down, oi, 0);
+ thread_execute(master, interface_up, oi, 0);
return CMD_SUCCESS;
}
oi->type = type;
/* Reset the interface */
- thread_add_event(master, interface_down, oi, 0, NULL);
- thread_add_event(master, interface_up, oi, 0, NULL);
+ thread_execute(master, interface_down, oi, 0);
+ thread_execute(master, interface_up, oi, 0);
return CMD_SUCCESS;
}
zlog_debug("Interface %s: clear by reset", ifp->name);
/* Reset the interface */
- thread_add_event(master, interface_down, oi, 0, NULL);
- thread_add_event(master, interface_up, oi, 0, NULL);
+ thread_execute(master, interface_down, oi, 0);
+ thread_execute(master, interface_up, oi, 0);
}
/* Clear interface */
/* Interface socket setting trial counter, resets on success */
uint8_t sso_try_cnt;
+ struct thread *thread_sso;
/* OSPF6 Interface flag */
char flag;
.description = "OSPF has attempted to change states when it should not be able to",
.suggestion = "Gather log files and open an issue",
},
+ {
+ .code = EC_OSPF_LARGE_HELLO,
+ .title = "OSPF Encountered a Large Hello",
+ .description = "OSPF attempted to send a Hello larger than MTU "
+ "but did not",
+ .suggestion = "Too many neighbors configured on a single interface."
+ " Suggestion is to decrease the number of neighbors on"
+ " a single interface/subnet"
+ },
{
.code = END_FERR,
}
EC_OSPF_LSA_MISSING,
EC_OSPF_PTP_NEIGHBOR,
EC_OSPF_LSA_SIZE,
+ EC_OSPF_LARGE_HELLO,
};
extern void ospf_error_init(void);
.prefix4))
flag = 1;
+ /* Hello packet overflows interface MTU. */
+ if (length + sizeof(uint32_t)
+ > ospf_packet_max(oi)) {
+ flog_err(
+ EC_OSPF_LARGE_HELLO,
+ "Oversized Hello packet!"
+ " Larger than MTU. Not sending it out");
+ return 0;
+ }
+
stream_put_ipv4(
s,
nbr->router_id
/* Prepare OSPF Hello body. */
length += ospf_make_hello(oi, op->s);
+ if (length == OSPF_HEADER_SIZE) {
+ /* Hello overshooting MTU */
+ ospf_packet_free(op);
+ return;
+ }
/* Fill OSPF header. */
ospf_fill_header(oi, op->s, length);
TestFlag.okfail('peer\\advertisement-interval')
TestFlag.okfail('peer\\capability dynamic')
TestFlag.okfail('peer\\capability extended-nexthop')
-TestFlag.okfail('peer\\capability extended-nexthop')
+#TestFlag.okfail('peer\\capability extended-nexthop')
TestFlag.okfail('peer\\description')
TestFlag.okfail('peer\\disable-connected-check')
TestFlag.okfail('peer\\dont-capability-negotiate')
#
# libyang user types
#
+
+if LIBYANG_EXT_BUILTIN
+lib_libfrr_la_SOURCES += yang/libyang_plugins/frr_user_types.c
+else
libyang_plugins_LTLIBRARIES += yang/libyang_plugins/frr_user_types.la
+endif
yang_libyang_plugins_frr_user_types_la_CFLAGS = $(WERROR)
yang_libyang_plugins_frr_user_types_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
.ifindex = ifp->ifindex,
.vrf_id = ifp->vrf_id,
};
+ uint32_t metric;
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
return;
break;
}
+ metric = (ifc->metric < (uint32_t)METRIC_MAX) ?
+ ifc->metric : ifp->metric;
rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p,
- NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
+ NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0);
rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p,
- NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
+ NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0);
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
char buf[PREFIX_STRLEN];
/* Add connected IPv4 route to the interface. */
void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
uint16_t prefixlen, struct in_addr *broad,
- const char *label)
+ const char *label, uint32_t metric)
{
struct prefix_ipv4 *p;
struct connected *ifc;
ifc = connected_new();
ifc->ifp = ifp;
ifc->flags = flags;
+ ifc->metric = metric;
/* If we get a notification from the kernel,
* we can safely assume the address is known to the kernel */
SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
/* Add connected IPv6 route to the interface. */
void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
struct in6_addr *broad, uint16_t prefixlen,
- const char *label)
+ const char *label, uint32_t metric)
{
struct prefix_ipv6 *p;
struct connected *ifc;
ifc = connected_new();
ifc->ifp = ifp;
ifc->flags = flags;
+ ifc->metric = metric;
/* If we get a notification from the kernel,
* we can safely assume the address is known to the kernel */
SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
extern void connected_add_ipv4(struct interface *ifp, int flags,
struct in_addr *addr, uint16_t prefixlen,
- struct in_addr *broad, const char *label);
+ struct in_addr *broad, const char *label,
+ uint32_t metric);
extern void connected_delete_ipv4(struct interface *ifp, int flags,
struct in_addr *addr, uint16_t prefixlen,
extern void connected_add_ipv6(struct interface *ifp, int flags,
struct in6_addr *address, struct in6_addr *broad,
- uint16_t prefixlen, const char *label);
+ uint16_t prefixlen, const char *label,
+ uint32_t metric);
extern void connected_delete_ipv6(struct interface *ifp,
struct in6_addr *address,
struct in6_addr *broad, uint16_t prefixlen);
}
connected_add_ipv4(ifp, flags, &addr->sin_addr,
- prefixlen, dest_pnt, NULL);
+ prefixlen, dest_pnt, NULL,
+ METRIC_MAX);
}
if (ifap->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *addr;
#endif
connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL,
- prefixlen, NULL);
+ prefixlen, NULL, METRIC_MAX);
}
}
/* Set address to the interface. */
if (af == AF_INET)
connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen,
- (struct in_addr *)dest_pnt, label);
+ (struct in_addr *)dest_pnt, label,
+ METRIC_MAX);
else if (af == AF_INET6)
connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL,
- prefixlen, label);
+ prefixlen, label, METRIC_MAX);
return 0;
}
uint8_t flags = 0;
char *label = NULL;
struct zebra_ns *zns;
+ uint32_t metric = METRIC_MAX;
zns = zebra_ns_lookup(ns_id);
ifa = NLMSG_DATA(h);
if (label && strcmp(ifp->name, label) == 0)
label = NULL;
+ if (tb[IFA_RT_PRIORITY])
+ metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]);
+
/* Register interface address to the interface. */
if (ifa->ifa_family == AF_INET) {
if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) {
if (h->nlmsg_type == RTM_NEWADDR)
connected_add_ipv4(ifp, flags, (struct in_addr *)addr,
ifa->ifa_prefixlen,
- (struct in_addr *)broad, label);
+ (struct in_addr *)broad, label,
+ metric);
else
connected_delete_ipv4(
ifp, flags, (struct in_addr *)addr,
connected_add_ipv6(ifp, flags,
(struct in6_addr *)addr,
(struct in6_addr *)broad,
- ifa->ifa_prefixlen, label);
+ ifa->ifa_prefixlen, label,
+ metric);
} else
connected_delete_ipv6(ifp, (struct in6_addr *)addr,
(struct in6_addr *)broad,
connected_add_ipv4(ifp, flags, &addr.sin.sin_addr,
ip_masklen(mask.sin.sin_addr),
&brd.sin.sin_addr,
- (isalias ? ifname : NULL));
+ (isalias ? ifname : NULL),
+ METRIC_MAX);
else
connected_delete_ipv4(ifp, flags, &addr.sin.sin_addr,
ip_masklen(mask.sin.sin_addr),
connected_add_ipv6(ifp, flags, &addr.sin6.sin6_addr,
NULL,
ip6_masklen(mask.sin6.sin6_addr),
- (isalias ? ifname : NULL));
+ (isalias ? ifname : NULL),
+ METRIC_MAX);
else
connected_delete_ipv6(ifp, &addr.sin6.sin6_addr, NULL,
ip6_masklen(mask.sin6.sin6_addr));
*/
if (cmd != RTM_ADD && cmd != RTM_DELETE) {
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("%s: %s odd command %s for flags %d",
+ zlog_debug("%s: %s odd command %s",
__func__, prefix_buf,
- lookup_msg(rtm_type_str, cmd, NULL),
- nexthop->flags);
+ lookup_msg(rtm_type_str, cmd, NULL));
return 0;
}
if (dplane_ctx_get_src(ctx) != NULL) {
zlog_err("route add: IPv6 sourcedest routes unsupported!");
- res = ZEBRA_DPLANE_REQUEST_FAILURE;
- goto done;
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
frr_elevate_privs(&zserv_privs) {
}
} /* Elevated privs */
-done:
-
return res;
}
if ((cmd == RTM_NEWROUTE
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|| (cmd == RTM_DELROUTE
- && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))) {
+ && CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))) {
netlink_route_info_add_nh(ri, nexthop);
}
}
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
resolved = 0;
for (ALL_NEXTHOPS(match->ng, newhop)) {
- if (!CHECK_FLAG(newhop->flags,
- NEXTHOP_FLAG_FIB))
+ if (!CHECK_FLAG(match->status,
+ ROUTE_ENTRY_INSTALLED))
continue;
if (CHECK_FLAG(newhop->flags,
NEXTHOP_FLAG_RECURSIVE))
} else if (re->type == ZEBRA_ROUTE_STATIC) {
resolved = 0;
for (ALL_NEXTHOPS(match->ng, newhop)) {
- if (!CHECK_FLAG(newhop->flags,
- NEXTHOP_FLAG_FIB))
+ if (!CHECK_FLAG(match->status,
+ ROUTE_ENTRY_INSTALLED))
continue;
if (set) {
struct route_table *table;
struct route_node *rn;
struct route_entry *match = NULL;
- struct nexthop *newhop;
/* Lookup table. */
table = zebra_vrf_table(afi, safi, vrf_id);
route_lock_node(rn);
} else {
if (match->type != ZEBRA_ROUTE_CONNECT) {
- int found = 0;
- for (ALL_NEXTHOPS(match->ng, newhop))
- if (CHECK_FLAG(newhop->flags,
- NEXTHOP_FLAG_FIB)) {
- found = 1;
- break;
- }
- if (!found)
+ if (!CHECK_FLAG(match->status,
+ ROUTE_ENTRY_INSTALLED))
return NULL;
}
struct route_table *table;
struct route_node *rn;
struct route_entry *match = NULL;
- struct nexthop *nexthop;
rib_dest_t *dest;
/* Lookup table. */
if (match->type == ZEBRA_ROUTE_CONNECT)
return match;
- for (ALL_NEXTHOPS(match->ng, nexthop))
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- return match;
+ if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED))
+ return match;
return NULL;
}
switch (ret) {
case ZEBRA_DPLANE_REQUEST_QUEUED:
+ SET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ if (old)
+ SET_FLAG(old->status, ROUTE_ENTRY_QUEUED);
if (zvrf)
zvrf->installs_queued++;
break;
struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
if (info->safi != SAFI_UNICAST) {
+ UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
for (ALL_NEXTHOPS(re->ng, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
return;
if (!RIB_SYSTEM_ROUTE(re))
rib_uninstall_kernel(rn, re);
+ else
+ UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
dest->selected_fib = NULL;
if (!RIB_SYSTEM_ROUTE(old))
rib_uninstall_kernel(rn, old);
else {
+ UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED);
/*
* We are setting this to NULL here
* because that is what we traditionally
rib_install_kernel(rn, new, old);
} else {
+ UNSET_FLAG(new->status, ROUTE_ENTRY_INSTALLED);
/*
* We do not need to install the
* selected route because it
if (RIB_SYSTEM_ROUTE(new)) {
if (!RIB_SYSTEM_ROUTE(old))
rib_uninstall_kernel(rn, old);
+ else
+ UNSET_FLAG(
+ old->status,
+ ROUTE_ENTRY_INSTALLED);
} else {
+ UNSET_FLAG(old->status,
+ ROUTE_ENTRY_INSTALLED);
for (nexthop = old->ng.nexthop; nexthop;
nexthop = nexthop->next)
UNSET_FLAG(nexthop->flags,
if (!RIB_SYSTEM_ROUTE(old))
rib_uninstall_kernel(rn, old);
- else
+ else {
+ UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED);
dest->selected_fib = NULL;
+ }
}
} else {
/*
* is ready
* to add routes.
*/
- if (!RIB_SYSTEM_ROUTE(new)) {
- bool in_fib = false;
-
- for (ALL_NEXTHOPS(new->ng, nexthop))
- if (CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_FIB)) {
- in_fib = true;
- break;
- }
- if (!in_fib)
- rib_install_kernel(rn, new, NULL);
- }
+ if (!RIB_SYSTEM_ROUTE(new)
+ && !CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED))
+ rib_install_kernel(rn, new, NULL);
}
/* Update prior route. */
/*
* Check sequence number(s) to detect stale results before continuing
*/
- if (re && (re->dplane_sequence != dplane_ctx_get_seq(ctx))) {
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
- zlog_debug("%u:%s Stale dplane result for re %p",
- dplane_ctx_get_vrf(ctx), dest_str, re);
- }
- re = NULL;
- }
-
- if (old_re &&
- (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx))) {
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
- zlog_debug("%u:%s Stale dplane result for old_re %p",
- dplane_ctx_get_vrf(ctx), dest_str, old_re);
- }
- old_re = NULL;
- }
-
- /*
- * Here's sort of a tough one: the route update result is stale.
- * Is it better to use the context block info to generate
- * redist and owner notification, or is it better to wait
- * for the up-to-date result to arrive?
- */
- if (re == NULL) {
- /* TODO -- for now, only expose up-to-date results */
- goto done;
+ if (re) {
+ if (re->dplane_sequence != dplane_ctx_get_seq(ctx)) {
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("%u:%s Stale dplane result for re %p",
+ dplane_ctx_get_vrf(ctx),
+ dest_str, re);
+ } else
+ UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ }
+
+ if (old_re) {
+ if (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx)) {
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("%u:%s Stale dplane result for old_re %p",
+ dplane_ctx_get_vrf(ctx),
+ dest_str, old_re);
+ } else
+ UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
}
switch (op) {
case DPLANE_OP_ROUTE_INSTALL:
case DPLANE_OP_ROUTE_UPDATE:
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
+ if (re) {
+ UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED);
+ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ }
+ if (old_re) {
+ UNSET_FLAG(old_re->status, ROUTE_ENTRY_FAILED);
+ UNSET_FLAG(old_re->status,
+ ROUTE_ENTRY_INSTALLED);
+ }
/* Update zebra nexthop FIB flag for each
* nexthop that was installed.
*/
for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
ctx_nexthop)) {
+ if (!re)
+ continue;
+
for (ALL_NEXTHOPS(re->ng, nexthop)) {
if (nexthop_same(ctx_nexthop, nexthop))
break;
* 'old' context info was stale, 'old_re' will be
* NULL here and that delete will not be sent.
*/
- redistribute_update(dest_pfx, src_pfx, re, old_re);
+ if (re)
+ redistribute_update(dest_pfx, src_pfx,
+ re, old_re);
/* Notify route owner */
- zsend_route_notify_owner(re, dest_pfx,
- ZAPI_ROUTE_INSTALLED);
+ zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED);
} else {
- zsend_route_notify_owner(re, dest_pfx,
- ZAPI_ROUTE_FAIL_INSTALL);
+ if (re)
+ SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
+ if (old_re)
+ SET_FLAG(old_re->status, ROUTE_ENTRY_FAILED);
+ if (re)
+ zsend_route_notify_owner(re, dest_pfx,
+ ZAPI_ROUTE_FAIL_INSTALL);
zlog_warn("%u:%s: Route install failed",
dplane_ctx_get_vrf(ctx),
}
break;
case DPLANE_OP_ROUTE_DELETE:
+ if (re)
+ SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
/*
* In the delete case, the zebra core datastructs were
* updated (or removed) at the time the delete was issued,
* so we're just notifying the route owner.
*/
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
+ if (re) {
+ UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED);
+ }
zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED);
if (zvrf)
zvrf->removals++;
} else {
+ if (re)
+ SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
zsend_route_notify_owner_ctx(ctx,
ZAPI_ROUTE_REMOVE_FAIL);
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
? "ACTIVE "
: ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
+ (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
? "FIB "
: ""),
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
}
/* If this route is kernel route, set FIB flag to the route. */
- if (RIB_SYSTEM_ROUTE(re))
+ if (RIB_SYSTEM_ROUTE(re)) {
+ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
/* Link new re to node.*/
if (IS_ZEBRA_DEBUG_RIB) {
rn, fib, fib->type);
}
if (allow_delete) {
+ UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED);
/* Unset flags. */
for (rtnh = fib->ng.nexthop; rtnh;
rtnh = rtnh->next)
* to a different spot (ie startup )
* this decision needs to be revisited
*/
+ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
for (ALL_NEXTHOPS(re->ng, nexthop))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
struct zserv *client;
char bufn[INET6_ADDRSTRLEN];
struct listnode *node;
- struct nexthop *nexthop;
if (re && (rnh->state == NULL)) {
- for (ALL_NEXTHOPS(re->ng, nexthop))
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
- state_changed = 1;
- break;
- }
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
+ state_changed = 1;
} else if (!re && (rnh->state != NULL))
state_changed = 1;
* check in a couple of places, so this is a single home for the logic we
* use.
*/
-static bool rnh_nexthop_valid(const struct nexthop *nh)
+static bool rnh_nexthop_valid(const struct route_entry *re,
+ const struct nexthop *nh)
{
- return (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
+ return (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
&& CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE));
}
* have an installed nexthop to be useful.
*/
for (ALL_NEXTHOPS(re->ng, nexthop)) {
- if (rnh_nexthop_valid(nexthop))
+ if (rnh_nexthop_valid(re, nexthop))
break;
}
state->distance = re->distance;
state->metric = re->metric;
state->vrf_id = re->vrf_id;
+ state->status = re->status;
route_entry_copy_nexthops(state, re->ng.nexthop);
rnh->state = state;
nump = stream_get_endp(s);
stream_putc(s, 0);
for (ALL_NEXTHOPS(re->ng, nh))
- if (rnh_nexthop_valid(nh)) {
+ if (rnh_nexthop_valid(re, nh)) {
stream_putl(s, nh->vrf_id);
stream_putc(s, nh->type);
switch (nh->type) {
return CMD_SUCCESS;
}
+static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
+{
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
+ if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE))
+ return '*';
+ else
+ return ' ';
+ }
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED)) {
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
+ return 'q';
+
+ return 'f';
+ }
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
+ return 'q';
+
+ return ' ';
+}
+
/* New RIB. Detailed information for IPv4 route. */
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
int mcast)
char addrstr[32];
vty_out(vty, " %c%s",
- CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
- ? CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_DUPLICATE)
- ? ' '
- : '*'
- : ' ',
+ re_status_output_char(re, nexthop),
nexthop->rparent ? " " : "");
switch (nexthop->type) {
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
json_object_boolean_true_add(json_route, "selected");
+ json_object_int_add(json_route, "distance",
+ re->distance);
+ json_object_int_add(json_route, "metric", re->metric);
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
+ json_object_boolean_true_add(json_route, "installed");
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED))
+ json_object_boolean_true_add(json_route, "failed");
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
+ json_object_boolean_true_add(json_route, "queued");
+
if (re->type != ZEBRA_ROUTE_CONNECT) {
json_object_int_add(json_route, "distance",
re->distance);
CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)
? '>'
: ' ',
- CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
- ? '*'
- : ' ',
+ re_status_output_char(re, nexthop),
srcdest_rnode2str(rn, buf, sizeof buf));
/* Distance and metric display. */
- if (re->type != ZEBRA_ROUTE_CONNECT)
+ if (((re->type == ZEBRA_ROUTE_CONNECT) &&
+ (re->distance || re->metric)) ||
+ (re->type != ZEBRA_ROUTE_CONNECT))
len += vty_out(vty, " [%u/%u]", re->distance,
re->metric);
} else {
vty_out(vty, " %c%*c",
- CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
- ? CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_DUPLICATE)
- ? ' '
- : '*'
- : ' ',
+ re_status_output_char(re, nexthop),
len - 3 + (2 * nexthop_level(nexthop)), ' ');
}
* In case of ECMP, count only once.
*/
cnt = 0;
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
+ fib_cnt[ZEBRA_ROUTE_TOTAL]++;
+ fib_cnt[re->type]++;
+ }
for (nexthop = re->ng.nexthop; (!cnt && nexthop);
nexthop = nexthop->next) {
cnt++;
rib_cnt[ZEBRA_ROUTE_TOTAL]++;
rib_cnt[re->type]++;
- if (CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_FIB)) {
- fib_cnt[ZEBRA_ROUTE_TOTAL]++;
- fib_cnt[re->type]++;
- }
if (re->type == ZEBRA_ROUTE_BGP
&& CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP)) {
rib_cnt[ZEBRA_ROUTE_IBGP]++;
- if (CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_FIB))
+ if (CHECK_FLAG(re->status,
+ ROUTE_ENTRY_INSTALLED))
fib_cnt[ZEBRA_ROUTE_IBGP]++;
}
}
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
struct ipaddr *ip, uint8_t flags,
- uint32_t seq, uint16_t cmd);
+ uint32_t seq, int state, uint16_t cmd);
static unsigned int neigh_hash_keymake(void *p);
static void *zvni_neigh_alloc(void *p);
static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
uint8_t flags, uint32_t seq);
static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
struct ethaddr *macaddr,
- uint8_t flags);
+ uint8_t flags, int state);
static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n);
static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
static zebra_vni_t *zvni_from_svi(struct interface *ifp,
*/
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
struct ipaddr *ip, uint8_t flags,
- uint32_t seq, uint16_t cmd)
+ uint32_t seq, int state, uint16_t cmd)
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
if (cmd == ZEBRA_MACIP_ADD) {
stream_putc(s, flags); /* sticky mac/gateway mac */
stream_putl(s, seq); /* sequence number */
+ } else {
+ stream_putl(s, state); /* state - active/inactive */
}
&& IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
zvni_neigh_send_del_to_client(wctx->zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, n->state);
if (wctx->uninstall)
zvni_neigh_uninstall(wctx->zvni, n);
ZEBRA_NEIGH_SET_INACTIVE(n);
n->loc_seq = 0;
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, ZEBRA_NEIGH_ACTIVE);
}
}
}
ZEBRA_NEIGH_SET_INACTIVE(n);
n->loc_seq = 0;
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, ZEBRA_NEIGH_ACTIVE);
}
}
}
SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- seq, ZEBRA_MACIP_ADD);
+ seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
}
/*
* Inform BGP about local neighbor deletion.
*/
static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
- struct ethaddr *macaddr, uint8_t flags)
+ struct ethaddr *macaddr, uint8_t flags,
+ int state)
{
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- 0, ZEBRA_MACIP_DEL);
+ 0, state, ZEBRA_MACIP_DEL);
}
/*
/* Remove neighbor from BGP. */
zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
- ZEBRA_MACIP_TYPE_GW);
+ ZEBRA_MACIP_TYPE_GW, ZEBRA_NEIGH_ACTIVE);
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
*/
if (IS_ZEBRA_NEIGH_ACTIVE(n))
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, n->state);
old_zmac = zvni_mac_lookup(zvni, &n->emac);
if (old_zmac) {
old_mac_seq = CHECK_FLAG(old_zmac->flags,
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
- seq, ZEBRA_MACIP_ADD);
+ seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
}
/*
static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr)
{
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */,
- 0 /* seq */, ZEBRA_MACIP_DEL);
+ 0 /* seq */, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_DEL);
}
/*
IS_ZEBRA_NEIGH_ACTIVE(n))
zvni_neigh_send_del_to_client(
zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, n->state);
/* update neigh list for macs */
old_mac = zvni_mac_lookup(zvni, &n->emac);
}
/* Remove neighbor from BGP. */
- if (IS_ZEBRA_NEIGH_ACTIVE(n))
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0);
+ zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
+ 0, n->state);
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
struct json_object *json;
};
-enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
+#define IS_ZEBRA_NEIGH_ACTIVE(n) (n->state == ZEBRA_NEIGH_ACTIVE)
-#define IS_ZEBRA_NEIGH_ACTIVE(n) n->state == ZEBRA_NEIGH_ACTIVE
-
-#define IS_ZEBRA_NEIGH_INACTIVE(n) n->state == ZEBRA_NEIGH_INACTIVE
+#define IS_ZEBRA_NEIGH_INACTIVE(n) (n->state == ZEBRA_NEIGH_INACTIVE)
#define ZEBRA_NEIGH_SET_ACTIVE(n) n->state = ZEBRA_NEIGH_ACTIVE