diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index fee2e89f8b..a104a2e16d 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -4896,6 +4896,23 @@ void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn) 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. */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 8d71c3123e..f0017f3533 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -503,4 +503,5 @@ extern struct evpnes *bgp_evpn_lookup_es(struct bgp *bgp, esi_t *esi); 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 */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 3828ce216b..b553cb42a5 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1888,6 +1888,14 @@ static struct bgpevpn *evpn_create_update_vni(struct bgp *bgp, vni_t vni) 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 */ diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index 6695596c6f..e29508bf36 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -148,7 +148,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, 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; diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index f8c0613208..31d2c540fa 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -335,7 +335,7 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, 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(); @@ -347,14 +347,14 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, 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); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 0664fdfd1c..22d5d35c82 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -672,7 +672,8 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen, 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); diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 129c143a64..b182fde1e2 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -1680,7 +1680,7 @@ static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add) ? "!" : "", 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 ? "" : prefix2str(bpf->src, bufsrc, sizeof(bufsrc)), @@ -1807,7 +1807,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, 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); @@ -1838,10 +1838,9 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, 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; @@ -1853,7 +1852,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, 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 && diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 041049d05b..50c484d7de 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -38,6 +38,7 @@ #include "queue.h" #include "memory.h" #include "lib/json.h" +#include "lib_errors.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -188,8 +189,24 @@ static void bgp_info_extra_free(struct bgp_info_extra **extra) 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; } @@ -198,8 +215,7 @@ static void bgp_info_extra_free(struct bgp_info_extra **extra) 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; @@ -338,14 +354,9 @@ static void bgp_pcount_adjust(struct bgp_node *rn, struct bgp_info *ri) /* 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); @@ -1039,8 +1050,8 @@ static enum filter_type bgp_input_filter(struct peer *peer, struct prefix *p, #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); @@ -1078,8 +1089,8 @@ static enum filter_type bgp_output_filter(struct peer *peer, struct prefix *p, #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); @@ -8187,7 +8198,6 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, vty_out(vty, " \"routeDistinguishers\" : {"); ++*json_header_depth; } - json_paths = json_object_new_object(); } if (use_json && rd) { @@ -8414,8 +8424,6 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, *total_cum = total_count; } if (use_json) { - if (json_paths) - json_object_free(json_paths); if (rd) { vty_out(vty, " }%s ", (is_last ? "" : ",")); } @@ -8573,9 +8581,19 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, 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; @@ -8652,12 +8670,41 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, } 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, @@ -9018,6 +9065,10 @@ DEFUN (show_ip_bgp, |prefix-list WORD\ |filter-list WORD\ |statistics\ + |community [exact-match]\ |community-list <(1-500)|WORD> [exact-match]\ |A.B.C.D/M longer-prefixes\ |X:X::X:X/M longer-prefixes\ @@ -9037,6 +9088,23 @@ DEFUN (show_ip_bgp, "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" @@ -9797,8 +9865,6 @@ static int bgp_peer_count_walker(struct thread *t) pc->count[PCOUNT_ADJ_IN]++; for (ri = rn->info; ri; ri = ri->next) { - char buf[SU_ADDRSTRLEN]; - if (ri->peer != peer) continue; @@ -9820,22 +9886,12 @@ static int bgp_peer_count_walker(struct thread *t) 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"); } } } diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 52c5dc5e90..82b268c31d 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -47,6 +47,7 @@ #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" @@ -131,12 +132,14 @@ static route_map_result_t route_match(void *rule, const struct prefix *prefix, 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; @@ -229,7 +232,7 @@ static void *route_match_compile(const char *arg) { 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; @@ -345,6 +348,19 @@ static int bgpd_sync_callback(struct thread *thread) 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)) { @@ -356,26 +372,36 @@ static int bgpd_sync_callback(struct thread *thread) 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 (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - if (!bgp->rib[afi][safi]) - continue; + for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) { + safi_t safi; - struct list *matches = list_new(); + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + if (!peer->bgp->rib[afi][safi]) + continue; - matches->del = (void (*)(void *))bgp_unlock_node; + struct list *matches = list_new(); - bgp_table_range_lookup(bgp->rib[afi][safi], prefix, - rec.max_len, matches); + matches->del = + (void (*)(void *))bgp_unlock_node; + + 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); + } } } @@ -398,14 +424,13 @@ static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi, 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; - } } } @@ -413,25 +438,23 @@ static void revalidate_all_routes(void) { struct bgp *bgp; struct listnode *node; - struct bgp_node *bgp_node; for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { - for (size_t i = 0; i < 2; i++) { - safi_t safi; - afi_t afi = (i == 0) ? AFI_IP : AFI_IP6; + 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 (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 (size_t i = 0; i < 2; i++) { + safi_t safi; + afi_t afi = (i == 0) ? AFI_IP : AFI_IP6; + + for (safi = SAFI_UNICAST; safi < SAFI_MAX; + safi++) { + if (!peer->bgp->rib[afi][safi]) + continue; + + bgp_soft_reconfig_in(peer, afi, safi); } } } @@ -442,28 +465,53 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)), const struct pfx_record rec, const bool added __attribute__((unused))) { - if (rtr_is_stopping || rtr_is_starting) + 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) @@ -514,6 +562,7 @@ static int start(void) rtr_is_stopping = 0; rtr_is_starting = 1; + rtr_update_overflow = 0; if (list_isempty(cache_list)) { RPKI_DEBUG( @@ -1210,10 +1259,10 @@ DEFUN_NOSH (rpki_exit, "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, diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index f7eac09546..60c2cbd4a4 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -128,9 +128,9 @@ static inline struct bgp_node *bgp_node_parent_nolock(struct bgp_node *node) /* * 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)); } /* diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index fda458cb84..1460a26215 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2019,7 +2019,7 @@ DEFUN (no_bgp_fast_external_failover, } /* "bgp enforce-first-as" configuration. */ -#if CONFDATE > 20180517 +#if CONFDATE > 20190517 CPP_NOTICE("bgpd: remove deprecated '[no] bgp enforce-first-as' commands") #endif @@ -10995,7 +10995,7 @@ DEFUN (show_ip_bgp_attr_info, } 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; @@ -11004,64 +11004,148 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, 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) { + 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 = name ? bgp_lookup_by_name(name) : bgp_get_default(); + if (!bgp) { vty_out(vty, "%% No such BGP instance exist\n"); return CMD_WARNING; } - } else { - bgp = bgp_get_default(); - if (!bgp) { + + if (!CHECK_FLAG(bgp->af_flags[afi][safi], + BGP_CONFIG_VRF_TO_VRF_IMPORT)) vty_out(vty, - "%% Default BGP instance does not exist\n"); - return CMD_WARNING; - } - } + "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)); - 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); - } + 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_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", - afi_safi_print(afi, safi)); - for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].export_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); + } + + 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", + afi_safi_print(afi, safi)); + + 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; @@ -11069,20 +11153,22 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, /* "show [ip] bgp route-leak" command. */ DEFUN (show_ip_bgp_route_leak, - show_ip_bgp_route_leak_cmd, - "show [ip] bgp [ 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 [ 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 */ @@ -11110,7 +11196,7 @@ DEFUN (show_ip_bgp_route_leak, 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, @@ -11462,7 +11548,7 @@ DEFUN (bgp_redistribute_ipv4, } 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( @@ -11483,6 +11569,7 @@ DEFUN (bgp_redistribute_ipv4_rmap, int idx_word = 3; int type; struct bgp_redist *red; + bool changed; type = proto_redistnum(AFI_IP, argv[idx_protocol]->text); if (type < 0) { @@ -11491,8 +11578,8 @@ DEFUN (bgp_redistribute_ipv4_rmap, } 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( @@ -11516,6 +11603,7 @@ DEFUN (bgp_redistribute_ipv4_metric, int type; uint32_t metric; struct bgp_redist *red; + bool changed; type = proto_redistnum(AFI_IP, argv[idx_protocol]->text); if (type < 0) { @@ -11525,8 +11613,8 @@ DEFUN (bgp_redistribute_ipv4_metric, 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( @@ -11553,6 +11641,7 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric, int type; uint32_t metric; struct bgp_redist *red; + bool changed; type = proto_redistnum(AFI_IP, argv[idx_protocol]->text); if (type < 0) { @@ -11562,9 +11651,9 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric, 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( @@ -11595,6 +11684,7 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap, int type; uint32_t metric; struct bgp_redist *red; + bool changed; type = proto_redistnum(AFI_IP, argv[idx_protocol]->text); if (type < 0) { @@ -11604,9 +11694,9 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap, 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( @@ -11642,7 +11732,7 @@ DEFUN (bgp_redistribute_ipv4_ospf, 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, @@ -11669,6 +11759,7 @@ DEFUN (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; @@ -11677,8 +11768,8 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap, 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, @@ -11709,6 +11800,7 @@ DEFUN (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; @@ -11719,8 +11811,9 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric, 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, @@ -11754,6 +11847,7 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_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; @@ -11764,9 +11858,10 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, 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( @@ -11803,6 +11898,7 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_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; @@ -11813,9 +11909,10 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, 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( @@ -11923,7 +12020,7 @@ DEFUN (bgp_redistribute_ipv6, } 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, @@ -11939,6 +12036,7 @@ 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) { @@ -11947,8 +12045,8 @@ DEFUN (bgp_redistribute_ipv6_rmap, } 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, @@ -11965,6 +12063,7 @@ 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) { @@ -11974,8 +12073,8 @@ DEFUN (bgp_redistribute_ipv6_metric, 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, @@ -11995,6 +12094,7 @@ 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) { @@ -12004,9 +12104,10 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric, 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, @@ -12026,6 +12127,7 @@ 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) { @@ -12035,9 +12137,10 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap, 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, diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index c7049ef213..43afc317e9 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1576,8 +1576,14 @@ static void bgp_redist_del(struct bgp *bgp, afi_t afi, uint8_t type, /* 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) { diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index e3c88b9db6..546d72402a 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -51,7 +51,8 @@ extern struct bgp_redist *bgp_redist_lookup(struct bgp *, afi_t, uint8_t, 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, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index c8b4e3acf5..7ff5053ce3 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3187,15 +3187,16 @@ int bgp_delete(struct bgp *bgp) .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); @@ -6631,17 +6632,6 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, uint8_t use_json, 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, " "); - } - return buf; - } - /* If there is no connection has been done before print `never'. */ if (uptime2 == 0) { if (use_json) { @@ -7356,7 +7346,7 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, } /* 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 */ diff --git a/configure.ac b/configure.ac index 96e201cc42..be1c2763a1 100755 --- a/configure.ac +++ b/configure.ac @@ -382,7 +382,7 @@ AC_ARG_ENABLE(bgp-vnc, 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, @@ -418,8 +418,6 @@ AC_ARG_ENABLE(rusage, 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, @@ -644,10 +642,6 @@ AM_CONDITIONAL([HAVE_PROTOBUF], [test "x$have_protobuf" = "xyes"]) # 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) @@ -1496,14 +1490,13 @@ int main(void); 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 diff --git a/debianpkg/backports/ubuntu12.04/debian/rules b/debianpkg/backports/ubuntu12.04/debian/rules index 3a6c80297e..7495db89cb 100755 --- a/debianpkg/backports/ubuntu12.04/debian/rules +++ b/debianpkg/backports/ubuntu12.04/debian/rules @@ -10,7 +10,6 @@ WANT_LDP ?= 1 WANT_PIM ?= 1 WANT_OSPFAPI ?= 1 -WANT_TCP_ZEBRA ?= 0 WANT_BGP_VNC ?= 1 WANT_CUMULUS_MODE ?= 0 WANT_MULTIPATH ?= 1 @@ -65,12 +64,6 @@ else 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 @@ -123,7 +116,6 @@ override_dh_auto_configure: $(USE_OSPFAPI) \ $(USE_MULTIPATH) \ $(USE_LDP) \ - $(USE_TCP_ZEBRA) \ --enable-fpm \ $(USE_FRR_USER) $(USE_FRR_GROUP) \ $(USE_FRR_VTY_GROUP) \ @@ -162,12 +154,8 @@ override_dh_auto_install: 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 diff --git a/debianpkg/backports/ubuntu14.04/debian/rules b/debianpkg/backports/ubuntu14.04/debian/rules index f7468d6f79..c955d0c945 100755 --- a/debianpkg/backports/ubuntu14.04/debian/rules +++ b/debianpkg/backports/ubuntu14.04/debian/rules @@ -10,7 +10,6 @@ WANT_LDP ?= 1 WANT_PIM ?= 1 WANT_OSPFAPI ?= 1 -WANT_TCP_ZEBRA ?= 0 WANT_BGP_VNC ?= 1 WANT_CUMULUS_MODE ?= 0 WANT_MULTIPATH ?= 1 @@ -75,12 +74,6 @@ else 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 @@ -152,7 +145,6 @@ override_dh_auto_configure: $(USE_OSPFAPI) \ $(USE_MULTIPATH) \ $(USE_LDP) \ - $(USE_TCP_ZEBRA) \ --enable-fpm \ $(USE_FRR_USER) $(USE_FRR_GROUP) \ $(USE_FRR_VTY_GROUP) \ @@ -196,12 +188,8 @@ override_dh_auto_install: 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 diff --git a/debianpkg/rules b/debianpkg/rules index c1cb865490..811d45bc0b 100755 --- a/debianpkg/rules +++ b/debianpkg/rules @@ -10,7 +10,6 @@ WANT_LDP ?= 1 WANT_PIM ?= 1 WANT_OSPFAPI ?= 1 -WANT_TCP_ZEBRA ?= 0 WANT_BGP_VNC ?= 1 WANT_CUMULUS_MODE ?= 0 WANT_MULTIPATH ?= 1 @@ -75,12 +74,6 @@ else 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 @@ -152,7 +145,6 @@ override_dh_auto_configure: $(USE_OSPFAPI) \ $(USE_MULTIPATH) \ $(USE_LDP) \ - $(USE_TCP_ZEBRA) \ --enable-fpm \ $(USE_FRR_USER) $(USE_FRR_GROUP) \ $(USE_FRR_VTY_GROUP) \ @@ -194,12 +186,8 @@ override_dh_auto_install: 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 diff --git a/doc/Makefile.am b/doc/Makefile.am index 6f72585485..f421865054 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -193,6 +193,7 @@ EXTRA_DIST = frr-sphinx.mk \ 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 \ diff --git a/doc/developer/library.rst b/doc/developer/library.rst index f6efa33051..77b2f229b7 100644 --- a/doc/developer/library.rst +++ b/doc/developer/library.rst @@ -7,6 +7,7 @@ Library Facilities (libfrr) .. toctree:: :maxdepth: 2 + logging memtypes hooks cli diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst new file mode 100644 index 0000000000..4338d900e6 --- /dev/null +++ b/doc/developer/logging.rst @@ -0,0 +1,131 @@ +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 diff --git a/doc/developer/zebra.rst b/doc/developer/zebra.rst index 3d64b67115..1bf31e9624 100644 --- a/doc/developer/zebra.rst +++ b/doc/developer/zebra.rst @@ -102,14 +102,6 @@ Zebra Protocol Commands +-----------------------------------+-------+ | 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 | diff --git a/doc/manpages/common-options.rst b/doc/manpages/common-options.rst index 1e99010505..5fff6fca66 100644 --- a/doc/manpages/common-options.rst +++ b/doc/manpages/common-options.rst @@ -126,7 +126,7 @@ These following options control the daemon's VTY (interactive command line) inte 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 diff --git a/doc/manpages/index.rst b/doc/manpages/index.rst index e95dd26e84..c62835c770 100644 --- a/doc/manpages/index.rst +++ b/doc/manpages/index.rst @@ -6,6 +6,7 @@ .. toctree:: :maxdepth: 2 + bfdd bgpd eigrpd isisd diff --git a/doc/user/_static/overrides.css b/doc/user/_static/overrides.css index 0d871c961a..3143f8bb65 100644 --- a/doc/user/_static/overrides.css +++ b/doc/user/_static/overrides.css @@ -6,3 +6,50 @@ div.body { 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; +} diff --git a/doc/user/_static/overrides.js b/doc/user/_static/overrides.js new file mode 100644 index 0000000000..73bf6123b5 --- /dev/null +++ b/doc/user/_static/overrides.js @@ -0,0 +1,13 @@ +/* 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(); +}); diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 8eb9efe789..986d1494a5 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -179,7 +179,7 @@ The following commands are available inside the BGP configuration node. .. _bfd-ospf-peer-config: OSPF BFD Configuration ---------------------- +---------------------- The following commands are available inside the interface configuration node. @@ -364,7 +364,7 @@ You can inspect the current BFD peer status with the following commands: 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: @@ -402,4 +402,4 @@ 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} diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index f1209c2172..2cea24a8bd 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1011,6 +1011,75 @@ is 4 octet long. The following format is used to define the community value. ``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 @@ -1030,6 +1099,11 @@ is 4 octet long. The following format is used to define the community value. 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. diff --git a/doc/user/conf.py b/doc/user/conf.py index 28081bca7d..2231989fe5 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -358,6 +358,7 @@ def setup(app): 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 diff --git a/doc/user/overview.rst b/doc/user/overview.rst index 369f17dcba..51bd6228e3 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -5,12 +5,12 @@ Overview ******** `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 @@ -150,27 +150,93 @@ Recent versions of the following compilers are well tested: .. _supported-protocols: -Supported Protocols & RFCs -========================== +Supported Protocols vs. Platform +================================ -The following well-known protocols are supported: +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. -- BGP -- Babel -- EIGRP -- IS-IS -- LDP -- NHRP -- OSPFv2 -- OSPFv3 -- PIM -- RIP -- RIPNG +.. role:: mark -The following technologies are supported as well: +.. 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.) -- PBR (Policy Based Routing) -- VNC (Virtual Network Control) ++--+--------------------------------+----------------+--------------+------------+------------+------------+ +| 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: diff --git a/doc/user/snmp.rst b/doc/user/snmp.rst index 38918ff250..5579969c0e 100644 --- a/doc/user/snmp.rst +++ b/doc/user/snmp.rst @@ -7,8 +7,8 @@ SNMP Support :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. @@ -18,16 +18,10 @@ 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/ `_ -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: @@ -42,7 +36,7 @@ master SNMP agent (snmpd) and each of the FRR daemons must be configured. In :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`: :: @@ -97,105 +91,6 @@ need to configure FRR to use another transport, you can configure it through 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 diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index d05dba33ee..7e8a4a4eda 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -43,6 +43,7 @@ #include "isisd/isis_constants.h" #include "isisd/isis_circuit.h" #include "isisd/isis_network.h" +#include "isisd/isis_pdu.h" #include "privs.h" diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 7cf83f20fa..cd4b76139f 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -536,7 +536,7 @@ void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream) *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); } } diff --git a/lib/buffer.c b/lib/buffer.c index 0292c85dac..1799c6b94f 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -274,19 +274,12 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width, 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) { @@ -334,11 +327,6 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width, { 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 { diff --git a/lib/compiler.h b/lib/compiler.h index b19c33f65e..24b8fafd10 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -24,6 +24,9 @@ #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) @@ -34,6 +37,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 @@ -55,6 +61,9 @@ #ifndef _ALLOC_SIZE # define _ALLOC_SIZE(x) #endif +#ifndef _FALLTHROUGH +#define _FALLTHROUGH +#endif /* * for warnings on macros, put in the macro content like this: diff --git a/lib/ferr.c b/lib/ferr.c index 2fa5db6f34..17ec51c4bf 100644 --- a/lib/ferr.c +++ b/lib/ferr.c @@ -107,7 +107,7 @@ struct log_ref *log_ref_get(uint32_t code) 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; @@ -146,7 +146,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json) 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'; diff --git a/lib/if.c b/lib/if.c index 6023624dc1..2bf0c6e6b5 100644 --- a/lib/if.c +++ b/lib/if.c @@ -393,7 +393,8 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id, int vty) * 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 @@ -471,6 +472,14 @@ int if_is_vrf(struct interface *ifp) 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) { @@ -1140,7 +1149,7 @@ const char *if_link_type_str(enum zebra_link_type llt) 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 } diff --git a/lib/if.h b/lib/if.h index 3a9c4af848..a861cf2d85 100644 --- a/lib/if.h +++ b/lib/if.h @@ -497,6 +497,7 @@ extern int if_is_operative(struct interface *); 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 *); diff --git a/lib/log.c b/lib/log.c index e011a78f1c..b067018e08 100644 --- a/lib/log.c +++ b/lib/log.c @@ -868,11 +868,16 @@ int zlog_rotate(void) 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; @@ -903,10 +908,6 @@ static const struct zebra_desc_table command_types[] = { 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), diff --git a/lib/log.h b/lib/log.h index 980f3ddf4b..7d05b84641 100644 --- a/lib/log.h +++ b/lib/log.h @@ -87,7 +87,7 @@ extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); /* 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__) diff --git a/lib/smux.c b/lib/smux.c deleted file mode 100644 index 51abfccba3..0000000000 --- a/lib/smux.c +++ /dev/null @@ -1,1416 +0,0 @@ -/* SNMP support - * Copyright (C) 1999 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 - -#ifdef SNMP_SMUX -#include -#include - -#include "log.h" -#include "thread.h" -#include "linklist.h" -#include "command.h" -#include -#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 */ diff --git a/lib/sockopt.c b/lib/sockopt.c index 878b5ae09d..3febcb714d 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -580,31 +580,7 @@ int sockopt_tcp_rtt(int sock) 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 /* diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c index c420c25f04..41d4e2bb57 100644 --- a/lib/spf_backoff.c +++ b/lib/spf_backoff.c @@ -143,7 +143,7 @@ static int spf_backoff_holddown_elapsed(struct thread *thread) long spf_backoff_schedule(struct spf_backoff *backoff) { - long rv; + long rv = 0; struct timeval now; gettimeofday(&now, NULL); @@ -176,9 +176,6 @@ long spf_backoff_schedule(struct spf_backoff *backoff) else rv = backoff->long_delay; break; - default: - zlog_warn("SPF Back-off(%s) in unknown state", backoff->name); - rv = backoff->init_delay; } backoff_debug( diff --git a/lib/stream.c b/lib/stream.c index cf9af4d3bb..55e7f64358 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -28,9 +28,9 @@ #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 */ @@ -100,9 +100,7 @@ struct stream *stream_new(size_t size) 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; @@ -116,7 +114,6 @@ void stream_free(struct stream *s) if (!s) return; - XFREE(MTYPE_STREAM_DATA, s->data); XFREE(MTYPE_STREAM, s); } @@ -166,27 +163,33 @@ struct stream *stream_dupcat(struct stream *s1, struct stream *s2, 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) diff --git a/lib/stream.h b/lib/stream.h index e808f039c6..ef9366e1ae 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -98,14 +98,15 @@ 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. */ @@ -154,7 +155,14 @@ extern struct stream *stream_new(size_t); 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 *); diff --git a/lib/subdir.am b/lib/subdir.am index b938dbcea3..50cfd70a57 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -150,7 +150,6 @@ pkginclude_HEADERS += \ lib/sha256.h \ lib/sigevent.h \ lib/skiplist.h \ - lib/smux.h \ lib/sockopt.h \ lib/sockunion.h \ lib/spf_backoff.h \ @@ -199,7 +198,6 @@ lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0 lib_libfrrsnmp_la_LIBADD = lib/libfrr.la $(SNMP_LIBS) lib_libfrrsnmp_la_SOURCES = \ lib/agentx.c \ - lib/smux.c \ lib/snmp.c \ # end diff --git a/lib/table.h b/lib/table.h index ac7df3e695..8304abe59b 100644 --- a/lib/table.h +++ b/lib/table.h @@ -235,17 +235,13 @@ static inline struct route_node *route_lock_node(struct route_node *node) } /* 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; } /* diff --git a/lib/thread.c b/lib/thread.c index 898e9e9fce..52bc79ffe6 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -36,6 +36,7 @@ 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__) @@ -423,19 +424,11 @@ struct thread_master *thread_master_create(const char *name) /* 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, @@ -539,17 +532,23 @@ static struct thread *thread_trim_head(struct thread_list *list) 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. */ @@ -580,7 +579,7 @@ static void thread_array_free(struct thread_master *m, 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) @@ -1182,17 +1181,19 @@ void thread_cancel_event(struct thread_master *master, void *arg) */ void thread_cancel(struct thread *thread) { - assert(thread->master->owner == pthread_self()); + struct thread_master *master = thread->master; - pthread_mutex_lock(&thread->master->mtx); + assert(master->owner == pthread_self()); + + 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); } /** diff --git a/lib/vrf.c b/lib/vrf.c index 36111dfeae..ecd09a6b91 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -342,91 +342,103 @@ void *vrf_info_lookup(vrf_id_t vrf_id) } /* - * VRF bit-map + * VRF hash for storing set or not. */ - -#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 */ - -#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) - -#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)) - -struct vrf_bitmap { - uint8_t *groups[VRF_BITMAP_NUM_OF_GROUPS]; +struct vrf_bit_set { + vrf_id_t vrf_id; + bool set; }; +static unsigned int vrf_hash_bitmap_key(void *data) +{ + struct vrf_bit_set *bit = data; + + return bit->vrf_id; +} + +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; + + 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) @@ -682,10 +694,8 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, 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) @@ -887,7 +897,7 @@ int vrf_bind(vrf_id_t vrf_id, int fd, char *name) 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); diff --git a/lib/vrf.h b/lib/vrf.h index 0f4f36be50..56ba101ff0 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -237,7 +237,7 @@ extern vrf_id_t vrf_get_default_id(void); #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); diff --git a/lib/zclient.c b/lib/zclient.c index cc91705ee2..b2bafcb7d8 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -676,11 +676,11 @@ int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p, * "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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -707,21 +707,16 @@ int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p, * 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. * @@ -734,226 +729,6 @@ int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p, * * 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) { diff --git a/lib/zclient.h b/lib/zclient.h index 962b1707c9..b8ff85e80f 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -73,10 +73,6 @@ typedef enum { 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, @@ -286,7 +282,7 @@ struct zclient { */ #define ZAPI_MESSAGE_TABLEID 0x80 -#define ZSERV_VERSION 5 +#define ZSERV_VERSION 6 /* Zserv protocol message header */ struct zmsghdr { uint16_t length; @@ -353,37 +349,6 @@ struct zapi_route { 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; @@ -600,15 +565,6 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s, 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 *); @@ -635,45 +591,6 @@ extern void zebra_read_pw_status_update(int command, struct zclient *zclient, 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, diff --git a/ospfclient/ospf_apiclient.c b/ospfclient/ospf_apiclient.c index db624ae074..50485cc7e2 100644 --- a/ospfclient/ospf_apiclient.c +++ b/ospfclient/ospf_apiclient.c @@ -46,6 +46,7 @@ #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" diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index c0ce971f0c..57e0ae5ec9 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -1425,19 +1425,7 @@ struct ospf_lsa *ospf_apiserver_opaque_lsa_new(struct ospf_area *area, 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; diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 18c1077da0..8e8f655305 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -73,26 +73,6 @@ void ospf_external_route_remove(struct ospf *ospf, struct prefix_ipv4 *p) 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) diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index 370c6787b4..ac7bd68b5f 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -68,8 +68,6 @@ extern void ospf_external_info_delete(struct ospf *, uint8_t, unsigned short, 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); diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index d84fd26ac4..0221d1e1b2 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -288,6 +288,7 @@ int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa) struct prefix_ipv4 asbr, p; struct route_node *rn; struct ospf_route *new, * or ; + char buf1[INET_ADDRSTRLEN]; int ret; assert(lsa); @@ -304,10 +305,14 @@ int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *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) { @@ -459,8 +464,9 @@ int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa) 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); diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c index b8d14c351e..f6ed9b81b9 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -977,20 +977,7 @@ static struct ospf_lsa *ospf_ext_pref_lsa_new(struct ospf_area *area, 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; @@ -1056,20 +1043,7 @@ static struct ospf_lsa *ospf_ext_link_lsa_new(struct ospf_area *area, 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; diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 002c6bba8d..b4e9dda58a 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -810,8 +810,7 @@ struct ospf_lsa *ospf_ls_request_new(struct lsa_header *lsah) { 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; diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 2651cf717b..7c8a68994f 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -167,6 +167,16 @@ struct ospf_lsa *ospf_lsa_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) { @@ -406,7 +416,7 @@ static uint16_t ospf_link_cost(struct ospf_interface *oi) } /* 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) { @@ -415,11 +425,11 @@ static char link_info_set(struct stream *s, struct in_addr id, * 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: @@ -431,30 +441,31 @@ static char link_info_set(struct stream *s, struct in_addr id, * * 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; @@ -500,7 +511,7 @@ static int lsa_link_ptop_set(struct stream *s, struct ospf_interface *oi) } /* 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; @@ -546,7 +557,7 @@ static int lsa_link_broadcast_set(struct stream *s, struct ospf_interface *oi) } } -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; @@ -560,7 +571,8 @@ static int lsa_link_loopback_set(struct stream *s, struct ospf_interface *oi) } /* 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); @@ -583,7 +595,7 @@ static int lsa_link_virtuallink_set(struct stream *s, struct ospf_interface *oi) 12.4.1.4.*/ /* from "edward rrr" 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; @@ -624,7 +636,7 @@ static int lsa_link_ptomp_set(struct stream *s, struct ospf_interface *oi) } /* 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; @@ -667,28 +679,28 @@ static int router_lsa_link_set(struct stream *s, struct ospf_area *area) } /* 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) @@ -773,7 +785,7 @@ static struct ospf_lsa *ospf_router_lsa_new(struct ospf_area *area) 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); @@ -781,17 +793,13 @@ static struct ospf_lsa *ospf_router_lsa_new(struct ospf_area *area) 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); @@ -997,17 +1005,13 @@ static struct ospf_lsa *ospf_network_lsa_new(struct ospf_interface *oi) 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); @@ -1181,13 +1185,12 @@ static struct ospf_lsa *ospf_summary_lsa_new(struct ospf_area *area, 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); @@ -1323,13 +1326,12 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_new(struct ospf_area *area, 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); @@ -1629,14 +1631,13 @@ static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf, 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); diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index f8f7b28d4e..ba4c4c1cac 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -235,6 +235,7 @@ extern int ospf_check_nbr_status(struct ospf *); /* 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 *); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 6dadc05bba..8853802d07 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -49,6 +49,7 @@ #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" diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index f1d4a39dba..56b83d22d5 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1742,7 +1742,7 @@ static struct list *ospf_ls_upd_list_lsa(struct ospf_neighbor *nbr, } /* 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 @@ -1761,7 +1761,6 @@ static struct list *ospf_ls_upd_list_lsa(struct ospf_neighbor *nbr, break; } - lsa->data = ospf_lsa_data_new(length); memcpy(lsa->data, lsah, length); if (IS_DEBUG_OSPF_EVENT) diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index fa7dd04d19..c9d0a53c8d 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -775,18 +775,7 @@ static struct ospf_lsa *ospf_router_info_lsa_new() 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 */ diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index c90db031dc..19d2e6a952 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -47,6 +47,7 @@ #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. */ diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index cc2d9282fe..a9dc1c18e3 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -1201,18 +1201,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf *ospf, 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) diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 0a7776cced..8c94a8ef99 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -111,10 +111,11 @@ static int ospf_interface_add(int command, struct zclient *zclient, 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); @@ -128,6 +129,8 @@ static int ospf_interface_add(int command, struct zclient *zclient, if (!ospf) return 0; + ospf_if_recalculate_output_cost(ifp); + ospf_if_update(ospf, ifp); hook_call(ospf_if_update, ifp); @@ -448,14 +451,17 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p, 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; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index ac8f0d92c3..bfaedf2fe7 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -52,10 +52,10 @@ #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" diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 7c45ce261a..611d8d3681 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -323,8 +323,8 @@ static void pim_show_assert_winner_metric_helper(struct vty *vty, 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; diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index e79e91d7df..72ccf3ab1e 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1495,14 +1495,6 @@ int pim_if_connected_to_source(struct interface *ifp, struct in_addr src) 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)) diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index cf025cbd4a..02926a6973 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -207,8 +207,6 @@ void pim_if_create_pimreg(struct pim_instance *pim); 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); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 92a78c4bb4..3137345037 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -174,7 +174,16 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) 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); diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index f0f336fb73..a0debc0c78 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -37,19 +37,20 @@ 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); } } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index b103da2e1b..7113d5405e 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -655,7 +655,7 @@ static int pim_hello_send(struct interface *ifp, uint16_t holdtime) { 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)) { @@ -757,7 +757,7 @@ void pim_hello_restart_triggered(struct interface *ifp) /* * 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; /* diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index db89125a98..15cbf6fbc3 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -167,6 +167,8 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, up->ref_count, up->flags, up->channel_oil->oil_ref_count); + assert(up->ref_count > 0); + --up->ref_count; if (up->ref_count >= 1) diff --git a/snapcraft/README.usage.md b/snapcraft/README.usage.md index 50711b13b7..a7b51a5656 100644 --- a/snapcraft/README.usage.md +++ b/snapcraft/README.usage.md @@ -31,7 +31,7 @@ Commands defined by this snap - `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 @@ -100,13 +100,13 @@ are named `eth0`, `eth1` and `eth2`, then the additional lines in 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` @@ -114,6 +114,17 @@ or `frr.set fpm netlink` command. The command will only enable the mode 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? diff --git a/snapcraft/scripts/bgpd-service b/snapcraft/scripts/bgpd-service index 4072031eda..6c3a6f5959 100644 --- a/snapcraft/scripts/bgpd-service +++ b/snapcraft/scripts/bgpd-service @@ -5,9 +5,16 @@ set -e -x 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 diff --git a/snapcraft/scripts/set-options b/snapcraft/scripts/set-options index e76e321ef8..0637d2ce5d 100755 --- a/snapcraft/scripts/set-options +++ b/snapcraft/scripts/set-options @@ -28,11 +28,34 @@ case $1 in ;; 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 diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index 563a05c5a7..b70d6efee2 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -136,7 +136,7 @@ apps: - 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 @@ -221,8 +221,27 @@ apps: - 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 @@ -247,6 +266,7 @@ parts: - flex - python3-dev - protobuf-c-compiler + - python3-sphinx stage-packages: - coreutils - iproute2 @@ -276,6 +296,7 @@ parts: - --enable-ldpd - --enable-fpm - --enable-protobuf + - --enable-rpki - --enable-configfile-mask=0640 - --enable-logfile-mask=0640 - --localstatedir=/var/run diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 98153f7149..771d8d1de3 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -766,7 +766,7 @@ DEFPY(ip_route_blackhole, "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; @@ -805,7 +805,7 @@ DEFPY(ip_route_blackhole_vrf, 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; @@ -868,7 +868,7 @@ DEFPY(ip_route_address_interface, 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; @@ -924,7 +924,7 @@ DEFPY(ip_route_address_interface_vrf, 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; @@ -984,7 +984,7 @@ DEFPY(ip_route, 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; @@ -1049,7 +1049,7 @@ DEFPY(ip_route_vrf, 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; @@ -1104,7 +1104,7 @@ DEFPY(ipv6_route_blackhole, "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; @@ -1144,7 +1144,7 @@ DEFPY(ipv6_route_blackhole_vrf, 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; @@ -1195,7 +1195,7 @@ DEFPY(ipv6_route_address_interface, 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; @@ -1255,7 +1255,7 @@ DEFPY(ipv6_route_address_interface_vrf, 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; @@ -1309,7 +1309,7 @@ DEFPY(ipv6_route, 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; @@ -1368,7 +1368,7 @@ DEFPY(ipv6_route_vrf, 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; diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index f3175e91fa..a87dc074df 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -34,6 +34,7 @@ #include "log.h" #include "nexthop.h" #include "nexthop_group.h" +#include "hash.h" #include "static_vrf.h" #include "static_routes.h" @@ -43,6 +44,7 @@ /* 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) { @@ -176,10 +178,16 @@ static void zebra_connected(struct zclient *zclient) 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; @@ -191,6 +199,14 @@ static int static_zebra_nexthop_update(int command, struct zclient *zclient, 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; } @@ -200,10 +216,50 @@ static void static_zebra_capabilities(struct zclient_capabilities *cap) 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; @@ -224,20 +280,48 @@ void static_zebra_nht_register(struct static_route *si, bool reg) 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, @@ -273,9 +357,10 @@ 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) @@ -372,4 +457,8 @@ void static_zebra_init(void) 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"); } diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 4612bdc26b..fef7d39ff5 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -821,7 +821,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type) 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*/ diff --git a/tests/lib/test_stream.c b/tests/lib/test_stream.c index 5dc751a1b2..2ecfc87942 100644 --- a/tests/lib/test_stream.c +++ b/tests/lib/test_stream.c @@ -57,7 +57,7 @@ int main(void) print_stream(s); - stream_resize(s, stream_get_endp(s)); + stream_resize_inplace(&s, stream_get_endp(s)); print_stream(s); diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index ef4d1a0835..c249115fd3 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1435,24 +1435,6 @@ DEFUNSH(VTYSH_BGPD, 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, @@ -1790,6 +1772,7 @@ static int vtysh_exit(struct vty *vty) case VTY_NODE: case KEYCHAIN_NODE: case BFD_NODE: + case RPKI_NODE: vtysh_execute("end"); vtysh_execute("configure terminal"); vty->node = CONFIG_NODE; @@ -1883,8 +1866,24 @@ DEFUNSH(VTYSH_BGPD, exit_vnc_config, exit_vnc_config_cmd, "exit-vnc", || 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") { diff --git a/zebra/GNOME-PRODUCT-ZEBRA-MIB b/zebra/GNOME-PRODUCT-ZEBRA-MIB deleted file mode 100644 index 96bcec5763..0000000000 --- a/zebra/GNOME-PRODUCT-ZEBRA-MIB +++ /dev/null @@ -1,78 +0,0 @@ -GNOME-PRODUCT-ZEBRA-MIB DEFINITIONS ::= BEGIN - -IMPORTS - MODULE-IDENTITY, - OBJECT-IDENTITY - FROM SNMPv2-SMI - gnomeProducts - FROM GNOME-SMI; - -zebra MODULE-IDENTITY - LAST-UPDATED "200004250000Z" - ORGANIZATION "GNOME project" - CONTACT-INFO - "GNU Network Object Model Environment project - - see http://www.gnome.org for contact persons of a particular - area or subproject of GNOME. - - Administrative contact for MIB module: - - Jochen Friedrich - Wingertstr. 70/1 - 68809 Neulussheim - Germany - - email: snmp@gnome.org" - DESCRIPTION - "The product registrations for the various zebra subdeamons. - These registrations are guaranteed to be unique and are used - for SMUX registration by default (if not overridden manually)." - ::= { gnomeProducts 2 } - -zserv OBJECT-IDENTITY - STATUS current - DESCRIPTION - "zserv is part of the zebra project which again is a GNU - endorsed internet routing program. - zserv is the main zebra process which implements routing - entries with the kernel and handles routing updates between - other routing protocols." - ::= { zebra 1 } - -bgpd OBJECT-IDENTITY - STATUS current - DESCRIPTION - "bgpd is part of the zebra project which again is a GNU - endorsed internet routing program." - ::= { zebra 2 } - -ripd OBJECT-IDENTITY - STATUS current - DESCRIPTION - "ripd is part of the zebra project which again is a GNU - endorsed internet routing program." - ::= { zebra 3 } - -ripngd OBJECT-IDENTITY - STATUS current - DESCRIPTION - "ripngd is part of the zebra project which again is a GNU - endorsed internet routing program." - ::= { zebra 4 } - -ospfd OBJECT-IDENTITY - STATUS current - DESCRIPTION - "ospfd is part of the zebra project which again is a GNU - endorsed internet routing program." - ::= { zebra 5 } - -ospf6d OBJECT-IDENTITY - STATUS current - DESCRIPTION - "ospf6d is part of the zebra project which again is a GNU - endorsed internet routing program." - ::= { zebra 6 } - -END diff --git a/zebra/GNOME-SMI b/zebra/GNOME-SMI deleted file mode 100644 index 164732bb40..0000000000 --- a/zebra/GNOME-SMI +++ /dev/null @@ -1,53 +0,0 @@ -GNOME-SMI DEFINITIONS ::= BEGIN - -IMPORTS - MODULE-IDENTITY, - OBJECT-IDENTITY, - enterprises - FROM SNMPv2-SMI; - -gnome MODULE-IDENTITY - LAST-UPDATED "9809010000Z" - ORGANIZATION "GNOME project" - CONTACT-INFO - "GNU Network Object Model Environment project - - see http://www.gnome.org for contact persons of a particular - area or subproject of GNOME. - - Administrative contact for MIB module: - - Jochen Friedrich - Wingertstr. 70/1 - 68809 Neulussheim - Germany - - email: snmp@gnome.org" - DESCRIPTION - "The Structure of GNOME." - ::= { enterprises 3317 } -- assigned by IANA - -gnomeProducts OBJECT-IDENTITY - STATUS current - DESCRIPTION - "gnomeProducts is the root OBJECT IDENTIFIER from - which sysObjectID values are assigned." - ::= { gnome 1 } - -gnomeMgmt OBJECT-IDENTITY - STATUS current - DESCRIPTION - "gnomeMgmt defines the subtree for production GNOME related - MIB registrations." - ::= { gnome 2 } - -gnomeTest OBJECT-IDENTITY - STATUS current - DESCRIPTION - "gnomeTest defines the subtree for testing GNOME related - MIB registrations." - ::= { gnome 3 } - --- more to come if necessary. - -END diff --git a/zebra/client_main.c b/zebra/client_main.c deleted file mode 100644 index 1ead7ee1fd..0000000000 --- a/zebra/client_main.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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 - -#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; -} diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index d17a9cf498..176bb2bbad 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -37,6 +37,7 @@ #include "zebra/interface.h" #include "zebra/rib.h" +#include "zebra/rt.h" #include diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index ef7c26c9df..545b4d9d6d 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -467,6 +467,18 @@ void netlink_parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta, } } +/** + * 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) { diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 65df15599d..af0cc83f4a 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -28,6 +28,8 @@ 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, diff --git a/zebra/redistribute.c b/zebra/redistribute.c index e3101fbe72..640d58e17e 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -715,7 +715,7 @@ int zebra_import_table_config(struct vty *vty) return write; } -void zebra_import_table_rm_update() +void zebra_import_table_rm_update(const char *rmap) { afi_t afi; int i; @@ -730,9 +730,8 @@ void zebra_import_table_rm_update() 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)) { diff --git a/zebra/redistribute.h b/zebra/redistribute.h index a0fbd13cf9..f67480da9c 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -71,6 +71,5 @@ extern int is_zebra_import_table_enabled(afi_t, uint32_t table_id); 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 */ diff --git a/zebra/rib.h b/zebra/rib.h index a37b2bf221..f821c6edb4 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -325,6 +325,8 @@ extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, 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); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 6a258e6853..cab3f43b19 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -246,6 +246,33 @@ static vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id) 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) @@ -274,6 +301,10 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, 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) @@ -508,6 +539,17 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, } 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 { @@ -532,6 +574,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, re->tag = tag; for (;;) { + struct nexthop *nh = NULL; vrf_id_t nh_vrf_id; if (len < (int)sizeof(*rtnh) || rtnh->rtnh_len > len) @@ -569,35 +612,46 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, 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; diff --git a/zebra/subdir.am b/zebra/subdir.am index f44574b236..5dc3750315 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -141,13 +141,3 @@ if DEV_BUILD 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 diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 008fc8f066..d95f78109c 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1022,6 +1022,7 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) unsigned short l = 0; uint8_t flags = 0; uint16_t type = cmd2type[hdr->command]; + bool exist; if (IS_ZEBRA_DEBUG_NHT) zlog_debug( @@ -1064,7 +1065,10 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) 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)) @@ -1084,7 +1088,9 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) 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: @@ -1584,202 +1590,6 @@ static void zread_route_del(ZAPI_HANDLER_ARGS) } } -/* 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) { @@ -1794,417 +1604,6 @@ stream_failure: 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) { @@ -3011,11 +2410,6 @@ void (*zserv_handlers[])(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, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b477cd4706..ab07549ec2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1501,17 +1501,37 @@ static struct route_entry *rib_choose_best(struct route_entry *current, /* 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; @@ -2651,8 +2671,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, } /* 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; @@ -2732,12 +2751,18 @@ void rib_update(vrf_id_t vrf_id, rib_update_event_t event) /* 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. */ diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 156600c105..0b585af6a0 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -103,7 +103,8 @@ char *rnh_str(struct rnh *rnh, char *buf, int size) 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; @@ -119,6 +120,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type) prefix2str(p, buf, sizeof(buf)); zlog_warn("%u: Add RNH %s type %d - table not found", vrfid, buf, type); + exists = false; return NULL; } @@ -136,7 +138,9 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type) route_lock_node(rn); rn->info = rnh; rnh->node = rn; - } + *exists = false; + } else + *exists = true; route_unlock_node(rn); return (rn->info); @@ -190,6 +194,14 @@ void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type) 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) { @@ -201,8 +213,7 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, } 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); } } @@ -247,9 +258,10 @@ void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) { 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; diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 9e09a1bc6f..f4b4b56390 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -68,7 +68,7 @@ static inline int rnh_resolve_via_default(int family) } 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); diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index fc17ee3491..7a6bc6684d 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -1033,13 +1033,13 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = { /* `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; @@ -1050,21 +1050,41 @@ route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, 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' */ @@ -1281,11 +1301,101 @@ static struct route_map_rule_cmd route_set_src_cmd = { "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) @@ -1307,11 +1417,6 @@ static int zebra_route_map_update_timer(struct thread *thread) * 1) VRF Aware * 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); } @@ -1555,12 +1660,19 @@ void zebra_route_map_init() 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); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 79c2bb03e6..9dfbfe6ce2 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1555,7 +1555,9 @@ static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n) 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)) @@ -1966,6 +1968,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, 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); @@ -2018,44 +2021,54 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, /* 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); + } + + /* 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); } - /* 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); - - /* Link to new MAC */ - listnode_add_sort(zmac->neigh_list, n); - } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { /* * Neighbor has moved from remote to local. Its @@ -2086,6 +2099,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, n->r_vtep_ip.s_addr = 0; SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); n->ifindex = ifp->ifindex; + check_rbit = true; } } @@ -2102,6 +2116,12 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, 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. */ @@ -2112,9 +2132,9 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, 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 @@ -3399,7 +3419,9 @@ static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) */ 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)) @@ -4023,6 +4045,7 @@ static void process_remote_macip_add(vni_t vni, 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); @@ -4062,6 +4085,7 @@ static void process_remote_macip_add(vni_t 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); @@ -4180,6 +4204,8 @@ static void process_remote_macip_add(vni_t vni, || !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; @@ -4258,6 +4284,8 @@ static void process_remote_macip_add(vni_t vni, /* 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); @@ -5384,10 +5412,11 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, 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? */ @@ -5520,7 +5549,6 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) flags, seq, inet_ntoa(vtep_ip), zebra_route_string(client->proto)); - process_remote_macip_add(vni, &macaddr, ipa_len, &ip, flags, seq, vtep_ip); }