UNSET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
}
+/*
+ * Lookup L3-VNI
+ */
+bool bgp_evpn_lookup_l3vni_l2vni_table(vni_t vni)
+{
+ struct list *inst = bm->bgp;
+ struct listnode *node;
+ struct bgp *bgp_vrf;
+
+ for (ALL_LIST_ELEMENTS_RO(inst, node, bgp_vrf)) {
+ if (bgp_vrf->l3vni == vni)
+ return true;
+ }
+
+ return false;
+}
+
/*
* Lookup VNI.
*/
extern struct evpnes *bgp_evpn_es_new(struct bgp *bgp, esi_t *esi,
struct ipaddr *originator_ip);
extern void bgp_evpn_es_free(struct bgp *bgp, struct evpnes *es);
+extern bool bgp_evpn_lookup_l3vni_l2vni_table(vni_t vni);
#endif /* _BGP_EVPN_PRIVATE_H */
vpn = bgp_evpn_lookup_vni(bgp, vni);
if (!vpn) {
+ /* Check if this L2VNI is already configured as L3VNI */
+ if (bgp_evpn_lookup_l3vni_l2vni_table(vni)) {
+ flog_err(BGP_ERR_VNI,
+ "%u: Failed to create L2VNI %u, it is configured as L3VNI",
+ bgp->vrf_id, vni);
+ return NULL;
+ }
+
/* tenant vrf will be updated when we get local_vni_add from
* zebra
*/
if (BGP_DEBUG(flowspec, FLOWSPEC)) {
char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
- char local_string[BGP_FLOWSPEC_NLRI_STRING_MAX * 2];
+ char local_string[BGP_FLOWSPEC_NLRI_STRING_MAX*2+16];
char ec_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
char *s = NULL;
struct listnode *node;
struct bgp_pbr_match_entry *bpme;
struct bgp_pbr_match *bpm;
- int unit = 0;
+ bool list_began = false;
struct list *list_bpm;
list_bpm = list_new();
if (listnode_lookup(list_bpm, bpm))
continue;
listnode_add(list_bpm, bpm);
- if (unit == 0)
+ if (!list_began) {
vty_out(vty, " (");
- else
+ list_began = true;
+ } else
vty_out(vty, ", ");
vty_out(vty, "%s", bpm->ipset_name);
- unit++;
}
- if (unit)
+ if (list_began)
vty_out(vty, ")");
vty_out(vty, "\n");
list_delete_and_null(&list_bpm);
listener->fd = sock;
/* this socket needs a change of ns. record bgp back pointer */
- if (bgp->vrf_id != VRF_DEFAULT && vrf_is_mapped_on_netns(bgp->vrf_id))
+ if (bgp->vrf_id != VRF_DEFAULT && vrf_is_mapped_on_netns(
+ vrf_lookup_by_id(bgp->vrf_id)))
listener->bgp = bgp;
memcpy(&listener->su, sa, salen);
? "!" : "",
bpf->dscp->val);
}
- zlog_info("BGP: %s FS PBR from %s to %s, %s %s",
+ zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
add ? "adding" : "removing",
bpf->src == NULL ? "<all>" :
prefix2str(bpf->src, bufsrc, sizeof(bufsrc)),
bgp_pbr_match_alloc_intern);
/* new, then self allocate ipset_name and unique */
- if (bpm && bpm->unique == 0) {
+ if (bpm->unique == 0) {
bpm->unique = ++bgp_pbr_match_counter_unique;
/* 0 value is forbidden */
sprintf(bpm->ipset_name, "match%p", bpm);
temp2.src_port_max = src_port ? src_port->max_port : 0;
temp2.dst_port_max = dst_port ? dst_port->max_port : 0;
temp2.proto = bpf->protocol;
- if (bpm)
- bpme = hash_get(bpm->entry_hash, &temp2,
- bgp_pbr_match_entry_alloc_intern);
- if (bpme && bpme->unique == 0) {
+ bpme = hash_get(bpm->entry_hash, &temp2,
+ bgp_pbr_match_entry_alloc_intern);
+ if (bpme->unique == 0) {
bpme->unique = ++bgp_pbr_match_entry_counter_unique;
/* 0 value is forbidden */
bpme->backpointer = bpm;
bpme_found = true;
/* already installed */
- if (bpme_found && bpme) {
+ if (bpme_found) {
struct bgp_info_extra *extra = bgp_info_extra_get(binfo);
if (extra && extra->bgp_fs_pbr &&
#include "queue.h"
#include "memory.h"
#include "lib/json.h"
+#include "lib_errors.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
if (e->parent) {
struct bgp_info *bi = (struct bgp_info *)e->parent;
- if (bi->net)
- bi->net = bgp_unlock_node((struct bgp_node *)bi->net);
+ if (bi->net) {
+ /* FIXME: since multiple e may have the same e->parent
+ * and e->parent->net is holding a refcount for each
+ * of them, we need to do some fudging here.
+ *
+ * WARNING: if bi->net->lock drops to 0, bi may be
+ * freed as well (because bi->net was holding the
+ * last reference to bi) => write after free!
+ */
+ unsigned refcount;
+
+ bi = bgp_info_lock(bi);
+ refcount = bi->net->lock - 1;
+ bgp_unlock_node((struct bgp_node *)bi->net);
+ if (!refcount)
+ bi->net = NULL;
+ bgp_info_unlock(bi);
+ }
bgp_info_unlock(e->parent);
e->parent = NULL;
}
bgp_unlock(e->bgp_orig);
if ((*extra)->bgp_fs_pbr)
- list_delete_all_node((*extra)->bgp_fs_pbr);
- (*extra)->bgp_fs_pbr = NULL;
+ list_delete_and_null(&((*extra)->bgp_fs_pbr));
XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra);
*extra = NULL;
/* slight hack, but more robust against errors. */
if (ri->peer->pcount[table->afi][table->safi])
ri->peer->pcount[table->afi][table->safi]--;
- else {
- zlog_warn(
- "%s: Asked to decrement 0 prefix count for peer %s",
- __func__, ri->peer->host);
- zlog_backtrace(LOG_WARNING);
- zlog_warn("%s: Please report to Quagga bugzilla",
- __func__);
- }
+ else
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "Asked to decrement 0 prefix count for peer");
} else if (BGP_INFO_COUNTABLE(ri)
&& !CHECK_FLAG(ri->flags, BGP_INFO_COUNTED)) {
SET_FLAG(ri->flags, BGP_INFO_COUNTED);
#define FILTER_EXIST_WARN(F, f, filter) \
if (BGP_DEBUG(update, UPDATE_IN) && !(F##_IN(filter))) \
- zlog_warn("%s: Could not find configured input %s-list %s!", \
- peer->host, #f, F##_IN_NAME(filter));
+ zlog_debug("%s: Could not find configured input %s-list %s!", \
+ peer->host, #f, F##_IN_NAME(filter));
if (DISTRIBUTE_IN_NAME(filter)) {
FILTER_EXIST_WARN(DISTRIBUTE, distribute, filter);
#define FILTER_EXIST_WARN(F, f, filter) \
if (BGP_DEBUG(update, UPDATE_OUT) && !(F##_OUT(filter))) \
- zlog_warn("%s: Could not find configured output %s-list %s!", \
- peer->host, #f, F##_OUT_NAME(filter));
+ zlog_debug("%s: Could not find configured output %s-list %s!", \
+ peer->host, #f, F##_OUT_NAME(filter));
if (DISTRIBUTE_OUT_NAME(filter)) {
FILTER_EXIST_WARN(DISTRIBUTE, distribute, filter);
vty_out(vty, " \"routeDistinguishers\" : {");
++*json_header_depth;
}
- json_paths = json_object_new_object();
}
if (use_json && rd) {
*total_cum = total_count;
}
if (use_json) {
- if (json_paths)
- json_object_free(json_paths);
if (rd) {
vty_out(vty, " }%s ", (is_last ? "" : ","));
}
int count = 0;
int best = 0;
int suppress = 0;
+ int accept_own = 0;
+ int route_filter_translated_v4 = 0;
+ int route_filter_v4 = 0;
+ int route_filter_translated_v6 = 0;
+ int route_filter_v6 = 0;
+ int llgr_stale = 0;
+ int no_llgr = 0;
+ int accept_own_nexthop = 0;
+ int blackhole = 0;
int no_export = 0;
int no_advertise = 0;
int local_as = 0;
+ int no_peer = 0;
int first = 1;
int has_valid_label = 0;
mpls_label_t label = 0;
} else
vty_out(vty, ", no best path");
- if (no_advertise)
- vty_out(vty, ", not advertised to any peer");
+ if (accept_own)
+ vty_out(vty,
+ ", accept own local route exported and imported in different VRF");
+ else if (route_filter_translated_v4)
+ vty_out(vty,
+ ", mark translated RTs for VPNv4 route filtering");
+ else if (route_filter_v4)
+ vty_out(vty,
+ ", attach RT as-is for VPNv4 route filtering");
+ else if (route_filter_translated_v6)
+ vty_out(vty,
+ ", mark translated RTs for VPNv6 route filtering");
+ else if (route_filter_v6)
+ vty_out(vty,
+ ", attach RT as-is for VPNv6 route filtering");
+ else if (llgr_stale)
+ vty_out(vty,
+ ", mark routes to be retained for a longer time. Requeres support for Long-lived BGP Graceful Restart");
+ else if (no_llgr)
+ vty_out(vty,
+ ", mark routes to not be treated according to Long-lived BGP Graceful Restart operations");
+ else if (accept_own_nexthop)
+ vty_out(vty,
+ ", accept local nexthop");
+ else if (blackhole)
+ vty_out(vty, ", inform peer to blackhole prefix");
else if (no_export)
vty_out(vty, ", not advertised to EBGP peer");
+ else if (no_advertise)
+ vty_out(vty, ", not advertised to any peer");
else if (local_as)
vty_out(vty, ", not advertised outside local AS");
+ else if (no_peer)
+ vty_out(vty,
+ ", inform EBGP peer not to advertise to their EBGP peers");
if (suppress)
vty_out(vty,
|prefix-list WORD\
|filter-list WORD\
|statistics\
+ |community <AA:NN|local-AS|no-advertise|no-export|graceful-shutdown\
+ no-peer|blackhole|llgr-stale|no-llgr|accept-own|accept-own-nexthop\
+ route-filter-v6|route-filter-v4|route-filter-translated-v6|\
+ route-filter-translated-v4> [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"
+ "Do not export to any peer (well-known community)\n"
+ "Inform EBGP peers to blackhole traffic to prefix (well-known community)\n"
+ "Staled Long-lived Graceful Restart VPN route (well-known community)\n"
+ "Removed because Long-lived Graceful Restart was not enabled for VPN route (well-known community)\n"
+ "Should accept local VPN route if exported and imported into different VRF (well-known community)\n"
+ "Should accept VPN route with local nexthop (well-known community)\n"
+ "RT VPNv6 route filtering (well-known community)\n"
+ "RT VPNv4 route filtering (well-known community)\n"
+ "RT translated VPNv6 route filtering (well-known community)\n"
+ "RT translated VPNv4 route filtering (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"
pc->count[PCOUNT_ADJ_IN]++;
for (ri = rn->info; ri; ri = ri->next) {
- char buf[SU_ADDRSTRLEN];
-
if (ri->peer != peer)
continue;
if (CHECK_FLAG(ri->flags, BGP_INFO_COUNTED)) {
pc->count[PCOUNT_COUNTED]++;
if (CHECK_FLAG(ri->flags, BGP_INFO_UNUSEABLE))
- zlog_warn(
- "%s [pcount] %s/%d is counted but flags 0x%x",
- peer->host,
- inet_ntop(rn->p.family,
- &rn->p.u.prefix, buf,
- SU_ADDRSTRLEN),
- rn->p.prefixlen, ri->flags);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "Attempting to count but flags say it is unusable");
} else {
if (!CHECK_FLAG(ri->flags, BGP_INFO_UNUSEABLE))
- zlog_warn(
- "%s [pcount] %s/%d not counted but flags 0x%x",
- peer->host,
- inet_ntop(rn->p.family,
- &rn->p.u.prefix, buf,
- SU_ADDRSTRLEN),
- rn->p.prefixlen, ri->flags);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "Not counted but flags say we should");
}
}
}
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_route.h"
+#include "lib/network.h"
#include "lib/thread.h"
#include "rtrlib/rtrlib.h"
#include "rtrlib/rtr_mgr.h"
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 void revalidate_all_routes(void);
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 _Atomic int rtr_update_overflow;
static int rpki_debug;
static unsigned int polling_period;
static unsigned int expire_interval;
{
int *rpki_status;
- rpki_status = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t));
+ rpki_status = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(int));
if (strcmp(arg, "valid") == 0)
*rpki_status = RPKI_VALID;
thread_add_read(bm->master, bgpd_sync_callback, NULL,
rpki_sync_socket_bgpd, NULL);
+
+ if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) {
+ while (read(rpki_sync_socket_bgpd, &rec,
+ sizeof(struct pfx_record))
+ != -1)
+ ;
+
+ atomic_store_explicit(&rtr_update_overflow, 0,
+ memory_order_seq_cst);
+ revalidate_all_routes();
+ return 0;
+ }
+
int retval =
read(rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record));
if (retval != sizeof(struct pfx_record)) {
afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
- safi_t safi;
+ struct peer *peer;
+ struct listnode *peer_listnode;
+
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) {
+ safi_t safi;
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
- if (!bgp->rib[afi][safi])
- continue;
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ if (!peer->bgp->rib[afi][safi])
+ continue;
- struct list *matches = list_new();
+ struct list *matches = list_new();
- matches->del = (void (*)(void *))bgp_unlock_node;
+ matches->del =
+ (void (*)(void *))bgp_unlock_node;
- bgp_table_range_lookup(bgp->rib[afi][safi], prefix,
- rec.max_len, matches);
+ bgp_table_range_lookup(
+ peer->bgp->rib[afi][safi], prefix,
+ rec.max_len, matches);
- struct bgp_node *bgp_node;
+ struct bgp_node *bgp_node;
+ struct listnode *bgp_listnode;
- for (ALL_LIST_ELEMENTS_RO(matches, node, bgp_node))
- revalidate_bgp_node(bgp_node, afi, safi);
+ for (ALL_LIST_ELEMENTS_RO(matches, bgp_listnode,
+ bgp_node))
+ revalidate_bgp_node(bgp_node, afi,
+ safi);
- list_delete_and_null(&matches);
+ list_delete_and_null(&matches);
+ }
}
}
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);
+ ret = bgp_update(ain->peer, &bgp_node->p, ain->addpath_rx_id,
+ ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
+ BGP_ROUTE_NORMAL, NULL, label, num_labels, 1,
+ NULL);
- if (ret < 0) {
- bgp_unlock_node(bgp_node);
+ if (ret < 0)
return;
- }
}
}
{
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;
+ struct peer *peer;
+ struct listnode *peer_listnode;
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
- if (!bgp->rib[afi][safi])
- continue;
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) {
+
+ for (size_t i = 0; i < 2; i++) {
+ safi_t safi;
+ afi_t afi = (i == 0) ? AFI_IP : AFI_IP6;
- 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);
- }
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX;
+ safi++) {
+ if (!peer->bgp->rib[afi][safi])
+ continue;
+
+ bgp_soft_reconfig_in(peer, afi, safi);
}
}
}
const struct pfx_record rec,
const bool added __attribute__((unused)))
{
- if (rtr_is_stopping || rtr_is_starting)
+ if (rtr_is_stopping || rtr_is_starting
+ || atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst))
return;
int retval =
write(rpki_sync_socket_rtr, &rec, sizeof(struct pfx_record));
- if (retval != sizeof(struct pfx_record))
+ if (retval == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ atomic_store_explicit(&rtr_update_overflow, 1,
+ memory_order_seq_cst);
+
+ else 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];
+ const char *msg;
RPKI_DEBUG("initializing sync socket");
if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fds) != 0) {
- RPKI_DEBUG("Could not open rpki sync socket");
- return;
+ msg = "could not open rpki sync socketpair";
+ goto err;
}
rpki_sync_socket_rtr = fds[0];
rpki_sync_socket_bgpd = fds[1];
+
+ if (set_nonblocking(rpki_sync_socket_rtr) != 0) {
+ msg = "could not set rpki_sync_socket_rtr to non blocking";
+ goto err;
+ }
+
+ if (set_nonblocking(rpki_sync_socket_bgpd) != 0) {
+ msg = "could not set rpki_sync_socket_bgpd to non blocking";
+ goto err;
+ }
+
+
thread_add_read(bm->master, bgpd_sync_callback, NULL,
rpki_sync_socket_bgpd, NULL);
+
+ return;
+
+err:
+ zlog_err("RPKI: %s", msg);
+ abort();
+
}
static int bgp_rpki_init(struct thread_master *master)
rtr_is_stopping = 0;
rtr_is_starting = 1;
+ rtr_update_overflow = 0;
if (list_isempty(cache_list)) {
RPKI_DEBUG(
"exit",
"Exit rpki configuration and restart rpki session\n")
{
- int ret = reset(false);
+ reset(false);
vty->node = CONFIG_NODE;
- return ret == SUCCESS ? CMD_SUCCESS : CMD_WARNING;
+ return CMD_SUCCESS;
}
DEFUN_NOSH (rpki_quit,
/*
* bgp_unlock_node
*/
-static inline struct bgp_node *bgp_unlock_node(struct bgp_node *node)
+static inline void bgp_unlock_node(struct bgp_node *node)
{
- return (struct bgp_node *)route_unlock_node(bgp_node_to_rnode(node));
+ route_unlock_node(bgp_node_to_rnode(node));
}
/*
}
/* "bgp enforce-first-as" configuration. */
-#if CONFDATE > 20180517
+#if CONFDATE > 20190517
CPP_NOTICE("bgpd: remove deprecated '[no] bgp enforce-first-as' commands")
#endif
}
static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
- afi_t afi, safi_t safi)
+ afi_t afi, safi_t safi, uint8_t use_json)
{
struct bgp *bgp;
struct listnode *node;
char *ecom_str;
vpn_policy_direction_t dir;
- if (name) {
- bgp = bgp_lookup_by_name(name);
+ if (use_json) {
+ json_object *json = NULL;
+ json_object *json_import_vrfs = NULL;
+ json_object *json_export_vrfs = NULL;
+
+ json = json_object_new_object();
+
+ /* Provide context for the block */
+ json_object_string_add(json, "vrf", name ? name : "default");
+ json_object_string_add(json, "afiSafi",
+ afi_safi_print(afi, safi));
+
+ bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
+
if (!bgp) {
- vty_out(vty, "%% No such BGP instance exist\n");
+ json_object_boolean_true_add(json,
+ "bgpNoSuchInstance");
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json,
+ JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+
return CMD_WARNING;
}
+
+ if (!CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
+ json_object_string_add(json, "importFromVrfs", "none");
+ json_object_string_add(json, "importRts", "none");
+ } else {
+ json_import_vrfs = json_object_new_array();
+
+ for (ALL_LIST_ELEMENTS_RO(
+ bgp->vpn_policy[afi].import_vrf,
+ node, vname))
+ json_object_array_add(json_import_vrfs,
+ json_object_new_string(vname));
+
+ dir = BGP_VPN_POLICY_DIR_FROMVPN;
+ ecom_str = ecommunity_ecom2str(
+ bgp->vpn_policy[afi].rtlist[dir],
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ json_object_object_add(json, "importFromVrfs",
+ json_import_vrfs);
+ json_object_string_add(json, "importRts", ecom_str);
+
+ XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+ }
+
+ if (!CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
+ json_object_string_add(json, "exportToVrfs", "none");
+ json_object_string_add(json, "routeDistinguisher",
+ "none");
+ json_object_string_add(json, "exportRts", "none");
+ } else {
+ json_export_vrfs = json_object_new_array();
+
+ for (ALL_LIST_ELEMENTS_RO(
+ bgp->vpn_policy[afi].export_vrf,
+ node, vname))
+ json_object_array_add(json_export_vrfs,
+ json_object_new_string(vname));
+ json_object_object_add(json, "exportToVrfs",
+ json_export_vrfs);
+ json_object_string_add(json, "routeDistinguisher",
+ prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd,
+ buf1, RD_ADDRSTRLEN));
+
+ dir = BGP_VPN_POLICY_DIR_TOVPN;
+ ecom_str = ecommunity_ecom2str(
+ bgp->vpn_policy[afi].rtlist[dir],
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ json_object_string_add(json, "exportRts", ecom_str);
+
+ XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+ }
+
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(json,
+ JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+
} else {
- bgp = bgp_get_default();
+ bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
+
if (!bgp) {
- vty_out(vty,
- "%% Default BGP instance does not exist\n");
+ vty_out(vty, "%% No such BGP instance exist\n");
return CMD_WARNING;
}
- }
- if (!CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
- vty_out(vty,
- "This VRF is not importing %s routes from any other VRF\n",
- afi_safi_print(afi, safi));
- } else {
- vty_out(vty,
- "This VRF is importing %s routes from the following VRFs:\n",
- afi_safi_print(afi, safi));
- for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].import_vrf, node,
- vname)) {
- vty_out(vty, " %s\n", vname);
+ if (!CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT))
+ vty_out(vty,
+ "This VRF is not importing %s routes from any other VRF\n",
+ afi_safi_print(afi, safi));
+ else {
+ vty_out(vty,
+ "This VRF is importing %s routes from the following VRFs:\n",
+ afi_safi_print(afi, safi));
+
+ for (ALL_LIST_ELEMENTS_RO(
+ bgp->vpn_policy[afi].import_vrf,
+ node, vname))
+ vty_out(vty, " %s\n", vname);
+
+ dir = BGP_VPN_POLICY_DIR_FROMVPN;
+ ecom_str = ecommunity_ecom2str(
+ bgp->vpn_policy[afi].rtlist[dir],
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ vty_out(vty, "Import RT(s): %s\n", ecom_str);
+
+ XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
- dir = BGP_VPN_POLICY_DIR_FROMVPN;
- ecom_str = ecommunity_ecom2str(
- bgp->vpn_policy[afi].rtlist[dir],
- ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- vty_out(vty, "Import RT(s): %s\n", ecom_str);
- XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
- }
- if (!CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
- vty_out(vty,
- "This VRF is not exporting %s routes to any other VRF\n",
+ if (!CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_EXPORT))
+ vty_out(vty,
+ "This VRF is not exporting %s routes to any other VRF\n",
afi_safi_print(afi, safi));
- } else {
- vty_out(vty,
- "This VRF is exporting %s routes to the following VRFs:\n",
+ else {
+ vty_out(vty,
+ "This VRF is exporting %s routes to the following VRFs:\n",
afi_safi_print(afi, safi));
- for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].export_vrf, node,
- vname)) {
- vty_out(vty, " %s\n", vname);
+
+ for (ALL_LIST_ELEMENTS_RO(
+ bgp->vpn_policy[afi].export_vrf,
+ node, vname))
+ vty_out(vty, " %s\n", vname);
+
+ vty_out(vty, "RD: %s\n",
+ prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd,
+ buf1, RD_ADDRSTRLEN));
+
+ dir = BGP_VPN_POLICY_DIR_TOVPN;
+ ecom_str = ecommunity_ecom2str(
+ bgp->vpn_policy[afi].rtlist[dir],
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ vty_out(vty, "Export RT: %s\n", ecom_str);
+ XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
- vty_out(vty, "RD: %s\n",
- prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd,
- buf1, RD_ADDRSTRLEN));
- dir = BGP_VPN_POLICY_DIR_TOVPN;
- ecom_str = ecommunity_ecom2str(
- bgp->vpn_policy[afi].rtlist[dir],
- ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- vty_out(vty, "Emport RT: %s\n", ecom_str);
- XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
return CMD_SUCCESS;
/* "show [ip] bgp route-leak" command. */
DEFUN (show_ip_bgp_route_leak,
- show_ip_bgp_route_leak_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] route-leak",
- SHOW_STR
- IP_STR
- BGP_STR
- BGP_INSTANCE_HELP_STR
- BGP_AFI_HELP_STR
- BGP_SAFI_HELP_STR
- "Route leaking information\n")
+ show_ip_bgp_route_leak_cmd,
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] route-leak [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ BGP_INSTANCE_HELP_STR
+ BGP_AFI_HELP_STR
+ BGP_SAFI_HELP_STR
+ "Route leaking information\n"
+ JSON_STR)
{
char *vrf = NULL;
afi_t afi = AFI_MAX;
safi_t safi = SAFI_MAX;
+ uint8_t uj = use_json(argc, argv);
int idx = 0;
/* show [ip] bgp */
return CMD_WARNING;
}
- return bgp_show_route_leak_vty(vty, vrf, afi, safi);
+ return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj);
}
static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
}
bgp_redist_add(bgp, AFI_IP, type, 0);
- return bgp_redistribute_set(bgp, AFI_IP, type, 0);
+ return bgp_redistribute_set(bgp, AFI_IP, type, 0, false);
}
ALIAS_HIDDEN(
int idx_word = 3;
int type;
struct bgp_redist *red;
+ bool changed;
type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
if (type < 0) {
}
red = bgp_redist_add(bgp, AFI_IP, type, 0);
- bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
- return bgp_redistribute_set(bgp, AFI_IP, type, 0);
+ changed = bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
+ return bgp_redistribute_set(bgp, AFI_IP, type, 0, changed);
}
ALIAS_HIDDEN(
int type;
uint32_t metric;
struct bgp_redist *red;
+ bool changed;
type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
if (type < 0) {
metric = strtoul(argv[idx_number]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP, type, 0);
- bgp_redistribute_metric_set(bgp, red, AFI_IP, type, metric);
- return bgp_redistribute_set(bgp, AFI_IP, type, 0);
+ changed = bgp_redistribute_metric_set(bgp, red, AFI_IP, type, metric);
+ return bgp_redistribute_set(bgp, AFI_IP, type, 0, changed);
}
ALIAS_HIDDEN(
int type;
uint32_t metric;
struct bgp_redist *red;
+ bool changed;
type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
if (type < 0) {
metric = strtoul(argv[idx_number]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP, type, 0);
- bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
- bgp_redistribute_metric_set(bgp, red, AFI_IP, type, metric);
- return bgp_redistribute_set(bgp, AFI_IP, type, 0);
+ changed = bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
+ changed |= bgp_redistribute_metric_set(bgp, red, AFI_IP, type, metric);
+ return bgp_redistribute_set(bgp, AFI_IP, type, 0, changed);
}
ALIAS_HIDDEN(
int type;
uint32_t metric;
struct bgp_redist *red;
+ bool changed;
type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
if (type < 0) {
metric = strtoul(argv[idx_number]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP, type, 0);
- bgp_redistribute_metric_set(bgp, red, AFI_IP, type, metric);
- bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
- return bgp_redistribute_set(bgp, AFI_IP, type, 0);
+ changed = bgp_redistribute_metric_set(bgp, red, AFI_IP, type, metric);
+ changed |= bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
+ return bgp_redistribute_set(bgp, AFI_IP, type, 0, changed);
}
ALIAS_HIDDEN(
protocol = ZEBRA_ROUTE_TABLE;
bgp_redist_add(bgp, AFI_IP, protocol, instance);
- return bgp_redistribute_set(bgp, AFI_IP, protocol, instance);
+ return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, false);
}
ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf, bgp_redistribute_ipv4_ospf_hidden_cmd,
struct bgp_redist *red;
unsigned short instance;
int protocol;
+ bool changed;
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
instance = strtoul(argv[idx_number]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP, protocol, instance);
- bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
- return bgp_redistribute_set(bgp, AFI_IP, protocol, instance);
+ changed = bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
+ return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, changed);
}
ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf_rmap,
struct bgp_redist *red;
unsigned short instance;
int protocol;
+ bool changed;
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
metric = strtoul(argv[idx_number_2]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP, protocol, instance);
- bgp_redistribute_metric_set(bgp, red, AFI_IP, protocol, metric);
- return bgp_redistribute_set(bgp, AFI_IP, protocol, instance);
+ changed = bgp_redistribute_metric_set(bgp, red, AFI_IP, protocol,
+ metric);
+ return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, changed);
}
ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf_metric,
struct bgp_redist *red;
unsigned short instance;
int protocol;
+ bool changed;
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
metric = strtoul(argv[idx_number_2]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP, protocol, instance);
- bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
- bgp_redistribute_metric_set(bgp, red, AFI_IP, protocol, metric);
- return bgp_redistribute_set(bgp, AFI_IP, protocol, instance);
+ changed = bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
+ changed |= bgp_redistribute_metric_set(bgp, red, AFI_IP, protocol,
+ metric);
+ return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, changed);
}
ALIAS_HIDDEN(
struct bgp_redist *red;
unsigned short instance;
int protocol;
+ bool changed;
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
metric = strtoul(argv[idx_number_2]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP, protocol, instance);
- bgp_redistribute_metric_set(bgp, red, AFI_IP, protocol, metric);
- bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
- return bgp_redistribute_set(bgp, AFI_IP, protocol, instance);
+ changed = bgp_redistribute_metric_set(bgp, red, AFI_IP, protocol,
+ metric);
+ changed |= bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
+ return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, changed);
}
ALIAS_HIDDEN(
}
bgp_redist_add(bgp, AFI_IP6, type, 0);
- return bgp_redistribute_set(bgp, AFI_IP6, type, 0);
+ return bgp_redistribute_set(bgp, AFI_IP6, type, 0, false);
}
DEFUN (bgp_redistribute_ipv6_rmap,
int idx_word = 3;
int type;
struct bgp_redist *red;
+ bool changed;
type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
if (type < 0) {
}
red = bgp_redist_add(bgp, AFI_IP6, type, 0);
- bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
- return bgp_redistribute_set(bgp, AFI_IP6, type, 0);
+ changed = bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
+ return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed);
}
DEFUN (bgp_redistribute_ipv6_metric,
int type;
uint32_t metric;
struct bgp_redist *red;
+ bool changed;
type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
if (type < 0) {
metric = strtoul(argv[idx_number]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP6, type, 0);
- bgp_redistribute_metric_set(bgp, red, AFI_IP6, type, metric);
- return bgp_redistribute_set(bgp, AFI_IP6, type, 0);
+ changed = bgp_redistribute_metric_set(bgp, red, AFI_IP6, type, metric);
+ return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed);
}
DEFUN (bgp_redistribute_ipv6_rmap_metric,
int type;
uint32_t metric;
struct bgp_redist *red;
+ bool changed;
type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
if (type < 0) {
metric = strtoul(argv[idx_number]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP6, type, 0);
- bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
- bgp_redistribute_metric_set(bgp, red, AFI_IP6, type, metric);
- return bgp_redistribute_set(bgp, AFI_IP6, type, 0);
+ changed = bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
+ changed |= bgp_redistribute_metric_set(bgp, red, AFI_IP6, type,
+ metric);
+ return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed);
}
DEFUN (bgp_redistribute_ipv6_metric_rmap,
int type;
uint32_t metric;
struct bgp_redist *red;
+ bool changed;
type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
if (type < 0) {
metric = strtoul(argv[idx_number]->arg, NULL, 10);
red = bgp_redist_add(bgp, AFI_IP6, type, 0);
- bgp_redistribute_metric_set(bgp, red, AFI_IP6, SAFI_UNICAST, metric);
- bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
- return bgp_redistribute_set(bgp, AFI_IP6, type, 0);
+ changed = bgp_redistribute_metric_set(bgp, red, AFI_IP6, SAFI_UNICAST,
+ metric);
+ changed |= bgp_redistribute_rmap_set(red, argv[idx_word]->arg);
+ return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed);
}
DEFUN (no_bgp_redistribute_ipv6,
/* Other routes redistribution into BGP. */
int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type,
- unsigned short instance)
+ unsigned short instance, bool changed)
{
+ /* If redistribute options are changed call
+ * bgp_redistribute_unreg() to reset the option and withdraw
+ * the routes
+ */
+ if (changed)
+ bgp_redistribute_unreg(bgp, afi, type, instance);
/* Return if already redistribute flag is set. */
if (instance) {
unsigned short);
extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t,
unsigned short);
-extern int bgp_redistribute_set(struct bgp *, afi_t, int, unsigned short);
+extern int bgp_redistribute_set(struct bgp *, afi_t, int, unsigned short,
+ bool changed);
extern int bgp_redistribute_resend(struct bgp *, afi_t, int, unsigned short);
extern int bgp_redistribute_rmap_set(struct bgp_redist *, const char *);
extern int bgp_redistribute_metric_set(struct bgp *, struct bgp_redist *, afi_t,
.import_redirect_rtlist);
bgp->vpn_policy[afi].import_redirect_rtlist = NULL;
}
- /* Remove visibility via the master list - there may however still be
- * routes to be processed still referencing the struct bgp.
- */
- listnode_delete(bm->bgp, bgp);
/* Deregister from Zebra, if needed */
if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
bgp_zebra_instance_deregister(bgp);
+ /* Remove visibility via the master list - there may however still be
+ * routes to be processed still referencing the struct bgp.
+ */
+ listnode_delete(bm->bgp, bgp);
+
/* Free interfaces in this instance. */
bgp_if_finish(bgp);
time_t uptime1, epoch_tbuf;
struct tm *tm;
- /* Check buffer length. */
- if (len < BGP_UPTIME_LEN) {
- if (!use_json) {
- zlog_warn("peer_uptime (): buffer shortage %lu",
- (unsigned long)len);
- /* XXX: should return status instead of buf... */
- snprintf(buf, len, "<error> ");
- }
- return buf;
- }
-
/* If there is no connection has been done before print `never'. */
if (uptime2 == 0) {
if (use_json) {
}
/* clang-format off */
-#if CONFDATE > 20180517
+#if CONFDATE > 20190517
CPP_NOTICE("bgpd: remove 'bgp enforce-first-as' config migration from bgp_config_write")
#endif
/* clang-format on */
AC_ARG_WITH(rfp-path,
AS_HELP_STRING([--with-rfp-path[=DIR]],[path to replaced stub RFP used with BGP VNC]))
AC_ARG_ENABLE(snmp,
- AS_HELP_STRING([--enable-snmp=ARG], [enable SNMP support (smux or agentx)]))
+ AS_HELP_STRING([--enable-snmp], [enable SNMP support for agentx]))
AC_ARG_ENABLE(zeromq,
AS_HELP_STRING([--enable-zeromq], [enable ZeroMQ handler (libfrrzmq)]))
AC_ARG_WITH(libpam,
AS_HELP_STRING([--disable-rusage], [disable using getrusage]))
AC_ARG_ENABLE(gcc_ultra_verbose,
AS_HELP_STRING([--enable-gcc-ultra-verbose], [enable ultra verbose GCC warnings]))
-AC_ARG_ENABLE(linux24_tcp_md5,
- AS_HELP_STRING([--enable-linux24-tcp-md5], [enable support for old, Linux-2.4 RFC2385 patch]))
AC_ARG_ENABLE(backtrace,
AS_HELP_STRING([--disable-backtrace,], [disable crash backtraces (default autodetect)]))
AC_ARG_ENABLE(time-check,
# End of logic for protobuf support.
#
-if test "${enable_linux24_tcp_md5}" = "yes"; then
- AC_DEFINE(HAVE_TCP_MD5_LINUX24,,Old Linux 2.4 TCP MD5 Signature Patch)
-fi
-
AC_MSG_CHECKING(if zebra should be configurable to send Route Advertisements)
if test "${enable_rtadv}" != "no"; then
AC_MSG_RESULT(yes)
yes)
SNMP_METHOD=agentx
;;
- smux|agentx)
+ agentx)
SNMP_METHOD="${enable_snmp}"
;;
*)
- AC_MSG_ERROR([--enable-snmp given with an unknown method (${enable_snmp}). Use smux or agentx])
+ AC_MSG_ERROR([--enable-snmp given with an unknown method (${enable_snmp}). Use yes or agentx])
;;
esac
- AH_TEMPLATE([SNMP_SMUX], [Use SNMP SMUX to interface with snmpd])
AH_TEMPLATE([SNMP_AGENTX], [Use SNMP AgentX to interface with snmpd])
AC_DEFINE_UNQUOTED(AS_TR_CPP(SNMP_${SNMP_METHOD}),,SNMP method to interface with snmpd)
fi
WANT_LDP ?= 1
WANT_PIM ?= 1
WANT_OSPFAPI ?= 1
-WANT_TCP_ZEBRA ?= 0
WANT_BGP_VNC ?= 1
WANT_CUMULUS_MODE ?= 0
WANT_MULTIPATH ?= 1
USE_OSPFAPI=--enable-ospfapi=no
endif
-ifeq ($(WANT_TCP_ZEBRA),1)
- USE_TCP_ZEBRA=--enable-tcp-zebra
-else
- USE_TCP_ZEBRA=--disable-tcp-zebra
-endif
-
ifeq ($(WANT_BGP_VNC), 1)
USE_BGP_VNC=--enable-bgp-vnc=yes
else
$(USE_OSPFAPI) \
$(USE_MULTIPATH) \
$(USE_LDP) \
- $(USE_TCP_ZEBRA) \
--enable-fpm \
$(USE_FRR_USER) $(USE_FRR_GROUP) \
$(USE_FRR_VTY_GROUP) \
mkdir -p debian/tmp/etc/frr/
perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample*
- # installing the Frr specific SNMP MIB
-ifeq ($(WANT_SNMP), 1)
- install -D -m 644 ./zebra/GNOME-PRODUCT-ZEBRA-MIB debian/tmp/usr/share/snmp/mibs/GNOME-PRODUCT-ZEBRA-MIB
-else
+ # leftover from previously shipping SMUX client OID MIB
mkdir -p debian/tmp/usr/share/snmp/mibs
-endif
# cleaning .la files
sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/*.la
WANT_LDP ?= 1
WANT_PIM ?= 1
WANT_OSPFAPI ?= 1
-WANT_TCP_ZEBRA ?= 0
WANT_BGP_VNC ?= 1
WANT_CUMULUS_MODE ?= 0
WANT_MULTIPATH ?= 1
USE_OSPFAPI=--enable-ospfapi=no
endif
-ifeq ($(WANT_TCP_ZEBRA),1)
- USE_TCP_ZEBRA=--enable-tcp-zebra
-else
- USE_TCP_ZEBRA=--disable-tcp-zebra
-endif
-
ifeq ($(WANT_BGP_VNC), 1)
USE_BGP_VNC=--enable-bgp-vnc=yes
else
$(USE_OSPFAPI) \
$(USE_MULTIPATH) \
$(USE_LDP) \
- $(USE_TCP_ZEBRA) \
--enable-fpm \
$(USE_FRR_USER) $(USE_FRR_GROUP) \
$(USE_FRR_VTY_GROUP) \
mkdir -p debian/tmp/etc/frr/
perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample*
- # installing the Frr specific SNMP MIB
-ifeq ($(WANT_SNMP), 1)
- install -D -m 644 ./zebra/GNOME-PRODUCT-ZEBRA-MIB debian/tmp/usr/share/snmp/mibs/GNOME-PRODUCT-ZEBRA-MIB
-else
+ # leftover from previously shipping SMUX client OID MIB
mkdir -p debian/tmp/usr/share/snmp/mibs/
-endif
# cleaning .la files
sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/*.la
WANT_LDP ?= 1
WANT_PIM ?= 1
WANT_OSPFAPI ?= 1
-WANT_TCP_ZEBRA ?= 0
WANT_BGP_VNC ?= 1
WANT_CUMULUS_MODE ?= 0
WANT_MULTIPATH ?= 1
USE_OSPFAPI=--enable-ospfapi=no
endif
-ifeq ($(WANT_TCP_ZEBRA),1)
- USE_TCP_ZEBRA=--enable-tcp-zebra
-else
- USE_TCP_ZEBRA=--disable-tcp-zebra
-endif
-
ifeq ($(WANT_BGP_VNC), 1)
USE_BGP_VNC=--enable-bgp-vnc=yes
else
$(USE_OSPFAPI) \
$(USE_MULTIPATH) \
$(USE_LDP) \
- $(USE_TCP_ZEBRA) \
--enable-fpm \
$(USE_FRR_USER) $(USE_FRR_GROUP) \
$(USE_FRR_VTY_GROUP) \
mkdir -p debian/tmp/etc/frr/
perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample*
- # installing the Frr specific SNMP MIB
-ifeq ($(WANT_SNMP), 1)
- install -D -m 644 ./zebra/GNOME-PRODUCT-ZEBRA-MIB debian/tmp/usr/share/snmp/mibs/GNOME-PRODUCT-ZEBRA-MIB
-else
+ # leftover from previously shipping SMUX client OID MIB
mkdir -p debian/tmp/usr/share/snmp/mibs/
-endif
# cleaning .la files
sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/*.la
developer/index.rst \
developer/ldpd-basic-test-setup.md \
developer/library.rst \
+ developer/logging.rst \
developer/Makefile.in \
developer/maintainer-release-build.rst \
developer/memtypes.rst \
.. toctree::
:maxdepth: 2
+ logging
memtypes
hooks
cli
--- /dev/null
+Developer's Guide to Logging
+============================
+
+One of the most frequent decisions to make while writing code for FRR is what
+to log, what level to log it at, and when to log it. Here is a list of
+recommendations for these decisions.
+
+
+Errors and warnings
+-------------------
+
+If it is something that the user will want to look at and maybe do
+something, it is either an **error** or a **warning**.
+
+We're expecting that warnings and errors are in some way visible to the
+user (in the worst case by looking at the log after the network broke, but
+maybe by a syslog collector from all routers.) Therefore, anything that
+needs to get the user in the loop—and only these things—are warnings or
+errors.
+
+Note that this doesn't neccessarily mean the user needs to fix something in
+the FRR instance. It also includes when we detect something else needs
+fixing, for example another router, the system we're running on, or the
+configuration. The common point is that the user should probably do
+*something*.
+
+Deciding between a warning and an error is slightly less obvious; the rule
+of thumb here is that an error will cause considerable fallout beyond its
+direct effect. Closing a BGP session due to a malformed update is an error
+since all routes from the peer are dropped; discarding one route because
+its attributes don't make sense is a warning.
+
+This also loosely corresponds to the kind of reaction we're expecting from
+the user. An error is likely to need immediate response while a warning
+might be snoozed for a bit and addressed as part of general maintenance.
+If a problem will self-repair (e.g. by retransmits), it should be a
+warning—unless the impact until that self-repair is very harsh.
+
+Examples for warnings:
+
+* a BGP update, LSA or LSP could not be processed, but operation is
+ proceeding and the broken pieces are likely to self-fix later
+* some kind of controller cannot be reached, but we can work without it
+* another router is using some unknown or unsupported capability
+
+Examples for errors:
+
+* dropping a BGP session due to malformed data
+* a socket for routing protocol operation cannot be opened
+* desynchronization from network state because something went wrong
+* *everything that we as developers would really like to be notified about,
+ i.e. some assumption in the code isn't holding up*
+
+
+Informational messages
+----------------------
+
+Anything that provides introspection to the user during normal operation
+is an **info** message.
+
+This includes all kinds of operational state transitions and events,
+especially if they might be interesting to the user during the course of
+figuring out a warning or an error.
+
+By itself, these messages should mostly be statements of fact. They might
+indicate the order and relationship in which things happened. Also covered
+are conditions that might be "operational issues" like a link failure due
+to an unplugged cable. If it's pretty much the point of running a routing
+daemon for, it's not a warning or an error, just business as usual.
+
+The user should be able to see the state of these bits from operational
+state output, i.e. `show interface` or `show foobar neighbors`. The log
+message indicating the change may have been printed weeks ago, but the
+state can always be viewed. (If some state change has an info message but
+no "show" command, maybe that command needs to be added.)
+
+Examples:
+
+* all kinds of up/down state changes
+
+ * interface coming up or going down
+ * addresses being added or deleted
+ * peers and neighbors coming up or going down
+
+* rejection of some routes due to user-configured route maps
+* backwards compatibility handling because another system on the network
+ has a different or smaller feature set
+
+.. note::
+ The previously used **notify** priority is replaced with *info* in all
+ cases. We don't currently have a well-defined use case for it.
+
+
+Debug messages and asserts
+--------------------------
+
+Everything that is only interesting on-demand, or only while developing,
+is a **debug** message. It might be interesting to the user for a
+particularly evasive issue, but in general these are details that an
+average user might not even be able to make sense of.
+
+Most (or all?) debug messages should be behind a `debug foobar` category
+switch that controls which subset of these messages is currently
+interesting and thus printed. If a debug message doesn't have such a
+guard, there should be a good explanation as to why.
+
+Conversely, debug messages are the only thing that should be guarded by
+these switches. Neither info nor warning or error messages should be
+hidden in this way.
+
+**Asserts** should only be used as pretty crashes. We are expecting that
+asserts remain enabled in production builds, but please try to not use
+asserts in a way that would cause a security problem if the assert wasn't
+there (i.e. don't use them for length checks.)
+
+The purpose of asserts is mainly to help development and bug hunting. If
+the daemon crashes, then having some more information is nice, and the
+assert can provide crucial hints that cut down on the time needed to track
+an issue. That said, if the issue can be reasonably handled and/or isn't
+going to crash the daemon, it shouldn't be an assert.
+
+For anything else where internal constraints are violated but we're not
+breaking due to it, it's an error instead (not a debug.) These require
+"user action" of notifying the developers.
+
+Examples:
+
+* mismatched :code:`prev`/:code:`next` pointers in lists
+* some field that is absolutely needed is :code:`NULL`
+* any other kind of data structure corruption that will cause the daemon
+ to crash sooner or later, one way or another
+-----------------------------------+-------+
| ZEBRA_INTERFACE_DOWN | 6 |
+-----------------------------------+-------+
-| ZEBRA_IPV4_ROUTE_ADD | 7 |
-+-----------------------------------+-------+
-| ZEBRA_IPV4_ROUTE_DELETE | 8 |
-+-----------------------------------+-------+
-| ZEBRA_IPV6_ROUTE_ADD | 9 |
-+-----------------------------------+-------+
-| ZEBRA_IPV6_ROUTE_DELETE | 10 |
-+-----------------------------------+-------+
| ZEBRA_REDISTRIBUTE_ADD | 11 |
+-----------------------------------+-------+
| ZEBRA_REDISTRIBUTE_DELETE | 12 |
staticd 2616
bfdd 2617
- Port 2607 is used for ospfd's Opaque LSA API, while port 2600 is used for the (insecure) TCP-ZEBRA interface.
+ Port 2607 is used for ospfd's Opaque LSA API.
.. option:: --vty_socket vty-path
.. toctree::
:maxdepth: 2
+ bfdd
bgpd
eigrpd
isisd
pre {
background-color: #e2e2e2;
}
+
+/* styling for the protocols vs. OS table in overview.rst */
+/* first, general bits */
+div.body td.mark {
+ text-align: center;
+ border-left: 1px solid #ccc;
+}
+table.mark th {
+ text-align: center;
+}
+table.mark td {
+ vertical-align: middle;
+}
+table.mark td[colspan="7"] {
+ text-align: center;
+ padding-top: 8pt;
+ padding-bottom: 2pt;
+}
+table.mark cite {
+ font-weight: bold;
+}
+
+/* individual Y/N/... cells */
+td.mark {
+ width: 4.5em;
+}
+td.mark span {
+ display: block;
+ padding: 3px 1px;
+ border: 1px dotted #666;
+ width: 36pt;
+ margin:auto;
+}
+span.mark-y { background-color: #77ffaa; }
+span.mark-geq { background-color: #aaff77; }
+span.mark-cp { background-color: #ffbb55; }
+span.mark-n { background-color: #ff8877; }
+span.mark-dag { background-color: #ffee99; font-size: 8pt; padding:0px 1px; border-top:0px; }
+
+/* for the legend below */
+li span.mark {
+ display: inline-block;
+ padding: 3px 1px;
+ border: 1px dotted #666;
+ width: 36pt;
+ text-align: center;
+}
--- /dev/null
+/* special styling for the protocols vs. OS table in overview.rst
+ *
+ * unfortunately this can't be done in straight CSS because we're changing
+ * the styling on the parent.
+ */
+$(document).ready(function() {
+ $("span.mark:contains('Y')" ).addClass("mark-y" ).parent("td").addClass("mark");
+ $("span.mark:contains('≥')" ).addClass("mark-geq").parent("td").addClass("mark");
+ $("span.mark:contains('N')" ).addClass("mark-n" ).parent("td").addClass("mark");
+ $("span.mark:contains('CP')").addClass("mark-cp" ).parent("td").addClass("mark");
+ $("span.mark:contains('†')" ).addClass("mark-dag").parent("td").addClass("mark");
+ $('td.mark').parents('table').addClass("mark").children('colgroup').remove();
+});
.. _bfd-ospf-peer-config:
OSPF BFD Configuration
----------------------
+----------------------
The following commands are available inside the interface configuration node.
Echo transmission interval: 50ms
frr# show bfd peer 192.168.0.1 json
-{"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-interval":50,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-interval":50}
+ {"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-interval":50,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-interval":50}
You can also inspect peer session counters with the following commands:
Zebra notifications: 4
frr# show bfd peer 192.168.0.1 counters json
-{"multihop":false,"peer":"192.168.0.1","control-packet-input":348,"control-packet-output":685,"echo-packet-input":6815,"echo-packet-output":6816,"session-up":1,"session-down":0,"zebra-notifications":4}
+ {"multihop":false,"peer":"192.168.0.1","control-packet-input":348,"control-packet-output":685,"echo-packet-input":6815,"echo-packet-output":6816,"session-up":1,"session-down":0,"zebra-notifications":4}
``internet``
``internet`` represents well-known communities value 0.
+``graceful-shutdown``
+ ``graceful-shutdown`` represents well-known communities value
+ ``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements
+ the purpose Graceful BGP Session Shutdown to reduce the amount of
+ lost traffic when taking BGP sessions down for maintainance. The use
+ of the community needs to be supported from your peers side to
+ actually have any effect.
+
+``accept-own``
+ ``accept-own`` represents well-known communities value ``ACCEPT_OWN``
+ ``0xFFFF0001`` ``65535:1``. :rfc:`7611` implements a way to signal
+ to a router to accept routes with a local nexthop address. This
+ can be the case when doing policing and having traffic having a
+ nexthop located in another VRF but still local interface to the
+ router. It is recommended to read the RFC for full details.
+
+``route-filter-translated-v4``
+ ``route-filter-translated-v4`` represents well-known communities value
+ ``ROUTE_FILTER_TRANSLATED_v4`` ``0xFFFF0002`` ``65535:2``.
+
+``route-filter-v4``
+ ``route-filter-v4`` represents well-known communities value
+ ``ROUTE_FILTER_v4`` ``0xFFFF0003`` ``65535:3``.
+
+``route-filter-translated-v6``
+ ``route-filter-translated-v6`` represents well-known communities value
+ ``ROUTE_FILTER_TRANSLATED_v6`` ``0xFFFF0004`` ``65535:4``.
+
+``route-filter-v6``
+ ``route-filter-v6`` represents well-known communities value
+ ``ROUTE_FILTER_v6`` ``0xFFFF0005`` ``65535:5``.
+
+``llgr-stale``
+ ``llgr-stale`` represents well-known communities value ``LLGR_STALE``
+ ``0xFFFF0006`` ``65535:6``.
+ Assigned and intented only for use with routers supporting the
+ Long-lived Graceful Restart Capability as described in
+ :rfc:`draft-uttaro-idr-bgp-persistence`.
+ Routers recieving routes with this community may (depending on
+ implementation) choose allow to reject or modify routes on the
+ presence or absence of this community.
+
+``no-llgr``
+ ``no-llgr`` represents well-known communities value ``NO_LLGR``
+ ``0xFFFF0007`` ``65535:7``.
+ Assigned and intented only for use with routers supporting the
+ Long-lived Graceful Restart Capability as described in
+ :rfc:`draft-uttaro-idr-bgp-persistence`.
+ Routers recieving routes with this community may (depending on
+ implementation) choose allow to reject or modify routes on the
+ presence or absence of this community.
+
+``accept-own-nexthop``
+ ``accept-own-nexthop`` represents well-known communities value
+ ``accept-own-nexthop`` ``0xFFFF0008`` ``65535:8``.
+ :rfc:`draft-agrewal-idr-accept-own-nexthop` describes
+ how to tag and label VPN routes to be able to send traffic between VRFs
+ via an internal layer 2 domain on the same PE device. Refer to
+ :rfc:`draft-agrewal-idr-accept-own-nexthop` for full details.
+
+``blackhole``
+ ``blackhole`` represents well-known communities value ``BLACKHOLE``
+ ``0xFFFF029A`` ``65535:666``. :rfc:`7999` documents sending prefixes to
+ EBGP peers and upstream for the purpose of blackholing traffic.
+ Prefixes tagged with the this community should normally not be
+ re-advertised from neighbors of the originating network. It is
+ recommended upon receiving prefixes tagged with this community to
+ add ``NO_EXPORT`` and ``NO_ADVERTISE``.
+
``no-export``
``no-export`` represents well-known communities value ``NO_EXPORT``
``0xFFFFFF01``. All routes carry this value must not be advertised to
it is considered as external BGP peer, so the route will not be announced to
the peer.
+``no-peer``
+ ``no-peer`` represents well-known communities value ``NOPEER``
+ ``0xFFFFFF04`` ``65535:65284``. :rfc:`3765` is used to communicate to
+ another network how the originating network want the prefix propagated.
+
When the communities attribute is received duplicate community values in the
attribute are ignored and value is sorted in numerical order.
app.add_object_type('clicmd', 'clicmd')
# css overrides for HTML theme
app.add_stylesheet('overrides.css')
+ app.add_javascript('overrides.js')
# load Pygments lexer for FRR config syntax
#
# NB: in Pygments 2.2+ this can be done with `load_lexer_from_file`, but we
********
`FRR`_ is a routing software package that provides TCP/IP based routing
-services with routing protocols support such as RIPv1, RIPv2, RIPng, OSPFv2,
-OSPFv3, IS-IS, BGP-4, and BGP-4+ (:ref:`supported-rfcs`). FRR also supports
+services with routing protocols support such as BGP, RIP, OSPF, IS-IS and more
+(see :ref:`supported-protocols`). FRR also supports
special BGP Route Reflector and Route Server behavior. In addition to
traditional IPv4 routing protocols, FRR also supports IPv6 routing protocols.
-With SNMP daemon which supports SMUX and AgentX protocol, FRR provides routing
-protocol MIBs (:ref:`snmp-support`).
+With an SNMP daemon that supports the AgentX protocol, FRR provides routing
+protocol MIB read-only access (:ref:`snmp-support`).
FRR uses an advanced software architecture to provide you with a high quality,
multi server routing engine. FRR has an interactive user interface for each
.. _supported-protocols:
-Supported Protocols & RFCs
-==========================
-
-The following well-known protocols are supported:
-
-- BGP
-- Babel
-- EIGRP
-- IS-IS
-- LDP
-- NHRP
-- OSPFv2
-- OSPFv3
-- PIM
-- RIP
-- RIPNG
-
-The following technologies are supported as well:
-
-- PBR (Policy Based Routing)
-- VNC (Virtual Network Control)
+Supported Protocols vs. Platform
+================================
+
+The following table lists all protocols cross-refrenced to all operating
+systems that have at least CI build tests. Note that for features, only
+features with system dependencies are included here.
+
+.. role:: mark
+
+.. comment - the :mark:`X` pieces mesh with a little bit of JavaScript and
+ CSS in _static/overrides.{js,css} respectively. The JS code looks at the
+ presence of the 'Y' 'N' '≥' '†' or 'CP' strings. This seemed to be the
+ best / least intrusive way of getting a nice table in HTML. The table
+ will look somewhat shoddy on other sphinx targets like PDF or info (but
+ should still be readable.)
+
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| Daemon / Feature | Linux | OpenBSD | FreeBSD | NetBSD | Solaris |
++==+================================+================+==============+============+============+============+
+| FRR Core |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `zebra` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | VRF | :mark:`≥4.8` | :mark:`N` | :mark:`N` | :mark:`N` | :mark:`N` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | MPLS | :mark:`≥4.5` | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `pbrd` (Policy Routing) | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` | :mark:`N` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| WAN / Carrier protocols |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `bgpd` (BGP) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | VRF / L3VPN | :mark:`≥4.8` | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` |
+| | | :mark:`†4.3` | | | | |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | EVPN | :mark:`≥4.18` | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` |
+| | | :mark:`†4.9` | | | | |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | VNC (Virtual Network Control) | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | Flowspec | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `ldpd` (LDP) | :mark:`≥4.5` | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | VPWS / PW | :mark:`N` | :mark:`≥5.8` | :mark:`N` | :mark:`N` | :mark:`N` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | VPLS | :mark:`N` | :mark:`≥5.8` | :mark:`N` | :mark:`N` | :mark:`N` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `nhrpd` (NHRP) | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` | :mark:`N` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| Link-State Routing |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `ospfd` (OSPFv2) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | Segment Routing | :mark:`≥4.12` | :mark:`N` | :mark:`N` | :mark:`N` | :mark:`N` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `ospf6d` (OSPFv3) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `isisd` (IS-IS) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| Distance-Vector Routing |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `ripd` (RIPv2) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `ripngd` (RIPng) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `babeld` (BABEL) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `eigrpd` (EIGRP) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| Multicast Routing |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| `pimd` (PIM) | :mark:`≥4.18` | :mark:`N` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | SSM (Source Specific) | :mark:`Y` | :mark:`N` | :mark:`Y` | :mark:`Y` | :mark:`Y` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+| | ASM (Any Source) | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` | :mark:`N` |
++--+--------------------------------+----------------+--------------+------------+------------+------------+
+
+The indicators have the following semantics:
+
+* :mark:`Y` - daemon/feature fully functional
+* :mark:`≥X.X` - fully functional with kernel version X.X or newer
+* :mark:`†X.X` - restricted functionality or impaired performance with kernel version X.X or newer
+* :mark:`CP` - control plane only (i.e. BGP route server / route reflector)
+* :mark:`N` - daemon/feature not supported by operating system
.. _supported-rfcs:
:abbr:`SNMP (Simple Network Managing Protocol)` is a widely implemented feature
for collecting network information from router and/or host. FRR itself does
not support SNMP agent (server daemon) functionality but is able to connect to
-a SNMP agent using the SMUX protocol (:rfc:`1227`) or the AgentX protocol
-(:rfc:`2741`) and make the routing protocol MIBs available through it.
+a SNMP agent using the the AgentX protocol (:rfc:`2741`) and make the
+routing protocol MIBs available through it.
Note that SNMP Support needs to be enabled at compile-time and loaded as module
on daemon startup. Refer to :ref:`loadable-module-support` on the latter.
Getting and installing an SNMP agent
====================================
-There are several SNMP agent which support SMUX or AgentX. We recommend to use
+The supported SNMP agent is AgentX. We recommend to use
the latest version of `net-snmp` which was formerly known as `ucd-snmp`. It is
free and open software and available at `http://www.net-snmp.org/ <http://www.net-snmp.org/>`_
-and as binary package for most Linux distributions. `net-snmp` has to be
-compiled with `--with-mib-modules=agentx` to be able to accept connections from
-FRR using AgentX protocol or with `--with-mib-modules=smux` to use SMUX
-protocol.
-
-Nowadays, SMUX is a legacy protocol. The AgentX protocol should be preferred
-for any new deployment. Both protocols have the same coverage.
+and as binary package for most Linux distributions.
.. _agentx-configuration:
:file:`/etc/snmp/snmpd.conf`, the ``master agentx`` directive should be added.
In each of the FRR daemons, ``agentx`` command will enable AgentX support.
-:file:`/etc/snmp/snmpd.conf`:
+:file:`/etc/snmp/zebra.conf`:
::
agentXSocket tcp:192.168.15.12:705
-.. _smux-configuration:
-
-SMUX configuration
-==================
-
-To enable SMUX protocol support, FRR must have been build with the
-:option:`--enable-snmp` option.
-
-A separate connection has then to be established between the SNMP agent (snmpd)
-and each of the FRR daemons. This connections each use different OID numbers
-and passwords. Be aware that this OID number is not the one that is used in
-queries by clients, it is solely used for the intercommunication of the
-daemons.
-
-In the following example the ospfd daemon will be connected to the snmpd daemon
-using the password "frr_ospfd". For testing it is recommending to take exactly
-the below snmpd.conf as wrong access restrictions can be hard to debug.
-
-:file:`/etc/snmp/snmpd.conf`:
-
-::
-
- #
- # example access restrictions setup
- #
- com2sec readonly default public
- group MyROGroup v1 readonly
- view all included .1 80
- access MyROGroup "" any noauth exact all none none
- #
- # the following line is relevant for FRR
- #
- smuxpeer .1.3.6.1.4.1.3317.1.2.5 frr_ospfd
-
-:file:`/etc/frr/ospf`:
-
-::
-
- ! ... the rest of ospfd.conf has been omitted for clarity ...
- !
- smux peer .1.3.6.1.4.1.3317.1.2.5 frr_ospfd
- !
-
-
-After restarting snmpd and frr, a successful connection can be verified in the
-syslog and by querying the SNMP daemon:
-
-::
-
- snmpd[12300]: [smux_accept] accepted fd 12 from 127.0.0.1:36255
- snmpd[12300]: accepted smux peer: \\
- oid GNOME-PRODUCT-ZEBRA-MIB::ospfd, frr-0.96.5
-
- # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1
- OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109
-
-
-Be warned that the current version (5.1.1) of the Net-SNMP daemon writes a line
-for every SNMP connect to the syslog which can lead to enormous log file sizes.
-If that is a problem you should consider to patch snmpd and comment out the
-troublesome `snmp_log()` line in the function `netsnmp_agent_check_packet()` in
-`agent/snmp_agent.c`.
-
-MIB and command reference
-=========================
-
-The following OID numbers are used for the interprocess communication of snmpd and
-the FRR daemons with SMUX only.::
-
- . (OIDs below .iso.org.dod.internet.private.enterprises)
- zebra .1.3.6.1.4.1.3317.1.2.1 .gnome.gnomeProducts.zebra.zserv
- bgpd .1.3.6.1.4.1.3317.1.2.2 .gnome.gnomeProducts.zebra.bgpd
- ripd .1.3.6.1.4.1.3317.1.2.3 .gnome.gnomeProducts.zebra.ripd
- ospfd .1.3.6.1.4.1.3317.1.2.5 .gnome.gnomeProducts.zebra.ospfd
- ospf6d .1.3.6.1.4.1.3317.1.2.6 .gnome.gnomeProducts.zebra.ospf6d
-
-
-Sadly, SNMP has not been implemented in all daemons yet. The following
-OID numbers are used for querying the SNMP daemon by a client:::
-
- zebra .1.3.6.1.2.1.4.24 .iso.org.dot.internet.mgmt.mib-2.ip.ipForward
- ospfd .1.3.6.1.2.1.14 .iso.org.dot.internet.mgmt.mib-2.ospf
- bgpd .1.3.6.1.2.1.15 .iso.org.dot.internet.mgmt.mib-2.bgp
- ripd .1.3.6.1.2.1.23 .iso.org.dot.internet.mgmt.mib-2.rip2
- ospf6d .1.3.6.1.3.102 .iso.org.dod.internet.experimental.ospfv3
-
-
-The following syntax is understood by the FRR daemons for configuring SNMP
-using SMUX:
-
-.. index:: smux peer OID
-.. clicmd:: smux peer OID
-.. index:: no smux peer OID
-.. clicmd:: no smux peer OID
-.. index:: smux peer OID PASSWORD
-.. clicmd:: smux peer OID PASSWORD
-.. index:: no smux peer OID PASSWORD
-.. clicmd:: no smux peer OID PASSWORD
-
Here is the syntax for using AgentX:
.. index:: agentx
#include "isisd/isis_constants.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_network.h"
+#include "isisd/isis_pdu.h"
#include "privs.h"
*stream = stream_new(stream_size);
} else {
if (STREAM_SIZE(*stream) != stream_size)
- stream_resize(*stream, stream_size);
+ stream_resize_inplace(stream, stream_size);
stream_reset(*stream);
}
}
if (!b->head)
return BUFFER_EMPTY;
- if (height < 1) {
- zlog_warn(
- "%s called with non-positive window height %d, forcing to 1",
- __func__, height);
+ if (height < 1)
height = 1;
- } else if (height >= 2)
+ else if (height >= 2)
height--;
- if (width < 1) {
- zlog_warn(
- "%s called with non-positive window width %d, forcing to 1",
- __func__, width);
+ if (width < 1)
width = 1;
- }
/* For erase and more data add two to b's buffer_data count.*/
if (b->head->next == NULL) {
{
iov_alloc *= 2;
if (iov != small_iov) {
- zlog_warn(
- "%s: growing iov array to %d; "
- "width %d, height %d, size %lu",
- __func__, iov_alloc, width, height,
- (unsigned long)b->size);
iov = XREALLOC(MTYPE_TMP, iov,
iov_alloc * sizeof(*iov));
} else {
#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5)
# define _RET_NONNULL , returns_nonnull
#endif
+#if __has_attribute(fallthrough)
+# define _FALLTHROUGH __attribute__((fallthrough));
+#endif
# define _CONSTRUCTOR(x) constructor(x)
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
# define _DESTRUCTOR(x) destructor(x)
# define _ALLOC_SIZE(x) alloc_size(x)
#endif
+#if __GNUC__ >= 7
+# define _FALLTHROUGH __attribute__((fallthrough));
+#endif
#endif
#ifdef __sun
#ifndef _ALLOC_SIZE
# define _ALLOC_SIZE(x)
#endif
+#ifndef _FALLTHROUGH
+#define _FALLTHROUGH
+#endif
/*
* for warnings on macros, put in the macro content like this:
void log_ref_display(struct vty *vty, uint32_t code, bool json)
{
struct log_ref *ref;
- struct json_object *top, *obj;
+ struct json_object *top = NULL, *obj = NULL;
struct list *errlist;
struct listnode *ln;
char ubuf[256];
snprintf(pbuf, sizeof(pbuf), "\nError %"PRIu32" - %s",
- code, ref->title);
+ ref->code, ref->title);
memset(ubuf, '=', strlen(pbuf));
ubuf[sizeof(ubuf) - 1] = '\0';
* this should not be considered as an update
* then create the new interface
*/
- if (ifp->vrf_id != vrf_id && vrf_is_mapped_on_netns(vrf_id))
+ if (ifp->vrf_id != vrf_id && vrf_is_mapped_on_netns(
+ vrf_lookup_by_id(vrf_id)))
return if_create(name, vrf_id);
/* If it came from the kernel
* or by way of zclient, believe it and update
return CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
}
+bool if_is_loopback_or_vrf(struct interface *ifp)
+{
+ if (if_is_loopback(ifp) || if_is_vrf(ifp))
+ return true;
+
+ return false;
+}
+
/* Does this interface support broadcast ? */
int if_is_broadcast(struct interface *ifp)
{
llts(ZEBRA_LLT_IEEE802154, "IEEE 802.15.4");
llts(ZEBRA_LLT_IEEE802154_PHY, "IEEE 802.15.4 Phy");
default:
- zlog_warn("Unknown value %d", llt);
+ flog_err(LIB_ERR_DEVELOPMENT, "Unknown value %d", llt);
return "Unknown type!";
#undef llts
}
extern int if_is_no_ptm_operative(struct interface *);
extern int if_is_loopback(struct interface *);
extern int if_is_vrf(struct interface *ifp);
+extern bool if_is_loopback_or_vrf(struct interface *ifp);
extern int if_is_broadcast(struct interface *);
extern int if_is_pointopoint(struct interface *);
extern int if_is_multicast(struct interface *);
save_errno = errno;
umask(oldumask);
if (zl->fp == NULL) {
+
+ pthread_mutex_unlock(&loglock);
+
flog_err_sys(
LIB_ERR_SYSTEM_CALL,
"Log rotate failed: cannot open file %s for append: %s",
zl->filename, safe_strerror(save_errno));
ret = -1;
+
+ pthread_mutex_lock(&loglock);
} else {
logfile_fd = fileno(zl->fp);
zl->maxlvl[ZLOG_DEST_FILE] = level;
DESC_ENTRY(ZEBRA_ROUTE_ADD),
DESC_ENTRY(ZEBRA_ROUTE_DELETE),
DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_OWNER),
- DESC_ENTRY(ZEBRA_IPV4_ROUTE_ADD),
- DESC_ENTRY(ZEBRA_IPV4_ROUTE_DELETE),
- DESC_ENTRY(ZEBRA_IPV6_ROUTE_ADD),
- DESC_ENTRY(ZEBRA_IPV6_ROUTE_DELETE),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_ADD),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_DELETE),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_DEFAULT_ADD),
/* For logs which have error codes associated with them */
#define flog_err(ferr_id, format, ...) \
- zlog_err("[EC %d] " format, ferr_id, ##__VA_ARGS__)
+ zlog_err("[EC %"PRIu32"] " format, ferr_id, ##__VA_ARGS__)
#define flog_err_sys(ferr_id, format, ...) \
flog_err(ferr_id, format, ##__VA_ARGS__)
+++ /dev/null
-/* SNMP support
- * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra 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.
- *
- * GNU Zebra 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>
-
-#ifdef SNMP_SMUX
-#include <net-snmp/net-snmp-config.h>
-#include <net-snmp/net-snmp-includes.h>
-
-#include "log.h"
-#include "thread.h"
-#include "linklist.h"
-#include "command.h"
-#include <lib/version.h>
-#include "memory.h"
-#include "sockunion.h"
-#include "smux.h"
-
-#define SMUX_PORT_DEFAULT 199
-
-#define SMUXMAXPKTSIZE 1500
-#define SMUXMAXSTRLEN 256
-
-#define SMUX_OPEN (ASN_APPLICATION | ASN_CONSTRUCTOR | 0)
-#define SMUX_CLOSE (ASN_APPLICATION | ASN_PRIMITIVE | 1)
-#define SMUX_RREQ (ASN_APPLICATION | ASN_CONSTRUCTOR | 2)
-#define SMUX_RRSP (ASN_APPLICATION | ASN_PRIMITIVE | 3)
-#define SMUX_SOUT (ASN_APPLICATION | ASN_PRIMITIVE | 4)
-
-#define SMUX_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0)
-#define SMUX_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 1)
-#define SMUX_GETRSP (ASN_CONTEXT | ASN_CONSTRUCTOR | 2)
-#define SMUX_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 3)
-#define SMUX_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 4)
-
-#define SMUX_MAX_FAILURE 3
-
-/* SNMP tree. */
-struct subtree {
- /* Tree's oid. */
- oid name[MAX_OID_LEN];
- uint8_t name_len;
-
- /* List of the variables. */
- struct variable *variables;
-
- /* Length of the variables list. */
- int variables_num;
-
- /* Width of the variables list. */
- int variables_width;
-
- /* Registered flag. */
- int registered;
-};
-
-#define min(A,B) ((A) < (B) ? (A) : (B))
-
-enum smux_event { SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ };
-
-void smux_event(enum smux_event, int);
-
-
-/* SMUX socket. */
-int smux_sock = -1;
-
-/* SMUX subtree list. */
-struct list *treelist;
-
-/* SMUX oid. */
-oid *smux_oid = NULL;
-size_t smux_oid_len;
-
-/* SMUX password. */
-char *smux_passwd = NULL;
-
-/* SMUX read threads. */
-struct thread *smux_read_thread;
-
-/* SMUX connect thrads. */
-struct thread *smux_connect_thread;
-
-/* SMUX debug flag. */
-int debug_smux = 0;
-
-/* SMUX failure count. */
-int fail = 0;
-
-/* SMUX node. */
-static struct cmd_node smux_node = {
- SMUX_NODE, "" /* SMUX has no interface. */
-};
-
-/* thread master */
-static struct thread_master *smux_master;
-
-static int oid_compare_part(oid *o1, int o1_len, oid *o2, int o2_len)
-{
- int i;
-
- for (i = 0; i < min(o1_len, o2_len); i++) {
- if (o1[i] < o2[i])
- return -1;
- else if (o1[i] > o2[i])
- return 1;
- }
- if (o1_len < o2_len)
- return -1;
-
- return 0;
-}
-
-static void smux_oid_dump(const char *prefix, const oid *oid, size_t oid_len)
-{
- unsigned int i;
- int first = 1;
- char buf[MAX_OID_LEN * 3];
-
- buf[0] = '\0';
-
- for (i = 0; i < oid_len; i++) {
- sprintf(buf + strlen(buf), "%s%d", first ? "" : ".",
- (int)oid[i]);
- first = 0;
- }
- zlog_debug("%s: %s", prefix, buf);
-}
-
-static int smux_socket(void)
-{
- int ret;
- struct addrinfo hints, *res0, *res;
- int gai;
- int sock = 0;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- gai = getaddrinfo(NULL, "smux", &hints, &res0);
- if (gai == EAI_SERVICE) {
- char servbuf[NI_MAXSERV];
- sprintf(servbuf, "%d", SMUX_PORT_DEFAULT);
- servbuf[sizeof(servbuf) - 1] = '\0';
- gai = getaddrinfo(NULL, servbuf, &hints, &res0);
- }
- if (gai) {
- zlog_warn("Cannot locate loopback service smux");
- return -1;
- }
- for (res = res0; res; res = res->ai_next) {
- if (res->ai_family != AF_INET && res->ai_family != AF_INET6)
- continue;
-
- sock = socket(res->ai_family, res->ai_socktype,
- res->ai_protocol);
- if (sock < 0)
- continue;
- sockopt_reuseaddr(sock);
- sockopt_reuseport(sock);
- ret = connect(sock, res->ai_addr, res->ai_addrlen);
- if (ret < 0) {
- close(sock);
- sock = -1;
- continue;
- }
- break;
- }
- freeaddrinfo(res0);
- if (sock < 0)
- zlog_warn("Can't connect to SNMP agent with SMUX");
- return sock;
-}
-
-static void smux_getresp_send(oid objid[], size_t objid_len, long reqid,
- long errstat, long errindex, uint8_t val_type,
- void *arg, size_t arg_len)
-{
- uint8_t buf[BUFSIZ];
- uint8_t *ptr, *h1, *h1e, *h2, *h2e;
- size_t len, length;
-
- ptr = buf;
- len = BUFSIZ;
- length = len;
-
- if (debug_smux) {
- zlog_debug("SMUX GETRSP send");
- zlog_debug("SMUX GETRSP reqid: %ld", reqid);
- }
-
- h1 = ptr;
- /* Place holder h1 for complete sequence */
- ptr = asn_build_sequence(ptr, &len, (uint8_t)SMUX_GETRSP, 0);
- h1e = ptr;
-
- ptr = asn_build_int(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), &reqid,
- sizeof(reqid));
-
- if (debug_smux)
- zlog_debug("SMUX GETRSP errstat: %ld", errstat);
-
- ptr = asn_build_int(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &errstat, sizeof(errstat));
- if (debug_smux)
- zlog_debug("SMUX GETRSP errindex: %ld", errindex);
-
- ptr = asn_build_int(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &errindex, sizeof(errindex));
-
- h2 = ptr;
- /* Place holder h2 for one variable */
- ptr = asn_build_sequence(ptr, &len,
- (uint8_t)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
- h2e = ptr;
-
- ptr = snmp_build_var_op(ptr, objid, &objid_len, val_type, arg_len, arg,
- &len);
-
- /* Now variable size is known, fill in size */
- asn_build_sequence(h2, &length,
- (uint8_t)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
- ptr - h2e);
-
- /* Fill in size of whole sequence */
- asn_build_sequence(h1, &length, (uint8_t)SMUX_GETRSP, ptr - h1e);
-
- if (debug_smux)
- zlog_debug("SMUX getresp send: %td", (ptr - buf));
-
- send(smux_sock, buf, (ptr - buf), 0);
-}
-
-static uint8_t *smux_var(uint8_t *ptr, size_t len, oid objid[],
- size_t *objid_len, size_t *var_val_len,
- uint8_t *var_val_type, void **var_value)
-{
- uint8_t type;
- uint8_t val_type;
- size_t val_len;
- uint8_t *val;
-
- if (debug_smux)
- zlog_debug("SMUX var parse: len %zd", len);
-
- /* Parse header. */
- ptr = asn_parse_header(ptr, &len, &type);
-
- if (debug_smux) {
- zlog_debug("SMUX var parse: type %d len %zd", type, len);
- zlog_debug("SMUX var parse: type must be %d",
- (ASN_SEQUENCE | ASN_CONSTRUCTOR));
- }
-
- /* Parse var option. */
- *objid_len = MAX_OID_LEN;
- ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type, &val_len,
- &val, &len);
-
- if (var_val_len)
- *var_val_len = val_len;
-
- if (var_value)
- *var_value = (void *)val;
-
- if (var_val_type)
- *var_val_type = val_type;
-
- /* Requested object id length is objid_len. */
- if (debug_smux)
- smux_oid_dump("Request OID", objid, *objid_len);
-
- if (debug_smux)
- zlog_debug("SMUX val_type: %d", val_type);
-
- /* Check request value type. */
- if (debug_smux)
- switch (val_type) {
- case ASN_NULL:
- /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set
- to
- ASN_NULL. */
- zlog_debug("ASN_NULL");
- break;
-
- case ASN_INTEGER:
- zlog_debug("ASN_INTEGER");
- break;
- case ASN_COUNTER:
- case ASN_GAUGE:
- case ASN_TIMETICKS:
- case ASN_UINTEGER:
- zlog_debug("ASN_COUNTER");
- break;
- case ASN_COUNTER64:
- zlog_debug("ASN_COUNTER64");
- break;
- case ASN_IPADDRESS:
- zlog_debug("ASN_IPADDRESS");
- break;
- case ASN_OCTET_STR:
- zlog_debug("ASN_OCTET_STR");
- break;
- case ASN_OPAQUE:
- case ASN_NSAP:
- case ASN_OBJECT_ID:
- zlog_debug("ASN_OPAQUE");
- break;
- case SNMP_NOSUCHOBJECT:
- zlog_debug("SNMP_NOSUCHOBJECT");
- break;
- case SNMP_NOSUCHINSTANCE:
- zlog_debug("SNMP_NOSUCHINSTANCE");
- break;
- case SNMP_ENDOFMIBVIEW:
- zlog_debug("SNMP_ENDOFMIBVIEW");
- break;
- case ASN_BIT_STR:
- zlog_debug("ASN_BIT_STR");
- break;
- default:
- zlog_debug("Unknown type");
- break;
- }
- return ptr;
-}
-
-/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
- ucd-snmp smux and as such suppose, that the peer receives in the message
- only one variable. Fortunately, IBM seems to do the same in AIX. */
-
-static int smux_set(oid *reqid, size_t *reqid_len, uint8_t val_type, void *val,
- size_t val_len, int action)
-{
- int j;
- struct subtree *subtree;
- struct variable *v;
- int subresult;
- oid *suffix;
- size_t suffix_len;
- int result;
- uint8_t *statP = NULL;
- WriteMethod *write_method = NULL;
- struct listnode *node, *nnode;
-
- /* Check */
- for (ALL_LIST_ELEMENTS(treelist, node, nnode, subtree)) {
- subresult = oid_compare_part(reqid, *reqid_len, subtree->name,
- subtree->name_len);
-
- /* Subtree matched. */
- if (subresult == 0) {
- /* Prepare suffix. */
- suffix = reqid + subtree->name_len;
- suffix_len = *reqid_len - subtree->name_len;
- result = subresult;
-
- /* Check variables. */
- for (j = 0; j < subtree->variables_num; j++) {
- v = &subtree->variables[j];
-
- /* Always check suffix */
- result = oid_compare_part(suffix, suffix_len,
- v->name, v->namelen);
-
- /* This is exact match so result must be zero.
- */
- if (result == 0) {
- if (debug_smux)
- zlog_debug(
- "SMUX function call index is %d",
- v->magic);
-
- statP = (*v->findVar)(
- v, suffix, &suffix_len, 1,
- &val_len, &write_method);
-
- if (write_method) {
- return (*write_method)(
- action, val, val_type,
- val_len, statP, suffix,
- suffix_len);
- } else {
- return SNMP_ERR_READONLY;
- }
- }
-
- /* If above execution is failed or oid is small
- (so
- there is no further match). */
- if (result < 0)
- return SNMP_ERR_NOSUCHNAME;
- }
- }
- }
- return SNMP_ERR_NOSUCHNAME;
-}
-
-static int smux_get(oid *reqid, size_t *reqid_len, int exact, uint8_t *val_type,
- void **val, size_t *val_len)
-{
- int j;
- struct subtree *subtree;
- struct variable *v;
- int subresult;
- oid *suffix;
- size_t suffix_len;
- int result;
- WriteMethod *write_method = NULL;
- struct listnode *node, *nnode;
-
- /* Check */
- for (ALL_LIST_ELEMENTS(treelist, node, nnode, subtree)) {
- subresult = oid_compare_part(reqid, *reqid_len, subtree->name,
- subtree->name_len);
-
- /* Subtree matched. */
- if (subresult == 0) {
- /* Prepare suffix. */
- suffix = reqid + subtree->name_len;
- suffix_len = *reqid_len - subtree->name_len;
- result = subresult;
-
- /* Check variables. */
- for (j = 0; j < subtree->variables_num; j++) {
- v = &subtree->variables[j];
-
- /* Always check suffix */
- result = oid_compare_part(suffix, suffix_len,
- v->name, v->namelen);
-
- /* This is exact match so result must be zero.
- */
- if (result == 0) {
- if (debug_smux)
- zlog_debug(
- "SMUX function call index is %d",
- v->magic);
-
- *val = (*v->findVar)(
- v, suffix, &suffix_len, exact,
- val_len, &write_method);
-
- /* There is no instance. */
- if (*val == NULL)
- return SNMP_NOSUCHINSTANCE;
-
- /* Call is suceed. */
- *val_type = v->type;
-
- return 0;
- }
-
- /* If above execution is failed or oid is small
- (so
- there is no further match). */
- if (result < 0)
- return SNMP_ERR_NOSUCHNAME;
- }
- }
- }
- return SNMP_ERR_NOSUCHNAME;
-}
-
-static int smux_getnext(oid *reqid, size_t *reqid_len, int exact,
- uint8_t *val_type, void **val, size_t *val_len)
-{
- int j;
- oid save[MAX_OID_LEN];
- int savelen = 0;
- struct subtree *subtree;
- struct variable *v;
- int subresult;
- oid *suffix;
- size_t suffix_len;
- int result;
- WriteMethod *write_method = NULL;
- struct listnode *node, *nnode;
-
-
- /* Save incoming request. */
- oid_copy(save, reqid, *reqid_len);
- savelen = *reqid_len;
-
- /* Check */
- for (ALL_LIST_ELEMENTS(treelist, node, nnode, subtree)) {
- subresult = oid_compare_part(reqid, *reqid_len, subtree->name,
- subtree->name_len);
-
- /* If request is in the tree. The agent has to make sure we
- only receive requests we have registered for. */
- /* Unfortunately, that's not true. In fact, a SMUX subagent has
- to
- behave as if it manages the whole SNMP MIB tree itself. It's
- the
- duty of the master agent to collect the best answer and
- return it
- to the manager. See RFC 1227 chapter 3.1.6 for the glory
- details
- :-). ucd-snmp really behaves bad here as it actually might
- ask
- multiple times for the same GETNEXT request as it throws away
- the
- answer when it expects it in a different subtree and might
- come
- back later with the very same request. --jochen */
-
- if (subresult <= 0) {
- /* Prepare suffix. */
- suffix = reqid + subtree->name_len;
- suffix_len = *reqid_len - subtree->name_len;
- if (subresult < 0) {
- oid_copy(reqid, subtree->name,
- subtree->name_len);
- *reqid_len = subtree->name_len;
- }
- for (j = 0; j < subtree->variables_num; j++) {
- result = subresult;
- v = &subtree->variables[j];
-
- /* Next then check result >= 0. */
- if (result == 0)
- result = oid_compare_part(
- suffix, suffix_len, v->name,
- v->namelen);
-
- if (result <= 0) {
- if (debug_smux)
- zlog_debug(
- "SMUX function call index is %d",
- v->magic);
- if (result < 0) {
- oid_copy(suffix, v->name,
- v->namelen);
- suffix_len = v->namelen;
- }
- *val = (*v->findVar)(
- v, suffix, &suffix_len, exact,
- val_len, &write_method);
- *reqid_len =
- suffix_len + subtree->name_len;
- if (*val) {
- *val_type = v->type;
- return 0;
- }
- }
- }
- }
- }
- memcpy(reqid, save, savelen * sizeof(oid));
- *reqid_len = savelen;
-
- return SNMP_ERR_NOSUCHNAME;
-}
-
-/* GET message header. */
-static uint8_t *smux_parse_get_header(uint8_t *ptr, size_t *len, long *reqid)
-{
- uint8_t type;
- long errstat;
- long errindex;
-
- /* Request ID. */
- ptr = asn_parse_int(ptr, len, &type, reqid, sizeof(*reqid));
-
- if (debug_smux)
- zlog_debug("SMUX GET reqid: %d len: %d", (int)*reqid,
- (int)*len);
-
- /* Error status. */
- ptr = asn_parse_int(ptr, len, &type, &errstat, sizeof(errstat));
-
- if (debug_smux)
- zlog_debug("SMUX GET errstat %ld len: %zd", errstat, *len);
-
- /* Error index. */
- ptr = asn_parse_int(ptr, len, &type, &errindex, sizeof(errindex));
-
- if (debug_smux)
- zlog_debug("SMUX GET errindex %ld len: %zd", errindex, *len);
-
- return ptr;
-}
-
-static void smux_parse_set(uint8_t *ptr, size_t len, int action)
-{
- long reqid;
- oid oid[MAX_OID_LEN];
- size_t oid_len;
- uint8_t val_type;
- void *val;
- size_t val_len;
- int ret;
-
- if (debug_smux)
- zlog_debug("SMUX SET(%s) message parse: len %zd",
- (RESERVE1 == action)
- ? "RESERVE1"
- : ((FREE == action) ? "FREE" : "COMMIT"),
- len);
-
- /* Parse SET message header. */
- ptr = smux_parse_get_header(ptr, &len, &reqid);
-
- /* Parse SET message object ID. */
- ptr = smux_var(ptr, len, oid, &oid_len, &val_len, &val_type, &val);
-
- ret = smux_set(oid, &oid_len, val_type, val, val_len, action);
- if (debug_smux)
- zlog_debug("SMUX SET ret %d", ret);
-
- /* Return result. */
- if (RESERVE1 == action)
- smux_getresp_send(oid, oid_len, reqid, ret, 3, ASN_NULL, NULL,
- 0);
-}
-
-static void smux_parse_get(uint8_t *ptr, size_t len, int exact)
-{
- long reqid;
- oid oid[MAX_OID_LEN];
- size_t oid_len;
- uint8_t val_type;
- void *val;
- size_t val_len;
- int ret;
-
- if (debug_smux)
- zlog_debug("SMUX GET message parse: len %zd", len);
-
- /* Parse GET message header. */
- ptr = smux_parse_get_header(ptr, &len, &reqid);
-
- /* Parse GET message object ID. We needn't the value come */
- ptr = smux_var(ptr, len, oid, &oid_len, NULL, NULL, NULL);
-
- /* Traditional getstatptr. */
- if (exact)
- ret = smux_get(oid, &oid_len, exact, &val_type, &val, &val_len);
- else
- ret = smux_getnext(oid, &oid_len, exact, &val_type, &val,
- &val_len);
-
- /* Return result. */
- if (ret == 0)
- smux_getresp_send(oid, oid_len, reqid, 0, 0, val_type, val,
- val_len);
- else
- smux_getresp_send(oid, oid_len, reqid, ret, 3, ASN_NULL, NULL,
- 0);
-}
-
-/* Parse SMUX_CLOSE message. */
-static void smux_parse_close(uint8_t *ptr, int len)
-{
- long reason = 0;
-
- while (len--) {
- reason = (reason << 8) | (long)*ptr;
- ptr++;
- }
- zlog_info("SMUX_CLOSE with reason: %ld", reason);
-}
-
-/* SMUX_RRSP message. */
-static void smux_parse_rrsp(uint8_t *ptr, size_t len)
-{
- uint8_t val;
- long errstat;
-
- ptr = asn_parse_int(ptr, &len, &val, &errstat, sizeof(errstat));
-
- if (debug_smux)
- zlog_debug("SMUX_RRSP value: %d errstat: %ld", val, errstat);
-}
-
-/* Parse SMUX message. */
-static int smux_parse(uint8_t *ptr, size_t len)
-{
- /* This buffer we'll use for SOUT message. We could allocate it with
- malloc and save only static pointer/lenght, but IMHO static
- buffer is a faster solusion. */
- static uint8_t sout_save_buff[SMUXMAXPKTSIZE];
- static int sout_save_len = 0;
-
- int len_income = len; /* see note below: YYY */
- uint8_t type;
- uint8_t rollback;
-
- rollback = ptr[2]; /* important only for SMUX_SOUT */
-
-process_rest: /* see note below: YYY */
-
- /* Parse SMUX message type and subsequent length. */
- ptr = asn_parse_header(ptr, &len, &type);
-
- if (debug_smux)
- zlog_debug("SMUX message received type: %d rest len: %zd", type,
- len);
-
- switch (type) {
- case SMUX_OPEN:
- /* Open must be not send from SNMP agent. */
- zlog_warn("SMUX_OPEN received: resetting connection.");
- return -1;
- break;
- case SMUX_RREQ:
- /* SMUX_RREQ message is invalid for us. */
- zlog_warn("SMUX_RREQ received: resetting connection.");
- return -1;
- break;
- case SMUX_SOUT:
- /* SMUX_SOUT message is now valied for us. */
- if (debug_smux)
- zlog_debug("SMUX_SOUT(%s)",
- rollback ? "rollback" : "commit");
-
- if (sout_save_len > 0) {
- smux_parse_set(sout_save_buff, sout_save_len,
- rollback ? FREE : COMMIT);
- sout_save_len = 0;
- } else
- zlog_warn("SMUX_SOUT sout_save_len=%d - invalid",
- (int)sout_save_len);
-
- if (len_income > 3) {
- /* YYY: this strange code has to solve the "slow peer"
- problem: When agent sends SMUX_SOUT message it
- doesn't
- wait any responce and may send some next message to
- subagent. Then the peer in 'smux_read()' will recieve
- from socket the 'concatenated' buffer, contaning both
- SMUX_SOUT message and the next one
- (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check:
- if
- the buffer is longer than 3 ( length of SMUX_SOUT ),
- we
- must process the rest of it. This effect may be
- observed
- if 'debug_smux' is set to '1' */
- ptr++;
- len = len_income - 3;
- goto process_rest;
- }
- break;
- case SMUX_GETRSP:
- /* SMUX_GETRSP message is invalid for us. */
- zlog_warn("SMUX_GETRSP received: resetting connection.");
- return -1;
- break;
- case SMUX_CLOSE:
- /* Close SMUX connection. */
- if (debug_smux)
- zlog_debug("SMUX_CLOSE");
- smux_parse_close(ptr, len);
- return -1;
- break;
- case SMUX_RRSP:
- /* This is response for register message. */
- if (debug_smux)
- zlog_debug("SMUX_RRSP");
- smux_parse_rrsp(ptr, len);
- break;
- case SMUX_GET:
- /* Exact request for object id. */
- if (debug_smux)
- zlog_debug("SMUX_GET");
- smux_parse_get(ptr, len, 1);
- break;
- case SMUX_GETNEXT:
- /* Next request for object id. */
- if (debug_smux)
- zlog_debug("SMUX_GETNEXT");
- smux_parse_get(ptr, len, 0);
- break;
- case SMUX_SET:
- /* SMUX_SET is supported with some limitations. */
- if (debug_smux)
- zlog_debug("SMUX_SET");
-
- /* save the data for future SMUX_SOUT */
- memcpy(sout_save_buff, ptr, len);
- sout_save_len = len;
- smux_parse_set(ptr, len, RESERVE1);
- break;
- default:
- zlog_info("Unknown type: %d", type);
- break;
- }
- return 0;
-}
-
-/* SMUX message read function. */
-static int smux_read(struct thread *t)
-{
- int sock;
- int len;
- uint8_t buf[SMUXMAXPKTSIZE];
- int ret;
-
- /* Clear thread. */
- sock = THREAD_FD(t);
- smux_read_thread = NULL;
-
- if (debug_smux)
- zlog_debug("SMUX read start");
-
- /* Read message from SMUX socket. */
- len = recv(sock, buf, SMUXMAXPKTSIZE, 0);
-
- if (len < 0) {
- zlog_warn("Can't read all SMUX packet: %s",
- safe_strerror(errno));
- close(sock);
- smux_sock = -1;
- smux_event(SMUX_CONNECT, 0);
- return -1;
- }
-
- if (len == 0) {
- zlog_warn("SMUX connection closed: %d", sock);
- close(sock);
- smux_sock = -1;
- smux_event(SMUX_CONNECT, 0);
- return -1;
- }
-
- if (debug_smux)
- zlog_debug("SMUX read len: %d", len);
-
- /* Parse the message. */
- ret = smux_parse(buf, len);
-
- if (ret < 0) {
- close(sock);
- smux_sock = -1;
- smux_event(SMUX_CONNECT, 0);
- return -1;
- }
-
- /* Regiser read thread. */
- smux_event(SMUX_READ, sock);
-
- return 0;
-}
-
-static int smux_open(int sock)
-{
- uint8_t buf[BUFSIZ];
- uint8_t *ptr;
- size_t len;
- long version;
- const char progname[] = FRR_SMUX_NAME "-" FRR_VERSION;
-
- if (debug_smux) {
- smux_oid_dump("SMUX open oid", smux_oid, smux_oid_len);
- zlog_debug("SMUX open progname: %s", progname);
- zlog_debug("SMUX open password: %s", smux_passwd);
- }
-
- ptr = buf;
- len = BUFSIZ;
-
- /* SMUX Header. As placeholder. */
- ptr = asn_build_header(ptr, &len, (uint8_t)SMUX_OPEN, 0);
-
- /* SMUX Open. */
- version = 0;
- ptr = asn_build_int(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &version, sizeof(version));
-
- /* SMUX connection oid. */
- ptr = asn_build_objid(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
- smux_oid, smux_oid_len);
-
- /* SMUX connection description. */
- ptr = asn_build_string(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
- (const uint8_t *)progname, strlen(progname));
-
- /* SMUX connection password. */
- ptr = asn_build_string(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
- (uint8_t *)smux_passwd, strlen(smux_passwd));
-
- /* Fill in real SMUX header. We exclude ASN header size (2). */
- len = BUFSIZ;
- asn_build_header(buf, &len, (uint8_t)SMUX_OPEN, (ptr - buf) - 2);
-
- return send(sock, buf, (ptr - buf), 0);
-}
-
-/* `ename` is ignored. Instead of using the provided enterprise OID,
- the SMUX peer is used. This keep compatibility with the previous
- versions of Quagga.
-
- All other fields are used as they are intended. */
-int smux_trap(struct variable *vp, size_t vp_len, const oid *ename,
- size_t enamelen, const oid *name, size_t namelen,
- const oid *iname, size_t inamelen,
- const struct trap_object *trapobj, size_t trapobjlen,
- uint8_t sptrap)
-{
- unsigned int i;
- uint8_t buf[BUFSIZ];
- uint8_t *ptr;
- size_t len, length;
- struct in_addr addr;
- unsigned long val;
- uint8_t *h1, *h1e;
-
- ptr = buf;
- len = BUFSIZ;
- length = len;
-
- /* When SMUX connection is not established. */
- if (smux_sock < 0)
- return 0;
-
- /* SMUX header. */
- ptr = asn_build_header(ptr, &len, (uint8_t)SMUX_TRAP, 0);
-
- /* Sub agent enterprise oid. */
- ptr = asn_build_objid(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
- smux_oid, smux_oid_len);
-
- /* IP address. */
- addr.s_addr = 0;
- ptr = asn_build_string(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
- (uint8_t *)&addr, sizeof(addr));
-
- /* Generic trap integer. */
- val = SNMP_TRAP_ENTERPRISESPECIFIC;
- ptr = asn_build_int(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *)&val, sizeof(val));
-
- /* Specific trap integer. */
- val = sptrap;
- ptr = asn_build_int(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *)&val, sizeof(val));
-
- /* Timeticks timestamp. */
- val = 0;
- ptr = asn_build_unsigned_int(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS), &val,
- sizeof(val));
-
- /* Variables. */
- h1 = ptr;
- ptr = asn_build_sequence(ptr, &len,
- (uint8_t)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
-
-
- /* Iteration for each objects. */
- h1e = ptr;
- for (i = 0; i < trapobjlen; i++) {
- int ret;
- oid oid[MAX_OID_LEN];
- size_t oid_len;
- void *val;
- size_t val_len;
- uint8_t val_type;
-
- /* Make OID. */
- if (trapobj[i].namelen > 0) {
- oid_copy(oid, name, namelen);
- oid_copy(oid + namelen, trapobj[i].name,
- trapobj[i].namelen);
- oid_copy(oid + namelen + trapobj[i].namelen, iname,
- inamelen);
- oid_len = namelen + trapobj[i].namelen + inamelen;
- } else {
- oid_copy(oid, name, namelen);
- oid_copy(oid + namelen, trapobj[i].name,
- trapobj[i].namelen * (-1));
- oid_len = namelen + trapobj[i].namelen * (-1);
- }
-
- if (debug_smux) {
- smux_oid_dump("Trap", name, namelen);
- if (trapobj[i].namelen < 0)
- smux_oid_dump("Trap", trapobj[i].name,
- (-1) * (trapobj[i].namelen));
- else {
- smux_oid_dump("Trap", trapobj[i].name,
- (trapobj[i].namelen));
- smux_oid_dump("Trap", iname, inamelen);
- }
- smux_oid_dump("Trap", oid, oid_len);
- zlog_info("BUFSIZ: %d // oid_len: %lu", BUFSIZ,
- (unsigned long)oid_len);
- }
-
- ret = smux_get(oid, &oid_len, 1, &val_type, &val, &val_len);
-
- if (debug_smux)
- zlog_debug("smux_get result %d", ret);
-
- if (ret == 0)
- ptr = snmp_build_var_op(ptr, oid, &oid_len, val_type,
- val_len, val, &len);
- }
-
- /* Now variable size is known, fill in size */
- asn_build_sequence(h1, &length,
- (uint8_t)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
- ptr - h1e);
-
- /* Fill in size of whole sequence */
- len = BUFSIZ;
- asn_build_header(buf, &len, (uint8_t)SMUX_TRAP, (ptr - buf) - 2);
-
- return send(smux_sock, buf, (ptr - buf), 0);
-}
-
-static int smux_register(int sock)
-{
- uint8_t buf[BUFSIZ];
- uint8_t *ptr;
- int ret;
- size_t len;
- long priority;
- long operation;
- struct subtree *subtree;
- struct listnode *node, *nnode;
-
- ret = 0;
-
- for (ALL_LIST_ELEMENTS(treelist, node, nnode, subtree)) {
- ptr = buf;
- len = BUFSIZ;
-
- /* SMUX RReq Header. */
- ptr = asn_build_header(ptr, &len, (uint8_t)SMUX_RREQ, 0);
-
- /* Register MIB tree. */
- ptr = asn_build_objid(ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OBJECT_ID),
- subtree->name, subtree->name_len);
-
- /* Priority. */
- priority = -1;
- ptr = asn_build_int(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &priority, sizeof(priority));
-
- /* Operation. */
- operation = 2; /* Register R/W */
- ptr = asn_build_int(
- ptr, &len,
- (uint8_t)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &operation, sizeof(operation));
-
- if (debug_smux) {
- smux_oid_dump("SMUX register oid", subtree->name,
- subtree->name_len);
- zlog_debug("SMUX register priority: %ld", priority);
- zlog_debug("SMUX register operation: %ld", operation);
- }
-
- len = BUFSIZ;
- asn_build_header(buf, &len, (uint8_t)SMUX_RREQ,
- (ptr - buf) - 2);
- ret = send(sock, buf, (ptr - buf), 0);
- if (ret < 0)
- return ret;
- }
- return ret;
-}
-
-/* Try to connect to SNMP agent. */
-static int smux_connect(struct thread *t)
-{
- int ret;
-
- if (debug_smux)
- zlog_debug("SMUX connect try %d", fail + 1);
-
- /* Clear thread poner of myself. */
- smux_connect_thread = NULL;
-
- /* Make socket. Try to connect. */
- smux_sock = smux_socket();
- if (smux_sock < 0) {
- if (++fail < SMUX_MAX_FAILURE)
- smux_event(SMUX_CONNECT, 0);
- return 0;
- }
-
- /* Send OPEN PDU. */
- ret = smux_open(smux_sock);
- if (ret < 0) {
- zlog_warn("SMUX open message send failed: %s",
- safe_strerror(errno));
- close(smux_sock);
- smux_sock = -1;
- if (++fail < SMUX_MAX_FAILURE)
- smux_event(SMUX_CONNECT, 0);
- return -1;
- }
-
- /* Send any outstanding register PDUs. */
- ret = smux_register(smux_sock);
- if (ret < 0) {
- zlog_warn("SMUX register message send failed: %s",
- safe_strerror(errno));
- close(smux_sock);
- smux_sock = -1;
- if (++fail < SMUX_MAX_FAILURE)
- smux_event(SMUX_CONNECT, 0);
- return -1;
- }
-
- /* Everything goes fine. */
- smux_event(SMUX_READ, smux_sock);
-
- return 0;
-}
-
-/* Clear all SMUX related resources. */
-static void smux_stop(void)
-{
- if (smux_read_thread) {
- thread_cancel(smux_read_thread);
- smux_read_thread = NULL;
- }
-
- if (smux_connect_thread) {
- thread_cancel(smux_connect_thread);
- smux_connect_thread = NULL;
- }
-
- if (smux_sock >= 0) {
- close(smux_sock);
- smux_sock = -1;
- }
-}
-
-
-void smux_event(enum smux_event event, int sock)
-{
- switch (event) {
- case SMUX_SCHEDULE:
- smux_connect_thread = NULL;
- thread_add_event(smux_master, smux_connect, NULL, 0,
- &smux_connect_thread);
- break;
- case SMUX_CONNECT:
- smux_connect_thread = NULL;
- thread_add_timer(smux_master, smux_connect, NULL, 10,
- &smux_connect_thread);
- break;
- case SMUX_READ:
- smux_read_thread = NULL;
- thread_add_read(smux_master, smux_read, NULL, sock,
- &smux_read_thread);
- break;
- default:
- break;
- }
-}
-
-static int smux_str2oid(const char *str, oid *oid, size_t *oid_len)
-{
- int len;
- int val;
-
- len = 0;
- val = 0;
- *oid_len = 0;
-
- if (*str == '.')
- str++;
- if (*str == '\0')
- return 0;
-
- while (1) {
- if (!isdigit(*str))
- return -1;
-
- while (isdigit(*str)) {
- val *= 10;
- val += (*str - '0');
- str++;
- }
-
- if (*str == '\0')
- break;
- if (*str != '.')
- return -1;
-
- oid[len++] = val;
- val = 0;
- str++;
- }
-
- oid[len++] = val;
- *oid_len = len;
-
- return 0;
-}
-
-static oid *smux_oid_dup(oid *objid, size_t objid_len)
-{
- oid *new;
-
- new = XMALLOC(MTYPE_TMP, sizeof(oid) * objid_len);
- oid_copy(new, objid, objid_len);
-
- return new;
-}
-
-static int smux_peer_oid(struct vty *vty, const char *oid_str,
- const char *passwd_str)
-{
- int ret;
- oid oid[MAX_OID_LEN];
- size_t oid_len;
-
- ret = smux_str2oid(oid_str, oid, &oid_len);
- if (ret != 0) {
- vty_out(vty, "object ID malformed\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (smux_oid) {
- free(smux_oid);
- smux_oid = NULL;
- }
-
- /* careful, smux_passwd might point to string constant */
- if (smux_passwd) {
- free(smux_passwd);
- smux_passwd = NULL;
- }
-
- smux_oid = smux_oid_dup(oid, oid_len);
- smux_oid_len = oid_len;
-
- if (passwd_str)
- smux_passwd = strdup(passwd_str);
- else
- smux_passwd = strdup("");
-
- return 0;
-}
-
-static int smux_peer_default(void)
-{
- if (smux_oid) {
- free(smux_oid);
- smux_oid = NULL;
- }
-
- /* careful, smux_passwd might be pointing at string constant */
- if (smux_passwd) {
- free(smux_passwd);
- smux_passwd = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (smux_peer,
- smux_peer_cmd,
- "smux peer OID",
- "SNMP MUX protocol settings\n"
- "SNMP MUX peer settings\n"
- "Object ID used in SMUX peering\n")
-{
- int idx_oid = 2;
- if (smux_peer_oid(vty, argv[idx_oid]->arg, NULL) == 0) {
- smux_start();
- return CMD_SUCCESS;
- } else
- return CMD_WARNING_CONFIG_FAILED;
-}
-
-DEFUN (smux_peer_password,
- smux_peer_password_cmd,
- "smux peer OID PASSWORD",
- "SNMP MUX protocol settings\n"
- "SNMP MUX peer settings\n"
- "SMUX peering object ID\n"
- "SMUX peering password\n")
-{
- int idx_oid = 2;
- if (smux_peer_oid(vty, argv[idx_oid]->arg, argv[3]->rg) == 0) {
- smux_start();
- return CMD_SUCCESS;
- } else
- return CMD_WARNING_CONFIG_FAILED;
-}
-
-DEFUN (no_smux_peer,
- no_smux_peer_cmd,
- "no smux peer [OID [PASSWORD]]",
- NO_STR
- "SNMP MUX protocol settings\n"
- "SNMP MUX peer settings\n"
- "SMUX peering object ID\n"
- "SMUX peering password\n")
-{
- smux_stop();
- return smux_peer_default();
-}
-
-static int config_write_smux(struct vty *vty)
-{
- int first = 1;
- unsigned int i;
-
- if (smux_oid) {
- vty_out(vty, "smux peer ");
- for (i = 0; i < smux_oid_len; i++) {
- vty_out(vty, "%s%d", first ? "" : ".",
- (int)smux_oid[i]);
- first = 0;
- }
- vty_out(vty, " %s\n", smux_passwd);
- }
- return 0;
-}
-
-/* Register subtree to smux master tree. */
-void smux_register_mib(const char *descr, struct variable *var, size_t width,
- int num, oid name[], size_t namelen)
-{
- struct subtree *tree;
-
- tree = (struct subtree *)malloc(sizeof(struct subtree));
- oid_copy(tree->name, name, namelen);
- tree->name_len = namelen;
- tree->variables = var;
- tree->variables_num = num;
- tree->variables_width = width;
- tree->registered = 0;
- listnode_add_sort(treelist, tree);
-}
-
-/* Compare function to keep treelist sorted */
-static int smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
-{
- return oid_compare(tree1->name, tree1->name_len, tree2->name,
- tree2->name_len);
-}
-
-/* Initialize some values then schedule first SMUX connection. */
-void smux_init(struct thread_master *tm)
-{
- assert(tm);
- /* copy callers thread master */
- smux_master = tm;
-
- /* Make MIB tree. */
- treelist = list_new();
- treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
-
- /* Install commands. */
- install_node(&smux_node, config_write_smux);
-
- install_element(CONFIG_NODE, &smux_peer_cmd);
- install_element(CONFIG_NODE, &smux_peer_password_cmd);
- install_element(CONFIG_NODE, &no_smux_peer_cmd);
- install_element(CONFIG_NODE, &no_smux_peer_oid_cmd);
- install_element(CONFIG_NODE, &no_smux_peer_oid_password_cmd);
-}
-
-void smux_start(void)
-{
- /* Close any existing connections. */
- smux_stop();
-
- /* Schedule first connection. */
- smux_event(SMUX_SCHEDULE, 0);
-}
-#endif /* SNMP_SMUX */
int sockopt_tcp_signature(int sock, union sockunion *su, const char *password)
{
-#if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
-/* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
- * version of the Quagga patch (based on work by Rick Payne, and Bruce
- * Simpson)
- */
-#define TCP_MD5_AUTH 13
-#define TCP_MD5_AUTH_ADD 1
-#define TCP_MD5_AUTH_DEL 2
- struct tcp_rfc2385_cmd {
- uint8_t command; /* Command - Add/Delete */
- uint32_t address; /* IPV4 address associated */
- uint8_t keylen; /* MD5 Key len (do NOT assume 0 terminated
- ascii) */
- void *key; /* MD5 Key */
- } cmd;
- struct in_addr *addr = &su->sin.sin_addr;
-
- cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
- cmd.address = addr->s_addr;
- cmd.keylen = (password != NULL ? strlen(password) : 0);
- cmd.key = password;
-
- return setsockopt(sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd);
-
-#elif HAVE_DECL_TCP_MD5SIG
+#if HAVE_DECL_TCP_MD5SIG
int ret;
#ifndef GNU_LINUX
/*
long spf_backoff_schedule(struct spf_backoff *backoff)
{
- long rv;
+ long rv = 0;
struct timeval now;
gettimeofday(&now, NULL);
else
rv = backoff->long_delay;
break;
- default:
- zlog_warn("SPF Back-off(%s) in unknown state", backoff->name);
- rv = backoff->init_delay;
}
backoff_debug(
#include "network.h"
#include "prefix.h"
#include "log.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream")
-DEFINE_MTYPE_STATIC(LIB, STREAM_DATA, "Stream data")
DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO")
/* Tests whether a position is valid */
assert(size > 0);
- s = XMALLOC(MTYPE_STREAM, sizeof(struct stream));
-
- s->data = XMALLOC(MTYPE_STREAM_DATA, size);
+ s = XMALLOC(MTYPE_STREAM, sizeof(struct stream) + size);
s->getp = s->endp = 0;
s->next = NULL;
if (!s)
return;
- XFREE(MTYPE_STREAM_DATA, s->data);
XFREE(MTYPE_STREAM, s);
}
return new;
}
-size_t stream_resize(struct stream *s, size_t newsize)
+size_t stream_resize_inplace(struct stream **sptr, size_t newsize)
{
- uint8_t *newdata;
- STREAM_VERIFY_SANE(s);
+ struct stream *orig = *sptr;
- newdata = XREALLOC(MTYPE_STREAM_DATA, s->data, newsize);
+ STREAM_VERIFY_SANE(orig);
- if (newdata == NULL)
- return s->size;
+ orig = XREALLOC(MTYPE_STREAM, orig, sizeof(struct stream) + newsize);
- s->data = newdata;
- s->size = newsize;
+ orig->size = newsize;
- if (s->endp > s->size)
- s->endp = s->size;
- if (s->getp > s->endp)
- s->getp = s->endp;
+ if (orig->endp > orig->size)
+ orig->endp = orig->size;
+ if (orig->getp > orig->endp)
+ orig->getp = orig->endp;
- STREAM_VERIFY_SANE(s);
+ STREAM_VERIFY_SANE(orig);
- return s->size;
+ *sptr = orig;
+ return orig->size;
+}
+
+size_t __attribute__((deprecated))stream_resize_orig(struct stream *s,
+ size_t newsize)
+{
+ assert("stream_resize: Switch code to use stream_resize_inplace" == NULL);
+
+ return stream_resize_inplace(&s, newsize);
}
size_t stream_get_getp(struct stream *s)
struct stream {
struct stream *next;
- /* Remainder is ***private*** to stream
+ /*
+ * Remainder is ***private*** to stream
* direct access is frowned upon!
* Use the appropriate functions/macros
*/
- size_t getp; /* next get position */
- size_t endp; /* last valid data position */
- size_t size; /* size of data segment */
- unsigned char *data; /* data pointer */
+ size_t getp; /* next get position */
+ size_t endp; /* last valid data position */
+ size_t size; /* size of data segment */
+ unsigned char data[0]; /* data pointer */
};
/* First in first out queue structure. */
extern void stream_free(struct stream *);
extern struct stream *stream_copy(struct stream *, struct stream *src);
extern struct stream *stream_dup(struct stream *);
-extern size_t stream_resize(struct stream *, size_t);
+
+#if CONFDATE > 20190821
+CPP_NOTICE("lib: time to remove stream_resize_orig")
+#endif
+extern size_t stream_resize_orig(struct stream *s, size_t newsize);
+#define stream_resize stream_resize_orig
+extern size_t stream_resize_inplace(struct stream **sptr, size_t newsize);
+
extern size_t stream_get_getp(struct stream *);
extern size_t stream_get_endp(struct stream *);
extern size_t stream_get_size(struct stream *);
lib/sha256.h \
lib/sigevent.h \
lib/skiplist.h \
- lib/smux.h \
lib/sockopt.h \
lib/sockunion.h \
lib/spf_backoff.h \
lib_libfrrsnmp_la_LIBADD = lib/libfrr.la $(SNMP_LIBS)
lib_libfrrsnmp_la_SOURCES = \
lib/agentx.c \
- lib/smux.c \
lib/snmp.c \
# end
}
/* Unlock node. */
-static inline struct route_node *route_unlock_node(struct route_node *node)
+static inline void route_unlock_node(struct route_node *node)
{
assert(node->lock > 0);
(*(unsigned *)&node->lock)--;
- if (node->lock == 0) {
+ if (node->lock == 0)
route_node_delete(node);
- return NULL;
- }
-
- return node;
}
/*
DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread")
DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master")
+DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info")
DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
#if defined(__APPLE__)
/* Initialize I/O task data structures */
getrlimit(RLIMIT_NOFILE, &limit);
rv->fd_limit = (int)limit.rlim_cur;
- rv->read =
- XCALLOC(MTYPE_THREAD, sizeof(struct thread *) * rv->fd_limit);
- if (rv->read == NULL) {
- XFREE(MTYPE_THREAD_MASTER, rv);
- return NULL;
- }
- rv->write =
- XCALLOC(MTYPE_THREAD, sizeof(struct thread *) * rv->fd_limit);
- if (rv->write == NULL) {
- XFREE(MTYPE_THREAD, rv->read);
- XFREE(MTYPE_THREAD_MASTER, rv);
- return NULL;
- }
+ rv->read = XCALLOC(MTYPE_THREAD_POLL,
+ sizeof(struct thread *) * rv->fd_limit);
+
+ rv->write = XCALLOC(MTYPE_THREAD_POLL,
+ sizeof(struct thread *) * rv->fd_limit);
rv->cpu_record = hash_create_size(
8, (unsigned int (*)(void *))cpu_record_hash_key,
return NULL;
}
+#define THREAD_UNUSED_DEPTH 10
+
/* Move thread to unuse list. */
static void thread_add_unuse(struct thread_master *m, struct thread *thread)
{
assert(m != NULL && thread != NULL);
assert(thread->next == NULL);
assert(thread->prev == NULL);
- thread->ref = NULL;
- thread->type = THREAD_UNUSED;
thread->hist->total_active--;
- thread_list_add(&m->unuse, thread);
+ memset(thread, 0, sizeof(struct thread));
+ thread->type = THREAD_UNUSED;
+
+ if (m->unuse.count < THREAD_UNUSED_DEPTH)
+ thread_list_add(&m->unuse, thread);
+ else
+ XFREE(MTYPE_THREAD, thread);
}
/* Free all unused thread. */
m->alloc--;
}
}
- XFREE(MTYPE_THREAD, thread_array);
+ XFREE(MTYPE_THREAD_POLL, thread_array);
}
static void thread_queue_free(struct thread_master *m, struct pqueue *queue)
*/
void thread_cancel(struct thread *thread)
{
- assert(thread->master->owner == pthread_self());
+ struct thread_master *master = thread->master;
+
+ assert(master->owner == pthread_self());
- pthread_mutex_lock(&thread->master->mtx);
+ pthread_mutex_lock(&master->mtx);
{
struct cancel_req *cr =
XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
cr->thread = thread;
- listnode_add(thread->master->cancel_req, cr);
- do_thread_cancel(thread->master);
+ listnode_add(master->cancel_req, cr);
+ do_thread_cancel(master);
}
- pthread_mutex_unlock(&thread->master->mtx);
+ pthread_mutex_unlock(&master->mtx);
}
/**
}
/*
- * VRF bit-map
+ * VRF hash for storing set or not.
*/
+struct vrf_bit_set {
+ vrf_id_t vrf_id;
+ bool set;
+};
-#define VRF_BITMAP_NUM_OF_GROUPS 1024
-#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT32_MAX / VRF_BITMAP_NUM_OF_GROUPS)
-#define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP \
- (VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */
+static unsigned int vrf_hash_bitmap_key(void *data)
+{
+ struct vrf_bit_set *bit = data;
-#define VRF_BITMAP_GROUP(_id) ((_id) / VRF_BITMAP_NUM_OF_BITS_IN_GROUP)
-#define VRF_BITMAP_BIT_OFFSET(_id) ((_id) % VRF_BITMAP_NUM_OF_BITS_IN_GROUP)
+ return bit->vrf_id;
+}
-#define VRF_BITMAP_INDEX_IN_GROUP(_bit_offset) ((_bit_offset) / CHAR_BIT)
-#define VRF_BITMAP_FLAG(_bit_offset) \
- (((uint8_t)1) << ((_bit_offset) % CHAR_BIT))
+static int vrf_hash_bitmap_cmp(const void *a, const void *b)
+{
+ const struct vrf_bit_set *bit1 = a;
+ const struct vrf_bit_set *bit2 = b;
-struct vrf_bitmap {
- uint8_t *groups[VRF_BITMAP_NUM_OF_GROUPS];
-};
+ return bit1->vrf_id == bit2->vrf_id;
+}
+
+static void *vrf_hash_bitmap_alloc(void *data)
+{
+ struct vrf_bit_set *copy = data;
+ struct vrf_bit_set *bit;
+
+ bit = XMALLOC(MTYPE_VRF_BITMAP, sizeof(*bit));
+ bit->vrf_id = copy->vrf_id;
+
+ return bit;
+}
+
+static void vrf_hash_bitmap_free(void *data)
+{
+ struct vrf_bit_set *bit = data;
+
+ XFREE(MTYPE_VRF_BITMAP, bit);
+}
vrf_bitmap_t vrf_bitmap_init(void)
{
- return (vrf_bitmap_t)XCALLOC(MTYPE_VRF_BITMAP,
- sizeof(struct vrf_bitmap));
+ return hash_create_size(32, vrf_hash_bitmap_key, vrf_hash_bitmap_cmp,
+ "VRF BIT HASH");
}
void vrf_bitmap_free(vrf_bitmap_t bmap)
{
- struct vrf_bitmap *bm = (struct vrf_bitmap *)bmap;
- int i;
+ struct hash *vrf_hash = bmap;
- if (bmap == VRF_BITMAP_NULL)
+ if (vrf_hash == NULL)
return;
- for (i = 0; i < VRF_BITMAP_NUM_OF_GROUPS; i++)
- if (bm->groups[i])
- XFREE(MTYPE_VRF_BITMAP, bm->groups[i]);
-
- XFREE(MTYPE_VRF_BITMAP, bm);
+ hash_clean(vrf_hash, vrf_hash_bitmap_free);
+ hash_free(vrf_hash);
}
void vrf_bitmap_set(vrf_bitmap_t bmap, vrf_id_t vrf_id)
{
- struct vrf_bitmap *bm = (struct vrf_bitmap *)bmap;
- uint8_t group = VRF_BITMAP_GROUP(vrf_id);
- uint8_t offset = VRF_BITMAP_BIT_OFFSET(vrf_id);
+ struct vrf_bit_set lookup = { .vrf_id = vrf_id };
+ struct hash *vrf_hash = bmap;
+ struct vrf_bit_set *bit;
- if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN)
+ if (vrf_hash == NULL || vrf_id == VRF_UNKNOWN)
return;
- if (bm->groups[group] == NULL)
- bm->groups[group] = XCALLOC(MTYPE_VRF_BITMAP,
- VRF_BITMAP_NUM_OF_BYTES_IN_GROUP);
-
- SET_FLAG(bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP(offset)],
- VRF_BITMAP_FLAG(offset));
+ bit = hash_get(vrf_hash, &lookup, vrf_hash_bitmap_alloc);
+ bit->set = true;
}
void vrf_bitmap_unset(vrf_bitmap_t bmap, vrf_id_t vrf_id)
{
- struct vrf_bitmap *bm = (struct vrf_bitmap *)bmap;
- uint8_t group = VRF_BITMAP_GROUP(vrf_id);
- uint8_t offset = VRF_BITMAP_BIT_OFFSET(vrf_id);
+ struct vrf_bit_set lookup = { .vrf_id = vrf_id };
+ struct hash *vrf_hash = bmap;
+ struct vrf_bit_set *bit;
- if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN
- || bm->groups[group] == NULL)
+ if (vrf_hash == NULL || vrf_id == VRF_UNKNOWN)
return;
- UNSET_FLAG(bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP(offset)],
- VRF_BITMAP_FLAG(offset));
+ bit = hash_get(vrf_hash, &lookup, vrf_hash_bitmap_alloc);
+ bit->set = false;
}
int vrf_bitmap_check(vrf_bitmap_t bmap, vrf_id_t vrf_id)
{
- struct vrf_bitmap *bm = (struct vrf_bitmap *)bmap;
- uint8_t group = VRF_BITMAP_GROUP(vrf_id);
- uint8_t offset = VRF_BITMAP_BIT_OFFSET(vrf_id);
+ struct vrf_bit_set lookup = { .vrf_id = vrf_id };
+ struct hash *vrf_hash = bmap;
+ struct vrf_bit_set *bit;
- if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN
- || bm->groups[group] == NULL)
+ if (vrf_hash == NULL || vrf_id == VRF_UNKNOWN)
return 0;
- return CHECK_FLAG(bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP(offset)],
- VRF_BITMAP_FLAG(offset))
- ? 1
- : 0;
+ bit = hash_lookup(vrf_hash, &lookup);
+ if (bit)
+ return bit->set;
+
+ return 0;
}
static void vrf_autocomplete(vector comps, struct cmd_token *token)
return CMD_SUCCESS;
}
-int vrf_is_mapped_on_netns(vrf_id_t vrf_id)
+int vrf_is_mapped_on_netns(struct vrf *vrf)
{
- struct vrf *vrf = vrf_lookup_by_id(vrf_id);
-
if (!vrf || vrf->data.l.netns_name[0] == '\0')
return 0;
if (vrf->vrf_id == VRF_DEFAULT)
if (fd < 0 || name == NULL)
return fd;
- if (vrf_is_mapped_on_netns(vrf_id))
+ if (vrf_is_mapped_on_netns(vrf_lookup_by_id(vrf_id)))
return fd;
#ifdef SO_BINDTODEVICE
ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1);
#define VRF_DEFAULT vrf_get_default_id()
/* VRF is mapped on netns or not ? */
-int vrf_is_mapped_on_netns(vrf_id_t vrf_id);
+int vrf_is_mapped_on_netns(struct vrf *vrf);
/* VRF switch from NETNS */
extern int vrf_switch_to_netns(vrf_id_t vrf_id);
* "xdr_encode"-like interface that allows daemon (client) to send
* a message to zebra server for a route that needs to be
* added/deleted to the kernel. Info about the route is specified
- * by the caller in a struct zapi_ipv4. zapi_ipv4_read() then writes
+ * by the caller in a struct zapi_route. zapi_route_encode() then writes
* the info down the zclient socket using the stream_* functions.
*
* The corresponding read ("xdr_decode") function on the server
- * side is zread_ipv4_add()/zread_ipv4_delete().
+ * side is zapi_route_decode().
*
* 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* is set to 1 and a nexthop of type NEXTHOP_TYPE_BLACKHOLE is the sole
* nexthop.
*
- * The original struct zapi_ipv4, zapi_ipv4_route() and zread_ipv4_*()
- * infrastructure was built around the traditional (32-bit "gate OR
- * ifindex") nexthop data unit. A special encoding can be used to feed
- * onlink (64-bit "gate AND ifindex") nexthops into zapi_ipv4_route()
- * using the same zapi_ipv4 structure. This is done by setting zapi_ipv4
- * fields as follows:
+ * The original struct zapi_route_*() infrastructure was built around
+ * the traditional (32-bit "gate OR ifindex") nexthop data unit.
+ * A special encoding can be used to feed onlink (64-bit "gate AND ifindex")
+ * nexthops into zapi_route_encode() using the same zapi_route structure.
+ * This is done by setting zapi_route fields as follows:
* - .message |= ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_ONLINK
* - .nexthop_num == .ifindex_num
* - .nexthop and .ifindex are filled with gate and ifindex parts of
* each compound nexthop, both in the same order
*
- * zapi_ipv4_route() will produce two nexthop data units for each such
- * interleaved 64-bit nexthop. On the zserv side of the socket it will be
- * mapped to a singlle NEXTHOP_TYPE_IPV4_IFINDEX_OL RIB nexthop structure.
- *
* If ZAPI_MESSAGE_DISTANCE is set, the distance value is written as a 1
* byte value.
*
*
* XXX: No attention paid to alignment.
*/
-int zapi_ipv4_route(uint8_t cmd, struct zclient *zclient, struct prefix_ipv4 *p,
- struct zapi_ipv4 *api)
-{
- int i;
- int psize;
- struct stream *s;
-
- /* Reset stream. */
- s = zclient->obuf;
- stream_reset(s);
-
- /* Some checks for labeled-unicast. The current expectation is that each
- * nexthop is accompanied by a label in the case of labeled-unicast.
- */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)
- && CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
- /* We expect prefixes installed with labels and the number to
- * match
- * the number of nexthops.
- */
- assert(api->label_num == api->nexthop_num);
- }
-
- zclient_create_header(s, cmd, api->vrf_id);
-
- /* Put type and nexthop. */
- stream_putc(s, api->type);
- stream_putw(s, api->instance);
- stream_putl(s, api->flags);
- stream_putc(s, api->message);
- stream_putw(s, api->safi);
-
- /* Put prefix information. */
- psize = PSIZE(p->prefixlen);
- stream_putc(s, p->prefixlen);
- stream_write(s, (uint8_t *)&p->prefix, psize);
-
- /* Nexthop, ifindex, distance and metric information. */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
- stream_putc(s, api->nexthop_num + api->ifindex_num);
-
- for (i = 0; i < api->nexthop_num; i++) {
- stream_putc(s, NEXTHOP_TYPE_IPV4);
- stream_put_in_addr(s, api->nexthop[i]);
- /* For labeled-unicast, each nexthop is followed by
- * label. */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL))
- stream_putl(s, api->label[i]);
- }
- for (i = 0; i < api->ifindex_num; i++) {
- stream_putc(s, NEXTHOP_TYPE_IFINDEX);
- stream_putl(s, api->ifindex[i]);
- }
- }
-
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
- stream_putc(s, api->distance);
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC))
- stream_putl(s, api->metric);
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TAG))
- stream_putl(s, api->tag);
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU))
- stream_putl(s, api->mtu);
-
- /* Put length at the first point of the stream. */
- stream_putw_at(s, 0, stream_get_endp(s));
-
- return zclient_send_message(zclient);
-}
-
-int zapi_ipv4_route_ipv6_nexthop(uint8_t cmd, struct zclient *zclient,
- struct prefix_ipv4 *p, struct zapi_ipv6 *api)
-{
- int i;
- int psize;
- struct stream *s;
-
- /* Reset stream. */
- s = zclient->obuf;
- stream_reset(s);
-
- /* Some checks for labeled-unicast. The current expectation is that each
- * nexthop is accompanied by a label in the case of labeled-unicast.
- */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)
- && CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
- /* We expect prefixes installed with labels and the number to
- * match
- * the number of nexthops.
- */
- assert(api->label_num == api->nexthop_num);
- }
-
- zclient_create_header(s, cmd, api->vrf_id);
-
- /* Put type and nexthop. */
- stream_putc(s, api->type);
- stream_putw(s, api->instance);
- stream_putl(s, api->flags);
- stream_putc(s, api->message);
- stream_putw(s, api->safi);
-
- /* Put prefix information. */
- psize = PSIZE(p->prefixlen);
- stream_putc(s, p->prefixlen);
- stream_write(s, (uint8_t *)&p->prefix, psize);
-
- /* Nexthop, ifindex, distance and metric information. */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
- stream_putc(s, api->nexthop_num + api->ifindex_num);
-
- for (i = 0; i < api->nexthop_num; i++) {
- stream_putc(s, NEXTHOP_TYPE_IPV6);
- stream_write(s, (uint8_t *)api->nexthop[i], 16);
- /* For labeled-unicast, each nexthop is followed by
- * label. */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL))
- stream_putl(s, api->label[i]);
- }
- for (i = 0; i < api->ifindex_num; i++) {
- stream_putc(s, NEXTHOP_TYPE_IFINDEX);
- stream_putl(s, api->ifindex[i]);
- }
- }
-
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
- stream_putc(s, api->distance);
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC))
- stream_putl(s, api->metric);
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TAG))
- stream_putl(s, api->tag);
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU))
- stream_putl(s, api->mtu);
-
- /* Put length at the first point of the stream. */
- stream_putw_at(s, 0, stream_get_endp(s));
-
- return zclient_send_message(zclient);
-}
-
-int zapi_ipv6_route(uint8_t cmd, struct zclient *zclient, struct prefix_ipv6 *p,
- struct prefix_ipv6 *src_p, struct zapi_ipv6 *api)
-{
- int i;
- int psize;
- struct stream *s;
-
- /* either we have !SRCPFX && src_p == NULL, or SRCPFX && src_p != NULL
- */
- assert(!(api->message & ZAPI_MESSAGE_SRCPFX) == !src_p);
-
- /* Reset stream. */
- s = zclient->obuf;
- stream_reset(s);
-
- /* Some checks for labeled-unicast. The current expectation is that each
- * nexthop is accompanied by a label in the case of labeled-unicast.
- */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)
- && CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
- /* We expect prefixes installed with labels and the number to
- * match
- * the number of nexthops.
- */
- assert(api->label_num == api->nexthop_num);
- }
-
- zclient_create_header(s, cmd, api->vrf_id);
-
- /* Put type and nexthop. */
- stream_putc(s, api->type);
- stream_putw(s, api->instance);
- stream_putl(s, api->flags);
- stream_putc(s, api->message);
- stream_putw(s, api->safi);
-
- /* Put prefix information. */
- psize = PSIZE(p->prefixlen);
- stream_putc(s, p->prefixlen);
- stream_write(s, (uint8_t *)&p->prefix, psize);
-
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_SRCPFX)) {
- psize = PSIZE(src_p->prefixlen);
- stream_putc(s, src_p->prefixlen);
- stream_write(s, (uint8_t *)&src_p->prefix, psize);
- }
-
- /* Nexthop, ifindex, distance and metric information. */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
- stream_putc(s, api->nexthop_num + api->ifindex_num);
-
- for (i = 0; i < api->nexthop_num; i++) {
- stream_putc(s, NEXTHOP_TYPE_IPV6);
- stream_write(s, (uint8_t *)api->nexthop[i], 16);
- /* For labeled-unicast, each nexthop is followed by
- * label. */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL))
- stream_putl(s, api->label[i]);
- }
- for (i = 0; i < api->ifindex_num; i++) {
- stream_putc(s, NEXTHOP_TYPE_IFINDEX);
- stream_putl(s, api->ifindex[i]);
- }
- }
-
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
- stream_putc(s, api->distance);
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC))
- stream_putl(s, api->metric);
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TAG))
- stream_putl(s, api->tag);
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU))
- stream_putl(s, api->mtu);
-
- /* Put length at the first point of the stream. */
- stream_putw_at(s, 0, stream_get_endp(s));
-
- return zclient_send_message(zclient);
-}
-
int zclient_route_send(uint8_t cmd, struct zclient *zclient,
struct zapi_route *api)
{
ZEBRA_ROUTE_ADD,
ZEBRA_ROUTE_DELETE,
ZEBRA_ROUTE_NOTIFY_OWNER,
- ZEBRA_IPV4_ROUTE_ADD,
- ZEBRA_IPV4_ROUTE_DELETE,
- ZEBRA_IPV6_ROUTE_ADD,
- ZEBRA_IPV6_ROUTE_DELETE,
ZEBRA_REDISTRIBUTE_ADD,
ZEBRA_REDISTRIBUTE_DELETE,
ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
*/
#define ZAPI_MESSAGE_TABLEID 0x80
-#define ZSERV_VERSION 5
+#define ZSERV_VERSION 6
/* Zserv protocol message header */
struct zmsghdr {
uint16_t length;
uint32_t tableid;
};
-/* Zebra IPv4 route message API. */
-struct zapi_ipv4 {
- uint8_t type;
- unsigned short instance;
-
- uint32_t flags;
-
- uint8_t message;
-
- safi_t safi;
-
- uint8_t nexthop_num;
- struct in_addr **nexthop;
-
- uint8_t ifindex_num;
- ifindex_t *ifindex;
-
- uint8_t label_num;
- unsigned int *label;
-
- uint8_t distance;
-
- uint32_t metric;
-
- route_tag_t tag;
-
- uint32_t mtu;
-
- vrf_id_t vrf_id;
-};
-
struct zapi_pw {
char ifname[IF_NAMESIZE];
ifindex_t ifindex;
extern void zebra_interface_if_set_value(struct stream *, struct interface *);
extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
-/* clang-format off */
-#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 */
-
-extern int zapi_ipv4_route(uint8_t, struct zclient *, struct prefix_ipv4 *,
- struct zapi_ipv4 *) __attribute__((deprecated));
-
extern struct interface *zebra_interface_link_params_read(struct stream *);
extern size_t zebra_interface_link_params_write(struct stream *,
struct interface *);
zebra_size_t length, vrf_id_t vrf_id,
struct zapi_pw_status *pw);
-/* IPv6 prefix add and delete function prototype. */
-
-struct zapi_ipv6 {
- uint8_t type;
- unsigned short instance;
-
- uint32_t flags;
-
- uint8_t message;
-
- safi_t safi;
-
- uint8_t nexthop_num;
- struct in6_addr **nexthop;
-
- uint8_t ifindex_num;
- ifindex_t *ifindex;
-
- uint8_t label_num;
- unsigned int *label;
-
- uint8_t distance;
-
- uint32_t metric;
-
- route_tag_t tag;
-
- uint32_t mtu;
-
- vrf_id_t vrf_id;
-};
-
-extern int zapi_ipv6_route(uint8_t cmd, struct zclient *zclient,
- struct prefix_ipv6 *p, struct prefix_ipv6 *src_p,
- struct zapi_ipv6 *api) __attribute__((deprecated));
-extern int zapi_ipv4_route_ipv6_nexthop(uint8_t, struct zclient *,
- struct prefix_ipv4 *,
- struct zapi_ipv6 *)
- __attribute__((deprecated));
extern int zclient_route_send(uint8_t, struct zclient *, struct zapi_route *);
extern int zclient_send_rnh(struct zclient *zclient, int command,
struct prefix *p, bool exact_match,
#include "ospfd/ospf_lsdb.h"
#include "ospfd/ospf_neighbor.h"
#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_api.h"
newlsa->length = htons(length);
/* Create OSPF LSA. */
- if ((new = ospf_lsa_new()) == NULL) {
- zlog_warn("ospf_apiserver_opaque_lsa_new: ospf_lsa_new() ?");
- stream_free(s);
- return NULL;
- }
-
- if ((new->data = ospf_lsa_data_new(length)) == NULL) {
- zlog_warn(
- "ospf_apiserver_opaque_lsa_new: ospf_lsa_data_new() ?");
- ospf_lsa_unlock(&new);
- stream_free(s);
- return NULL;
- }
+ new = ospf_lsa_new_and_data(length);
new->area = area;
new->oi = oi;
p->prefixlen);
}
-/* Lookup external route. */
-struct ospf_route *ospf_external_route_lookup(struct ospf *ospf,
- struct prefix_ipv4 *p)
-{
- struct route_node *rn;
-
- rn = route_node_lookup(ospf->old_external_route, (struct prefix *)p);
- if (rn) {
- route_unlock_node(rn);
- if (rn->info)
- return rn->info;
- }
-
- zlog_warn("Route[%s/%d]: lookup, no such prefix", inet_ntoa(p->prefix),
- p->prefixlen);
-
- return NULL;
-}
-
-
/* Add an External info for AS-external-LSA. */
struct external_info *ospf_external_info_new(uint8_t type,
unsigned short instance)
extern struct external_info *ospf_external_info_lookup(struct ospf *, uint8_t,
unsigned short,
struct prefix_ipv4 *);
-extern struct ospf_route *ospf_external_route_lookup(struct ospf *,
- struct prefix_ipv4 *);
extern void ospf_asbr_status_update(struct ospf *, uint8_t);
extern void ospf_redistribute_withdraw(struct ospf *, uint8_t, unsigned short);
struct prefix_ipv4 asbr, p;
struct route_node *rn;
struct ospf_route *new, * or ;
+ char buf1[INET_ADDRSTRLEN];
int ret;
assert(lsa);
return 0;
}
- if (IS_DEBUG_OSPF(lsa, LSA))
+ if (IS_DEBUG_OSPF(lsa, LSA)) {
+ snprintf(buf1, INET_ADDRSTRLEN, "%s",
+ inet_ntoa(al->header.adv_router));
zlog_debug(
- "Route[External]: Calculate AS-external-LSA to %s/%d",
- inet_ntoa(al->header.id), ip_masklen(al->mask));
+ "Route[External]: Calculate AS-external-LSA to %s/%d adv_router %s",
+ inet_ntoa(al->header.id), ip_masklen(al->mask), buf1);
+ }
+
/* (1) If the cost specified by the LSA is LSInfinity, or if the
LSA's LS age is equal to MaxAge, then examine the next LSA. */
if ((metric = GET_METRIC(al->e[0].metric)) >= OSPF_LS_INFINITY) {
if (!rn || (or = rn->info) == NULL) {
if (IS_DEBUG_OSPF(lsa, LSA))
- zlog_debug("Route[External]: Adding a new route %s/%d",
- inet_ntoa(p.prefix), p.prefixlen);
+ zlog_debug("Route[External]: Adding a new route %s/%d with paths %u",
+ inet_ntoa(p.prefix), p.prefixlen,
+ listcount(asbr_route->paths));
ospf_route_add(ospf->new_external_route, &p, new, asbr_route);
lsah->length = htons(length);
/* Now, create an OSPF LSA instance. */
- new = ospf_lsa_new();
- if (new == NULL) {
- zlog_warn("EXT (%s): ospf_lsa_new() error", __func__);
- stream_free(s);
- return NULL;
- }
- new->data = ospf_lsa_data_new(length);
- if (new->data == NULL) {
- zlog_warn("EXT (%s): ospf_lsa_data_new() error", __func__);
- ospf_lsa_unlock(&new);
- new = NULL;
- stream_free(s);
- return NULL;
- }
+ new = ospf_lsa_new_and_data(length);
/* Segment Routing belongs only to default VRF */
new->vrf_id = VRF_DEFAULT;
lsah->length = htons(length);
/* Now, create an OSPF LSA instance. */
- new = ospf_lsa_new();
- if (new == NULL) {
- zlog_warn("EXT (%s): ospf_lsa_new() error", __func__);
- stream_free(s);
- return NULL;
- }
- new->data = ospf_lsa_data_new(length);
- if (new->data == NULL) {
- zlog_warn("EXT (%s): ospf_lsa_data_new() error", __func__);
- ospf_lsa_unlock(&new);
- new = NULL;
- stream_free(s);
- return NULL;
- }
+ new = ospf_lsa_new_and_data(length);
/* Segment Routing belongs only to default VRF */
new->vrf_id = VRF_DEFAULT;
{
struct ospf_lsa *new;
- new = ospf_lsa_new();
- new->data = ospf_lsa_data_new(OSPF_LSA_HEADER_SIZE);
+ new = ospf_lsa_new_and_data(OSPF_LSA_HEADER_SIZE);
memcpy(new->data, lsah, OSPF_LSA_HEADER_SIZE);
return new;
return new;
}
+struct ospf_lsa *ospf_lsa_new_and_data(size_t size)
+{
+ struct ospf_lsa *new;
+
+ new = ospf_lsa_new();
+ new->data = ospf_lsa_data_new(size);
+
+ return new;
+}
+
/* Duplicate OSPF LSA. */
struct ospf_lsa *ospf_lsa_dup(struct ospf_lsa *lsa)
{
}
/* Set a link information. */
-static char link_info_set(struct stream *s, struct in_addr id,
+static char link_info_set(struct stream **s, struct in_addr id,
struct in_addr data, uint8_t type, uint8_t tos,
uint16_t cost)
{
* more.
* we try accomodate those here.
*/
- if (STREAM_WRITEABLE(s) < OSPF_ROUTER_LSA_LINK_SIZE) {
+ if (STREAM_WRITEABLE(*s) < OSPF_ROUTER_LSA_LINK_SIZE) {
size_t ret = OSPF_MAX_LSA_SIZE;
/* Can we enlarge the stream still? */
- if (STREAM_SIZE(s) == OSPF_MAX_LSA_SIZE) {
+ if (STREAM_SIZE(*s) == OSPF_MAX_LSA_SIZE) {
/* we futz the size here for simplicity, really we need
* to account
* for just:
*
* Simpler just to subtract OSPF_MAX_LSA_SIZE though.
*/
- ret = stream_resize(
+ ret = stream_resize_inplace(
s, OSPF_MAX_PACKET_SIZE - OSPF_MAX_LSA_SIZE);
}
if (ret == OSPF_MAX_LSA_SIZE) {
zlog_warn(
"%s: Out of space in LSA stream, left %zd, size %zd",
- __func__, STREAM_WRITEABLE(s), STREAM_SIZE(s));
+ __func__, STREAM_WRITEABLE(*s),
+ STREAM_SIZE(*s));
return 0;
}
}
/* TOS based routing is not supported. */
- stream_put_ipv4(s, id.s_addr); /* Link ID. */
- stream_put_ipv4(s, data.s_addr); /* Link Data. */
- stream_putc(s, type); /* Link Type. */
- stream_putc(s, tos); /* TOS = 0. */
- stream_putw(s, cost); /* Link Cost. */
+ stream_put_ipv4(*s, id.s_addr); /* Link ID. */
+ stream_put_ipv4(*s, data.s_addr); /* Link Data. */
+ stream_putc(*s, type); /* Link Type. */
+ stream_putc(*s, tos); /* TOS = 0. */
+ stream_putw(*s, cost); /* Link Cost. */
return 1;
}
/* Describe Point-to-Point link (Section 12.4.1.1). */
-static int lsa_link_ptop_set(struct stream *s, struct ospf_interface *oi)
+static int lsa_link_ptop_set(struct stream **s, struct ospf_interface *oi)
{
int links = 0;
struct ospf_neighbor *nbr;
}
/* Describe Broadcast Link. */
-static int lsa_link_broadcast_set(struct stream *s, struct ospf_interface *oi)
+static int lsa_link_broadcast_set(struct stream **s, struct ospf_interface *oi)
{
struct ospf_neighbor *dr;
struct in_addr id, mask;
}
}
-static int lsa_link_loopback_set(struct stream *s, struct ospf_interface *oi)
+static int lsa_link_loopback_set(struct stream **s, struct ospf_interface *oi)
{
struct in_addr id, mask;
}
/* Describe Virtual Link. */
-static int lsa_link_virtuallink_set(struct stream *s, struct ospf_interface *oi)
+static int lsa_link_virtuallink_set(struct stream **s,
+ struct ospf_interface *oi)
{
struct ospf_neighbor *nbr;
uint16_t cost = ospf_link_cost(oi);
12.4.1.4.*/
/* from "edward rrr" <edward_rrr@hotmail.com>
http://marc.theaimsgroup.com/?l=zebra&m=100739222210507&w=2 */
-static int lsa_link_ptomp_set(struct stream *s, struct ospf_interface *oi)
+static int lsa_link_ptomp_set(struct stream **s, struct ospf_interface *oi)
{
int links = 0;
struct route_node *rn;
}
/* Set router-LSA link information. */
-static int router_lsa_link_set(struct stream *s, struct ospf_area *area)
+static int router_lsa_link_set(struct stream **s, struct ospf_area *area)
{
struct listnode *node;
struct ospf_interface *oi;
}
/* Set router-LSA body. */
-static void ospf_router_lsa_body_set(struct stream *s, struct ospf_area *area)
+static void ospf_router_lsa_body_set(struct stream **s, struct ospf_area *area)
{
unsigned long putp;
uint16_t cnt;
/* Set flags. */
- stream_putc(s, router_lsa_flags(area));
+ stream_putc(*s, router_lsa_flags(area));
/* Set Zero fields. */
- stream_putc(s, 0);
+ stream_putc(*s, 0);
/* Keep pointer to # links. */
- putp = stream_get_endp(s);
+ putp = stream_get_endp(*s);
/* Forward word */
- stream_putw(s, 0);
+ stream_putw(*s, 0);
/* Set all link information. */
cnt = router_lsa_link_set(s, area);
/* Set # of links here. */
- stream_putw_at(s, putp, cnt);
+ stream_putw_at(*s, putp, cnt);
}
static int ospf_stub_router_timer(struct thread *t)
OSPF_ROUTER_LSA, ospf->router_id, ospf->router_id);
/* Set router-LSA body fields. */
- ospf_router_lsa_body_set(s, area);
+ ospf_router_lsa_body_set(&s, area);
/* Set length. */
length = stream_get_endp(s);
lsah->length = htons(length);
/* Now, create OSPF LSA instance. */
- if ((new = ospf_lsa_new()) == NULL) {
- zlog_err("%s: Unable to create new lsa", __func__);
- return NULL;
- }
+ new = ospf_lsa_new_and_data(length);
new->area = area;
SET_FLAG(new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED);
new->vrf_id = area->ospf->vrf_id;
/* Copy LSA data to store, discard stream. */
- new->data = ospf_lsa_data_new(length);
memcpy(new->data, lsah, length);
stream_free(s);
lsah->length = htons(length);
/* Create OSPF LSA instance. */
- if ((new = ospf_lsa_new()) == NULL) {
- zlog_err("%s: ospf_lsa_new returned NULL", __func__);
- return NULL;
- }
+ new = ospf_lsa_new_and_data(length);
new->area = oi->area;
SET_FLAG(new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED);
new->vrf_id = oi->ospf->vrf_id;
/* Copy LSA to store. */
- new->data = ospf_lsa_data_new(length);
memcpy(new->data, lsah, length);
stream_free(s);
lsah->length = htons(length);
/* Create OSPF LSA instance. */
- new = ospf_lsa_new();
+ new = ospf_lsa_new_and_data(length);
new->area = area;
SET_FLAG(new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED);
new->vrf_id = area->ospf->vrf_id;
/* Copy LSA to store. */
- new->data = ospf_lsa_data_new(length);
memcpy(new->data, lsah, length);
stream_free(s);
lsah->length = htons(length);
/* Create OSPF LSA instance. */
- new = ospf_lsa_new();
+ new = ospf_lsa_new_and_data(length);
new->area = area;
SET_FLAG(new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED);
new->vrf_id = area->ospf->vrf_id;
/* Copy LSA to store. */
- new->data = ospf_lsa_data_new(length);
memcpy(new->data, lsah, length);
stream_free(s);
lsah->length = htons(length);
/* Now, create OSPF LSA instance. */
- new = ospf_lsa_new();
+ new = ospf_lsa_new_and_data(length);
new->area = NULL;
SET_FLAG(new->flags,
OSPF_LSA_SELF | OSPF_LSA_APPROVED | OSPF_LSA_SELF_CHECKED);
new->vrf_id = ospf->vrf_id;
/* Copy LSA data to store, discard stream. */
- new->data = ospf_lsa_data_new(length);
memcpy(new->data, lsah, length);
stream_free(s);
/* Prototype for LSA primitive. */
extern struct ospf_lsa *ospf_lsa_new(void);
+extern struct ospf_lsa *ospf_lsa_new_and_data(size_t size);
extern struct ospf_lsa *ospf_lsa_dup(struct ospf_lsa *);
extern void ospf_lsa_free(struct ospf_lsa *);
extern struct ospf_lsa *ospf_lsa_lock(struct ospf_lsa *);
#include "ospfd/ospf_lsdb.h"
#include "ospfd/ospf_neighbor.h"
#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_vty.h"
#include "ospfd/ospf_bfd.h"
}
/* Create OSPF LSA instance. */
- lsa = ospf_lsa_new();
+ lsa = ospf_lsa_new_and_data(length);
lsa->vrf_id = oi->ospf->vrf_id;
/* We may wish to put some error checking if type NSSA comes in
break;
}
- lsa->data = ospf_lsa_data_new(length);
memcpy(lsa->data, lsah, length);
if (IS_DEBUG_OSPF_EVENT)
lsah->length = htons(length);
/* Now, create an OSPF LSA instance. */
- if ((new = ospf_lsa_new()) == NULL) {
- zlog_warn("ospf_router_info_lsa_new: ospf_lsa_new() ?");
- stream_free(s);
- return NULL;
- }
- if ((new->data = ospf_lsa_data_new(length)) == NULL) {
- zlog_warn("ospf_router_info_lsa_new: ospf_lsa_data_new() ?");
- ospf_lsa_unlock(&new);
- new = NULL;
- stream_free(s);
- return new;
- }
+ new = ospf_lsa_new_and_data(length);
new->area = OspfRI.area; /* Area must be null if the Opaque type is AS
scope, fulfill otherwise */
#include "ospfd/ospf_flood.h"
#include "ospfd/ospf_ism.h"
#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
#include "ospfd/ospf_zebra.h"
/* OSPF2-MIB. */
lsah->length = htons(length);
/* Now, create an OSPF LSA instance. */
- if ((new = ospf_lsa_new()) == NULL) {
- zlog_warn("%s: ospf_lsa_new() ?", __func__);
- stream_free(s);
- return NULL;
- }
- if ((new->data = ospf_lsa_data_new(length)) == NULL) {
- zlog_warn("%s: ospf_lsa_data_new() ?", __func__);
- ospf_lsa_unlock(&new);
- new = NULL;
- stream_free(s);
- return new;
- }
+ new = ospf_lsa_new_and_data(length);
new->vrf_id = ospf->vrf_id;
if (area && area->ospf)
if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
zlog_debug(
- "Zebra: interface add %s vrf %s[%u] index %d flags %llx metric %d mtu %d",
+ "Zebra: interface add %s vrf %s[%u] index %d flags %llx metric %d mtu %d speed %u",
ifp->name, ospf_vrf_id_to_name(ifp->vrf_id),
ifp->vrf_id, ifp->ifindex,
- (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
+ (unsigned long long)ifp->flags, ifp->metric, ifp->mtu,
+ ifp->speed);
assert(ifp->info);
if (!ospf)
return 0;
+ ospf_if_recalculate_output_cost(ifp);
+
ospf_if_update(ospf, ifp);
hook_call(ospf_if_update, ifp);
count++;
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) {
- char buf[2][PREFIX2STR_BUFFER];
+ char buf[2][INET_ADDRSTRLEN];
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index(path->ifindex, ospf->vrf_id);
zlog_debug(
- "Zebra: Route add %s nexthop %s, ifindex=%d",
+ "Zebra: Route add %s nexthop %s, ifindex=%d %s",
prefix2str(p, buf[0], sizeof(buf[0])),
inet_ntop(AF_INET, &path->nexthop,
buf[1], sizeof(buf[1])),
- path->ifindex);
+ path->ifindex, ifp ? ifp->name : " ");
}
}
api.nexthop_num = count;
#include "ospfd/ospf_spf.h"
#include "ospfd/ospf_packet.h"
#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_flood.h"
-#include "ospfd/ospf_route.h"
#include "ospfd/ospf_ase.h"
char addr_str[INET_ADDRSTRLEN];
struct pim_assert_metric *am;
struct in_addr ifaddr;
- char pref_str[5];
- char metr_str[7];
+ char pref_str[16];
+ char metr_str[16];
ifaddr = pim_ifp->primary_address;
return 0;
}
-bool pim_if_is_loopback(struct interface *ifp)
-{
- if (if_is_loopback(ifp) || if_is_vrf(ifp))
- return true;
-
- return false;
-}
-
bool pim_if_is_vrf_device(struct interface *ifp)
{
if (if_is_vrf(ifp))
int pim_if_connected_to_source(struct interface *ifp, struct in_addr src);
int pim_update_source_set(struct interface *ifp, struct in_addr source);
-bool pim_if_is_loopback(struct interface *ifp);
-
bool pim_if_is_vrf_device(struct interface *ifp);
int pim_if_ifchannel_count(struct pim_interface *pim_ifp);
ifchannel list is empty before deleting upstream_del
ref count will take care of it.
*/
- pim_upstream_del(pim_ifp->pim, ch->upstream, __PRETTY_FUNCTION__);
+ if (ch->upstream->ref_count > 0)
+ pim_upstream_del(pim_ifp->pim, ch->upstream,
+ __PRETTY_FUNCTION__);
+
+ else
+ zlog_warn("%s: Avoiding deletion of upstream with ref_count %d "
+ "from ifchannel(%s): %s", __PRETTY_FUNCTION__,
+ ch->upstream->ref_count, ch->interface->name,
+ ch->sg_str);
+
ch->upstream = NULL;
THREAD_OFF(ch->t_ifjoin_expiry_timer);
char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
{
+ char *out;
struct prefix_sg sg;
int i;
sg.src = c_oil->oil.mfcc_origin;
sg.grp = c_oil->oil.mfcc_mcastgrp;
- sprintf(buf, "%s IIF: %d, OIFS: ", pim_str_sg_dump(&sg),
- c_oil->oil.mfcc_parent);
+ snprintf(buf, size, "%s IIF: %d, OIFS: ", pim_str_sg_dump(&sg),
+ c_oil->oil.mfcc_parent);
+ out = buf + strlen(buf);
for (i = 0; i < MAXVIFS; i++) {
if (c_oil->oil.mfcc_ttls[i] != 0) {
- char buf1[10];
- sprintf(buf1, "%d ", i);
- strcat(buf, buf1);
+ snprintf(out, buf + size - out, "%d ", i);
+ out += strlen(out);
}
}
{
struct pim_interface *pim_ifp = ifp->info;
- if (pim_if_is_loopback(ifp))
+ if (if_is_loopback_or_vrf(ifp))
return 0;
if (hello_send(ifp, holdtime)) {
/*
* No need to ever start loopback or vrf device hello's
*/
- if (pim_if_is_loopback(ifp))
+ if (if_is_loopback_or_vrf(ifp))
return;
/*
up->ref_count, up->flags,
up->channel_oil->oil_ref_count);
+ assert(up->ref_count > 0);
+
--up->ref_count;
if (up->ref_count >= 1)
- `frr.readme`:
Returns this document `cat README_usage.md`
- `frr.set`:
- Allows to enable `FPM` module. See FPM section below
+ Allows to enable `FPM` and/or disable RPKIi module. See Module section below
and for debugging defined at this time (May get removed later - do not
depend on them). These are mainly intended to debug the Snap
These settings require either a reboot or a manual configuration with
`sysctl` as well.
-FPM Module
+Modules
----------
-The `frr.set` allows to turn FPM module on or off.
+The `frr.set` allows to turn FPM module ond the RPKI module on or off.
frr.set fpm {disable|protobuf|netlink}
- Disables FPM or enables FPM with selected mode
+ Disables FPM or enables FPM with selected mode (default: disabled)
By default, the FPM module is disabled, but installed with netlink and
protobuf support. To enable the FPM module, use the `frr.set fpm protobuf`
for the next restart of zebra. Please reboot or restart zebra after
changing the mode to become effective.
+ frr.set rpki {enable|disable}
+
+ Disables or enables BGP RPKI (default: enabled)
+
+By default, the RPKI module is enabled. To disable the RPKI module
+use the `frr.set rpki disable` command. The command will only enable
+the module after the next restart of the bgp daemon. Please reboot or
+restart bgpd after changing the mode to become effective.
+(Normally, there is no need to disable the module as it has no effect
+if there are no RPKI configurations in BGP)
+
FAQ
---
- frr.vtysh displays `--MORE--` on long output. How to suppress this?
if ! [ -e $SNAP_DATA/bgpd.conf ]; then
cp $SNAP/etc/frr/bgpd.conf.default $SNAP_DATA/bgpd.conf
fi
+# If no RPKI option is specified, then we create a default
+# with RPKI enabled
+if ! [ -e $SNAP_DATA/rpki.conf ]; then
+ echo "-M rpki" > $SNAP_DATA/rpki.conf
+fi
+EXTRA_OPTIONS="`cat $SNAP_DATA/rpki.conf`"
exec $SNAP/sbin/bgpd \
-f $SNAP_DATA/bgpd.conf \
--pid_file $SNAP_DATA/bgpd.pid \
--socket $SNAP_DATA/zsock \
- --vty_socket $SNAP_DATA
+ --vty_socket $SNAP_DATA \
+ --moduledir $SNAP/lib/frr/modules $EXTRA_OPTIONS
;;
esac
;;
+ rpki)
+ case $2 in
+ disable)
+ echo "" > $SNAP_DATA/rpki.conf
+ echo "RPKI module disabled. Please restart FRR"
+ ;;
+ enable)
+ echo "-M rpki" > $SNAP_DATA/rpki.conf
+ echo "RPKI module enabled. Please restart FRR"
+ ;;
+ *)
+ echo "Usage:"
+ echo " ${SNAP_NAME}.set rpki {disable|enable}"
+ echo ""
+ echo " Disables BGP RPKI module or enables it (default: enabled)"
+ echo " Mode will be saved for next restart of bgpd, but bgpd"
+ echo " is not automatically restarted"
+ exit 1
+ ;;
+ esac
+ ;;
*)
echo "Usage:"
echo " ${SNAP_NAME}.set fpm {disable|protobuf|netlink}"
+ echo " ${SNAP_NAME}.set rpki {disable|enable}"
echo ""
- echo " Disables FPM or enables FPM with selected mode"
+ echo " fpm: Disables FPM or enables FPM with selected mode"
+ echo " rpki: Disables BGP RPKI or enables it (default: enabled)"
exit 1
;;
esac
- network-bind
- network-control
bgpd-debug:
- command: sbin/bgpd -f $SNAP_DATA/bgpd.conf --pid_file $SNAP_DATA/bgpd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA
+ command: sbin/bgpd -f $SNAP_DATA/bgpd.conf --pid_file $SNAP_DATA/bgpd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA --moduledir $SNAP/lib/frr/modules `cat $SNAP_DATA/rpki.conf 2> /dev/null`
plugs:
- network
- network-bind
- network-control
parts:
+ rtrlib:
+ build-packages:
+ - cmake
+ - make
+ - gcc
+ - libssh-dev
+ stage-packages:
+ - libssh-4
+ prime:
+ - lib/x86_64-linux-gnu/librtr.so*
+ - usr/lib/x86_64-linux-gnu/libssh.so*
+ source: https://github.com/rtrlib/rtrlib.git
+ source-type: git
+ source-tag: v0.5.0
+ plugin: cmake
+ configflags:
+ - -DCMAKE_BUILD_TYPE=Release
frr:
- build-packages:
+ after: [rtrlib]
+ build-packages:
+ - gcc
- autoconf
- automake
- libtool
- flex
- python3-dev
- protobuf-c-compiler
+ - python3-sphinx
stage-packages:
- coreutils
- iproute2
- --enable-ldpd
- --enable-fpm
- --enable-protobuf
+ - --enable-rpki
- --enable-configfile-mask=0640
- --enable-logfile-mask=0640
- --localstatedir=/var/run
"Table to configure\n"
"The table number to configure\n")
{
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
VTY_DECLVAR_CONTEXT(vrf, vrf);
struct static_vrf *svrf = vrf->info;
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && !vrf_is_mapped_on_netns(vrf)) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
return CMD_WARNING_CONFIG_FAILED;
}
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
struct static_vrf *svrf = vrf->info;
struct static_vrf *nh_svrf;
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && !vrf_is_mapped_on_netns(vrf)) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
struct static_vrf *nh_svrf;
const char *flag = NULL;
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
struct static_vrf *nh_svrf;
const char *flag = NULL;
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && !vrf_is_mapped_on_netns(vrf)) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
"Table to configure\n"
"The table number to configure\n")
{
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
VTY_DECLVAR_CONTEXT(vrf, vrf);
struct static_vrf *svrf = vrf->info;
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && !vrf_is_mapped_on_netns(vrf)) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
struct static_vrf *svrf;
struct static_vrf *nh_svrf;
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
struct static_vrf *svrf = vrf->info;
struct static_vrf *nh_svrf;
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && !vrf_is_mapped_on_netns(vrf)) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
struct static_vrf *svrf;
struct static_vrf *nh_svrf;
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
struct static_vrf *svrf = vrf->info;
struct static_vrf *nh_svrf;
- if (table_str && !vrf_is_backend_netns()) {
+ if (table_str && !vrf_is_mapped_on_netns(vrf)) {
vty_out(vty,
"%% table param only available when running on netns-based vrfs\n");
return CMD_WARNING_CONFIG_FAILED;
#include "log.h"
#include "nexthop.h"
#include "nexthop_group.h"
+#include "hash.h"
#include "static_vrf.h"
#include "static_routes.h"
/* Zebra structure to hold current status. */
struct zclient *zclient;
+static struct hash *static_nht_hash;
static struct interface *zebra_interface_if_lookup(struct stream *s)
{
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
+struct static_nht_data {
+ struct prefix *nh;
+ uint32_t refcount;
+ uint8_t nh_num;
+};
static int static_zebra_nexthop_update(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
+ struct static_nht_data *nhtd, lookup;
struct zapi_route nhr;
afi_t afi = AFI_IP;
if (nhr.prefix.family == AF_INET6)
afi = AFI_IP6;
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.nh = &nhr.prefix;
+
+ nhtd = hash_lookup(static_nht_hash, &lookup);
+ if (nhtd)
+ nhtd->nh_num = nhr.nexthop_num;
+
+
static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id);
return 1;
}
mpls_enabled = cap->mpls_enabled;
}
+static unsigned int static_nht_hash_key(void *data)
+{
+ struct static_nht_data *nhtd = data;
+
+ return prefix_hash_key(nhtd->nh);
+}
+
+static int static_nht_hash_cmp(const void *d1, const void *d2)
+{
+ const struct static_nht_data *nhtd1 = d1;
+ const struct static_nht_data *nhtd2 = d2;
+
+ return prefix_same(nhtd1->nh, nhtd2->nh);
+}
+
+static void *static_nht_hash_alloc(void *data)
+{
+ struct static_nht_data *copy = data;
+ struct static_nht_data *new;
+
+ new = XMALLOC(MTYPE_TMP, sizeof(*new));
+
+ new->nh = prefix_new();
+ prefix_copy(new->nh, copy->nh);
+ new->refcount = 0;
+ new->nh_num = 0;
+
+ return new;
+}
+
+static void static_nht_hash_free(void *data)
+{
+ struct static_nht_data *nhtd = data;
+
+ prefix_free(nhtd->nh);
+ XFREE(MTYPE_TMP, nhtd);
+}
+
void static_zebra_nht_register(struct static_route *si, bool reg)
{
+ struct static_nht_data *nhtd, lookup;
uint32_t cmd;
struct prefix p;
+ afi_t afi = AFI_IP;
cmd = (reg) ?
ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
p.u.prefix4 = si->addr.ipv4;
+ afi = AFI_IP;
break;
case STATIC_IPV6_GATEWAY:
case STATIC_IPV6_GATEWAY_IFNAME:
p.family = AF_INET6;
p.prefixlen = IPV6_MAX_BITLEN;
p.u.prefix6 = si->addr.ipv6;
+ afi = AFI_IP6;
break;
}
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.nh = &p;
+
+ si->nh_registered = reg;
+
+ if (reg) {
+ nhtd = hash_get(static_nht_hash, &lookup,
+ static_nht_hash_alloc);
+ nhtd->refcount++;
+
+ if (nhtd->refcount > 1) {
+ static_nht_update(nhtd->nh, nhtd->nh_num,
+ afi, si->nh_vrf_id);
+ return;
+ }
+ } else {
+ nhtd = hash_lookup(static_nht_hash, &lookup);
+ if (!nhtd)
+ return;
+
+ nhtd->refcount--;
+ if (nhtd->refcount >= 1)
+ return;
+
+ hash_release(static_nht_hash, nhtd);
+ static_nht_hash_free(nhtd);
+ }
+
if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
zlog_warn("%s: Failure to send nexthop to zebra",
__PRETTY_FUNCTION__);
-
- si->nh_registered = reg;
}
extern void static_zebra_route_add(struct route_node *rn,
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = si_changed->tag;
}
- api.tableid = si_changed->table_id;
-
- zlog_debug("Distance sent down: %d %d", si_changed->distance, install);
+ if (si_changed->table_id != 0) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
+ api.tableid = si_changed->table_id;
+ }
for (/*loaded above*/; si; si = si->next) {
api_nh = &api.nexthops[nh_num];
if (si->nh_vrf_id == VRF_UNKNOWN)
zclient->interface_address_delete = interface_address_delete;
zclient->route_notify_owner = route_notify_owner;
zclient->nexthop_update = static_zebra_nexthop_update;
+
+ static_nht_hash = hash_create(static_nht_hash_key,
+ static_nht_hash_cmp,
+ "Static Nexthop Tracking hash");
}
switch (type) {
case CAPABILITY:
len += 2; /* to cover the OPT-Param header */
- __attribute__ ((fallthrough));
+ _FALLTHROUGH
case OPT_PARAM:
printf("len: %u\n", len);
/* peek_for_as4 wants getp at capibility*/
print_stream(s);
- stream_resize(s, stream_get_endp(s));
+ stream_resize_inplace(&s, stream_get_endp(s));
print_stream(s);
return CMD_SUCCESS;
}
-DEFUNSH(VTYSH_BGPD,
- rpki_exit,
- rpki_exit_cmd,
- "exit",
- "Exit current mode and down to previous mode\n")
-{
- vty->node = CONFIG_NODE;
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_BGPD,
- rpki_quit,
- rpki_quit_cmd,
- "quit",
- "Exit current mode and down to previous mode\n")
-{
- return rpki_exit(self, vty, argc, argv);
-}
#endif
DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd,
case VTY_NODE:
case KEYCHAIN_NODE:
case BFD_NODE:
+ case RPKI_NODE:
vtysh_execute("end");
vtysh_execute("configure terminal");
vty->node = CONFIG_NODE;
|| vty->node == BGP_VNC_L2_GROUP_NODE)
vty->node = BGP_NODE;
return CMD_SUCCESS;
+
+}
+
+#if defined(HAVE_RPKI)
+DEFUNSH(VTYSH_BGPD, rpki_exit, rpki_exit_cmd, "exit",
+ "Exit current mode and down to previous mode\n")
+{
+ vtysh_exit(vty);
+ return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_BGPD, rpki_quit, rpki_quit_cmd, "quit",
+ "Exit current mode and down to previous mode\n")
+{
+ return rpki_exit(self, vty, argc, argv);
}
+#endif /* HAVE_RPKI */
DEFUNSH(VTYSH_PIMD|VTYSH_ZEBRA, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf",
"Exit from VRF configuration mode\n")
+++ /dev/null
-GNOME-PRODUCT-ZEBRA-MIB DEFINITIONS ::= BEGIN\r
-\r
-IMPORTS\r
- MODULE-IDENTITY,\r
- OBJECT-IDENTITY\r
- FROM SNMPv2-SMI\r
- gnomeProducts\r
- FROM GNOME-SMI;\r
-\r
-zebra MODULE-IDENTITY\r
- LAST-UPDATED "200004250000Z"\r
- ORGANIZATION "GNOME project"\r
- CONTACT-INFO\r
- "GNU Network Object Model Environment project\r
- \r
- see http://www.gnome.org for contact persons of a particular\r
- area or subproject of GNOME.\r
-\r
- Administrative contact for MIB module:\r
-\r
- Jochen Friedrich\r
- Wingertstr. 70/1\r
- 68809 Neulussheim\r
- Germany \r
-\r
- email: snmp@gnome.org"\r
- DESCRIPTION\r
- "The product registrations for the various zebra subdeamons.\r
- These registrations are guaranteed to be unique and are used\r
- for SMUX registration by default (if not overridden manually)."\r
- ::= { gnomeProducts 2 }\r
-\r
-zserv OBJECT-IDENTITY\r
- STATUS current\r
- DESCRIPTION\r
- "zserv is part of the zebra project which again is a GNU\r
- endorsed internet routing program.\r
- zserv is the main zebra process which implements routing\r
- entries with the kernel and handles routing updates between\r
- other routing protocols."\r
- ::= { zebra 1 }\r
-\r
-bgpd OBJECT-IDENTITY\r
- STATUS current\r
- DESCRIPTION\r
- "bgpd is part of the zebra project which again is a GNU\r
- endorsed internet routing program."\r
- ::= { zebra 2 }\r
-\r
-ripd OBJECT-IDENTITY\r
- STATUS current\r
- DESCRIPTION\r
- "ripd is part of the zebra project which again is a GNU\r
- endorsed internet routing program."\r
- ::= { zebra 3 }\r
-\r
-ripngd OBJECT-IDENTITY\r
- STATUS current\r
- DESCRIPTION\r
- "ripngd is part of the zebra project which again is a GNU\r
- endorsed internet routing program."\r
- ::= { zebra 4 }\r
-\r
-ospfd OBJECT-IDENTITY\r
- STATUS current\r
- DESCRIPTION\r
- "ospfd is part of the zebra project which again is a GNU\r
- endorsed internet routing program."\r
- ::= { zebra 5 }\r
-\r
-ospf6d OBJECT-IDENTITY\r
- STATUS current\r
- DESCRIPTION\r
- "ospf6d is part of the zebra project which again is a GNU\r
- endorsed internet routing program."\r
- ::= { zebra 6 }\r
-\r
-END\r
+++ /dev/null
-GNOME-SMI DEFINITIONS ::= BEGIN\r
-\r
-IMPORTS\r
- MODULE-IDENTITY,\r
- OBJECT-IDENTITY,\r
- enterprises\r
- FROM SNMPv2-SMI;\r
-\r
-gnome MODULE-IDENTITY\r
- LAST-UPDATED "9809010000Z"\r
- ORGANIZATION "GNOME project"\r
- CONTACT-INFO\r
- "GNU Network Object Model Environment project\r
- \r
- see http://www.gnome.org for contact persons of a particular\r
- area or subproject of GNOME.\r
-\r
- Administrative contact for MIB module:\r
-\r
- Jochen Friedrich\r
- Wingertstr. 70/1\r
- 68809 Neulussheim\r
- Germany \r
-\r
- email: snmp@gnome.org"\r
- DESCRIPTION\r
- "The Structure of GNOME."\r
- ::= { enterprises 3317 } -- assigned by IANA\r
-\r
-gnomeProducts OBJECT-IDENTITY\r
- STATUS current\r
- DESCRIPTION\r
- "gnomeProducts is the root OBJECT IDENTIFIER from\r
- which sysObjectID values are assigned."\r
- ::= { gnome 1 }\r
-\r
-gnomeMgmt OBJECT-IDENTITY\r
- STATUS current\r
- DESCRIPTION\r
- "gnomeMgmt defines the subtree for production GNOME related\r
- MIB registrations."\r
- ::= { gnome 2 }\r
-\r
-gnomeTest OBJECT-IDENTITY\r
- STATUS current\r
- DESCRIPTION\r
- "gnomeTest defines the subtree for testing GNOME related\r
- MIB registrations."\r
- ::= { gnome 3 }\r
-\r
--- more to come if necessary.\r
-\r
-END\r
+++ /dev/null
-/*
- * GNU Zebra client test main routine.
- * Copyright (C) 1997 Kunihiro Ishiguro
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra 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.
- *
- * GNU Zebra 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 "stream.h"
-#include "zclient.h"
-#include "thread.h"
-#include "table.h"
-#include "zebra/rib.h"
-#include "zebra/zserv.h"
-
-struct thread *master;
-
-/* Zebra client structure. */
-struct zclient *zclient = NULL;
-
-/* Zebra socket. */
-int sock;
-
-/* IPv4 route add and delete test. */
-void zebra_test_ipv4(int command, int type, char *prefix, char *gateway,
- uint8_t distance)
-{
- struct zapi_ipv4 api;
- struct prefix_ipv4 p;
- struct in_addr gate;
- struct in_addr *gpnt;
-
- str2prefix_ipv4(prefix, &p);
- if (!inet_aton(gateway, &gate)) {
- printf("Gateway specified: %s is illegal\n", gateway);
- return;
- }
-
- gpnt = &gate;
-
- api.vrf_id = VRF_DEFAULT;
- api.type = type;
- api.flags = 0;
-
- api.message = 0;
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = 1;
- api.nexthop = &gpnt;
- api.ifindex_num = 0;
- if (distance) {
- SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
- api.distance = distance;
- }
-
-
- switch (command) {
- case ZEBRA_IPV4_ROUTE_ADD:
- zapi_ipv4_add(zclient, &p, &api);
- break;
- case ZEBRA_IPV4_ROUTE_DELETE:
- zapi_ipv4_delete(zclient, &p, &api);
- break;
- }
-}
-
-/* IPv6 route add and delete test. */
-void zebra_test_v6(int sock)
-{
- struct prefix_ipv6 p;
- struct in6_addr nexthop;
-
- str2prefix_ipv6("3ffe:506::2/128", &p);
- inet_pton(AF_INET6, "::1", &nexthop);
-
- /* zebra_ipv6_add (sock, ZEBRA_ROUTE_STATIC, 0, &p, &nexthop, 1); */
-
- sleep(5);
- /* zebra_ipv6_delete (sock, ZEBRA_ROUTE_STATIC, 0, &p, &nexthop, 1); */
-}
-
-/* Print out usage and exit. */
-void usage_exit()
-{
- fprintf(stderr, "Usage: client filename\n");
- exit(1);
-}
-
-struct zebra_info {
- char *str;
- int type;
-} zebra_type[] = {{"static", ZEBRA_ROUTE_STATIC},
- {"rip", ZEBRA_ROUTE_RIP},
- {"ripng", ZEBRA_ROUTE_RIPNG},
- {"ospf", ZEBRA_ROUTE_OSPF},
- {"ospf6", ZEBRA_ROUTE_OSPF6},
- {"bgp", ZEBRA_ROUTE_BGP},
- {"nhrp", ZEBRA_ROUTE_NHRP},
- {"pim", ZEBRA_ROUTE_PIM},
- {NULL, 0}};
-
-/* Zebra route simulator. */
-void zebra_sim(FILE *fp)
-{
- char buf[BUFSIZ];
- char distance_str[BUFSIZ];
- uint8_t distance;
-
- while (fgets(buf, sizeof buf, fp)) {
- int i;
- int ret;
- int type;
- char str[BUFSIZ], command[BUFSIZ], prefix[BUFSIZ],
- gateway[BUFSIZ];
-
- distance = 0;
-
- if (*buf == '#')
- continue;
-
- type = ZEBRA_ROUTE_STATIC;
-
- ret = sscanf(buf, "%s %s %s %s %s\n", command, str, prefix,
- gateway, distance_str);
-
- if (ret == 5) {
- distance = atoi(distance_str);
- } else {
- ret = sscanf(buf, "%s %s %s %s\n", command, str, prefix,
- gateway);
-
- if (ret != 4)
- continue;
- }
-
- i = 0;
- while (zebra_type[i++].str) {
- if (strcmp(zebra_type[i].str, str) == 0) {
- type = zebra_type[i].type;
- break;
- }
- }
-
- if (strcmp(command, "add") == 0) {
- zebra_test_ipv4(ZEBRA_IPV4_ROUTE_ADD, type, prefix,
- gateway, distance);
- printf("%s", buf);
- continue;
- }
-
- if (strcmp(command, "del") == 0) {
- zebra_test_ipv4(ZEBRA_IPV4_ROUTE_DELETE, type, prefix,
- gateway, distance);
- printf("%s", buf);
- continue;
- }
- }
-}
-
-/* Test zebra client main routine. */
-int main(int argc, char **argv)
-{
- struct thread_master *master;
- FILE *fp;
-
- if (argc == 1)
- usage_exit();
-
- master = thread_master_create(NULL);
- /* Establish connection to zebra. */
- zclient = zclient_new_notify(master, &zclient_options_default);
- zclient->enable = 1;
- zclient_socket_connect(zclient);
-
- /* Open simulation file. */
- fp = fopen(argv[1], "r");
- if (fp == NULL) {
- fprintf(stderr,
- "%% Can't open configuration file %s due to '%s'\n",
- argv[1], safe_strerror(errno));
- exit(1);
- }
-
- /* Do main work. */
- zebra_sim(fp);
-
- sleep(100);
-
- fclose(fp);
- close(sock);
-
- return 0;
-}
#include "zebra/interface.h"
#include "zebra/rib.h"
+#include "zebra/rt.h"
#include <ifaddrs.h>
}
}
+/**
+ * netlink_parse_rtattr_nested() - Parses a nested route attribute
+ * @tb: Pointer to array for storing rtattr in.
+ * @max: Max number to store.
+ * @rta: Pointer to rtattr to look for nested items in.
+ */
+void netlink_parse_rtattr_nested(struct rtattr **tb, int max,
+ struct rtattr *rta)
+{
+ netlink_parse_rtattr(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta));
+}
+
int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
const void *data, unsigned int alen)
{
extern void netlink_parse_rtattr(struct rtattr **tb, int max,
struct rtattr *rta, int len);
+extern void netlink_parse_rtattr_nested(struct rtattr **tb, int max,
+ struct rtattr *rta);
extern int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
const void *data, unsigned int alen);
extern int rta_addattr_l(struct rtattr *rta, unsigned int maxlen, int type,
return write;
}
-void zebra_import_table_rm_update()
+void zebra_import_table_rm_update(const char *rmap)
{
afi_t afi;
int i;
continue;
rmap_name = zebra_get_import_table_route_map(afi, i);
- if (!rmap_name)
- return;
-
+ if ((!rmap_name) || (strcmp(rmap_name, rmap) != 0))
+ continue;
table = zebra_vrf_other_route_table(afi, i,
VRF_DEFAULT);
for (rn = route_top(table); rn; rn = route_next(rn)) {
extern int zebra_import_table_config(struct vty *);
-extern void zebra_import_table_rm_update(void);
-
+extern void zebra_import_table_rm_update(const char *rmap);
#endif /* _ZEBRA_REDISTRIBUTE_H */
vrf_id_t vrf_id);
extern void rib_update(vrf_id_t vrf_id, rib_update_event_t event);
+extern void rib_update_table(struct route_table *table,
+ rib_update_event_t event);
extern void rib_sweep_route(void);
extern void rib_sweep_table(struct route_table *table);
extern void rib_close_table(struct route_table *table);
return VRF_DEFAULT;
}
+/**
+ * @parse_encap_mpls() - Parses encapsulated mpls attributes
+ * @tb: Pointer to rtattr to look for nested items in.
+ * @labels: Pointer to store labels in.
+ *
+ * Return: Number of mpls labels found.
+ */
+static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels)
+{
+ struct rtattr *tb_encap[MPLS_IPTUNNEL_MAX + 1] = {0};
+ mpls_lse_t *lses = NULL;
+ int num_labels = 0;
+ uint32_t ttl = 0;
+ uint32_t bos = 0;
+ uint32_t exp = 0;
+ mpls_label_t label = 0;
+
+ netlink_parse_rtattr_nested(tb_encap, MPLS_IPTUNNEL_MAX, tb);
+ lses = (mpls_lse_t *)RTA_DATA(tb_encap[MPLS_IPTUNNEL_DST]);
+ while (!bos && num_labels < MPLS_MAX_LABELS) {
+ mpls_lse_decode(lses[num_labels], &label, &ttl, &exp, &bos);
+ labels[num_labels++] = label;
+ }
+
+ return num_labels;
+}
+
/* Looking up routing table by netlink interface. */
static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
int startup)
void *src = NULL; /* IPv6 srcdest source prefix */
enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
+ /* MPLS labels */
+ mpls_label_t labels[MPLS_MAX_LABELS] = {0};
+ int num_labels = 0;
+
rtm = NLMSG_DATA(h);
if (startup && h->nlmsg_type != RTM_NEWROUTE)
}
nh.vrf_id = nh_vrf_id;
+ if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
+ && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
+ == LWTUNNEL_ENCAP_MPLS) {
+ num_labels =
+ parse_encap_mpls(tb[RTA_ENCAP], labels);
+ }
+
+ if (num_labels)
+ nexthop_add_labels(&nh, ZEBRA_LSP_STATIC,
+ num_labels, labels);
+
rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p,
&src_p, &nh, table, metric, mtu, distance, tag);
} else {
re->tag = tag;
for (;;) {
+ struct nexthop *nh = NULL;
vrf_id_t nh_vrf_id;
if (len < (int)sizeof(*rtnh)
|| rtnh->rtnh_len > len)
if (tb[RTA_GATEWAY])
gate = RTA_DATA(
tb[RTA_GATEWAY]);
+ if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
+ && *(uint16_t *)RTA_DATA(
+ tb[RTA_ENCAP_TYPE])
+ == LWTUNNEL_ENCAP_MPLS) {
+ num_labels = parse_encap_mpls(
+ tb[RTA_ENCAP], labels);
+ }
}
if (gate) {
if (rtm->rtm_family == AF_INET) {
if (index)
- route_entry_nexthop_ipv4_ifindex_add(
+ nh = route_entry_nexthop_ipv4_ifindex_add(
re, gate,
prefsrc, index,
nh_vrf_id);
else
- route_entry_nexthop_ipv4_add(
+ nh = route_entry_nexthop_ipv4_add(
re, gate,
prefsrc,
nh_vrf_id);
} else if (rtm->rtm_family
== AF_INET6) {
if (index)
- route_entry_nexthop_ipv6_ifindex_add(
+ nh = route_entry_nexthop_ipv6_ifindex_add(
re, gate, index,
nh_vrf_id);
else
- route_entry_nexthop_ipv6_add(
+ nh = route_entry_nexthop_ipv6_add(
re, gate,
nh_vrf_id);
}
} else
- route_entry_nexthop_ifindex_add(
+ nh = route_entry_nexthop_ifindex_add(
re, index, nh_vrf_id);
+ if (nh && num_labels)
+ nexthop_add_labels(nh, ZEBRA_LSP_STATIC,
+ num_labels, labels);
+
if (rtnh->rtnh_len == 0)
break;
zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_dt.c
endif
endif
-
-EXTRA_DIST += \
- zebra/GNOME-SMI \
- zebra/GNOME-PRODUCT-ZEBRA-MIB \
- # end
-
-# -- unmaintained --
-# noinst_PROGRAMS += zebra/client
-# zebra_client_SOURCES = zebra/client_main.c
-# zebra_client_LDADD = lib/libfrr.la
unsigned short l = 0;
uint8_t flags = 0;
uint16_t type = cmd2type[hdr->command];
+ bool exist;
if (IS_ZEBRA_DEBUG_NHT)
zlog_debug(
p.family);
return;
}
- rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type);
+ rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type, &exist);
+ if (!rnh)
+ return;
+
if (type == RNH_NEXTHOP_TYPE) {
if (flags
&& !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf));
/* Anything not AF_INET/INET6 has been filtered out above */
- zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type, &p);
+ if (!exist)
+ zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type,
+ &p);
}
stream_failure:
}
}
-/* This function support multiple nexthop. */
-/*
- * Parse the ZEBRA_IPV4_ROUTE_ADD sent from client. Update re and
- * add kernel route.
- */
-static void zread_ipv4_add(ZAPI_HANDLER_ARGS)
-{
- int i;
- struct route_entry *re;
- struct prefix p;
- uint8_t message;
- struct in_addr nhop_addr;
- uint8_t nexthop_num;
- uint8_t nexthop_type;
- struct stream *s;
- ifindex_t ifindex;
- safi_t safi;
- int ret;
- enum lsp_types_t label_type = ZEBRA_LSP_NONE;
- mpls_label_t label;
- struct nexthop *nexthop;
- enum blackhole_type bh_type = BLACKHOLE_NULL;
-
- /* Get input stream. */
- s = msg;
-
- /* Allocate new re. */
- re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
-
- /* Type, flags, message. */
- STREAM_GETC(s, re->type);
- if (re->type > ZEBRA_ROUTE_MAX) {
- zlog_warn("%s: Specified route type %d is not a legal value\n",
- __PRETTY_FUNCTION__, re->type);
- XFREE(MTYPE_RE, re);
- return;
- }
- STREAM_GETW(s, re->instance);
- STREAM_GETL(s, re->flags);
- STREAM_GETC(s, message);
- STREAM_GETW(s, safi);
- re->uptime = time(NULL);
-
- /* IPv4 prefix. */
- memset(&p, 0, sizeof(struct prefix_ipv4));
- p.family = AF_INET;
- STREAM_GETC(s, p.prefixlen);
- if (p.prefixlen > IPV4_MAX_BITLEN) {
- zlog_warn(
- "%s: Specified prefix length %d is greater than what v4 can be",
- __PRETTY_FUNCTION__, p.prefixlen);
- XFREE(MTYPE_RE, re);
- return;
- }
- STREAM_GET(&p.u.prefix4, s, PSIZE(p.prefixlen));
-
- /* VRF ID */
- re->vrf_id = zvrf_id(zvrf);
-
- /* Nexthop parse. */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP)) {
- STREAM_GETC(s, nexthop_num);
- zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
- nexthop_num);
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
- label_type = lsp_type_from_re_type(client->proto);
-
- for (i = 0; i < nexthop_num; i++) {
- STREAM_GETC(s, nexthop_type);
-
- switch (nexthop_type) {
- case NEXTHOP_TYPE_IFINDEX:
- STREAM_GETL(s, ifindex);
- route_entry_nexthop_ifindex_add(re, ifindex,
- re->vrf_id);
- break;
- case NEXTHOP_TYPE_IPV4:
- STREAM_GET(&nhop_addr.s_addr, s,
- IPV4_MAX_BYTELEN);
- nexthop = route_entry_nexthop_ipv4_add(
- re, &nhop_addr, NULL, re->vrf_id);
- /*
- * For labeled-unicast, each nexthop is followed
- * by the label.
- */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL)) {
- STREAM_GETL(s, label);
- nexthop_add_labels(nexthop, label_type,
- 1, &label);
- }
- break;
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- STREAM_GET(&nhop_addr.s_addr, s,
- IPV4_MAX_BYTELEN);
- STREAM_GETL(s, ifindex);
- route_entry_nexthop_ipv4_ifindex_add(
- re, &nhop_addr, NULL, ifindex,
- re->vrf_id);
- break;
- case NEXTHOP_TYPE_IPV6:
- zlog_warn(
- "%s: Please use ZEBRA_ROUTE_ADD if you want to pass v6 nexthops",
- __PRETTY_FUNCTION__);
- nexthops_free(re->ng.nexthop);
- XFREE(MTYPE_RE, re);
- return;
- case NEXTHOP_TYPE_BLACKHOLE:
- route_entry_nexthop_blackhole_add(re, bh_type);
- break;
- default:
- zlog_warn(
- "%s: Specified nexthop type: %d does not exist",
- __PRETTY_FUNCTION__, nexthop_type);
- nexthops_free(re->ng.nexthop);
- XFREE(MTYPE_RE, re);
- return;
- }
- }
- }
-
- /* Distance. */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE))
- STREAM_GETC(s, re->distance);
-
- /* Metric. */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC))
- STREAM_GETL(s, re->metric);
-
- /* Tag */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_TAG))
- STREAM_GETL(s, re->tag);
- else
- re->tag = 0;
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_MTU))
- STREAM_GETL(s, re->mtu);
- else
- re->mtu = 0;
-
- /* Table */
- re->table = zvrf->table_id;
-
- ret = rib_add_multipath(AFI_IP, safi, &p, NULL, re);
-
- /* Stats */
- if (ret > 0)
- client->v4_route_add_cnt++;
- else if (ret < 0)
- client->v4_route_upd8_cnt++;
-
- return;
-
-stream_failure:
- nexthops_free(re->ng.nexthop);
- XFREE(MTYPE_RE, re);
-}
-
-/* Zebra server IPv4 prefix delete function. */
-static void zread_ipv4_delete(ZAPI_HANDLER_ARGS)
-{
- struct stream *s;
- struct zapi_ipv4 api;
- struct prefix p;
- uint32_t table_id;
-
- s = msg;
-
- /* Type, flags, message. */
- STREAM_GETC(s, api.type);
- STREAM_GETW(s, api.instance);
- STREAM_GETL(s, api.flags);
- STREAM_GETC(s, api.message);
- STREAM_GETW(s, api.safi);
-
- /* IPv4 prefix. */
- memset(&p, 0, sizeof(struct prefix));
- p.family = AF_INET;
- STREAM_GETC(s, p.prefixlen);
- if (p.prefixlen > IPV4_MAX_BITLEN) {
- zlog_warn("%s: Passed in prefixlen %d is impossible",
- __PRETTY_FUNCTION__, p.prefixlen);
- return;
- }
- STREAM_GET(&p.u.prefix4, s, PSIZE(p.prefixlen));
-
- table_id = zvrf->table_id;
-
- rib_delete(AFI_IP, api.safi, zvrf_id(zvrf), api.type, api.instance,
- api.flags, &p, NULL, NULL, table_id, 0, 0, false);
- client->v4_route_del_cnt++;
-
-stream_failure:
- return;
-}
-
/* MRIB Nexthop lookup for IPv4. */
static void zread_ipv4_nexthop_lookup_mrib(ZAPI_HANDLER_ARGS)
{
return;
}
-/* Zebra server IPv6 prefix add function. */
-static void zread_ipv4_route_ipv6_nexthop_add(ZAPI_HANDLER_ARGS)
-{
- unsigned int i;
- struct stream *s;
- struct in6_addr nhop_addr;
- struct route_entry *re;
- uint8_t message;
- uint8_t nexthop_num;
- uint8_t nexthop_type;
- struct prefix p;
- safi_t safi;
- static struct in6_addr nexthops[MULTIPATH_NUM];
- static unsigned int ifindices[MULTIPATH_NUM];
- int ret;
- static mpls_label_t labels[MULTIPATH_NUM];
- enum lsp_types_t label_type = ZEBRA_LSP_NONE;
- mpls_label_t label;
- struct nexthop *nexthop;
- enum blackhole_type bh_type = BLACKHOLE_NULL;
-
- /* Get input stream. */
- s = msg;
-
- memset(&nhop_addr, 0, sizeof(struct in6_addr));
-
- /* Allocate new re. */
- re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
-
- /* Type, flags, message. */
- STREAM_GETC(s, re->type);
- if (re->type > ZEBRA_ROUTE_MAX) {
- zlog_warn("%s: Specified route type: %d is not a legal value\n",
- __PRETTY_FUNCTION__, re->type);
- XFREE(MTYPE_RE, re);
- return;
- }
- STREAM_GETW(s, re->instance);
- STREAM_GETL(s, re->flags);
- STREAM_GETC(s, message);
- STREAM_GETW(s, safi);
- re->uptime = time(NULL);
-
- /* IPv4 prefix. */
- memset(&p, 0, sizeof(struct prefix_ipv4));
- p.family = AF_INET;
- STREAM_GETC(s, p.prefixlen);
- if (p.prefixlen > IPV4_MAX_BITLEN) {
- zlog_warn(
- "%s: Prefix Length %d is greater than what a v4 address can use",
- __PRETTY_FUNCTION__, p.prefixlen);
- XFREE(MTYPE_RE, re);
- return;
- }
- STREAM_GET(&p.u.prefix4, s, PSIZE(p.prefixlen));
-
- /* VRF ID */
- re->vrf_id = zvrf_id(zvrf);
-
- /*
- * We need to give nh-addr, nh-ifindex with the same next-hop object
- * to the re to ensure that IPv6 multipathing works; need to coalesce
- * these. Clients should send the same number of paired set of
- * next-hop-addr/next-hop-ifindices.
- */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP)) {
- unsigned int nh_count = 0;
- unsigned int if_count = 0;
- unsigned int max_nh_if = 0;
-
- STREAM_GETC(s, nexthop_num);
- zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
- nexthop_num);
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
- label_type = lsp_type_from_re_type(client->proto);
-
- for (i = 0; i < nexthop_num; i++) {
- STREAM_GETC(s, nexthop_type);
-
- switch (nexthop_type) {
- case NEXTHOP_TYPE_IPV6:
- STREAM_GET(&nhop_addr, s, 16);
- if (nh_count < MULTIPATH_NUM) {
- /*
- * For labeled-unicast, each nexthop is
- * followed by the label.
- */
- if (CHECK_FLAG(message,
- ZAPI_MESSAGE_LABEL)) {
- STREAM_GETL(s, label);
- labels[nh_count] = label;
- }
- nexthops[nh_count] = nhop_addr;
- nh_count++;
- }
- break;
- case NEXTHOP_TYPE_IFINDEX:
- if (if_count < multipath_num)
- STREAM_GETL(s, ifindices[if_count++]);
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- route_entry_nexthop_blackhole_add(re, bh_type);
- break;
- default:
- zlog_warn(
- "%s: Please use ZEBRA_ROUTE_ADD if you want to pass non v6 nexthops",
- __PRETTY_FUNCTION__);
- nexthops_free(re->ng.nexthop);
- XFREE(MTYPE_RE, re);
- return;
- }
- }
-
- max_nh_if = (nh_count > if_count) ? nh_count : if_count;
- for (i = 0; i < max_nh_if; i++) {
- if ((i < nh_count)
- && !IN6_IS_ADDR_UNSPECIFIED(&nexthops[i])) {
- if ((i < if_count) && ifindices[i])
- nexthop =
- route_entry_nexthop_ipv6_ifindex_add(
- re, &nexthops[i],
- ifindices[i],
- re->vrf_id);
- else
- nexthop = route_entry_nexthop_ipv6_add(
- re, &nexthops[i], re->vrf_id);
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
- nexthop_add_labels(nexthop, label_type,
- 1, &labels[i]);
- } else {
- if ((i < if_count) && ifindices[i])
- route_entry_nexthop_ifindex_add(
- re, ifindices[i], re->vrf_id);
- }
- }
- }
-
- /* Distance. */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE))
- STREAM_GETC(s, re->distance);
-
- /* Metric. */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC))
- STREAM_GETL(s, re->metric);
-
- /* Tag */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_TAG))
- STREAM_GETL(s, re->tag);
- else
- re->tag = 0;
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_MTU))
- STREAM_GETL(s, re->mtu);
- else
- re->mtu = 0;
-
- /* Table */
- re->table = zvrf->table_id;
-
- ret = rib_add_multipath(AFI_IP6, safi, &p, NULL, re);
- /* Stats */
- if (ret > 0)
- client->v4_route_add_cnt++;
- else if (ret < 0)
- client->v4_route_upd8_cnt++;
-
- return;
-
-stream_failure:
- nexthops_free(re->ng.nexthop);
- XFREE(MTYPE_RE, re);
-}
-
-static void zread_ipv6_add(ZAPI_HANDLER_ARGS)
-{
- unsigned int i;
- struct stream *s;
- struct in6_addr nhop_addr;
- ifindex_t ifindex;
- struct route_entry *re;
- uint8_t message;
- uint8_t nexthop_num;
- uint8_t nexthop_type;
- struct prefix p;
- struct prefix_ipv6 src_p, *src_pp;
- safi_t safi;
- static struct in6_addr nexthops[MULTIPATH_NUM];
- static unsigned int ifindices[MULTIPATH_NUM];
- int ret;
- static mpls_label_t labels[MULTIPATH_NUM];
- enum lsp_types_t label_type = ZEBRA_LSP_NONE;
- mpls_label_t label;
- struct nexthop *nexthop;
- enum blackhole_type bh_type = BLACKHOLE_NULL;
-
- /* Get input stream. */
- s = msg;
-
- memset(&nhop_addr, 0, sizeof(struct in6_addr));
-
- /* Allocate new re. */
- re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
-
- /* Type, flags, message. */
- STREAM_GETC(s, re->type);
- if (re->type > ZEBRA_ROUTE_MAX) {
- zlog_warn("%s: Specified route type: %d is not a legal value\n",
- __PRETTY_FUNCTION__, re->type);
- XFREE(MTYPE_RE, re);
- return;
- }
- STREAM_GETW(s, re->instance);
- STREAM_GETL(s, re->flags);
- STREAM_GETC(s, message);
- STREAM_GETW(s, safi);
- re->uptime = time(NULL);
-
- /* IPv6 prefix. */
- memset(&p, 0, sizeof(p));
- p.family = AF_INET6;
- STREAM_GETC(s, p.prefixlen);
- if (p.prefixlen > IPV6_MAX_BITLEN) {
- zlog_warn(
- "%s: Specified prefix length %d is to large for v6 prefix",
- __PRETTY_FUNCTION__, p.prefixlen);
- XFREE(MTYPE_RE, re);
- return;
- }
- STREAM_GET(&p.u.prefix6, s, PSIZE(p.prefixlen));
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_SRCPFX)) {
- memset(&src_p, 0, sizeof(src_p));
- src_p.family = AF_INET6;
- STREAM_GETC(s, src_p.prefixlen);
- if (src_p.prefixlen > IPV6_MAX_BITLEN) {
- zlog_warn(
- "%s: Specified src prefix length %d is to large for v6 prefix",
- __PRETTY_FUNCTION__, src_p.prefixlen);
- XFREE(MTYPE_RE, re);
- return;
- }
- STREAM_GET(&src_p.prefix, s, PSIZE(src_p.prefixlen));
- src_pp = &src_p;
- } else
- src_pp = NULL;
-
- /* VRF ID */
- re->vrf_id = zvrf_id(zvrf);
-
- /*
- * We need to give nh-addr, nh-ifindex with the same next-hop object
- * to the re to ensure that IPv6 multipathing works; need to coalesce
- * these. Clients should send the same number of paired set of
- * next-hop-addr/next-hop-ifindices.
- */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP)) {
- unsigned int nh_count = 0;
- unsigned int if_count = 0;
- unsigned int max_nh_if = 0;
-
- STREAM_GETC(s, nexthop_num);
- zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
- nexthop_num);
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
- label_type = lsp_type_from_re_type(client->proto);
-
- for (i = 0; i < nexthop_num; i++) {
- STREAM_GETC(s, nexthop_type);
-
- switch (nexthop_type) {
- case NEXTHOP_TYPE_IPV6:
- STREAM_GET(&nhop_addr, s, 16);
- if (nh_count < MULTIPATH_NUM) {
- /*
- * For labeled-unicast, each nexthop is
- * followed by label.
- */
- if (CHECK_FLAG(message,
- ZAPI_MESSAGE_LABEL)) {
- STREAM_GETL(s, label);
- labels[nh_count] = label;
- }
- nexthops[nh_count++] = nhop_addr;
- }
- break;
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- STREAM_GET(&nhop_addr, s, 16);
- STREAM_GETL(s, ifindex);
- route_entry_nexthop_ipv6_ifindex_add(
- re, &nhop_addr, ifindex, re->vrf_id);
- break;
- case NEXTHOP_TYPE_IFINDEX:
- if (if_count < multipath_num)
- STREAM_GETL(s, ifindices[if_count++]);
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- route_entry_nexthop_blackhole_add(re, bh_type);
- break;
- default:
- zlog_warn(
- "%s: Please use ZEBRA_ROUTE_ADD if you want to pass non v6 nexthops",
- __PRETTY_FUNCTION__);
- nexthops_free(re->ng.nexthop);
- XFREE(MTYPE_RE, re);
- return;
- }
- }
-
- max_nh_if = (nh_count > if_count) ? nh_count : if_count;
- for (i = 0; i < max_nh_if; i++) {
- if ((i < nh_count)
- && !IN6_IS_ADDR_UNSPECIFIED(&nexthops[i])) {
- if ((i < if_count) && ifindices[i])
- nexthop =
- route_entry_nexthop_ipv6_ifindex_add(
- re, &nexthops[i],
- ifindices[i],
- re->vrf_id);
- else
- nexthop = route_entry_nexthop_ipv6_add(
- re, &nexthops[i], re->vrf_id);
- if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
- nexthop_add_labels(nexthop, label_type,
- 1, &labels[i]);
- } else {
- if ((i < if_count) && ifindices[i])
- route_entry_nexthop_ifindex_add(
- re, ifindices[i], re->vrf_id);
- }
- }
- }
-
- /* Distance. */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE))
- STREAM_GETC(s, re->distance);
-
- /* Metric. */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC))
- STREAM_GETL(s, re->metric);
-
- /* Tag */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_TAG))
- STREAM_GETL(s, re->tag);
- else
- re->tag = 0;
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_MTU))
- STREAM_GETL(s, re->mtu);
- else
- re->mtu = 0;
-
- re->table = zvrf->table_id;
-
- ret = rib_add_multipath(AFI_IP6, safi, &p, src_pp, re);
- /* Stats */
- if (ret > 0)
- client->v6_route_add_cnt++;
- else if (ret < 0)
- client->v6_route_upd8_cnt++;
-
- return;
-
-stream_failure:
- nexthops_free(re->ng.nexthop);
- XFREE(MTYPE_RE, re);
-}
-
-/* Zebra server IPv6 prefix delete function. */
-static void zread_ipv6_delete(ZAPI_HANDLER_ARGS)
-{
- struct stream *s;
- struct zapi_ipv6 api;
- struct prefix p;
- struct prefix_ipv6 src_p, *src_pp;
-
- s = msg;
-
- /* Type, flags, message. */
- STREAM_GETC(s, api.type);
- STREAM_GETW(s, api.instance);
- STREAM_GETL(s, api.flags);
- STREAM_GETC(s, api.message);
- STREAM_GETW(s, api.safi);
-
- /* IPv4 prefix. */
- memset(&p, 0, sizeof(struct prefix));
- p.family = AF_INET6;
- STREAM_GETC(s, p.prefixlen);
- STREAM_GET(&p.u.prefix6, s, PSIZE(p.prefixlen));
-
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) {
- memset(&src_p, 0, sizeof(struct prefix_ipv6));
- src_p.family = AF_INET6;
- STREAM_GETC(s, src_p.prefixlen);
- STREAM_GET(&src_p.prefix, s, PSIZE(src_p.prefixlen));
- src_pp = &src_p;
- } else
- src_pp = NULL;
-
- rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type, api.instance,
- api.flags, &p, src_pp, NULL, client->rtm_table, 0, 0, false);
-
- client->v6_route_del_cnt++;
-
-stream_failure:
- return;
-}
-
/* Register zebra server router-id information. Send current router-id */
static void zread_router_id_add(ZAPI_HANDLER_ARGS)
{
[ZEBRA_INTERFACE_DELETE] = zread_interface_delete,
[ZEBRA_ROUTE_ADD] = zread_route_add,
[ZEBRA_ROUTE_DELETE] = zread_route_del,
- [ZEBRA_IPV4_ROUTE_ADD] = zread_ipv4_add,
- [ZEBRA_IPV4_ROUTE_DELETE] = zread_ipv4_delete,
- [ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD] = zread_ipv4_route_ipv6_nexthop_add,
- [ZEBRA_IPV6_ROUTE_ADD] = zread_ipv6_add,
- [ZEBRA_IPV6_ROUTE_DELETE] = zread_ipv6_delete,
[ZEBRA_REDISTRIBUTE_ADD] = zebra_redistribute_add,
[ZEBRA_REDISTRIBUTE_DELETE] = zebra_redistribute_delete,
[ZEBRA_REDISTRIBUTE_DEFAULT_ADD] = zebra_redistribute_default_add,
/* filter route selection in following order:
* - connected beats other types
+ * - if both connected, loopback or vrf wins
* - lower distance beats higher
* - lower metric beats higher for equal distance
* - last, hence oldest, route wins tie break.
*/
- /* Connected routes. Pick the last connected
+ /* Connected routes. Check to see if either are a vrf
+ * or loopback interface. If not, pick the last connected
* route of the set of lowest metric connected routes.
*/
if (alternate->type == ZEBRA_ROUTE_CONNECT) {
- if (current->type != ZEBRA_ROUTE_CONNECT
- || alternate->metric <= current->metric)
+ if (current->type != ZEBRA_ROUTE_CONNECT)
+ return alternate;
+
+ /* both are connected. are either loop or vrf? */
+ struct nexthop *nexthop = NULL;
+
+ for (ALL_NEXTHOPS(alternate->ng, nexthop)) {
+ if (if_is_loopback_or_vrf(if_lookup_by_index(
+ nexthop->ifindex, alternate->vrf_id)))
+ return alternate;
+ }
+
+ for (ALL_NEXTHOPS(current->ng, nexthop)) {
+ if (if_is_loopback_or_vrf(if_lookup_by_index(
+ nexthop->ifindex, current->vrf_id)))
+ return current;
+ }
+
+ /* Neither are loop or vrf so pick best metric */
+ if (alternate->metric <= current->metric)
return alternate;
return current;
}
/* Schedule routes of a particular table (address-family) based on event. */
-static void rib_update_table(struct route_table *table,
- rib_update_event_t event)
+void rib_update_table(struct route_table *table, rib_update_event_t event)
{
struct route_node *rn;
struct route_entry *re, *next;
/* Process routes of interested address-families. */
table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
- if (table)
+ if (table) {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s : AFI_IP event %d", __func__, event);
rib_update_table(table, event);
+ }
table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, vrf_id);
- if (table)
+ if (table) {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s : AFI_IP6 event %d", __func__, event);
rib_update_table(table, event);
+ }
}
/* Delete self installed routes after zebra is relaunched. */
return buf;
}
-struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
+struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
+ bool *exists)
{
struct route_table *table;
struct route_node *rn;
prefix2str(p, buf, sizeof(buf));
zlog_warn("%u: Add RNH %s type %d - table not found", vrfid,
buf, type);
+ exists = false;
return NULL;
}
route_lock_node(rn);
rn->info = rnh;
rnh->node = rn;
- }
+ *exists = false;
+ } else
+ *exists = true;
route_unlock_node(rn);
return (rn->info);
route_unlock_node(rn);
}
+/*
+ * This code will send to the registering client
+ * the looked up rnh.
+ * For a rnh that was created, there is no data
+ * so it will send an empty nexthop group
+ * If rnh exists then we know it has been evaluated
+ * and as such it will have a resolved rnh.
+ */
void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
rnh_type_t type, vrf_id_t vrf_id)
{
}
if (!listnode_lookup(rnh->client_list, client)) {
listnode_add(rnh->client_list, client);
- send_client(rnh, client, type,
- vrf_id); // Pending: check if its needed
+ send_client(rnh, client, type, vrf_id);
}
}
{
struct prefix nh;
struct rnh *rnh;
+ bool exists;
addr2hostprefix(pw->af, &pw->nexthop, &nh);
- rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE);
+ rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE, &exists);
if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) {
listnode_add(rnh->zebra_pseudowire_list, pw);
pw->rnh = rnh;
}
extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid,
- rnh_type_t type);
+ rnh_type_t type, bool *exists);
extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid,
rnh_type_t type);
extern void zebra_free_rnh(struct rnh *rnh);
/* `match ip address prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+route_match_address_prefix_list(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object, afi_t afi)
{
struct prefix_list *plist;
if (type == RMAP_ZEBRA) {
- plist = prefix_list_lookup(AFI_IP, (char *)rule);
+ plist = prefix_list_lookup(afi, (char *)rule);
if (plist == NULL)
return RMAP_NOMATCH;
return RMAP_NOMATCH;
}
-static void *route_match_ip_address_prefix_list_compile(const char *arg)
+static route_map_result_t
+route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ return (route_match_address_prefix_list(rule, prefix, type, object,
+ AFI_IP));
+}
+
+static void *route_match_address_prefix_list_compile(const char *arg)
{
return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
}
-static void route_match_ip_address_prefix_list_free(void *rule)
+static void route_match_address_prefix_list_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
"ip address prefix-list", route_match_ip_address_prefix_list,
- route_match_ip_address_prefix_list_compile,
- route_match_ip_address_prefix_list_free};
+ route_match_address_prefix_list_compile,
+ route_match_address_prefix_list_free};
+static route_map_result_t
+route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ return (route_match_address_prefix_list(rule, prefix, type, object,
+ AFI_IP6));
+}
+
+static struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
+ "ipv6 address prefix-list", route_match_ipv6_address_prefix_list,
+ route_match_address_prefix_list_compile,
+ route_match_address_prefix_list_free};
/* `match ip address prefix-len PREFIXLEN' */
"src", route_set_src, route_set_src_compile, route_set_src_free,
};
+/* The function checks if the changed routemap specified by parameter rmap
+ * matches the configured protocol routemaps in proto_rm table. If there is
+ * a match then rib_update_table() to process the routes.
+ */
+static void zebra_rib_table_rm_update(const char *rmap)
+{
+ int i = 0;
+ struct route_table *table;
+ char *rmap_name;
+ char afi_ip = 0;
+ char afi_ipv6 = 0;
+
+ for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) {
+ /* Check for ip routemap table */
+ rmap_name = proto_rm[AFI_IP][i];
+ if (rmap_name && (strcmp(rmap_name, rmap) == 0)) {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s : AFI_IP rmap %s, route type %s",
+ __func__, rmap, zebra_route_string(i));
+ /* There is single rib table for all protocols */
+ if (afi_ip == 0) {
+ table = zebra_vrf_table(AFI_IP, SAFI_UNICAST,
+ VRF_DEFAULT);
+ if (table) {
+ afi_ip = 1;
+ rib_update_table(table,
+ RIB_UPDATE_RMAP_CHANGE);
+ }
+ }
+ }
+
+ /* Check for ipv6 routemap table */
+ rmap_name = proto_rm[AFI_IP6][i];
+ if (rmap_name && (strcmp(rmap_name, rmap) == 0)) {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s : AFI_IP6 rmap %s,route type %s",
+ __func__, rmap, zebra_route_string(i));
+ if (afi_ipv6 == 0) {
+ table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST,
+ VRF_DEFAULT);
+ if (table) {
+ afi_ipv6 = 1;
+ rib_update_table(table,
+ RIB_UPDATE_RMAP_CHANGE);
+ }
+ }
+ }
+ }
+}
+
+/* The function checks if the changed routemap specified by parameter rmap
+ * matches the configured protocol routemaps in nht_rm table. If there is
+ * a match then zebra_evaluate_rnh() to process the nexthops.
+ */
+static void zebra_nht_rm_update(const char *rmap)
+{
+ int i = 0;
+ char *rmap_name;
+ char afi_ip = 0;
+ char afi_ipv6 = 0;
+
+ for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) {
+ rmap_name = nht_rm[AFI_IP][i];
+ if (rmap_name && (strcmp(rmap_name, rmap) == 0)) {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s : AFI_IP rmap %s route type %s",
+ __func__, rmap, zebra_route_string(i));
+ if (afi_ip == 0) {
+ afi_ip = 1;
+ zebra_evaluate_rnh(0, AF_INET, 1,
+ RNH_NEXTHOP_TYPE, NULL);
+ }
+ }
+ rmap_name = nht_rm[AFI_IP6][i];
+ if (rmap_name && (strcmp(rmap_name, rmap) == 0)) {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s : AFI_IP6 rmap %s route type %s",
+ __func__, rmap, zebra_route_string(i));
+ if (afi_ipv6 == 0) {
+ afi_ipv6 = 1;
+ zebra_evaluate_rnh(0, AF_INET6, 1,
+ RNH_NEXTHOP_TYPE, NULL);
+ }
+ }
+ }
+}
+
static void zebra_route_map_process_update_cb(char *rmap_name)
{
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("Event handler for route-map: %s",
rmap_name);
+ zebra_import_table_rm_update(rmap_name);
+ zebra_rib_table_rm_update(rmap_name);
+ zebra_nht_rm_update(rmap_name);
}
static int zebra_route_map_update_timer(struct thread *thread)
* 1) VRF Aware <sigh>
* 2) Route-map aware
*/
- zebra_import_table_rm_update();
- rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
- zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
- zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
-
return (0);
}
route_map_match_tag_hook(generic_match_add);
route_map_no_match_tag_hook(generic_match_delete);
+ route_map_match_ipv6_address_hook(generic_match_add);
+ route_map_no_match_ipv6_address_hook(generic_match_delete);
+
+ route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
+ route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
+
route_map_install_match(&route_match_tag_cmd);
route_map_install_match(&route_match_interface_cmd);
route_map_install_match(&route_match_ip_next_hop_cmd);
route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
route_map_install_match(&route_match_ip_address_cmd);
route_map_install_match(&route_match_ip_address_prefix_list_cmd);
+ route_map_install_match(&route_match_ipv6_address_prefix_list_cmd);
route_map_install_match(&route_match_ip_address_prefix_len_cmd);
route_map_install_match(&route_match_ipv6_address_prefix_len_cmd);
route_map_install_match(&route_match_ip_nexthop_prefix_len_cmd);
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
struct interface *vlan_if;
+#ifdef GNU_LINUX
uint8_t flags;
+#endif
int ret = 0;
if (!(n->flags & ZEBRA_NEIGH_REMOTE))
uint32_t old_mac_seq = 0, mac_new_seq = 0;
bool upd_mac_seq = false;
bool neigh_mac_change = false;
+ bool check_rbit = false;
/* Check if the MAC exists. */
zmac = zvni_mac_lookup(zvni, macaddr);
/* Set "local" forwarding info. */
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
n->ifindex = ifp->ifindex;
+ check_rbit = true;
} else {
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
/* If there is no MAC change, BGP isn't interested. */
+ if (router_flag !=
+ (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)
+ ? 1 : 0))
+ check_rbit = true;
+
if (memcmp(n->emac.octet, macaddr->octet,
ETH_ALEN) == 0) {
/* Update any params and return - client doesn't
* care about a purely local change.
*/
n->ifindex = ifp->ifindex;
- return 0;
- }
+ } else {
- /* If the MAC has changed, need to issue a delete
- * first as this means a different MACIP route.
- * Also, need to do some unlinking/relinking.
- * We also need to update the MAC's sequence number
- * in different situations.
- */
- if (IS_ZEBRA_NEIGH_ACTIVE(n))
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0);
- old_zmac = zvni_mac_lookup(zvni, &n->emac);
- if (old_zmac) {
- old_mac_seq = CHECK_FLAG(old_zmac->flags,
- ZEBRA_MAC_REMOTE) ?
- old_zmac->rem_seq : old_zmac->loc_seq;
- neigh_mac_change = upd_mac_seq = true;
- listnode_delete(old_zmac->neigh_list, n);
- zvni_deref_ip2mac(zvni, old_zmac, 0);
- }
+ /* If the MAC has changed, need to issue a
+ * delete first as this means a different
+ * MACIP route. Also, need to do some
+ * unlinking/relinking. We also need to
+ * update the MAC's sequence number
+ * in different situations.
+ */
+ if (IS_ZEBRA_NEIGH_ACTIVE(n))
+ zvni_neigh_send_del_to_client(
+ zvni->vni, &n->ip, &n->emac, 0);
+ old_zmac = zvni_mac_lookup(zvni, &n->emac);
+ if (old_zmac) {
+ old_mac_seq =
+ CHECK_FLAG(old_zmac->flags,
+ ZEBRA_MAC_REMOTE) ?
+ old_zmac->rem_seq :
+ old_zmac->loc_seq;
+ neigh_mac_change = upd_mac_seq = true;
+ listnode_delete(
+ old_zmac->neigh_list, n);
+ zvni_deref_ip2mac(zvni, old_zmac, 0);
+ }
- /* Update the forwarding info. */
- n->ifindex = ifp->ifindex;
- memcpy(&n->emac, macaddr, ETH_ALEN);
+ /* Update the forwarding info. */
+ n->ifindex = ifp->ifindex;
+ memcpy(&n->emac, macaddr, ETH_ALEN);
- /* Link to new MAC */
- listnode_add_sort(zmac->neigh_list, n);
+ /* Link to new MAC */
+ listnode_add_sort(zmac->neigh_list, n);
+ }
} else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
/*
n->r_vtep_ip.s_addr = 0;
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
n->ifindex = ifp->ifindex;
+ check_rbit = true;
}
}
MAX(seq1, seq2) : zmac->loc_seq;
}
+ /*Mark Router flag (R-bit) */
+ if (router_flag)
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ else
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
/* Before we program this in BGP, we need to check if MAC is locally
* learnt. If not, force neighbor to be inactive and reset its seq.
*/
return 0;
}
- /* Set router flag (R-bit) */
- if (router_flag)
- SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ if (!check_rbit) {
+ return 0;
+ }
/* If the MAC's sequence number has changed, inform the MAC and all
* neighbors associated with the MAC to BGP, else just inform this
*/
static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
{
+#ifdef GNU_LINUX
uint8_t flags;
+#endif
int ret = 0;
if (!is_l3vni_oper_up(zl3vni))
uint32_t tmp_seq;
uint8_t sticky = 0;
u_char remote_gw = 0;
+ uint8_t router_flag = 0;
/* Locate VNI hash entry - expected to exist. */
zvni = zvni_lookup(vni);
sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
remote_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+ router_flag = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
mac = zvni_mac_lookup(zvni, macaddr);
|| !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
|| (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0)
|| !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip)
+ || ((CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) ? 1 : 0)
+ != router_flag)
|| seq != n->rem_seq)
update_neigh = 1;
/* Set router flag (R-bit) to this Neighbor entry */
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ else
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
/* Install the entry. */
zvni_neigh_install(zvni, n);
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s-> L2-VNI %u",
+ "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s %s-> L2-VNI %u",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, state, ext_learned ? "ext-learned " : "",
+ router_flag ? "router " : "",
zvni->vni);
/* Is this about a local neighbor or a remote one? */
flags, seq, inet_ntoa(vtep_ip),
zebra_route_string(client->proto));
-
process_remote_macip_add(vni, &macaddr, ipa_len, &ip,
flags, seq, vtep_ip);
}