diff options
168 files changed, 6139 insertions, 3772 deletions
diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 9fa32ee6fa..4419160cd7 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -292,7 +292,7 @@ DEFUN (babel_network, if (ret < 0) { vty_out (vty, "There is same network configuration %s\n", argv[1]->arg); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } return CMD_SUCCESS; @@ -1321,7 +1321,7 @@ interface_config_write (struct vty *vty) int write = 0; for (ALL_LIST_ELEMENTS_RO (vrf_iflist(VRF_DEFAULT), node, ifp)) { - vty_out (vty, "interface %s\n",ifp->name); + vty_frame (vty, "interface %s\n",ifp->name); if (ifp->desc) vty_out (vty, " description %s\n",ifp->desc); babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); @@ -1377,7 +1377,7 @@ interface_config_write (struct vty *vty) write++; } } - vty_out (vty, "!\n"); + vty_endframe (vty, "!\n"); write++; } return write; diff --git a/babeld/kernel.c b/babeld/kernel.c index 394d7b1e81..3343ca2e95 100644 --- a/babeld/kernel.c +++ b/babeld/kernel.c @@ -169,7 +169,7 @@ zebra_route(int add, int family, const unsigned char *pref, unsigned short plen, api.prefix = quagga_prefix; if(metric >= KERNEL_INFINITY) { - api.flags = ZEBRA_FLAG_REJECT; + zapi_route_set_blackhole(&api, BLACKHOLE_REJECT); } else { SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b03b408f7d..e15a7618b8 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -848,10 +848,24 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, u_char origin, attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); if (community) { + u_int32_t gshut = COMMUNITY_GSHUT; + + /* If we are not shutting down ourselves and we are + * aggregating a route that contains the GSHUT community we + * need to remove that community when creating the aggregate */ + if (!bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN) && + community_include(community, gshut)) { + community_del_val(community, &gshut); + } + attr.community = community; attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); } + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { + bgp_attr_add_gshut_community(&attr); + } + attr.label_index = BGP_INVALID_LABEL_INDEX; attr.label = MPLS_INVALID_LABEL; attr.weight = BGP_ATTR_DEFAULT_WEIGHT; @@ -1400,7 +1414,7 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args) attr->local_pref = stream_getl(peer->ibuf); - /* Set atomic aggregate flag. */ + /* Set the local-pref flag. */ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); return BGP_ATTR_PARSE_PROCEED; @@ -3058,20 +3072,20 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) { - if (attr->lcommunity->size * 12 > 255) { + if (lcom_length(attr->lcommunity) > 255) { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putw(s, attr->lcommunity->size * 12); + stream_putw(s, lcom_length(attr->lcommunity)); } else { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putc(s, attr->lcommunity->size * 12); + stream_putc(s, lcom_length(attr->lcommunity)); } stream_put(s, attr->lcommunity->val, - attr->lcommunity->size * 12); + lcom_length(attr->lcommunity)); } /* Route Reflector. */ @@ -3422,21 +3436,20 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr, /* Large Community attribute. */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { - if (attr->lcommunity->size * 12 > 255) { + if (lcom_length(attr->lcommunity) > 255) { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putw(s, attr->lcommunity->size * 12); + stream_putw(s, lcom_length(attr->lcommunity)); } else { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putc(s, attr->lcommunity->size * 12); + stream_putc(s, lcom_length(attr->lcommunity)); } - stream_put(s, attr->lcommunity->val, - attr->lcommunity->size * 12); + stream_put(s, attr->lcommunity->val, lcom_length(attr->lcommunity)); } /* Add a MP_NLRI attribute to dump the IPv6 next hop */ diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 13587b3599..b62a0a540c 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -355,6 +355,9 @@ static char *community_str_get(struct community *com, int i) case COMMUNITY_LOCAL_AS: len = strlen(" local-AS"); break; + case COMMUNITY_GSHUT: + len = strlen(" graceful-shutdown"); + break; default: len = strlen(" 65536:65535"); break; @@ -380,6 +383,10 @@ static char *community_str_get(struct community *com, int i) strcpy(pnt, "local-AS"); pnt += strlen("local-AS"); break; + case COMMUNITY_GSHUT: + strcpy(pnt, "graceful-shutdown"); + pnt += strlen("graceful-shutdown"); + break; default: as = (comval >> 16) & 0xFFFF; val = comval & 0xFFFF; @@ -450,8 +457,7 @@ static char *lcommunity_str_get(struct lcommunity *lcom, int i) u_char *ptr; char *pnt; - ptr = lcom->val; - ptr += (i * LCOMMUNITY_SIZE); + ptr = lcom->val + (i * LCOMMUNITY_SIZE); memcpy(&lcomval, ptr, LCOMMUNITY_SIZE); @@ -704,8 +710,7 @@ struct community *community_list_match_delete(struct community *com, /* Loop over each community value and evaluate each against the * community-list. If we need to delete a community value add its index - * to - * com_index_to_delete. + * to com_index_to_delete. */ for (i = 0; i < com->size; i++) { val = community_val_get(com, i); @@ -906,12 +911,10 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom, /* Loop over each lcommunity value and evaluate each against the * community-list. If we need to delete a community value add its index - * to - * com_index_to_delete. + * to com_index_to_delete. */ - ptr = lcom->val; for (i = 0; i < lcom->size; i++) { - ptr += (i * LCOMMUNITY_SIZE); + ptr = lcom->val + (i * LCOMMUNITY_SIZE); for (entry = list->head; entry; entry = entry->next) { if (entry->any) { if (entry->direct == COMMUNITY_PERMIT) { @@ -930,7 +933,7 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom, break; } - else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) + else if ((entry->style == LARGE_COMMUNITY_LIST_EXPANDED) && lcommunity_regexp_include(entry->reg, lcom, i)) { if (entry->direct == COMMUNITY_PERMIT) { @@ -943,9 +946,8 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom, } /* Delete all of the communities we flagged for deletion */ - ptr = lcom->val; for (i = delete_index - 1; i >= 0; i--) { - ptr += (com_index_to_delete[i] * LCOMMUNITY_SIZE); + ptr = lcom->val + (com_index_to_delete[i] * LCOMMUNITY_SIZE); lcommunity_del_val(lcom, ptr); } diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 389d723e04..7e8411b6a0 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -191,6 +191,7 @@ struct community *community_uniq_sort(struct community *com) 0xFFFFFF01 "no-export" 0xFFFFFF02 "no-advertise" 0xFFFFFF03 "local-AS" + 0xFFFF0000 "graceful-shutdown" For other values, "AS:VAL" format is used. */ static void set_community_string(struct community *com) @@ -244,6 +245,9 @@ static void set_community_string(struct community *com) case COMMUNITY_LOCAL_AS: len += strlen(" local-AS"); break; + case COMMUNITY_GSHUT: + len += strlen(" graceful-shutdown"); + break; default: len += strlen(" 65536:65535"); break; @@ -289,6 +293,12 @@ static void set_community_string(struct community *com) json_string = json_object_new_string("localAs"); json_object_array_add(json_community_list, json_string); break; + case COMMUNITY_GSHUT: + strcpy(pnt, "graceful-shutdown"); + pnt += strlen("graceful-shutdown"); + json_string = json_object_new_string("gracefulShutdown"); + json_object_array_add(json_community_list, json_string); + break; default: as = (comval >> 16) & 0xFFFF; val = comval & 0xFFFF; @@ -480,6 +490,7 @@ enum community_token { community_token_no_export, community_token_no_advertise, community_token_local_as, + community_token_gshut, community_token_unknown }; @@ -523,6 +534,12 @@ community_gettoken(const char *buf, enum community_token *token, u_int32_t *val) p += strlen("local-AS"); return p; } + if (strncmp(p, "graceful-shutdown", strlen("graceful-shutdown")) == 0) { + *val = COMMUNITY_GSHUT; + *token = community_token_gshut; + p += strlen("graceful-shutdown"); + return p; + } /* Unknown string. */ *token = community_token_unknown; @@ -595,6 +612,7 @@ struct community *community_str2com(const char *str) case community_token_no_export: case community_token_no_advertise: case community_token_local_as: + case community_token_gshut: if (com == NULL) { com = community_new(); com->json = NULL; diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index c59eebf2e9..f728debdb5 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -48,6 +48,7 @@ struct community { #define COMMUNITY_NO_ADVERTISE 0xFFFFFF02 #define COMMUNITY_NO_EXPORT_SUBCONFED 0xFFFFFF03 #define COMMUNITY_LOCAL_AS 0xFFFFFF03 +#define COMMUNITY_GSHUT 0xFFFF0000 /* Macros of community attribute. */ #define com_length(X) ((X)->size * 4) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 0560dc46f9..8c3a1b337b 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -45,6 +45,8 @@ #include "bgpd/bgp_encap_types.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_nexthop.h" /* * Definitions and external declarations. @@ -1199,6 +1201,13 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn, return 0; } + /* Update the tunnel-ip hash */ + bgp_tip_del(bgp, &vpn->originator_ip); + bgp_tip_add(bgp, &originator_ip); + + /* filter routes as martian nexthop db has changed */ + bgp_filter_evpn_routes_upon_martian_nh_change(bgp); + /* Need to withdraw type-3 route as the originator IP is part * of the key. */ @@ -2042,7 +2051,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */ stream_putc(s, 8 + 10 + 4 + 1 + len + 3); stream_put(s, prd->val, 8); - if (attr && attr) + if (attr) stream_put(s, &(attr->evpn_overlay.eth_s_id), 10); else stream_put(s, &temp, 10); @@ -2052,7 +2061,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr); else stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16); - if (attr && attr) { + if (attr) { if (IS_IPADDR_V4(&p_evpn_p->ip)) stream_put_ipv4(s, attr->evpn_overlay.gw_ip.ipv4.s_addr); @@ -2179,6 +2188,71 @@ char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len) } /* + * Function to convert evpn route to json format. + * NOTE: We don't use prefix2str as the output here is a bit different. + */ +void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json) +{ + char buf1[ETHER_ADDR_STRLEN]; + char buf2[PREFIX2STR_BUFFER]; + + if (!json) + return; + + if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) { + json_object_int_add(json, "routeType", p->prefix.route_type); + json_object_int_add(json, "ethTag", 0); + json_object_int_add(json, "ipLen", + IS_EVPN_PREFIX_IPADDR_V4(p) + ? IPV4_MAX_BITLEN + : IPV6_MAX_BITLEN); + json_object_string_add(json, "ip", + inet_ntoa(p->prefix.ip.ipaddr_v4)); + } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + if (IS_EVPN_PREFIX_IPADDR_NONE(p)) { + json_object_int_add(json, "routeType", + p->prefix.route_type); + json_object_int_add( + json, "esi", + 0); /* TODO: we don't support esi yet */ + json_object_int_add(json, "ethTag", 0); + json_object_int_add(json, "macLen", 8 * ETH_ALEN); + json_object_string_add(json, "mac", + prefix_mac2str(&p->prefix.mac, + buf1, + sizeof(buf1))); + } else { + u_char family; + + family = IS_EVPN_PREFIX_IPADDR_V4(p) ? AF_INET + : AF_INET6; + + json_object_int_add(json, "routeType", + p->prefix.route_type); + json_object_int_add( + json, "esi", + 0); /* TODO: we don't support esi yet */ + json_object_int_add(json, "ethTag", 0); + json_object_int_add(json, "macLen", 8 * ETH_ALEN); + json_object_string_add(json, "mac", + prefix_mac2str(&p->prefix.mac, + buf1, + sizeof(buf1))); + json_object_int_add(json, "ipLen", + IS_EVPN_PREFIX_IPADDR_V4(p) + ? IPV4_MAX_BITLEN + : IPV6_MAX_BITLEN); + json_object_string_add( + json, "ip", + inet_ntop(family, &p->prefix.ip.ip.addr, buf2, + PREFIX2STR_BUFFER)); + } + } else { + /* Currently, this is to cater to other AF_ETHERNET code. */ + } +} + +/* * Function to convert evpn route to string. * NOTE: We don't use prefix2str as the output here is a bit different. */ @@ -2562,6 +2636,71 @@ int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi, return install_uninstall_evpn_route(bgp, afi, safi, p, ri, 0); } +/* filter routes which have martian next hops */ +int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp) +{ + afi_t afi; + safi_t safi; + struct bgp_node *rd_rn, *rn; + struct bgp_table *table; + struct bgp_info *ri; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + + /* Walk entire global routing table and evaluate routes which could be + * imported into this VPN. Note that we cannot just look at the routes + * for the VNI's RD - + * remote routes applicable for this VNI could have any RD. + */ + /* EVPN routes are a 2-level table. */ + for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn; + rd_rn = bgp_route_next(rd_rn)) { + table = (struct bgp_table *)(rd_rn->info); + if (!table) + continue; + + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + + for (ri = rn->info; ri; ri = ri->next) { + + /* Consider "valid" remote routes applicable for + * this VNI. */ + if (!(ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_NORMAL)) + continue; + + if (bgp_nexthop_self(bgp, ri->attr->nexthop)) { + + char attr_str[BUFSIZ]; + char pbuf[PREFIX_STRLEN]; + + bgp_dump_attr(ri->attr, attr_str, + BUFSIZ); + + if (bgp_debug_update(ri->peer, &rn->p, + NULL, 1)) + zlog_debug( + "%u: prefix %s with attr %s - DENIED due to martian or self nexthop", + bgp->vrf_id, + prefix2str( + &rn->p, pbuf, + sizeof(pbuf)), + attr_str); + + bgp_evpn_unimport_route(bgp, afi, safi, + &rn->p, ri); + + bgp_rib_remove(rn, ri, ri->peer, afi, + safi); + } + } + } + } + + return 0; +} + /* * Handle del of a local MACIP. */ @@ -2657,6 +2796,11 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni) */ delete_routes_for_vni(bgp, vpn); + /* + * tunnel is no longer active, del tunnel ip address from tip_hash + */ + bgp_tip_del(bgp, &vpn->originator_ip); + /* Clear "live" flag and see if hash needs to be freed. */ UNSET_FLAG(vpn->flags, VNI_FLAG_LIVE); if (!is_vni_configured(vpn)) @@ -2704,13 +2848,19 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, } } - /* if the VNI is live already, there is nothibng more to do */ + /* if the VNI is live already, there is nothing more to do */ if (is_vni_live(vpn)) return 0; /* Mark as "live" */ SET_FLAG(vpn->flags, VNI_FLAG_LIVE); + /* tunnel is now active, add tunnel-ip to db */ + bgp_tip_add(bgp, &originator_ip); + + /* filter routes as nexthop database has changed */ + bgp_filter_evpn_routes_upon_martian_nh_change(bgp); + /* Create EVPN type-3 route and schedule for processing. */ build_evpn_type3_prefix(&p, vpn->originator_ip); if (update_evpn_route(bgp, vpn, &p, 0)) { @@ -2725,6 +2875,10 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, */ install_routes_for_vni(bgp, vpn); + /* If we are advertising gateway mac-ip + It needs to be conveyed again to zebra */ + bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip, vpn->vni); + return 0; } diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index e9b7857212..985f41f586 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -28,6 +28,7 @@ extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw); extern char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len); extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len); +extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json); extern void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, struct prefix_rd *prd, mpls_label_t *label, struct attr *attr, int addpath_encode, @@ -38,6 +39,7 @@ extern int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, struct bgp_info *ri); extern int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, struct bgp_info *ri); +extern int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp); extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac, struct ipaddr *ip); extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 9dc459cd4e..a58f73f4bc 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -28,6 +28,8 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" +#define RT_ADDRSTRLEN 28 + /* EVPN prefix lengths. */ #define EVPN_TYPE_2_ROUTE_PREFIXLEN 224 #define EVPN_TYPE_3_ROUTE_PREFIXLEN 224 diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 948c7f50f2..2410f30ddf 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -38,6 +38,7 @@ #define SHOW_DISPLAY_STANDARD 0 #define SHOW_DISPLAY_TAGS 1 #define SHOW_DISPLAY_OVERLAY 2 +#define VNI_STR_LEN 32 /* * Context for VNI hash walk - used by callbacks. @@ -46,15 +47,12 @@ struct vni_walk_ctx { struct bgp *bgp; struct vty *vty; struct in_addr vtep_ip; -}; - -struct evpn_config_write { - int write; - struct vty *vty; + json_object *json; }; #if defined(HAVE_CUMULUS) -static void display_import_rt(struct vty *vty, struct irt_node *irt) +static void display_import_rt(struct vty *vty, struct irt_node *irt, + json_object *json) { u_char *pnt; u_char type, sub_type; @@ -68,7 +66,14 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt) } eip; struct listnode *node, *nnode; struct bgpevpn *tmp_vpn; + json_object *json_rt = NULL; + json_object *json_vnis = NULL; + char rt_buf[RT_ADDRSTRLEN]; + if (json) { + json_rt = json_object_new_object(); + json_vnis = json_object_new_array(); + } /* TODO: This needs to go into a function */ @@ -88,7 +93,13 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt) eas.val |= (*pnt++ << 8); eas.val |= (*pnt++); - vty_out(vty, "Route-target: %u:%u", eas.as, eas.val); + snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val); + + if (json) + json_object_string_add(json_rt, "rt", rt_buf); + else + vty_out(vty, "Route-target: %s", rt_buf); + break; case ECOMMUNITY_ENCODE_IP: @@ -97,7 +108,14 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt) eip.val = (*pnt++ << 8); eip.val |= (*pnt++); - vty_out(vty, "Route-target: %s:%u", inet_ntoa(eip.ip), eip.val); + snprintf(rt_buf, RT_ADDRSTRLEN, "%s:%u", inet_ntoa(eip.ip), + eip.val); + + if (json) + json_object_string_add(json_rt, "rt", rt_buf); + else + vty_out(vty, "Route-target: %s", rt_buf); + break; case ECOMMUNITY_ENCODE_AS4: @@ -109,65 +127,102 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt) eas.val = (*pnt++ << 8); eas.val |= (*pnt++); - vty_out(vty, "Route-target: %u:%u", eas.as, eas.val); + snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val); + + if (json) + json_object_string_add(json_rt, "rt", rt_buf); + else + vty_out(vty, "Route-target: %s", rt_buf); + break; default: return; } - vty_out(vty, "\n"); - vty_out(vty, "List of VNIs importing routes with this route-target:\n"); + if (!json) { + vty_out(vty, + "\nList of VNIs importing routes with this route-target:\n"); + } + + for (ALL_LIST_ELEMENTS(irt->vnis, node, nnode, tmp_vpn)) { + if (json) + json_object_array_add( + json_vnis, json_object_new_int64(tmp_vpn->vni)); + else + vty_out(vty, " %u\n", tmp_vpn->vni); + } - for (ALL_LIST_ELEMENTS(irt->vnis, node, nnode, tmp_vpn)) - vty_out(vty, " %u\n", tmp_vpn->vni); + if (json) { + json_object_object_add(json_rt, "vnis", json_vnis); + json_object_object_add(json, rt_buf, json_rt); + } } -static void show_import_rt_entry(struct hash_backet *backet, struct vty *vty) +static void show_import_rt_entry(struct hash_backet *backet, void *args[]) { + json_object *json = NULL; + struct vty *vty = NULL; struct irt_node *irt = (struct irt_node *)backet->data; - display_import_rt(vty, irt); + + vty = args[0]; + json = args[1]; + + display_import_rt(vty, irt, json); + + return; } static void bgp_evpn_show_route_rd_header(struct vty *vty, - struct bgp_node *rd_rn) + struct bgp_node *rd_rn, + json_object *json) { u_int16_t type; struct rd_as rd_as; struct rd_ip rd_ip; u_char *pnt; + char rd_str[RD_ADDRSTRLEN]; pnt = rd_rn->p.u.val; /* Decode RD type. */ type = decode_rd_type(pnt); + if (json) + return; + vty_out(vty, "Route Distinguisher: "); switch (type) { case RD_TYPE_AS: decode_rd_as(pnt + 2, &rd_as); - vty_out(vty, "%u:%d", rd_as.as, rd_as.val); + snprintf(rd_str, RD_ADDRSTRLEN, "%u:%d", rd_as.as, rd_as.val); break; case RD_TYPE_IP: decode_rd_ip(pnt + 2, &rd_ip); - vty_out(vty, "%s:%d", inet_ntoa(rd_ip.ip), rd_ip.val); + snprintf(rd_str, RD_ADDRSTRLEN, "%s:%d", inet_ntoa(rd_ip.ip), + rd_ip.val); break; default: - vty_out(vty, "Unknown RD type"); + snprintf(rd_str, RD_ADDRSTRLEN, "Unknown RD type"); break; } - vty_out(vty, "\n"); + vty_out(vty, "%s\n", rd_str); } -static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp) +static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp, + json_object *json) { char ri_header[] = " Network Next Hop Metric LocPrf Weight Path\n"; + if (json) + return; + + vty_out(vty, "BGP table version is 0, local router ID is %s\n", inet_ntoa(bgp->router_id)); vty_out(vty, @@ -180,43 +235,83 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp) vty_out(vty, "%s", ri_header); } -static void display_vni(struct vty *vty, struct bgpevpn *vpn) +static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) { char buf1[INET6_ADDRSTRLEN]; char *ecom_str; struct listnode *node, *nnode; struct ecommunity *ecom; + json_object *json_import_rtl; + json_object *json_export_rtl; + + if (json) { + json_import_rtl = json_object_new_array(); + json_export_rtl = json_object_new_array(); + json_object_int_add(json, "vni", vpn->vni); + json_object_string_add(json, "kernelFlag", + is_vni_live(vpn) ? "Yes" : "No"); + json_object_string_add( + json, "rd", + prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN)); + json_object_string_add(json, "originatorIp", + inet_ntoa(vpn->originator_ip)); + json_object_string_add(json, "advertiseGatewayMacip", + vpn->advertise_gw_macip ? "Yes" : "No"); + } else { + vty_out(vty, "VNI: %d", vpn->vni); + if (is_vni_live(vpn)) + vty_out(vty, " (known to the kernel)"); + vty_out(vty, "\n"); - vty_out(vty, "VNI: %d", vpn->vni); - if (is_vni_live(vpn)) - vty_out(vty, " (known to the kernel)"); - vty_out(vty, "\n"); + vty_out(vty, " RD: %s\n", + prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN)); + vty_out(vty, " Originator IP: %s\n", + inet_ntoa(vpn->originator_ip)); + vty_out(vty, " Advertise-gw-macip : %s\n", + vpn->advertise_gw_macip ? "Yes" : "No"); + } - vty_out(vty, " RD: %s\n", - prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN)); - vty_out(vty, " Originator IP: %s\n", inet_ntoa(vpn->originator_ip)); - vty_out(vty, " Advertise-gw-macip : %s\n", - vpn->advertise_gw_macip ? "Yes" : "No"); + if (!json) + vty_out(vty, " Import Route Target:\n"); - vty_out(vty, " Import Route Target:\n"); for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) { ecom_str = ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - vty_out(vty, " %s\n", ecom_str); + + if (json) + json_object_array_add(json_import_rtl, + json_object_new_string(ecom_str)); + else + vty_out(vty, " %s\n", ecom_str); + XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); } - vty_out(vty, " Export Route Target:\n"); + if (json) + json_object_object_add(json, "importRts", json_import_rtl); + else + vty_out(vty, " Export Route Target:\n"); + for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) { ecom_str = ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - vty_out(vty, " %s\n", ecom_str); + + if (json) + json_object_array_add(json_export_rtl, + json_object_new_string(ecom_str)); + else + vty_out(vty, " %s\n", ecom_str); + XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); } + + if (json) + json_object_object_add(json, "exportRts", json_export_rtl); } static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, - struct vty *vty, struct in_addr vtep_ip) + struct vty *vty, struct in_addr vtep_ip, + json_object *json) { struct bgp_node *rn; struct bgp_info *ri; @@ -228,41 +323,79 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, for (rn = bgp_table_top(vpn->route_table); rn; rn = bgp_route_next(rn)) { struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + int add_prefix_to_json = 0; + char prefix_str[BUFSIZ]; + json_object *json_paths = NULL; + json_object *json_prefix = NULL; + + bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str, + sizeof(prefix_str)); if (type && evp->prefix.route_type != type) continue; + if (json) + json_prefix = json_object_new_object(); + if (rn->info) { /* Overall header/legend displayed once. */ if (header) { - bgp_evpn_show_route_header(vty, bgp); + bgp_evpn_show_route_header(vty, bgp, json); header = 0; } prefix_cnt++; } + if (json) + json_paths = json_object_new_array(); + /* For EVPN, the prefix is displayed for each path (to fit in * with code that already exists). */ for (ri = rn->info; ri; ri = ri->next) { + json_object *json_path = NULL; + if (vtep_ip.s_addr && !IPV4_ADDR_SAME(&(vtep_ip), &(ri->attr->nexthop))) continue; + if (json) + json_path = json_object_new_array(); + + route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, json_path); + + if (json) + json_object_array_add(json_paths, json_path); + path_cnt++; - route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, NULL); + add_prefix_to_json = 1; + } + + if (json && add_prefix_to_json) { + json_object_string_add(json_prefix, "prefix", + prefix_str); + json_object_int_add(json_prefix, "prefixLen", + rn->p.prefixlen); + json_object_object_add(json_prefix, "paths", + json_paths); + json_object_object_add(json, prefix_str, json_prefix); } } - if (prefix_cnt == 0) - vty_out(vty, "No EVPN prefixes %sexist for this VNI\n", - type ? "(of requested type) " : ""); - else - vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n", - prefix_cnt, path_cnt, - type ? " (of requested type)" : ""); + if (json) { + json_object_int_add(json, "numPrefix", prefix_cnt); + json_object_int_add(json, "numPaths", path_cnt); + } else { + if (prefix_cnt == 0) + vty_out(vty, "No EVPN prefixes %sexist for this VNI", + type ? "(of requested type) " : ""); + else + vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s", + prefix_cnt, path_cnt, + type ? " (of requested type)" : ""); + } } static void show_vni_routes_hash(struct hash_backet *backet, void *arg) @@ -270,13 +403,31 @@ static void show_vni_routes_hash(struct hash_backet *backet, void *arg) struct bgpevpn *vpn = (struct bgpevpn *)backet->data; struct vni_walk_ctx *wctx = arg; struct vty *vty = wctx->vty; + json_object *json = wctx->json; + json_object *json_vni = NULL; + char vni_str[VNI_STR_LEN]; + + snprintf(vni_str, VNI_STR_LEN, "%d", vpn->vni); + if (json) { + json_vni = json_object_new_object(); + json_object_int_add(json_vni, "vni", vpn->vni); + } else { + vty_out(vty, "\nVNI: %d\n\n", vpn->vni); + } - vty_out(vty, "\nVNI: %d\n\n", vpn->vni); - show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip); + show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni); + + if (json) + json_object_object_add(json, vni_str, json_vni); } -static void show_vni_entry(struct hash_backet *backet, struct vty *vty) +static void show_vni_entry(struct hash_backet *backet, void *args[]) { + struct vty *vty; + json_object *json; + json_object *json_vni; + json_object *json_import_rtl; + json_object *json_export_rtl; struct bgpevpn *vpn = (struct bgpevpn *)backet->data; char buf1[10]; char buf2[INET6_ADDRSTRLEN]; @@ -285,42 +436,92 @@ static void show_vni_entry(struct hash_backet *backet, struct vty *vty) struct listnode *node, *nnode; struct ecommunity *ecom; + vty = args[0]; + json = args[1]; + + if (json) { + json_vni = json_object_new_object(); + json_import_rtl = json_object_new_array(); + json_export_rtl = json_object_new_array(); + } + buf1[0] = '\0'; if (is_vni_live(vpn)) sprintf(buf1, "*"); - vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni, - inet_ntoa(vpn->originator_ip), - prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN)); + if (json) { + json_object_int_add(json_vni, "vni", vpn->vni); + json_object_string_add(json_vni, "inKernel", + is_vni_live(vpn) ? "True" : "False"); + json_object_string_add(json_vni, "originatorIp", + inet_ntoa(vpn->originator_ip)); + json_object_string_add( + json_vni, "rd", + prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN)); + } else { + vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni, + inet_ntoa(vpn->originator_ip), + prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN)); + } for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) { ecom_str = ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - if (listcount(vpn->import_rtl) > 1) - sprintf(rt_buf, "%s, ...", ecom_str); - else - sprintf(rt_buf, "%s", ecom_str); - vty_out(vty, " %-25s", rt_buf); + if (json) { + json_object_array_add(json_import_rtl, + json_object_new_string(ecom_str)); + } else { + if (listcount(vpn->import_rtl) > 1) + sprintf(rt_buf, "%s, ...", ecom_str); + else + sprintf(rt_buf, "%s", ecom_str); + vty_out(vty, " %-25s", rt_buf); + } XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); - break; + + /* If there are multiple import RTs we break here and show only + * one */ + if (!json) + break; } + if (json) + json_object_object_add(json_vni, "importRTs", json_import_rtl); + for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) { ecom_str = ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - if (listcount(vpn->export_rtl) > 1) - sprintf(rt_buf, "%s, ...", ecom_str); - else - sprintf(rt_buf, "%s", ecom_str); - vty_out(vty, " %-25s", rt_buf); + if (json) { + json_object_array_add(json_export_rtl, + json_object_new_string(ecom_str)); + } else { + if (listcount(vpn->export_rtl) > 1) + sprintf(rt_buf, "%s, ...", ecom_str); + else + sprintf(rt_buf, "%s", ecom_str); + vty_out(vty, " %-25s", rt_buf); + } XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); - break; + + /* If there are multiple export RTs we break here and show only + * one */ + if (!json) + break; + } + + if (json) { + char vni_str[VNI_STR_LEN]; + + json_object_object_add(json_vni, "exportRTs", json_export_rtl); + snprintf(vni_str, VNI_STR_LEN, "%u", vpn->vni); + json_object_object_add(json, vni_str, json_vni); + } else { + vty_out(vty, "\n"); } - vty_out(vty, "\n"); } #endif /* HAVE_CUMULUS */ @@ -380,155 +581,139 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) continue; - if ((table = rn->info) != NULL) { - rd_header = 1; - - for (rm = bgp_table_top(table); rm; - rm = bgp_route_next(rm)) - for (ri = rm->info; ri; ri = ri->next) { - total_count++; - if (type == bgp_show_type_neighbor) { - union sockunion *su = - output_arg; - - if (ri->peer->su_remote == NULL - || !sockunion_same( - ri->peer->su_remote, - su)) - continue; - } - if (header == 0) { - if (use_json) { - if (option - == SHOW_DISPLAY_TAGS) { - json_object_int_add( - json, - "bgpTableVersion", - 0); - json_object_string_add( - json, - "bgpLocalRouterId", - inet_ntoa( - bgp->router_id)); - json_object_object_add( - json, - "bgpStatusCodes", - json_scode); - json_object_object_add( - json, - "bgpOriginCodes", - json_ocode); - } - } else { - if (option - == SHOW_DISPLAY_TAGS) - vty_out(vty, - V4_HEADER_TAG); - else if ( - option - == SHOW_DISPLAY_OVERLAY) - vty_out(vty, - V4_HEADER_OVERLAY); - else { - vty_out(vty, - "BGP table version is 0, local router ID is %s\n", - inet_ntoa( - bgp->router_id)); - vty_out(vty, - "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n"); - vty_out(vty, - "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n"); - vty_out(vty, - V4_HEADER); - } - } - header = 0; - } - if (rd_header) { - u_int16_t type; - struct rd_as rd_as; - struct rd_ip rd_ip; - u_char *pnt; + if ((table = rn->info) == NULL) + continue; - pnt = rn->p.u.val; + rd_header = 1; - /* Decode RD type. */ - type = decode_rd_type(pnt); - /* Decode RD value. */ - if (type == RD_TYPE_AS) - decode_rd_as(pnt + 2, - &rd_as); - else if (type == RD_TYPE_AS4) - decode_rd_as4(pnt + 2, - &rd_as); - else if (type == RD_TYPE_IP) - decode_rd_ip(pnt + 2, - &rd_ip); - if (use_json) { - char buffer[BUFSIZ]; - if (type == RD_TYPE_AS - || type == RD_TYPE_AS4) - sprintf(buffer, - "%u:%d", - rd_as.as, - rd_as.val); - else if (type - == RD_TYPE_IP) - sprintf(buffer, - "%s:%d", - inet_ntoa( - rd_ip.ip), - rd_ip.val); + for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) + for (ri = rm->info; ri; ri = ri->next) { + total_count++; + if (type == bgp_show_type_neighbor) { + union sockunion *su = output_arg; + + if (ri->peer->su_remote == NULL + || !sockunion_same( + ri->peer->su_remote, su)) + continue; + } + if (header == 0) { + if (use_json) { + if (option + == SHOW_DISPLAY_TAGS) { + json_object_int_add( + json, + "bgpTableVersion", + 0); json_object_string_add( - json_nroute, - "routeDistinguisher", - buffer); - } else { + json, + "bgpLocalRouterId", + inet_ntoa( + bgp->router_id)); + json_object_object_add( + json, + "bgpStatusCodes", + json_scode); + json_object_object_add( + json, + "bgpOriginCodes", + json_ocode); + } + } else { + if (option == SHOW_DISPLAY_TAGS) + vty_out(vty, + V4_HEADER_TAG); + else if ( + option + == SHOW_DISPLAY_OVERLAY) + vty_out(vty, + V4_HEADER_OVERLAY); + else { + vty_out(vty, + "BGP table version is 0, local router ID is %s\n", + inet_ntoa( + bgp->router_id)); vty_out(vty, - "Route Distinguisher: "); - if (type == RD_TYPE_AS) - vty_out(vty, - "as2 %u:%d", - rd_as.as, - rd_as.val); - else if (type - == RD_TYPE_AS4) - vty_out(vty, - "as4 %u:%d", - rd_as.as, - rd_as.val); - else if (type - == RD_TYPE_IP) - vty_out(vty, - "ip %s:%d", - inet_ntoa( - rd_ip.ip), - rd_ip.val); - vty_out(vty, "\n\n"); + "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n"); + vty_out(vty, + "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n"); + vty_out(vty, V4_HEADER); } - rd_header = 0; } - if (use_json) - json_array = - json_object_new_array(); - else - json_array = NULL; - if (option == SHOW_DISPLAY_TAGS) - route_vty_out_tag( - vty, &rm->p, ri, 0, - SAFI_EVPN, json_array); - else if (option == SHOW_DISPLAY_OVERLAY) - route_vty_out_overlay( - vty, &rm->p, ri, 0, - json_array); - else - route_vty_out(vty, &rm->p, ri, - 0, SAFI_EVPN, - json_array); - output_count++; + header = 0; } - /* XXX json */ - } + if (rd_header) { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type(pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as(pnt + 2, &rd_as); + else if (type == RD_TYPE_AS4) + decode_rd_as4(pnt + 2, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip(pnt + 2, &rd_ip); + if (use_json) { + char buffer[BUFSIZ]; + if (type == RD_TYPE_AS + || type == RD_TYPE_AS4) + sprintf(buffer, "%u:%d", + rd_as.as, + rd_as.val); + else if (type == RD_TYPE_IP) + sprintf(buffer, "%s:%d", + inet_ntoa( + rd_ip.ip), + rd_ip.val); + json_object_string_add( + json_nroute, + "routeDistinguisher", + buffer); + } else { + vty_out(vty, + "Route Distinguisher: "); + if (type == RD_TYPE_AS) + vty_out(vty, + "as2 %u:%d", + rd_as.as, + rd_as.val); + else if (type == RD_TYPE_AS4) + vty_out(vty, + "as4 %u:%d", + rd_as.as, + rd_as.val); + else if (type == RD_TYPE_IP) + vty_out(vty, "ip %s:%d", + inet_ntoa( + rd_ip.ip), + rd_ip.val); + vty_out(vty, "\n\n"); + } + rd_header = 0; + } + if (use_json) + json_array = json_object_new_array(); + else + json_array = NULL; + if (option == SHOW_DISPLAY_TAGS) + route_vty_out_tag(vty, &rm->p, ri, 0, + SAFI_EVPN, + json_array); + else if (option == SHOW_DISPLAY_OVERLAY) + route_vty_out_overlay(vty, &rm->p, ri, + 0, json_array); + else + route_vty_out(vty, &rm->p, ri, 0, + SAFI_EVPN, json_array); + output_count++; + } + /* XXX json */ } if (output_count == 0) vty_out(vty, "No prefixes displayed, %ld exist\n", total_count); @@ -1281,19 +1466,25 @@ static int evpn_delete_vni(struct bgp *bgp, struct bgpevpn *vpn) /* * Display import RT mapping to VNIs (vty handler) */ -static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp) +static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp, + json_object *json) { + void *args[2]; + + args[0] = vty; + args[1] = json; + hash_iterate( bgp->import_rt_hash, (void (*)(struct hash_backet *, void *))show_import_rt_entry, - vty); + args); } /* * Display EVPN routes for all VNIs - vty handler. */ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, - struct in_addr vtep_ip) + struct in_addr vtep_ip, json_object *json) { u_int32_t num_vnis; struct vni_walk_ctx wctx; @@ -1305,6 +1496,7 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, wctx.bgp = bgp; wctx.vty = vty; wctx.vtep_ip = vtep_ip; + wctx.json = json; hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, void *))show_vni_routes_hash, &wctx); @@ -1314,7 +1506,8 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, * Display EVPN routes for a VNI -- for specific type-3 route (vty handler). */ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, - vni_t vni, struct in_addr orig_ip) + vni_t vni, struct in_addr orig_ip, + json_object *json) { struct bgpevpn *vpn; struct prefix_evpn p; @@ -1323,6 +1516,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, u_int32_t path_cnt = 0; afi_t afi; safi_t safi; + json_object *json_paths = NULL; afi = AFI_L2VPN; safi = SAFI_EVPN; @@ -1338,20 +1532,42 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, build_evpn_type3_prefix(&p, orig_ip); rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p); if (!rn || !rn->info) { - vty_out(vty, "%% Network not in table\n"); + if (!json) + vty_out(vty, "%% Network not in table\n"); return; } + if (json) + json_paths = json_object_new_array(); + /* Prefix and num paths displayed once per prefix. */ - route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, NULL); + route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, json); /* Display each path for this prefix. */ for (ri = rn->info; ri; ri = ri->next) { - route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, NULL); + json_object *json_path = NULL; + + if (json) + json_path = json_object_new_array(); + + route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, + json_path); + + if (json) + json_object_array_add(json_paths, json_path); + path_cnt++; } - vty_out(vty, "\nDisplayed %u paths for requested prefix\n", path_cnt); + if (json) { + if (path_cnt) + json_object_object_add(json, "paths", json_paths); + + json_object_int_add(json, "numPaths", path_cnt); + } else { + vty_out(vty, "\nDisplayed %u paths for requested prefix\n", + path_cnt); + } } /* @@ -1360,7 +1576,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, */ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, vni_t vni, struct ethaddr *mac, - struct ipaddr *ip) + struct ipaddr *ip, json_object *json) { struct bgpevpn *vpn; struct prefix_evpn p; @@ -1369,6 +1585,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, u_int32_t path_cnt = 0; afi_t afi; safi_t safi; + json_object *json_paths = NULL; afi = AFI_L2VPN; safi = SAFI_EVPN; @@ -1376,7 +1593,8 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, /* Locate VNI. */ vpn = bgp_evpn_lookup_vni(bgp, vni); if (!vpn) { - vty_out(vty, "VNI not found\n"); + if (!json) + vty_out(vty, "VNI not found\n"); return; } @@ -1384,20 +1602,42 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, build_evpn_type2_prefix(&p, mac, ip); rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p); if (!rn || !rn->info) { - vty_out(vty, "%% Network not in table\n"); + if (!json) + vty_out(vty, "%% Network not in table\n"); return; } + if (json) + json_paths = json_object_new_array(); + /* Prefix and num paths displayed once per prefix. */ - route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, NULL); + route_vty_out_detail_header(vty, bgp, rn, NULL, afi, safi, json); /* Display each path for this prefix. */ for (ri = rn->info; ri; ri = ri->next) { - route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, NULL); + json_object *json_path = NULL; + + if (json) + json_path = json_object_new_array(); + + route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, + json_path); + + if (json) + json_object_array_add(json_paths, json_path); + path_cnt++; } - vty_out(vty, "\nDisplayed %u paths for requested prefix\n", path_cnt); + if (json) { + if (path_cnt) + json_object_object_add(json, "paths", json_paths); + + json_object_int_add(json, "numPaths", path_cnt); + } else { + vty_out(vty, "\nDisplayed %u paths for requested prefix\n", + path_cnt); + } } /* @@ -1406,19 +1646,21 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, * If the vtep_ip is non zero, only routes behind that vtep are shown */ static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni, - int type, struct in_addr vtep_ip) + int type, struct in_addr vtep_ip, + json_object *json) { struct bgpevpn *vpn; /* Locate VNI. */ vpn = bgp_evpn_lookup_vni(bgp, vni); if (!vpn) { - vty_out(vty, "VNI not found\n"); + if (!json) + vty_out(vty, "VNI not found\n"); return; } /* Walk this VNI's route table and display appropriate routes. */ - show_vni_routes(bgp, vpn, type, vty, vtep_ip); + show_vni_routes(bgp, vpn, type, vty, vtep_ip, json); } /* @@ -1428,7 +1670,7 @@ static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni, */ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, struct prefix_rd *prd, struct ethaddr *mac, - struct ipaddr *ip) + struct ipaddr *ip, json_object *json) { struct prefix_evpn p; struct bgp_node *rn; @@ -1436,6 +1678,8 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, afi_t afi; safi_t safi; u_int32_t path_cnt = 0; + json_object *json_paths = NULL; + char prefix_str[BUFSIZ]; afi = AFI_L2VPN; safi = SAFI_EVPN; @@ -1445,20 +1689,44 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, rn = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi, (struct prefix *)&p, prd); if (!rn || !rn->info) { - vty_out(vty, "%% Network not in table\n"); + if (!json) + vty_out(vty, "%% Network not in table\n"); return; } + bgp_evpn_route2str((struct prefix_evpn *)&p, prefix_str, + sizeof(prefix_str)); + /* Prefix and num paths displayed once per prefix. */ - route_vty_out_detail_header(vty, bgp, rn, prd, afi, safi, NULL); + route_vty_out_detail_header(vty, bgp, rn, prd, afi, safi, json); + + if (json) + json_paths = json_object_new_array(); /* Display each path for this prefix. */ for (ri = rn->info; ri; ri = ri->next) { - route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, NULL); + json_object *json_path = NULL; + + if (json) + json_path = json_object_new_array(); + + route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, + json_path); + + if (json) + json_object_array_add(json_paths, json_path); + path_cnt++; } - vty_out(vty, "\nDisplayed %u paths for requested prefix\n", path_cnt); + if (json && path_cnt) { + if (path_cnt) + json_object_object_add(json, prefix_str, json_paths); + json_object_int_add(json, "numPaths", path_cnt); + } else { + vty_out(vty, "\nDisplayed %u paths for requested prefix\n", + path_cnt); + } } /* @@ -1466,7 +1734,8 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, * If 'type' is non-zero, only routes matching that type are shown. */ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, - struct prefix_rd *prd, int type) + struct prefix_rd *prd, int type, + json_object *json) { struct bgp_node *rd_rn; struct bgp_table *table; @@ -1476,28 +1745,49 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, afi_t afi; safi_t safi; u_int32_t prefix_cnt, path_cnt; + char rd_str[RD_ADDRSTRLEN]; + json_object *json_rd = NULL; + int add_rd_to_json = 0; afi = AFI_L2VPN; safi = SAFI_EVPN; prefix_cnt = path_cnt = 0; + prefix_rd2str((struct prefix_rd *)prd, rd_str, sizeof(rd_str)); + rd_rn = bgp_node_lookup(bgp->rib[afi][safi], (struct prefix *)prd); if (!rd_rn) return; + table = (struct bgp_table *)rd_rn->info; if (table == NULL) return; + if (json) { + json_rd = json_object_new_object(); + json_object_string_add(json_rd, "rd", rd_str); + } + /* Display all prefixes with this RD. */ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + json_object *json_prefix = NULL; + json_object *json_paths = NULL; + char prefix_str[BUFSIZ]; + int add_prefix_to_json = 0; + + bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str, + sizeof(prefix_str)); if (type && evp->prefix.route_type != type) continue; + if (json) + json_prefix = json_object_new_object(); + if (rn->info) { /* RD header and legend - once overall. */ - if (rd_header) { + if (rd_header && !json) { vty_out(vty, "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:" "[MAC]\n"); @@ -1509,34 +1799,64 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, /* Prefix and num paths displayed once per prefix. */ route_vty_out_detail_header(vty, bgp, rn, prd, afi, - safi, NULL); + safi, json_prefix); prefix_cnt++; } + if (json) + json_paths = json_object_new_array(); + /* Display each path for this prefix. */ for (ri = rn->info; ri; ri = ri->next) { + json_object *json_path = NULL; + + if (json) + json_path = json_object_new_array(); + route_vty_out_detail(vty, bgp, &rn->p, ri, afi, safi, - NULL); + json_path); + + if (json) + json_object_array_add(json_paths, json_path); + path_cnt++; + add_prefix_to_json = 1; + add_rd_to_json = 1; + } + + if (json && add_prefix_to_json) { + json_object_object_add(json_prefix, "paths", + json_paths); + json_object_object_add(json_rd, prefix_str, + json_prefix); } } - if (prefix_cnt == 0) - vty_out(vty, "No prefixes exist with this RD%s\n", - type ? " (of requested type)" : ""); - else - vty_out(vty, - "\nDisplayed %u prefixes (%u paths) with this RD%s\n", - prefix_cnt, path_cnt, - type ? " (of requested type)" : ""); + if (json && add_rd_to_json) + json_object_object_add(json, rd_str, json_rd); + + if (json) { + json_object_int_add(json, "numPrefix", prefix_cnt); + json_object_int_add(json, "numPaths", path_cnt); + } else { + if (prefix_cnt == 0) + vty_out(vty, "No prefixes exist with this RD%s\n", + type ? " (of requested type)" : ""); + else + vty_out(vty, + "\nDisplayed %u prefixes (%u paths) with this RD%s\n", + prefix_cnt, path_cnt, + type ? " (of requested type)" : ""); + } } /* * Display BGP EVPN routing table - all routes (vty handler). * If 'type' is non-zero, only routes matching that type are shown. */ -static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type) +static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, + json_object *json) { struct bgp_node *rd_rn; struct bgp_table *table; @@ -1557,15 +1877,36 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type) */ for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn; rd_rn = bgp_route_next(rd_rn)) { + char rd_str[RD_ADDRSTRLEN]; + json_object *json_rd = NULL; /* contains routes for an RD */ + int add_rd_to_json = 0; + table = (struct bgp_table *)rd_rn->info; if (table == NULL) continue; + prefix_rd2str((struct prefix_rd *)&rd_rn->p, rd_str, + sizeof(rd_str)); + + if (json) { + json_rd = json_object_new_object(); + json_object_string_add(json_rd, "rd", rd_str); + } + rd_header = 1; /* Display all prefixes for an RD */ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + json_object *json_prefix = + NULL; /* contains prefix under a RD */ + json_object *json_paths = + NULL; /* array of paths under a prefix*/ struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + char prefix_str[BUFSIZ]; + int add_prefix_to_json = 0; + + bgp_evpn_route2str((struct prefix_evpn *)&rn->p, + prefix_str, sizeof(prefix_str)); if (type && evp->prefix.route_type != type) continue; @@ -1573,74 +1914,126 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type) if (rn->info) { /* Overall header/legend displayed once. */ if (header) { - bgp_evpn_show_route_header(vty, bgp); + bgp_evpn_show_route_header(vty, bgp, + json); header = 0; } /* RD header - per RD. */ if (rd_header) { - bgp_evpn_show_route_rd_header(vty, - rd_rn); + bgp_evpn_show_route_rd_header( + vty, rd_rn, json); rd_header = 0; } prefix_cnt++; } + if (json) { + json_prefix = json_object_new_object(); + json_paths = json_object_new_array(); + json_object_string_add(json_prefix, "prefix", + prefix_str); + json_object_int_add(json_prefix, "prefixLen", + rn->p.prefixlen); + } + /* For EVPN, the prefix is displayed for each path (to * fit in * with code that already exists). */ for (ri = rn->info; ri; ri = ri->next) { + json_object *json_path = NULL; path_cnt++; + add_prefix_to_json = 1; + add_rd_to_json = 1; + + if (json) + json_path = json_object_new_array(); + route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, - NULL); + json_path); + + if (json) + json_object_array_add(json_paths, + json_path); + } + + if (json && add_prefix_to_json) { + json_object_object_add(json_prefix, "paths", + json_paths); + json_object_object_add(json_rd, prefix_str, + json_prefix); } } + + if (json && add_rd_to_json) + json_object_object_add(json, rd_str, json_rd); } - if (prefix_cnt == 0) - vty_out(vty, "No EVPN prefixes %sexist\n", - type ? "(of requested type) " : ""); - else - vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n", - prefix_cnt, path_cnt, - type ? " (of requested type)" : ""); + if (json) { + json_object_int_add(json, "numPrefix", prefix_cnt); + json_object_int_add(json, "numPaths", path_cnt); + } else { + if (prefix_cnt == 0) { + vty_out(vty, "No EVPN prefixes %sexist\n", + type ? "(of requested type) " : ""); + } else { + vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n", + prefix_cnt, path_cnt, + type ? " (of requested type)" : ""); + } + } } /* * Display specified VNI (vty handler) */ -static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni) +static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni, + json_object *json) { struct bgpevpn *vpn; vpn = bgp_evpn_lookup_vni(bgp, vni); if (!vpn) { - vty_out(vty, "VNI not found\n"); - return; + if (json) { + vty_out(vty, "{}\n"); + } else { + vty_out(vty, "VNI not found\n"); + return; + } } - display_vni(vty, vpn); + display_vni(vty, vpn, json); } /* * Display a VNI (upon user query). */ -static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp) +static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp, + json_object *json) { u_int32_t num_vnis; + void *args[2]; num_vnis = hashcount(bgp->vnihash); if (!num_vnis) return; - vty_out(vty, "Number of VNIs: %u\n", num_vnis); - vty_out(vty, "Flags: * - Kernel \n"); - vty_out(vty, " %-10s %-15s %-21s %-25s %-25s\n", "VNI", "Orig IP", - "RD", "Import RT", "Export RT"); + + if (json) { + json_object_int_add(json, "numVnis", num_vnis); + } else { + vty_out(vty, "Number of VNIs: %u\n", num_vnis); + vty_out(vty, "Flags: * - Kernel\n"); + vty_out(vty, " %-10s %-15s %-21s %-25s %-25s\n", "VNI", + "Orig IP", "RD", "Import RT", "Export RT"); + } + + args[0] = vty; + args[1] = json; hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, void *))show_vni_entry, - vty); + args); } /* @@ -1709,17 +2102,14 @@ static void evpn_unset_advertise_all_vni(struct bgp *bgp) } #endif /* HAVE_CUMULUS */ -static void write_vni_config(struct vty *vty, struct bgpevpn *vpn, int *write) +static void write_vni_config(struct vty *vty, struct bgpevpn *vpn) { char buf1[INET6_ADDRSTRLEN]; - afi_t afi = AFI_L2VPN; - safi_t safi = SAFI_EVPN; char *ecom_str; struct listnode *node, *nnode; struct ecommunity *ecom; if (is_vni_configured(vpn)) { - bgp_config_write_family_header(vty, afi, safi, write); vty_out(vty, " vni %d\n", vpn->vni); if (is_rd_configured(vpn)) vty_out(vty, " rd %s\n", @@ -1755,10 +2145,10 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn, int *write) } static void write_vni_config_for_entry(struct hash_backet *backet, - struct evpn_config_write *cfg) + struct vty *vty) { struct bgpevpn *vpn = (struct bgpevpn *)backet->data; - write_vni_config(cfg->vty, vpn, &cfg->write); + write_vni_config(vty, vpn); } #if defined(HAVE_CUMULUS) @@ -1863,19 +2253,24 @@ DEFUN (no_bgp_evpn_advertise_all_vni, /* * Display VNI information - for all or a specific VNI */ -DEFUN (show_bgp_l2vpn_evpn_vni, - show_bgp_l2vpn_evpn_vni_cmd, - "show bgp l2vpn evpn vni [(1-16777215)]", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Show VNI\n" - "VNI number\n") +DEFUN(show_bgp_l2vpn_evpn_vni, + show_bgp_l2vpn_evpn_vni_cmd, + "show bgp l2vpn evpn vni [(1-16777215)] [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Show VNI\n" + "VNI number\n" + JSON_STR) { struct bgp *bgp; vni_t vni; int idx = 0; + u_char uj = 0; + json_object *json = NULL; + + uj = use_json(argc, argv); bgp = bgp_get_default(); if (!bgp) @@ -1884,18 +2279,46 @@ DEFUN (show_bgp_l2vpn_evpn_vni, if (!argv_find(argv, argc, "evpn", &idx)) return CMD_WARNING; - if (argc == ((idx + 1) + 1)) { - vty_out(vty, "Advertise gateway macip flag: %s\n", - bgp->advertise_gw_macip ? "Enabled" : "Disabled"); + if (uj) + json = json_object_new_object(); - /* Display all VNIs */ - vty_out(vty, "Advertise All VNI flag: %s\n", - bgp->advertise_all_vni ? "Enabled" : "Disabled"); - evpn_show_all_vnis(vty, bgp); + if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) { + if (uj) { + json_object_string_add(json, "advertiseGatewayMacip", + bgp->advertise_gw_macip + ? "Enabled" + : "Disabled"); + json_object_string_add(json, "advertiseAllVnis", + bgp->advertise_all_vni + ? "Enabled" + : "Disabled"); + } else { + vty_out(vty, "Advertise Gateway Macip: %s\n", + bgp->advertise_gw_macip ? "Enabled" + : "Disabled"); + + /* Display all VNIs */ + vty_out(vty, "Advertise All VNI flag: %s\n", + bgp->advertise_all_vni ? "Enabled" + : "Disabled"); + } + + evpn_show_all_vnis(vty, bgp, json); } else { + int vni_idx = 0; + + if (!argv_find(argv, argc, "vni", &vni_idx)) + return CMD_WARNING; + /* Display specific VNI */ - vni = strtoul(argv[argc - 1]->arg, NULL, 10); - evpn_show_vni(vty, bgp, vni); + vni = strtoul(argv[vni_idx + 1]->arg, NULL, 10); + evpn_show_vni(vty, bgp, vni, json); + } + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); } return CMD_SUCCESS; @@ -1904,15 +2327,15 @@ DEFUN (show_bgp_l2vpn_evpn_vni, /* * Display EVPN neighbor summary. */ -DEFUN (show_bgp_l2vpn_evpn_summary, - show_bgp_l2vpn_evpn_summary_cmd, - "show bgp l2vpn evpn summary [json]", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Summary of BGP neighbor status\n" - JSON_STR) +DEFUN(show_bgp_l2vpn_evpn_summary, + show_bgp_l2vpn_evpn_summary_cmd, + "show bgp l2vpn evpn summary [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Summary of BGP neighbor status\n" + JSON_STR) { u_char uj = use_json(argc, argv); return bgp_show_summary_vty(vty, NULL, AFI_L2VPN, SAFI_EVPN, uj); @@ -1921,176 +2344,238 @@ DEFUN (show_bgp_l2vpn_evpn_summary, /* * Display global EVPN routing table. */ -DEFUN (show_bgp_l2vpn_evpn_route, - show_bgp_l2vpn_evpn_route_cmd, - "show bgp l2vpn evpn route [type <macip|multicast>]", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "EVPN route information\n" - "Specify Route type\n" - "MAC-IP (Type-2) route\n" - "Multicast (Type-3) route\n") +DEFUN(show_bgp_l2vpn_evpn_route, + show_bgp_l2vpn_evpn_route_cmd, + "show bgp l2vpn evpn route [type <macip|multicast>] [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" + "Specify Route type\n" + "MAC-IP (Type-2) route\n" + "Multicast (Type-3) route\n" + JSON_STR) { struct bgp *bgp; - int idx = 0; + int type_idx; int type = 0; + u_char uj = 0; + json_object *json = NULL; + + uj = use_json(argc, argv); bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - if (!argv_find(argv, argc, "evpn", &idx)) - return CMD_WARNING; + if (uj) + json = json_object_new_object(); - if (argc == ((idx + 1) + 3)) { + /* get the type */ + if (argv_find(argv, argc, "type", &type_idx)) { /* Specific type is requested */ - if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0) + if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0) type = BGP_EVPN_MAC_IP_ROUTE; - else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0) + else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0) type = BGP_EVPN_IMET_ROUTE; else return CMD_WARNING; } - evpn_show_all_routes(vty, bgp, type); + evpn_show_all_routes(vty, bgp, type, json); + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; } /* * Display global EVPN routing table for specific RD. */ -DEFUN (show_bgp_l2vpn_evpn_route_rd, - show_bgp_l2vpn_evpn_route_rd_cmd, - "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>]", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "EVPN route information\n" - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n" - "Specify Route type\n" - "MAC-IP (Type-2) route\n" - "Multicast (Type-3) route\n") +DEFUN(show_bgp_l2vpn_evpn_route_rd, + show_bgp_l2vpn_evpn_route_rd_cmd, + "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>] [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n" + "Specify Route type\n" + "MAC-IP (Type-2) route\n" + "Multicast (Type-3) route\n" + JSON_STR) { struct bgp *bgp; int ret; struct prefix_rd prd; - int idx = 0; int type = 0; + int rd_idx = 0; + int type_idx = 0; + int uj = 0; + json_object *json = NULL; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - if (!argv_find(argv, argc, "evpn", &idx)) - return CMD_WARNING; + /* check if we need json output */ + uj = use_json(argc, argv); + if (uj) + json = json_object_new_object(); - ret = str2prefix_rd(argv[idx + 3]->arg, &prd); - if (!ret) { - vty_out(vty, "%% Malformed Route Distinguisher\n"); - return CMD_WARNING; + /* get the RD */ + if (argv_find(argv, argc, "rd", &rd_idx)) { + ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd); + + if (!ret) { + vty_out(vty, "%% Malformed Route Distinguisher\n"); + return CMD_WARNING; + } } - if (argc == ((idx + 1) + 5)) { + /* get the type */ + if (argv_find(argv, argc, "type", &type_idx)) { /* Specific type is requested */ - if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0) + if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0) type = BGP_EVPN_MAC_IP_ROUTE; - else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0) + else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0) type = BGP_EVPN_IMET_ROUTE; else return CMD_WARNING; } - evpn_show_route_rd(vty, bgp, &prd, type); + evpn_show_route_rd(vty, bgp, &prd, type, json); + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; } /* * Display global EVPN routing table for specific RD and MACIP. */ -DEFUN (show_bgp_l2vpn_evpn_route_rd_macip, - show_bgp_l2vpn_evpn_route_rd_macip_cmd, - "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "EVPN route information\n" - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n" - "MAC\n" - "MAC address (e.g., 00:e0:ec:20:12:62)\n" - "IP\n" - "IP address (IPv4 or IPv6)\n") +DEFUN(show_bgp_l2vpn_evpn_route_rd_macip, + show_bgp_l2vpn_evpn_route_rd_macip_cmd, + "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD] [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n" + "IP\n" + "IP address (IPv4 or IPv6)\n" + JSON_STR) { struct bgp *bgp; int ret; struct prefix_rd prd; struct ethaddr mac; struct ipaddr ip; - int idx = 0; + int rd_idx = 0; + int mac_idx = 0; + int ip_idx = 0; + int uj = 0; + json_object *json = NULL; + + memset(&mac, 0, sizeof(struct ethaddr)); + memset(&ip, 0, sizeof(struct ipaddr)); bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - if (!argv_find(argv, argc, "evpn", &idx)) - return CMD_WARNING; + /* check if we need json output */ + uj = use_json(argc, argv); + if (uj) + json = json_object_new_object(); - ret = str2prefix_rd(argv[idx + 3]->arg, &prd); - if (!ret) { - vty_out(vty, "%% Malformed Route Distinguisher\n"); - return CMD_WARNING; + /* get the prd */ + if (argv_find(argv, argc, "rd", &rd_idx)) { + ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd); + if (!ret) { + vty_out(vty, "%% Malformed Route Distinguisher\n"); + return CMD_WARNING; + } } - if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) { - vty_out(vty, "%% Malformed MAC address\n"); - return CMD_WARNING; + + /* get the mac */ + if (argv_find(argv, argc, "mac", &mac_idx)) { + if (!prefix_str2mac(argv[mac_idx + 1]->arg, &mac)) { + vty_out(vty, "%% Malformed MAC address\n"); + return CMD_WARNING; + } } - memset(&ip, 0, sizeof(ip)); - if (argc == (idx + 1 + 7) && argv[argc - 1]->arg != NULL) { - /* Specific MAC+IP requested */ - if (str2ipaddr(argv[argc - 1]->arg, &ip) != 0) { + + /* get the ip if specified */ + if (argv_find(argv, argc, "ip", &ip_idx)) { + if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) { vty_out(vty, "%% Malformed IP address\n"); return CMD_WARNING; } } - evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip); + evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip, json); + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; } /* * Display per-VNI EVPN routing table. */ -DEFUN (show_bgp_l2vpn_evpn_route_vni, - show_bgp_l2vpn_evpn_route_vni_cmd, - "show bgp l2vpn evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "EVPN route information\n" - "VXLAN Network Identifier\n" - "VNI number\n" - "Specify Route type\n" - "MAC-IP (Type-2) route\n" - "Multicast (Type-3) route\n" - "Remote VTEP\n" - "Remote VTEP IP address\n") +DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd, + "show bgp l2vpn evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>] [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" + "VXLAN Network Identifier\n" + "VNI number\n" + "Specify Route type\n" + "MAC-IP (Type-2) route\n" + "Multicast (Type-3) route\n" + "Remote VTEP\n" + "Remote VTEP IP address\n" + JSON_STR) { vni_t vni; struct bgp *bgp; struct in_addr vtep_ip; int type = 0; int idx = 0; + int uj = 0; + json_object *json = NULL; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; + /* check if we need json output */ + uj = use_json(argc, argv); + if (uj) + json = json_object_new_object(); + if (!argv_find(argv, argc, "evpn", &idx)) return CMD_WARNING; @@ -2098,7 +2583,8 @@ DEFUN (show_bgp_l2vpn_evpn_route_vni, vni = strtoul(argv[idx + 3]->arg, NULL, 10); - if (argc == (idx + 1 + 5) && argv[idx + 4]->arg) { + if ((!uj && ((argc == (idx + 1 + 5)) && argv[idx + 4]->arg)) + || (uj && ((argc == (idx + 1 + 6)) && argv[idx + 4]->arg))) { if (strncmp(argv[idx + 4]->arg, "type", 4) == 0) { if (strncmp(argv[idx + 5]->arg, "ma", 2) == 0) type = BGP_EVPN_MAC_IP_ROUTE; @@ -2115,156 +2601,233 @@ DEFUN (show_bgp_l2vpn_evpn_route_vni, return CMD_WARNING; } - evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip); + evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip, json); + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; } /* * Display per-VNI EVPN routing table for specific MACIP. */ -DEFUN (show_bgp_l2vpn_evpn_route_vni_macip, - show_bgp_l2vpn_evpn_route_vni_macip_cmd, - "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD]", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "EVPN route information\n" - "VXLAN Network Identifier\n" - "VNI number\n" - "MAC\n" - "MAC address (e.g., 00:e0:ec:20:12:62)\n" - "IP\n" - "IP address (IPv4 or IPv6)\n") +DEFUN(show_bgp_l2vpn_evpn_route_vni_macip, + show_bgp_l2vpn_evpn_route_vni_macip_cmd, + "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD] [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" + "VXLAN Network Identifier\n" + "VNI number\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n" + "IP\n" + "IP address (IPv4 or IPv6)\n" + JSON_STR) { vni_t vni; struct bgp *bgp; struct ethaddr mac; struct ipaddr ip; int idx = 0; + int uj = 0; + json_object *json = NULL; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; + /* check if we need json output */ + uj = use_json(argc, argv); + if (uj) + json = json_object_new_object(); + if (!argv_find(argv, argc, "evpn", &idx)) return CMD_WARNING; + /* get the VNI */ vni = strtoul(argv[idx + 3]->arg, NULL, 10); + + /* get the mac */ if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) { vty_out(vty, "%% Malformed MAC address\n"); return CMD_WARNING; } + + /* get the ip */ memset(&ip, 0, sizeof(ip)); - if (argc == (idx + 1 + 7) && argv[idx + 7]->arg != NULL) { + if ((!uj && ((argc == (idx + 1 + 7)) && argv[idx + 7]->arg != NULL)) + || (uj + && ((argc == (idx + 1 + 8)) && argv[idx + 7]->arg != NULL))) { if (str2ipaddr(argv[idx + 7]->arg, &ip) != 0) { vty_out(vty, "%% Malformed IP address\n"); return CMD_WARNING; } } - evpn_show_route_vni_macip(vty, bgp, vni, &mac, &ip); + evpn_show_route_vni_macip(vty, bgp, vni, &mac, &ip, json); + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; } /* * Display per-VNI EVPN routing table for specific multicast IP (remote VTEP). */ -DEFUN (show_bgp_l2vpn_evpn_route_vni_multicast, - show_bgp_l2vpn_evpn_route_vni_multicast_cmd, - "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "EVPN route information\n" - "VXLAN Network Identifier\n" - "VNI number\n" - "Multicast (Type-3) route\n" - "Originating Router IP address\n") +DEFUN(show_bgp_l2vpn_evpn_route_vni_multicast, + show_bgp_l2vpn_evpn_route_vni_multicast_cmd, + "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" + "VXLAN Network Identifier\n" + "VNI number\n" + "Multicast (Type-3) route\n" + "Originating Router IP address\n" + JSON_STR) { vni_t vni; struct bgp *bgp; int ret; struct in_addr orig_ip; int idx = 0; + int uj = 0; + json_object *json = NULL; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; + /* check if we need json output */ + uj = use_json(argc, argv); + if (uj) + json = json_object_new_object(); + if (!argv_find(argv, argc, "evpn", &idx)) return CMD_WARNING; + /* get the VNI */ vni = strtoul(argv[idx + 3]->arg, NULL, 10); + + /* get the ip */ ret = inet_aton(argv[idx + 5]->arg, &orig_ip); if (!ret) { vty_out(vty, "%% Malformed Originating Router IP address\n"); return CMD_WARNING; } - evpn_show_route_vni_multicast(vty, bgp, vni, orig_ip); + evpn_show_route_vni_multicast(vty, bgp, vni, orig_ip, json); + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; } /* * Display per-VNI EVPN routing table - for all VNIs. */ -DEFUN (show_bgp_l2vpn_evpn_route_vni_all, - show_bgp_l2vpn_evpn_route_vni_all_cmd, - "show bgp l2vpn evpn route vni all [vtep A.B.C.D]", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "EVPN route information\n" - "VXLAN Network Identifier\n" - "All VNIs\n" - "Remote VTEP\n" - "Remote VTEP IP address\n") +DEFUN(show_bgp_l2vpn_evpn_route_vni_all, + show_bgp_l2vpn_evpn_route_vni_all_cmd, + "show bgp l2vpn evpn route vni all [vtep A.B.C.D] [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" + "VXLAN Network Identifier\n" + "All VNIs\n" + "Remote VTEP\n" + "Remote VTEP IP address\n" + JSON_STR) { struct bgp *bgp; struct in_addr vtep_ip; int idx = 0; + int uj = 0; + json_object *json = NULL; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; + /* check if we need json output */ + uj = use_json(argc, argv); + if (uj) + json = json_object_new_object(); + if (!argv_find(argv, argc, "evpn", &idx)) return CMD_WARNING; vtep_ip.s_addr = 0; - if (argc == (idx + 1 + 5) && argv[idx + 5]->arg) { + if ((!uj && (argc == (idx + 1 + 5) && argv[idx + 5]->arg)) + || (uj && (argc == (idx + 1 + 6) && argv[idx + 5]->arg))) { if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) { vty_out(vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } } - evpn_show_routes_vni_all(vty, bgp, vtep_ip); + evpn_show_routes_vni_all(vty, bgp, vtep_ip, json); + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; } /* * Display EVPN import route-target hash table */ -DEFUN (show_bgp_l2vpn_evpn_import_rt, - show_bgp_l2vpn_evpn_import_rt_cmd, - "show bgp l2vpn evpn import-rt", - SHOW_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Show import route target\n") +DEFUN(show_bgp_l2vpn_evpn_import_rt, + show_bgp_l2vpn_evpn_import_rt_cmd, + "show bgp l2vpn evpn import-rt [json]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Show import route target\n" + JSON_STR) { struct bgp *bgp; + u_char uj = 0; + json_object *json = NULL; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - evpn_show_import_rts(vty, bgp); + uj = use_json(argc, argv); + if (uj) + json = json_object_new_object(); + + evpn_show_import_rts(vty, bgp, json); + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; } @@ -2741,29 +3304,19 @@ DEFUN (no_bgp_evpn_vni_rt_without_val, * Output EVPN configuration information. */ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi, int *write) + safi_t safi) { - struct evpn_config_write cfg; - - if (bgp->vnihash) { - cfg.write = *write; - cfg.vty = vty; + if (bgp->vnihash) hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, void *))write_vni_config_for_entry, - &cfg); - *write = cfg.write; - } + vty); - if (bgp->advertise_all_vni) { - bgp_config_write_family_header(vty, afi, safi, write); + if (bgp->advertise_all_vni) vty_out(vty, " advertise-all-vni\n"); - } - if (bgp->advertise_gw_macip) { - bgp_config_write_family_header(vty, afi, safi, write); + if (bgp->advertise_gw_macip) vty_out(vty, " advertise-default-gw\n"); - } } void bgp_ethernetvpn_init(void) diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h index 3bc24593f4..4d07f7d038 100644 --- a/bgpd/bgp_evpn_vty.h +++ b/bgpd/bgp_evpn_vty.h @@ -22,7 +22,7 @@ #define _FRR_BGP_EVPN_VTY_H extern void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, - afi_t afi, safi_t safi, int *write); + afi_t afi, safi_t safi); extern void bgp_ethernetvpn_init(void); #define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n" diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index f4393c1b2d..395ae52712 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -148,12 +148,11 @@ struct lcommunity *lcommunity_dup(struct lcommunity *lcom) { struct lcommunity *new; - new = XCALLOC(MTYPE_LCOMMUNITY, sizeof(struct lcommunity)); + new = lcommunity_new(); new->size = lcom->size; if (new->size) { - new->val = XMALLOC(MTYPE_LCOMMUNITY_VAL, - lcom->size * LCOMMUNITY_SIZE); - memcpy(new->val, lcom->val, lcom->size * LCOMMUNITY_SIZE); + new->val = XMALLOC(MTYPE_LCOMMUNITY_VAL, lcom_length(lcom)); + memcpy(new->val, lcom->val, lcom_length(lcom)); } else new->val = NULL; return new; @@ -175,14 +174,13 @@ struct lcommunity *lcommunity_merge(struct lcommunity *lcom1, if (lcom1->val) lcom1->val = XREALLOC(MTYPE_LCOMMUNITY_VAL, lcom1->val, - (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); + lcom_length(lcom1) + lcom_length(lcom2)); else lcom1->val = XMALLOC(MTYPE_LCOMMUNITY_VAL, - (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); + lcom_length(lcom1) + lcom_length(lcom2)); - memcpy(lcom1->val + (lcom1->size * LCOMMUNITY_SIZE), lcom2->val, - lcom2->size * LCOMMUNITY_SIZE); + memcpy(lcom1->val + lcom_length(lcom1), lcom2->val, lcom_length(lcom2)); lcom1->size += lcom2->size; return lcom1; @@ -231,7 +229,7 @@ void lcommunity_unintern(struct lcommunity **lcom) unsigned int lcommunity_hash_make(void *arg) { const struct lcommunity *lcom = arg; - int size = lcom->size * LCOMMUNITY_SIZE; + int size = lcom_length(lcom); u_int8_t *pnt = lcom->val; unsigned int key = 0; int c; @@ -261,7 +259,7 @@ int lcommunity_cmp(const void *arg1, const void *arg2) const struct lcommunity *lcom2 = arg2; return (lcom1->size == lcom2->size - && memcmp(lcom1->val, lcom2->val, lcom1->size * LCOMMUNITY_SIZE) + && memcmp(lcom1->val, lcom2->val, lcom_length(lcom1)) == 0); } @@ -400,9 +398,8 @@ int lcommunity_include(struct lcommunity *lcom, u_char *ptr) int i; u_char *lcom_ptr; - lcom_ptr = lcom->val; for (i = 0; i < lcom->size; i++) { - lcom_ptr += (i * LCOMMUNITY_SIZE); + lcom_ptr = lcom->val + (i * LCOMMUNITY_SIZE); if (memcmp(ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0) return 1; } @@ -447,7 +444,7 @@ char *lcommunity_lcom2str(struct lcommunity *lcom, int format) if (!first) str_buf[str_pnt++] = ' '; - pnt = lcom->val + (i * 12); + pnt = lcom->val + (i * LCOMMUNITY_SIZE); globaladmin = (*pnt++ << 24); globaladmin |= (*pnt++ << 16); @@ -489,7 +486,7 @@ int lcommunity_match(const struct lcommunity *lcom1, /* Every community on com2 needs to be on com1 for this to match */ while (i < lcom1->size && j < lcom2->size) { - if (memcmp(lcom1->val + (i * 12), lcom2->val + (j * 12), + if (memcmp(lcom1->val + (i * LCOMMUNITY_SIZE), lcom2->val + (j * LCOMMUNITY_SIZE), LCOMMUNITY_SIZE) == 0) j++; @@ -526,10 +523,10 @@ void lcommunity_del_val(struct lcommunity *lcom, u_char *ptr) if (lcom->size > 0) lcom->val = - XREALLOC(MTYPE_COMMUNITY_VAL, lcom->val, + XREALLOC(MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length(lcom)); else { - XFREE(MTYPE_COMMUNITY_VAL, lcom->val); + XFREE(MTYPE_LCOMMUNITY_VAL, lcom->val); lcom->val = NULL; } return; diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h index 1a3304e719..7576d7a980 100644 --- a/bgpd/bgp_lcommunity.h +++ b/bgpd/bgp_lcommunity.h @@ -37,14 +37,14 @@ struct lcommunity { /* Size of Extended Communities attribute. */ int size; - /* Extended Communities value. */ + /* Large Communities value. */ u_int8_t *val; /* Human readable format string. */ char *str; }; -/* Extended community value is eight octet. */ +/* Large community value is 12 octets. */ struct lcommunity_val { char val[LCOMMUNITY_SIZE]; }; diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 3df40fa87a..37054ce425 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -101,6 +101,7 @@ DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array") DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp") DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate") DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address") +DEFINE_MTYPE(BGPD, TIP_ADDR, "BGP own tunnel-ip address") DEFINE_MTYPE(BGPD, BGP_REDIST, "BGP redistribution") DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information") diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 152cfaeaf2..35b83a0401 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -97,6 +97,7 @@ DECLARE_MTYPE(BGP_DAMP_ARRAY) DECLARE_MTYPE(BGP_REGEXP) DECLARE_MTYPE(BGP_AGGREGATE) DECLARE_MTYPE(BGP_ADDR) +DECLARE_MTYPE(TIP_ADDR) DECLARE_MTYPE(BGP_REDIST) DECLARE_MTYPE(BGP_FILTER_NAME) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 63a84684bb..b7d7cd9fa3 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -88,11 +88,86 @@ static void bgp_nexthop_cache_reset(struct bgp_table *table) } } -/* BGP own address structure */ -struct bgp_addr { - struct in_addr addr; - int refcnt; -}; +static void *bgp_tip_hash_alloc(void *p) +{ + const struct in_addr *val = (const struct in_addr *)p; + struct tip_addr *addr; + + addr = XMALLOC(MTYPE_TIP_ADDR, sizeof(struct tip_addr)); + addr->refcnt = 0; + addr->addr.s_addr = val->s_addr; + + return addr; +} + +static void bgp_tip_hash_free(void *addr) +{ + XFREE(MTYPE_TIP_ADDR, addr); +} + +static unsigned int bgp_tip_hash_key_make(void *p) +{ + const struct tip_addr *addr = p; + + return jhash_1word(addr->addr.s_addr, 0); +} + +static int bgp_tip_hash_cmp(const void *p1, const void *p2) +{ + const struct tip_addr *addr1 = p1; + const struct tip_addr *addr2 = p2; + + return addr1->addr.s_addr == addr2->addr.s_addr; +} + +void bgp_tip_hash_init(struct bgp *bgp) +{ + bgp->tip_hash = + hash_create(bgp_tip_hash_key_make, bgp_tip_hash_cmp, NULL); +} + +void bgp_tip_hash_destroy(struct bgp *bgp) +{ + if (bgp->tip_hash == NULL) + return; + hash_clean(bgp->tip_hash, bgp_tip_hash_free); + hash_free(bgp->tip_hash); + bgp->tip_hash = NULL; +} + +void bgp_tip_add(struct bgp *bgp, struct in_addr *tip) +{ + struct tip_addr tmp; + struct tip_addr *addr; + + tmp.addr = *tip; + + addr = hash_get(bgp->tip_hash, &tmp, bgp_tip_hash_alloc); + if (!addr) + return; + + addr->refcnt++; +} + +void bgp_tip_del(struct bgp *bgp, struct in_addr *tip) +{ + struct tip_addr tmp; + struct tip_addr *addr; + + tmp.addr = *tip; + + addr = hash_lookup(bgp->tip_hash, &tmp); + /* may have been deleted earlier by bgp_interface_down() */ + if (addr == NULL) + return; + + addr->refcnt--; + + if (addr->refcnt == 0) { + hash_release(bgp->tip_hash, addr); + XFREE(MTYPE_TIP_ADDR, addr); + } +} static void *bgp_address_hash_alloc(void *p) { @@ -304,6 +379,7 @@ void bgp_connected_delete(struct bgp *bgp, struct connected *ifc) int bgp_nexthop_self(struct bgp *bgp, struct in_addr nh_addr) { struct bgp_addr tmp, *addr; + struct tip_addr tmp_tip, *tip; tmp.addr = nh_addr; @@ -311,6 +387,11 @@ int bgp_nexthop_self(struct bgp *bgp, struct in_addr nh_addr) if (addr) return 1; + tmp_tip.addr = nh_addr; + tip = hash_lookup(bgp->tip_hash, &tmp_tip); + if (tip) + return 1; + return 0; } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 37dad577c2..b482778fdf 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -66,6 +66,18 @@ struct bgp_nexthop_cache { struct bgp *bgp; }; +/* BGP own address structure */ +struct bgp_addr { + struct in_addr addr; + int refcnt; +}; + +/* Own tunnel-ip address structure */ +struct tip_addr { + struct in_addr addr; + int refcnt; +}; + extern int bgp_nexthop_lookup(afi_t, struct peer *peer, struct bgp_info *, int *, int *); extern void bgp_connected_add(struct bgp *bgp, struct connected *c); @@ -82,5 +94,9 @@ extern void bgp_scan_finish(struct bgp *bgp); extern void bgp_scan_vty_init(void); extern void bgp_address_init(struct bgp *bgp); extern void bgp_address_destroy(struct bgp *bgp); +extern void bgp_tip_add(struct bgp *bgp, struct in_addr *tip); +extern void bgp_tip_del(struct bgp *bgp, struct in_addr *tip); +extern void bgp_tip_hash_init(struct bgp *bgp); +extern void bgp_tip_hash_destroy(struct bgp *bgp); #endif /* _QUAGGA_BGP_NEXTHOP_H */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 3a7a60b14d..a0fc10c745 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -482,6 +482,34 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) evaluate_paths(bnc); } +/* + * Cleanup nexthop registration and status information for BGP nexthops + * pertaining to this VRF. This is invoked upon VRF deletion. + */ +void bgp_cleanup_nexthops(struct bgp *bgp) +{ + afi_t afi; + struct bgp_node *rn; + struct bgp_nexthop_cache *bnc; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + if (!bgp->nexthop_cache_table[afi]) + continue; + + for (rn = bgp_table_top(bgp->nexthop_cache_table[afi]); rn; + rn = bgp_route_next(rn)) { + bnc = rn->info; + if (!bnc) + continue; + + /* Clear relevant flags. */ + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); + } + } +} + /** * make_prefix - make a prefix structure from the path (essentially * path's node. diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index f649bb2259..4b297f410c 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -66,4 +66,10 @@ void bgp_unlink_nexthop_by_peer(struct peer *); */ extern void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer); +/* + * Cleanup nexthop registration and status information for BGP nexthops + * pertaining to this VRF. This is invoked upon VRF deletion. + */ +extern void bgp_cleanup_nexthops(struct bgp *bgp); + #endif /* _BGP_NHT_H */ diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 3ee865e3ba..5c9ba89a57 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -1271,7 +1271,6 @@ void bgp_open_capability(struct stream *s, struct peer *peer) as_t local_as; u_int32_t restart_time; u_char afi_safi_count = 0; - struct utsname names; int adv_addpath_tx = 0; /* Remember current pointer for Opt Parm Len. */ @@ -1441,8 +1440,7 @@ void bgp_open_capability(struct stream *s, struct peer *peer) } /* Hostname capability */ - uname(&names); - if (names.nodename[0] != '\0') { + if (cmd_hostname_get()) { SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); rcapp = stream_get_endp(s); /* Ptr to length placeholder */ @@ -1450,26 +1448,21 @@ void bgp_open_capability(struct stream *s, struct peer *peer) stream_putc(s, CAPABILITY_CODE_FQDN); capp = stream_get_endp(s); stream_putc(s, 0); /* dummy len for now */ - len = strlen(names.nodename); + len = strlen(cmd_hostname_get()); if (len > BGP_MAX_HOSTNAME) len = BGP_MAX_HOSTNAME; stream_putc(s, len); - stream_put(s, names.nodename, len); -#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME - if ((names.domainname[0] != '\0') - && (strcmp(names.domainname, "(none)") != 0)) { - len = strlen(names.domainname); + stream_put(s, cmd_hostname_get(), len); + if (cmd_domainname_get()) { + len = strlen(cmd_domainname_get()); if (len > BGP_MAX_HOSTNAME) len = BGP_MAX_HOSTNAME; stream_putc(s, len); - stream_put(s, names.domainname, len); + stream_put(s, cmd_domainname_get(), len); } else -#endif - { stream_putc(s, 0); /* 0 length */ - } /* Set the lengths straight */ len = stream_get_endp(s) - rcapp - 1; @@ -1478,14 +1471,10 @@ void bgp_open_capability(struct stream *s, struct peer *peer) stream_putc_at(s, capp, len); if (bgp_debug_neighbor_events(peer)) -#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME zlog_debug( "%s Sending hostname cap with hn = %s, dn = %s", - peer->host, names.nodename, names.domainname); -#else - zlog_debug("%s Sending hostname cap with hn = %s", - peer->host, names.nodename); -#endif + peer->host, cmd_hostname_get(), + cmd_domainname_get()); } /* Sending base graceful-restart capability irrespective of the config diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 288271e5a1..f354071654 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1268,6 +1268,39 @@ static void bgp_peer_as_override(struct bgp *bgp, afi_t afi, safi_t safi, } } +void bgp_attr_add_gshut_community(struct attr *attr) +{ + struct community *old; + struct community *new; + struct community *merge; + struct community *gshut; + + old = attr->community; + gshut = community_str2com("graceful-shutdown"); + + if (old) { + merge = community_merge(community_dup(old), gshut); + + if (old->refcnt== 0) + community_free(old); + + new = community_uniq_sort(merge); + community_free(merge); + } else { + new = community_dup(gshut); + } + + community_free(gshut); + attr->community = new; + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); + + /* When we add the graceful-shutdown community we must also + * lower the local-preference */ + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); + attr->local_pref = BGP_GSHUT_LOCAL_PREF; +} + + static void subgroup_announce_reset_nhop(u_char family, struct attr *attr) { if (family == AF_INET) @@ -1624,6 +1657,15 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri, } } + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); + attr->local_pref = BGP_GSHUT_LOCAL_PREF; + } else { + bgp_attr_add_gshut_community(attr); + } + } + /* After route-map has been applied, we check to see if the nexthop to * be carried in the attribute (that is used for the announcement) can * be cleared off or not. We do this in all cases where we would be @@ -2042,9 +2084,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* Do we need to allocate or free labels? * Right now, since we only deal with per-prefix labels, it is not - * necessary - * to do this upon changes to best path except of the label index - * changes. + * necessary to do this upon changes to best path except if the label + * index changes */ if (bgp->allocate_mpls_labels[afi][safi]) { if (new_select) { @@ -2201,18 +2242,22 @@ static wq_item_status bgp_process_wq(struct work_queue *wq, void *data) struct bgp_process_queue *pqnode = data; struct bgp *bgp = pqnode->bgp; struct bgp_table *table; - struct bgp_node *rn, *nrn; + struct bgp_node *rn; /* eoiu marker */ if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)) { bgp_process_main_one(bgp, NULL, 0, 0); - + /* should always have dedicated wq call */ + assert(STAILQ_FIRST(&pqnode->pqueue) == NULL); return WQ_SUCCESS; } - STAILQ_FOREACH_SAFE(rn, &pqnode->pqueue, pq, nrn) { + while (!STAILQ_EMPTY(&pqnode->pqueue)) { + rn = STAILQ_FIRST(&pqnode->pqueue); + STAILQ_REMOVE_HEAD(&pqnode->pqueue, pq); + STAILQ_NEXT(rn, pq) = NULL; /* complete unlink */ table = bgp_node_table(rn); - + /* note, new RNs may be added as part of processing */ bgp_process_main_one(bgp, rn, table->afi, table->safi); bgp_unlock_node(rn); @@ -2251,8 +2296,7 @@ void bgp_process_queue_init(void) bm->process_main_queue->spec.yield = 50 * 1000L; } -static struct bgp_process_queue *bgp_process_queue_work(struct work_queue *wq, - struct bgp *bgp) +static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp) { struct bgp_process_queue *pqnode; @@ -2262,8 +2306,6 @@ static struct bgp_process_queue *bgp_process_queue_work(struct work_queue *wq, pqnode->bgp = bgp_lock(bgp); STAILQ_INIT(&pqnode->pqueue); - work_queue_add(wq, pqnode); - return pqnode; } @@ -2272,6 +2314,7 @@ void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) #define ARBITRARY_PROCESS_QLEN 10000 struct work_queue *wq = bm->process_main_queue; struct bgp_process_queue *pqnode; + int pqnode_reuse = 0; /* already scheduled for processing? */ if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED)) @@ -2288,19 +2331,25 @@ void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) || pqnode->bgp != bgp || pqnode->queued >= ARBITRARY_PROCESS_QLEN) - pqnode = bgp_process_queue_work(wq, bgp); + pqnode = bgp_processq_alloc(bgp); + else + pqnode_reuse = 1; } else - pqnode = bgp_process_queue_work(wq, bgp); - + pqnode = bgp_processq_alloc(bgp); /* all unlocked in bgp_process_wq */ bgp_table_lock(bgp_node_table(rn)); SET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED); bgp_lock_node(rn); + /* can't be enqueued twice */ + assert(STAILQ_NEXT(rn, pq) == NULL); STAILQ_INSERT_TAIL(&pqnode->pqueue, rn, pq); pqnode->queued++; + if (!pqnode_reuse) + work_queue_add(wq, pqnode); + return; } @@ -2311,9 +2360,10 @@ void bgp_add_eoiu_mark(struct bgp *bgp) if (bm->process_main_queue == NULL) return; - pqnode = bgp_process_queue_work(bm->process_main_queue, bgp); + pqnode = bgp_processq_alloc(bgp); SET_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER); + work_queue_add(bm->process_main_queue, pqnode); } static int bgp_maximum_prefix_restart_timer(struct thread *thread) @@ -2425,8 +2475,8 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, /* Unconditionally remove the route from the RIB, without taking * damping into consideration (eg, because the session went down) */ -static void bgp_rib_remove(struct bgp_node *rn, struct bgp_info *ri, - struct peer *peer, afi_t afi, safi_t safi) +void bgp_rib_remove(struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, + afi_t afi, safi_t safi) { bgp_aggregate_decrement(peer->bgp, &rn->p, ri, afi, safi); @@ -2729,6 +2779,22 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, goto filtered; } + if (peer->sort == BGP_PEER_EBGP) { + + /* If we receive the graceful-shutdown community from an eBGP peer we + * must lower local-preference */ + if (new_attr.community && + community_include(new_attr.community, COMMUNITY_GSHUT)) { + new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); + new_attr.local_pref = BGP_GSHUT_LOCAL_PREF; + + /* If graceful-shutdown is configured then add the GSHUT community to + * all paths received from eBGP peers */ + } else if (bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { + bgp_attr_add_gshut_community(&new_attr); + } + } + /* next hop check. */ if (bgp_update_martian_nexthop(bgp, afi, safi, &new_attr)) { reason = "martian or self next-hop;"; @@ -3391,21 +3457,22 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi, for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) for (ain = rn->adj_in; ain; ain = ain->next) { - if (ain->peer == peer) { - struct bgp_info *ri = rn->info; - mpls_label_t label = - (ri && ri->extra) ? ri->extra->label - : MPLS_INVALID_LABEL; + if (ain->peer != peer) + continue; - ret = bgp_update( - peer, &rn->p, ain->addpath_rx_id, - ain->attr, afi, safi, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, prd, &label, 1, NULL); + struct bgp_info *ri = rn->info; + mpls_label_t label = (ri && ri->extra) + ? ri->extra->label + : MPLS_INVALID_LABEL; - if (ret < 0) { - bgp_unlock_node(rn); - return; - } + ret = bgp_update(peer, &rn->p, ain->addpath_rx_id, + ain->attr, afi, safi, ZEBRA_ROUTE_BGP, + BGP_ROUTE_NORMAL, prd, &label, 1, + NULL); + + if (ret < 0) { + bgp_unlock_node(rn); + return; } } } @@ -3454,24 +3521,25 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data) /* It is possible that we have multiple paths for a prefix from a peer * if that peer is using AddPath. */ - for (ri = rn->info; ri; ri = ri->next) - if (ri->peer == peer) { - /* graceful restart STALE flag set. */ - if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT) - && peer->nsf[afi][safi] - && !CHECK_FLAG(ri->flags, BGP_INFO_STALE) - && !CHECK_FLAG(ri->flags, BGP_INFO_UNUSEABLE)) - bgp_info_set_flag(rn, ri, BGP_INFO_STALE); - else { - /* If this is an EVPN route, process for - * un-import. */ - if (safi == SAFI_EVPN) - bgp_evpn_unimport_route(peer->bgp, afi, - safi, &rn->p, - ri); - bgp_rib_remove(rn, ri, peer, afi, safi); - } + for (ri = rn->info; ri; ri = ri->next) { + if (ri->peer != peer) + continue; + + /* graceful restart STALE flag set. */ + if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT) + && peer->nsf[afi][safi] + && !CHECK_FLAG(ri->flags, BGP_INFO_STALE) + && !CHECK_FLAG(ri->flags, BGP_INFO_UNUSEABLE)) + bgp_info_set_flag(rn, ri, BGP_INFO_STALE); + else { + /* If this is an EVPN route, process for + * un-import. */ + if (safi == SAFI_EVPN) + bgp_evpn_unimport_route(peer->bgp, afi, safi, + &rn->p, ri); + bgp_rib_remove(rn, ri, peer, afi, safi); } + } return WQ_SUCCESS; } @@ -3705,34 +3773,33 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) struct bgp_info *ri; /* look for neighbor in tables */ - if ((table = rn->info) != NULL) { - for (rm = bgp_table_top(table); rm; - rm = bgp_route_next(rm)) - for (ri = rm->info; ri; ri = ri->next) - if (ri->peer == peer) { - if (CHECK_FLAG( - ri->flags, - BGP_INFO_STALE)) - bgp_rib_remove( - rm, ri, - peer, - afi, - safi); - break; - } - } + if ((table = rn->info) == NULL) + continue; + + for (rm = bgp_table_top(table); rm; + rm = bgp_route_next(rm)) + for (ri = rm->info; ri; ri = ri->next) { + if (ri->peer != peer) + continue; + if (!CHECK_FLAG(ri->flags, + BGP_INFO_STALE)) + break; + + bgp_rib_remove(rm, ri, peer, afi, safi); + break; + } } } else { for (rn = bgp_table_top(peer->bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) - for (ri = rn->info; ri; ri = ri->next) - if (ri->peer == peer) { - if (CHECK_FLAG(ri->flags, - BGP_INFO_STALE)) - bgp_rib_remove(rn, ri, peer, - afi, safi); + for (ri = rn->info; ri; ri = ri->next) { + if (ri->peer != peer) + continue; + if (!CHECK_FLAG(ri->flags, BGP_INFO_STALE)) break; - } + bgp_rib_remove(rn, ri, peer, afi, safi); + break; + } } } @@ -4048,9 +4115,18 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p, bgp_static_withdraw(bgp, p, afi, safi); return; } + + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) + bgp_attr_add_gshut_community(&attr_tmp); + attr_new = bgp_attr_intern(&attr_tmp); - } else + } else { + + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) + bgp_attr_add_gshut_community(&attr); + attr_new = bgp_attr_intern(&attr); + } for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP @@ -4556,28 +4632,27 @@ void bgp_static_add(struct bgp *bgp) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) for (rn = bgp_table_top(bgp->route[afi][safi]); rn; - rn = bgp_route_next(rn)) - if (rn->info != NULL) { - if ((safi == SAFI_MPLS_VPN) - || (safi == SAFI_ENCAP) - || (safi == SAFI_EVPN)) { - table = rn->info; - - for (rm = bgp_table_top(table); - rm; - rm = bgp_route_next(rm)) { - bgp_static = rm->info; - bgp_static_update_safi( - bgp, &rm->p, - bgp_static, afi, - safi); - } - } else { - bgp_static_update(bgp, &rn->p, - rn->info, afi, - safi); + rn = bgp_route_next(rn)) { + if (rn->info == NULL) + continue; + + if ((safi == SAFI_MPLS_VPN) + || (safi == SAFI_ENCAP) + || (safi == SAFI_EVPN)) { + table = rn->info; + + for (rm = bgp_table_top(table); rm; + rm = bgp_route_next(rm)) { + bgp_static = rm->info; + bgp_static_update_safi( + bgp, &rm->p, bgp_static, + afi, safi); } + } else { + bgp_static_update(bgp, &rn->p, rn->info, + afi, safi); } + } } /* Called from bgp_delete(). Delete all static routes from the BGP @@ -4594,37 +4669,36 @@ void bgp_static_delete(struct bgp *bgp) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) for (rn = bgp_table_top(bgp->route[afi][safi]); rn; - rn = bgp_route_next(rn)) - if (rn->info != NULL) { - if ((safi == SAFI_MPLS_VPN) - || (safi == SAFI_ENCAP) - || (safi == SAFI_EVPN)) { - table = rn->info; - - for (rm = bgp_table_top(table); - rm; - rm = bgp_route_next(rm)) { - bgp_static = rm->info; - bgp_static_withdraw_safi( - bgp, &rm->p, - AFI_IP, safi, - (struct - prefix_rd *)&rn - ->p); - bgp_static_free( - bgp_static); - rn->info = NULL; - bgp_unlock_node(rn); - } - } else { - bgp_static = rn->info; - bgp_static_withdraw(bgp, &rn->p, - afi, safi); + rn = bgp_route_next(rn)) { + if (rn->info == NULL) + continue; + + if ((safi == SAFI_MPLS_VPN) + || (safi == SAFI_ENCAP) + || (safi == SAFI_EVPN)) { + table = rn->info; + + for (rm = bgp_table_top(table); rm; + rm = bgp_route_next(rm)) { + bgp_static = rm->info; + bgp_static_withdraw_safi( + bgp, &rm->p, AFI_IP, + safi, + (struct prefix_rd *)&rn + ->p); bgp_static_free(bgp_static); rn->info = NULL; bgp_unlock_node(rn); } + } else { + bgp_static = rn->info; + bgp_static_withdraw(bgp, &rn->p, afi, + safi); + bgp_static_free(bgp_static); + rn->info = NULL; + bgp_unlock_node(rn); } + } } void bgp_static_redo_import_check(struct bgp *bgp) @@ -4641,29 +4715,29 @@ void bgp_static_redo_import_check(struct bgp *bgp) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) for (rn = bgp_table_top(bgp->route[afi][safi]); rn; - rn = bgp_route_next(rn)) - if (rn->info != NULL) { - if ((safi == SAFI_MPLS_VPN) - || (safi == SAFI_ENCAP) - || (safi == SAFI_EVPN)) { - table = rn->info; - - for (rm = bgp_table_top(table); - rm; - rm = bgp_route_next(rm)) { - bgp_static = rm->info; - bgp_static_update_safi( - bgp, &rm->p, - bgp_static, afi, - safi); - } - } else { - bgp_static = rn->info; - bgp_static_update(bgp, &rn->p, - bgp_static, - afi, safi); + rn = bgp_route_next(rn)) { + if (rn->info == NULL) + continue; + + if ((safi == SAFI_MPLS_VPN) + || (safi == SAFI_ENCAP) + || (safi == SAFI_EVPN)) { + table = rn->info; + + for (rm = bgp_table_top(table); rm; + rm = bgp_route_next(rm)) { + bgp_static = rm->info; + bgp_static_update_safi( + bgp, &rm->p, bgp_static, + afi, safi); } + } else { + bgp_static = rn->info; + bgp_static_update(bgp, &rn->p, + bgp_static, afi, + safi); } + } bgp_flag_unset(bgp, BGP_FLAG_FORCE_STATIC_PROCESS); } @@ -4947,16 +5021,13 @@ static int bgp_table_map_unset(struct vty *vty, afi_t afi, safi_t safi, return CMD_SUCCESS; } -int bgp_config_write_table_map(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi, int *write) +void bgp_config_write_table_map(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) { if (bgp->table_map[afi][safi].name) { - bgp_config_write_family_header(vty, afi, safi, write); vty_out(vty, " table-map %s\n", bgp->table_map[afi][safi].name); } - - return 0; } DEFUN (bgp_table_map, @@ -5687,83 +5758,75 @@ static void bgp_aggregate_add(struct bgp *bgp, struct prefix *p, afi_t afi, /* If routes exists below this node, generate aggregate routes. */ top = bgp_node_get(table, p); for (rn = bgp_node_get(table, p); rn; - rn = bgp_route_next_until(rn, top)) - if (rn->p.prefixlen > p->prefixlen) { - match = 0; + rn = bgp_route_next_until(rn, top)) { + if (rn->p.prefixlen <= p->prefixlen) + continue; - for (ri = rn->info; ri; ri = ri->next) { - if (BGP_INFO_HOLDDOWN(ri)) - continue; + match = 0; - if (ri->attr->flag - & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) - atomic_aggregate = 1; + for (ri = rn->info; ri; ri = ri->next) { + if (BGP_INFO_HOLDDOWN(ri)) + continue; - if (ri->sub_type != BGP_ROUTE_AGGREGATE) { - /* summary-only aggregate route suppress - aggregated - route announcement. */ - if (aggregate->summary_only) { - (bgp_info_extra_get(ri)) - ->suppress++; - bgp_info_set_flag( - rn, ri, - BGP_INFO_ATTR_CHANGED); - match++; - } + if (ri->attr->flag + & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) + atomic_aggregate = 1; - /* If at least one route among routes - * that are aggregated has - * ORIGIN with the value INCOMPLETE, - * then the aggregated route - * MUST have the ORIGIN attribute with - * the value INCOMPLETE. - * Otherwise, if at least one route - * among routes that are - * aggregated has ORIGIN with the value - * EGP, then the aggregated - * route MUST have the ORIGIN attribute - * with the value EGP. - */ - if (origin < ri->attr->origin) - origin = ri->attr->origin; + if (ri->sub_type == BGP_ROUTE_AGGREGATE) + continue; - /* as-set aggregate route generate - origin, as path, - community aggregation. */ - if (aggregate->as_set) { - if (aspath) { - asmerge = aspath_aggregate( - aspath, - ri->attr->aspath); - aspath_free(aspath); - aspath = asmerge; - } else - aspath = aspath_dup( - ri->attr->aspath); + /* summary-only aggregate route suppress + * aggregated route announcement. */ + if (aggregate->summary_only) { + (bgp_info_extra_get(ri))->suppress++; + bgp_info_set_flag(rn, ri, + BGP_INFO_ATTR_CHANGED); + match++; + } - if (ri->attr->community) { - if (community) { - commerge = community_merge( - community, - ri->attr->community); - community = community_uniq_sort( - commerge); - community_free( - commerge); - } else - community = community_dup( - ri->attr->community); - } - } - aggregate->count++; + /* If at least one route among routes that are + * aggregated has ORIGIN with the value INCOMPLETE, + * then the aggregated route MUST have the ORIGIN + * attribute with the value INCOMPLETE. Otherwise, if + * at least one route among routes that are aggregated + * has ORIGIN with the value EGP, then the aggregated + * route MUST have the ORIGIN attribute with the value + * EGP. + */ + if (origin < ri->attr->origin) + origin = ri->attr->origin; + + /* as-set aggregate route generate origin, as path, + * community aggregation. */ + if (aggregate->as_set) { + if (aspath) { + asmerge = aspath_aggregate( + aspath, ri->attr->aspath); + aspath_free(aspath); + aspath = asmerge; + } else + aspath = aspath_dup(ri->attr->aspath); + + if (ri->attr->community) { + if (community) { + commerge = community_merge( + community, + ri->attr->community); + community = community_uniq_sort( + commerge); + community_free(commerge); + } else + community = community_dup( + ri->attr->community); } } - - /* If this node is suppressed, process the change. */ - if (match) - bgp_process(bgp, rn, afi, safi); + aggregate->count++; } + + /* If this node is suppressed, process the change. */ + if (match) + bgp_process(bgp, rn, afi, safi); + } bgp_unlock_node(top); /* Add aggregate route to BGP table. */ @@ -5809,34 +5872,34 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, /* If routes exists below this node, generate aggregate routes. */ top = bgp_node_get(table, p); for (rn = bgp_node_get(table, p); rn; - rn = bgp_route_next_until(rn, top)) - if (rn->p.prefixlen > p->prefixlen) { - match = 0; + rn = bgp_route_next_until(rn, top)) { + if (rn->p.prefixlen <= p->prefixlen) + continue; + match = 0; - for (ri = rn->info; ri; ri = ri->next) { - if (BGP_INFO_HOLDDOWN(ri)) - continue; + for (ri = rn->info; ri; ri = ri->next) { + if (BGP_INFO_HOLDDOWN(ri)) + continue; - if (ri->sub_type != BGP_ROUTE_AGGREGATE) { - if (aggregate->summary_only - && ri->extra) { - ri->extra->suppress--; - - if (ri->extra->suppress == 0) { - bgp_info_set_flag( - rn, ri, - BGP_INFO_ATTR_CHANGED); - match++; - } - } - aggregate->count--; + if (ri->sub_type == BGP_ROUTE_AGGREGATE) + continue; + + if (aggregate->summary_only && ri->extra) { + ri->extra->suppress--; + + if (ri->extra->suppress == 0) { + bgp_info_set_flag( + rn, ri, BGP_INFO_ATTR_CHANGED); + match++; } } - - /* If this node was suppressed, process the change. */ - if (match) - bgp_process(bgp, rn, afi, safi); + aggregate->count--; } + + /* If this node was suppressed, process the change. */ + if (match) + bgp_process(bgp, rn, afi, safi); + } bgp_unlock_node(top); /* Delete aggregate route from BGP table. */ @@ -6158,6 +6221,9 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, } } + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) + bgp_attr_add_gshut_community(&attr_new); + bn = bgp_afi_node_get(bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST, p, NULL); @@ -6270,46 +6336,66 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type, } /* Static function to display route. */ -static void route_vty_out_route(struct prefix *p, struct vty *vty) +static void route_vty_out_route(struct prefix *p, struct vty *vty, + json_object *json) { int len; u_int32_t destination; char buf[BUFSIZ]; if (p->family == AF_INET) { - len = vty_out(vty, "%s", - inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ)); - destination = ntohl(p->u.prefix4.s_addr); - - if ((IN_CLASSC(destination) && p->prefixlen == 24) - || (IN_CLASSB(destination) && p->prefixlen == 16) - || (IN_CLASSA(destination) && p->prefixlen == 8) - || p->u.prefix4.s_addr == 0) { - /* When mask is natural, mask is not displayed. */ - } else - len += vty_out(vty, "/%d", p->prefixlen); + if (!json) { + len = vty_out(vty, "%s", + inet_ntop(p->family, &p->u.prefix, buf, + BUFSIZ)); + destination = ntohl(p->u.prefix4.s_addr); + + if ((IN_CLASSC(destination) && p->prefixlen == 24) + || (IN_CLASSB(destination) && p->prefixlen == 16) + || (IN_CLASSA(destination) && p->prefixlen == 8) + || p->u.prefix4.s_addr == 0) { + /* When mask is natural, + mask is not displayed. */ + } else + len += vty_out(vty, "/%d", p->prefixlen); + } else { + json_object_string_add(json, "prefix", + inet_ntop(p->family, + &p->u.prefix, buf, + BUFSIZ)); + json_object_int_add(json, "prefixLen", p->prefixlen); + } } else if (p->family == AF_ETHERNET) { prefix2str(p, buf, PREFIX_STRLEN); len = vty_out(vty, "%s", buf); } else if (p->family == AF_EVPN) { #if defined(HAVE_CUMULUS) - len = vty_out(vty, "%s", - bgp_evpn_route2str((struct prefix_evpn *)p, buf, - BUFSIZ)); + if (!json) + len = vty_out( + vty, "%s", + bgp_evpn_route2str((struct prefix_evpn *)p, buf, + BUFSIZ)); + else + bgp_evpn_route2json((struct prefix_evpn *)p, json); #else prefix2str(p, buf, PREFIX_STRLEN); len = vty_out(vty, "%s", buf); #endif - } else - len = vty_out(vty, "%s/%d", - inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), - p->prefixlen); + } else { + if (!json) + len = vty_out( + vty, "%s/%d", + inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + } - len = 17 - len; - if (len < 1) - vty_out(vty, "\n%*s", 20, " "); - else - vty_out(vty, "%*s", len, " "); + if (!json) { + len = 17 - len; + if (len < 1) + vty_out(vty, "\n%*s", 20, " "); + else + vty_out(vty, "%*s", len, " "); + } } enum bgp_display_type { @@ -6413,9 +6499,11 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo, if (!json_paths) { /* print prefix and mask */ if (!display) - route_vty_out_route(p, vty); + route_vty_out_route(p, vty, json_path); else vty_out(vty, "%*s", 17, " "); + } else { + route_vty_out_route(p, vty, json_path); } /* Print attribute */ @@ -6711,7 +6799,7 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr, json_net, "addrPrefix", inet_ntop(p->family, &p->u.prefix, buff, BUFSIZ)); else - route_vty_out_route(p, vty); + route_vty_out_route(p, vty, NULL); /* Print attribute */ if (attr) { @@ -6844,7 +6932,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p, /* print prefix and mask */ if (json == NULL) { if (!display) - route_vty_out_route(p, vty); + route_vty_out_route(p, vty, NULL); else vty_out(vty, "%*s", 17, " "); } @@ -6959,7 +7047,7 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p, /* print prefix and mask */ if (!display) - route_vty_out_route(p, vty); + route_vty_out_route(p, vty, NULL); else vty_out(vty, "%*s", 17, " "); @@ -7028,7 +7116,7 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p, /* print prefix and mask */ if (!use_json) { if (!display) - route_vty_out_route(p, vty); + route_vty_out_route(p, vty, NULL); else vty_out(vty, "%*s", 17, " "); } @@ -7097,7 +7185,7 @@ static void flap_route_vty_out(struct vty *vty, struct prefix *p, /* print prefix and mask */ if (!use_json) { if (!display) - route_vty_out_route(p, vty); + route_vty_out_route(p, vty, NULL); else vty_out(vty, "%*s", 17, " "); } @@ -8026,8 +8114,8 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp, static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr, afi_t afi, safi_t safi, enum bgp_show_type type); -static int bgp_show_community(struct vty *vty, struct bgp *bgp, int argc, - struct cmd_token **argv, int exact, afi_t afi, +static int bgp_show_community(struct vty *vty, struct bgp *bgp, + const char *comstr, int exact, afi_t afi, safi_t safi); static int bgp_show_table(struct vty *vty, struct bgp *bgp, @@ -8380,6 +8468,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, #if defined(HAVE_CUMULUS) char buf3[EVPN_ROUTE_STRLEN]; #endif + char prefix_str[BUFSIZ]; int count = 0; int best = 0; int suppress = 0; @@ -8401,10 +8490,9 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, if (has_valid_label) json_object_int_add(json, "localLabel", label); - json_object_string_add(json, "prefix", - inet_ntop(p->family, &p->u.prefix, buf2, - INET6_ADDRSTRLEN)); - json_object_int_add(json, "prefixlen", p->prefixlen); + json_object_string_add( + json, "prefix", + prefix2str(p, prefix_str, sizeof(prefix_str))); } else { #if defined(HAVE_CUMULUS) if (safi == SAFI_EVPN) @@ -8564,55 +8652,45 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) continue; - if ((table = rn->info) != NULL) { - header = 1; - - if ((rm = bgp_node_match(table, &match)) - != NULL) { - if (prefix_check - && rm->p.prefixlen - != match.prefixlen) { - bgp_unlock_node(rm); - continue; - } + if ((table = rn->info) == NULL) + continue; - for (ri = rm->info; ri; ri = ri->next) { - if (header) { - route_vty_out_detail_header( - vty, bgp, rm, - (struct - prefix_rd *)&rn - ->p, - AFI_IP, safi, - json); - header = 0; - } - display++; - - if (pathtype == BGP_PATH_ALL - || (pathtype - == BGP_PATH_BESTPATH - && CHECK_FLAG( - ri->flags, - BGP_INFO_SELECTED)) - || (pathtype - == BGP_PATH_MULTIPATH - && (CHECK_FLAG( - ri->flags, - BGP_INFO_MULTIPATH) - || CHECK_FLAG( - ri->flags, - BGP_INFO_SELECTED)))) - route_vty_out_detail( - vty, bgp, - &rm->p, ri, - AFI_IP, safi, - json_paths); - } + header = 1; - bgp_unlock_node(rm); + if ((rm = bgp_node_match(table, &match)) == NULL) + continue; + + if (prefix_check + && rm->p.prefixlen != match.prefixlen) { + bgp_unlock_node(rm); + continue; + } + + for (ri = rm->info; ri; ri = ri->next) { + if (header) { + route_vty_out_detail_header( + vty, bgp, rm, + (struct prefix_rd *)&rn->p, + AFI_IP, safi, json); + header = 0; } + display++; + + if (pathtype == BGP_PATH_ALL + || (pathtype == BGP_PATH_BESTPATH + && CHECK_FLAG(ri->flags, + BGP_INFO_SELECTED)) + || (pathtype == BGP_PATH_MULTIPATH + && (CHECK_FLAG(ri->flags, + BGP_INFO_MULTIPATH) + || CHECK_FLAG(ri->flags, + BGP_INFO_SELECTED)))) + route_vty_out_detail(vty, bgp, &rm->p, + ri, AFI_IP, safi, + json_paths); } + + bgp_unlock_node(rm); } } else { header = 1; @@ -8852,7 +8930,7 @@ DEFUN (show_ip_bgp, |prefix-list WORD\ |filter-list WORD\ |statistics\ - |community <AA:NN|local-AS|no-advertise|no-export> [exact-match]\ + |community <AA:NN|local-AS|no-advertise|no-export|graceful-shutdown> [exact-match]\ |community-list <(1-500)|WORD> [exact-match]\ |A.B.C.D/M longer-prefixes\ |X:X::X:X/M longer-prefixes\ @@ -8877,6 +8955,7 @@ DEFUN (show_ip_bgp, "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" + "Graceful shutdown (well-known community)\n" "Exact match of the communities\n" "Display routes matching the community-list\n" "community-list number\n" @@ -8892,6 +8971,7 @@ DEFUN (show_ip_bgp, int exact_match = 0; struct bgp *bgp = NULL; int idx = 0; + int idx_community_type = 0; bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, &bgp); @@ -8920,12 +9000,15 @@ DEFUN (show_ip_bgp, if (argv_find(argv, argc, "community", &idx)) { /* show a specific community */ - if (argv_find(argv, argc, "local-AS", &idx) - || argv_find(argv, argc, "no-advertise", &idx) - || argv_find(argv, argc, "no-export", &idx)) { - if (argv_find(argv, argc, "exact_match", &idx)) + if (argv_find(argv, argc, "local-AS", &idx_community_type) + || argv_find(argv, argc, "no-advertise", &idx_community_type) + || argv_find(argv, argc, "no-export", &idx_community_type) + || argv_find(argv, argc, "graceful-shutdown", &idx_community_type) + || argv_find(argv, argc, "AA:NN", &idx_community_type)) { + + if (argv_find(argv, argc, "exact-match", &idx)) exact_match = 1; - return bgp_show_community(vty, bgp, argc, argv, + return bgp_show_community(vty, bgp, argv[idx_community_type]->arg, exact_match, afi, safi); } } @@ -9213,39 +9296,16 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp, return bgp_show(vty, bgp, afi, safi, type, rmap, 0); } -static int bgp_show_community(struct vty *vty, struct bgp *bgp, int argc, - struct cmd_token **argv, int exact, afi_t afi, +static int bgp_show_community(struct vty *vty, struct bgp *bgp, + const char *comstr, int exact, afi_t afi, safi_t safi) { struct community *com; - struct buffer *b; - int i; - char *str; - int first = 0; int ret = 0; - b = buffer_new(1024); - for (i = 0; i < argc; i++) { - if (first) - buffer_putc(b, ' '); - else { - if (strmatch(argv[i]->text, "unicast") - || strmatch(argv[i]->text, "multicast")) - continue; - first = 1; - } - - buffer_putstr(b, argv[i]->arg); - } - buffer_putc(b, '\0'); - - str = buffer_getstr(b); - buffer_free(b); - - com = community_str2com(str); - XFREE(MTYPE_TMP, str); + com = community_str2com(comstr); if (!com) { - vty_out(vty, "%% Community malformed: \n"); + vty_out(vty, "%% Community malformed: %s\n", comstr); return CMD_WARNING; } @@ -9998,60 +10058,54 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { if (in) { for (ain = rn->adj_in; ain; ain = ain->next) { - if (ain->peer == peer) { - if (header1) { - if (use_json) { - json_object_int_add( - json, - "bgpTableVersion", - 0); - json_object_string_add( - json, - "bgpLocalRouterId", - inet_ntoa( - bgp->router_id)); - json_object_object_add( - json, - "bgpStatusCodes", - json_scode); - json_object_object_add( - json, - "bgpOriginCodes", - json_ocode); - } else { - vty_out(vty, - "BGP table version is 0, local router ID is %s\n", - inet_ntoa( - bgp->router_id)); - vty_out(vty, - BGP_SHOW_SCODE_HEADER); - vty_out(vty, - BGP_SHOW_OCODE_HEADER); - } - header1 = 0; - } - if (header2) { - if (!use_json) - vty_out(vty, - BGP_SHOW_HEADER); - header2 = 0; - } - if (ain->attr) { - bgp_attr_dup(&attr, ain->attr); - if (bgp_input_modifier( - peer, &rn->p, &attr, - afi, safi, - rmap_name) - != RMAP_DENY) { - route_vty_out_tmp( - vty, &rn->p, - &attr, safi, - use_json, - json_ar); - output_count++; - } else - filtered_count++; + if (ain->peer != peer) + continue; + if (header1) { + if (use_json) { + json_object_int_add( + json, "bgpTableVersion", + 0); + json_object_string_add( + json, + "bgpLocalRouterId", + inet_ntoa( + bgp->router_id)); + json_object_object_add( + json, "bgpStatusCodes", + json_scode); + json_object_object_add( + json, "bgpOriginCodes", + json_ocode); + } else { + vty_out(vty, + "BGP table version is 0, local router ID is %s\n", + inet_ntoa( + bgp->router_id)); + vty_out(vty, + BGP_SHOW_SCODE_HEADER); + vty_out(vty, + BGP_SHOW_OCODE_HEADER); } + header1 = 0; + } + if (header2) { + if (!use_json) + vty_out(vty, BGP_SHOW_HEADER); + header2 = 0; + } + if (ain->attr) { + bgp_attr_dup(&attr, ain->attr); + if (bgp_input_modifier(peer, &rn->p, + &attr, afi, safi, + rmap_name) + != RMAP_DENY) { + route_vty_out_tmp(vty, &rn->p, + &attr, safi, + use_json, + json_ar); + output_count++; + } else + filtered_count++; } } } else { @@ -10338,10 +10392,6 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer, return CMD_WARNING; } - /* labeled-unicast routes live in the unicast table */ - if (safi == SAFI_LABELED_UNICAST) - safi = SAFI_UNICAST; - return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, use_json); } @@ -10859,32 +10909,27 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, rn = bgp_route_next(rn)) { if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) continue; + if ((table = rn->info) == NULL) + continue; + if ((rm = bgp_node_match(table, &match)) == NULL) + continue; - if ((table = rn->info) != NULL) - if ((rm = bgp_node_match(table, &match)) - != NULL) { - if (!prefix_check - || rm->p.prefixlen - == match.prefixlen) { - ri = rm->info; - while (ri) { - if (ri->extra - && ri->extra - ->damp_info) { - ri_temp = - ri->next; - bgp_damp_info_free( - ri->extra - ->damp_info, - 1); - ri = ri_temp; - } else - ri = ri->next; - } - } - - bgp_unlock_node(rm); + if (!prefix_check + || rm->p.prefixlen == match.prefixlen) { + ri = rm->info; + while (ri) { + if (ri->extra && ri->extra->damp_info) { + ri_temp = ri->next; + bgp_damp_info_free( + ri->extra->damp_info, + 1); + ri = ri_temp; + } else + ri = ri->next; } + } + + bgp_unlock_node(rm); } } else { if ((rn = bgp_node_match(bgp->rib[afi][safi], &match)) @@ -10978,8 +11023,8 @@ DEFUN (clear_ip_bgp_dampening_address_mask, } /* also used for encap safi */ -static int bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp, - afi_t afi, safi_t safi, int *write) +static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi) { struct bgp_node *prn; struct bgp_node *rn; @@ -10993,48 +11038,42 @@ static int bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp, /* Network configuration. */ for (prn = bgp_table_top(bgp->route[afi][safi]); prn; - prn = bgp_route_next(prn)) - if ((table = prn->info) != NULL) - for (rn = bgp_table_top(table); rn; - rn = bgp_route_next(rn)) - if ((bgp_static = rn->info) != NULL) { - p = &rn->p; - prd = (struct prefix_rd *)&prn->p; + prn = bgp_route_next(prn)) { + if ((table = prn->info) == NULL) + continue; - /* "address-family" display. */ - bgp_config_write_family_header( - vty, afi, safi, write); + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + if ((bgp_static = rn->info) == NULL) + continue; - /* "network" configuration display. */ - prefix_rd2str(prd, rdbuf, - RD_ADDRSTRLEN); - label = decode_label( - &bgp_static->label); + p = &rn->p; + prd = (struct prefix_rd *)&prn->p; - vty_out(vty, " network %s/%d rd %s", - inet_ntop(p->family, - &p->u.prefix, buf, - SU_ADDRSTRLEN), - p->prefixlen, rdbuf); - if (safi == SAFI_MPLS_VPN) - vty_out(vty, " label %u", - label); - - if (bgp_static->rmap.name) - vty_out(vty, " route-map %s", - bgp_static->rmap.name); - else { - if (bgp_static->backdoor) - vty_out(vty, - " backdoor"); - } - vty_out(vty, "\n"); - } - return 0; + /* "network" configuration display. */ + prefix_rd2str(prd, rdbuf, RD_ADDRSTRLEN); + label = decode_label(&bgp_static->label); + + vty_out(vty, " network %s/%d rd %s", + inet_ntop(p->family, &p->u.prefix, buf, + SU_ADDRSTRLEN), + p->prefixlen, rdbuf); + if (safi == SAFI_MPLS_VPN) + vty_out(vty, " label %u", label); + + if (bgp_static->rmap.name) + vty_out(vty, " route-map %s", + bgp_static->rmap.name); + else { + if (bgp_static->backdoor) + vty_out(vty, " backdoor"); + } + vty_out(vty, "\n"); + } + } } -static int bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, - afi_t afi, safi_t safi, int *write) +static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi) { struct bgp_node *prn; struct bgp_node *rn; @@ -11048,59 +11087,50 @@ static int bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, /* Network configuration. */ for (prn = bgp_table_top(bgp->route[afi][safi]); prn; - prn = bgp_route_next(prn)) - if ((table = prn->info) != NULL) - for (rn = bgp_table_top(table); rn; - rn = bgp_route_next(rn)) - if ((bgp_static = rn->info) != NULL) { - char *macrouter = NULL; - char *esi = NULL; - - if (bgp_static->router_mac) - macrouter = prefix_mac2str( - bgp_static->router_mac, - NULL, 0); - if (bgp_static->eth_s_id) - esi = esi2str( - bgp_static->eth_s_id); - p = &rn->p; - prd = (struct prefix_rd *)&prn->p; + prn = bgp_route_next(prn)) { + if ((table = prn->info) == NULL) + continue; - /* "address-family" display. */ - bgp_config_write_family_header( - vty, afi, safi, write); + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + if ((bgp_static = rn->info) == NULL) + continue; - /* "network" configuration display. */ - prefix_rd2str(prd, rdbuf, - RD_ADDRSTRLEN); + char *macrouter = NULL; + char *esi = NULL; - inet_ntop(AF_INET, - &bgp_static->igpnexthop, buf2, - SU_ADDRSTRLEN); + if (bgp_static->router_mac) + macrouter = prefix_mac2str( + bgp_static->router_mac, NULL, 0); + if (bgp_static->eth_s_id) + esi = esi2str(bgp_static->eth_s_id); + p = &rn->p; + prd = (struct prefix_rd *)&prn->p; - prefix2str(p, buf, sizeof(buf)), - vty_out(vty, - " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s", - buf, rdbuf, - p->u.prefix_evpn - .eth_tag, - decode_label( - &bgp_static - ->label), - esi, buf2, macrouter); - vty_out(vty, "\n"); - if (macrouter) - XFREE(MTYPE_TMP, macrouter); - if (esi) - XFREE(MTYPE_TMP, esi); - } - return 0; + /* "network" configuration display. */ + prefix_rd2str(prd, rdbuf, RD_ADDRSTRLEN); + + inet_ntop(AF_INET, &bgp_static->igpnexthop, buf2, + SU_ADDRSTRLEN); + + prefix2str(p, buf, sizeof(buf)); + vty_out(vty, + " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s\n", + buf, rdbuf, p->u.prefix_evpn.eth_tag, + decode_label(&bgp_static->label), esi, buf2, + macrouter); + + if (macrouter) + XFREE(MTYPE_TMP, macrouter); + if (esi) + XFREE(MTYPE_TMP, esi); + } + } } /* Configuration of static route announcement and aggregate information. */ -int bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi, int *write) +void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) { struct bgp_node *rn; struct prefix *p; @@ -11108,106 +11138,98 @@ int bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, struct bgp_aggregate *bgp_aggregate; char buf[SU_ADDRSTRLEN]; - if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) - return bgp_config_write_network_vpn(vty, bgp, afi, safi, write); + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) { + bgp_config_write_network_vpn(vty, bgp, afi, safi); + return; + } - if (afi == AFI_L2VPN && safi == SAFI_EVPN) - return bgp_config_write_network_evpn(vty, bgp, afi, safi, - write); + if (afi == AFI_L2VPN && safi == SAFI_EVPN) { + bgp_config_write_network_evpn(vty, bgp, afi, safi); + return; + } /* Network configuration. */ for (rn = bgp_table_top(bgp->route[afi][safi]); rn; - rn = bgp_route_next(rn)) - if ((bgp_static = rn->info) != NULL) { - p = &rn->p; + rn = bgp_route_next(rn)) { + if ((bgp_static = rn->info) == NULL) + continue; - /* "address-family" display. */ - bgp_config_write_family_header(vty, afi, safi, write); + p = &rn->p; - /* "network" configuration display. */ - if (bgp_option_check(BGP_OPT_CONFIG_CISCO) - && afi == AFI_IP) { - u_int32_t destination; - struct in_addr netmask; - - destination = ntohl(p->u.prefix4.s_addr); - masklen2ip(p->prefixlen, &netmask); - vty_out(vty, " network %s", - inet_ntop(p->family, &p->u.prefix, buf, - SU_ADDRSTRLEN)); - - if ((IN_CLASSC(destination) - && p->prefixlen == 24) - || (IN_CLASSB(destination) - && p->prefixlen == 16) - || (IN_CLASSA(destination) - && p->prefixlen == 8) - || p->u.prefix4.s_addr == 0) { - /* Natural mask is not display. */ - } else - vty_out(vty, " mask %s", - inet_ntoa(netmask)); - } else { - vty_out(vty, " network %s/%d", - inet_ntop(p->family, &p->u.prefix, buf, - SU_ADDRSTRLEN), - p->prefixlen); - } + /* "network" configuration display. */ + if (bgp_option_check(BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) { + u_int32_t destination; + struct in_addr netmask; - if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX) - vty_out(vty, " label-index %u", - bgp_static->label_index); + destination = ntohl(p->u.prefix4.s_addr); + masklen2ip(p->prefixlen, &netmask); + vty_out(vty, " network %s", + inet_ntop(p->family, &p->u.prefix, buf, + SU_ADDRSTRLEN)); - if (bgp_static->rmap.name) - vty_out(vty, " route-map %s", - bgp_static->rmap.name); - else { - if (bgp_static->backdoor) - vty_out(vty, " backdoor"); - } + if ((IN_CLASSC(destination) && p->prefixlen == 24) + || (IN_CLASSB(destination) && p->prefixlen == 16) + || (IN_CLASSA(destination) && p->prefixlen == 8) + || p->u.prefix4.s_addr == 0) { + /* Natural mask is not display. */ + } else + vty_out(vty, " mask %s", inet_ntoa(netmask)); + } else { + vty_out(vty, " network %s/%d", + inet_ntop(p->family, &p->u.prefix, buf, + SU_ADDRSTRLEN), + p->prefixlen); + } - vty_out(vty, "\n"); + if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX) + vty_out(vty, " label-index %u", + bgp_static->label_index); + + if (bgp_static->rmap.name) + vty_out(vty, " route-map %s", bgp_static->rmap.name); + else { + if (bgp_static->backdoor) + vty_out(vty, " backdoor"); } + vty_out(vty, "\n"); + } + /* Aggregate-address configuration. */ for (rn = bgp_table_top(bgp->aggregate[afi][safi]); rn; - rn = bgp_route_next(rn)) - if ((bgp_aggregate = rn->info) != NULL) { - p = &rn->p; - - /* "address-family" display. */ - bgp_config_write_family_header(vty, afi, safi, write); + rn = bgp_route_next(rn)) { + if ((bgp_aggregate = rn->info) == NULL) + continue; - if (bgp_option_check(BGP_OPT_CONFIG_CISCO) - && afi == AFI_IP) { - struct in_addr netmask; + p = &rn->p; - masklen2ip(p->prefixlen, &netmask); - vty_out(vty, " aggregate-address %s %s", - inet_ntop(p->family, &p->u.prefix, buf, - SU_ADDRSTRLEN), - inet_ntoa(netmask)); - } else { - vty_out(vty, " aggregate-address %s/%d", - inet_ntop(p->family, &p->u.prefix, buf, - SU_ADDRSTRLEN), - p->prefixlen); - } + if (bgp_option_check(BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) { + struct in_addr netmask; - if (bgp_aggregate->as_set) - vty_out(vty, " as-set"); + masklen2ip(p->prefixlen, &netmask); + vty_out(vty, " aggregate-address %s %s", + inet_ntop(p->family, &p->u.prefix, buf, + SU_ADDRSTRLEN), + inet_ntoa(netmask)); + } else { + vty_out(vty, " aggregate-address %s/%d", + inet_ntop(p->family, &p->u.prefix, buf, + SU_ADDRSTRLEN), + p->prefixlen); + } - if (bgp_aggregate->summary_only) - vty_out(vty, " summary-only"); + if (bgp_aggregate->as_set) + vty_out(vty, " as-set"); - vty_out(vty, "\n"); - } + if (bgp_aggregate->summary_only) + vty_out(vty, " summary-only"); - return 0; + vty_out(vty, "\n"); + } } -int bgp_config_write_distance(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi, int *write) +void bgp_config_write_distance(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) { struct bgp_node *rn; struct bgp_distance *bdistance; @@ -11219,7 +11241,6 @@ int bgp_config_write_distance(struct vty *vty, struct bgp *bgp, afi_t afi, || bgp->distance_ibgp[afi][safi] != ZEBRA_IBGP_DISTANCE_DEFAULT || bgp->distance_local[afi][safi] != ZEBRA_IBGP_DISTANCE_DEFAULT)) { - bgp_config_write_family_header(vty, afi, safi, write); vty_out(vty, " distance bgp %d %d %d\n", bgp->distance_ebgp[afi][safi], bgp->distance_ibgp[afi][safi], @@ -11231,15 +11252,12 @@ int bgp_config_write_distance(struct vty *vty, struct bgp *bgp, afi_t afi, if ((bdistance = rn->info) != NULL) { char buf[PREFIX_STRLEN]; - bgp_config_write_family_header(vty, afi, safi, write); vty_out(vty, " distance %d %s %s\n", bdistance->distance, prefix2str(&rn->p, buf, sizeof(buf)), bdistance->access_list ? bdistance->access_list : ""); } - - return *write; } /* Allocate routing table structure and install commands. */ diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 55f812d4a0..6caa1c8939 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -294,6 +294,8 @@ static inline int bgp_fibupd_safi(safi_t safi) } /* Prototypes. */ +extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_info *ri, + struct peer *peer, afi_t afi, safi_t safi); extern void bgp_process_queue_init(void); extern void bgp_route_init(void); extern void bgp_route_finish(void); @@ -367,12 +369,11 @@ extern void bgp_process(struct bgp *, struct bgp_node *, afi_t, safi_t); * queue element with NULL bgp node. */ extern void bgp_add_eoiu_mark(struct bgp *); -extern int bgp_config_write_table_map(struct vty *, struct bgp *, afi_t, safi_t, - int *); -extern int bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t, - int *); -extern int bgp_config_write_distance(struct vty *, struct bgp *, afi_t, safi_t, - int *); +extern void bgp_config_write_table_map(struct vty *, struct bgp *, afi_t, + safi_t); +extern void bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t); +extern void bgp_config_write_distance(struct vty *, struct bgp *, afi_t, + safi_t); extern void bgp_aggregate_increment(struct bgp *, struct prefix *, struct bgp_info *, afi_t, safi_t); @@ -423,6 +424,7 @@ extern void bgp_info_restore(struct bgp_node *, struct bgp_info *); extern int bgp_info_cmp_compatible(struct bgp *, struct bgp_info *, struct bgp_info *, char *pfx_buf, afi_t afi, safi_t safi); +extern void bgp_attr_add_gshut_community(struct attr *attr); extern void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn, struct bgp_maxpaths_cfg *mpath_cfg, diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 5a5d2a5d5d..f5663e9262 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -658,8 +658,10 @@ static void *route_match_vni_compile(const char *arg) return NULL; *vni = strtoul(arg, &end, 10); - if (*end != '\0') + if (*end != '\0') { + XFREE(MTYPE_ROUTE_MAP_COMPILED, vni); return NULL; + } return vni; } @@ -1491,18 +1493,19 @@ static route_map_result_t route_set_community(void *rule, struct prefix *prefix, if (rcs->additive && old) { merge = community_merge(community_dup(old), rcs->com); - /* HACK: if the old community is not intern'd, - * we should free it here, or all reference to it may be - * lost. - * Really need to cleanup attribute caching sometime. - */ - if (old->refcnt == 0) - community_free(old); new = community_uniq_sort(merge); community_free(merge); } else new = community_dup(rcs->com); + /* HACK: if the old community is not intern'd, + * we should free it here, or all reference to it may be + * lost. + * Really need to cleanup attribute caching sometime. + */ + if (old && old->refcnt == 0) + community_free(old); + /* will be interned by caller if required */ attr->community = new; @@ -1527,7 +1530,7 @@ static void *route_set_community_compile(const char *arg) sp = strstr(arg, "additive"); if (sp && sp > arg) { - /* "additive" keyworkd is included. */ + /* "additive" keyword is included. */ additive = 1; *(sp - 1) = '\0'; } @@ -1608,18 +1611,19 @@ static route_map_result_t route_set_lcommunity(void *rule, merge = lcommunity_merge(lcommunity_dup(old), rcs->lcom); - /* HACK: if the old large-community is not intern'd, - * we should free it here, or all reference to it may be - * lost. - * Really need to cleanup attribute caching sometime. - */ - if (old->refcnt == 0) - lcommunity_free(&old); new = lcommunity_uniq_sort(merge); lcommunity_free(&merge); } else new = lcommunity_dup(rcs->lcom); + /* HACK: if the old large-community is not intern'd, + * we should free it here, or all reference to it may be + * lost. + * Really need to cleanup attribute caching sometime. + */ + if (old && old->refcnt == 0) + lcommunity_free(&old); + /* will be intern()'d or attr_flush()'d by bgp_update_main() */ attr->lcommunity = new; @@ -2669,25 +2673,27 @@ static int bgp_route_match_add(struct vty *vty, const char *command, const char *arg, route_map_event_t type) { VTY_DECLVAR_CONTEXT(route_map_index, index); + int retval = CMD_SUCCESS; int ret; ret = route_map_add_match(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% BGP Can't find rule.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% BGP Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% BGP Can't find rule.\n"); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, "%% BGP Argument is malformed.\n"); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + if (type != RMAP_EVENT_MATCH_ADDED) { + route_map_upd8_dependency(type, arg, index->map->name); } + break; } - if (type != RMAP_EVENT_MATCH_ADDED) { - route_map_upd8_dependency(type, arg, index->map->name); - } - - return CMD_SUCCESS; + return retval; } /* Delete bgp route map rule. */ @@ -2696,6 +2702,7 @@ static int bgp_route_match_delete(struct vty *vty, const char *command, { VTY_DECLVAR_CONTEXT(route_map_index, index); int ret; + int retval = CMD_SUCCESS; char *dep_name = NULL; const char *tmpstr; char *rmap_name = NULL; @@ -2714,31 +2721,27 @@ static int bgp_route_match_delete(struct vty *vty, const char *command, } ret = route_map_delete_match(index, command, dep_name); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% BGP Can't find rule.\n"); - break; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% BGP Argument is malformed.\n"); - break; - } - if (dep_name) - XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); - if (rmap_name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); - return CMD_WARNING_CONFIG_FAILED; + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% BGP Can't find rule.\n"); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, "%% BGP Argument is malformed.\n"); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + if (type != RMAP_EVENT_MATCH_DELETED && dep_name) + route_map_upd8_dependency(type, dep_name, rmap_name); + break; } - if (type != RMAP_EVENT_MATCH_DELETED && dep_name) - route_map_upd8_dependency(type, dep_name, rmap_name); - if (dep_name) XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); if (rmap_name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); - return CMD_SUCCESS; + return retval; } /* @@ -3768,6 +3771,11 @@ DEFUN (set_community, buffer_putstr(b, "no-export"); continue; } + if (strncmp(argv[i]->arg, "graceful-shutdown", strlen(argv[i]->arg)) + == 0) { + buffer_putstr(b, "graceful-shutdown"); + continue; + } buffer_putstr(b, argv[i]->arg); } buffer_putc(b, '\0'); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 0a33fa5ed4..1bd6fb8b3d 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -691,6 +691,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); aspath = attr.aspath; + attr.local_pref = bgp->default_local_pref; if (afi == AFI_IP) @@ -749,6 +750,11 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) } else { if (!CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE)) { + + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { + bgp_attr_add_gshut_community(&attr); + } + SET_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE); subgroup_default_update_packet(subgrp, &attr, from); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index f040ed9a08..a29b7f7bec 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1279,7 +1279,7 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty) return CMD_SUCCESS; } -int bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp) +void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp) { if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) { vty_out(vty, " update-delay %d", bgp->v_update_delay); @@ -1287,8 +1287,6 @@ int bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp) vty_out(vty, " %d", bgp->v_establish_wait); vty_out(vty, "\n"); } - - return 0; } @@ -1342,12 +1340,10 @@ static int bgp_wpkt_quanta_config_vty(struct vty *vty, const char *num, return CMD_SUCCESS; } -int bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp) +void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp) { if (bgp->wpkt_quanta != BGP_WRITE_PACKET_MAX) vty_out(vty, " write-quanta %d\n", bgp->wpkt_quanta); - - return 0; } @@ -1374,12 +1370,10 @@ DEFUN (no_bgp_wpkt_quanta, return bgp_wpkt_quanta_config_vty(vty, argv[idx_number]->arg, 0); } -int bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp) +void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp) { if (bgp->coalesce_time != BGP_DEFAULT_SUBGROUP_COALESCE_TIME) vty_out(vty, " coalesce-time %u\n", bgp->coalesce_time); - - return 0; } @@ -1503,17 +1497,15 @@ ALIAS_HIDDEN(no_bgp_maxpaths_ibgp, no_bgp_maxpaths_ibgp_hidden_cmd, "Number of paths\n" "Match the cluster length\n") -int bgp_config_write_maxpaths(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi, int *write) +void bgp_config_write_maxpaths(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) { if (bgp->maxpaths[afi][safi].maxpaths_ebgp != MULTIPATH_NUM) { - bgp_config_write_family_header(vty, afi, safi, write); vty_out(vty, " maximum-paths %d\n", bgp->maxpaths[afi][safi].maxpaths_ebgp); } if (bgp->maxpaths[afi][safi].maxpaths_ibgp != MULTIPATH_NUM) { - bgp_config_write_family_header(vty, afi, safi, write); vty_out(vty, " maximum-paths ibgp %d", bgp->maxpaths[afi][safi].maxpaths_ibgp); if (CHECK_FLAG(bgp->maxpaths[afi][safi].ibgp_flags, @@ -1521,8 +1513,6 @@ int bgp_config_write_maxpaths(struct vty *vty, struct bgp *bgp, afi_t afi, vty_out(vty, " equal-cluster-length"); vty_out(vty, "\n"); } - - return 0; } /* BGP timers. */ @@ -1804,6 +1794,69 @@ DEFUN (no_bgp_graceful_restart_preserve_fw, return CMD_SUCCESS; } +static void bgp_redistribute_redo(struct bgp *bgp) +{ + afi_t afi; + int i; + struct list *red_list; + struct listnode *node; + struct bgp_redist *red; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { + + red_list = bgp->redist[afi][i]; + if (!red_list) + continue; + + for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) { + bgp_redistribute_resend(bgp, afi, i, + red->instance); + } + } + } +} + +/* "bgp graceful-shutdown" configuration */ +DEFUN (bgp_graceful_shutdown, + bgp_graceful_shutdown_cmd, + "bgp graceful-shutdown", + BGP_STR + "Graceful shutdown parameters\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (!bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { + bgp_flag_set(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN); + bgp_static_redo_import_check(bgp); + bgp_redistribute_redo(bgp); + bgp_clear_star_soft_out(vty, bgp->name); + bgp_clear_star_soft_in(vty, bgp->name); + } + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_graceful_shutdown, + no_bgp_graceful_shutdown_cmd, + "no bgp graceful-shutdown", + NO_STR + BGP_STR + "Graceful shutdown parameters\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { + bgp_flag_unset(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN); + bgp_static_redo_import_check(bgp); + bgp_redistribute_redo(bgp); + bgp_clear_star_soft_out(vty, bgp->name); + bgp_clear_star_soft_in(vty, bgp->name); + } + + return CMD_SUCCESS; +} + /* "bgp fast-external-failover" configuration. */ DEFUN (bgp_fast_external_failover, bgp_fast_external_failover_cmd, @@ -2459,7 +2512,7 @@ DEFUN (no_bgp_listen_range, return bgp_vty_return(vty, ret); } -int bgp_config_write_listen(struct vty *vty, struct bgp *bgp) +void bgp_config_write_listen(struct vty *vty, struct bgp *bgp) { struct peer_group *group; struct listnode *node, *nnode, *rnode, *nrnode; @@ -2482,8 +2535,6 @@ int bgp_config_write_listen(struct vty *vty, struct bgp *bgp) } } } - - return 0; } @@ -6424,6 +6475,57 @@ DEFUN (show_bgp_vrfs, return CMD_SUCCESS; } +static void show_address_entry(struct hash_backet *backet, void *args) +{ + struct vty *vty = (struct vty *)args; + struct bgp_addr *addr = (struct bgp_addr *)backet->data; + + vty_out(vty, "addr: %s, count: %d\n", inet_ntoa(addr->addr), + addr->refcnt); +} + +static void show_tip_entry(struct hash_backet *backet, void *args) +{ + struct vty *vty = (struct vty *)args; + struct tip_addr *tip = (struct tip_addr *)backet->data; + + vty_out(vty, "addr: %s, count: %d\n", inet_ntoa(tip->addr), + tip->refcnt); +} + +static void bgp_show_martian_nexthops(struct vty *vty, struct bgp *bgp) +{ + vty_out(vty, "self nexthop database:\n"); + hash_iterate(bgp->address_hash, + (void (*)(struct hash_backet *, void *))show_address_entry, + vty); + + vty_out(vty, "Tunnel-ip database:\n"); + hash_iterate(bgp->tip_hash, + (void (*)(struct hash_backet *, void *))show_tip_entry, + vty); +} + +DEFUN(show_bgp_martian_nexthop_db, + show_bgp_martian_nexthop_db_cmd, + "show bgp martian next-hop", + SHOW_STR + BGP_STR + "martian next-hops\n" + "martian next-hop database\n") +{ + struct bgp *bgp = NULL; + + bgp = bgp_get_default(); + if (!bgp) { + vty_out(vty, "%% No BGP process is configured\n"); + return CMD_WARNING; + } + bgp_show_martian_nexthops(vty, bgp); + + return CMD_SUCCESS; +} + DEFUN (show_bgp_memory, show_bgp_memory_cmd, "show [ip] bgp memory", @@ -6622,367 +6724,321 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) continue; - if (peer->afc[afi][safi]) { - if (!count) { - unsigned long ents; - char memstrbuf[MTYPE_MEMSTR_LEN]; - int vrf_id_ui; + if (!peer->afc[afi][safi]) + continue; - vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN) - ? -1 - : bgp->vrf_id; + if (!count) { + unsigned long ents; + char memstrbuf[MTYPE_MEMSTR_LEN]; + int vrf_id_ui; - /* Usage summary and header */ + vrf_id_ui = + (bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id; + + /* Usage summary and header */ + if (use_json) { + json_object_string_add( + json, "routerId", + inet_ntoa(bgp->router_id)); + json_object_int_add(json, "as", bgp->as); + json_object_int_add(json, "vrfId", vrf_id_ui); + json_object_string_add( + json, "vrfName", + (bgp->inst_type + == BGP_INSTANCE_TYPE_DEFAULT) + ? "Default" + : bgp->name); + } else { + vty_out(vty, + "BGP router identifier %s, local AS number %u vrf-id %d", + inet_ntoa(bgp->router_id), bgp->as, + vrf_id_ui); + vty_out(vty, "\n"); + } + + if (bgp_update_delay_configured(bgp)) { if (use_json) { - json_object_string_add( - json, "routerId", - inet_ntoa(bgp->router_id)); - json_object_int_add(json, "as", - bgp->as); - json_object_int_add(json, "vrfId", - vrf_id_ui); - json_object_string_add( - json, "vrfName", - (bgp->inst_type - == BGP_INSTANCE_TYPE_DEFAULT) - ? "Default" - : bgp->name); - } else { - vty_out(vty, - "BGP router identifier %s, local AS number %u vrf-id %d", - inet_ntoa(bgp->router_id), - bgp->as, vrf_id_ui); - vty_out(vty, "\n"); - } + json_object_int_add( + json, "updateDelayLimit", + bgp->v_update_delay); - if (bgp_update_delay_configured(bgp)) { - if (use_json) { + if (bgp->v_update_delay + != bgp->v_establish_wait) json_object_int_add( json, - "updateDelayLimit", - bgp->v_update_delay); + "updateDelayEstablishWait", + bgp->v_establish_wait); - if (bgp->v_update_delay - != bgp->v_establish_wait) - json_object_int_add( - json, - "updateDelayEstablishWait", - bgp->v_establish_wait); - - if (bgp_update_delay_active( - bgp)) { + if (bgp_update_delay_active(bgp)) { + json_object_string_add( + json, + "updateDelayFirstNeighbor", + bgp->update_delay_begin_time); + json_object_boolean_true_add( + json, + "updateDelayInProgress"); + } else { + if (bgp->update_delay_over) { json_object_string_add( json, "updateDelayFirstNeighbor", bgp->update_delay_begin_time); - json_object_boolean_true_add( + json_object_string_add( json, - "updateDelayInProgress"); - } else { - if (bgp->update_delay_over) { - json_object_string_add( - json, - "updateDelayFirstNeighbor", - bgp->update_delay_begin_time); - json_object_string_add( - json, - "updateDelayBestpathResumed", - bgp->update_delay_end_time); - json_object_string_add( - json, - "updateDelayZebraUpdateResume", - bgp->update_delay_zebra_resume_time); - json_object_string_add( - json, - "updateDelayPeerUpdateResume", - bgp->update_delay_peers_resume_time); - } + "updateDelayBestpathResumed", + bgp->update_delay_end_time); + json_object_string_add( + json, + "updateDelayZebraUpdateResume", + bgp->update_delay_zebra_resume_time); + json_object_string_add( + json, + "updateDelayPeerUpdateResume", + bgp->update_delay_peers_resume_time); } - } else { + } + } else { + vty_out(vty, + "Read-only mode update-delay limit: %d seconds\n", + bgp->v_update_delay); + if (bgp->v_update_delay + != bgp->v_establish_wait) vty_out(vty, - "Read-only mode update-delay limit: %d seconds\n", - bgp->v_update_delay); - if (bgp->v_update_delay - != bgp->v_establish_wait) - vty_out(vty, - " Establish wait: %d seconds\n", - bgp->v_establish_wait); + " Establish wait: %d seconds\n", + bgp->v_establish_wait); - if (bgp_update_delay_active( - bgp)) { + if (bgp_update_delay_active(bgp)) { + vty_out(vty, + " First neighbor established: %s\n", + bgp->update_delay_begin_time); + vty_out(vty, + " Delay in progress\n"); + } else { + if (bgp->update_delay_over) { vty_out(vty, " First neighbor established: %s\n", bgp->update_delay_begin_time); vty_out(vty, - " Delay in progress\n"); - } else { - if (bgp->update_delay_over) { - vty_out(vty, - " First neighbor established: %s\n", - bgp->update_delay_begin_time); - vty_out(vty, - " Best-paths resumed: %s\n", - bgp->update_delay_end_time); - vty_out(vty, - " zebra update resumed: %s\n", - bgp->update_delay_zebra_resume_time); - vty_out(vty, - " peers update resumed: %s\n", - bgp->update_delay_peers_resume_time); - } + " Best-paths resumed: %s\n", + bgp->update_delay_end_time); + vty_out(vty, + " zebra update resumed: %s\n", + bgp->update_delay_zebra_resume_time); + vty_out(vty, + " peers update resumed: %s\n", + bgp->update_delay_peers_resume_time); } } } + } - if (use_json) { - if (bgp_maxmed_onstartup_configured(bgp) - && bgp->maxmed_active) - json_object_boolean_true_add( - json, - "maxMedOnStartup"); - if (bgp->v_maxmed_admin) - json_object_boolean_true_add( - json, - "maxMedAdministrative"); + if (use_json) { + if (bgp_maxmed_onstartup_configured(bgp) + && bgp->maxmed_active) + json_object_boolean_true_add( + json, "maxMedOnStartup"); + if (bgp->v_maxmed_admin) + json_object_boolean_true_add( + json, "maxMedAdministrative"); - json_object_int_add( - json, "tableVersion", - bgp_table_version( - bgp->rib[afi][safi])); - - ents = bgp_table_count( - bgp->rib[afi][safi]); - json_object_int_add(json, "ribCount", - ents); - json_object_int_add( - json, "ribMemory", - ents * sizeof(struct bgp_node)); + json_object_int_add( + json, "tableVersion", + bgp_table_version(bgp->rib[afi][safi])); - ents = listcount(bgp->peer); - json_object_int_add(json, "peerCount", - ents); - json_object_int_add( - json, "peerMemory", - ents * sizeof(struct peer)); + ents = bgp_table_count(bgp->rib[afi][safi]); + json_object_int_add(json, "ribCount", ents); + json_object_int_add( + json, "ribMemory", + ents * sizeof(struct bgp_node)); - if ((ents = listcount(bgp->group))) { - json_object_int_add( - json, "peerGroupCount", - ents); - json_object_int_add( - json, "peerGroupMemory", - ents * sizeof(struct - peer_group)); - } + ents = listcount(bgp->peer); + json_object_int_add(json, "peerCount", ents); + json_object_int_add(json, "peerMemory", + ents * sizeof(struct peer)); - if (CHECK_FLAG(bgp->af_flags[afi][safi], - BGP_CONFIG_DAMPENING)) - json_object_boolean_true_add( - json, - "dampeningEnabled"); - } else { - if (bgp_maxmed_onstartup_configured(bgp) - && bgp->maxmed_active) - vty_out(vty, - "Max-med on-startup active\n"); - if (bgp->v_maxmed_admin) - vty_out(vty, - "Max-med administrative active\n"); + if ((ents = listcount(bgp->group))) { + json_object_int_add( + json, "peerGroupCount", ents); + json_object_int_add( + json, "peerGroupMemory", + ents * sizeof(struct + peer_group)); + } + if (CHECK_FLAG(bgp->af_flags[afi][safi], + BGP_CONFIG_DAMPENING)) + json_object_boolean_true_add( + json, "dampeningEnabled"); + } else { + if (bgp_maxmed_onstartup_configured(bgp) + && bgp->maxmed_active) vty_out(vty, - "BGP table version %" PRIu64 - "\n", - bgp_table_version( - bgp->rib[afi][safi])); - - ents = bgp_table_count( - bgp->rib[afi][safi]); + "Max-med on-startup active\n"); + if (bgp->v_maxmed_admin) vty_out(vty, - "RIB entries %ld, using %s of memory\n", - ents, - mtype_memstr( - memstrbuf, - sizeof(memstrbuf), - ents * sizeof(struct - bgp_node))); + "Max-med administrative active\n"); + + vty_out(vty, "BGP table version %" PRIu64 "\n", + bgp_table_version(bgp->rib[afi][safi])); - /* Peer related usage */ - ents = listcount(bgp->peer); + ents = bgp_table_count(bgp->rib[afi][safi]); + vty_out(vty, + "RIB entries %ld, using %s of memory\n", + ents, + mtype_memstr(memstrbuf, + sizeof(memstrbuf), + ents * sizeof(struct + bgp_node))); + + /* Peer related usage */ + ents = listcount(bgp->peer); + vty_out(vty, "Peers %ld, using %s of memory\n", + ents, + mtype_memstr( + memstrbuf, sizeof(memstrbuf), + ents * sizeof(struct peer))); + + if ((ents = listcount(bgp->group))) vty_out(vty, - "Peers %ld, using %s of memory\n", + "Peer groups %ld, using %s of memory\n", ents, mtype_memstr( memstrbuf, sizeof(memstrbuf), ents * sizeof(struct - peer))); + peer_group))); - if ((ents = listcount(bgp->group))) - vty_out(vty, - "Peer groups %ld, using %s of memory\n", - ents, - mtype_memstr( - memstrbuf, - sizeof(memstrbuf), - ents * sizeof(struct - peer_group))); - - if (CHECK_FLAG(bgp->af_flags[afi][safi], - BGP_CONFIG_DAMPENING)) - vty_out(vty, - "Dampening enabled.\n"); - vty_out(vty, "\n"); + if (CHECK_FLAG(bgp->af_flags[afi][safi], + BGP_CONFIG_DAMPENING)) + vty_out(vty, "Dampening enabled.\n"); + vty_out(vty, "\n"); - /* Subtract 8 here because 'Neighbor' is - * 8 characters */ - vty_out(vty, "Neighbor"); - vty_out(vty, "%*s", - max_neighbor_width - 8, " "); - vty_out(vty, - "V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd\n"); - } + /* Subtract 8 here because 'Neighbor' is + * 8 characters */ + vty_out(vty, "Neighbor"); + vty_out(vty, "%*s", max_neighbor_width - 8, + " "); + vty_out(vty, + "V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd\n"); } + } - count++; - - if (use_json) { - json_peer = json_object_new_object(); - - if (peer_dynamic_neighbor(peer)) - json_object_boolean_true_add( - json_peer, "dynamicPeer"); + count++; - if (peer->hostname) - json_object_string_add(json_peer, - "hostname", - peer->hostname); + if (use_json) { + json_peer = json_object_new_object(); + + if (peer_dynamic_neighbor(peer)) + json_object_boolean_true_add(json_peer, + "dynamicPeer"); + + if (peer->hostname) + json_object_string_add(json_peer, "hostname", + peer->hostname); + + if (peer->domainname) + json_object_string_add(json_peer, "domainname", + peer->domainname); + + json_object_int_add(json_peer, "remoteAs", peer->as); + json_object_int_add(json_peer, "version", 4); + json_object_int_add(json_peer, "msgRcvd", + peer->open_in + peer->update_in + + peer->keepalive_in + + peer->notify_in + + peer->refresh_in + + peer->dynamic_cap_in); + json_object_int_add(json_peer, "msgSent", + peer->open_out + peer->update_out + + peer->keepalive_out + + peer->notify_out + + peer->refresh_out + + peer->dynamic_cap_out); + + json_object_int_add(json_peer, "tableVersion", + peer->version[afi][safi]); + json_object_int_add(json_peer, "outq", + peer->obuf->count); + json_object_int_add(json_peer, "inq", 0); + peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN, + use_json, json_peer); + json_object_int_add(json_peer, "prefixReceivedCount", + peer->pcount[afi][pfx_rcd_safi]); - if (peer->domainname) - json_object_string_add( - json_peer, "domainname", - peer->domainname); + if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) + json_object_string_add(json_peer, "state", + "Idle (Admin)"); + else if (CHECK_FLAG(peer->sflags, + PEER_STATUS_PREFIX_OVERFLOW)) + json_object_string_add(json_peer, "state", + "Idle (PfxCt)"); + else + json_object_string_add( + json_peer, "state", + lookup_msg(bgp_status_msg, peer->status, + NULL)); + + if (peer->conf_if) + json_object_string_add(json_peer, "idType", + "interface"); + else if (peer->su.sa.sa_family == AF_INET) + json_object_string_add(json_peer, "idType", + "ipv4"); + else if (peer->su.sa.sa_family == AF_INET6) + json_object_string_add(json_peer, "idType", + "ipv6"); + + json_object_object_add(json_peers, peer->host, + json_peer); + } else { + memset(dn_flag, '\0', sizeof(dn_flag)); + if (peer_dynamic_neighbor(peer)) { + dn_count++; + dn_flag[0] = '*'; + } - json_object_int_add(json_peer, "remoteAs", - peer->as); - json_object_int_add(json_peer, "version", 4); - json_object_int_add( - json_peer, "msgRcvd", - peer->open_in + peer->update_in - + peer->keepalive_in - + peer->notify_in - + peer->refresh_in - + peer->dynamic_cap_in); - json_object_int_add( - json_peer, "msgSent", - peer->open_out + peer->update_out - + peer->keepalive_out - + peer->notify_out - + peer->refresh_out - + peer->dynamic_cap_out); - - json_object_int_add(json_peer, "tableVersion", - peer->version[afi][safi]); - json_object_int_add(json_peer, "outq", - peer->obuf->count); - json_object_int_add(json_peer, "inq", 0); + if (peer->hostname + && bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME)) + len = vty_out(vty, "%s%s(%s)", dn_flag, + peer->hostname, peer->host); + else + len = vty_out(vty, "%s%s", dn_flag, peer->host); + + /* pad the neighbor column with spaces */ + if (len < max_neighbor_width) + vty_out(vty, "%*s", max_neighbor_width - len, + " "); + + vty_out(vty, "4 %10u %7d %7d %8" PRIu64 " %4d %4zd %8s", + peer->as, + peer->open_in + peer->update_in + + peer->keepalive_in + peer->notify_in + + peer->refresh_in + + peer->dynamic_cap_in, + peer->open_out + peer->update_out + + peer->keepalive_out + peer->notify_out + + peer->refresh_out + + peer->dynamic_cap_out, + peer->version[afi][safi], 0, peer->obuf->count, peer_uptime(peer->uptime, timebuf, - BGP_UPTIME_LEN, use_json, - json_peer); - json_object_int_add( - json_peer, "prefixReceivedCount", - peer->pcount[afi][pfx_rcd_safi]); + BGP_UPTIME_LEN, 0, NULL)); + if (peer->status == Established) + vty_out(vty, " %12ld", + peer->pcount[afi][pfx_rcd_safi]); + else { if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) - json_object_string_add(json_peer, - "state", - "Idle (Admin)"); + vty_out(vty, " Idle (Admin)"); else if (CHECK_FLAG( peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) - json_object_string_add(json_peer, - "state", - "Idle (PfxCt)"); + vty_out(vty, " Idle (PfxCt)"); else - json_object_string_add( - json_peer, "state", + vty_out(vty, " %12s", lookup_msg(bgp_status_msg, peer->status, NULL)); - - if (peer->conf_if) - json_object_string_add(json_peer, - "idType", - "interface"); - else if (peer->su.sa.sa_family == AF_INET) - json_object_string_add( - json_peer, "idType", "ipv4"); - else if (peer->su.sa.sa_family == AF_INET6) - json_object_string_add( - json_peer, "idType", "ipv6"); - - json_object_object_add(json_peers, peer->host, - json_peer); - } else { - memset(dn_flag, '\0', sizeof(dn_flag)); - if (peer_dynamic_neighbor(peer)) { - dn_count++; - dn_flag[0] = '*'; - } - - if (peer->hostname - && bgp_flag_check(bgp, - BGP_FLAG_SHOW_HOSTNAME)) - len = vty_out(vty, "%s%s(%s)", dn_flag, - peer->hostname, - peer->host); - else - len = vty_out(vty, "%s%s", dn_flag, - peer->host); - - /* pad the neighbor column with spaces */ - if (len < max_neighbor_width) - vty_out(vty, "%*s", - max_neighbor_width - len, " "); - - vty_out(vty, "4 %10u %7d %7d %8" PRIu64 - " %4d %4zd %8s", - peer->as, - peer->open_in + peer->update_in - + peer->keepalive_in - + peer->notify_in - + peer->refresh_in - + peer->dynamic_cap_in, - peer->open_out + peer->update_out - + peer->keepalive_out - + peer->notify_out - + peer->refresh_out - + peer->dynamic_cap_out, - peer->version[afi][safi], 0, - peer->obuf->count, - peer_uptime(peer->uptime, timebuf, - BGP_UPTIME_LEN, 0, NULL)); - - if (peer->status == Established) - vty_out(vty, " %12ld", - peer->pcount[afi] - [pfx_rcd_safi]); - else { - if (CHECK_FLAG(peer->flags, - PEER_FLAG_SHUTDOWN)) - vty_out(vty, " Idle (Admin)"); - else if ( - CHECK_FLAG( - peer->sflags, - PEER_STATUS_PREFIX_OVERFLOW)) - vty_out(vty, " Idle (PfxCt)"); - else - vty_out(vty, " %12s", - lookup_msg( - bgp_status_msg, - peer->status, - NULL)); - } - vty_out(vty, "\n"); } + vty_out(vty, "\n"); } } @@ -7528,6 +7584,12 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, "defaultNotSent"); } + if (afi == AFI_L2VPN && safi == SAFI_EVPN) { + if (p->bgp->advertise_all_vni) + json_object_boolean_true_add( + json_addr, "advertiseAllVnis"); + } + if (filter->plist[FILTER_IN].name || filter->dlist[FILTER_IN].name || filter->aslist[FILTER_IN].name @@ -7793,6 +7855,12 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, vty_out(vty, " default not sent\n"); } + /* advertise-vni-all */ + if (afi == AFI_L2VPN && safi == SAFI_EVPN) { + if (p->bgp->advertise_all_vni) + vty_out(vty, " advertise-all-vni\n"); + } + if (filter->plist[FILTER_IN].name || filter->dlist[FILTER_IN].name || filter->aslist[FILTER_IN].name @@ -8577,6 +8645,41 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json, json_cap, "multiprotocolExtensions", json_multi); + /* Hostname capabilities */ + json_object *json_hname = NULL; + + json_hname = json_object_new_object(); + + if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) { + json_object_string_add( + json_hname, "advHostName", + bgp->peer_self->hostname + ? bgp->peer_self + ->hostname + : "n/a"); + json_object_string_add( + json_hname, "advDomainName", + bgp->peer_self->domainname + ? bgp->peer_self + ->domainname + : "n/a"); + } + + + if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) { + json_object_string_add( + json_hname, "rcvHostName", + p->hostname ? p->hostname + : "n/a"); + json_object_string_add( + json_hname, "rcvDomainName", + p->domainname ? p->domainname + : "n/a"); + } + + json_object_object_add(json_cap, "hostName", + json_hname); + /* Gracefull Restart */ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || CHECK_FLAG(p->cap, @@ -8910,25 +9013,36 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json, } /* Hostname capability */ - if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV) - || CHECK_FLAG(p->cap, - PEER_CAP_HOSTNAME_RCV)) { + vty_out(vty, " Hostname Capability:"); + + if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) { vty_out(vty, - " Hostname Capability:"); - if (CHECK_FLAG(p->cap, - PEER_CAP_HOSTNAME_ADV)) - vty_out(vty, " advertised"); - if (CHECK_FLAG(p->cap, - PEER_CAP_HOSTNAME_RCV)) - vty_out(vty, " %sreceived", - CHECK_FLAG( - p->cap, - PEER_CAP_HOSTNAME_ADV) - ? "and " - : ""); - vty_out(vty, "\n"); + " advertised (name: %s,domain name: %s)", + bgp->peer_self->hostname + ? bgp->peer_self + ->hostname + : "n/a", + bgp->peer_self->domainname + ? bgp->peer_self + ->domainname + : "n/a"); + } else { + vty_out(vty, " not advertised"); } + if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) { + vty_out(vty, + " received (name: %s,domain name: %s)", + p->hostname ? p->hostname + : "n/a", + p->domainname ? p->domainname + : "n/a"); + } else { + vty_out(vty, " not received"); + } + + vty_out(vty, "\n"); + /* Gracefull Restart */ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || CHECK_FLAG(p->cap, @@ -10438,6 +10552,7 @@ DEFUN (bgp_redistribute_ipv4, vty_out(vty, "%% Invalid route type\n"); return CMD_WARNING_CONFIG_FAILED; } + bgp_redist_add(bgp, AFI_IP, type, 0); return bgp_redistribute_set(bgp, AFI_IP, type, 0); } @@ -11041,14 +11156,14 @@ DEFUN (no_bgp_redistribute_ipv6, return bgp_redistribute_unset(bgp, AFI_IP6, type, 0); } -int bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi, int *write) +void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) { int i; /* Unicast redistribution only. */ if (safi != SAFI_UNICAST) - return 0; + return; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { /* Redistribute BGP does not make sense. */ @@ -11062,11 +11177,6 @@ int bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi, continue; for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) { - /* Display "address-family" when it is not yet - * diplayed. */ - bgp_config_write_family_header(vty, afi, safi, - write); - /* "redistribute" configuration. */ vty_out(vty, " redistribute %s", zebra_route_string(i)); @@ -11082,7 +11192,6 @@ int bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi, } } } - return *write; } /* BGP node structure. */ @@ -11314,6 +11423,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_graceful_restart_preserve_fw_cmd); install_element(BGP_NODE, &no_bgp_graceful_restart_preserve_fw_cmd); + /* "bgp graceful-shutdown" commands */ + install_element(BGP_NODE, &bgp_graceful_shutdown_cmd); + install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd); + /* "bgp fast-external-failover" commands */ install_element(BGP_NODE, &bgp_fast_external_failover_cmd); install_element(BGP_NODE, &no_bgp_fast_external_failover_cmd); @@ -12264,6 +12377,9 @@ void bgp_vty_init(void) /* "show [ip] bgp memory" commands. */ install_element(VIEW_NODE, &show_bgp_memory_cmd); + /* "show bgp martian next-hop" */ + install_element(VIEW_NODE, &show_bgp_martian_nexthop_db_cmd); + /* "show [ip] bgp views" commands. */ install_element(VIEW_NODE, &show_bgp_views_cmd); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 62bc27d507..59bc012661 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -46,10 +46,10 @@ struct bgp; extern void bgp_vty_init(void); extern const char *afi_safi_print(afi_t, safi_t); extern const char *afi_safi_json(afi_t, safi_t); -extern int bgp_config_write_update_delay(struct vty *, struct bgp *); -extern int bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp); -extern int bgp_config_write_listen(struct vty *vty, struct bgp *bgp); -extern int bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp); +extern void bgp_config_write_update_delay(struct vty *, struct bgp *); +extern void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp); +extern void bgp_config_write_listen(struct vty *vty, struct bgp *bgp); +extern void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp); extern int bgp_vty_return(struct vty *vty, int ret); extern struct peer *peer_and_group_lookup_vty(struct vty *vty, const char *peer_str); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 9a092404d5..8b9d55295d 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1022,7 +1022,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, * in * the RIB */ if (info->sub_type == BGP_ROUTE_AGGREGATE) - SET_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE); + zapi_route_set_blackhole(&api, BLACKHOLE_NULL); if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || info->sub_type == BGP_ROUTE_AGGREGATE) { @@ -1152,7 +1152,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, if (has_valid_label) SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); - if (!CHECK_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE)) + if (info->sub_type != BGP_ROUTE_AGGREGATE) api.nexthop_num = valid_nh_count; SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 11405d1c1b..7d37864f44 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -26,10 +26,10 @@ extern void bgp_zebra_init(struct thread_master *master); extern void bgp_zebra_destroy(void); extern int bgp_if_update_all(void); -extern int bgp_config_write_maxpaths(struct vty *, struct bgp *, afi_t, safi_t, - int *); -extern int bgp_config_write_redistribute(struct vty *, struct bgp *, afi_t, - safi_t, int *); +extern void bgp_config_write_maxpaths(struct vty *, struct bgp *, afi_t, + safi_t); +extern void bgp_config_write_redistribute(struct vty *, struct bgp *, afi_t, + safi_t); extern void bgp_zebra_announce(struct bgp_node *, struct prefix *, struct bgp_info *, struct bgp *, afi_t, safi_t); extern void bgp_zebra_announce_table(struct bgp *, afi_t, safi_t); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 92121f6aef..d147055749 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2816,6 +2816,21 @@ static struct bgp *bgp_create(as_t *as, const char *name, XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host); bgp->peer_self->host = XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement"); + if (bgp->peer_self->hostname != NULL) { + XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname); + bgp->peer_self->hostname = NULL; + } + if (cmd_hostname_get()) + bgp->peer_self->hostname = + XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_hostname_get()); + + if (bgp->peer_self->domainname != NULL) { + XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname); + bgp->peer_self->domainname = NULL; + } + if (cmd_domainname_get()) + bgp->peer_self->domainname = + XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_domainname_get()); bgp->peer = list_new(); bgp->peer->cmp = (int (*)(void *, void *))peer_cmp; bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, NULL); @@ -2988,6 +3003,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, bgp = bgp_create(as, name, inst_type); bgp_router_id_set(bgp, &bgp->router_id_zebra); bgp_address_init(bgp); + bgp_tip_hash_init(bgp); bgp_scan_init(bgp); *bgp_val = bgp; @@ -3069,6 +3085,9 @@ void bgp_instance_down(struct bgp *bgp) /* Purge network and redistributed routes. */ bgp_purge_static_redist_routes(bgp); + + /* Cleanup registered nexthops (flags) */ + bgp_cleanup_nexthops(bgp); } /* Delete BGP instance. */ @@ -3200,6 +3219,7 @@ void bgp_free(struct bgp *bgp) bgp_scan_finish(bgp); bgp_address_destroy(bgp); + bgp_tip_hash_destroy(bgp); bgp_evpn_cleanup(bgp); @@ -6184,14 +6204,8 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, u_char use_json, return buf; } -#define afi_header_vty_out(vty, afi, safi, write, format, ...) \ - do { \ - bgp_config_write_family_header(vty, afi, safi, write); \ - vty_out(vty, format, ## __VA_ARGS__); \ - } while (0) - static void bgp_config_write_filter(struct vty *vty, struct peer *peer, - afi_t afi, safi_t safi, int *write) + afi_t afi, safi_t safi) { struct bgp_filter *filter; struct bgp_filter *gfilter = NULL; @@ -6210,16 +6224,13 @@ static void bgp_config_write_filter(struct vty *vty, struct peer *peer, if (!gfilter || !gfilter->dlist[in].name || strcmp(filter->dlist[in].name, gfilter->dlist[in].name) != 0) { - afi_header_vty_out( - vty, afi, safi, write, - " neighbor %s distribute-list %s in\n", addr, - filter->dlist[in].name); + vty_out(vty, " neighbor %s distribute-list %s in\n", + addr, filter->dlist[in].name); } if (filter->dlist[out].name && !gfilter) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s distribute-list %s out\n", - addr, filter->dlist[out].name); + vty_out(vty, " neighbor %s distribute-list %s out\n", addr, + filter->dlist[out].name); } /* prefix-list. */ @@ -6227,19 +6238,17 @@ static void bgp_config_write_filter(struct vty *vty, struct peer *peer, if (!gfilter || !gfilter->plist[in].name || strcmp(filter->plist[in].name, gfilter->plist[in].name) != 0) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s prefix-list %s in\n", - addr, filter->plist[in].name); + vty_out(vty, " neighbor %s prefix-list %s in\n", addr, + filter->plist[in].name); } - if (filter->plist[out].name) - if (!gfilter || !gfilter->plist[out].name - || strcmp(filter->plist[out].name, gfilter->plist[out].name) - != 0) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s prefix-list %s out\n", - addr, filter->plist[out].name); - } + if (filter->plist[out].name) + if (!gfilter || !gfilter->plist[out].name + || strcmp(filter->plist[out].name, gfilter->plist[out].name) + != 0) { + vty_out(vty, " neighbor %s prefix-list %s out\n", addr, + filter->plist[out].name); + } /* route-map. */ if (filter->map[RMAP_IN].name) @@ -6247,9 +6256,8 @@ static void bgp_config_write_filter(struct vty *vty, struct peer *peer, || strcmp(filter->map[RMAP_IN].name, gfilter->map[RMAP_IN].name) != 0) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s route-map %s in\n", - addr, filter->map[RMAP_IN].name); + vty_out(vty, " neighbor %s route-map %s in\n", addr, + filter->map[RMAP_IN].name); } if (filter->map[RMAP_OUT].name) @@ -6257,16 +6265,14 @@ static void bgp_config_write_filter(struct vty *vty, struct peer *peer, || strcmp(filter->map[RMAP_OUT].name, gfilter->map[RMAP_OUT].name) != 0) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s route-map %s out\n", - addr, filter->map[RMAP_OUT].name); + vty_out(vty, " neighbor %s route-map %s out\n", addr, + filter->map[RMAP_OUT].name); } /* unsuppress-map */ if (filter->usmap.name && !gfilter) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s unsuppress-map %s\n", addr, - filter->usmap.name); + vty_out(vty, " neighbor %s unsuppress-map %s\n", addr, + filter->usmap.name); } /* filter-list. */ @@ -6274,15 +6280,13 @@ static void bgp_config_write_filter(struct vty *vty, struct peer *peer, if (!gfilter || !gfilter->aslist[in].name || strcmp(filter->aslist[in].name, gfilter->aslist[in].name) != 0) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s filter-list %s in\n", - addr, filter->aslist[in].name); + vty_out(vty, " neighbor %s filter-list %s in\n", addr, + filter->aslist[in].name); } if (filter->aslist[out].name && !gfilter) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s filter-list %s out\n", addr, - filter->aslist[out].name); + vty_out(vty, " neighbor %s filter-list %s out\n", addr, + filter->aslist[out].name); } } @@ -6602,8 +6606,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, /* BGP peer configuration display function. */ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, - struct peer *peer, afi_t afi, safi_t safi, - int *write) + struct peer *peer, afi_t afi, safi_t safi) { struct peer *g_peer = NULL; char *addr; @@ -6626,36 +6629,29 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, /* If the peer-group is active but peer is not, print a 'no * activate' */ if (g_peer->afc[afi][safi] && !peer->afc[afi][safi]) { - afi_header_vty_out(vty, afi, safi, write, - " no neighbor %s activate\n", addr); + vty_out(vty, " no neighbor %s activate\n", addr); } /* If the peer-group is not active but peer is, print an 'activate' */ else if (!g_peer->afc[afi][safi] && peer->afc[afi][safi]) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s activate\n", addr); + vty_out(vty, " neighbor %s activate\n", addr); } } else { if (peer->afc[afi][safi]) { if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)) { - afi_header_vty_out( - vty, afi, safi, write, - " neighbor %s activate\n", + vty_out(vty, " neighbor %s activate\n", addr); } } else - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s activate\n", - addr); + vty_out(vty, " neighbor %s activate\n", addr); } else { if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { if (!bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)) { - afi_header_vty_out( - vty, afi, safi, write, + vty_out(vty, " no neighbor %s activate\n", addr); } @@ -6666,25 +6662,20 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, /* addpath TX knobs */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ADDPATH_TX_ALL_PATHS)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s addpath-tx-all-paths\n", - addr); + vty_out(vty, " neighbor %s addpath-tx-all-paths\n", addr); } if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s addpath-tx-bestpath-per-AS\n", - addr); + vty_out(vty, " neighbor %s addpath-tx-bestpath-per-AS\n", + addr); } /* ORF capability. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) || peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_RM)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s capability orf prefix-list", - addr); + vty_out(vty, " neighbor %s capability orf prefix-list", addr); if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) @@ -6702,57 +6693,46 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, /* Route reflector client. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s route-reflector-client\n", - addr); + vty_out(vty, " neighbor %s route-reflector-client\n", addr); } /* next-hop-self force */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_FORCE_NEXTHOP_SELF)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s next-hop-self force\n", addr); + vty_out(vty, " neighbor %s next-hop-self force\n", addr); } /* next-hop-self */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s next-hop-self\n", addr); + vty_out(vty, " neighbor %s next-hop-self\n", addr); } /* remove-private-AS */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)) { - afi_header_vty_out( - vty, afi, safi, write, - " neighbor %s remove-private-AS all replace-AS\n", + vty_out(vty, " neighbor %s remove-private-AS all replace-AS\n", addr); } else if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)) { - afi_header_vty_out( - vty, afi, safi, write, - " neighbor %s remove-private-AS replace-AS\n", addr); + vty_out(vty, " neighbor %s remove-private-AS replace-AS\n", + addr); } else if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s remove-private-AS all\n", - addr); + vty_out(vty, " neighbor %s remove-private-AS all\n", addr); } else if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s remove-private-AS\n", addr); + vty_out(vty, " neighbor %s remove-private-AS\n", addr); } /* as-override */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s as-override\n", addr); + vty_out(vty, " neighbor %s as-override\n", addr); } /* send-community print. */ @@ -6764,27 +6744,21 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, && peergroup_af_flag_check( peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s send-community all\n", - addr); + vty_out(vty, " neighbor %s send-community all\n", + addr); } else if (peergroup_af_flag_check( peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)) { - afi_header_vty_out( - vty, afi, safi, write, - " neighbor %s send-community large\n", addr); + vty_out(vty, " neighbor %s send-community large\n", + addr); } else if (peergroup_af_flag_check( peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) { - afi_header_vty_out( - vty, afi, safi, write, - " neighbor %s send-community extended\n", + vty_out(vty, " neighbor %s send-community extended\n", addr); } else if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s send-community\n", - addr); + vty_out(vty, " neighbor %s send-community\n", addr); } } else { if (!peer_af_flag_check(peer, afi, safi, @@ -6801,9 +6775,8 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, && (!g_peer || peer_af_flag_check( g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))) { - afi_header_vty_out( - vty, afi, safi, write, - " no neighbor %s send-community all\n", addr); + vty_out(vty, " no neighbor %s send-community all\n", + addr); } else { if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) @@ -6811,8 +6784,7 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, || peer_af_flag_check( g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))) { - afi_header_vty_out( - vty, afi, safi, write, + vty_out(vty, " no neighbor %s send-community large\n", addr); } @@ -6823,8 +6795,7 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, || peer_af_flag_check( g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))) { - afi_header_vty_out( - vty, afi, safi, write, + vty_out(vty, " no neighbor %s send-community extended\n", addr); } @@ -6834,8 +6805,7 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, && (!g_peer || peer_af_flag_check( g_peer, afi, safi, PEER_FLAG_SEND_COMMUNITY))) { - afi_header_vty_out( - vty, afi, safi, write, + vty_out(vty, " no neighbor %s send-community\n", addr); } @@ -6853,8 +6823,7 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, || (peer->default_rmap[afi][safi].name && strcmp(peer->default_rmap[afi][safi].name, g_peer->default_rmap[afi][safi].name))))) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s default-originate", addr); + vty_out(vty, " neighbor %s default-originate", addr); if (peer->default_rmap[afi][safi].name) vty_out(vty, " route-map %s", peer->default_rmap[afi][safi].name); @@ -6863,9 +6832,8 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, /* Soft reconfiguration inbound. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOFT_RECONFIG)) { - afi_header_vty_out( - vty, afi, safi, write, - " neighbor %s soft-reconfiguration inbound\n", addr); + vty_out(vty, " neighbor %s soft-reconfiguration inbound\n", + addr); } /* maximum-prefix. */ @@ -6878,9 +6846,8 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, PEER_FLAG_MAX_PREFIX_WARNING) != CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s maximum-prefix %lu", - addr, peer->pmax[afi][safi]); + vty_out(vty, " neighbor %s maximum-prefix %lu", addr, + peer->pmax[afi][safi]); if (peer->pmax_threshold[afi][safi] != MAXIMUM_PREFIX_THRESHOLD_DEFAULT) vty_out(vty, " %u", @@ -6897,16 +6864,13 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, /* Route server client. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_RSERVER_CLIENT)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s route-server-client\n", addr); + vty_out(vty, " neighbor %s route-server-client\n", addr); } /* Nexthop-local unchanged. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s nexthop-local unchanged\n", - addr); + vty_out(vty, " neighbor %s nexthop-local unchanged\n", addr); } /* allowas-in <1-10> */ @@ -6917,14 +6881,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, || peer->allowas_in[afi][safi] != g_peer->allowas_in[afi][safi]) { if (peer->allowas_in[afi][safi] == 3) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s allowas-in\n", - addr); + vty_out(vty, " neighbor %s allowas-in\n", + addr); } else { - afi_header_vty_out( - vty, afi, safi, write, - " neighbor %s allowas-in %d\n", addr, - peer->allowas_in[afi][safi]); + vty_out(vty, " neighbor %s allowas-in %d\n", + addr, peer->allowas_in[afi][safi]); } } } @@ -6935,9 +6896,7 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, if (!peer_group_active(peer) || !peer_af_flag_check(g_peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN)) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s allowas-in origin\n", - addr); + vty_out(vty, " neighbor %s allowas-in origin\n", addr); } } @@ -6947,15 +6906,13 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, || !peer_af_flag_check(g_peer, afi, safi, PEER_FLAG_WEIGHT) || peer->weight[afi][safi] != g_peer->weight[afi][safi]) { if (peer->weight[afi][safi]) { - afi_header_vty_out(vty, afi, safi, write, - " neighbor %s weight %lu\n", - addr, - peer->weight[afi][safi]); + vty_out(vty, " neighbor %s weight %lu\n", addr, + peer->weight[afi][safi]); } } /* Filter. */ - bgp_config_write_filter(vty, peer, afi, safi, write); + bgp_config_write_filter(vty, peer, afi, safi); /* atribute-unchanged. */ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED) || @@ -6970,18 +6927,15 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MED_UNCHANGED)) { - afi_header_vty_out( - vty, afi, safi, write, + vty_out(vty, " neighbor %s attribute-unchanged%s%s%s\n", addr, - peer_af_flag_check( - peer, afi, safi, - PEER_FLAG_AS_PATH_UNCHANGED) + peer_af_flag_check(peer, afi, safi, + PEER_FLAG_AS_PATH_UNCHANGED) ? " as-path" : "", - peer_af_flag_check( - peer, afi, safi, - PEER_FLAG_NEXTHOP_UNCHANGED) + peer_af_flag_check(peer, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED) ? " next-hop" : "", peer_af_flag_check(peer, afi, safi, @@ -6992,64 +6946,52 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, } } -/* Display "address-family" configuration header. */ -void bgp_config_write_family_header(struct vty *vty, afi_t afi, safi_t safi, - int *write) +/* Address family based peer configuration display. */ +static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) { - if (*write) - return; + struct peer *peer; + struct peer_group *group; + struct listnode *node, *nnode; - vty_out(vty, " !\n address-family "); + vty_frame(vty, " !\n address-family "); if (afi == AFI_IP) { if (safi == SAFI_UNICAST) - vty_out(vty, "ipv4 unicast"); + vty_frame(vty, "ipv4 unicast"); else if (safi == SAFI_LABELED_UNICAST) - vty_out(vty, "ipv4 labeled-unicast"); + vty_frame(vty, "ipv4 labeled-unicast"); else if (safi == SAFI_MULTICAST) - vty_out(vty, "ipv4 multicast"); + vty_frame(vty, "ipv4 multicast"); else if (safi == SAFI_MPLS_VPN) - vty_out(vty, "ipv4 vpn"); + vty_frame(vty, "ipv4 vpn"); else if (safi == SAFI_ENCAP) - vty_out(vty, "ipv4 encap"); + vty_frame(vty, "ipv4 encap"); } else if (afi == AFI_IP6) { if (safi == SAFI_UNICAST) - vty_out(vty, "ipv6 unicast"); + vty_frame(vty, "ipv6 unicast"); else if (safi == SAFI_LABELED_UNICAST) - vty_out(vty, "ipv6 labeled-unicast"); + vty_frame(vty, "ipv6 labeled-unicast"); else if (safi == SAFI_MULTICAST) - vty_out(vty, "ipv6 multicast"); + vty_frame(vty, "ipv6 multicast"); else if (safi == SAFI_MPLS_VPN) - vty_out(vty, "ipv6 vpn"); + vty_frame(vty, "ipv6 vpn"); else if (safi == SAFI_ENCAP) - vty_out(vty, "ipv6 encap"); + vty_frame(vty, "ipv6 encap"); } else if (afi == AFI_L2VPN) { if (safi == SAFI_EVPN) - vty_out(vty, "l2vpn evpn"); + vty_frame(vty, "l2vpn evpn"); } - vty_out(vty, "\n"); + vty_frame(vty, "\n"); - *write = 1; -} + bgp_config_write_distance(vty, bgp, afi, safi); -/* Address family based peer configuration display. */ -static int bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi) -{ - int write = 0; - struct peer *peer; - struct peer_group *group; - struct listnode *node, *nnode; + bgp_config_write_network(vty, bgp, afi, safi); - bgp_config_write_distance(vty, bgp, afi, safi, &write); - - bgp_config_write_network(vty, bgp, afi, safi, &write); - - bgp_config_write_redistribute(vty, bgp, afi, safi, &write); + bgp_config_write_redistribute(vty, bgp, afi, safi); for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) - bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi, - &write); + bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi); for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { /* Skip dynamic neighbors. */ @@ -7058,20 +7000,16 @@ static int bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, /* Do not display doppelganger peers */ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) - bgp_config_write_peer_af(vty, bgp, peer, afi, safi, - &write); + bgp_config_write_peer_af(vty, bgp, peer, afi, safi); } - bgp_config_write_maxpaths(vty, bgp, afi, safi, &write); - bgp_config_write_table_map(vty, bgp, afi, safi, &write); + bgp_config_write_maxpaths(vty, bgp, afi, safi); + bgp_config_write_table_map(vty, bgp, afi, safi); if (safi == SAFI_EVPN) - bgp_config_write_evpn_info(vty, bgp, afi, safi, &write); + bgp_config_write_evpn_info(vty, bgp, afi, safi); - if (write) - vty_out(vty, " exit-address-family\n"); - - return write; + vty_endframe(vty, " exit-address-family\n"); } int bgp_config_write(struct vty *vty) @@ -7099,11 +7037,11 @@ int bgp_config_write(struct vty *vty) vty_out(vty, "bgp route-map delay-timer %u\n", bm->rmap_update_timer); + if (write) + vty_out(vty, "!\n"); + /* BGP configuration. */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { - if (write) - vty_out(vty, "!\n"); - /* Router bgp ASN */ vty_out(vty, "router bgp %u", bgp->as); @@ -7247,6 +7185,10 @@ int bgp_config_write(struct vty *vty) if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_RESTART)) vty_out(vty, " bgp graceful-restart\n"); + /* BGP graceful-shutdown */ + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) + vty_out(vty, " bgp graceful-shutdown\n"); + /* BGP graceful-restart Preserve State F bit. */ if (bgp_flag_check(bgp, BGP_FLAG_GR_PRESERVE_FWD)) vty_out(vty, @@ -7323,54 +7265,46 @@ int bgp_config_write(struct vty *vty) vty_out(vty, " no auto-summary\n"); /* IPv4 unicast configuration. */ - write += - bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST); + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST); /* IPv4 multicast configuration. */ - write += bgp_config_write_family(vty, bgp, AFI_IP, - SAFI_MULTICAST); + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_MULTICAST); /* IPv4 labeled-unicast configuration. */ - write += bgp_config_write_family(vty, bgp, AFI_IP, - SAFI_LABELED_UNICAST); + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_LABELED_UNICAST); /* IPv4 VPN configuration. */ - write += bgp_config_write_family(vty, bgp, AFI_IP, - SAFI_MPLS_VPN); + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_MPLS_VPN); /* ENCAPv4 configuration. */ - write += bgp_config_write_family(vty, bgp, AFI_IP, SAFI_ENCAP); + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_ENCAP); /* IPv6 unicast configuration. */ - write += bgp_config_write_family(vty, bgp, AFI_IP6, - SAFI_UNICAST); + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_UNICAST); /* IPv6 multicast configuration. */ - write += bgp_config_write_family(vty, bgp, AFI_IP6, - SAFI_MULTICAST); + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_MULTICAST); /* IPv6 labeled-unicast configuration. */ - write += bgp_config_write_family(vty, bgp, AFI_IP6, - SAFI_LABELED_UNICAST); + bgp_config_write_family(vty, bgp, AFI_IP6, + SAFI_LABELED_UNICAST); /* IPv6 VPN configuration. */ - write += bgp_config_write_family(vty, bgp, AFI_IP6, - SAFI_MPLS_VPN); + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_MPLS_VPN); /* ENCAPv6 configuration. */ - write += bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_ENCAP); + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_ENCAP); /* EVPN configuration. */ - write += - bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN); + bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN); #if ENABLE_BGP_VNC - write += bgp_rfapi_cfg_write(vty, bgp); + bgp_rfapi_cfg_write(vty, bgp); #endif - write++; + vty_out(vty, "!\n"); } - return write; + return 0; } void bgp_master_init(struct thread_master *master) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 5ede9ba13d..9c38a65b40 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -303,6 +303,7 @@ struct bgp { #define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 18) #define BGP_FLAG_SHOW_HOSTNAME (1 << 19) #define BGP_FLAG_GR_PRESERVE_FWD (1 << 20) +#define BGP_FLAG_GRACEFUL_SHUTDOWN (1 << 21) /* BGP Per AF flags */ u_int16_t af_flags[AFI_MAX][SAFI_MAX]; @@ -318,6 +319,10 @@ struct bgp { struct hash *address_hash; + /* DB for all local tunnel-ips - used mainly for martian checks + Currently it only has all VxLan tunnel IPs*/ + struct hash *tip_hash; + /* Static route configuration. */ struct bgp_table *route[AFI_MAX][SAFI_MAX]; @@ -1094,6 +1099,10 @@ struct bgp_nlri { /* BGP default local preference. */ #define BGP_DEFAULT_LOCAL_PREF 100 +/* BGP local-preference to send when 'bgp graceful-shutdown' + * is configured */ +#define BGP_GSHUT_LOCAL_PREF 0 + /* BGP default subgroup packet queue max . */ #define BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX 40 @@ -1234,7 +1243,6 @@ extern void peer_xfer_config(struct peer *dst, struct peer *src); extern char *peer_uptime(time_t, char *, size_t, u_char, json_object *); extern int bgp_config_write(struct vty *); -extern void bgp_config_write_family_header(struct vty *, afi_t, safi_t, int *); extern void bgp_master_init(struct thread_master *master); diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index c8e2dd9525..a39fe068bd 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -2977,11 +2977,6 @@ DEFUN_NOSH (vnc_vrf_policy, struct rfapi_nve_group_cfg *rfg; VTY_DECLVAR_CONTEXT(bgp, bgp); - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* Search for name */ rfg = bgp_rfapi_cfg_match_byname(bgp, argv[1]->arg, RFAPI_GROUP_CFG_VRF); @@ -3012,10 +3007,6 @@ DEFUN (vnc_no_vrf_policy, { VTY_DECLVAR_CONTEXT(bgp, bgp); - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } return bgp_rfapi_delete_named_nve_group(vty, bgp, argv[2]->arg, RFAPI_GROUP_CFG_VRF); } @@ -3031,11 +3022,6 @@ DEFUN (vnc_vrf_policy_label, uint32_t label; VTY_DECLVAR_CONTEXT(bgp, bgp); - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* make sure it's still in list */ if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { /* Not in list anymore */ @@ -3145,11 +3131,6 @@ DEFUN (vnc_vrf_policy_rt_import, int is_export_bgp = 0; int is_export_zebra = 0; - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* make sure it's still in list */ if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { /* Not in list anymore */ @@ -3213,11 +3194,6 @@ DEFUN (vnc_vrf_policy_rt_export, VTY_DECLVAR_CONTEXT(bgp, bgp); int rc; - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* make sure it's still in list */ if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { /* Not in list anymore */ @@ -3253,11 +3229,6 @@ DEFUN (vnc_vrf_policy_rt_both, struct listnode *node; struct rfapi_rfg_name *rfgn; - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* make sure it's still in list */ if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { /* Not in list anymore */ @@ -3333,11 +3304,6 @@ DEFUN (vnc_vrf_policy_rd, VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); VTY_DECLVAR_CONTEXT(bgp, bgp); - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* make sure it's still in list */ if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { /* Not in list anymore */ @@ -3420,13 +3386,8 @@ DEFUN_NOSH (vnc_l2_group, struct rfapi_l2_group_cfg *rfg; VTY_DECLVAR_CONTEXT(bgp, bgp); - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* Search for name */ - rfg = rfapi_l2_group_lookup_byname(bgp, argv[1]->arg); + rfg = rfapi_l2_group_lookup_byname(bgp, argv[2]->arg); if (!rfg) { rfg = rfapi_l2_group_new(); @@ -3435,7 +3396,7 @@ DEFUN_NOSH (vnc_l2_group, vty_out(vty, "Can't allocate memory for L2 group\n"); return CMD_WARNING_CONFIG_FAILED; } - rfg->name = strdup(argv[1]->arg); + rfg->name = strdup(argv[2]->arg); /* add to tail of list */ listnode_add(bgp->rfapi_cfg->l2_groups, rfg); } @@ -3505,28 +3466,19 @@ DEFUN (vnc_no_l2_group, { VTY_DECLVAR_CONTEXT(bgp, bgp); - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } return bgp_rfapi_delete_named_l2_group(vty, bgp, argv[3]->arg); } DEFUN (vnc_l2_group_lni, vnc_l2_group_lni_cmd, - "logical-network-id <0-4294967295>", + "logical-network-id (0-4294967295)", "Specify Logical Network ID associated with group\n" "value\n") { VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); VTY_DECLVAR_CONTEXT(bgp, bgp); - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* make sure it's still in list */ if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) { /* Not in list anymore */ @@ -3549,11 +3501,6 @@ DEFUN (vnc_l2_group_labels, VTY_DECLVAR_CONTEXT(bgp, bgp); struct list *ll; - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* make sure it's still in list */ if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) { /* Not in list anymore */ @@ -3589,11 +3536,6 @@ DEFUN (vnc_l2_group_no_labels, VTY_DECLVAR_CONTEXT(bgp, bgp); struct list *ll; - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* make sure it's still in list */ if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) { /* Not in list anymore */ @@ -3646,10 +3588,6 @@ DEFUN (vnc_l2_group_rt, vty_out(vty, "Unknown option, %s\n", argv[1]->arg); return CMD_ERR_NO_MATCH; } - if (!bgp) { - vty_out(vty, "No BGP process is configured\n"); - return CMD_WARNING_CONFIG_FAILED; - } /* make sure it's still in list */ if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) { diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index d63975a22b..3f427c3903 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -3875,10 +3875,9 @@ rfapiBgpInfoFilteredImportFunction(safi_t safi) default: /* not expected */ + zlog_err("%s: bad safi %d", __func__, safi); return NULL; } - zlog_err("%s: bad safi %d", __func__, safi); - return NULL; } void rfapiProcessUpdate(struct peer *peer, diff --git a/configure.ac b/configure.ac index bf66e00f9f..3daf01fcc5 100755 --- a/configure.ac +++ b/configure.ac @@ -195,6 +195,7 @@ fi dnl always want these CFLAGS AC_C_FLAG([-fno-omit-frame-pointer]) +AC_C_FLAG([-funwind-tables]) AC_C_FLAG([-Wall]) AC_C_FLAG([-Wextra]) AC_C_FLAG([-Wmissing-prototypes]) @@ -320,6 +321,8 @@ 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)])) +AC_ARG_ENABLE(zeromq, + AS_HELP_STRING([--enable-zeromq], [enable ZeroMQ handler (libfrrzmq)])) AC_ARG_WITH(libpam, AS_HELP_STRING([--with-libpam], [use libpam for PAM support in vtysh])) AC_ARG_ENABLE(ospfapi, @@ -877,6 +880,7 @@ case "$host_os" in AC_DEFINE(KAME,1,KAME IPv6) ;; esac +AM_CONDITIONAL(SOLARIS, test "${SOLARIS}" = "solaris") AC_SYS_LARGEFILE @@ -1714,6 +1718,21 @@ AC_CHECK_HEADER([malloc.h], ) ], [], FRR_INCLUDES) +dnl ------ +dnl ZeroMQ +dnl ------ +if test "x$enable_zeromq" != "xno"; then + PKG_CHECK_MODULES(ZEROMQ, [libzmq >= 4.0.0], [ + AC_DEFINE(HAVE_ZEROMQ, 1, [Enable ZeroMQ support]) + ZEROMQ=true + ], [ + if test "x$enable_zeromq" = "xyes"; then + AC_MSG_ERROR([configuration specifies --enable-zeromq but libzmq was not found]) + fi + ]) +fi +AM_CONDITIONAL([ZEROMQ], test "x$ZEROMQ" = "xtrue") + dnl ---------- dnl configure date dnl ---------- @@ -1819,6 +1838,7 @@ AC_CONFIG_FILES([Makefile doc/watchfrr.8 doc/zebra.8 doc/frr.1 + doc/frr-args.8 pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh pkgsrc/eigrpd.sh]) diff --git a/debian/frr.install b/debian/frr.install index 49aeb395bb..8fc5fa5fa6 100644 --- a/debian/frr.install +++ b/debian/frr.install @@ -16,6 +16,7 @@ usr/share/man/man8/ripngd.8 usr/share/man/man8/zebra.8 usr/share/man/man8/isisd.8 usr/share/man/man8/watchfrr.8 +usr/share/man/man8/frr-args.8 usr/share/snmp/mibs/ tools/etc/* etc/ tools/*.service lib/systemd/system diff --git a/doc/Makefile.am b/doc/Makefile.am index 9016df7372..7d31e4cc47 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -52,7 +52,7 @@ info_TEXINFOS = frr.texi # because it cant just work from the png's directly it seems - contrary # to the documentation... frr.pdf: $(info_TEXINFOS) $(figures_pdf) $(frr_TEXINFOS) defines.texi - $(TEXI2PDF) -o "$@" $< + $(TEXI2PDF) -o "$@" $< || true # don't ask me why the info file is in srcdir $(srcdir)/frr.info: $(frr_TEXINFOS) defines.texi @@ -79,7 +79,7 @@ frr_TEXINFOS = appendix.texi basic.texi bgpd.texi isisd.texi filter.texi \ .dia.png: $(DIATOPNG) "$@" $< -man_MANS = frr.1 +man_MANS = frr.1 frr-args.8 if PIMD man_MANS += pimd.8 diff --git a/doc/bgpd.texi b/doc/bgpd.texi index d6b07a270f..8e0da12949 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -698,11 +698,8 @@ This command is deprecated and may be removed in a future release. Its use should be avoided. @end deffn -@c for some reason, using [all] here triggers a bug in texinfo... -@deffn {BGP} {neighbor @var{peer} next-hop-self} {} -@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {} -@deffnx {BGP} {neighbor @var{peer} next-hop-self all} {} -@deffnx {BGP} {no neighbor @var{peer} next-hop-self all} {} +@deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {} +@deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {} This command specifies an announced route's nexthop as being equivalent to the address of the bgp router if it is learned via eBGP. If the optional keyword @code{all} is specified the modifiation is done diff --git a/doc/frr-args.8.in b/doc/frr-args.8.in new file mode 100644 index 0000000000..3dc84e1e22 --- /dev/null +++ b/doc/frr-args.8.in @@ -0,0 +1,248 @@ +.TH frr-args 8 "28 August 2017" "@PACKAGE_FULLNAME@ general options" "Version @PACKAGE_VERSION@" +.SH NAME +frr-args \- common command line options for all @PACKAGE_FULLNAME@ daemons. +.SH SYNOPSIS +<\fBzebra\fR|\fBbgpd\fR|\fB...\fR> +[\fB\-h\fR] [\fB\-v\fR] + +<\fBzebra\fR|\fBbgpd\fR|\fB...\fR> +[\fB\-d\fR|\fB\-t\fR|\fB\-dt\fR] +[\fB\-C\fR] +[\fB\-f\fR \fIconfig-file\fR] +[\fB\-i\fR \fIpid-file\fR] +[\fB\-z\fR \fIzclient-path\fR] +[\fB\-u\fR \fIuser\fR] +[\fB\-g\fR \fIgroup\fR] +[\fB\-A\fR \fIvty-addr\fR] +[\fB\-P\fR \fIvty-port\fR] +[\fB\-M\fR \fImodule\fR[\fB:\fIoptions\fR]] +[\fB\-N\fR \fIpathspace\fR] +[\fB\-\-vty_socket\fR \fIvty-path\fR] +[\fB\-\-moduledir\fR \fImodule-path\fR] + +.SH DESCRIPTION +@PACKAGE_NAME@ daemons share a large part of their command line options; +this man page documents these. For options on specific daemons please refer +to their respective man pages. Most of the common options are related to +process control, configuration and common library functionality. + +.SH HELP AND VERSION +.TP +\fB\-h\fR, \fB\-\-help\fR +Print a short description of the daemon's command line options. +.TP +\fB\-v\fR, \fB\-\-version\fR +Print version and build information for the daemon. +.PP +Both of these options inhibit normal operation and will immediately exit. + +.SH PROCESS CONTROL +These options control background operation: +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Launches the process in background/daemon mode, forking and detaching from +the terminal. + +The parent process will delay its exit until the daemon/child has finished +its initialization and has entered its main loop. This is important for +\fBzebra\fR startup because the other daemons will attempt to connect to +\fBzebra\fR. A return from \fBzebra -d\fR guarantees its readiness to +accept these connections. +.TP +\fB\-t\fR, \fB\-\-terminal\fR +Opens an interactive VTY session on the terminal, allowing for both state +and configuration operations. Note that the terminal starts operating after +startup has completed and the configuration file has been loaded. + +The process will exit when end of file is detected on the terminal. It is +possible to daemonize a process started with \fB-t\fR (but without \fB-d\fR) +by sending \fISIGQUIT\fR to the process (normally mapped to a \fI^\\\fR +keypress.) +.TP +\fB\-dt\fR, \fB\-\-daemon \-\-terminal\fR +This combination of the previous two options will delay the daemon from +going into background until the terminal session ends (by end of file.) + +If the process receives \fISIGINT\fR (e.g. a \fI^C\fR keypress) in this +mode, it will exit instead of daemonizing. +.PP +It is safe to suspend (\fISIGTSTP\fR / \fI^Z\fR) the terminal session +opened by the previous two options; this will only stop the terminal but +not the protocol daemon itself (which runs in a separate second process.) + +.SH CONFIGURATION AND PATHS +The following options control configuration and file system locations for +@PACKAGE_NAME@ processes: +.TP +\fB\-f\fR, \fB\-\-config_file\fR \fIconfig-file\fR +Specify a configuration file to be used instead of the default +\fB\fI@CFG_SYSCONF@/<daemon>.conf\fR file. + +Note that the daemon will attempt to write to this file if the +\fIwrite file\fR command is issued on its VTY interface or through +\fBvtysh\fR. +.TP +\fB\-C\fR, \fB\-\-dryrun\fR +Load the configuration file and check its validity, then exit. +.TP +\fB\-i\fR, \fB\-\-pid_file\fR \fIpid-file\fR +Output a pid file to a location other than the default +\fB\fI@CFG_STATE@/<daemon>.pid\fR. +.TP +\fB\-z\fR, \fB\-\-socket\fR \fIzclient-path\fR +Override the path of the ZAPI socket used to communicate between \fBzebra\fR +and the various protocol daemons. The default is +\fB\fI@CFG_STATE@/zserv.api\fR. The value of this option must be the same +across all daemons. +.TP +\fB\-N\fR, \fB\-\-pathspace\fR \fIpathspace\fR +Insert \fIpathspace\fR into all default paths, changing the defaults to: +.IP +\fB@CFG_SYSCONF@/\fIpathspace\fB/<daemon>.conf\fR +.br +\fB@CFG_STATE@/\fIpathspace\fB/<daemon>.pid\fR +.br +\fB@CFG_STATE@/\fIpathspace\fB/<daemon>.vty\fR +.br +\fB@CFG_STATE@/\fIpathspace\fB/zserv.api\fR + +\'.\' and \'/\' characters will not be accepted in \fIpathspace\fR, but the +empty string will be accepted. + +Note that this only changes the respective defaults, it has no effect on +the respective path if the \fB\-f\fR, \fB\-i\fR, \fB\-z\fR or +\fB\-\-vty_socket\fR options are used. + +The purpose of this option is to easily group all file system related +bits together for running multiple fully-separate "logical routers" on a +system, particularly with Linux network namespaces. Groups of daemons +running with distinct \fIpathspace\fR values will be completely unaware +of each other and not interact in any way. + +This option does not do any system setup (like network namespaces.) This +must be done by the user, for example by running: +.IP +\fBip netns exec \fInamespace \fB<daemon> -N \fInamespace\fR + +.SH PROCESS CREDENTIALS +.TP +\fB\-u\fR, \fB\-\-user\fR \fIuser\fR +(default: \fB@enable_user@\fR) +.TP +\fB\-g\fR, \fB\-\-group\fR \fIgroup\fR +(default: \fB@enable_group@\fR) +.IP +Change the user/group which the daemon will switch to. +.PP +Note that there is an additional group, \fB@enable_vty_group@\fR, which +controls group ownership of the VTY sockets. The name of this group cannot +currently be changed, and \fIuser\fR must be a member of this group. + +.SH VTY SETUP +These following options control the daemon's VTY (interactive command line) +interface. The interface is available over TCP, using the telnet protocol, +as well as through the \fBvtysh\fR frontend. +.TP +\fB\-A\fR, \fB--vty_addr\fR \fIvty-addr\fR +Specify an IP/IPv6 address to bind the TCP VTY interface to. It is +generally recommended to specify \fI::1\fR or \fI127.0.0.1\fR. For reasons +of backwards compatibility, the default is to listen on all interfaces. +.TP +\fB\-P\fR, \fB--vty_port\fR \fIvty-port\fR +Override the daemon's default TCP VTY port (each daemon has a different +default value upwards of 2600, listed below.) Specifying \fI0\fR disables +the TCP VTY interface. + +Default ports are: + +.ta 16m +zebra 2601 +.br +ripd 2602 +.br +ripngd 2603 +.br +ospfd 2604 +.br +bgpd 2605 +.br +ospf6d 2606 +.br +isisd 2608 +.br +babeld 2609 +.br +nhrpd 2610 +.br +pimd 2611 +.br +ldpd 2612 +.br +eigrpd 2613 + +Port 2607 is used for ospfd's Opaque LSA API, while port 2600 is used for +the (insecure) TCP-ZEBRA interface. +.TP +\fB\-\-vty_socket\fR \fIvty-path\fR +Overrides the directory used for the \fB<daemon>.vty\fR sockets. +\fBvtysh\fR connects to these sockets in order to access each daemon's +VTY. +.br +Default: \fB\fI@CFG_STATE@\fR[\fB/\fI<pathspace>\fR] + +NB: Unlike the other options, this option specifies a \fBdirectory\fR, +not a full path. + +This option is primarily used by the SNAP packaging system, its semantics +may change. It should not be neccessary in most other scenarios. + +.SH MODULE LOADING +@PACKAGE_NAME@ supports optional dynamically loadable modules, although +these can only be loaded at startup. The set of available modules may vary +across distributions and packages, and modules may be available for +installation as separate packages. +.TP +\fB\-M\fR, \fB\-\-module\fR \fImodule\fR[\fB:\fIoptions\fR] +Load a module named \fImodule\fR, optionally passing \fIoptions\fR to it. + +If there is a \'/\' character in \fImodule\fR, the value is assumed to be +a pathname to a module. + +If there is no \'/\' character, the module directory (see next option) +is searched first for a module named "\fI<daemon>\fB_\fI<module>\fB.so\fR", +then for "\fI<module>\fB.so\fR". +This allows for a module to exist in variations appropriate for particular +daemons, e.g. \fIzebra_snmp\fR and \fIbgp_snmp\fR, with the correct one +selected by \fI\-M snmp\fR. + +The meaning of \fIoptions\fR is specific to the module being loaded. Most +modules currently ignore it. + +Modules are loaded in the order as listed on the command line. This is +not generally relevant. +.TP +\fB\-\-moduledir\fR \fImodule-path\fR +Look for modules in the \fImodule-path\fR directory instead of the default +\fI@CFG_MODULE@\fR. (This path is \fBnot\fR affected by the \fB\-N\fR +option.) +.PP +The list of loaded modules can be inspected at runtime with the +\fBshow modules\fR VTY command. + + +.SH "SEE ALSO" +.BR zebra (8), +.BR vtysh (1), +.BR ripd (8), +.BR ripngd (8), +.BR ospfd (8), +.BR ospf6d (8), +.BR bgpd (8), +.BR isisd (8), +.BR babeld (8), +.BR nhrpd (8), +.BR pimd (8), +.BR ldpd (8), +.BR eigrpd (8) + +\fIhttps://frrouting.org/ diff --git a/doc/main.texi b/doc/main.texi index 265d6295ef..9e2ca5e506 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -65,6 +65,17 @@ Up or down the current interface. Set the IPv4 or IPv6 address/prefix for the interface. @end deffn +@deffn {Interface Command} {ip address @var{local-addr} peer @var{peer-addr/prefix}} {} +@deffnx {Interface Command} {no ip address @var{local-addr} peer @var{peer-addr/prefix}} {} +Configure an IPv4 Pointopoint address on the interface. +(The concept of PtP addressing does not exist for IPv6.) + +@var{local-addr} has no subnet mask since the local side in PtP +addressing is always a single (/32) address. @var{peer-addr/prefix} +can be an arbitrary subnet behind the other end of the link (or even on the +link in Point-to-Multipoint setups), though generally /32s are used. +@end deffn + @deffn {Interface Command} {ip address @var{address/prefix} secondary} {} @deffnx {Interface Command} {no ip address @var{address/prefix} secondary} {} Set the secondary flag for this address. This causes ospfd to not treat the diff --git a/eigrpd/eigrp_const.h b/eigrpd/eigrp_const.h index a008891a51..3fa59756b7 100644 --- a/eigrpd/eigrp_const.h +++ b/eigrpd/eigrp_const.h @@ -130,10 +130,10 @@ enum metric_change { #define EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL 2 // Remote external network /*EIGRP TT entry flags*/ -#define EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG (1 << 0) -#define EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG (1 << 1) -#define EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG (1 << 2) -#define EIGRP_NEIGHBOR_ENTRY_EXTERNAL_FLAG (1 << 3) +#define EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG (1 << 0) +#define EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG (1 << 1) +#define EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG (1 << 2) +#define EIGRP_NEXTHOP_ENTRY_EXTERNAL_FLAG (1 << 3) /*EIGRP FSM state count, event count*/ #define EIGRP_FSM_STATE_MAX 5 diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index 74515c98cb..091b271129 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -295,15 +295,17 @@ void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn) vty_out(vty, "%s, ", prefix2str(tn->destination, buffer, PREFIX_STRLEN)); - vty_out(vty, "%u successors, ", successors->count); + vty_out(vty, "%u successors, ", + (successors) ? successors->count : 0); vty_out(vty, "FD is %u, serno: %" PRIu64 " \n", tn->fdistance, tn->serno); - list_delete(successors); + if (successors) + list_delete(successors); } -void show_ip_eigrp_neighbor_entry(struct vty *vty, struct eigrp *eigrp, - struct eigrp_neighbor_entry *te, int *first) +void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp, + struct eigrp_nexthop_entry *te, int *first) { if (te->reported_distance == EIGRP_MAX_METRIC) return; diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h index 7f9381595a..cda304ba6d 100644 --- a/eigrpd/eigrp_dump.h +++ b/eigrpd/eigrp_dump.h @@ -156,8 +156,8 @@ extern void show_ip_eigrp_neighbor_sub(struct vty *, struct eigrp_neighbor *, int); extern void show_ip_eigrp_prefix_entry(struct vty *, struct eigrp_prefix_entry *); -extern void show_ip_eigrp_neighbor_entry(struct vty *, struct eigrp *, - struct eigrp_neighbor_entry *, int *); +extern void show_ip_eigrp_nexthop_entry(struct vty *, struct eigrp *, + struct eigrp_nexthop_entry *, int *); extern void eigrp_debug_init(void); diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c index 47cd112cf5..4514e5b9a8 100644 --- a/eigrpd/eigrp_fsm.c +++ b/eigrpd/eigrp_fsm.c @@ -183,12 +183,12 @@ static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) // Loading base information from message // struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_neighbor_entry *entry = msg->entry; + struct eigrp_nexthop_entry *entry = msg->entry; u_char actual_state = prefix->state; enum metric_change change; if (entry == NULL) { - entry = eigrp_neighbor_entry_new(); + entry = eigrp_nexthop_entry_new(); entry->adv_router = msg->adv_router; entry->ei = msg->adv_router->ei; entry->prefix = prefix; @@ -203,7 +203,7 @@ static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) switch (actual_state) { case EIGRP_FSM_STATE_PASSIVE: { - struct eigrp_neighbor_entry *head = + struct eigrp_nexthop_entry *head = listnode_head(prefix->entries); if (head->reported_distance < prefix->fdistance) { @@ -224,7 +224,7 @@ static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } case EIGRP_FSM_STATE_ACTIVE_0: { if (msg->packet_type == EIGRP_OPC_REPLY) { - struct eigrp_neighbor_entry *head = + struct eigrp_nexthop_entry *head = listnode_head(prefix->entries); listnode_delete(prefix->rij, entry->adv_router); @@ -240,7 +240,7 @@ static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) return EIGRP_FSM_EVENT_LR_FCN; } else if (msg->packet_type == EIGRP_OPC_QUERY && (entry->flags - & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_QACT; } @@ -250,14 +250,14 @@ static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } case EIGRP_FSM_STATE_ACTIVE_1: { if (msg->packet_type == EIGRP_OPC_QUERY - && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + && (entry->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_QACT; } else if (msg->packet_type == EIGRP_OPC_REPLY) { listnode_delete(prefix->rij, entry->adv_router); if (change == METRIC_INCREASE && (entry->flags - & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_DINC; } else if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; @@ -267,7 +267,7 @@ static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1 && (entry->flags - & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_DINC; } return EIGRP_FSM_KEEP_STATE; @@ -276,7 +276,7 @@ static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } case EIGRP_FSM_STATE_ACTIVE_2: { if (msg->packet_type == EIGRP_OPC_REPLY) { - struct eigrp_neighbor_entry *head = + struct eigrp_nexthop_entry *head = listnode_head(prefix->entries); listnode_delete(prefix->rij, entry->adv_router); @@ -302,7 +302,7 @@ static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) if (change == METRIC_INCREASE && (entry->flags - & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_DINC; } else if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; @@ -312,7 +312,7 @@ static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1 && (entry->flags - & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_DINC; } return EIGRP_FSM_KEEP_STATE; @@ -348,7 +348,7 @@ int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg) struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; struct list *successors = eigrp_topology_get_successor(prefix); - struct eigrp_neighbor_entry *ne; + struct eigrp_nexthop_entry *ne; assert(successors); // If this is NULL we have shit the bed, fun huh? @@ -376,7 +376,7 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; struct list *successors = eigrp_topology_get_successor(prefix); - struct eigrp_neighbor_entry *ne; + struct eigrp_nexthop_entry *ne; assert(successors); // If this is NULL somebody poked us in the eye. @@ -401,7 +401,7 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) { struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_neighbor_entry *ne = listnode_head(prefix->entries); + struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); if (prefix->state == EIGRP_FSM_STATE_PASSIVE) { if (!eigrp_metrics_is_same(prefix->reported_metric, @@ -431,7 +431,7 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_neighbor_entry *ne = listnode_head(prefix->entries); + struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); prefix->fdistance = prefix->distance = prefix->rdistance = ne->distance; @@ -461,7 +461,7 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg) { struct list *successors = eigrp_topology_get_successor(msg->prefix); - struct eigrp_neighbor_entry *ne; + struct eigrp_nexthop_entry *ne; assert(successors); // Trump and his big hands @@ -483,7 +483,7 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_neighbor_entry *ne = listnode_head(prefix->entries); + struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); prefix->state = EIGRP_FSM_STATE_PASSIVE; prefix->distance = prefix->rdistance = ne->distance; @@ -515,7 +515,7 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_neighbor_entry *best_successor; + struct eigrp_nexthop_entry *best_successor; struct list *successors = eigrp_topology_get_successor(prefix); assert(successors); // Routing without a stack @@ -544,7 +544,7 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg) { struct list *successors = eigrp_topology_get_successor(msg->prefix); - struct eigrp_neighbor_entry *ne; + struct eigrp_nexthop_entry *ne; assert(successors); // Cats and no Dogs diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c index ef10ebf54c..49647c6b85 100644 --- a/eigrpd/eigrp_hello.c +++ b/eigrpd/eigrp_hello.c @@ -412,11 +412,15 @@ void eigrp_sw_version_initialize(void) { char ver_string[] = VERSION; char *dash = strstr(ver_string, "-"); + int ret; if (dash) dash[0] = '\0'; - sscanf(ver_string, "%d.%d", &FRR_MAJOR, &FRR_MINOR); + ret = sscanf(ver_string, "%d.%d", &FRR_MAJOR, &FRR_MINOR); + if (ret != 2) + zlog_err("Did not Properly parse %s, please fix VERSION string", + VERSION); } /** diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index aa59516002..f2512eadad 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -245,19 +245,18 @@ struct eigrp_if_params *eigrp_lookup_if_params(struct interface *ifp, int eigrp_if_up(struct eigrp_interface *ei) { struct eigrp_prefix_entry *pe; - struct eigrp_neighbor_entry *ne; + struct eigrp_nexthop_entry *ne; struct eigrp_metrics metric; struct eigrp_interface *ei2; struct listnode *node, *nnode; - struct eigrp *eigrp = eigrp_lookup(); + struct eigrp *eigrp; if (ei == NULL) return 0; - if (eigrp != NULL) - eigrp_adjust_sndbuflen(eigrp, ei->ifp->mtu); - else - zlog_warn("%s: eigrp_lookup () returned NULL", __func__); + eigrp = ei->eigrp; + eigrp_adjust_sndbuflen(eigrp, ei->ifp->mtu); + eigrp_if_stream_set(ei); /* Set multicast memberships appropriately for new state. */ @@ -280,14 +279,14 @@ int eigrp_if_up(struct eigrp_interface *ei) /*Add connected entry to topology table*/ - ne = eigrp_neighbor_entry_new(); + ne = eigrp_nexthop_entry_new(); ne->ei = ei; ne->reported_metric = metric; ne->total_metric = metric; ne->distance = eigrp_calculate_metrics(eigrp, metric); ne->reported_distance = 0; ne->adv_router = eigrp->neighbor_self; - ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; + ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; struct prefix dest_addr; @@ -314,7 +313,7 @@ int eigrp_if_up(struct eigrp_interface *ei) eigrp_prefix_entry_add(eigrp->topology_table, pe); listnode_add(eigrp->topology_changes_internalIPV4, pe); - eigrp_neighbor_entry_add(pe, ne); + eigrp_nexthop_entry_add(pe, ne); for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) { eigrp_update_send(ei2); @@ -326,7 +325,7 @@ int eigrp_if_up(struct eigrp_interface *ei) struct eigrp_fsm_action_message msg; ne->prefix = pe; - eigrp_neighbor_entry_add(pe, ne); + eigrp_nexthop_entry_add(pe, ne); msg.packet_type = EIGRP_OPC_UPDATE; msg.eigrp = eigrp; diff --git a/eigrpd/eigrp_memory.c b/eigrpd/eigrp_memory.c index a8f603d2e5..85b14c28ce 100644 --- a/eigrpd/eigrp_memory.c +++ b/eigrpd/eigrp_memory.c @@ -38,5 +38,5 @@ DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV") DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV") DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV") DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_ENTRY, "EIGRP Prefix") -DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR_ENTRY, "EIGRP Neighbor Entry") +DEFINE_MTYPE(EIGRPD, EIGRP_NEXTHOP_ENTRY, "EIGRP Nexthop Entry") DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message") diff --git a/eigrpd/eigrp_memory.h b/eigrpd/eigrp_memory.h index b8c85a49b0..e4d02c09d4 100644 --- a/eigrpd/eigrp_memory.h +++ b/eigrpd/eigrp_memory.h @@ -37,7 +37,7 @@ DECLARE_MTYPE(EIGRP_SEQ_TLV) DECLARE_MTYPE(EIGRP_AUTH_TLV) DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV) DECLARE_MTYPE(EIGRP_PREFIX_ENTRY) -DECLARE_MTYPE(EIGRP_NEIGHBOR_ENTRY) +DECLARE_MTYPE(EIGRP_NEXTHOP_ENTRY) DECLARE_MTYPE(EIGRP_FSM_MSG) #endif /* _FRR_EIGRP_MEMORY_H */ diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c index 5d78dc375c..b7b336949e 100644 --- a/eigrpd/eigrp_neighbor.c +++ b/eigrpd/eigrp_neighbor.c @@ -358,7 +358,7 @@ void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty) eigrp_nbr_delete(nbr); } -int eigrp_nbr_split_horizon_check(struct eigrp_neighbor_entry *ne, struct eigrp_interface *ei) +int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne, struct eigrp_interface *ei) { if (ne->distance == EIGRP_MAX_METRIC) return 0; diff --git a/eigrpd/eigrp_neighbor.h b/eigrpd/eigrp_neighbor.h index 6467fb24a9..b939e25e5e 100644 --- a/eigrpd/eigrp_neighbor.h +++ b/eigrpd/eigrp_neighbor.h @@ -53,6 +53,6 @@ extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr_process(struct eigrp *, struct in_addr); extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty); -extern int eigrp_nbr_split_horizon_check(struct eigrp_neighbor_entry *ne, +extern int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne, struct eigrp_interface *ei); #endif /* _ZEBRA_EIGRP_NEIGHBOR_H */ diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index 0cf5bd9bad..c5f4080317 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -413,7 +413,7 @@ u_int32_t eigrp_calculate_metrics(struct eigrp *eigrp, } u_int32_t eigrp_calculate_total_metrics(struct eigrp *eigrp, - struct eigrp_neighbor_entry *entry) + struct eigrp_nexthop_entry *entry) { entry->total_metric = entry->reported_metric; uint64_t temp_delay = (uint64_t)entry->total_metric.delay diff --git a/eigrpd/eigrp_network.h b/eigrpd/eigrp_network.h index 6ddd57eee5..77bd1416fc 100644 --- a/eigrpd/eigrp_network.h +++ b/eigrpd/eigrp_network.h @@ -45,7 +45,7 @@ extern void eigrp_adjust_sndbuflen(struct eigrp *, unsigned int); extern u_int32_t eigrp_calculate_metrics(struct eigrp *, struct eigrp_metrics); extern u_int32_t eigrp_calculate_total_metrics(struct eigrp *, - struct eigrp_neighbor_entry *); + struct eigrp_nexthop_entry *); extern u_char eigrp_metrics_is_same(struct eigrp_metrics, struct eigrp_metrics); extern void eigrp_external_routes_refresh(struct eigrp *, int); diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index 68e7cdcbbe..8a7d4d9587 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -193,6 +193,12 @@ int eigrp_check_md5_digest(struct stream *s, if (keychain) key = key_lookup_for_send(keychain); + if (!key) { + zlog_warn("Interface %s: Expected key value not found in config", + nbr->ei->ifp->name); + return 0; + } + memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); @@ -229,8 +235,7 @@ int eigrp_check_md5_digest(struct stream *s, } /* save neighbor's crypt_seqnum */ - if (nbr) - nbr->crypt_seqnum = authTLV->key_sequence; + nbr->crypt_seqnum = authTLV->key_sequence; return 1; } @@ -240,10 +245,11 @@ int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s, { struct key *key = NULL; struct keychain *keychain; - char *source_ip; + char source_ip[PREFIX_STRLEN]; unsigned char digest[EIGRP_AUTH_TYPE_SHA256_LEN]; unsigned char buffer[1 + PLAINTEXT_LENGTH + 45 + 1] = {0}; + HMAC_SHA256_CTX ctx; void *ibuf; size_t backup_get, backup_end; @@ -263,11 +269,13 @@ int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s, if (keychain) key = key_lookup_for_send(keychain); - // saved_len[index] = strnzcpyn(saved_key[index], key, - // PLAINTEXT_LENGTH + 1); + if (!key) { + zlog_warn("Interface %s: Expected key value not found in config", + ei->ifp->name); + return 0; + } - source_ip = calloc(16, sizeof(char)); - inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, 16); + inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, PREFIX_STRLEN); memset(&ctx, 0, sizeof(ctx)); buffer[0] = '\n'; @@ -287,7 +295,6 @@ int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s, stream_set_endp(s, backup_end); eigrp_authTLV_SHA256_free(auth_TLV); - free(source_ip); return EIGRP_AUTH_TYPE_SHA256_LEN; } @@ -613,10 +620,10 @@ int eigrp_read(struct thread *thread) opcode = eigrph->opcode; if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) { - char src[100], dst[100]; + char src[PREFIX_STRLEN], dst[PREFIX_STRLEN]; - strcpy(src, inet_ntoa(iph->ip_src)); - strcpy(dst, inet_ntoa(iph->ip_dst)); + strncpy(src, inet_ntoa(iph->ip_src), PREFIX_STRLEN); + strncpy(dst, inet_ntoa(iph->ip_dst), PREFIX_STRLEN); zlog_debug("Received [%s][%d/%d] length [%u] via [%s] src [%s] dst [%s]", lookup_msg(eigrp_packet_type_str, opcode, NULL), ntohl(eigrph->sequence), ntohl(eigrph->ack), length, diff --git a/eigrpd/eigrp_packet.h b/eigrpd/eigrp_packet.h index e52fd268fa..a7d510218f 100644 --- a/eigrpd/eigrp_packet.h +++ b/eigrpd/eigrp_packet.h @@ -83,6 +83,10 @@ extern int eigrp_hello_timer(struct thread *); /* * These externs are found in eigrp_update.c */ +extern bool eigrp_update_prefix_apply(struct eigrp *eigrp, + struct eigrp_interface *ei, + int in, + struct prefix *prefix); extern void eigrp_update_send(struct eigrp_interface *); extern void eigrp_update_receive(struct eigrp *, struct ip *, struct eigrp_header *, struct stream *, diff --git a/eigrpd/eigrp_query.c b/eigrpd/eigrp_query.c index 0167c8b3c2..03c3705ffd 100644 --- a/eigrpd/eigrp_query.c +++ b/eigrpd/eigrp_query.c @@ -126,7 +126,7 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph, * know)*/ if (dest != NULL) { struct eigrp_fsm_action_message msg; - struct eigrp_neighbor_entry *entry = + struct eigrp_nexthop_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); msg.packet_type = EIGRP_OPC_QUERY; diff --git a/eigrpd/eigrp_reply.c b/eigrpd/eigrp_reply.c index 2b5b0aa44b..20d8b1b47c 100644 --- a/eigrpd/eigrp_reply.c +++ b/eigrpd/eigrp_reply.c @@ -64,43 +64,20 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe) { struct eigrp_packet *ep; u_int16_t length = EIGRP_HEADER_LEN; - - struct access_list *alist; - struct prefix_list *plist; - struct access_list *alist_i; - struct prefix_list *plist_i; - struct eigrp *e; + struct eigrp_interface *ei = nbr->ei; + struct eigrp *eigrp = ei->eigrp; struct eigrp_prefix_entry *pe2; // TODO: Work in progress /* Filtering */ /* get list from eigrp process */ - e = eigrp_lookup(); pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, sizeof(struct eigrp_prefix_entry)); memcpy(pe2, pe, sizeof(struct eigrp_prefix_entry)); - /* Get access-lists and prefix-lists from process and interface */ - alist = e->list[EIGRP_FILTER_OUT]; - plist = e->prefix[EIGRP_FILTER_OUT]; - alist_i = nbr->ei->list[EIGRP_FILTER_OUT]; - plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT]; - - /* Check if any list fits */ - if ((alist - && access_list_apply(alist, pe2->destination) - == FILTER_DENY) - || (plist - && prefix_list_apply(plist, - pe2->destination) - == PREFIX_DENY) - || (alist_i - && access_list_apply(alist_i, - pe2->destination) - == FILTER_DENY) - || (plist_i - && prefix_list_apply(plist_i, - pe2->destination) - == PREFIX_DENY)) { + + if (eigrp_update_prefix_apply(eigrp, ei, + EIGRP_FILTER_OUT, + pe2->destination)) { zlog_info("REPLY SEND: Setting Metric to max"); pe2->reported_metric.delay = EIGRP_MAX_METRIC; @@ -110,34 +87,34 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe) * End of filtering */ - ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); + ep = eigrp_packet_new(ei->ifp->mtu, nbr); /* Prepare EIGRP INIT UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_REPLY, e, ep->s, 0, - nbr->ei->eigrp->sequence_number, 0); + eigrp_packet_header_init(EIGRP_OPC_REPLY, eigrp, ep->s, 0, + eigrp->sequence_number, 0); // encode Authentication TLV, if needed - if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) - && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) { - length += eigrp_add_authTLV_MD5_to_stream(ep->s, nbr->ei); + if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) + && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) { + length += eigrp_add_authTLV_MD5_to_stream(ep->s, ei); } length += eigrp_add_internalTLV_to_stream(ep->s, pe2); - if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) - && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) { - eigrp_make_md5_digest(nbr->ei, ep->s, EIGRP_AUTH_UPDATE_FLAG); + if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) + && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) { + eigrp_make_md5_digest(ei, ep->s, EIGRP_AUTH_UPDATE_FLAG); } /* EIGRP Checksum */ - eigrp_packet_checksum(nbr->ei, ep->s, length); + eigrp_packet_checksum(ei, ep->s, length); ep->length = length; ep->dst.s_addr = nbr->src.s_addr; /*This ack number we await from neighbor*/ - ep->sequence_number = nbr->ei->eigrp->sequence_number; + ep->sequence_number = eigrp->sequence_number; /*Put packet to retransmission queue*/ eigrp_fifo_push(nbr->retrans_queue, ep); @@ -157,12 +134,6 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph, struct eigrp_neighbor *nbr; struct TLV_IPv4_Internal_type *tlv; - struct access_list *alist; - struct prefix_list *plist; - struct access_list *alist_i; - struct prefix_list *plist_i; - struct eigrp *e; - u_int16_t type; /* increment statistics. */ @@ -197,38 +168,12 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph, assert(dest); struct eigrp_fsm_action_message msg; - struct eigrp_neighbor_entry *entry = + struct eigrp_nexthop_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); - /* - * Filtering - */ - // TODO: Work in progress - /* get list from eigrp process */ - e = eigrp_lookup(); - /* Get access-lists and prefix-lists from process and - * interface */ - alist = e->list[EIGRP_FILTER_IN]; - plist = e->prefix[EIGRP_FILTER_IN]; - alist_i = ei->list[EIGRP_FILTER_IN]; - plist_i = ei->prefix[EIGRP_FILTER_IN]; - /* Check if any list fits */ - if ((alist - && access_list_apply(alist, - (struct prefix *)&dest_addr) - == FILTER_DENY) - || (plist - && prefix_list_apply( - plist, (struct prefix *)&dest_addr) - == PREFIX_DENY) - || (alist_i - && access_list_apply( - alist_i, (struct prefix *)&dest_addr) - == FILTER_DENY) - || (plist_i - && prefix_list_apply( - plist_i, (struct prefix *)&dest_addr) - == PREFIX_DENY)) { + if (eigrp_update_prefix_apply(eigrp, ei, + EIGRP_FILTER_IN, + &dest_addr)) { tlv->metric.delay = EIGRP_MAX_METRIC; } /* diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index b645ed1987..9f80c6c017 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -137,16 +137,19 @@ static int eigrp_route_match_add(struct vty *vty, struct route_map_index *index, { int ret; ret = route_map_add_match(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% Can't find rule.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; - } + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% Can't find rule.\n"); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, "%% Argument is malformed.\n"); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + break; } + return CMD_SUCCESS; } @@ -157,16 +160,19 @@ static int eigrp_route_match_delete(struct vty *vty, { int ret; ret = route_map_delete_match(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% Can't find rule.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; - } + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% Can't find rule.\n"); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, "%% Argument is malformed.\n"); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + break; } + return CMD_SUCCESS; } @@ -177,25 +183,27 @@ static int eigrp_route_set_add(struct vty *vty, struct route_map_index *index, int ret; ret = route_map_add_set(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% Can't find rule.\n"); + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% Can't find rule.\n"); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + /* + * rip, ripng and other protocols share the set metric command + * but only values from 0 to 16 are valid for rip and ripng + * if metric is out of range for rip and ripng, it is + * not for other protocols. Do not return an error + */ + if (strcmp(command, "metric")) { + vty_out(vty, "%% Argument is malformed.\n"); return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - /* rip, ripng and other protocols share the set metric - command - but only values from 0 to 16 are valid for rip and - ripng - if metric is out of range for rip and ripng, it is - not for - other protocols. Do not return an error */ - if (strcmp(command, "metric")) { - vty_out(vty, "%% Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; - } } + break; + case RMAP_COMPILE_SUCCESS: + break; } + return CMD_SUCCESS; } @@ -207,16 +215,19 @@ static int eigrp_route_set_delete(struct vty *vty, int ret; ret = route_map_delete_set(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% Can't find rule.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; - } + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% Can't find rule.\n"); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, "%% Argument is malformed.\n"); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + break; } + return CMD_SUCCESS; } @@ -247,7 +258,7 @@ static route_map_result_t route_match_metric(void *rule, struct prefix *prefix, // u_int32_t *metric; // u_int32_t check; // struct rip_info *rinfo; - // struct eigrp_neighbor_entry *te; + // struct eigrp_nexthop_entry *te; // struct eigrp_prefix_entry *pe; // struct listnode *node, *node2, *nnode, *nnode2; // struct eigrp *e; diff --git a/eigrpd/eigrp_routemap.h b/eigrpd/eigrp_routemap.h index f378d88cd8..1d37b25efc 100644 --- a/eigrpd/eigrp_routemap.h +++ b/eigrpd/eigrp_routemap.h @@ -8,6 +8,12 @@ #ifndef EIGRPD_EIGRP_ROUTEMAP_H_ #define EIGRPD_EIGRP_ROUTEMAP_H_ +#include "if_rmap.h" + +extern bool eigrp_routemap_prefix_apply(struct eigrp *eigrp, + struct eigrp_interface *ei, + int in, + struct prefix *prefix); extern void eigrp_route_map_update(const char *); extern void eigrp_route_map_init(); extern void eigrp_if_rmap_update(struct if_rmap *); diff --git a/eigrpd/eigrp_siaquery.c b/eigrpd/eigrp_siaquery.c index 7264e53b6b..b242bcaae9 100644 --- a/eigrpd/eigrp_siaquery.c +++ b/eigrpd/eigrp_siaquery.c @@ -95,7 +95,7 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph, * know)*/ if (dest != NULL) { struct eigrp_fsm_action_message msg; - struct eigrp_neighbor_entry *entry = + struct eigrp_nexthop_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); msg.packet_type = EIGRP_OPC_SIAQUERY; diff --git a/eigrpd/eigrp_siareply.c b/eigrpd/eigrp_siareply.c index 8496c05675..4998a2d54b 100644 --- a/eigrpd/eigrp_siareply.c +++ b/eigrpd/eigrp_siareply.c @@ -94,7 +94,7 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph, * know)*/ if (dest != NULL) { struct eigrp_fsm_action_message msg; - struct eigrp_neighbor_entry *entry = + struct eigrp_nexthop_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); msg.packet_type = EIGRP_OPC_SIAQUERY; diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h index b769774a03..5bc63a7c47 100644 --- a/eigrpd/eigrp_structs.h +++ b/eigrpd/eigrp_structs.h @@ -480,7 +480,7 @@ struct eigrp_prefix_entry { }; /* EIGRP Topology table record structure */ -struct eigrp_neighbor_entry { +struct eigrp_nexthop_entry { struct eigrp_prefix_entry *prefix; u_int32_t reported_distance; // distance reported by neighbor u_int32_t distance; // sum of reported distance and link cost to @@ -508,7 +508,7 @@ struct eigrp_fsm_action_message { u_char packet_type; // UPDATE, QUERY, SIAQUERY, SIAREPLY struct eigrp *eigrp; // which thread sent mesg struct eigrp_neighbor *adv_router; // advertising neighbor - struct eigrp_neighbor_entry *entry; + struct eigrp_nexthop_entry *entry; struct eigrp_prefix_entry *prefix; msg_data_t data_type; // internal or external tlv type struct eigrp_metrics metrics; diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c index 64e65b694c..f1bc83af63 100644 --- a/eigrpd/eigrp_topology.c +++ b/eigrpd/eigrp_topology.c @@ -54,8 +54,8 @@ static int eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *, struct eigrp_prefix_entry *); static void eigrp_prefix_entry_del(struct eigrp_prefix_entry *); -static int eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *, - struct eigrp_neighbor_entry *); +static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *, + struct eigrp_nexthop_entry *); /* * Returns linkedlist used as topology table @@ -116,7 +116,7 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new() sizeof(struct eigrp_prefix_entry)); new->entries = list_new(); new->rij = list_new(); - new->entries->cmp = (int (*)(void *, void *))eigrp_neighbor_entry_cmp; + new->entries->cmp = (int (*)(void *, void *))eigrp_nexthop_entry_cmp; new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC; new->destination = NULL; @@ -126,8 +126,8 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new() /* * Topology entry comparison */ -static int eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *entry1, - struct eigrp_neighbor_entry *entry2) +static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1, + struct eigrp_nexthop_entry *entry2) { if (entry1->distance < entry2->distance) return -1; @@ -141,12 +141,12 @@ static int eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *entry1, * Returns new topology entry */ -struct eigrp_neighbor_entry *eigrp_neighbor_entry_new() +struct eigrp_nexthop_entry *eigrp_nexthop_entry_new() { - struct eigrp_neighbor_entry *new; + struct eigrp_nexthop_entry *new; - new = XCALLOC(MTYPE_EIGRP_NEIGHBOR_ENTRY, - sizeof(struct eigrp_neighbor_entry)); + new = XCALLOC(MTYPE_EIGRP_NEXTHOP_ENTRY, + sizeof(struct eigrp_nexthop_entry)); new->reported_distance = EIGRP_MAX_METRIC; new->distance = EIGRP_MAX_METRIC; @@ -185,8 +185,8 @@ void eigrp_prefix_entry_add(struct list *topology, /* * Adding topology entry to topology node */ -void eigrp_neighbor_entry_add(struct eigrp_prefix_entry *node, - struct eigrp_neighbor_entry *entry) +void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *node, + struct eigrp_nexthop_entry *entry) { struct list *l = list_new(); @@ -229,13 +229,13 @@ void eigrp_prefix_entry_delete(struct list *topology, /* * Deleting topology entry from topology node */ -void eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *node, - struct eigrp_neighbor_entry *entry) +void eigrp_nexthop_entry_delete(struct eigrp_prefix_entry *node, + struct eigrp_nexthop_entry *entry) { if (listnode_lookup(node->entries, entry) != NULL) { listnode_delete(node->entries, entry); eigrp_zebra_route_delete(node->destination); - XFREE(MTYPE_EIGRP_NEIGHBOR_ENTRY, entry); + XFREE(MTYPE_EIGRP_NEXTHOP_ENTRY, entry); } } @@ -283,11 +283,11 @@ eigrp_topology_table_lookup_ipv4(struct list *topology_table, struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node) { struct list *successors = list_new(); - struct eigrp_neighbor_entry *data; + struct eigrp_nexthop_entry *data; struct listnode *node1, *node2; for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) { - if (data->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) { + if (data->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) { listnode_add(successors, data); } } @@ -321,10 +321,10 @@ eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node, return successors; } -struct eigrp_neighbor_entry * +struct eigrp_nexthop_entry * eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr) { - struct eigrp_neighbor_entry *data; + struct eigrp_nexthop_entry *data; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS(entries, node, nnode, data)) { if (data->adv_router == nbr) { @@ -341,7 +341,7 @@ struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp, { struct listnode *node1, *node11, *node2, *node22; struct eigrp_prefix_entry *prefix; - struct eigrp_neighbor_entry *entry; + struct eigrp_nexthop_entry *entry; /* create new empty list for prefixes storage */ struct list *prefixes = list_new(); @@ -365,7 +365,7 @@ enum metric_change eigrp_topology_update_distance(struct eigrp_fsm_action_messag { struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_neighbor_entry *entry = msg->entry; + struct eigrp_nexthop_entry *entry = msg->entry; enum metric_change change = METRIC_SAME; u_int32_t new_reported_distance; @@ -439,24 +439,24 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp) void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest) { struct listnode *node; - struct eigrp_neighbor_entry *entry; + struct eigrp_nexthop_entry *entry; struct eigrp *eigrp = eigrp_lookup(); for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) { if (((uint64_t)entry->distance - <= (uint64_t)(dest->distance * eigrp->variance)) + <= (uint64_t)dest->distance * (uint64_t)eigrp->variance) && entry->distance != EIGRP_MAX_METRIC) // is successor { - entry->flags |= EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; - entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG; + entry->flags |= EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; + entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG; } else if (entry->reported_distance < dest->fdistance) // is feasible successor { - entry->flags |= EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG; - entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; + entry->flags |= EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG; + entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; } else { - entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG; - entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; + entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG; + entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; } } } @@ -467,19 +467,19 @@ void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix) struct list *successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths); struct listnode *node; - struct eigrp_neighbor_entry *entry; + struct eigrp_nexthop_entry *entry; if (successors) { eigrp_zebra_route_add(prefix->destination, successors); for (ALL_LIST_ELEMENTS_RO(successors, node, entry)) - entry->flags |= EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG; + entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG; list_delete(successors); } else { eigrp_zebra_route_delete(prefix->destination); for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry)) - entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG; + entry->flags &= ~EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG; } } @@ -488,7 +488,7 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp, { struct listnode *node1, *node11, *node2, *node22; struct eigrp_prefix_entry *prefix; - struct eigrp_neighbor_entry *entry; + struct eigrp_nexthop_entry *entry; for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix)) { for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry)) { @@ -517,10 +517,10 @@ void eigrp_update_topology_table_prefix(struct list *table, { struct listnode *node1, *node2; - struct eigrp_neighbor_entry *entry; + struct eigrp_nexthop_entry *entry; for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) { if (entry->distance == EIGRP_MAX_METRIC) { - eigrp_neighbor_entry_delete(prefix, entry); + eigrp_nexthop_entry_delete(prefix, entry); } } if (prefix->distance == EIGRP_MAX_METRIC diff --git a/eigrpd/eigrp_topology.h b/eigrpd/eigrp_topology.h index 8bff08b75a..ef5b32d5bf 100644 --- a/eigrpd/eigrp_topology.h +++ b/eigrpd/eigrp_topology.h @@ -36,16 +36,16 @@ extern struct list *eigrp_topology_new(void); extern void eigrp_topology_init(struct list *); extern struct eigrp_prefix_entry *eigrp_prefix_entry_new(void); -extern struct eigrp_neighbor_entry *eigrp_neighbor_entry_new(void); +extern struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void); extern void eigrp_topology_free(struct list *); extern void eigrp_topology_cleanup(struct list *); extern void eigrp_prefix_entry_add(struct list *, struct eigrp_prefix_entry *); -extern void eigrp_neighbor_entry_add(struct eigrp_prefix_entry *, - struct eigrp_neighbor_entry *); +extern void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *, + struct eigrp_nexthop_entry *); extern void eigrp_prefix_entry_delete(struct list *, struct eigrp_prefix_entry *); -extern void eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *, - struct eigrp_neighbor_entry *); +extern void eigrp_nexthop_entry_delete(struct eigrp_prefix_entry *, + struct eigrp_nexthop_entry *); extern void eigrp_topology_delete_all(struct list *); extern unsigned int eigrp_topology_table_isempty(struct list *); extern struct eigrp_prefix_entry * @@ -54,7 +54,7 @@ extern struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *); extern struct list * eigrp_topology_get_successor_max(struct eigrp_prefix_entry *pe, unsigned int maxpaths); -extern struct eigrp_neighbor_entry * +extern struct eigrp_nexthop_entry * eigrp_prefix_entry_lookup(struct list *, struct eigrp_neighbor *); extern struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *, struct eigrp_neighbor *); diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c index d6a1134124..baa1ac5533 100644 --- a/eigrpd/eigrp_update.c +++ b/eigrpd/eigrp_update.c @@ -63,6 +63,32 @@ #include "eigrpd/eigrp_network.h" #include "eigrpd/eigrp_memory.h" +bool eigrp_update_prefix_apply(struct eigrp *eigrp, + struct eigrp_interface *ei, + int in, struct prefix *prefix) +{ + struct access_list *alist; + struct prefix_list *plist; + + alist = eigrp->list[in]; + if (alist && access_list_apply(alist, prefix) == FILTER_DENY) + return true; + + plist = eigrp->prefix[in]; + if (plist && prefix_list_apply(plist, prefix) == PREFIX_DENY) + return true; + + alist = ei->list[in]; + if (alist && access_list_apply(alist, prefix) == FILTER_DENY) + return true; + + plist = ei->prefix[in]; + if (plist && prefix_list_apply(plist, prefix) == PREFIX_DENY) + return true; + + return false; +} + /** * @fn remove_received_prefix_gr * @@ -125,7 +151,7 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp, /* set delay to MAX */ fsm_msg.metrics.delay = EIGRP_MAX_METRIC; - struct eigrp_neighbor_entry *entry = + struct eigrp_nexthop_entry *entry = eigrp_prefix_entry_lookup(prefix->entries, nbr); fsm_msg.packet_type = EIGRP_OPC_UPDATE; @@ -150,15 +176,12 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, struct eigrp_neighbor *nbr; struct TLV_IPv4_Internal_type *tlv; struct eigrp_prefix_entry *pe; - struct eigrp_neighbor_entry *ne; + struct eigrp_nexthop_entry *ne; u_int32_t flags; u_int16_t type; u_int16_t length; u_char same; - struct access_list *alist; - struct prefix_list *plist; struct prefix dest_addr; - struct eigrp *e; u_char graceful_restart; u_char graceful_restart_final; struct list *nbr_prefixes = NULL; @@ -296,7 +319,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, dest); struct eigrp_fsm_action_message msg; - struct eigrp_neighbor_entry *entry = + struct eigrp_nexthop_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); @@ -319,7 +342,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, pe->state = EIGRP_FSM_STATE_PASSIVE; pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE; - ne = eigrp_neighbor_entry_new(); + ne = eigrp_nexthop_entry_new(); ne->ei = ei; ne->adv_router = nbr; ne->reported_metric = tlv->metric; @@ -328,67 +351,10 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, /* * Filtering */ - e = eigrp_lookup(); - /* - * Check if there is any access-list on - * interface (IN direction) - * and set distance to max - */ - alist = ei->list[EIGRP_FILTER_IN]; - - /* Check if access-list fits */ - if (alist - && access_list_apply(alist, - &dest_addr) - == FILTER_DENY) { - /* If yes, set reported metric to Max */ - ne->reported_metric.delay = - EIGRP_MAX_METRIC; - } else { - ne->distance = - eigrp_calculate_total_metrics( - eigrp, ne); - } - - plist = e->prefix[EIGRP_FILTER_IN]; - - /* Check if prefix-list fits */ - if (plist - && prefix_list_apply(plist, - &dest_addr) - == PREFIX_DENY) { - /* If yes, set reported metric to Max */ - ne->reported_metric.delay = - EIGRP_MAX_METRIC; - } - - /*Get access-list from current interface */ - alist = ei->list[EIGRP_FILTER_IN]; - - /* Check if access-list fits */ - if (alist - && access_list_apply(alist, - &dest_addr) - == FILTER_DENY) { - /* If yes, set reported metric to Max */ - ne->reported_metric.delay = - EIGRP_MAX_METRIC; - } - - plist = ei->prefix[EIGRP_FILTER_IN]; - - /* Check if prefix-list fits */ - if (plist - && prefix_list_apply(plist, - &dest_addr) - == PREFIX_DENY) { - /* If yes, set reported metric to Max */ - ne->reported_metric.delay = - EIGRP_MAX_METRIC; - } - /* - * End of filtering - */ + if (eigrp_update_prefix_apply(eigrp, ei, + EIGRP_FILTER_IN, + &dest_addr)) + ne->reported_metric.delay = EIGRP_MAX_METRIC; ne->distance = eigrp_calculate_total_metrics( eigrp, ne); @@ -396,11 +362,11 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, pe->fdistance = pe->distance = pe->rdistance = ne->distance; ne->prefix = pe; - ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; + ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; eigrp_prefix_entry_add(eigrp->topology_table, pe); - eigrp_neighbor_entry_add(pe, ne); + eigrp_nexthop_entry_add(pe, ne); pe->distance = pe->fdistance = pe->rdistance = ne->distance; pe->reported_metric = ne->total_metric; @@ -443,6 +409,9 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, eigrp_query_send_all(eigrp); eigrp_update_send_all(eigrp, ei); + + if (nbr_prefixes) + list_delete(nbr_prefixes); } /*send EIGRP Update packet*/ @@ -559,86 +528,64 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) { struct eigrp_packet *ep; u_int16_t length = EIGRP_HEADER_LEN; - struct eigrp_neighbor_entry *te; + struct eigrp_nexthop_entry *te; struct eigrp_prefix_entry *pe; struct listnode *node, *node2, *nnode, *nnode2; - struct access_list *alist; - struct prefix_list *plist; - struct access_list *alist_i; - struct prefix_list *plist_i; - struct eigrp *e; + struct eigrp_interface *ei = nbr->ei; + struct eigrp *eigrp = ei->eigrp; struct prefix *dest_addr; - u_int32_t seq_no = nbr->ei->eigrp->sequence_number; + u_int32_t seq_no = eigrp->sequence_number; - ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); + ep = eigrp_packet_new(ei->ifp->mtu, nbr); /* Prepare EIGRP EOT UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp, + eigrp_packet_header_init(EIGRP_OPC_UPDATE, eigrp, ep->s, EIGRP_EOT_FLAG, seq_no, nbr->recv_sequence_number); // encode Authentication TLV, if needed - if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && - (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) { - length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); + if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && + (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei); } - for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) { + for (ALL_LIST_ELEMENTS(eigrp->topology_table, node, nnode, pe)) { for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te)) { - if (eigrp_nbr_split_horizon_check(te, nbr->ei)) + if (eigrp_nbr_split_horizon_check(te, ei)) continue; - if ((length + 0x001D) > (u_int16_t)nbr->ei->ifp->mtu) { + if ((length + 0x001D) > (u_int16_t)ei->ifp->mtu) { eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length); seq_no++; length = EIGRP_HEADER_LEN; - ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); - eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp, + ep = eigrp_packet_new(ei->ifp->mtu, nbr); + eigrp_packet_header_init(EIGRP_OPC_UPDATE, eigrp, ep->s, EIGRP_EOT_FLAG, seq_no, nbr->recv_sequence_number); - if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && - (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && + (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) { - length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); + length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei); } } /* Get destination address from prefix */ dest_addr = pe->destination; - /* - * Filtering - */ - //TODO: Work in progress - /* get list from eigrp process */ - e = eigrp_lookup(); - /* Get access-lists and prefix-lists from process and interface */ - alist = e->list[EIGRP_FILTER_OUT]; - plist = e->prefix[EIGRP_FILTER_OUT]; - alist_i = nbr->ei->list[EIGRP_FILTER_OUT]; - plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT]; - /* Check if any list fits */ - if ((alist - && access_list_apply (alist, - dest_addr) == FILTER_DENY)|| - (plist && prefix_list_apply (plist, - dest_addr) == PREFIX_DENY)|| - (alist_i && access_list_apply (alist_i, - dest_addr) == FILTER_DENY)|| - (plist_i && prefix_list_apply (plist_i, - dest_addr) == PREFIX_DENY)) { - //pe->reported_metric.delay = EIGRP_MAX_METRIC; + if (eigrp_update_prefix_apply(eigrp, ei, + EIGRP_FILTER_OUT, + dest_addr)) continue; - } else { + else { length += eigrp_add_internalTLV_to_stream(ep->s, pe); } } } eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length); - nbr->ei->eigrp->sequence_number = seq_no++; + eigrp->sequence_number = seq_no++; } void eigrp_update_send(struct eigrp_interface *ei) @@ -647,13 +594,9 @@ void eigrp_update_send(struct eigrp_interface *ei) struct listnode *node, *nnode; struct eigrp_prefix_entry *pe; u_char has_tlv; - struct access_list *alist; - struct prefix_list *plist; - struct access_list *alist_i; - struct prefix_list *plist_i; - struct eigrp *e; + struct eigrp *eigrp = ei->eigrp; struct prefix *dest_addr; - u_int32_t seq_no = ei->eigrp->sequence_number; + u_int32_t seq_no = eigrp->sequence_number; if (ei->nbrs->count == 0) return; @@ -663,7 +606,7 @@ void eigrp_update_send(struct eigrp_interface *ei) ep = eigrp_packet_new(ei->ifp->mtu, NULL); /* Prepare EIGRP INIT UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei->eigrp, + eigrp_packet_header_init(EIGRP_OPC_UPDATE, eigrp, ep->s, 0, seq_no, 0); // encode Authentication TLV, if needed @@ -675,7 +618,7 @@ void eigrp_update_send(struct eigrp_interface *ei) has_tlv = 0; for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe)) { - struct eigrp_neighbor_entry *ne; + struct eigrp_nexthop_entry *ne; if (!(pe->req_action & EIGRP_FSM_NEED_UPDATE)) continue; @@ -701,7 +644,7 @@ void eigrp_update_send(struct eigrp_interface *ei) length = EIGRP_HEADER_LEN; ep = eigrp_packet_new(ei->ifp->mtu, NULL); - eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei->eigrp, + eigrp_packet_header_init(EIGRP_OPC_UPDATE, eigrp, ep->s, 0, seq_no, 0); if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) { @@ -712,34 +655,9 @@ void eigrp_update_send(struct eigrp_interface *ei) /* Get destination address from prefix */ dest_addr = pe->destination; - /* - * Filtering - */ - e = eigrp_lookup(); - /* Get access-lists and prefix-lists from process and - * interface */ - alist = e->list[EIGRP_FILTER_OUT]; - plist = e->prefix[EIGRP_FILTER_OUT]; - alist_i = ei->list[EIGRP_FILTER_OUT]; - plist_i = ei->prefix[EIGRP_FILTER_OUT]; - - /* Check if any list fits */ - if ((alist - && access_list_apply(alist, - dest_addr) - == FILTER_DENY) - || (plist - && prefix_list_apply(plist, - dest_addr) - == PREFIX_DENY) - || (alist_i - && access_list_apply(alist_i, - dest_addr) - == FILTER_DENY) - || (plist_i - && prefix_list_apply(plist_i, - dest_addr) - == PREFIX_DENY)) { + if (eigrp_update_prefix_apply(eigrp, ei, + EIGRP_FILTER_OUT, + dest_addr)) { // pe->reported_metric.delay = EIGRP_MAX_METRIC; continue; } else { @@ -766,7 +684,7 @@ void eigrp_update_send(struct eigrp_interface *ei) ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS); /*This ack number we await from neighbor*/ - ep->sequence_number = ei->eigrp->sequence_number; + ep->sequence_number = eigrp->sequence_number; if (IS_DEBUG_EIGRP_PACKET(0, RECV)) zlog_debug("Enqueuing Update length[%u] Seq [%u]", length, @@ -821,9 +739,8 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) struct listnode *node, *nnode; struct eigrp_prefix_entry *pe; struct prefix *dest_addr; - struct eigrp *e; - struct access_list *alist, *alist_i; - struct prefix_list *plist, *plist_i; + struct eigrp_interface *ei = nbr->ei; + struct eigrp *eigrp = ei->eigrp; struct list *prefixes; u_int32_t flags; unsigned int send_prefixes; @@ -865,47 +782,28 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) } } - ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); + ep = eigrp_packet_new(ei->ifp->mtu, nbr); /* Prepare EIGRP Graceful restart UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp, ep->s, flags, - nbr->ei->eigrp->sequence_number, + eigrp_packet_header_init(EIGRP_OPC_UPDATE, eigrp, ep->s, flags, + eigrp->sequence_number, nbr->recv_sequence_number); // encode Authentication TLV, if needed - if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) - && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) { - length += eigrp_add_authTLV_MD5_to_stream(ep->s, nbr->ei); + if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) + && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) { + length += eigrp_add_authTLV_MD5_to_stream(ep->s, ei); } - for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, - pe)) { + for (ALL_LIST_ELEMENTS(eigrp->topology_table, node, nnode, pe)) { /* * Filtering */ dest_addr = pe->destination; - /* get list from eigrp process */ - e = eigrp_lookup(); - /* Get access-lists and prefix-lists from process and interface - */ - alist = e->list[EIGRP_FILTER_OUT]; - plist = e->prefix[EIGRP_FILTER_OUT]; - alist_i = nbr->ei->list[EIGRP_FILTER_OUT]; - plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT]; - - /* Check if any list fits */ - if ((alist - && access_list_apply(alist, dest_addr) - == FILTER_DENY) - || (plist - && prefix_list_apply(plist, dest_addr) - == PREFIX_DENY) - || (alist_i - && access_list_apply(alist_i, dest_addr) - == FILTER_DENY) - || (plist_i - && prefix_list_apply(plist_i, dest_addr) - == PREFIX_DENY)) { + + if (eigrp_update_prefix_apply(eigrp, ei, + EIGRP_FILTER_OUT, + dest_addr)) { /* do not send filtered route */ zlog_info("Filtered prefix %s won't be sent out.", inet_ntoa(dest_addr->u.prefix4)); @@ -915,24 +813,13 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) send_prefixes++; } - alist = e->list[EIGRP_FILTER_IN]; - plist = e->prefix[EIGRP_FILTER_IN]; - alist_i = nbr->ei->list[EIGRP_FILTER_IN]; - plist_i = nbr->ei->prefix[EIGRP_FILTER_IN]; - - /* Check if any list fits */ - if ((alist - && access_list_apply(alist, dest_addr) - == FILTER_DENY) - || (plist - && prefix_list_apply(plist, dest_addr) - == PREFIX_DENY) - || (alist_i - && access_list_apply(alist_i, dest_addr) - == FILTER_DENY) - || (plist_i - && prefix_list_apply(plist_i, dest_addr) - == PREFIX_DENY)) { + /* + * This makes no sense, Filter out then filter in??? + * Look into this more - DBS + */ + if (eigrp_update_prefix_apply(eigrp, ei, + EIGRP_FILTER_IN, + dest_addr)) { /* do not send filtered route */ zlog_info("Filtered prefix %s will be removed.", inet_ntoa(dest_addr->u.prefix4)); @@ -940,11 +827,11 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) /* prepare message for FSM */ struct eigrp_fsm_action_message fsm_msg; - struct eigrp_neighbor_entry *entry = + struct eigrp_nexthop_entry *entry = eigrp_prefix_entry_lookup(pe->entries, nbr); fsm_msg.packet_type = EIGRP_OPC_UPDATE; - fsm_msg.eigrp = e; + fsm_msg.eigrp = eigrp; fsm_msg.data_type = EIGRP_INT; fsm_msg.adv_router = nbr; fsm_msg.metrics = pe->reported_metric; @@ -956,9 +843,6 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) /* send message to FSM */ eigrp_fsm_event(&fsm_msg); } - /* - * End of filtering - */ /* NULL the pointer */ dest_addr = NULL; @@ -972,19 +856,19 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) } /* compute Auth digest */ - if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) - && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) { - eigrp_make_md5_digest(nbr->ei, ep->s, EIGRP_AUTH_UPDATE_FLAG); + if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) + && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) { + eigrp_make_md5_digest(ei, ep->s, EIGRP_AUTH_UPDATE_FLAG); } /* EIGRP Checksum */ - eigrp_packet_checksum(nbr->ei, ep->s, length); + eigrp_packet_checksum(ei, ep->s, length); ep->length = length; ep->dst.s_addr = nbr->src.s_addr; /*This ack number we await from neighbor*/ - ep->sequence_number = nbr->ei->eigrp->sequence_number; + ep->sequence_number = eigrp->sequence_number; if (IS_DEBUG_EIGRP_PACKET(0, RECV)) zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]", diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index 4a8842f30e..01407a746f 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -93,7 +93,7 @@ static int config_write_interfaces(struct vty *vty, struct eigrp *eigrp) struct listnode *node; for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { - vty_out(vty, "interface %s\n", ei->ifp->name); + vty_frame(vty, "interface %s\n", ei->ifp->name); if ((IF_DEF_PARAMS(ei->ifp)->auth_type) == EIGRP_AUTH_TYPE_MD5) { @@ -128,7 +128,7 @@ static int config_write_interfaces(struct vty *vty, struct eigrp *eigrp) } /*Separate this EIGRP interface configuration from the others*/ - vty_out(vty, "!\n"); + vty_endframe(vty, "!\n"); } return 0; @@ -140,7 +140,7 @@ static int eigrp_write_interface(struct vty *vty) struct interface *ifp; for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { - vty_out(vty, "interface %s\n", ifp->name); + vty_frame(vty, "interface %s\n", ifp->name); if (ifp->desc) vty_out(vty, " description %s\n", ifp->desc); @@ -157,7 +157,7 @@ static int eigrp_write_interface(struct vty *vty) vty_out(vty, " ip hold-time eigrp %u\n", IF_DEF_PARAMS(ifp)->v_wait); - vty_out(vty, "!\n"); + vty_endframe(vty, "!\n"); } return 0; @@ -400,7 +400,7 @@ DEFUN (eigrp_network, if (ret == 0) { vty_out(vty, "There is already same network statement.\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } return CMD_SUCCESS; @@ -464,7 +464,7 @@ DEFUN (show_ip_eigrp_topology, struct eigrp *eigrp; struct listnode *node, *node2; struct eigrp_prefix_entry *tn; - struct eigrp_neighbor_entry *te; + struct eigrp_nexthop_entry *te; int first; eigrp = eigrp_lookup(); @@ -480,12 +480,12 @@ DEFUN (show_ip_eigrp_topology, for (ALL_LIST_ELEMENTS_RO(tn->entries, node2, te)) { if (argc == 5 || (((te->flags - & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) - == EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) + & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) + == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) || ((te->flags - & EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG) - == EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG))) { - show_ip_eigrp_neighbor_entry(vty, eigrp, te, + & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG) + == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) { + show_ip_eigrp_nexthop_entry(vty, eigrp, te, &first); first = 0; } @@ -1267,7 +1267,11 @@ DEFUN (clear_ip_eigrp_neighbors_IP, struct eigrp_neighbor *nbr; struct in_addr nbr_addr; - inet_aton(argv[4]->arg, &nbr_addr); + if (!inet_aton(argv[4]->arg, &nbr_addr)) { + vty_out(vty, "Unable to parse %s", + argv[4]->arg); + return CMD_WARNING; + } /* Check if eigrp process is enabled */ eigrp = eigrp_lookup(); @@ -1370,7 +1374,11 @@ DEFUN (clear_ip_eigrp_neighbors_IP_soft, struct eigrp_neighbor *nbr; struct in_addr nbr_addr; - inet_aton(argv[4]->arg, &nbr_addr); + if (!inet_aton(argv[4]->arg, &nbr_addr)) { + vty_out(vty, "Unable to parse: %s", + argv[4]->arg); + return CMD_WARNING; + } /* Check if eigrp process is enabled */ eigrp = eigrp_lookup(); diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 47871dfd3e..e61b3d748c 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -365,7 +365,7 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors) { struct zapi_route api; struct zapi_nexthop *api_nh; - struct eigrp_neighbor_entry *te; + struct eigrp_nexthop_entry *te; struct listnode *node; int count = 0; diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index a1aa87e396..192b225cae 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -948,7 +948,7 @@ int isis_interface_config_write(struct vty *vty) continue; /* IF name */ - vty_out(vty, "interface %s\n", ifp->name); + vty_frame(vty, "interface %s\n", ifp->name); write++; /* IF desc */ if (ifp->desc) { @@ -1145,7 +1145,7 @@ int isis_interface_config_write(struct vty *vty) } write += circuit_write_mt_settings(circuit, vty); } - vty_out(vty, "!\n"); + vty_endframe(vty, "!\n"); } return write; @@ -1190,13 +1190,13 @@ void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router, lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); } -int isis_circuit_passive_set(struct isis_circuit *circuit, bool passive) +ferr_r isis_circuit_passive_set(struct isis_circuit *circuit, bool passive) { if (circuit->is_passive == passive) - return 0; + return ferr_ok(); if (if_is_loopback(circuit->interface) && !passive) - return -1; + return ferr_cfg_invalid("loopback is always passive"); if (circuit->state != C_STATE_UP) { circuit->is_passive = passive; @@ -1207,30 +1207,33 @@ int isis_circuit_passive_set(struct isis_circuit *circuit, bool passive) isis_csm_state_change(ISIS_ENABLE, circuit, area); } - return 0; + return ferr_ok(); } -int isis_circuit_metric_set(struct isis_circuit *circuit, int level, int metric) +ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level, + int metric) { assert(level == IS_LEVEL_1 || level == IS_LEVEL_2); if (metric > MAX_WIDE_LINK_METRIC) - return -1; + return ferr_cfg_invalid("metric %d too large for wide metric", + metric); if (circuit->area && circuit->area->oldmetric && metric > MAX_NARROW_LINK_METRIC) - return -1; + return ferr_cfg_invalid("metric %d too large for narrow metric", + metric); circuit->te_metric[level - 1] = metric; circuit->metric[level - 1] = metric; if (circuit->area) lsp_regenerate_schedule(circuit->area, level, 0); - return 0; + return ferr_ok(); } -int isis_circuit_passwd_unset(struct isis_circuit *circuit) +ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit) { memset(&circuit->passwd, 0, sizeof(circuit->passwd)); - return 0; + return ferr_ok(); } static int isis_circuit_passwd_set(struct isis_circuit *circuit, @@ -1239,50 +1242,50 @@ static int isis_circuit_passwd_set(struct isis_circuit *circuit, int len; if (!passwd) - return -1; + return ferr_code_bug("no circuit password given"); len = strlen(passwd); if (len > 254) - return -1; + return ferr_code_bug( + "circuit password too long (max 254 chars)"); circuit->passwd.len = len; strncpy((char *)circuit->passwd.passwd, passwd, 255); circuit->passwd.type = passwd_type; - return 0; + return ferr_ok(); } -int isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit, - const char *passwd) +ferr_r isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit, + const char *passwd) { return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_CLEARTXT, passwd); } -int isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, - const char *passwd) +ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, + const char *passwd) { return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_HMAC_MD5, passwd); } + struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1, }; -int isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) +ferr_r isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) { + if (circuit->circ_type == circ_type) + return ferr_ok(); + /* Changing the network type to/of loopback or unknown interfaces * is not supported. */ if (circ_type == CIRCUIT_T_UNKNOWN || circ_type == CIRCUIT_T_LOOPBACK || circuit->circ_type == CIRCUIT_T_LOOPBACK) { - if (circuit->circ_type != circ_type) - return -1; - else - return 0; + return ferr_cfg_invalid( + "cannot change network type on unknown interface"); } - if (circuit->circ_type == circ_type) - return 0; - if (circuit->state != C_STATE_UP) { circuit->circ_type = circ_type; circuit->circ_type_config = circ_type; @@ -1290,14 +1293,15 @@ int isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) struct isis_area *area = circuit->area; if (circ_type == CIRCUIT_T_BROADCAST && !if_is_broadcast(circuit->interface)) - return -1; + return ferr_cfg_reality( + "cannot configure non-broadcast interface for broadcast operation"); isis_csm_state_change(ISIS_DISABLE, circuit, area); circuit->circ_type = circ_type; circuit->circ_type_config = circ_type; isis_csm_state_change(ISIS_ENABLE, circuit, area); } - return 0; + return ferr_ok(); } int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid, diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index ad53be4683..5906efd2b8 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -27,6 +27,7 @@ #include "if.h" #include "qobj.h" #include "prefix.h" +#include "ferr.h" #include "isis_constants.h" #include "isis_common.h" @@ -178,18 +179,18 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area, struct interface *ifp); void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router, bool ipv6_router); -int isis_circuit_passive_set(struct isis_circuit *circuit, bool passive); +ferr_r isis_circuit_passive_set(struct isis_circuit *circuit, bool passive); void isis_circuit_is_type_set(struct isis_circuit *circuit, int is_type); -int isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type); +ferr_r isis_circuit_circ_type_set (struct isis_circuit *circuit, int circ_type); -int isis_circuit_metric_set(struct isis_circuit *circuit, int level, - int metric); +ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level, + int metric); -int isis_circuit_passwd_unset(struct isis_circuit *circuit); -int isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit, - const char *passwd); -int isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, - const char *passwd); +ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit); +ferr_r isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit, + const char *passwd); +ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, + const char *passwd); int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid, bool enabled); diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index 6fa7988304..17b043444c 100644 --- a/isisd/isis_dynhn.c +++ b/isisd/isis_dynhn.c @@ -146,6 +146,6 @@ void dynhn_print_all(struct vty *vty) } vty_out(vty, " * %s %s\n", sysid_print(isis->sysid), - unix_hostname()); + cmd_hostname_get()); return; } diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 6bf6e45d92..2e1e8e5fc3 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -290,12 +290,21 @@ int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno, return LSP_OLDER; } -static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer) +static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer, bool keep) { uint8_t pdu_type = (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE; struct isis_lsp_hdr *hdr = &lsp->hdr; struct stream *stream = lsp->pdu; + size_t orig_getp, orig_endp; + + if (keep) { + orig_getp = stream_get_getp(lsp->pdu); + orig_endp = stream_get_endp(lsp->pdu); + } + + stream_set_getp(lsp->pdu, 0); + stream_set_endp(lsp->pdu, 0); fill_fixed_hdr(pdu_type, stream); @@ -307,6 +316,11 @@ static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer) stream_putl(stream, hdr->seqno); stream_putw(stream, hdr->checksum); stream_putc(stream, hdr->lsp_bits); + + if (keep) { + stream_set_endp(lsp->pdu, orig_endp); + stream_set_getp(lsp->pdu, orig_getp); + } } static void lsp_add_auth(struct isis_lsp *lsp) @@ -325,8 +339,7 @@ static void lsp_pack_pdu(struct isis_lsp *lsp) lsp_add_auth(lsp); size_t len_pointer; - stream_reset(lsp->pdu); - put_lsp_hdr(lsp, &len_pointer); + put_lsp_hdr(lsp, &len_pointer, false); isis_pack_tlvs(lsp->tlvs, lsp->pdu, len_pointer, false, true); lsp->hdr.pdu_len = stream_get_endp(lsp->pdu); @@ -457,16 +470,10 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, lsp->own_lsp = 0; } + lsp_update_data(lsp, hdr, tlvs, stream, area, level); if (confusion) { - lsp_clear_data(lsp); - if (lsp->pdu != NULL) - stream_free(lsp->pdu); - lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu); - lsp->age_out = ZERO_AGE_LIFETIME; - lsp->hdr.rem_lifetime = 0; - lsp_pack_pdu(lsp); - } else { - lsp_update_data(lsp, hdr, tlvs, stream, area, level); + lsp->hdr.rem_lifetime = hdr->rem_lifetime = 0; + put_lsp_hdr(lsp, NULL, true); } /* insert the lsp back into the database */ @@ -523,7 +530,7 @@ struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id, lsp->level = level; lsp->age_out = ZERO_AGE_LIFETIME; lsp_link_fragment(lsp, lsp0); - put_lsp_hdr(lsp, NULL); + put_lsp_hdr(lsp, NULL, false); if (isis->debugs & DEBUG_EVENTS) zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x", @@ -600,7 +607,7 @@ static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag) if (dyn) sprintf((char *)id, "%.14s", dyn->hostname); else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost) - sprintf((char *)id, "%.14s", unix_hostname()); + sprintf((char *)id, "%.14s", cmd_hostname_get()); else memcpy(id, sysid_print(lsp_id), 15); if (frag) @@ -880,9 +887,9 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } /* Dynamic Hostname */ if (area->dynhostname) { - isis_tlvs_set_dynamic_hostname(lsp->tlvs, unix_hostname()); + isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get()); lsp_debug("ISIS (%s): Adding dynamic hostname '%s'", - area->area_tag, unix_hostname()); + area->area_tag, cmd_hostname_get()); } else { lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag); diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index e8888a5f5b..0a1d9aaa1a 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -432,24 +432,6 @@ struct in_addr newprefix2inaddr(u_char *prefix_start, u_char prefix_masklen) } /* - * Returns host.name if any, otherwise - * it returns the system hostname. - */ -const char *unix_hostname(void) -{ - static struct utsname names; - const char *hostname; - - hostname = host.name; - if (!hostname) { - uname(&names); - hostname = names.nodename; - } - - return hostname; -} - -/* * Returns the dynamic hostname associated with the passed system ID. * If no dynamic hostname found then returns formatted system ID. */ @@ -462,7 +444,7 @@ const char *print_sys_hostname(const u_char *sysid) /* For our system ID return our host name */ if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0) - return unix_hostname(); + return cmd_hostname_get(); dyn = dynhn_find_by_id(sysid); if (dyn) diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h index 5a19a1ffa0..b81db34df6 100644 --- a/isisd/isis_misc.h +++ b/isisd/isis_misc.h @@ -56,7 +56,6 @@ void zlog_dump_data(void *data, int len); * misc functions */ unsigned long isis_jitter(unsigned long timer, unsigned long jitter); -const char *unix_hostname(void); /* * macros diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index ea94b65805..198cf35e68 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -64,17 +64,6 @@ static afi_t afi_for_redist_protocol(int protocol) return AFI_IP; } -static int is_default(struct prefix *p) -{ - if (p->family == AF_INET) - if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0) - return 1; - if (p->family == AF_INET6) - if (IN6_IS_ADDR_UNSPECIFIED(&p->u.prefix6) && p->prefixlen == 0) - return 1; - return 0; -} - static struct route_table *get_ext_info(struct isis *i, int family) { int protocol = redist_protocol(family); @@ -286,7 +275,7 @@ void isis_redist_add(int type, struct prefix *p, u_char distance, info->distance = distance; info->metric = metric; - if (is_default(p)) + if (is_default_prefix(p)) type = DEFAULT_ROUTE; for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) @@ -316,7 +305,7 @@ void isis_redist_delete(int type, struct prefix *p) zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf, zebra_route_string(type)); - if (is_default(p)) { + if (is_default_prefix(p)) { /* Don't remove default route but add synthetic route for use * by "default-information originate always". Areas without the * "always" setting will ignore routes with origin @@ -454,7 +443,7 @@ static void isis_redist_set(struct isis_area *area, int level, int family, info = rn->info; if (type == DEFAULT_ROUTE) { - if (!is_default(&rn->p)) + if (!is_default_prefix(&rn->p)) continue; } else { if (info->origin != type) @@ -490,7 +479,7 @@ static void isis_redist_unset(struct isis_area *area, int level, int family, info = rn->info; if (type == DEFAULT_ROUTE) { - if (!is_default(&rn->p)) + if (!is_default_prefix(&rn->p)) continue; } else { if (info->origin != type) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 9acbc21838..04e0276324 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1294,10 +1294,10 @@ static int isis_run_spf(struct isis_area *area, int level, int family, /* * C.2.7 Step 2 */ - if (isis_vertex_queue_count(&spftree->tents) == 0) { + if (!isis_vertex_queue_count(&spftree->tents) + && (isis->debugs & DEBUG_SPF_EVENTS)) { zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid)); - goto out; } while (isis_vertex_queue_count(&spftree->tents)) { @@ -1440,9 +1440,7 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, u_char *root_sysid) { struct listnode *node; - struct listnode *anode; struct isis_vertex *vertex; - struct isis_adjacency *adj; char buff[PREFIX2STR_BUFFER]; vty_out(vty, @@ -1452,50 +1450,59 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { vty_out(vty, "%-20s %-12s %-6s", print_sys_hostname(root_sysid), "", ""); - vty_out(vty, "%-30s", ""); - } else { - int rows = 0; - vty_out(vty, "%-20s %-12s %-6u ", - vid2string(vertex, buff, sizeof(buff)), - vtype2string(vertex->type), vertex->d_N); - for (ALL_LIST_ELEMENTS_RO(vertex->Adj_N, anode, adj)) { - if (adj) { - if (rows) { - vty_out(vty, "\n"); - vty_out(vty, - "%-20s %-12s %-6s ", "", - "", ""); - } - vty_out(vty, "%-20s %-9s ", - print_sys_hostname(adj->sysid), - adj->circuit->interface->name); - ++rows; - } - } - if (rows == 0) - vty_out(vty, "%-30s ", ""); + vty_out(vty, "%-30s\n", ""); + continue; } - /* Print list of parents for the ECMP DAG */ - if (listcount(vertex->parents) > 0) { - struct listnode *pnode; - struct isis_vertex *pvertex; - int rows = 0; - for (ALL_LIST_ELEMENTS_RO(vertex->parents, pnode, - pvertex)) { - if (rows) { - vty_out(vty, "\n"); - vty_out(vty, "%-72s", ""); - } + int rows = 0; + struct listnode *anode = listhead(vertex->Adj_N); + struct listnode *pnode = listhead(vertex->parents); + struct isis_adjacency *adj; + struct isis_vertex *pvertex; + + vty_out(vty, "%-20s %-12s %-6u ", + vid2string(vertex, buff, sizeof(buff)), + vtype2string(vertex->type), vertex->d_N); + for (unsigned int i = 0; + i < MAX(listcount(vertex->Adj_N), + listcount(vertex->parents)); i++) { + if (anode) { + adj = listgetdata(anode); + anode = anode->next; + } else { + adj = NULL; + } + + if (pnode) { + pvertex = listgetdata(pnode); + pnode = pnode->next; + } else { + pvertex = NULL; + } + + if (rows) { + vty_out(vty, "\n"); + vty_out(vty, "%-20s %-12s %-6s ", "", "", ""); + } + + if (adj) { + vty_out(vty, "%-20s %-9s ", + print_sys_hostname(adj->sysid), + adj->circuit->interface->name); + } + + if (pvertex) { + if (!adj) + vty_out(vty, "%-20s %-9s ", "", ""); + vty_out(vty, "%s(%d)", - vid2string(pvertex, buff, sizeof(buff)), + vid2string(pvertex, buff, + sizeof(buff)), pvertex->type); - ++rows; } - } else { - vty_out(vty, " NULL "); - } + ++rows; + } vty_out(vty, "\n"); } } diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index 17d8ad3c0b..02e28a73fe 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -164,7 +164,8 @@ DEFUN (isis_passive, if (!circuit) return CMD_ERR_NO_MATCH; - isis_circuit_passive_set(circuit, 1); + CMD_FERR_RETURN(isis_circuit_passive_set(circuit, 1), + "Cannot set passive: $ERR"); return CMD_SUCCESS; } @@ -179,12 +180,8 @@ DEFUN (no_isis_passive, if (!circuit) return CMD_ERR_NO_MATCH; - if (if_is_loopback(circuit->interface)) { - vty_out(vty, "Can't set no passive for loopback interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - isis_circuit_passive_set(circuit, 0); + CMD_FERR_RETURN(isis_circuit_passive_set(circuit, 0), + "Cannot set no passive: $ERR"); return CMD_SUCCESS; } @@ -301,7 +298,8 @@ DEFUN (isis_passwd, int idx_encryption = 2; int idx_word = 3; struct isis_circuit *circuit = isis_circuit_lookup(vty); - int rv; + ferr_r rv; + if (!circuit) return CMD_ERR_NO_MATCH; @@ -311,11 +309,8 @@ DEFUN (isis_passwd, else rv = isis_circuit_passwd_cleartext_set(circuit, argv[idx_word]->arg); - if (rv) { - vty_out(vty, "Too long circuit password (>254)\n"); - return CMD_WARNING_CONFIG_FAILED; - } + CMD_FERR_RETURN(rv, "Failed to set circuit password: $ERR"); return CMD_SUCCESS; } @@ -333,8 +328,8 @@ DEFUN (no_isis_passwd, if (!circuit) return CMD_ERR_NO_MATCH; - isis_circuit_passwd_unset(circuit); - + CMD_FERR_RETURN(isis_circuit_passwd_unset(circuit), + "Failed to unset circuit password: $ERR"); return CMD_SUCCESS; } @@ -507,8 +502,10 @@ DEFUN (isis_metric, return CMD_WARNING_CONFIG_FAILED; } - isis_circuit_metric_set(circuit, IS_LEVEL_1, met); - isis_circuit_metric_set(circuit, IS_LEVEL_2, met); + CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_1, met), + "Failed to set L1 metric: $ERR"); + CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_2, met), + "Failed to set L2 metric: $ERR"); return CMD_SUCCESS; } @@ -525,8 +522,12 @@ DEFUN (no_isis_metric, if (!circuit) return CMD_ERR_NO_MATCH; - isis_circuit_metric_set(circuit, IS_LEVEL_1, DEFAULT_CIRCUIT_METRIC); - isis_circuit_metric_set(circuit, IS_LEVEL_2, DEFAULT_CIRCUIT_METRIC); + CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_1, + DEFAULT_CIRCUIT_METRIC), + "Failed to set L1 metric: $ERR"); + CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_2, + DEFAULT_CIRCUIT_METRIC), + "Failed to set L2 metric: $ERR"); return CMD_SUCCESS; } @@ -546,28 +547,8 @@ DEFUN (isis_metric_l1, return CMD_ERR_NO_MATCH; met = atoi(argv[idx_number]->arg); - - /* RFC3787 section 5.1 */ - if (circuit->area && circuit->area->oldmetric == 1 - && met > MAX_NARROW_LINK_METRIC) { - vty_out(vty, - "Invalid metric %d - should be <0-63> " - "when narrow metric type enabled\n", - met); - return CMD_WARNING_CONFIG_FAILED; - } - - /* RFC4444 */ - if (circuit->area && circuit->area->newmetric == 1 - && met > MAX_WIDE_LINK_METRIC) { - vty_out(vty, - "Invalid metric %d - should be <0-16777215> " - "when wide metric type enabled\n", - met); - return CMD_WARNING_CONFIG_FAILED; - } - - isis_circuit_metric_set(circuit, IS_LEVEL_1, met); + CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_1, met), + "Failed to set L1 metric: $ERR"); return CMD_SUCCESS; } @@ -585,7 +566,9 @@ DEFUN (no_isis_metric_l1, if (!circuit) return CMD_ERR_NO_MATCH; - isis_circuit_metric_set(circuit, IS_LEVEL_1, DEFAULT_CIRCUIT_METRIC); + CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_1, + DEFAULT_CIRCUIT_METRIC), + "Failed to set L1 metric: $ERR"); return CMD_SUCCESS; } @@ -605,28 +588,8 @@ DEFUN (isis_metric_l2, return CMD_ERR_NO_MATCH; met = atoi(argv[idx_number]->arg); - - /* RFC3787 section 5.1 */ - if (circuit->area && circuit->area->oldmetric == 1 - && met > MAX_NARROW_LINK_METRIC) { - vty_out(vty, - "Invalid metric %d - should be <0-63> " - "when narrow metric type enabled\n", - met); - return CMD_WARNING_CONFIG_FAILED; - } - - /* RFC4444 */ - if (circuit->area && circuit->area->newmetric == 1 - && met > MAX_WIDE_LINK_METRIC) { - vty_out(vty, - "Invalid metric %d - should be <0-16777215> " - "when wide metric type enabled\n", - met); - return CMD_WARNING_CONFIG_FAILED; - } - - isis_circuit_metric_set(circuit, IS_LEVEL_2, met); + CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_2, met), + "Failed to set L2 metric: $ERR"); return CMD_SUCCESS; } @@ -644,7 +607,9 @@ DEFUN (no_isis_metric_l2, if (!circuit) return CMD_ERR_NO_MATCH; - isis_circuit_metric_set(circuit, IS_LEVEL_2, DEFAULT_CIRCUIT_METRIC); + CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_2, + DEFAULT_CIRCUIT_METRIC), + "Failed to set L2 metric: $ERR"); return CMD_SUCCESS; } diff --git a/isisd/isisd.c b/isisd/isisd.c index 3d39a1ed52..bdc1d836db 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1441,7 +1441,7 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level) lsp = lsp_search( lspid, area->lspdb[level]); - } else if (strncmp(unix_hostname(), + } else if (strncmp(cmd_hostname_get(), sysid, 15) == 0) { memcpy(lspid, isis->sysid, diff --git a/lib/command.c b/lib/command.c index c86025a3bd..a303781370 100644 --- a/lib/command.c +++ b/lib/command.c @@ -125,6 +125,23 @@ vector cmdvec = NULL; /* Host information structure. */ struct host host; +/* + * Returns host.name if any, otherwise + * it returns the system hostname. + */ +const char *cmd_hostname_get(void) +{ + return host.name; +} + +/* + * Returns unix domainname + */ +const char *cmd_domainname_get(void) +{ + return host.domainname; +} + /* Standard command node structures. */ static struct cmd_node auth_node = { AUTH_NODE, "Password: ", @@ -475,8 +492,8 @@ static char *zencrypt(const char *passwd) /* This function write configuration of this host. */ static int config_write_host(struct vty *vty) { - if (host.name) - vty_out(vty, "hostname %s\n", host.name); + if (cmd_hostname_get()) + vty_out(vty, "hostname %s\n", cmd_hostname_get()); if (host.encrypt) { if (host.password_encrypt) @@ -1411,7 +1428,7 @@ DEFUN (show_version, "Displays zebra version\n") { vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION, - host.name ? host.name : ""); + cmd_hostname_get() ? cmd_hostname_get() : ""); vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO); vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS); @@ -1745,6 +1762,40 @@ DEFUN (show_startup_config, return CMD_SUCCESS; } +int cmd_domainname_set(const char *domainname) +{ + XFREE(MTYPE_HOST, host.domainname); + host.domainname = domainname ? XSTRDUP(MTYPE_HOST, domainname) : NULL; + return CMD_SUCCESS; +} + +/* Hostname configuration */ +DEFUN(config_domainname, + domainname_cmd, + "domainname WORD", + "Set system's domain name\n" + "This system's domain name\n") +{ + struct cmd_token *word = argv[1]; + + if (!isalpha((int)word->arg[0])) { + vty_out(vty, "Please specify string starting with alphabet\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return cmd_domainname_set(word->arg); +} + +DEFUN(config_no_domainname, + no_domainname_cmd, + "no domainname [DOMAINNAME]", + NO_STR + "Reset system's domain name\n" + "domain name of this router\n") +{ + return cmd_domainname_set(NULL); +} + int cmd_hostname_set(const char *hostname) { XFREE(MTYPE_HOST, host.name); @@ -2515,9 +2566,12 @@ void install_default(enum node_type node) * terminal = -1 -- watchfrr / no logging, but minimal config control */ void cmd_init(int terminal) { + struct utsname names; + if (array_size(node_names) != NODE_TYPE_MAX) assert(!"Update the CLI node description array!"); + uname(&names); qobj_init(); varhandlers = list_new(); @@ -2526,7 +2580,15 @@ void cmd_init(int terminal) cmdvec = vector_init(VECTOR_MIN_SIZE); /* Default host value settings. */ - host.name = NULL; + host.name = XSTRDUP(MTYPE_HOST, names.nodename); +#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME + if ((strcmp(names.domainname, "(none)") == 0)) + host.domainname = NULL; + else + host.domainname = XSTRDUP(MTYPE_HOST, names.domainname); +#else + host.domainname = NULL; +#endif host.password = NULL; host.enable = NULL; host.logfile = NULL; @@ -2579,6 +2641,8 @@ void cmd_init(int terminal) install_element(CONFIG_NODE, &hostname_cmd); install_element(CONFIG_NODE, &no_hostname_cmd); + install_element(CONFIG_NODE, &domainname_cmd); + install_element(CONFIG_NODE, &no_domainname_cmd); install_element(CONFIG_NODE, &frr_version_defaults_cmd); install_element(CONFIG_NODE, &debug_memstats_cmd); @@ -2644,6 +2708,8 @@ void cmd_terminate() if (host.name) XFREE(MTYPE_HOST, host.name); + if (host.domainname) + XFREE(MTYPE_HOST, host.domainname); if (host.password) XFREE(MTYPE_HOST, host.password); if (host.password_encrypt) diff --git a/lib/command.h b/lib/command.h index 8f12e2aabd..1c6938523c 100644 --- a/lib/command.h +++ b/lib/command.h @@ -41,6 +41,9 @@ struct host { /* Host name of this router. */ char *name; + /* Domainname of this router */ + char *domainname; + /* Password for vty interface. */ char *password; char *password_encrypt; @@ -398,7 +401,10 @@ extern void cmd_terminate(void); extern void cmd_exit(struct vty *vty); extern int cmd_list_cmds(struct vty *vty, int do_permute); +extern int cmd_domainname_set(const char *domainname); extern int cmd_hostname_set(const char *hostname); +extern const char *cmd_hostname_get(void); +extern const char *cmd_domainname_get(void); /* NOT safe for general use; call this only if DEV_BUILD! */ extern void grammar_sandbox_init(void); diff --git a/lib/ferr.c b/lib/ferr.c new file mode 100644 index 0000000000..2a039d2089 --- /dev/null +++ b/lib/ferr.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <pthread.h> +#include <signal.h> + +#include "ferr.h" +#include "vty.h" +#include "jhash.h" +#include "memory.h" + +DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information") + +static pthread_key_t errkey; + +static void ferr_free(void *arg) +{ + XFREE(MTYPE_ERRINFO, arg); +} + +static void err_key_init(void) __attribute__((_CONSTRUCTOR(500))); +static void err_key_init(void) +{ + pthread_key_create(&errkey, ferr_free); +} + +static void err_key_fini(void) __attribute__((_DESTRUCTOR(500))); +static void err_key_fini(void) +{ + pthread_key_delete(errkey); +} + +const struct ferr *ferr_get_last(ferr_r errval) +{ + struct ferr *last_error = pthread_getspecific(errkey); + if (!last_error || last_error->kind == 0) + return NULL; + return last_error; +} + +ferr_r ferr_clear(void) +{ + struct ferr *last_error = pthread_getspecific(errkey); + if (last_error) + last_error->kind = 0; + return ferr_ok(); +} + +static ferr_r ferr_set_va(const char *file, int line, const char *func, + enum ferr_kind kind, const char *pathname, int errno_val, + const char *text, va_list va) +{ + struct ferr *error = pthread_getspecific(errkey); + + if (!error) { + error = XCALLOC(MTYPE_ERRINFO, sizeof(*error)); + if (!error) { + /* we're screwed */ + zlog_err("out of memory while allocating error info"); + raise(SIGSEGV); + } + + pthread_setspecific(errkey, error); + } + + error->file = file; + error->line = line; + error->func = func; + error->kind = kind; + + error->unique_id = jhash(text, strlen(text), + jhash(file, strlen(file), 0xd4ed0298)); + + error->errno_val = errno_val; + if (pathname) + snprintf(error->pathname, sizeof(error->pathname), + "%s", pathname); + else + error->pathname[0] = '\0'; + + vsnprintf(error->message, sizeof(error->message), text, va); + return -1; +} + +ferr_r ferr_set_internal(const char *file, int line, const char *func, + enum ferr_kind kind, const char *text, ...) +{ + ferr_r rv; + va_list va; + va_start(va, text); + rv = ferr_set_va(file, line, func, kind, NULL, 0, text, va); + va_end(va); + return rv; +} + +ferr_r ferr_set_internal_ext(const char *file, int line, const char *func, + enum ferr_kind kind, const char *pathname, int errno_val, + const char *text, ...) +{ + ferr_r rv; + va_list va; + va_start(va, text); + rv = ferr_set_va(file, line, func, kind, pathname, errno_val, text, va); + va_end(va); + return rv; +} + +#define REPLACE "$ERR" +void vty_print_error(struct vty *vty, ferr_r err, const char *msg, ...) +{ + char tmpmsg[512], *replacepos; + const struct ferr *last_error = ferr_get_last(err); + + va_list va; + va_start(va, msg); + vsnprintf(tmpmsg, sizeof(tmpmsg), msg, va); + va_end(va); + + replacepos = strstr(tmpmsg, REPLACE); + if (!replacepos) + vty_out(vty, "%s\n", tmpmsg); + else { + replacepos[0] = '\0'; + replacepos += sizeof(REPLACE) - 1; + vty_out(vty, "%s%s%s\n", + tmpmsg, + last_error ? last_error->message : "(no error?)", + replacepos); + } +} + diff --git a/lib/ferr.h b/lib/ferr.h new file mode 100644 index 0000000000..a570637372 --- /dev/null +++ b/lib/ferr.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _FRR_FERR_H +#define _FRR_FERR_H + +/*********************************************************** + * scroll down to the end of this file for a full example! * + ***********************************************************/ + +#include <stdint.h> +#include <limits.h> +#include <errno.h> + +/* return type when this error indication stuff is used. + * + * guaranteed to have boolean evaluation to "false" when OK, "true" when error + * (i.e. can be changed to pointer in the future if neccessary) + * + * For checking, always use "if (value)", nothing else. + * Do _NOT_ use any integer constant (!= 0), or sign check (< 0). + */ +typedef int ferr_r; + +/* rough category of error indication */ +enum ferr_kind { + /* no error */ + FERR_OK = 0, + + /* something isn't the way it's supposed to be. + * (things that might otherwise be asserts, really) + */ + FERR_CODE_BUG, + + /* user-supplied parameters don't make sense or is inconsistent + * if you can express a rule for it (e.g. "holdtime > 2 * keepalive"), + * it's this category. + */ + FERR_CONFIG_INVALID, + + /* user-supplied parameters don't line up with reality + * (IP address or interface not available, etc.) + * NB: these are really TODOs where the code needs to be fixed to + * respond to future changes! + */ + FERR_CONFIG_REALITY, + + /* out of some system resource (probably memory) + * aka "you didn't spend enough money error" */ + FERR_RESOURCE, + + /* system error (permission denied, etc.) */ + FERR_SYSTEM, + + /* error return from some external library + * (FERR_SYSTEM and FERR_LIBRARY are not strongly distinct) */ + FERR_LIBRARY, +}; + +struct ferr { + /* code location */ + const char *file; + const char *func; + int line; + + enum ferr_kind kind; + + /* unique_id is calculated as a checksum of source filename and error + * message format (*before* calling vsnprintf). Line number and + * function name are not used; this keeps the number reasonably static + * across changes. + */ + uint32_t unique_id; + + char message[384]; + + /* valid if != 0. note "errno" might be preprocessor foobar. */ + int errno_val; + /* valid if pathname[0] != '\0' */ + char pathname[PATH_MAX]; +}; + +/* get error details. + * + * NB: errval/ferr_r does NOT carry the full error information. It's only + * passed around for future API flexibility. ferr_get_last always returns + * the last error set in the current thread. + */ +const struct ferr *ferr_get_last(ferr_r errval); + +/* can optionally be called at strategic locations. + * always returns 0. */ +ferr_r ferr_clear(void); + +/* do NOT call these functions directly. only for macro use! */ +ferr_r ferr_set_internal(const char *file, int line, const char *func, + enum ferr_kind kind, const char *text, ...); +ferr_r ferr_set_internal_ext(const char *file, int line, const char *func, + enum ferr_kind kind, const char *pathname, int errno_val, + const char *text, ...); + +#define ferr_ok() \ + 0 + +/* Report an error. + * + * If you need to do cleanup (free memory, etc.), save the return value in a + * variable of type ferr_r. + * + * Don't put a \n at the end of the error message. + */ +#define ferr_code_bug(...) \ + ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CODE_BUG, \ + __VA_ARGS__) +#define ferr_cfg_invalid(...) \ + ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CONFIG_INVALID, \ + __VA_ARGS__) +#define ferr_cfg_reality(...) \ + ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CONFIG_REALITY, \ + __VA_ARGS__) +#define ferr_cfg_resource(...) \ + ferr_set_internal(__FILE__, __LINE__, __func__, FERR_RESOURCE, \ + __VA_ARGS__) +#define ferr_system(...) \ + ferr_set_internal(__FILE__, __LINE__, __func__, FERR_SYSTEM, \ + __VA_ARGS__) +#define ferr_library(...) \ + ferr_set_internal(__FILE__, __LINE__, __func__, FERR_LIBRARY, \ + __VA_ARGS__) + +/* extended information variants */ +#define ferr_system_errno(...) \ + ferr_set_internal_ext(__FILE__, __LINE__, __func__, FERR_SYSTEM, \ + NULL, errno, __VA_ARGS__) +#define ferr_system_path_errno(path, ...) \ + ferr_set_internal_ext(__FILE__, __LINE__, __func__, FERR_SYSTEM, \ + path, errno, __VA_ARGS__) + +#include "vty.h" +/* print error message to vty; $ERR is replaced by the error's message */ +void vty_print_error(struct vty *vty, ferr_r err, const char *msg, ...); + +#define CMD_FERR_DO(func, action, ...) \ + do { ferr_r cmd_retval = func; \ + if (cmd_retval) { \ + vty_print_error(vty, cmd_retval, __VA_ARGS__); \ + action; \ + } \ + } while (0) + +#define CMD_FERR_RETURN(func, ...) \ + CMD_FERR_DO(func, return CMD_WARNING, __VA_ARGS__) +#define CMD_FERR_GOTO(func, label, ...) \ + CMD_FERR_DO(func, goto label, __VA_ARGS__) + +/* example: + +ferr_r foo_bar_set(struct object *obj, int bar) +{ + if (bar < 1 || bar >= 100) + return ferr_config_invalid("bar setting (%d) must be 0<x<100", bar); + obj->bar = bar; + if (ioctl (obj->fd, bar)) + return ferr_system_errno("couldn't set bar to %d", bar); + + return ferr_ok(); +} + +DEFUN("bla") +{ + CMD_FERR_RETURN(foo_bar_set(obj, atoi(argv[1])), + "command failed: $ERR\n"); + return CMD_SUCCESS; +} + +*/ + +#endif /* _FERR_H */ diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c new file mode 100644 index 0000000000..861f7a5f0c --- /dev/null +++ b/lib/frr_zmq.c @@ -0,0 +1,191 @@ +/* + * libzebra ZeroMQ bindings + * Copyright (C) 2015 David Lamparter + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <zebra.h> +#include <zmq.h> + +#include "thread.h" +#include "memory.h" +#include "frr_zmq.h" +#include "log.h" + +DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback") + +/* libzmq's context */ +void *frrzmq_context = NULL; +static unsigned frrzmq_initcount = 0; + +void frrzmq_init(void) +{ + if (frrzmq_initcount++ == 0) { + frrzmq_context = zmq_ctx_new(); + zmq_ctx_set(frrzmq_context, ZMQ_IPV6, 1); + } +} + +void frrzmq_finish(void) +{ + if (--frrzmq_initcount == 0) { + zmq_ctx_term(frrzmq_context); + frrzmq_context = NULL; + } +} + +/* read callback integration */ +struct frrzmq_cb { + struct thread *thread; + void *zmqsock; + void *arg; + int fd; + + bool cancelled; + + void (*cb_msg)(void *arg, void *zmqsock); + void (*cb_part)(void *arg, void *zmqsock, + zmq_msg_t *msg, unsigned partnum); +}; + + +static int frrzmq_read_msg(struct thread *t) +{ + struct frrzmq_cb *cb = THREAD_ARG(t); + zmq_msg_t msg; + unsigned partno; + int ret, more; + size_t moresz; + + while (1) { + zmq_pollitem_t polli = { + .socket = cb->zmqsock, + .events = ZMQ_POLLIN + }; + ret = zmq_poll(&polli, 1, 0); + + if (ret < 0) + goto out_err; + if (!(polli.revents & ZMQ_POLLIN)) + break; + + if (cb->cb_msg) { + cb->cb_msg(cb->arg, cb->zmqsock); + + if (cb->cancelled) { + XFREE(MTYPE_ZEROMQ_CB, cb); + return 0; + } + continue; + } + + partno = 0; + if (zmq_msg_init(&msg)) + goto out_err; + do { + ret = zmq_msg_recv(&msg, cb->zmqsock, ZMQ_NOBLOCK); + if (ret < 0) { + if (errno == EAGAIN) + break; + + zmq_msg_close(&msg); + goto out_err; + } + + cb->cb_part(cb->arg, cb->zmqsock, &msg, partno); + if (cb->cancelled) { + zmq_msg_close(&msg); + XFREE(MTYPE_ZEROMQ_CB, cb); + return 0; + } + + /* cb_part may have read additional parts of the + * message; don't use zmq_msg_more here */ + moresz = sizeof(more); + more = 0; + ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE, + &more, &moresz); + if (ret < 0) { + zmq_msg_close(&msg); + goto out_err; + } + + partno++; + } while (more); + zmq_msg_close(&msg); + } + + funcname_thread_add_read_write(THREAD_READ, t->master, frrzmq_read_msg, + cb, cb->fd, &cb->thread, t->funcname, t->schedfrom, + t->schedfrom_line); + return 0; + +out_err: + zlog_err("ZeroMQ error: %s(%d)", strerror (errno), errno); + return 0; +} + +struct frrzmq_cb *funcname_frrzmq_thread_add_read( + struct thread_master *master, + void (*msgfunc)(void *arg, void *zmqsock), + void (*partfunc)(void *arg, void *zmqsock, + zmq_msg_t *msg, unsigned partnum), + void *arg, void *zmqsock, debugargdef) +{ + int fd, events; + size_t len; + struct frrzmq_cb *cb; + + if (!(msgfunc || partfunc) || (msgfunc && partfunc)) + return NULL; + len = sizeof(fd); + if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len)) + return NULL; + len = sizeof(events); + if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len)) + return NULL; + + cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb)); + if (!cb) + return NULL; + + cb->arg = arg; + cb->zmqsock = zmqsock; + cb->cb_msg = msgfunc; + cb->cb_part = partfunc; + cb->fd = fd; + + if (events & ZMQ_POLLIN) + funcname_thread_add_event(master, + frrzmq_read_msg, cb, fd, &cb->thread, + funcname, schedfrom, fromln); + else + funcname_thread_add_read_write(THREAD_READ, master, + frrzmq_read_msg, cb, fd, &cb->thread, + funcname, schedfrom, fromln); + return cb; +} + +void frrzmq_thread_cancel(struct frrzmq_cb *cb) +{ + if (!cb->thread) { + /* canceling from within callback */ + cb->cancelled = 1; + return; + } + thread_cancel(cb->thread); + XFREE(MTYPE_ZEROMQ_CB, cb); +} diff --git a/lib/frr_zmq.h b/lib/frr_zmq.h new file mode 100644 index 0000000000..69c6f8580d --- /dev/null +++ b/lib/frr_zmq.h @@ -0,0 +1,88 @@ +/* + * libzebra ZeroMQ bindings + * Copyright (C) 2015 David Lamparter + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _FRRZMQ_H +#define _FRRZMQ_H + +#include "thread.h" +#include <zmq.h> + +/* linking/packaging note: this is a separate library that needs to be + * linked into any daemon/library/module that wishes to use its + * functionality. The purpose of this is to encapsulate the libzmq + * dependency and not make libfrr/FRR itself depend on libzmq. + * + * libfrrzmq should be put in LDFLAGS/LIBADD *before* either libfrr or + * libzmq, and both of these should always be listed, e.g. + * foo_LDFLAGS = libfrrzmq.la libfrr.la $(ZEROMQ_LIBS) + */ + +/* libzmq's context + * + * this is mostly here as a convenience, it has IPv6 enabled but nothing + * else is tied to it; you can use a separate context without problems + */ +extern void *frrzmq_context; + +extern void frrzmq_init (void); +extern void frrzmq_finish (void); + +#define debugargdef const char *funcname, const char *schedfrom, int fromln + +/* core event registration, one of these 2 macros should be used */ +#define frrzmq_thread_add_read_msg(m,f,a,z) funcname_frrzmq_thread_add_read( \ + m,f,NULL,a,z,#f,__FILE__,__LINE__) +#define frrzmq_thread_add_read_part(m,f,a,z) funcname_frrzmq_thread_add_read( \ + m,NULL,f,a,z,#f,__FILE__,__LINE__) + +struct frrzmq_cb; + +/* Set up a POLLIN notification to be called from the libfrr main loop. + * This has the following properties: + * + * - since ZeroMQ works with edge triggered notifications, it will loop and + * dispatch as many events as ZeroMQ has pending at the time libfrr calls + * into this code + * - due to this looping (which means it non-single-issue), the callback is + * also persistent. Do _NOT_ re-register the event inside of your + * callback function. + * - either msgfunc or partfunc will be called (only one can be specified) + * - msgfunc is called once for each incoming message + * - if partfunc is specified, the message is read and partfunc is called + * for each ZeroMQ multi-part subpart. Note that you can't send replies + * before all parts have been read because that violates the ZeroMQ FSM. + * - you can safely cancel the callback from within itself + * - installing a callback will check for pending events (ZMQ_EVENTS) and + * may schedule the event to run as soon as libfrr is back in its main + * loop. + * + * TODO #1: add ZMQ_POLLERR / error callback + * TODO #2: add frrzmq_check_events() function to check for edge triggered + * things that may have happened after a zmq_send() call or so + */ +extern struct frrzmq_cb *funcname_frrzmq_thread_add_read( + struct thread_master *master, + void (*msgfunc)(void *arg, void *zmqsock), + void (*partfunc)(void *arg, void *zmqsock, + zmq_msg_t *msg, unsigned partnum), + void *arg, void *zmqsock, debugargdef); + +extern void frrzmq_thread_cancel(struct frrzmq_cb *cb); + +#endif /* _FRRZMQ_H */ diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index 89b0993d1d..264c7c48f0 100644 --- a/lib/grammar_sandbox_main.c +++ b/lib/grammar_sandbox_main.c @@ -50,6 +50,7 @@ int main(int argc, char **argv) /* Library inits. */ cmd_init(1); host.name = strdup("test"); + host.domainname = strdup("testdomainname"); vty_init(master); memory_init(); diff --git a/lib/libfrr.c b/lib/libfrr.c index 9944fdd1e1..3e2e008223 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -101,13 +101,15 @@ static const struct optspec os_always = { static const struct option lo_cfg_pid_dry[] = { {"pid_file", required_argument, NULL, 'i'}, {"config_file", required_argument, NULL, 'f'}, + {"pathspace", required_argument, NULL, 'N'}, {"dryrun", no_argument, NULL, 'C'}, {"terminal", no_argument, NULL, 't'}, {NULL}}; static const struct optspec os_cfg_pid_dry = { - "f:i:Ct", + "f:i:CtN:", " -f, --config_file Set configuration file name\n" " -i, --pid_file Set process identifier file name\n" + " -N, --pathspace Insert prefix into config & socket paths\n" " -C, --dryrun Check configuration for validity and exit\n" " -t, --terminal Open terminal session on stdio\n" " -d -t Daemonize after terminal session ends\n", @@ -351,6 +353,23 @@ static int frr_opt(int opt) return 1; di->config_file = optarg; break; + case 'N': + if (di->flags & FRR_NO_CFG_PID_DRY) + return 1; + if (di->pathspace) { + fprintf(stderr, + "-N/--pathspace option specified more than once!\n"); + errors++; + break; + } + if (strchr(optarg, '/') || strchr(optarg, '.')) { + fprintf(stderr, + "slashes or dots are not permitted in the --pathspace option.\n"); + errors++; + break; + } + di->pathspace = optarg; + break; case 'C': if (di->flags & FRR_NO_CFG_PID_DRY) return 1; @@ -500,14 +519,25 @@ struct thread_master *frr_init(void) struct option_chain *oc; struct frrmod_runtime *module; char moderr[256]; + char p_instance[16] = "", p_pathspace[256] = ""; const char *dir; dir = di->module_path ? di->module_path : frr_moduledir; srandom(time(NULL)); - if (di->instance) + if (di->instance) { snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]", di->logname, di->instance); + snprintf(p_instance, sizeof(p_instance), "-%d", di->instance); + } + if (di->pathspace) + snprintf(p_pathspace, sizeof(p_pathspace), "/%s", + di->pathspace); + + snprintf(config_default, sizeof(config_default), "%s%s/%s%s.conf", + frr_sysconfdir, p_pathspace, di->name, p_instance); + snprintf(pidfile_default, sizeof(pidfile_default), "%s%s/%s%s.pid", + frr_vtydir, p_pathspace, di->name, p_instance); zprivs_preinit(di->privs); @@ -695,14 +725,6 @@ void frr_config_fork(void) { hook_call(frr_late_init, master); - if (di->instance) { - snprintf(config_default, sizeof(config_default), - "%s/%s-%d.conf", frr_sysconfdir, di->name, - di->instance); - snprintf(pidfile_default, sizeof(pidfile_default), - "%s/%s-%d.pid", frr_vtydir, di->name, di->instance); - } - vty_read_config(di->config_file, config_default); /* Don't start execution if we are in dry-run mode */ @@ -723,7 +745,13 @@ void frr_vty_serv(void) * (not currently set anywhere) */ if (!di->vty_path) { const char *dir; - dir = di->vty_sock_path ? di->vty_sock_path : frr_vtydir; + char defvtydir[256]; + + snprintf(defvtydir, sizeof(defvtydir), "%s%s%s", frr_vtydir, + di->pathspace ? "/" : "", + di->pathspace ? di->pathspace : ""); + + dir = di->vty_sock_path ? di->vty_sock_path : defvtydir; if (di->instance) snprintf(vtypath_default, sizeof(vtypath_default), diff --git a/lib/libfrr.h b/lib/libfrr.h index f7d69eecb3..fe6c46670a 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -54,6 +54,7 @@ struct frr_daemon_info { const char *pid_file; const char *vty_path; const char *module_path; + const char *pathspace; const char *proghelp; void (*printhelp)(FILE *target); diff --git a/lib/nexthop.c b/lib/nexthop.c index 7180be33dd..2dba412f45 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -36,7 +36,8 @@ DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop") DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label") /* check if nexthops are same, non-recursive */ -int nexthop_same_no_recurse(struct nexthop *next1, struct nexthop *next2) +int nexthop_same_no_recurse(const struct nexthop *next1, + const struct nexthop *next2) { if (next1->type != next2->type) return 0; diff --git a/lib/nexthop.h b/lib/nexthop.h index e7804379f1..781eb93413 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -43,6 +43,13 @@ enum nexthop_types_t { NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */ }; +enum blackhole_type { + BLACKHOLE_UNSPEC = 0, + BLACKHOLE_NULL, + BLACKHOLE_REJECT, + BLACKHOLE_ADMINPROHIB, +}; + /* Nexthop label structure. */ struct nexthop_label { u_int8_t num_labels; @@ -69,7 +76,10 @@ struct nexthop { #define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */ /* Nexthop address */ - union g_addr gate; + union { + union g_addr gate; + enum blackhole_type bh_type; + }; union g_addr src; union g_addr rmap_src; /* Src is set via routemap */ @@ -128,8 +138,8 @@ void nexthop_add_labels(struct nexthop *, enum lsp_types_t, u_int8_t, void nexthop_del_labels(struct nexthop *); extern const char *nexthop_type_to_str(enum nexthop_types_t nh_type); -extern int nexthop_same_no_recurse(struct nexthop *next1, - struct nexthop *next2); +extern int nexthop_same_no_recurse(const struct nexthop *next1, + const struct nexthop *next2); extern int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2); extern const char *nexthop2str(struct nexthop *nexthop, char *str, int size); @@ -312,7 +312,7 @@ DEFUN_NOSH (ns_netns, if (ns->name && strcmp(ns->name, pathname) != 0) { vty_out(vty, "NS %u is already configured with NETNS %s\n", ns->ns_id, ns->name); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } if (!ns->name) diff --git a/lib/prefix.h b/lib/prefix.h index a27f46ba0a..0732cf1290 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -315,7 +315,9 @@ extern void prefix_ipv4_free(struct prefix_ipv4 *); extern int str2prefix_ipv4(const char *, struct prefix_ipv4 *); extern void apply_mask_ipv4(struct prefix_ipv4 *); -#define PREFIX_COPY_IPV4(DST, SRC) \ +#define PREFIX_COPY(DST, SRC) \ + *((struct prefix *)(DST)) = *((const struct prefix *)(SRC)) +#define PREFIX_COPY_IPV4(DST, SRC) \ *((struct prefix_ipv4 *)(DST)) = *((const struct prefix_ipv4 *)(SRC)); extern int prefix_ipv4_any(const struct prefix_ipv4 *); @@ -377,15 +379,20 @@ static inline int ipv4_martian(struct in_addr *addr) return 0; } -static inline int is_default_prefix(struct prefix *p) +static inline int is_default_prefix(const struct prefix *p) { if (!p) return 0; - if (((p->family == AF_INET) && (p->u.prefix4.s_addr == INADDR_ANY)) - || ((p->family == AF_INET6) - && !memcmp(&p->u.prefix6, &in6addr_any, - sizeof(struct in6_addr)))) + if ((p->family == AF_INET) && + (p->u.prefix4.s_addr == INADDR_ANY) && + (p->prefixlen == 0)) + return 1; + + if ((p->family == AF_INET6) && + (p->prefixlen == 0) && + (!memcmp(&p->u.prefix6, &in6addr_any, + sizeof(struct in6_addr)))) return 1; return 0; diff --git a/lib/routemap.c b/lib/routemap.c index a70248633c..409c9c3780 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -416,23 +416,25 @@ int generic_match_add(struct vty *vty, struct route_map_index *index, int ret; ret = route_map_add_match(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; + switch (ret) { + case RMAP_COMPILE_SUCCESS: + if (type != RMAP_EVENT_MATCH_ADDED) { + route_map_upd8_dependency(type, arg, index->map->name); } + break; + case RMAP_RULE_MISSING: + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; } - if (type != RMAP_EVENT_MATCH_ADDED) { - route_map_upd8_dependency(type, arg, index->map->name); - } return CMD_SUCCESS; } @@ -441,6 +443,7 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, route_map_event_t type) { int ret; + int retval = CMD_SUCCESS; char *dep_name = NULL; const char *tmpstr; char *rmap_name = NULL; @@ -459,34 +462,30 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, } ret = route_map_delete_match(index, command, dep_name); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - break; - case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - break; - } - if (dep_name) - XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); - if (rmap_name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); - return CMD_WARNING_CONFIG_FAILED; + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + if (type != RMAP_EVENT_MATCH_DELETED && dep_name) + route_map_upd8_dependency(type, dep_name, rmap_name); + break; } - if (type != RMAP_EVENT_MATCH_DELETED && dep_name) - route_map_upd8_dependency(type, dep_name, rmap_name); - if (dep_name) XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); if (rmap_name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); - return CMD_SUCCESS; + return retval; } int generic_set_add(struct vty *vty, struct route_map_index *index, @@ -495,19 +494,22 @@ int generic_set_add(struct vty *vty, struct route_map_index *index, int ret; ret = route_map_add_set(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - } + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + break; } + return CMD_SUCCESS; } @@ -517,19 +519,22 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index, int ret; ret = route_map_delete_set(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - } + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + break; } + return CMD_SUCCESS; } @@ -1217,7 +1222,7 @@ int route_map_add_match(struct route_map_index *index, const char *match_name, RMAP_EVENT_CALL_ADDED); } - return 0; + return RMAP_COMPILE_SUCCESS; } /* Delete specified route match rule. */ @@ -1304,7 +1309,7 @@ int route_map_add_set(struct route_map_index *index, const char *set_name, route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED); } - return 0; + return RMAP_COMPILE_SUCCESS; } /* Delete route map set rule. */ @@ -2201,7 +2206,7 @@ DEFUN (no_set_ip_nexthop, "Next hop address\n" "IP address of next hop\n") { - int idx; + int idx = 0; VTY_DECLVAR_CONTEXT(route_map_index, index); const char *arg = NULL; diff --git a/lib/routemap.h b/lib/routemap.h index 43af8dbcfe..b166de1e09 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -99,8 +99,10 @@ struct route_map_rule_cmd { /* Route map apply error. */ enum { + RMAP_COMPILE_SUCCESS, + /* Route map rule is missing. */ - RMAP_RULE_MISSING = 1, + RMAP_RULE_MISSING, /* Route map rule can't compile */ RMAP_COMPILE_ERROR diff --git a/lib/sockunion.h b/lib/sockunion.h index 7b1c7ba9c5..67a7a46272 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -34,6 +34,7 @@ union sockunion { struct sockaddr_in6 sin6; #ifdef __OpenBSD__ struct sockaddr_mpls smpls; + struct sockaddr_rtlabel rtlabel; #endif }; diff --git a/lib/subdir.am b/lib/subdir.am index d6349ba22d..c8eddc8e25 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -17,6 +17,7 @@ lib_libfrr_la_SOURCES = \ lib/csv.c \ lib/distribute.c \ lib/event_counter.c \ + lib/ferr.c \ lib/filter.c \ lib/frr_pthread.c \ lib/getopt.c \ @@ -89,6 +90,7 @@ pkginclude_HEADERS += \ lib/csv.h \ lib/distribute.h \ lib/event_counter.h \ + lib/ferr.h \ lib/fifo.h \ lib/filter.h \ lib/freebsd-queue.h \ @@ -184,6 +186,21 @@ lib_libfrrsnmp_la_SOURCES = \ # end # +# ZeroMQ support +# +if ZEROMQ +lib_LTLIBRARIES += lib/libfrrzmq.la +pkginclude_HEADERS += lib/frr_zmq.h +endif + +lib_libfrrzmq_la_CFLAGS = $(WERROR) $(ZEROMQ_CFLAGS) +lib_libfrrzmq_la_LDFLAGS = -version-info 0:0:0 +lib_libfrrzmq_la_LIBADD = lib/libfrr.la $(ZEROMQ_LIBS) +lib_libfrrzmq_la_SOURCES = \ + lib/frr_zmq.c \ + #end + +# # CLI utilities # noinst_PROGRAMS += \ @@ -91,6 +91,24 @@ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; static int do_log_commands = 0; +void vty_frame(struct vty *vty, const char *format, ...) +{ + va_list args; + + va_start(args, format); + vsnprintf(vty->frame + vty->frame_pos, + sizeof(vty->frame) - vty->frame_pos, format, args); + vty->frame_pos = strlen(vty->frame); + va_end(args); +} + +void vty_endframe(struct vty *vty, const char *endtext) +{ + if (vty->frame_pos == 0 && endtext) + vty_out(vty, "%s", endtext); + vty->frame_pos = 0; +} + /* VTY standard output function. */ int vty_out(struct vty *vty, const char *format, ...) { @@ -100,6 +118,11 @@ int vty_out(struct vty *vty, const char *format, ...) char buf[1024]; char *p = NULL; + if (vty->frame_pos) { + vty->frame_pos = 0; + vty_out(vty, "%s", vty->frame); + } + if (vty_shell(vty)) { va_start(args, format); vprintf(format, args); @@ -250,16 +273,8 @@ void vty_hello(struct vty *vty) /* Put out prompt and wait input from user. */ static void vty_prompt(struct vty *vty) { - struct utsname names; - const char *hostname; - if (vty->type == VTY_TERM) { - hostname = host.name; - if (!hostname) { - uname(&names); - hostname = names.nodename; - } - vty_out(vty, cmd_prompt(vty->node), hostname); + vty_out(vty, cmd_prompt(vty->node), cmd_hostname_get()); } } @@ -125,6 +125,12 @@ struct vty { /* What address is this vty comming from. */ char address[SU_ADDRSTRLEN]; + + /* "frame" output. This is buffered and will be printed if some + * actual output follows, or will be discarded if the frame ends + * without any output. */ + size_t frame_pos; + char frame[1024]; }; static inline void vty_push_context(struct vty *vty, int node, uint64_t id) @@ -247,7 +253,16 @@ extern void vty_terminate(void); extern void vty_reset(void); extern struct vty *vty_new(void); extern struct vty *vty_stdio(void (*atclose)(int isexit)); + +/* - vty_frame() output goes to a buffer (for context-begin markers) + * - vty_out() will first print this buffer, and clear it + * - vty_endframe() clears the buffer without printing it, and prints an + * extra string if the buffer was empty before (for context-end markers) + */ extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); +extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); +extern void vty_endframe(struct vty *, const char *); + extern void vty_read_config(const char *, char *); extern void vty_time_print(struct vty *, int); extern void vty_serv_sock(const char *, unsigned short, const char *); diff --git a/lib/zclient.c b/lib/zclient.c index 72fa2679b3..910e05cb47 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -621,10 +621,9 @@ static int zclient_connect(struct thread *t) * | IPv4 Nexthop address or Interface Index number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * - * Alternatively, if the flags field has ZEBRA_FLAG_BLACKHOLE or - * ZEBRA_FLAG_REJECT is set then Nexthop count is set to 1, then _no_ - * nexthop information is provided, and the message describes a prefix - * to blackhole or reject route. + * Alternatively, if the route is a blackhole route, then Nexthop count + * 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 @@ -692,14 +691,7 @@ int zapi_ipv4_route(u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) { - /* traditional 32-bit data units */ - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_BLACKHOLE)) { - stream_putc(s, 1); - stream_putc(s, NEXTHOP_TYPE_BLACKHOLE); - /* XXX assert(api->nexthop_num == 0); */ - /* XXX assert(api->ifindex_num == 0); */ - } else - stream_putc(s, api->nexthop_num + api->ifindex_num); + stream_putc(s, api->nexthop_num + api->ifindex_num); for (i = 0; i < api->nexthop_num; i++) { stream_putc(s, NEXTHOP_TYPE_IPV4); @@ -769,13 +761,7 @@ int zapi_ipv4_route_ipv6_nexthop(u_char cmd, struct zclient *zclient, /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) { - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_BLACKHOLE)) { - stream_putc(s, 1); - stream_putc(s, NEXTHOP_TYPE_BLACKHOLE); - /* XXX assert(api->nexthop_num == 0); */ - /* XXX assert(api->ifindex_num == 0); */ - } else - stream_putc(s, api->nexthop_num + api->ifindex_num); + stream_putc(s, api->nexthop_num + api->ifindex_num); for (i = 0; i < api->nexthop_num; i++) { stream_putc(s, NEXTHOP_TYPE_IPV6); @@ -855,13 +841,7 @@ int zapi_ipv6_route(u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) { - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_BLACKHOLE)) { - stream_putc(s, 1); - stream_putc(s, NEXTHOP_TYPE_BLACKHOLE); - /* XXX assert(api->nexthop_num == 0); */ - /* XXX assert(api->ifindex_num == 0); */ - } else - stream_putc(s, api->nexthop_num + api->ifindex_num); + stream_putc(s, api->nexthop_num + api->ifindex_num); for (i = 0; i < api->nexthop_num; i++) { stream_putc(s, NEXTHOP_TYPE_IPV6); @@ -948,6 +928,7 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api) stream_putc(s, api_nh->type); switch (api_nh->type) { case NEXTHOP_TYPE_BLACKHOLE: + stream_putc(s, api_nh->bh_type); break; case NEXTHOP_TYPE_IPV4: stream_put_in_addr(s, &api_nh->gate.ipv4); @@ -1060,6 +1041,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) api_nh->type = stream_getc(s); switch (api_nh->type) { case NEXTHOP_TYPE_BLACKHOLE: + api_nh->bh_type = stream_getc(s); break; case NEXTHOP_TYPE_IPV4: api_nh->gate.ipv4.s_addr = stream_get_ipv4(s); diff --git a/lib/zclient.h b/lib/zclient.h index 7c4780201e..288951eb1a 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -222,7 +222,10 @@ struct zserv_header { struct zapi_nexthop { enum nexthop_types_t type; ifindex_t ifindex; - union g_addr gate; + union { + union g_addr gate; + enum blackhole_type bh_type; + }; /* MPLS labels for BGP-LU or Segment Routing */ uint8_t label_num; @@ -429,4 +432,14 @@ extern int zclient_route_send(u_char, struct zclient *, struct zapi_route *); extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *); extern int zapi_route_decode(struct stream *, struct zapi_route *); +static inline void zapi_route_set_blackhole(struct zapi_route *api, + enum blackhole_type bh_type) +{ + api->nexthop_num = 1; + api->nexthops[0].type = NEXTHOP_TYPE_BLACKHOLE; + api->nexthops[0].bh_type = bh_type; + SET_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP); +}; + + #endif /* _ZEBRA_ZCLIENT_H */ diff --git a/lib/zebra.h b/lib/zebra.h index 6d64bbd670..fa5fa89f77 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -404,13 +404,13 @@ extern const char *zserv_command_string(unsigned int command); /* Zebra message flags */ #define ZEBRA_FLAG_INTERNAL 0x01 #define ZEBRA_FLAG_SELFROUTE 0x02 -#define ZEBRA_FLAG_BLACKHOLE 0x04 #define ZEBRA_FLAG_IBGP 0x08 #define ZEBRA_FLAG_SELECTED 0x10 #define ZEBRA_FLAG_STATIC 0x40 -#define ZEBRA_FLAG_REJECT 0x80 #define ZEBRA_FLAG_SCOPE_LINK 0x100 #define ZEBRA_FLAG_FIB_OVERRIDE 0x200 +/* ZEBRA_FLAG_BLACKHOLE was 0x04 */ +/* ZEBRA_FLAG_REJECT was 0x80 */ /* Zebra FEC flags. */ #define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1 diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 4b86bca5f7..495e226f15 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -99,7 +99,9 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix switch (type) { case NHRP_CACHE_NEGATIVE: - SET_FLAG(api.flags, ZEBRA_FLAG_REJECT); + zapi_route_set_blackhole(&api, BLACKHOLE_REJECT); + ifp = NULL; + nexthop = NULL; break; case NHRP_CACHE_DYNAMIC: case NHRP_CACHE_NHS: @@ -158,7 +160,7 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix " count %d dev %s", add ? "add" : "del", buf[0], nexthop ? inet_ntop(api.prefix.family, &api_nh->gate, buf[1], sizeof(buf[1])) : "<onlink>", - api.metric, api.nexthop_num, ifp->name); + api.metric, api.nexthop_num, ifp ? ifp->name : "none"); } zclient_route_send(add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, zclient, diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 6d78fc1d2b..bd5b1aa6f1 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -854,7 +854,7 @@ static int interface_config_write(struct vty *vty) int i; for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { - vty_out (vty, "interface %s\n", ifp->name); + vty_frame(vty, "interface %s\n", ifp->name); if (ifp->desc) vty_out (vty, " description %s\n", ifp->desc); @@ -913,7 +913,7 @@ static int interface_config_write(struct vty *vty) } } - vty_out (vty, "!\n"); + vty_endframe(vty, "!\n"); } return 0; diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 649d7a1000..485937d882 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -643,9 +643,9 @@ void ospf6_area_plist_update(struct prefix_list *plist, int add) const char *name = prefix_list_name(plist); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) { - if (!strcmp(PREFIX_NAME_IN(oa), name)) + if (PREFIX_NAME_IN(oa) && !strcmp(PREFIX_NAME_IN(oa), name)) PREFIX_LIST_IN(oa) = add ? plist : NULL; - if (!strcmp(PREFIX_NAME_OUT(oa), name)) + if (PREFIX_NAME_OUT(oa) && !strcmp(PREFIX_NAME_OUT(oa), name)) PREFIX_LIST_OUT(oa) = add ? plist : NULL; } } diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index dd3630af16..de20fbc3ab 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -985,21 +985,20 @@ static struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = { static int route_map_command_status(struct vty *vty, int ret) { - if (!ret) - return CMD_SUCCESS; - switch (ret) { case RMAP_RULE_MISSING: vty_out(vty, "OSPF6 Can't find rule.\n"); + return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_ERROR: vty_out(vty, "OSPF6 Argument is malformed.\n"); + return CMD_WARNING_CONFIG_FAILED; break; - default: - vty_out(vty, "OSPF6 route-map add set failed.\n"); + case RMAP_COMPILE_SUCCESS: break; } - return CMD_WARNING_CONFIG_FAILED; + + return CMD_SUCCESS; } /* add "set metric-type" */ diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index bb63fb966e..8cfed81a81 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1755,7 +1755,7 @@ static int config_write_ospf6_interface(struct vty *vty) if (oi == NULL) continue; - vty_out(vty, "interface %s\n", oi->interface->name); + vty_frame(vty, "interface %s\n", oi->interface->name); if (ifp->desc) vty_out(vty, " description %s\n", ifp->desc); @@ -1808,7 +1808,7 @@ static int config_write_ospf6_interface(struct vty *vty) ospf6_bfd_write_config(vty, oi); - vty_out(vty, "!\n"); + vty_endframe(vty, "!\n"); } return 0; } diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 387690bc8a..e77bf690f3 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -306,21 +306,25 @@ DEFUN (no_router_ospf6, } /* change Router_ID commands. */ -DEFUN (ospf6_router_id, - ospf6_router_id_cmd, - "router-id A.B.C.D", - "Configure OSPF Router-ID\n" - V4NOTATION_STR) +DEFUN(ospf6_router_id, + ospf6_router_id_cmd, + "ospf6 router-id A.B.C.D", + OSPF6_STR + "Configure OSPF6 Router-ID\n" + V4NOTATION_STR) { VTY_DECLVAR_CONTEXT(ospf6, o); - int idx_ipv4 = 1; + int idx = 0; int ret; + const char *router_id_str; u_int32_t router_id; - ret = inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id); + argv_find(argv, argc, "A.B.C.D", &idx); + router_id_str = argv[idx]->arg; + + ret = inet_pton(AF_INET, router_id_str, &router_id); if (ret == 0) { - vty_out(vty, "malformed OSPF Router-ID: %s\n", - argv[idx_ipv4]->arg); + vty_out(vty, "malformed OSPF Router-ID: %s\n", router_id_str); return CMD_SUCCESS; } @@ -331,6 +335,39 @@ DEFUN (ospf6_router_id, return CMD_SUCCESS; } +DEFUN(no_ospf6_router_id, + no_ospf6_router_id_cmd, + "no ospf6 router-id [A.B.C.D]", + NO_STR OSPF6_STR + "Configure OSPF6 Router-ID\n" + V4NOTATION_STR) +{ + VTY_DECLVAR_CONTEXT(ospf6, o); + o->router_id_static = 0; + o->router_id = 0; + + return CMD_SUCCESS; +} + +#if CONFDATE > 20180828 +CPP_NOTICE("ospf6: `router-id A.B.C.D` deprecated 2017/08/28") +#endif +ALIAS_HIDDEN(ospf6_router_id, + ospf6_router_id_hdn_cmd, + "router-id A.B.C.D", + "Configure OSPF6 Router-ID\n" + V4NOTATION_STR) + +#if CONFDATE > 20180828 +CPP_NOTICE("ospf6: `no router-id A.B.C.D` deprecated 2017/08/28") +#endif +ALIAS_HIDDEN(no_ospf6_router_id, + no_ospf6_router_id_hdn_cmd, + "no router-id [A.B.C.D]", + NO_STR + "Configure OSPF6 Router-ID\n" + V4NOTATION_STR) + DEFUN (ospf6_log_adjacency_changes, ospf6_log_adjacency_changes_cmd, "log-adjacency-changes", @@ -974,7 +1011,7 @@ static int config_write_ospf6(struct vty *vty) sizeof(router_id)); vty_out(vty, "router ospf6\n"); if (ospf6->router_id_static != 0) - vty_out(vty, " router-id %s\n", router_id); + vty_out(vty, " ospf6 router-id %s\n", router_id); /* log-adjacency-changes flag print. */ if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { @@ -1032,6 +1069,9 @@ void ospf6_top_init(void) install_default(OSPF6_NODE); install_element(OSPF6_NODE, &ospf6_router_id_cmd); + install_element(OSPF6_NODE, &no_ospf6_router_id_cmd); + install_element(OSPF6_NODE, &ospf6_router_id_hdn_cmd); + install_element(OSPF6_NODE, &no_ospf6_router_id_hdn_cmd); install_element(OSPF6_NODE, &ospf6_log_adjacency_changes_cmd); install_element(OSPF6_NODE, &ospf6_log_adjacency_changes_detail_cmd); install_element(OSPF6_NODE, &no_ospf6_log_adjacency_changes_cmd); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 3443bc47b6..2372bc54b7 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -231,11 +231,7 @@ static int ospf6_zebra_read_route(int command, struct zclient *zclient, char prefixstr[PREFIX2STR_BUFFER], nexthopstr[128]; prefix2str((struct prefix *)&api.prefix, prefixstr, sizeof(prefixstr)); - if (nexthop) - inet_ntop(AF_INET6, nexthop, nexthopstr, - sizeof(nexthopstr)); - else - snprintf(nexthopstr, sizeof(nexthopstr), "::"); + inet_ntop(AF_INET6, nexthop, nexthopstr, sizeof(nexthopstr)); zlog_debug( "Zebra Receive route %s: %s %s nexthop %s ifindex %ld tag %" ROUTE_TAG_PRI, @@ -392,9 +388,9 @@ void ospf6_zebra_add_discard(struct ospf6_route *request) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; - api.flags = ZEBRA_FLAG_BLACKHOLE; api.safi = SAFI_UNICAST; api.prefix = *dest; + zapi_route_set_blackhole(&api, BLACKHOLE_NULL); zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); @@ -425,9 +421,9 @@ void ospf6_zebra_delete_discard(struct ospf6_route *request) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; - api.flags = ZEBRA_FLAG_BLACKHOLE; api.safi = SAFI_UNICAST; api.prefix = *dest; + zapi_route_set_blackhole(&api, BLACKHOLE_NULL); zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 1c1c76c1af..5517008909 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -2425,7 +2425,7 @@ DEFUN (show_ip_ospf_mpls_te_router, if (ntohs(OspfMplsTE.router_addr.header.type) != 0) show_vty_router_addr(vty, &OspfMplsTE.router_addr.header); - else if (vty != NULL) + else vty_out(vty, " N/A\n"); } return CMD_SUCCESS; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 87aef1ea97..4cbd4b4a99 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -507,7 +507,7 @@ DEFUN (ospf_network_area, ret = ospf_network_set(ospf, &p, area_id, format); if (ret == 0) { vty_out(vty, "There is already same network statement.\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } return CMD_SUCCESS; @@ -847,7 +847,7 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data, != NULL) { vty_out(vty, "OSPF: Key %d already exists\n", vl_config->crypto_key_id); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } ck = ospf_crypt_key_new(); ck->key_id = vl_config->crypto_key_id; @@ -2268,7 +2268,9 @@ DEFUN (no_ospf_timers_lsa_min_arrival, return CMD_SUCCESS; } -/* Deprecated: 08/07/2017 */ +#if CONFDATE > 20180708 +CPP_NOTICE("ospf: `timers lsa arrival (0-1000)` deprecated 2017/07/08") +#endif ALIAS_HIDDEN (ospf_timers_lsa_min_arrival, ospf_timers_lsa_arrival_cmd, "timers lsa arrival (0-1000)", @@ -2277,7 +2279,9 @@ ALIAS_HIDDEN (ospf_timers_lsa_min_arrival, "ospf minimum arrival interval delay\n" "delay (msec) between accepted lsas\n"); -/* Deprecated: 08/07/2017 */ +#if CONFDATE > 20180708 +CPP_NOTICE("ospf: `no timers lsa arrival (0-1000)` deprecated 2017/07/08") +#endif ALIAS_HIDDEN (no_ospf_timers_lsa_min_arrival, no_ospf_timers_lsa_arrival_cmd, "no timers lsa arrival (0-1000)", @@ -2306,7 +2310,10 @@ DEFUN (ospf_neighbor, unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT; - inet_aton(argv[idx_ipv4]->arg, &nbr_addr); + if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) { + vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n"); + return CMD_WARNING_CONFIG_FAILED; + } if (argc > 2) priority = strtoul(argv[idx_pri]->arg, NULL, 10); @@ -2343,7 +2350,10 @@ DEFUN (ospf_neighbor_poll_interval, unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT; - inet_aton(argv[idx_ipv4]->arg, &nbr_addr); + if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) { + vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n"); + return CMD_WARNING_CONFIG_FAILED; + } interval = strtoul(argv[idx_poll]->arg, NULL, 10); @@ -2374,7 +2384,10 @@ DEFUN (no_ospf_neighbor, int idx_ipv4 = 2; struct in_addr nbr_addr; - inet_aton(argv[idx_ipv4]->arg, &nbr_addr); + if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) { + vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n"); + return CMD_WARNING_CONFIG_FAILED; + } (void)ospf_nbr_nbma_unset(ospf, nbr_addr); @@ -2396,7 +2409,10 @@ DEFUN (no_ospf_neighbor_poll, int idx_ipv4 = 2; struct in_addr nbr_addr; - inet_aton(argv[idx_ipv4]->arg, &nbr_addr); + if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) { + vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n"); + return CMD_WARNING_CONFIG_FAILED; + } (void)ospf_nbr_nbma_unset(ospf, nbr_addr); @@ -5950,7 +5966,7 @@ DEFUN (ip_ospf_message_digest_key, key_id = strtol(keyid, NULL, 10); if (ospf_crypt_key_lookup(params->auth_crypt, key_id) != NULL) { vty_out(vty, "OSPF: Key %d already exists\n", key_id); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } ck = ospf_crypt_key_new(); @@ -6958,7 +6974,10 @@ DEFUN (ip_ospf_area, // Check if we have an address arg and proccess it if (argc == idx + 3) { - inet_aton(argv[idx + 2]->arg, &addr); + if (!inet_aton(argv[idx + 2]->arg, &addr)) { + vty_out(vty, "Please specify Intf Address by A.B.C.D\n"); + return CMD_WARNING_CONFIG_FAILED; + } // update/create address-level params params = ospf_get_if_params((ifp), (addr)); if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { @@ -7017,7 +7036,10 @@ DEFUN (no_ip_ospf_area, // Check if we have an address arg and proccess it if (argc == idx + 3) { - inet_aton(argv[idx + 2]->arg, &addr); + if (!inet_aton(argv[idx + 2]->arg, &addr)) { + vty_out(vty, "Please specify Intf Address by A.B.C.D\n"); + return CMD_WARNING_CONFIG_FAILED; + } params = ospf_lookup_if_params(ifp, addr); if ((params) == NULL) return CMD_SUCCESS; @@ -8152,8 +8174,8 @@ static int config_write_interface(struct vty *vty) if (ifp->ifindex == IFINDEX_DELETED) continue; - vty_out(vty, "!\n"); - vty_out(vty, "interface %s\n", ifp->name); + vty_frame(vty, "!\n"); + vty_frame(vty, "interface %s\n", ifp->name); if (ifp->desc) vty_out(vty, " description %s\n", ifp->desc); @@ -8367,6 +8389,8 @@ static int config_write_interface(struct vty *vty) } while (rn); ospf_opaque_config_write_if(vty, ifp); + + vty_endframe(vty, NULL); } return write; diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index dcb392f1ad..e26a33c35f 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -442,9 +442,9 @@ void ospf_zebra_add_discard(struct prefix_ipv4 *p) api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF; api.instance = ospf->instance; - api.flags = ZEBRA_FLAG_BLACKHOLE; api.safi = SAFI_UNICAST; memcpy(&api.prefix, p, sizeof(*p)); + zapi_route_set_blackhole(&api, BLACKHOLE_NULL); zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); @@ -462,9 +462,9 @@ void ospf_zebra_delete_discard(struct prefix_ipv4 *p) api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF; api.instance = ospf->instance; - api.flags = ZEBRA_FLAG_BLACKHOLE; api.safi = SAFI_UNICAST; memcpy(&api.prefix, p, sizeof(*p)); + zapi_route_set_blackhole(&api, BLACKHOLE_NULL); zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); @@ -900,17 +900,10 @@ static int ospf_zebra_read_route(int command, struct zclient *zclient, if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { /* XXX|HACK|TODO|FIXME: - * Maybe we should ignore reject/blackhole routes? Testing shows - * that - * there is no problems though and this is only way to - * "summarize" - * routes in ASBR at the moment. Maybe we need just a better - * generalised - * solution for these types? - * - * if ( CHECK_FLAG (api.flags, ZEBRA_FLAG_BLACKHOLE) - * || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT)) - * return 0; + * Maybe we should ignore reject/blackhole routes? Testing + * shows that there is no problems though and this is only way + * to "summarize" routes in ASBR at the moment. Maybe we need + * just a better generalised solution for these types? */ /* Protocol tag overwrites all other tag value sent by zebra */ diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index ae509f4a9b..4a9c53cf29 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -4895,6 +4895,9 @@ DEFUN (show_ip_mroute_count, int idx = 2; struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + if (!vrf) + return CMD_WARNING; + show_mroute_count(vrf->info, vty); return CMD_SUCCESS; } diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 7fc77556ec..d1f8085b48 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -195,11 +195,16 @@ static int pim_vrf_config_write(struct vty *vty) RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { pim = vrf->info; - if (!pim || vrf->vrf_id != VRF_DEFAULT) { - vty_out(vty, "vrf %s\n", vrf->name); - pim_global_config_write_worker(pim, vty); - vty_out(vty, "!\n"); - } + + if (!pim) + continue; + + if (vrf->vrf_id == VRF_DEFAULT) + continue; + + vty_out(vty, "vrf %s\n", vrf->name); + pim_global_config_write_worker(pim, vty); + vty_out(vty, "!\n"); } return 0; diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 52d240f54b..dca3bf4af3 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -713,21 +713,26 @@ int pim_mroute_socket_enable(struct pim_instance *pim) fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); + if (fd < 0) { + zlog_warn("Could not create mroute socket: errno=%d: %s", errno, + safe_strerror(errno)); + return -2; + } + #ifdef SO_BINDTODEVICE - setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, pim->vrf->name, - strlen(pim->vrf->name)); + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, pim->vrf->name, + strlen(pim->vrf->name))) { + zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s", + safe_strerror(errno)); + close(fd); + return -3; + } #endif if (pimd_privs.change(ZPRIVS_LOWER)) zlog_err("pim_mroute_socket_enable: could not lower privs, %s", safe_strerror(errno)); - if (fd < 0) { - zlog_warn("Could not create mroute socket: errno=%d: %s", errno, - safe_strerror(errno)); - return -2; - } - pim->mroute_socket = fd; if (pim_mroute_set(pim, 1)) { zlog_warn( diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c index 9473462e63..f245a04353 100644 --- a/pimd/pim_msdp_socket.c +++ b/pimd/pim_msdp_socket.c @@ -156,9 +156,15 @@ int pim_msdp_sock_listen(struct pim_instance *pim) if (!ifp) { zlog_err("%s: Unable to lookup vrf interface: %s", __PRETTY_FUNCTION__, pim->vrf->name); + close(sock); + return -1; + } + if (pim_socket_bind(sock, ifp)) { + zlog_err("%s: Unable to bind to socket: %s", + __PRETTY_FUNCTION__, safe_strerror(errno)); + close(sock); return -1; } - pim_socket_bind(sock, ifp); } if (pimd_privs.change(ZPRIVS_RAISE)) { @@ -236,7 +242,13 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp) __PRETTY_FUNCTION__, mp->pim->vrf->name); return -1; } - pim_socket_bind(mp->fd, ifp); + if (pim_socket_bind(mp->fd, ifp)) { + zlog_err("%s: Unable to bind to socket: %s", + __PRETTY_FUNCTION__, safe_strerror(errno)); + close(mp->fd); + mp->fd = -1; + return -1; + } } set_nonblocking(mp->fd); diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 05592992a9..e2c411a307 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -542,7 +542,9 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, } pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info); - str2prefix("224.0.0.0/4", &g_all); + if (!str2prefix("224.0.0.0/4", &g_all)) + return PIM_RP_BAD_ADDRESS; + rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index a4d3d7e4b3..a5a842ceee 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -65,22 +65,21 @@ int pim_socket_raw(int protocol) return fd; } -int pim_socket_ip_hdr(int fd) +void pim_socket_ip_hdr(int fd) { const int on = 1; - int ret; if (pimd_privs.change(ZPRIVS_RAISE)) zlog_err("%s: could not raise privs, %s", __PRETTY_FUNCTION__, safe_strerror(errno)); - ret = setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)); + if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))) + zlog_err("%s: Could not turn on IP_HDRINCL option: %s", + __PRETTY_FUNCTION__, safe_strerror(errno)); if (pimd_privs.change(ZPRIVS_LOWER)) zlog_err("%s: could not lower privs, %s", __PRETTY_FUNCTION__, safe_strerror(errno)); - - return ret; } /* diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index aa46cd6200..358dd39a44 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -36,7 +36,7 @@ #define PIM_SOCK_ERR_BIND (-11) /* Can't bind to interface */ int pim_socket_bind(int fd, struct interface *ifp); -int pim_socket_ip_hdr(int fd); +void pim_socket_ip_hdr(int fd); int pim_socket_raw(int protocol); int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, u_char loop); diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c index 8d270e6205..71bb6f2abd 100644 --- a/pimd/pim_ssm.c +++ b/pimd/pim_ssm.c @@ -71,7 +71,10 @@ static int pim_is_grp_standard_ssm(struct prefix *group) static struct prefix group_ssm; if (first) { - str2prefix(PIM_SSM_STANDARD_RANGE, &group_ssm); + if (!str2prefix(PIM_SSM_STANDARD_RANGE, &group_ssm)) + zlog_err("%s: Failure to Read Group Address: %s", + __PRETTY_FUNCTION__, PIM_SSM_STANDARD_RANGE); + first = 0; } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 96b9568c61..0bf2ce5d56 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1364,7 +1364,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) pim_upstream_start_register_stop_timer(up, 1); if (((up->channel_oil->cc.lastused / 100) - > PIM_KEEPALIVE_PERIOD) + > pim->keep_alive_time) && (I_am_RP(pim_ifp->pim, up->sg.grp))) { if (PIM_DEBUG_TRACE) zlog_debug( diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 8914f6eb00..7607bdf13b 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -255,10 +255,10 @@ int pim_interface_config_write(struct vty *vty) /* IF name */ if (vrf->vrf_id == VRF_DEFAULT) - vty_out(vty, "interface %s\n", ifp->name); + vty_frame(vty, "interface %s\n", ifp->name); else - vty_out(vty, "interface %s vrf %s\n", ifp->name, - vrf->name); + vty_frame(vty, "interface %s vrf %s\n", + ifp->name, vrf->name); ++writes; if (ifp->info) { @@ -363,7 +363,7 @@ int pim_interface_config_write(struct vty *vty) pim_static_write_mroute(pim, vty, ifp); pim_bfd_write_config(vty, ifp); } - vty_out(vty, "!\n"); + vty_endframe(vty, "!\n"); ++writes; } } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 7b060aef4b..a1107e2424 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -184,6 +184,13 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, && (ifp->vrf_id != vrf->vrf_id)) { struct interface *master = if_lookup_by_name( vrf->name, vrf->vrf_id); + + if (!master) { + zlog_debug("%s: Unable to find Master interface for %s", + __PRETTY_FUNCTION__, + vrf->name); + return 0; + } zclient_interface_set_master(zclient, master, ifp); } diff --git a/pimd/test_igmpv3_join.c b/pimd/test_igmpv3_join.c index 3d104e7c7c..bf44f3c94a 100644 --- a/pimd/test_igmpv3_join.c +++ b/pimd/test_igmpv3_join.c @@ -139,7 +139,7 @@ int main(int argc, const char *argv[]) printf("%s: waiting...\n", prog_name); if (getchar() == EOF) - fprintf(stderr, "getchar failure\n"); + fprintf(stderr, "getchar failure\n"); close(fd); diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index cc0632b562..ea8a312364 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -326,7 +326,7 @@ rm -f %{buildroot}%{_libdir}/frr/modules/*.la # install /etc sources %if "%{initsystem}" == "systemd" mkdir -p %{buildroot}%{_unitdir} -install %{zeb_rh_src}/frr.service \ +install -m644 %{zeb_rh_src}/frr.service \ %{buildroot}%{_unitdir}/frr.service install %{zeb_rh_src}/frr.init \ %{buildroot}%{_sbindir}/frr diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 00b6d1cadd..1b2cbb61c3 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -1751,7 +1751,7 @@ static int rip_interface_config_write(struct vty *vty) && (!ri->auth_str) && (!ri->key_chain)) continue; - vty_out(vty, "interface %s\n", ifp->name); + vty_frame(vty, "interface %s\n", ifp->name); if (ifp->desc) vty_out(vty, " description %s\n", ifp->desc); @@ -1807,7 +1807,7 @@ static int rip_interface_config_write(struct vty *vty) vty_out(vty, " ip rip authentication key-chain %s\n", ri->key_chain); - vty_out(vty, "!\n"); + vty_endframe(vty, "!\n"); } return 0; } diff --git a/ripd/ripd.c b/ripd/ripd.c index d9b38bba89..6d6d0b92fd 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1685,6 +1685,7 @@ int rip_recvmsg(int sock, u_char *buf, int size, struct sockaddr_in *from, struct cmsghdr *ptr; char adata[1024]; + memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)from; msg.msg_namelen = sizeof(struct sockaddr_in); msg.msg_iov = &iov; @@ -2880,7 +2881,7 @@ DEFUN (rip_route, if (node->info) { vty_out(vty, "There is already same static route.\n"); route_unlock_node(node); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } node->info = (void *)1; @@ -3352,7 +3353,7 @@ DEFUN (rip_allow_ecmp, { if (rip->ecmp) { vty_out(vty, "ECMP is already enabled.\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } rip->ecmp = 1; @@ -3368,7 +3369,7 @@ DEFUN (no_rip_allow_ecmp, { if (!rip->ecmp) { vty_out(vty, "ECMP is already disabled.\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } rip->ecmp = 0; diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 02fab68254..5c65f522ef 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -1084,7 +1084,7 @@ static int interface_config_write(struct vty *vty) && (ri->split_horizon == ri->split_horizon_default)) continue; - vty_out(vty, "interface %s\n", ifp->name); + vty_frame(vty, "interface %s\n", ifp->name); if (ifp->desc) vty_out(vty, " description %s\n", ifp->desc); @@ -1105,7 +1105,7 @@ static int interface_config_write(struct vty *vty) } } - vty_out(vty, "!\n"); + vty_endframe(vty, "!\n"); write++; } diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 2883698f47..e4368c9f9f 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -176,6 +176,7 @@ int ripng_send_packet(caddr_t buf, int bufsize, struct sockaddr_in6 *to, addr.sin6_port = htons(RIPNG_PORT_DEFAULT); } + memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&addr; msg.msg_namelen = sizeof(struct sockaddr_in6); msg.msg_iov = &iov; @@ -228,6 +229,7 @@ static int ripng_recv_packet(int sock, u_char *buf, int bufsize, char adata[1024]; /* Fill in message and iovec. */ + memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)from; msg.msg_namelen = sizeof(struct sockaddr_in6); msg.msg_iov = &iov; @@ -2215,7 +2217,7 @@ DEFUN (ripng_route, if (rp->info) { vty_out(vty, "There is already same static route.\n"); route_unlock_node(rp); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } rp->info = (void *)1; @@ -2283,7 +2285,7 @@ DEFUN (ripng_aggregate_address, if (node->info) { vty_out(vty, "There is already same aggregate route.\n"); route_unlock_node(node); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } node->info = (void *)1; @@ -2619,7 +2621,7 @@ DEFUN (ripng_allow_ecmp, { if (ripng->ecmp) { vty_out(vty, "ECMP is already enabled.\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } ripng->ecmp = 1; @@ -2635,7 +2637,7 @@ DEFUN (no_ripng_allow_ecmp, { if (!ripng->ecmp) { vty_out(vty, "ECMP is already disabled.\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } ripng->ecmp = 0; diff --git a/tests/.gitignore b/tests/.gitignore index 604ffaa8b6..41349cce24 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -45,4 +45,5 @@ __pycache__ /lib/test_timer_correctness /lib/test_timer_performance /lib/test_ttable +/lib/test_zmq /ospf6d/test_lsdb diff --git a/tests/Makefile.am b/tests/Makefile.am index 59ea3c4c69..1c0e9ee732 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -25,8 +25,12 @@ TESTS_BGPD = endif if ISISD +if SOLARIS +TESTS_ISISD = +else TESTS_ISISD = \ isisd/test_fuzz_isis_tlv +endif else TESTS_ISISD = endif @@ -72,6 +76,12 @@ check_PROGRAMS = \ $(TESTS_OSPF6D) \ # end +if ZEROMQ +check_PROGRAMS += \ + lib/test_zmq \ + # end +endif + ../vtysh/vtysh_cmd.c: $(MAKE) -C ../vtysh vtysh_cmd.c @@ -112,6 +122,8 @@ lib_test_timer_correctness_SOURCES = lib/test_timer_correctness.c \ lib_test_timer_performance_SOURCES = lib/test_timer_performance.c \ helpers/c/prng.c lib_test_ttable_SOURCES = lib/test_ttable.c +lib_test_zmq_SOURCES = lib/test_zmq.c +lib_test_zmq_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS) lib_cli_test_cli_SOURCES = lib/cli/test_cli.c lib/cli/common_cli.c lib_cli_test_commands_SOURCES = lib/cli/test_commands_defun.c \ lib/cli/test_commands.c \ @@ -147,6 +159,7 @@ lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD) lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD) lib_test_ttable_LDADD = $(ALL_TESTS_LDADD) +lib_test_zmq_LDADD = ../lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS) lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD) lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD) bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD) diff --git a/tests/isisd/test_fuzz_isis_tlv.py b/tests/isisd/test_fuzz_isis_tlv.py index 60938472b5..bf700bfee2 100644 --- a/tests/isisd/test_fuzz_isis_tlv.py +++ b/tests/isisd/test_fuzz_isis_tlv.py @@ -1,6 +1,15 @@ import frrtest -class TestFuzzIsisTLV(frrtest.TestMultiOut): - program = './test_fuzz_isis_tlv' +import pytest +import platform -TestFuzzIsisTLV.exit_cleanly() +if platform.uname()[0] == 'SunOS': + class TestFuzzIsisTLV: + @pytest.mark.skipif(True, reason='Test unsupported on SunOS') + def test_exit_cleanly(self): + pass +else: + class TestFuzzIsisTLV(frrtest.TestMultiOut): + program = './test_fuzz_isis_tlv' + + TestFuzzIsisTLV.exit_cleanly() diff --git a/tests/lib/cli/test_commands.py b/tests/lib/cli/test_commands.py index bda0bbac44..d55345186a 100644 --- a/tests/lib/cli/test_commands.py +++ b/tests/lib/cli/test_commands.py @@ -8,4 +8,4 @@ class TestCommands(frrtest.TestRefOut): @pytest.mark.skipif('QUAGGA_TEST_COMMANDS' not in os.environ, reason='QUAGGA_TEST_COMMANDS not set') def test_refout(self): - return super(TestCommands, self).test_refout(self) + return super(TestCommands, self).test_refout() diff --git a/tests/lib/test_zmq.c b/tests/lib/test_zmq.c new file mode 100644 index 0000000000..c270ec3d18 --- /dev/null +++ b/tests/lib/test_zmq.c @@ -0,0 +1,212 @@ +/* + * ZeroMQ event test + * Copyright (C) 2017 David Lamparter, for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <zebra.h> +#include "memory.h" +#include "sigevent.h" +#include "frr_zmq.h" + +DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer") + +static struct thread_master *master; + +static void msg_buf_free(void *data, void *hint) +{ + XFREE(MTYPE_TESTBUF, data); +} + +static void run_client(int syncfd) +{ + int i, j; + char buf[32]; + char dummy; + void *zmqctx = NULL; + void *zmqsock; + + read(syncfd, &dummy, 1); + + zmqctx = zmq_ctx_new(); + zmq_ctx_set(zmqctx, ZMQ_IPV6, 1); + + zmqsock = zmq_socket(zmqctx, ZMQ_REQ); + if (zmq_connect(zmqsock, "tcp://127.0.0.1:17171")) { + perror("zmq_connect"); + exit(1); + } + + /* single-part */ + for (i = 0; i < 8; i++) { + snprintf(buf, sizeof(buf), "msg #%d %c%c%c", + i, 'a' + i, 'b' + i, 'c' + i); + printf("client send: %s\n", buf); + fflush(stdout); + zmq_send(zmqsock, buf, strlen(buf) + 1, 0); + zmq_recv(zmqsock, buf, sizeof(buf), 0); + printf("client recv: %s\n", buf); + } + + /* multipart */ + for (i = 2; i < 5; i++) { + int more; + + printf("---\n"); + for (j = 1; j <= i; j++) { + zmq_msg_t part; + char *dyn = XMALLOC(MTYPE_TESTBUF, 32); + + snprintf(dyn, 32, "part %d/%d", j, i); + printf("client send: %s\n", dyn); + fflush(stdout); + + zmq_msg_init_data(&part, dyn, strlen(dyn) + 1, + msg_buf_free, NULL); + zmq_msg_send(&part, zmqsock, j < i ? ZMQ_SNDMORE : 0); + } + + zmq_msg_t part; + do { + char *data; + + zmq_msg_recv(&part, zmqsock, 0); + data = zmq_msg_data(&part); + more = zmq_msg_more(&part); + printf("client recv (more: %d): %s\n", more, data); + } while (more); + zmq_msg_close(&part); + } + zmq_close(zmqsock); + zmq_ctx_term(zmqctx); +} + +static struct frrzmq_cb *cb; + +static void serverpartfn(void *arg, void *zmqsock, zmq_msg_t *msg, + unsigned partnum) +{ + int more = zmq_msg_more(msg); + char *in = zmq_msg_data(msg); + size_t i; + zmq_msg_t reply; + char *out; + + printf("server recv part %u (more: %d): %s\n", partnum, more, in); + fflush(stdout); + /* REQ-REP doesn't allow sending a reply here */ + if (more) + return; + + out = XMALLOC(MTYPE_TESTBUF, strlen(in) + 1); + for (i = 0; i < strlen(in); i++) + out[i] = toupper(in[i]); + out[i] = '\0'; + zmq_msg_init_data(&reply, out, strlen(out) + 1, msg_buf_free, NULL); + zmq_msg_send(&reply, zmqsock, ZMQ_SNDMORE); + + out = XMALLOC(MTYPE_TESTBUF, 32); + snprintf(out, 32, "msg# was %u", partnum); + zmq_msg_init_data(&reply, out, strlen(out) + 1, msg_buf_free, NULL); + zmq_msg_send(&reply, zmqsock, 0); +} + +static void serverfn(void *arg, void *zmqsock) +{ + static int num = 0; + + char buf[32]; + size_t i; + zmq_recv(zmqsock, buf, sizeof(buf), 0); + + printf("server recv: %s\n", buf); + fflush(stdout); + for (i = 0; i < strlen(buf); i++) + buf[i] = toupper(buf[i]); + zmq_send(zmqsock, buf, strlen(buf) + 1, 0); + + if (++num < 4) + return; + + /* change to multipart callback */ + frrzmq_thread_cancel(cb); + + cb = frrzmq_thread_add_read_part(master, serverpartfn, NULL, zmqsock); +} + +static void sigchld(void) +{ + printf("child exited.\n"); + frrzmq_thread_cancel(cb); +} + +static struct quagga_signal_t sigs[] = { + { + .signal = SIGCHLD, + .handler = sigchld, + }, +}; + +static void run_server(int syncfd) +{ + void *zmqsock; + char dummy = 0; + struct thread t; + + master = thread_master_create(NULL); + signal_init(master, array_size(sigs), sigs); + frrzmq_init(); + + zmqsock = zmq_socket(frrzmq_context, ZMQ_REP); + if (zmq_bind(zmqsock, "tcp://*:17171")) { + perror("zmq_bind"); + exit(1); + } + + cb = frrzmq_thread_add_read_msg(master, serverfn, NULL, zmqsock); + + write(syncfd, &dummy, sizeof(dummy)); + while (thread_fetch(master, &t)) + thread_call(&t); + + zmq_close(zmqsock); + frrzmq_finish(); + thread_master_free(master); + log_memstats_stderr("test"); +} + +int main(void) +{ + int syncpipe[2]; + pid_t child; + + if (pipe(syncpipe)) { + perror("pipe"); + exit(1); + } + + child = fork(); + if (child < 0) { + perror("fork"); + exit(1); + } else if (child == 0) { + run_client(syncpipe[0]); + exit(0); + } + + run_server(syncpipe[1]); + exit(0); +} diff --git a/tests/lib/test_zmq.py b/tests/lib/test_zmq.py new file mode 100644 index 0000000000..1f8ee54169 --- /dev/null +++ b/tests/lib/test_zmq.py @@ -0,0 +1,11 @@ +import frrtest +import pytest +import os + +class TestZMQ(frrtest.TestRefOut): + program = './test_zmq' + + @pytest.mark.skipif('S["ZEROMQ_TRUE"]=""\n' not in open('../config.status').readlines(), + reason='ZEROMQ not enabled') + def test_refout(self): + return super(TestZMQ, self).test_refout() diff --git a/tests/lib/test_zmq.refout b/tests/lib/test_zmq.refout new file mode 100644 index 0000000000..61f45f02b1 --- /dev/null +++ b/tests/lib/test_zmq.refout @@ -0,0 +1,50 @@ +client send: msg #0 abc +server recv: msg #0 abc +client recv: MSG #0 ABC +client send: msg #1 bcd +server recv: msg #1 bcd +client recv: MSG #1 BCD +client send: msg #2 cde +server recv: msg #2 cde +client recv: MSG #2 CDE +client send: msg #3 def +server recv: msg #3 def +client recv: MSG #3 DEF +client send: msg #4 efg +server recv part 0 (more: 0): msg #4 efg +client recv: MSG #4 EFG +client send: msg #5 fgh +client recv: msg# was 0 +client send: msg #6 ghi +server recv part 0 (more: 0): msg #6 ghi +client recv: MSG #6 GHI +client send: msg #7 hij +client recv: msg# was 0 +--- +client send: part 1/2 +client send: part 2/2 +server recv part 0 (more: 1): part 1/2 +server recv part 1 (more: 0): part 2/2 +client recv (more: 1): PART 2/2 +client recv (more: 0): msg# was 1 +--- +client send: part 1/3 +client send: part 2/3 +client send: part 3/3 +server recv part 0 (more: 1): part 1/3 +server recv part 1 (more: 1): part 2/3 +server recv part 2 (more: 0): part 3/3 +client recv (more: 1): PART 3/3 +client recv (more: 0): msg# was 2 +--- +client send: part 1/4 +client send: part 2/4 +client send: part 3/4 +client send: part 4/4 +server recv part 0 (more: 1): part 1/4 +server recv part 1 (more: 1): part 2/4 +server recv part 2 (more: 1): part 3/4 +server recv part 3 (more: 0): part 4/4 +client recv (more: 1): PART 4/4 +client recv (more: 0): msg# was 3 +child exited. diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 85cbcae4df..cbfdf41127 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2295,12 +2295,12 @@ int vtysh_write_config_integrated(void) fprintf(stdout, "Building Configuration...\n"); - backup_config_file(quagga_config); - fp = fopen(quagga_config, "w"); + backup_config_file(frr_config); + fp = fopen(frr_config, "w"); if (fp == NULL) { fprintf(stdout, "%% Error: failed to open configuration file %s: %s\n", - quagga_config, safe_strerror(errno)); + frr_config, safe_strerror(errno)); return CMD_WARNING_CONFIG_FAILED; } fd = fileno(fp); @@ -2313,7 +2313,7 @@ int vtysh_write_config_integrated(void) if (fchmod(fd, CONFIGFILE_MASK) != 0) { printf("%% Warning: can't chmod configuration file %s: %s\n", - quagga_config, safe_strerror(errno)); + frr_config, safe_strerror(errno)); err++; } @@ -2345,18 +2345,18 @@ int vtysh_write_config_integrated(void) if ((uid != (uid_t)-1 || gid != (gid_t)-1) && fchown(fd, uid, gid)) { printf("%% Warning: can't chown configuration file %s: %s\n", - quagga_config, safe_strerror(errno)); + frr_config, safe_strerror(errno)); err++; } } else { - printf("%% Warning: stat() failed on %s: %s\n", quagga_config, + printf("%% Warning: stat() failed on %s: %s\n", frr_config, safe_strerror(errno)); err++; } fclose(fp); - printf("Integrated configuration saved to %s\n", quagga_config); + printf("Integrated configuration saved to %s\n", frr_config); if (err) return CMD_WARNING; @@ -2370,7 +2370,7 @@ static bool want_config_integrated(void) switch (vtysh_write_integrated) { case WRITE_INTEGRATED_UNSPECIFIED: - if (stat(quagga_config, &s) && errno == ENOENT) + if (stat(frr_config, &s) && errno == ENOENT) return false; return true; case WRITE_INTEGRATED_NO: @@ -2712,7 +2712,7 @@ static int vtysh_connect(struct vtysh_client *vclient) if (!vclient->path[0]) snprintf(vclient->path, sizeof(vclient->path), "%s/%s.vty", - vty_sock_path, vclient->name); + vtydir, vclient->name); path = vclient->path; /* Stat socket to see if we have permission to access it. */ @@ -2806,7 +2806,7 @@ static void vtysh_update_all_insances(struct vtysh_client *head_client) return; /* ls vty_sock_dir and look for all files ending in .vty */ - dir = opendir(vty_sock_path); + dir = opendir(vtydir); if (dir) { while ((file = readdir(dir)) != NULL) { if (begins_with(file->d_name, "ospfd-") @@ -2814,7 +2814,7 @@ static void vtysh_update_all_insances(struct vtysh_client *head_client) if (n == MAXIMUM_INSTANCES) { fprintf(stderr, "Parsing %s, client limit(%d) reached!\n", - vty_sock_path, n); + vtydir, n); break; } client = (struct vtysh_client *)malloc( @@ -2823,7 +2823,7 @@ static void vtysh_update_all_insances(struct vtysh_client *head_client) client->name = "ospfd"; client->flag = VTYSH_OSPFD; snprintf(client->path, sizeof(client->path), - "%s/%s", vty_sock_path, file->d_name); + "%s/%s", vtydir, file->d_name); client->next = NULL; vtysh_client_sorted_insert(head_client, client); n++; @@ -2891,21 +2891,9 @@ void vtysh_readline_init(void) char *vtysh_prompt(void) { - static struct utsname names; static char buf[100]; - const char *hostname; - extern struct host host; - - hostname = host.name; - - if (!hostname) { - if (!names.nodename[0]) - uname(&names); - hostname = names.nodename; - } - - snprintf(buf, sizeof buf, cmd_prompt(vty->node), hostname); + snprintf(buf, sizeof buf, cmd_prompt(vty->node), cmd_hostname_get()); return buf; } diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index b0866ec7f3..9d6ea4bda4 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -49,10 +49,6 @@ DECLARE_MGROUP(MVTYSH) #define VTYSH_NS VTYSH_ZEBRA #define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD -/* vtysh local configuration file. */ -#define VTYSH_DEFAULT_CONFIG "vtysh.conf" -#define FRR_DEFAULT_CONFIG "frr.conf" - enum vtysh_write_integrated { WRITE_INTEGRATED_UNSPECIFIED, WRITE_INTEGRATED_NO, @@ -61,7 +57,8 @@ enum vtysh_write_integrated { extern enum vtysh_write_integrated vtysh_write_integrated; -extern char *quagga_config; +extern char frr_config[]; +extern char vtydir[]; void vtysh_init_vty(void); void vtysh_init_cmd(void); @@ -93,11 +90,12 @@ void vtysh_config_init(void); void vtysh_pager_init(void); +void suid_on(void); +void suid_off(void); + /* Child process execution flag. */ extern int execute_flag; extern struct vty *vty; -extern const char *vty_sock_path; - #endif /* VTYSH_H */ diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index c561b5222f..d7e79d6b2c 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -245,7 +245,10 @@ void vtysh_config_parse_line(void *arg, const char *line) == 0 || strncmp(line, "ip extcommunity-list", strlen("ip extcommunity-list")) - == 0) + == 0 + || strncmp(line, "ip large-community-list", + strlen("ip large-community-list")) + == 0) config = config_get(COMMUNITY_LIST_NODE, line); else if (strncmp(line, "ip route", strlen("ip route")) == 0) config = config_get(IP_NODE, line); @@ -420,10 +423,9 @@ int vtysh_read_config(const char *config_default_dir) void vtysh_config_write() { char line[81]; - extern struct host host; - if (host.name) { - sprintf(line, "hostname %s", host.name); + if (cmd_hostname_get()) { + sprintf(line, "hostname %s", cmd_hostname_get()); vtysh_config_parse_line(NULL, line); } if (vtysh_write_integrated == WRITE_INTEGRATED_NO) diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 8145bf3641..f4c21e69cd 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -44,18 +44,22 @@ /* VTY shell program name. */ char *progname; +/* SUID mode */ +static uid_t elevuid, realuid; +static gid_t elevgid, realgid; + +#define VTYSH_CONFIG_NAME "vtysh.conf" +#define FRR_CONFIG_NAME "frr.conf" + /* Configuration file name and directory. */ -static char vtysh_config_always[MAXPATHLEN] = SYSCONFDIR VTYSH_DEFAULT_CONFIG; -static char quagga_config_default[MAXPATHLEN] = SYSCONFDIR FRR_DEFAULT_CONFIG; -char *quagga_config = quagga_config_default; -char history_file[MAXPATHLEN]; +static char vtysh_config[MAXPATHLEN]; +char frr_config[MAXPATHLEN]; +char vtydir[MAXPATHLEN]; +static char history_file[MAXPATHLEN]; /* Flag for indicate executing child command. */ int execute_flag = 0; -/* VTY Socket prefix */ -const char *vty_sock_path = NULL; - /* For sigsetjmp() & siglongjmp(). */ static sigjmp_buf jmpbuf; @@ -145,6 +149,7 @@ static void usage(int status) "-m, --markfile Mark input file with context end\n" " --vty_socket Override vty socket path\n" " --config_dir Override config directory path\n" + "-N --pathspace Insert prefix into config & socket paths\n" "-w, --writeconfig Write integrated config (frr.conf) and exit\n" "-h, --help Display this help and exit\n\n" "Note that multiple commands may be executed from the command\n" @@ -174,6 +179,7 @@ struct option longopts[] = { {"noerror", no_argument, NULL, 'n'}, {"mark", no_argument, NULL, 'm'}, {"writeconfig", no_argument, NULL, 'w'}, + {"pathspace", no_argument, NULL, 'N'}, {0}}; /* Read a string, and return a pointer to it. Returns NULL on EOF. */ @@ -249,6 +255,30 @@ static void vtysh_unflock_config(void) close(flock_fd); } +void suid_on(void) +{ + if (elevuid != realuid && seteuid(elevuid)) { + perror("seteuid(on)"); + exit(1); + } + if (elevgid != realgid && setegid(elevgid)) { + perror("setegid(on)"); + exit(1); + } +} + +void suid_off(void) +{ + if (elevuid != realuid && seteuid(realuid)) { + perror("seteuid(off)"); + exit(1); + } + if (elevgid != realgid && setegid(realgid)) { + perror("setegid(off)"); + exit(1); + } +} + /* VTY shell main routine. */ int main(int argc, char **argv, char **env) { @@ -258,7 +288,6 @@ int main(int argc, char **argv, char **env) int boot_flag = 0; const char *daemon_name = NULL; const char *inputfile = NULL; - const char *vtysh_configfile_name; struct cmd_rec { char *line; struct cmd_rec *next; @@ -270,16 +299,22 @@ int main(int argc, char **argv, char **env) int writeconfig = 0; int ret = 0; char *homedir = NULL; + int ditch_suid = 0; + char sysconfdir[MAXPATHLEN]; + char pathspace[MAXPATHLEN] = ""; - /* check for restricted functionality if vtysh is run setuid */ - int restricted = (getuid() != geteuid()) || (getgid() != getegid()); + /* SUID: drop down to calling user & go back up when needed */ + elevuid = geteuid(); + elevgid = getegid(); + realuid = getuid(); + realgid = getgid(); + suid_off(); /* Preserve name of myself. */ progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]); - /* if logging open now */ - if ((p = getenv("VTYSH_LOG")) != NULL) - logfile = fopen(p, "a"); + strlcpy(sysconfdir, frr_sysconfdir, sizeof(sysconfdir)); + strlcpy(vtydir, frr_vtydir, sizeof(vtydir)); /* Option handling. */ while (1) { @@ -307,63 +342,20 @@ int main(int argc, char **argv, char **env) tail = cr; } break; case OPTION_VTYSOCK: - vty_sock_path = optarg; + ditch_suid = 1; /* option disables SUID */ + strlcpy(vtydir, optarg, sizeof(vtydir)); break; case OPTION_CONFDIR: - /* - * Skip option for Config Directory if setuid - */ - if (restricted) { + ditch_suid = 1; /* option disables SUID */ + strlcpy(sysconfdir, optarg, sizeof(sysconfdir)); + break; + case 'N': + if (strchr(optarg, '/') || strchr(optarg, '.')) { fprintf(stderr, - "Overriding of Config Directory blocked for vtysh with setuid"); - return 1; + "slashes or dots are not permitted in the --pathspace option.\n"); + exit(1); } - /* - * Overwrite location for vtysh.conf - */ - vtysh_configfile_name = - strrchr(VTYSH_DEFAULT_CONFIG, '/'); - if (vtysh_configfile_name) - /* skip '/' */ - vtysh_configfile_name++; - else - /* - * VTYSH_DEFAULT_CONFIG configured with relative - * path - * during config? Should really never happen for - * sensible config - */ - vtysh_configfile_name = - (char *)VTYSH_DEFAULT_CONFIG; - strlcpy(vtysh_config_always, optarg, - sizeof(vtysh_config_always)); - strlcat(vtysh_config_always, "/", - sizeof(vtysh_config_always)); - strlcat(vtysh_config_always, vtysh_configfile_name, - sizeof(vtysh_config_always)); - /* - * Overwrite location for frr.conf - */ - vtysh_configfile_name = - strrchr(FRR_DEFAULT_CONFIG, '/'); - if (vtysh_configfile_name) - /* skip '/' */ - vtysh_configfile_name++; - else - /* - * FRR_DEFAULT_CONFIG configured with relative - * path - * during config? Should really never happen for - * sensible config - */ - vtysh_configfile_name = - (char *)FRR_DEFAULT_CONFIG; - strlcpy(quagga_config_default, optarg, - sizeof(vtysh_config_always)); - strlcat(quagga_config_default, "/", - sizeof(vtysh_config_always)); - strlcat(quagga_config_default, vtysh_configfile_name, - sizeof(quagga_config_default)); + snprintf(pathspace, sizeof(pathspace), "/%s", optarg); break; case 'd': daemon_name = optarg; @@ -395,8 +387,10 @@ int main(int argc, char **argv, char **env) } } - if (!vty_sock_path) - vty_sock_path = frr_vtydir; + if (ditch_suid) { + elevuid = realuid; + elevgid = realgid; + } if (markfile + writeconfig + dryrun + boot_flag > 1) { fprintf(stderr, @@ -410,6 +404,12 @@ int main(int argc, char **argv, char **env) "NOT SUPPORTED since its\nresults are inconsistent!\n"); } + snprintf(vtysh_config, sizeof(vtysh_config), "%s%s/%s", sysconfdir, + pathspace, VTYSH_CONFIG_NAME); + snprintf(frr_config, sizeof(frr_config), "%s%s/%s", sysconfdir, + pathspace, FRR_CONFIG_NAME); + strlcat(vtydir, pathspace, sizeof(vtydir)); + /* Initialize user input buffer. */ line_read = NULL; setlinebuf(stdout); @@ -425,8 +425,11 @@ int main(int argc, char **argv, char **env) vty_init_vtysh(); - /* Read vtysh configuration file before connecting to daemons. */ - vtysh_read_config(vtysh_config_always); + /* Read vtysh configuration file before connecting to daemons. + * (file may not be readable to calling user in SUID mode) */ + suid_on(); + vtysh_read_config(vtysh_config); + suid_off(); if (markfile) { if (!inputfile) { @@ -442,7 +445,7 @@ int main(int argc, char **argv, char **env) if (inputfile) { ret = vtysh_read_config(inputfile); } else { - ret = vtysh_read_config(quagga_config_default); + ret = vtysh_read_config(frr_config); } exit(ret); @@ -486,6 +489,9 @@ int main(int argc, char **argv, char **env) } } + /* SUID: go back up elevated privs */ + suid_on(); + /* Make sure we pass authentication before proceeding. */ vtysh_auth(); @@ -498,6 +504,9 @@ int main(int argc, char **argv, char **env) exit(1); } + /* SUID: back down, don't need privs further on */ + suid_off(); + if (writeconfig) { vtysh_execute("enable"); return vtysh_write_config_integrated(); @@ -531,6 +540,17 @@ int main(int argc, char **argv, char **env) } } + if (getenv("VTYSH_LOG")) { + const char *logpath = getenv("VTYSH_LOG"); + + logfile = fopen(logpath, "a"); + if (!logfile) { + fprintf(stderr, "Failed to open logfile (%s): %s\n", + logpath, strerror(errno)); + exit(1); + } + } + /* If eval mode. */ if (cmd) { /* Enter into enable node. */ @@ -592,13 +612,13 @@ int main(int argc, char **argv, char **env) /* Boot startup configuration file. */ if (boot_flag) { - vtysh_flock_config(quagga_config); - int ret = vtysh_read_config(quagga_config); + vtysh_flock_config(frr_config); + int ret = vtysh_read_config(frr_config); vtysh_unflock_config(); if (ret) { fprintf(stderr, "Configuration file[%s] processing failure: %d\n", - quagga_config, ret); + frr_config, ret); if (no_error) exit(0); else diff --git a/zebra/connected.c b/zebra/connected.c index 701314f246..77a560c6bd 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -54,10 +54,7 @@ static void connected_withdraw(struct connected *ifc) if (ifc->address->family == AF_INET) if_subnet_delete(ifc->ifp, ifc); - if (ifc->address->family == AF_INET) - connected_down_ipv4(ifc->ifp, ifc); - else - connected_down_ipv6(ifc->ifp, ifc); + connected_down(ifc->ifp, ifc); UNSET_FLAG(ifc->conf, ZEBRA_IFC_REAL); } @@ -92,16 +89,15 @@ static void connected_announce(struct interface *ifp, struct connected *ifc) zebra_interface_address_add_update(ifp, ifc); if (if_is_operative(ifp)) { - if (ifc->address->family == AF_INET) - connected_up_ipv4(ifp, ifc); - else - connected_up_ipv6(ifp, ifc); + connected_up(ifp, ifc); } } /* If same interface address is already exist... */ -struct connected *connected_check(struct interface *ifp, struct prefix *p) +struct connected *connected_check(struct interface *ifp, + union prefixconstptr pu) { + const struct prefix *p = pu.p; struct connected *ifc; struct listnode *node; @@ -112,6 +108,33 @@ struct connected *connected_check(struct interface *ifp, struct prefix *p) return NULL; } +/* same, but with peer address */ +struct connected *connected_check_ptp(struct interface *ifp, + union prefixconstptr pu, + union prefixconstptr du) +{ + const struct prefix *p = pu.p; + const struct prefix *d = du.p; + struct connected *ifc; + struct listnode *node; + + /* ignore broadcast addresses */ + if (p->prefixlen != IPV4_MAX_PREFIXLEN) + d = NULL; + + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + if (!prefix_same(ifc->address, p)) + continue; + if (!CONNECTED_PEER(ifc) && !d) + return ifc; + if (CONNECTED_PEER(ifc) && d + && prefix_same(ifc->destination, d)) + return ifc; + } + + return NULL; +} + /* Check if two ifc's describe the same address in the same state */ static int connected_same(struct connected *ifc1, struct connected *ifc2) { @@ -145,7 +168,8 @@ static void connected_update(struct interface *ifp, struct connected *ifc) struct connected *current; /* Check same connected route. */ - if ((current = connected_check(ifp, (struct prefix *)ifc->address))) { + current = connected_check_ptp(ifp, ifc->address, ifc->destination); + if (current) { if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED)) SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); @@ -174,43 +198,70 @@ static void connected_update(struct interface *ifp, struct connected *ifc) } /* Called from if_up(). */ -void connected_up_ipv4(struct interface *ifp, struct connected *ifc) +void connected_up(struct interface *ifp, struct connected *ifc) { + afi_t afi; struct prefix p; + struct nexthop nh = { + .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, + }; if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) return; - PREFIX_COPY_IPV4((struct prefix_ipv4 *)&p, CONNECTED_PREFIX(ifc)); + PREFIX_COPY(&p, CONNECTED_PREFIX(ifc)); /* Apply mask to the network. */ apply_mask(&p); - /* In case of connected address is 0.0.0.0/0 we treat it tunnel - address. */ - if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) + afi = family2afi(p.family); + + switch (afi) { + case AFI_IP: + /* + * In case of connected address is 0.0.0.0/0 we treat it tunnel + * address. + */ + if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) + return; + break; + case AFI_IP6: +#ifndef LINUX + /* XXX: It is already done by rib_bogus_ipv6 within rib_add */ + if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) + return; +#endif + break; + default: + zlog_warn("Received unknown AFI: %s", afi2str(afi)); return; + break; + } - rib_add(AFI_IP, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, - &p, NULL, NULL, NULL, ifp->ifindex, RT_TABLE_MAIN, ifp->metric, - 0, 0); + rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, + &p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0); - rib_add(AFI_IP, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, - &p, NULL, NULL, NULL, ifp->ifindex, RT_TABLE_MAIN, ifp->metric, - 0, 0); + rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, + &p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0); - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - "%u: IF %s IPv4 address add/up, scheduling RIB processing", - ifp->vrf_id, ifp->name); + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + char buf[PREFIX_STRLEN]; + + zlog_debug("%u: IF %s address %s add/up, scheduling RIB processing", + ifp->vrf_id, ifp->name, + prefix2str(&p, buf, sizeof(buf))); + } rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); /* Schedule LSP forwarding entries for processing, if appropriate. */ if (ifp->vrf_id == VRF_DEFAULT) { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug( - "%u: IF %s IPv4 address add/up, scheduling MPLS processing", - ifp->vrf_id, ifp->name); + if (IS_ZEBRA_DEBUG_MPLS) { + char buf[PREFIX_STRLEN]; + + zlog_debug("%u: IF %s IP %s address add/up, scheduling MPLS processing", + ifp->vrf_id, ifp->name, + prefix2str(&p, buf, sizeof(buf))); + } mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id)); } } @@ -238,7 +289,8 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, p = prefix_ipv4_new(); p->family = AF_INET; p->prefix = *addr; - p->prefixlen = prefixlen; + p->prefixlen = CHECK_FLAG(flags, ZEBRA_IFA_PEER) ? IPV4_MAX_PREFIXLEN + : prefixlen; ifc->address = (struct prefix *)p; /* If there is broadcast or peer address. */ @@ -303,127 +355,136 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, connected_update(ifp, ifc); } -void connected_down_ipv4(struct interface *ifp, struct connected *ifc) +void connected_down(struct interface *ifp, struct connected *ifc) { + afi_t afi; struct prefix p; + struct nexthop nh = { + .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, + }; if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) return; - PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); + PREFIX_COPY(&p, CONNECTED_PREFIX(ifc)); /* Apply mask to the network. */ apply_mask(&p); - /* In case of connected address is 0.0.0.0/0 we treat it tunnel - address. */ - if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) - return; + afi = family2afi(p.family); - /* Same logic as for connected_up_ipv4(): push the changes into the - * head. */ - rib_delete(AFI_IP, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, - &p, NULL, NULL, ifp->ifindex, 0, 0); + switch (afi) { + case AFI_IP: + /* + * In case of connected address is 0.0.0.0/0 we treat it tunnel + * address. + */ + if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) + return; + break; + case AFI_IP6: + if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) + return; + break; + default: + zlog_info("Unknown AFI: %s", afi2str(afi)); + break; + } + + /* + * Same logic as for connected_up(): push the changes into the + * head. + */ + rib_delete(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, + &p, NULL, &nh, 0, 0); + + rib_delete(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, + 0, &p, NULL, &nh, 0, 0); - rib_delete(AFI_IP, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - 0, &p, NULL, NULL, ifp->ifindex, 0, 0); + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + char buf[PREFIX_STRLEN]; - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - "%u: IF %s IPv4 address down, scheduling RIB processing", - ifp->vrf_id, ifp->name); + zlog_debug("%u: IF %s IP %s address down, scheduling RIB processing", + ifp->vrf_id, ifp->name, + prefix2str(&p, buf, sizeof(buf))); + } rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); /* Schedule LSP forwarding entries for processing, if appropriate. */ if (ifp->vrf_id == VRF_DEFAULT) { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug( - "%u: IF %s IPv4 address add/up, scheduling MPLS processing", - ifp->vrf_id, ifp->name); + if (IS_ZEBRA_DEBUG_MPLS) { + char buf[PREFIX_STRLEN]; + + zlog_debug("%u: IF %s IP %s address down, scheduling MPLS processing", + ifp->vrf_id, ifp->name, + prefix2str(&p, buf, sizeof(buf))); + } mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id)); } } -/* Delete connected IPv4 route to the interface. */ -void connected_delete_ipv4(struct interface *ifp, int flags, - struct in_addr *addr, u_char prefixlen, - struct in_addr *broad) +static void connected_delete_helper(struct connected *ifc, struct prefix *p) { - struct prefix_ipv4 p; - struct connected *ifc; + struct interface *ifp; - memset(&p, 0, sizeof(struct prefix_ipv4)); - p.family = AF_INET; - p.prefix = *addr; - p.prefixlen = prefixlen; - - ifc = connected_check(ifp, (struct prefix *)&p); if (!ifc) return; + ifp = ifc->ifp; connected_withdraw(ifc); - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - "%u: IF %s IPv4 address del, scheduling RIB processing", - ifp->vrf_id, ifp->name); + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + char buf[PREFIX_STRLEN]; + zlog_debug("%u: IF %s IP %s address del, scheduling RIB processing", + ifp->vrf_id, ifp->name, + prefix2str(p, buf, sizeof(buf))); + } rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); /* Schedule LSP forwarding entries for processing, if appropriate. */ if (ifp->vrf_id == VRF_DEFAULT) { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug( - "%u: IF %s IPv4 address add/up, scheduling MPLS processing", - ifp->vrf_id, ifp->name); + if (IS_ZEBRA_DEBUG_MPLS) { + char buf[PREFIX_STRLEN]; + + zlog_debug("%u: IF %s IP %s address delete, scheduling MPLS processing", + ifp->vrf_id, ifp->name, + prefix2str(p, buf, sizeof(buf))); + } mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id)); } } -void connected_up_ipv6(struct interface *ifp, struct connected *ifc) +/* Delete connected IPv4 route to the interface. */ +void connected_delete_ipv4(struct interface *ifp, int flags, + struct in_addr *addr, u_char prefixlen, + struct in_addr *broad) { - struct prefix p; - - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) - return; - - PREFIX_COPY_IPV6((struct prefix_ipv6 *)&p, CONNECTED_PREFIX(ifc)); - - /* Apply mask to the network. */ - apply_mask(&p); - -#ifndef LINUX - /* XXX: It is already done by rib_bogus_ipv6 within rib_add */ - if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) - return; -#endif - - rib_add(AFI_IP6, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, - &p, NULL, NULL, NULL, ifp->ifindex, RT_TABLE_MAIN, ifp->metric, - 0, 0); - - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - "%u: IF %s IPv6 address down, scheduling RIB processing", - ifp->vrf_id, ifp->name); + struct prefix p, d; + struct connected *ifc; - rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); + memset(&p, 0, sizeof(struct prefix)); + p.family = AF_INET; + p.u.prefix4 = *addr; + p.prefixlen = CHECK_FLAG(flags, ZEBRA_IFA_PEER) ? IPV4_MAX_PREFIXLEN + : prefixlen; - /* Schedule LSP forwarding entries for processing, if appropriate. */ - if (ifp->vrf_id == VRF_DEFAULT) { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug( - "%u: IF %s IPv4 address add/up, scheduling MPLS processing", - ifp->vrf_id, ifp->name); - mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id)); - } + if (broad) { + memset(&d, 0, sizeof(struct prefix)); + d.family = AF_INET; + d.u.prefix4 = *broad; + d.prefixlen = prefixlen; + ifc = connected_check_ptp(ifp, &p, &d); + } else + ifc = connected_check_ptp(ifp, &p, NULL); + + connected_delete_helper(ifc, &p); } /* Add connected IPv6 route to the interface. */ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, - u_char prefixlen, struct in6_addr *broad, - const char *label) + u_char prefixlen, const char *label) { struct prefix_ipv6 *p; struct connected *ifc; @@ -446,29 +507,6 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, p->prefixlen = prefixlen; ifc->address = (struct prefix *)p; - /* If there is broadcast or peer address. */ - if (broad) { - if (IN6_IS_ADDR_UNSPECIFIED(broad)) - zlog_warn( - "warning: %s called for interface %s with unspecified " - "destination address; ignoring!", - __func__, ifp->name); - else { - p = prefix_ipv6_new(); - p->family = AF_INET6; - IPV6_ADDR_COPY(&p->prefix, broad); - p->prefixlen = prefixlen; - ifc->destination = (struct prefix *)p; - } - } - if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination) { - zlog_warn( - "warning: %s called for interface %s " - "with peer flag set, but no peer address supplied", - __func__, ifp->name); - UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); - } - /* Label of this address. */ if (label) ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); @@ -486,72 +524,20 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, connected_update(ifp, ifc); } -void connected_down_ipv6(struct interface *ifp, struct connected *ifc) -{ - struct prefix p; - - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) - return; - - PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); - - apply_mask(&p); - - if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) - return; - - rib_delete(AFI_IP6, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - 0, &p, NULL, NULL, ifp->ifindex, 0, 0); - - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - "%u: IF %s IPv6 address down, scheduling RIB processing", - ifp->vrf_id, ifp->name); - - rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); - - /* Schedule LSP forwarding entries for processing, if appropriate. */ - if (ifp->vrf_id == VRF_DEFAULT) { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug( - "%u: IF %s IPv4 address add/up, scheduling MPLS processing", - ifp->vrf_id, ifp->name); - mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id)); - } -} - void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address, - u_char prefixlen, struct in6_addr *broad) + u_char prefixlen) { - struct prefix_ipv6 p; + struct prefix p; struct connected *ifc; - memset(&p, 0, sizeof(struct prefix_ipv6)); + memset(&p, 0, sizeof(struct prefix)); p.family = AF_INET6; - memcpy(&p.prefix, address, sizeof(struct in6_addr)); + memcpy(&p.u.prefix6, address, sizeof(struct in6_addr)); p.prefixlen = prefixlen; - ifc = connected_check(ifp, (struct prefix *)&p); - if (!ifc) - return; - - connected_withdraw(ifc); - - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - "%u: IF %s IPv6 address del, scheduling RIB processing", - ifp->vrf_id, ifp->name); - - rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); + ifc = connected_check(ifp, &p); - /* Schedule LSP forwarding entries for processing, if appropriate. */ - if (ifp->vrf_id == VRF_DEFAULT) { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug( - "%u: IF %s IPv4 address add/up, scheduling MPLS processing", - ifp->vrf_id, ifp->name); - mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id)); - } + connected_delete_helper(ifc, &p); } int connected_is_unnumbered(struct interface *ifp) diff --git a/zebra/connected.h b/zebra/connected.h index eaf79fe9aa..d10a092984 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -23,7 +23,10 @@ #define _ZEBRA_CONNECTED_H extern struct connected *connected_check(struct interface *ifp, - struct prefix *p); + union prefixconstptr p); +extern struct connected *connected_check_ptp(struct interface *ifp, + union prefixconstptr p, + union prefixconstptr d); extern void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, @@ -35,18 +38,14 @@ extern void connected_delete_ipv4(struct interface *ifp, int flags, extern void connected_delete_ipv4_unnumbered(struct connected *ifc); -extern void connected_up_ipv4(struct interface *, struct connected *); -extern void connected_down_ipv4(struct interface *, struct connected *); +extern void connected_up(struct interface *ifp, struct connected *ifc); +extern void connected_down(struct interface *ifp, struct connected *ifc); extern void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *address, u_char prefixlen, - struct in6_addr *broad, const char *label); + const char *label); extern void connected_delete_ipv6(struct interface *ifp, - struct in6_addr *address, u_char prefixlen, - struct in6_addr *broad); - -extern void connected_up_ipv6(struct interface *, struct connected *); -extern void connected_down_ipv6(struct interface *ifp, struct connected *); + struct in6_addr *address, u_char prefixlen); extern int connected_is_unnumbered(struct interface *); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index a65fcb2b8c..6396911e1b 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -214,7 +214,7 @@ static int if_getaddrs(void) dest_pnt = NULL; - if (ifap->ifa_dstaddr + if (if_is_pointopoint(ifp) && ifap->ifa_dstaddr && !IPV4_ADDR_SAME(&addr->sin_addr, &((struct sockaddr_in *) ifap->ifa_dstaddr) @@ -239,35 +239,12 @@ static int if_getaddrs(void) if (ifap->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr; struct sockaddr_in6 *mask; - struct sockaddr_in6 *dest; - struct in6_addr *dest_pnt; int flags = 0; addr = (struct sockaddr_in6 *)ifap->ifa_addr; mask = (struct sockaddr_in6 *)ifap->ifa_netmask; prefixlen = ip6_masklen(mask->sin6_addr); - dest_pnt = NULL; - - if (ifap->ifa_dstaddr - && !IPV6_ADDR_SAME(&addr->sin6_addr, - &((struct sockaddr_in6 *) - ifap->ifa_dstaddr) - ->sin6_addr)) { - dest = (struct sockaddr_in6 *)ifap->ifa_dstaddr; - dest_pnt = &dest->sin6_addr; - flags = ZEBRA_IFA_PEER; - } else if (ifap->ifa_broadaddr - && !IPV6_ADDR_SAME( - &addr->sin6_addr, - &((struct sockaddr_in6 *) - ifap->ifa_broadaddr) - ->sin6_addr)) { - dest = (struct sockaddr_in6 *) - ifap->ifa_broadaddr; - dest_pnt = &dest->sin6_addr; - } - #if defined(KAME) if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { addr->sin6_scope_id = @@ -279,7 +256,7 @@ static int if_getaddrs(void) #endif connected_add_ipv6(ifp, flags, &addr->sin6_addr, - prefixlen, dest_pnt, NULL); + prefixlen, NULL); } } diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 3d53194593..9ec575b5b0 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -317,8 +317,7 @@ static int if_get_addr(struct interface *ifp, struct sockaddr *addr, (struct in_addr *)dest_pnt, label); else if (af == AF_INET6) connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, - prefixlen, (struct in6_addr *)dest_pnt, - label); + prefixlen, label); return 0; } diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 0d08155178..5a42e0c8f1 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -393,7 +393,7 @@ static int get_iflink_speed(const char *ifname) memset(&ifdata, 0, sizeof(ifdata)); /* set interface name */ - strcpy(ifdata.ifr_name, ifname); + strlcpy(ifdata.ifr_name, ifname, sizeof(ifdata.ifr_name)); /* initialize ethtool interface */ memset(&ecmd, 0, sizeof(ecmd)); @@ -830,18 +830,24 @@ static int netlink_address(int cmd, int family, struct interface *ifp, req.ifa.ifa_family = family; req.ifa.ifa_index = ifp->ifindex; - req.ifa.ifa_prefixlen = p->prefixlen; addattr_l(&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen); - if (family == AF_INET && cmd == RTM_NEWADDR) { - if (!CONNECTED_PEER(ifc) && ifc->destination) { + if (family == AF_INET) { + if (CONNECTED_PEER(ifc)) { + p = ifc->destination; + addattr_l(&req.n, sizeof req, IFA_ADDRESS, &p->u.prefix, + bytelen); + } else if (cmd == RTM_NEWADDR && ifc->destination) { p = ifc->destination; addattr_l(&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, bytelen); } } + /* p is now either ifc->address or ifc->destination */ + req.ifa.ifa_prefixlen = p->prefixlen; + if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) SET_FLAG(req.ifa.ifa_flags, IFA_F_SECONDARY); @@ -993,14 +999,12 @@ int netlink_interface_addr(struct sockaddr_nl *snl, struct nlmsghdr *h, */ if (!(ifa->ifa_flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))) - connected_add_ipv6( - ifp, flags, (struct in6_addr *)addr, - ifa->ifa_prefixlen, - (struct in6_addr *)broad, label); + connected_add_ipv6(ifp, flags, + (struct in6_addr *)addr, + ifa->ifa_prefixlen, label); } else connected_delete_ipv6(ifp, (struct in6_addr *)addr, - ifa->ifa_prefixlen, - (struct in6_addr *)broad); + ifa->ifa_prefixlen); } return 0; diff --git a/zebra/interface.c b/zebra/interface.c index c17e408ea0..5d02259159 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -242,7 +242,7 @@ int if_subnet_add(struct interface *ifp, struct connected *ifc) /* Get address derived subnet node and associated address list, while marking address secondary attribute appropriately. */ - cp = *ifc->address; + cp = *CONNECTED_PREFIX(ifc); apply_mask(&cp); rn = route_node_get(zebra_if->ipv4_subnets, &cp); @@ -267,12 +267,16 @@ int if_subnet_delete(struct interface *ifp, struct connected *ifc) struct route_node *rn; struct zebra_if *zebra_if; struct list *addr_list; + struct prefix cp; assert(ifp && ifp->info && ifc); zebra_if = ifp->info; + cp = *CONNECTED_PREFIX(ifc); + apply_mask(&cp); + /* Get address derived subnet node. */ - rn = route_node_lookup(zebra_if->ipv4_subnets, ifc->address); + rn = route_node_lookup(zebra_if->ipv4_subnets, &cp); if (!(rn && rn->info)) { zlog_warn( "Trying to remove an address from an unknown subnet." @@ -493,7 +497,7 @@ void if_add_update(struct interface *ifp) if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { SET_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE); - if (if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) { + if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "interface %s vrf %u index %d is shutdown. " @@ -523,18 +527,13 @@ static void if_install_connected(struct interface *ifp) struct listnode *node; struct listnode *next; struct connected *ifc; - struct prefix *p; if (ifp->connected) { for (ALL_LIST_ELEMENTS(ifp->connected, node, next, ifc)) { if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) zebra_interface_address_add_update(ifp, ifc); - p = ifc->address; - if (p->family == AF_INET) - connected_up_ipv4(ifp, ifc); - else if (p->family == AF_INET6) - connected_up_ipv6(ifp, ifc); + connected_up(ifp, ifc); } } } @@ -545,17 +544,11 @@ static void if_uninstall_connected(struct interface *ifp) struct listnode *node; struct listnode *next; struct connected *ifc; - struct prefix *p; if (ifp->connected) { for (ALL_LIST_ELEMENTS(ifp->connected, node, next, ifc)) { - p = ifc->address; zebra_interface_address_delete_update(ifp, ifc); - - if (p->family == AF_INET) - connected_down_ipv4(ifp, ifc); - else if (p->family == AF_INET6) - connected_down_ipv6(ifp, ifc); + connected_down(ifp, ifc); } } } @@ -565,7 +558,7 @@ static void if_uninstall_connected(struct interface *ifp) static void if_delete_connected(struct interface *ifp) { struct connected *ifc; - struct prefix *p; + struct prefix cp; struct route_node *rn; struct zebra_if *zebra_if; @@ -578,11 +571,13 @@ static void if_delete_connected(struct interface *ifp) while ((node = (last ? last->next : listhead(ifp->connected)))) { ifc = listgetdata(node); - p = ifc->address; - if (p->family == AF_INET + cp = *CONNECTED_PREFIX(ifc); + apply_mask(&cp); + + if (cp.family == AF_INET && (rn = route_node_lookup(zebra_if->ipv4_subnets, - p))) { + &cp))) { struct listnode *anode; struct listnode *next; struct listnode *first; @@ -602,7 +597,7 @@ static void if_delete_connected(struct interface *ifp) next = anode->next; ifc = listgetdata(anode); - connected_down_ipv4(ifp, ifc); + connected_down(ifp, ifc); /* XXX: We have to send notifications * here explicitly, because we destroy @@ -635,8 +630,8 @@ static void if_delete_connected(struct interface *ifp) list_delete(addr_list); rn->info = NULL; route_unlock_node(rn); - } else if (p->family == AF_INET6) { - connected_down_ipv6(ifp, ifc); + } else if (cp.family == AF_INET6) { + connected_down(ifp, ifc); zebra_interface_address_delete_update(ifp, ifc); @@ -873,7 +868,8 @@ void if_up(struct interface *ifp) link_if = ifp; zebra_vxlan_svi_up(ifp, link_if); } else if (IS_ZEBRA_IF_VLAN(ifp)) { - link_if = zif->link; + link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + zif->link_ifindex); if (link_if) zebra_vxlan_svi_up(ifp, link_if); } @@ -901,7 +897,8 @@ void if_down(struct interface *ifp) link_if = ifp; zebra_vxlan_svi_down(ifp, link_if); } else if (IS_ZEBRA_IF_VLAN(ifp)) { - link_if = zif->link; + link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + zif->link_ifindex); if (link_if) zebra_vxlan_svi_down(ifp, link_if); } @@ -966,6 +963,8 @@ static void connected_dump_vty(struct vty *vty, struct connected *connected) vty_out(vty, (CONNECTED_PEER(connected) ? " peer " : " broadcast ")); prefix_vty_out(vty, connected->destination); + if (CONNECTED_PEER(connected)) + vty_out(vty, "/%d", connected->destination->prefixlen); } if (CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY)) @@ -2365,38 +2364,56 @@ static int ip_address_install(struct vty *vty, struct interface *ifp, const char *label) { struct zebra_if *if_data; - struct prefix_ipv4 cp; + struct prefix_ipv4 lp, pp; struct connected *ifc; struct prefix_ipv4 *p; int ret; if_data = ifp->info; - ret = str2prefix_ipv4(addr_str, &cp); + ret = str2prefix_ipv4(addr_str, &lp); if (ret <= 0) { vty_out(vty, "%% Malformed address \n"); return CMD_WARNING_CONFIG_FAILED; } - if (ipv4_martian(&cp.prefix)) { + if (ipv4_martian(&lp.prefix)) { vty_out(vty, "%% Invalid address\n"); return CMD_WARNING_CONFIG_FAILED; } - ifc = connected_check(ifp, (struct prefix *)&cp); + if (peer_str) { + if (lp.prefixlen != 32) { + vty_out(vty, + "%% Local prefix length for P-t-P address must be /32\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = str2prefix_ipv4(peer_str, &pp); + if (ret <= 0) { + vty_out(vty, "%% Malformed peer address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + + ifc = connected_check_ptp(ifp, &lp, peer_str ? &pp : NULL); if (!ifc) { ifc = connected_new(); ifc->ifp = ifp; /* Address. */ p = prefix_ipv4_new(); - *p = cp; + *p = lp; ifc->address = (struct prefix *)p; - /* Broadcast. */ - if (p->prefixlen <= IPV4_MAX_PREFIXLEN - 2) { + if (peer_str) { + SET_FLAG(ifc->flags, ZEBRA_IFA_PEER); p = prefix_ipv4_new(); - *p = cp; + *p = pp; + ifc->destination = (struct prefix *)p; + } else if (p->prefixlen <= IPV4_MAX_PREFIXLEN - 2) { + p = prefix_ipv4_new(); + *p = lp; p->prefix.s_addr = ipv4_broadcast_addr(p->prefix.s_addr, p->prefixlen); ifc->destination = (struct prefix *)p; @@ -2445,19 +2462,33 @@ static int ip_address_uninstall(struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, const char *label) { - struct prefix_ipv4 cp; + struct prefix_ipv4 lp, pp; struct connected *ifc; int ret; /* Convert to prefix structure. */ - ret = str2prefix_ipv4(addr_str, &cp); + ret = str2prefix_ipv4(addr_str, &lp); if (ret <= 0) { vty_out(vty, "%% Malformed address \n"); return CMD_WARNING_CONFIG_FAILED; } + if (peer_str) { + if (lp.prefixlen != 32) { + vty_out(vty, + "%% Local prefix length for P-t-P address must be /32\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = str2prefix_ipv4(peer_str, &pp); + if (ret <= 0) { + vty_out(vty, "%% Malformed peer address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + /* Check current interface address. */ - ifc = connected_check(ifp, (struct prefix *)&cp); + ifc = connected_check_ptp(ifp, &lp, peer_str ? &pp : NULL); if (!ifc) { vty_out(vty, "%% Can't find address\n"); return CMD_WARNING_CONFIG_FAILED; @@ -2517,6 +2548,32 @@ DEFUN (no_ip_address, NULL, NULL); } +DEFUN(ip_address_peer, + ip_address_peer_cmd, + "ip address A.B.C.D peer A.B.C.D/M", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "Local IP (e.g. 10.0.0.1) for P-t-P address\n" + "Specify P-t-P address\n" + "Peer IP address (e.g. 10.0.0.1/8)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + return ip_address_install(vty, ifp, argv[2]->arg, argv[4]->arg, NULL); +} + +DEFUN(no_ip_address_peer, + no_ip_address_peer_cmd, + "no ip address A.B.C.D peer A.B.C.D/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "Local IP (e.g. 10.0.0.1) for P-t-P address\n" + "Specify P-t-P address\n" + "Peer IP address (e.g. 10.0.0.1/8)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + return ip_address_uninstall(vty, ifp, argv[3]->arg, argv[5]->arg, NULL); +} #ifdef HAVE_NETLINK DEFUN (ip_address_label, @@ -2791,7 +2848,7 @@ static int if_config_write(struct vty *vty) vrf = vrf_lookup_by_id(ifp->vrf_id); if (ifp->vrf_id == VRF_DEFAULT) - vty_out(vty, "interface %s\n", ifp->name); + vty_frame(vty, "interface %s\n", ifp->name); else vty_out(vty, "interface %s vrf %s\n", ifp->name, vrf->name); @@ -2820,7 +2877,16 @@ static int if_config_write(struct vty *vty) p = ifc->address; vty_out(vty, " ip%s address %s", p->family == AF_INET ? "" : "v6", - prefix2str(p, buf, sizeof(buf))); + inet_ntop(p->family, &p->u.prefix, buf, + sizeof(buf))); + if (CONNECTED_PEER(ifc)) { + p = ifc->destination; + vty_out(vty, " peer %s", + inet_ntop(p->family, + &p->u.prefix, buf, + sizeof(buf))); + } + vty_out(vty, "/%d", p->prefixlen); if (ifc->label) vty_out(vty, " label %s", ifc->label); @@ -2842,7 +2908,7 @@ static int if_config_write(struct vty *vty) link_params_config_write(vty, ifp); - vty_out(vty, "!\n"); + vty_endframe(vty, "!\n"); } return 0; } @@ -2876,6 +2942,8 @@ void zebra_if_init(void) install_element(INTERFACE_NODE, &no_bandwidth_if_cmd); install_element(INTERFACE_NODE, &ip_address_cmd); install_element(INTERFACE_NODE, &no_ip_address_cmd); + install_element(INTERFACE_NODE, &ip_address_peer_cmd); + install_element(INTERFACE_NODE, &no_ip_address_peer_cmd); install_element(INTERFACE_NODE, &ipv6_address_cmd); install_element(INTERFACE_NODE, &no_ipv6_address_cmd); #ifdef HAVE_NETLINK diff --git a/zebra/interface.h b/zebra/interface.h index 7b56dcd4a4..6bc05e21c5 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -183,12 +183,12 @@ struct rtadvconf { /* Zebra interface type - ones of interest. */ typedef enum { - ZEBRA_IF_VXLAN, /* VxLAN interface */ - ZEBRA_IF_VRF, /* VRF device */ - ZEBRA_IF_BRIDGE, /* bridge device */ - ZEBRA_IF_VLAN, /* VLAN sub-interface */ - ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/ - ZEBRA_IF_OTHER, /* Anything else */ + ZEBRA_IF_OTHER = 0, /* Anything else */ + ZEBRA_IF_VXLAN, /* VxLAN interface */ + ZEBRA_IF_VRF, /* VRF device */ + ZEBRA_IF_BRIDGE, /* bridge device */ + ZEBRA_IF_VLAN, /* VLAN sub-interface */ + ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/ } zebra_iftype_t; /* Zebra "slave" interface type */ diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 835f1f4934..58118ce006 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -44,7 +44,7 @@ extern struct zebra_privs_t zserv_privs; /* clear and set interface name string */ void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp) { - strncpy(ifreq->ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq->ifr_name, ifp->name, sizeof(ifreq->ifr_name)); } /* call ioctl system call */ @@ -179,10 +179,15 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc) { int ret; struct ifaliasreq addreq; - struct sockaddr_in addr; - struct sockaddr_in mask; + struct sockaddr_in addr, mask, peer; struct prefix_ipv4 *p; + /* don't configure PtP addresses on broadcast ifs or reverse */ + if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) { + errno = EINVAL; + return -1; + } + p = (struct prefix_ipv4 *)ifc->address; rib_lookup_and_pushup(p, ifp->vrf_id); @@ -197,6 +202,18 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc) #endif memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in)); + if (CONNECTED_PEER(ifc)) { + p = (struct prefix_ipv4 *)ifc->destination; + memset(&mask, 0, sizeof(struct sockaddr_in)); + peer.sin_addr = p->prefix; + peer.sin_family = p->family; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + peer.sin_len = sizeof(struct sockaddr_in); +#endif + memcpy(&addreq.ifra_broadaddr, &peer, + sizeof(struct sockaddr_in)); + } + memset(&mask, 0, sizeof(struct sockaddr_in)); masklen2ip(p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; @@ -217,10 +234,15 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc) { int ret; struct ifaliasreq addreq; - struct sockaddr_in addr; - struct sockaddr_in mask; + struct sockaddr_in addr, mask, peer; struct prefix_ipv4 *p; + /* this would probably wreak havoc */ + if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) { + errno = EINVAL; + return -1; + } + p = (struct prefix_ipv4 *)ifc->address; memset(&addreq, 0, sizeof addreq); @@ -234,6 +256,18 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc) #endif memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in)); + if (CONNECTED_PEER(ifc)) { + p = (struct prefix_ipv4 *)ifc->destination; + memset(&mask, 0, sizeof(struct sockaddr_in)); + peer.sin_addr = p->prefix; + peer.sin_family = p->family; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + peer.sin_len = sizeof(struct sockaddr_in); +#endif + memcpy(&addreq.ifra_broadaddr, &peer, + sizeof(struct sockaddr_in)); + } + memset(&mask, 0, sizeof(struct sockaddr_in)); masklen2ip(p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 0832245536..11bc9b0440 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -182,6 +182,7 @@ static int irdp_recvmsg(int sock, u_char *buf, int size, int *ifindex) char adata[CMSG_SPACE(SOPT_SIZE_CMSG_PKTINFO_IPV4())]; int ret; + memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)0; msg.msg_namelen = 0; msg.msg_iov = &iov; diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index e2a1deb9ac..df8cdb3ab3 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -441,6 +441,12 @@ int ifm_read(struct if_msghdr *ifm) RTA_ADDR_GET(NULL, RTA_IFA, ifm->ifm_addrs, cp); RTA_ADDR_GET(NULL, RTA_AUTHOR, ifm->ifm_addrs, cp); RTA_ADDR_GET(NULL, RTA_BRD, ifm->ifm_addrs, cp); +#ifdef RTA_LABEL + RTA_ATTR_GET(NULL, RTA_LABEL, ifm->ifm_addrs, cp); +#endif +#ifdef RTA_SRC + RTA_ADDR_GET(NULL, RTA_SRC, ifm->ifm_addrs, cp); +#endif if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: sdl ifname %s", __func__, @@ -661,6 +667,12 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, RTA_ADDR_GET(addr, RTA_IFA, ifm->ifam_addrs, pnt); RTA_ADDR_GET(NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt); RTA_ADDR_GET(brd, RTA_BRD, ifm->ifam_addrs, pnt); +#ifdef RTA_LABEL + RTA_ATTR_GET(NULL, RTA_LABEL, ifm->ifam_addrs, pnt); +#endif +#ifdef RTA_SRC + RTA_ADDR_GET(NULL, RTA_SRC, ifm->ifam_addrs, pnt); +#endif if (IS_ZEBRA_DEBUG_KERNEL) { int family = sockunion_family(addr); @@ -762,12 +774,10 @@ int ifam_read(struct ifa_msghdr *ifam) if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv6(ifp, flags, &addr.sin6.sin6_addr, ip6_masklen(mask.sin6.sin6_addr), - &brd.sin6.sin6_addr, (isalias ? ifname : NULL)); else connected_delete_ipv6(ifp, &addr.sin6.sin6_addr, - ip6_masklen(mask.sin6.sin6_addr), - &brd.sin6.sin6_addr); + ip6_masklen(mask.sin6.sin6_addr)); break; default: /* Unsupported family silently ignore... */ @@ -829,6 +839,17 @@ static int rtm_read_mesg(struct rt_msghdr *rtm, union sockunion *dest, RTA_ADDR_GET(NULL, RTA_IFA, rtm->rtm_addrs, pnt); RTA_ADDR_GET(NULL, RTA_AUTHOR, rtm->rtm_addrs, pnt); RTA_ADDR_GET(NULL, RTA_BRD, rtm->rtm_addrs, pnt); +#ifdef RTA_LABEL +#if 0 + union sockunion label; + memset(&label, 0, sizeof(label)); + RTA_ATTR_GET(&label, RTA_LABEL, rtm->rtm_addrs, pnt); +#endif + RTA_ATTR_GET(NULL, RTA_LABEL, rtm->rtm_addrs, pnt); +#endif +#ifdef RTA_SRC + RTA_ADDR_GET(NULL, RTA_SRC, rtm->rtm_addrs, pnt); +#endif /* If there is netmask information set it's family same as destination family*/ @@ -849,6 +870,7 @@ void rtm_read(struct rt_msghdr *rtm) union sockunion dest, mask, gate; char ifname[INTERFACE_NAMSIZ + 1]; short ifnlen = 0; + struct nexthop nh; zebra_flags = 0; @@ -886,11 +908,15 @@ void rtm_read(struct rt_msghdr *rtm) if (flags & RTF_STATIC) SET_FLAG(zebra_flags, ZEBRA_FLAG_STATIC); + memset(&nh, 0, sizeof(nh)); /* This is a reject or blackhole route */ - if (flags & RTF_REJECT) - SET_FLAG(zebra_flags, ZEBRA_FLAG_REJECT); - if (flags & RTF_BLACKHOLE) - SET_FLAG(zebra_flags, ZEBRA_FLAG_BLACKHOLE); + if (flags & RTF_REJECT) { + nh.type = NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = BLACKHOLE_REJECT; + } else if (flags & RTF_BLACKHOLE) { + nh.type = NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = BLACKHOLE_NULL; + } if (dest.sa.sa_family == AF_INET) { struct prefix p; @@ -1016,18 +1042,22 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_CHANGE) rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - NULL, 0, 0, 0); + NULL, 0, 0); + + if (!nh.type) { + nh.type = NEXTHOP_TYPE_IPV4; + nh.gate.ipv4 = gate.sin.sin_addr; + } - union g_addr ggate = {.ipv4 = gate.sin.sin_addr}; if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &ggate, NULL, 0, 0, 0, 0, 0); + &nh, 0, 0, 0, 0); else rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &ggate, 0, 0, 0); + &nh, 0, 0); } if (dest.sa.sa_family == AF_INET6) { /* One day we might have a debug section here like one in the @@ -1058,18 +1088,24 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_CHANGE) rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - NULL, 0, 0, 0); + NULL, 0, 0); + + if (!nh.type) { + nh.type = ifindex ? NEXTHOP_TYPE_IPV6_IFINDEX + : NEXTHOP_TYPE_IPV6; + nh.gate.ipv6 = gate.sin6.sin6_addr; + nh.ifindex = ifindex; + } - union g_addr ggate = {.ipv6 = gate.sin6.sin6_addr}; if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &ggate, NULL, ifindex, 0, 0, 0, 0); + &nh, 0, 0, 0, 0); else rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &ggate, ifindex, 0, 0); + &nh, 0, 0); } } @@ -1079,7 +1115,7 @@ void rtm_read(struct rt_msghdr *rtm) */ int rtm_write(int message, union sockunion *dest, union sockunion *mask, union sockunion *gate, union sockunion *mpls, unsigned int index, - int zebra_flags, int metric) + enum blackhole_type bh_type, int metric) { int ret; caddr_t pnt; @@ -1169,11 +1205,16 @@ int rtm_write(int message, union sockunion *dest, union sockunion *mask, /* Tagging route with flags */ msg.rtm.rtm_flags |= (RTF_PROTO1); - /* Additional flags. */ - if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) - msg.rtm.rtm_flags |= RTF_BLACKHOLE; - if (zebra_flags & ZEBRA_FLAG_REJECT) + switch (bh_type) { + case BLACKHOLE_UNSPEC: + break; + case BLACKHOLE_REJECT: msg.rtm.rtm_flags |= RTF_REJECT; + break; + default: + msg.rtm.rtm_flags |= RTF_BLACKHOLE; + break; + } #define SOCKADDRSET(X, R) \ diff --git a/zebra/kernel_socket.h b/zebra/kernel_socket.h index 41b322185f..096a21f782 100644 --- a/zebra/kernel_socket.h +++ b/zebra/kernel_socket.h @@ -34,8 +34,8 @@ extern void rtm_read(struct rt_msghdr *); extern int ifam_read(struct ifa_msghdr *); extern int ifm_read(struct if_msghdr *); extern int rtm_write(int, union sockunion *, union sockunion *, - union sockunion *, union sockunion *, unsigned int, int, - int); + union sockunion *, union sockunion *, unsigned int, + enum blackhole_type, int); extern const struct message rtm_type_str[]; #endif /* __ZEBRA_KERNEL_SOCKET_H */ diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 9b21eb4d8c..ce86b6c1e3 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -52,25 +52,17 @@ static u_int32_t zebra_import_table_distance[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX]; int is_zebra_import_table_enabled(afi_t afi, u_int32_t table_id) { + /* + * Make sure that what we are called with actualy makes sense + */ + if (afi == AFI_MAX) + return 0; + if (is_zebra_valid_kernel_table(table_id)) return zebra_import_table_used[afi][table_id]; return 0; } -int is_default(struct prefix *p) -{ - if (p->family == AF_INET) - if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0) - return 1; -#if 0 /* IPv6 default separation is now pending until protocol daemon \ - can handle that. */ - if (p->family == AF_INET6) - if (IN6_IS_ADDR_UNSPECIFIED (&p->u.prefix6) && p->prefixlen == 0) - return 1; -#endif /* 0 */ - return 0; -} - static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id) { int afi; @@ -175,7 +167,7 @@ void redistribute_update(struct prefix *p, struct prefix *src_p, for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { send_redistribute = 0; - if (is_default(p) + if (is_default_prefix(p) && vrf_bitmap_check(client->redist_default, re->vrf_id)) send_redistribute = 1; else if (vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL], @@ -234,7 +226,7 @@ void redistribute_delete(struct prefix *p, struct prefix *src_p, } for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { - if ((is_default(p) + if ((is_default_prefix(p) && vrf_bitmap_check(client->redist_default, re->vrf_id)) || vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL], re->vrf_id) @@ -496,94 +488,78 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re, struct route_entry *newre; struct route_entry *same; struct prefix p; - struct nexthop *nhop; - union g_addr *gate; route_map_result_t ret = RMAP_MATCH; + afi_t afi; + afi = family2afi(rn->p.family); if (rmap_name) ret = zebra_import_table_route_map_check( - AFI_IP, re->type, &rn->p, re->nexthop, re->vrf_id, + afi, re->type, &rn->p, re->nexthop, re->vrf_id, re->tag, rmap_name); - if (ret == RMAP_MATCH) { - if (rn->p.family == AF_INET) { - p.family = AF_INET; - p.prefixlen = rn->p.prefixlen; - p.u.prefix4 = rn->p.u.prefix4; + if (ret != RMAP_MATCH) { + zebra_del_import_table_entry(rn, re); + return 0; + } - RNODE_FOREACH_RE(rn, same) - { - if (CHECK_FLAG(same->status, - ROUTE_ENTRY_REMOVED)) - continue; + prefix_copy(&p, &rn->p); - if (same->type == re->type - && same->instance == re->instance - && same->table == re->table - && same->type != ZEBRA_ROUTE_CONNECT) - break; - } + RNODE_FOREACH_RE(rn, same) + { + if (CHECK_FLAG(same->status, + ROUTE_ENTRY_REMOVED)) + continue; - if (same) - zebra_del_import_table_entry(rn, same); - - - if (re->nexthop_num == 1) { - nhop = re->nexthop; - if (nhop->type == NEXTHOP_TYPE_IFINDEX) - gate = NULL; - else - gate = (union g_addr *)&nhop->gate.ipv4; - - rib_add(AFI_IP, SAFI_UNICAST, re->vrf_id, - ZEBRA_ROUTE_TABLE, re->table, 0, &p, - NULL, gate, - (union g_addr *)&nhop->src.ipv4, - nhop->ifindex, zebrad.rtm_table_default, - re->metric, re->mtu, - zebra_import_table_distance[AFI_IP] - [re->table]); - } else if (re->nexthop_num > 1) { - newre = XCALLOC(MTYPE_RE, - sizeof(struct route_entry)); - newre->type = ZEBRA_ROUTE_TABLE; - newre->distance = - zebra_import_table_distance[AFI_IP] - [re->table]; - newre->flags = re->flags; - newre->metric = re->metric; - newre->mtu = re->mtu; - newre->table = zebrad.rtm_table_default; - newre->nexthop_num = 0; - newre->uptime = time(NULL); - newre->instance = re->table; - route_entry_copy_nexthops(newre, re->nexthop); - - rib_add_multipath(AFI_IP, SAFI_UNICAST, &p, - NULL, newre); - } - } - } else { - zebra_del_import_table_entry(rn, re); + if (same->type == re->type + && same->instance == re->instance + && same->table == re->table + && same->type != ZEBRA_ROUTE_CONNECT) + break; + } + + if (same) + zebra_del_import_table_entry(rn, same); + + if (re->nexthop_num == 1) { + rib_add(afi, SAFI_UNICAST, re->vrf_id, + ZEBRA_ROUTE_TABLE, re->table, 0, &p, + NULL, re->nexthop, + zebrad.rtm_table_default, re->metric, + re->mtu, + zebra_import_table_distance[afi] + [re->table]); + } else if (re->nexthop_num > 1) { + newre = XCALLOC(MTYPE_RE, + sizeof(struct route_entry)); + newre->type = ZEBRA_ROUTE_TABLE; + newre->distance = + zebra_import_table_distance[afi][re->table]; + newre->flags = re->flags; + newre->metric = re->metric; + newre->mtu = re->mtu; + newre->table = zebrad.rtm_table_default; + newre->nexthop_num = 0; + newre->uptime = time(NULL); + newre->instance = re->table; + route_entry_copy_nexthops(newre, re->nexthop); + + rib_add_multipath(afi, SAFI_UNICAST, &p, + NULL, newre); } - /* DD: Add IPv6 code */ return 0; } int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re) { struct prefix p; + afi_t afi; - if (rn->p.family == AF_INET) { - p.family = AF_INET; - p.prefixlen = rn->p.prefixlen; - p.u.prefix4 = rn->p.u.prefix4; + afi = family2afi(rn->p.family); + prefix_copy(&p, &rn->p); - rib_delete(AFI_IP, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, - re->table, re->flags, &p, NULL, NULL, 0, - zebrad.rtm_table_default, re->metric); - } - /* DD: Add IPv6 code */ + rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, + re->table, re->flags, &p, NULL, NULL, + zebrad.rtm_table_default, re->metric); return 0; } @@ -673,28 +649,27 @@ int zebra_import_table_config(struct vty *vty) for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (i = 1; i < ZEBRA_KERNEL_TABLE_MAX; i++) { - if (is_zebra_import_table_enabled(afi, i)) { - if (zebra_import_table_distance[afi][i] - != ZEBRA_TABLE_DISTANCE_DEFAULT) { - vty_out(vty, - "%s import-table %d distance %d", - afi_str[afi], i, - zebra_import_table_distance[afi] - [i]); - } else { - vty_out(vty, "%s import-table %d", - afi_str[afi], i); - } - - rmap_name = zebra_get_import_table_route_map( - afi, i); - if (rmap_name) - vty_out(vty, " route-map %s", - rmap_name); + if (!is_zebra_import_table_enabled(afi, i)) + continue; - vty_out(vty, "\n"); - write = 1; + if (zebra_import_table_distance[afi][i] + != ZEBRA_TABLE_DISTANCE_DEFAULT) { + vty_out(vty, + "%s import-table %d distance %d", + afi_str[afi], i, + zebra_import_table_distance[afi][i]); + } else { + vty_out(vty, "%s import-table %d", + afi_str[afi], i); } + + rmap_name = zebra_get_import_table_route_map(afi, i); + if (rmap_name) + vty_out(vty, " route-map %s", + rmap_name); + + vty_out(vty, "\n"); + write = 1; } } @@ -712,42 +687,43 @@ void zebra_import_table_rm_update() for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (i = 1; i < ZEBRA_KERNEL_TABLE_MAX; i++) { - if (is_zebra_import_table_enabled(afi, i)) { - rmap_name = zebra_get_import_table_route_map( - afi, i); - if (!rmap_name) - return; - - table = zebra_vrf_other_route_table( - afi, i, VRF_DEFAULT); - for (rn = route_top(table); rn; - rn = route_next(rn)) { - /* For each entry in the non-default - * routing table, - * add the entry in the main table - */ - if (!rn->info) - continue; + if (!is_zebra_import_table_enabled(afi, i)) + continue; - RNODE_FOREACH_RE(rn, re) - { - if (CHECK_FLAG( - re->status, - ROUTE_ENTRY_REMOVED)) - continue; - break; - } + rmap_name = zebra_get_import_table_route_map(afi, i); + if (!rmap_name) + return; + + table = zebra_vrf_other_route_table(afi, + i, + VRF_DEFAULT); + for (rn = route_top(table); rn; + rn = route_next(rn)) { + /* For each entry in the non-default + * routing table, + * add the entry in the main table + */ + if (!rn->info) + continue; - if (!re) + RNODE_FOREACH_RE(rn, re) + { + if (CHECK_FLAG( + re->status, + ROUTE_ENTRY_REMOVED)) continue; - - if (((afi == AFI_IP) - && (rn->p.family == AF_INET)) - || ((afi == AFI_IP6) - && (rn->p.family == AF_INET6))) - zebra_add_import_table_entry( - rn, re, rmap_name); + break; } + + if (!re) + continue; + + if (((afi == AFI_IP) + && (rn->p.family == AF_INET)) + || ((afi == AFI_IP6) + && (rn->p.family == AF_INET6))) + zebra_add_import_table_entry( + rn, re, rmap_name); } } } diff --git a/zebra/redistribute.h b/zebra/redistribute.h index 819b67918b..5edb06c3da 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -72,6 +72,4 @@ extern int zebra_import_table_config(struct vty *); extern void zebra_import_table_rm_update(void); -extern int is_default(struct prefix *); - #endif /* _ZEBRA_REDISTRIBUTE_H */ diff --git a/zebra/rib.h b/zebra/rib.h index 495b731e88..4cc69377d8 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -45,9 +45,6 @@ struct route_entry { /* Nexthop structure */ struct nexthop *nexthop; - /* Refrence count. */ - unsigned long refcnt; - /* Tag */ route_tag_t tag; @@ -231,7 +228,8 @@ typedef enum { extern struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *, ifindex_t); -extern struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *); +extern struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *, + enum blackhole_type); extern struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *, struct in_addr *, struct in_addr *); @@ -294,18 +292,17 @@ extern int rib_uninstall_kernel(struct route_node *rn, struct route_entry *re); * also implicitly withdraw equal prefix of same type. */ extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, int flags, struct prefix *p, - struct prefix_ipv6 *src_p, union g_addr *gate, - union g_addr *src, ifindex_t ifindex, u_int32_t table_id, - u_int32_t metric, u_int32_t mtu, u_char distance); + struct prefix_ipv6 *src_p, const struct nexthop *nh, + u_int32_t table_id, u_int32_t metric, u_int32_t mtu, + u_char distance); extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *, struct prefix_ipv6 *src_p, struct route_entry *); extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, int flags, struct prefix *p, - struct prefix_ipv6 *src_p, union g_addr *gate, - ifindex_t ifindex, u_int32_t table_id, - u_int32_t metric); + struct prefix_ipv6 *src_p, const struct nexthop *nh, + u_int32_t table_id, u_int32_t metric); extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t, union g_addr *, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index e28fe5630a..f05025e630 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -240,13 +240,27 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl, void *gate = NULL; void *prefsrc = NULL; /* IPv4 preferred source host address */ void *src = NULL; /* IPv6 srcdest source prefix */ + enum blackhole_type bh_type = BLACKHOLE_UNSPEC; rtm = NLMSG_DATA(h); if (startup && h->nlmsg_type != RTM_NEWROUTE) return 0; - if (startup && rtm->rtm_type != RTN_UNICAST) + switch (rtm->rtm_type) { + case RTN_UNICAST: + break; + case RTN_BLACKHOLE: + bh_type = BLACKHOLE_NULL; + break; + case RTN_UNREACHABLE: + bh_type = BLACKHOLE_REJECT; + break; + case RTN_PROHIBIT: + bh_type = BLACKHOLE_ADMINPROHIB; + break; + default: return 0; + } len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); if (len < 0) @@ -365,11 +379,39 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl, afi = AFI_IP6; if (h->nlmsg_type == RTM_NEWROUTE) { - if (!tb[RTA_MULTIPATH]) + if (!tb[RTA_MULTIPATH]) { + struct nexthop nh; + size_t sz = (afi == AFI_IP) ? 4 : 16; + + memset(&nh, 0, sizeof(nh)); + + if (bh_type == BLACKHOLE_UNSPEC) { + if (index && !gate) + nh.type = NEXTHOP_TYPE_IFINDEX; + else if (index && gate) + nh.type = (afi == AFI_IP) + ? NEXTHOP_TYPE_IPV4_IFINDEX + : NEXTHOP_TYPE_IPV6_IFINDEX; + else if (!index && gate) + nh.type = (afi == AFI_IP) + ? NEXTHOP_TYPE_IPV4 + : NEXTHOP_TYPE_IPV6; + else { + nh.type = NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = bh_type; + } + } else { + nh.type = NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = bh_type; + } + nh.ifindex = index; + if (prefsrc) + memcpy(&nh.src, prefsrc, sz); + if (gate) + memcpy(&nh.gate, gate, sz); rib_add(afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, - 0, flags, &p, NULL, gate, prefsrc, index, table, - metric, mtu, 0); - else { + 0, flags, &p, NULL, &nh, table, metric, mtu, 0); + } else { /* This is a multipath route */ struct route_entry *re; @@ -444,41 +486,43 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl, NULL, re); } } else { - if (!tb[RTA_MULTIPATH]) - rib_delete(afi, SAFI_UNICAST, vrf_id, - ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, gate, - index, table, metric); - else { - struct rtnexthop *rtnh = - (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); - - len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); - - for (;;) { - if (len < (int)sizeof(*rtnh) - || rtnh->rtnh_len > len) - break; - - gate = NULL; - if (rtnh->rtnh_len > sizeof(*rtnh)) { - memset(tb, 0, sizeof(tb)); - netlink_parse_rtattr( - tb, RTA_MAX, RTNH_DATA(rtnh), - rtnh->rtnh_len - sizeof(*rtnh)); - if (tb[RTA_GATEWAY]) - gate = RTA_DATA( - tb[RTA_GATEWAY]); + if (!tb[RTA_MULTIPATH]) { + struct nexthop nh; + size_t sz = (afi == AFI_IP) ? 4 : 16; + + memset(&nh, 0, sizeof(nh)); + if (bh_type == BLACKHOLE_UNSPEC) { + if (index && !gate) + nh.type = NEXTHOP_TYPE_IFINDEX; + else if (index && gate) + nh.type = + (afi == AFI_IP) + ? NEXTHOP_TYPE_IPV4_IFINDEX + : NEXTHOP_TYPE_IPV6_IFINDEX; + else if (!index && gate) + nh.type = (afi == AFI_IP) + ? NEXTHOP_TYPE_IPV4 + : NEXTHOP_TYPE_IPV6; + else { + nh.type = NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = BLACKHOLE_UNSPEC; } - - if (gate) - rib_delete(afi, SAFI_UNICAST, vrf_id, - ZEBRA_ROUTE_KERNEL, 0, flags, - &p, NULL, gate, index, - table, metric); - - len -= NLMSG_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); + } else { + nh.type = NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = bh_type; } + nh.ifindex = index; + if (gate) + memcpy(&nh.gate, gate, sz); + rib_delete(afi, SAFI_UNICAST, vrf_id, + ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, &nh, + table, metric); + } else { + /* XXX: need to compare the entire list of nexthops + * here for NLM_F_APPEND stupidity */ + rib_delete(afi, SAFI_UNICAST, vrf_id, + ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, NULL, + table, metric); } } @@ -558,8 +602,8 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl, if (IS_ZEBRA_DEBUG_KERNEL) { struct interface *ifp; - strcpy(sbuf, inet_ntoa(m->sg.src)); - strcpy(gbuf, inet_ntoa(m->sg.grp)); + strlcpy(sbuf, inet_ntoa(m->sg.src), sizeof(sbuf)); + strlcpy(gbuf, inet_ntoa(m->sg.grp), sizeof(gbuf)); for (count = 0; count < oif_count; count++) { ifp = if_lookup_by_index(oif[count], vrf); char temp[256]; @@ -609,18 +653,10 @@ int netlink_route_change(struct sockaddr_nl *snl, struct nlmsghdr *h, if (len < 0) return -1; - switch (rtm->rtm_type) { - case RTN_UNICAST: - netlink_route_change_read_unicast(snl, h, ns_id, startup); - break; - case RTN_MULTICAST: + if (rtm->rtm_type == RTN_MULTICAST) netlink_route_change_read_multicast(snl, h, ns_id, startup); - break; - default: - return 0; - break; - } - + else + netlink_route_change_read_unicast(snl, h, ns_id, startup); return 0; } @@ -1207,7 +1243,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p, struct sockaddr_nl snl; struct nexthop *nexthop = NULL; unsigned int nexthop_num; - int discard; + int discard = 0; int family = PREFIX_FAMILY(p); const char *routedesc; int setsrc = 0; @@ -1238,24 +1274,23 @@ static int netlink_route_multipath(int cmd, struct prefix *p, req.r.rtm_src_len = src_p ? src_p->prefixlen : 0; req.r.rtm_protocol = get_rt_proto(re->type); req.r.rtm_scope = RT_SCOPE_UNIVERSE; + req.r.rtm_type = RTN_UNICAST; - if ((re->flags & ZEBRA_FLAG_BLACKHOLE) - || (re->flags & ZEBRA_FLAG_REJECT)) + if (re->nexthop_num == 1 + && re->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { discard = 1; - else - discard = 0; - - if (cmd == RTM_NEWROUTE) { - if (discard) { - if (re->flags & ZEBRA_FLAG_BLACKHOLE) - req.r.rtm_type = RTN_BLACKHOLE; - else if (re->flags & ZEBRA_FLAG_REJECT) - req.r.rtm_type = RTN_UNREACHABLE; - else - assert(RTN_BLACKHOLE - != RTN_UNREACHABLE); /* false */ - } else - req.r.rtm_type = RTN_UNICAST; + + switch (re->nexthop->bh_type) { + case BLACKHOLE_ADMINPROHIB: + req.r.rtm_type = RTN_PROHIBIT; + break; + case BLACKHOLE_REJECT: + req.r.rtm_type = RTN_UNREACHABLE; + break; + default: + req.r.rtm_type = RTN_BLACKHOLE; + break; + } } addattr_l(&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); @@ -1280,6 +1315,9 @@ static int netlink_route_multipath(int cmd, struct prefix *p, addattr32(&req.n, sizeof req, RTA_TABLE, re->table); } + if (discard) + goto skip; + if (re->mtu || re->nexthop_mtu) { char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *)buf; @@ -1293,21 +1331,6 @@ static int netlink_route_multipath(int cmd, struct prefix *p, RTA_PAYLOAD(rta)); } - if (discard) { - if (cmd == RTM_NEWROUTE) - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { - /* We shouldn't encounter recursive nexthops on - * discard routes, - * but it is probably better to handle that case - * correctly anyway. - */ - if (CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_RECURSIVE)) - continue; - } - goto skip; - } - /* Count overall nexthops so we can decide whether to use singlepath * or multipath case. */ nexthop_num = 0; @@ -1553,6 +1576,8 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) int kernel_route_rib(struct prefix *p, struct prefix *src_p, struct route_entry *old, struct route_entry *new) { + assert(old || new); + if (!old && new) return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 0); if (old && !new) @@ -2005,7 +2030,8 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h, * itself */ if (IS_ZEBRA_IF_VLAN(ifp)) { - link_if = zif->link; + link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + zif->link_ifindex); if (!link_if) return 0; } else if (IS_ZEBRA_IF_BRIDGE(ifp)) diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 32ae41b917..d8e37a10c3 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -42,11 +42,6 @@ extern struct zebra_privs_t zserv_privs; -/* kernel socket export */ -extern int rtm_write(int message, union sockunion *dest, union sockunion *mask, - union sockunion *gate, union sockunion *mpls, - unsigned int index, int zebra_flags, int metric); - #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN /* Adjust netmask socket length. Return value is a adjusted sin_len value. */ @@ -108,6 +103,7 @@ static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re) int gate = 0; int error; char prefix_buf[PREFIX_STRLEN]; + enum blackhole_type bh_type = BLACKHOLE_UNSPEC; if (IS_ZEBRA_DEBUG_RIB) prefix2str(p, prefix_buf, sizeof(prefix_buf)); @@ -155,6 +151,7 @@ static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re) struct in_addr loopback; loopback.s_addr = htonl(INADDR_LOOPBACK); sin_gate.sin_addr = loopback; + bh_type = nexthop->bh_type; gate = 1; } @@ -178,11 +175,11 @@ static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re) smplsp = (union sockunion *)&smpls; #endif - error = rtm_write( - cmd, (union sockunion *)&sin_dest, - (union sockunion *)mask, - gate ? (union sockunion *)&sin_gate : NULL, - smplsp, ifindex, re->flags, re->metric); + error = rtm_write(cmd, (union sockunion *)&sin_dest, + (union sockunion *)mask, + gate ? (union sockunion *)&sin_gate + : NULL, + smplsp, ifindex, bh_type, re->metric); if (IS_ZEBRA_DEBUG_RIB) { if (!gate) { @@ -292,6 +289,7 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re) ifindex_t ifindex = 0; int gate = 0; int error; + enum blackhole_type bh_type = BLACKHOLE_UNSPEC; memset(&sin_dest, 0, sizeof(struct sockaddr_in6)); sin_dest.sin6_family = AF_INET6; @@ -331,6 +329,9 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re) || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) ifindex = nexthop->ifindex; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) + bh_type = nexthop->bh_type; + if (cmd == RTM_ADD) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } @@ -369,7 +370,7 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re) error = rtm_write(cmd, (union sockunion *)&sin_dest, (union sockunion *)mask, gate ? (union sockunion *)&sin_gate : NULL, - smplsp, ifindex, re->flags, re->metric); + smplsp, ifindex, bh_type, re->metric); #if 0 if (error) diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 2182d6618c..88836af72e 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -107,6 +107,7 @@ static int rtadv_recv_packet(struct zebra_ns *zns, int sock, u_char *buf, char adata[1024]; /* Fill in message and iovec. */ + memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)from; msg.msg_namelen = sizeof(struct sockaddr_in6); msg.msg_iov = &iov; @@ -629,7 +630,6 @@ static int rtadv_make_socket(void) safe_strerror(errno)); if (sock < 0) { - close(sock); return -1; } diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 1bba003a0a..62f3224b6e 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -75,8 +75,8 @@ static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry) { struct prefix prefix; - struct in_addr tmpaddr, gateway; - union g_addr *ggateway; + struct in_addr tmpaddr; + struct nexthop nh; u_char zebra_flags = 0; if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE) @@ -93,11 +93,12 @@ static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry) tmpaddr.s_addr = routeEntry->ipRouteMask; prefix.prefixlen = ip_masklen(tmpaddr); - gateway.s_addr = routeEntry->ipRouteNextHop; - ggateway = (union g_addr *)&gateway; + memset(&nh, 0, sizeof(nh)); + nh.type = NEXTHOP_TYPE_IPV4; + nh.gate.ipv4.s_addr = routeEntry->ipRouteNextHop; rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, - zebra_flags, &prefix, NULL, ggateway, NULL, 0, 0, 0, 0, 0); + zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0); } void route_read(struct zebra_ns *zns) diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 28f7956639..27c7891372 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -222,7 +222,6 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, rib_dest_t *dest, struct route_entry *re) { struct nexthop *nexthop; - int discard; memset(ri, 0, sizeof(*ri)); @@ -247,30 +246,9 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, } ri->rtm_protocol = netlink_proto_from_route_type(re->type); - - if ((re->flags & ZEBRA_FLAG_BLACKHOLE) - || (re->flags & ZEBRA_FLAG_REJECT)) - discard = 1; - else - discard = 0; - - if (cmd == RTM_NEWROUTE) { - if (discard) { - if (re->flags & ZEBRA_FLAG_BLACKHOLE) - ri->rtm_type = RTN_BLACKHOLE; - else if (re->flags & ZEBRA_FLAG_REJECT) - ri->rtm_type = RTN_UNREACHABLE; - else - assert(0); - } else - ri->rtm_type = RTN_UNICAST; - } - + ri->rtm_type = RTN_UNICAST; ri->metric = &re->metric; - if (discard) - return 1; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { if (ri->num_nhs >= multipath_num) break; @@ -278,6 +256,22 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { + switch (nexthop->bh_type) { + case BLACKHOLE_ADMINPROHIB: + ri->rtm_type = RTN_PROHIBIT; + break; + case BLACKHOLE_REJECT: + ri->rtm_type = RTN_UNREACHABLE; + break; + case BLACKHOLE_NULL: + default: + ri->rtm_type = RTN_BLACKHOLE; + break; + } + return 1; + } + if ((cmd == RTM_NEWROUTE && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c index 450ad5b0bf..b850f1fb1e 100644 --- a/zebra/zebra_fpm_protobuf.c +++ b/zebra/zebra_fpm_protobuf.c @@ -141,7 +141,6 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator, struct route_entry *re) { Fpm__AddRoute *msg; - int discard; struct nexthop *nexthop; uint num_nhs, u; struct nexthop *nexthops[MULTIPATH_NUM]; @@ -164,26 +163,7 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator, msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST; msg->key = fpm_route_key_create(allocator, rib_dest_prefix(dest)); qpb_protocol_set(&msg->protocol, re->type); - - if ((re->flags & ZEBRA_FLAG_BLACKHOLE) - || (re->flags & ZEBRA_FLAG_REJECT)) - discard = 1; - else - discard = 0; - - if (discard) { - if (re->flags & ZEBRA_FLAG_BLACKHOLE) { - msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE; - } else if (re->flags & ZEBRA_FLAG_REJECT) { - msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE; - } else { - assert(0); - } - return msg; - } else { - msg->route_type = FPM__ROUTE_TYPE__NORMAL; - } - + msg->route_type = FPM__ROUTE_TYPE__NORMAL; msg->metric = re->metric; /* @@ -197,6 +177,19 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator, if (num_nhs >= ZEBRA_NUM_OF(nexthops)) break; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE; + break; + case BLACKHOLE_NULL: + default: + msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE; + break; + } + return msg; + } + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 5d059a4502..3d505857c2 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -224,12 +224,19 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp, zif->brslave_info.bridge_ifindex = bridge_ifindex; /* Set up or remove link with master */ - if (bridge_ifindex != IFINDEX_INTERNAL) + if (bridge_ifindex != IFINDEX_INTERNAL) { zebra_l2_map_slave_to_bridge(&zif->brslave_info); - else if (old_bridge_ifindex != IFINDEX_INTERNAL) + /* In the case of VxLAN, invoke the handler for EVPN. */ + if (zif->zif_type == ZEBRA_IF_VXLAN) + zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE); + } else if (old_bridge_ifindex != IFINDEX_INTERNAL) { + /* + * In the case of VxLAN, invoke the handler for EVPN. + * Note that this should be done *prior* + * to unmapping the interface from the bridge. + */ + if (zif->zif_type == ZEBRA_IF_VXLAN) + zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE); zebra_l2_unmap_slave_from_bridge(&zif->brslave_info); - - /* In the case of VxLAN, invoke the handler for EVPN. */ - if (zif->zif_type == ZEBRA_IF_VXLAN) - zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE); + } } diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index cee3a03858..3c4de40db3 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -840,7 +840,7 @@ static void lsp_schedule(struct hash_backet *backet, void *ctxt) zebra_lsp_t *lsp; lsp = (zebra_lsp_t *)backet->data; - lsp_processq_add(lsp); + (void)lsp_processq_add(lsp); } /* @@ -2718,10 +2718,10 @@ int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf) for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) { for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next) { - char buf[INET6_ADDRSTRLEN]; + char buf[BUFSIZ]; char lstr[30]; - snhlfe2str(snhlfe, buf, BUFSIZ); + snhlfe2str(snhlfe, buf, sizeof(buf)); switch (snhlfe->out_label) { case MPLS_V4_EXP_NULL_LABEL: case MPLS_V6_EXP_NULL_LABEL: diff --git a/zebra/zebra_mroute.c b/zebra/zebra_mroute.c index c4d674df23..75d5d5d627 100644 --- a/zebra/zebra_mroute.c +++ b/zebra/zebra_mroute.c @@ -48,8 +48,8 @@ int zebra_ipmr_route_stats(struct zserv *client, int fd, u_short length, char sbuf[40]; char gbuf[40]; - strcpy(sbuf, inet_ntoa(mroute.sg.src)); - strcpy(gbuf, inet_ntoa(mroute.sg.grp)); + strlcpy(sbuf, inet_ntoa(mroute.sg.src), sizeof(sbuf)); + strlcpy(gbuf, inet_ntoa(mroute.sg.grp), sizeof(gbuf)); zlog_debug("Asking for (%s,%s) mroute information", sbuf, gbuf); } diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 1bf672d4a1..b18b3e7429 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -156,7 +156,7 @@ void zebra_ptm_finish(void) if (ptm_cb.wb) buffer_free(ptm_cb.wb); - if (ptm_cb.ptm_sock != -1) + if (ptm_cb.ptm_sock >= 0) close(ptm_cb.ptm_sock); } diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index 0b6263fac5..ce9f19c3cc 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -328,6 +328,7 @@ DEFUN_NOSH (pseudowire_if, if (!pw) return CMD_SUCCESS; zebra_pw_del(zvrf, pw); + return CMD_SUCCESS; } if (!pw) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index dc61ea5e40..deb434bd35 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -291,13 +291,14 @@ struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re, return nexthop; } -struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *re) +struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *re, + enum blackhole_type bh_type) { struct nexthop *nexthop; nexthop = nexthop_new(); nexthop->type = NEXTHOP_TYPE_BLACKHOLE; - SET_FLAG(re->flags, ZEBRA_FLAG_BLACKHOLE); + nexthop->bh_type = bh_type; route_entry_nexthop_add(re, nexthop); @@ -471,12 +472,6 @@ static int nexthop_active(afi_t afi, struct route_entry *re, continue; } - /* If the longest prefix match for the nexthop yields - * a blackhole, mark it as inactive. */ - if (CHECK_FLAG(match->flags, ZEBRA_FLAG_BLACKHOLE) - || CHECK_FLAG(match->flags, ZEBRA_FLAG_REJECT)) - return 0; - if (match->type == ZEBRA_ROUTE_CONNECT) { /* Directly point connected route. */ newhop = match->nexthop; @@ -488,41 +483,46 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return 1; } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_INTERNAL)) { resolved = 0; - for (ALL_NEXTHOPS(match->nexthop, newhop)) - if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_FIB) - && !CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_RECURSIVE)) { - if (set) { - SET_FLAG( - nexthop->flags, - NEXTHOP_FLAG_RECURSIVE); - SET_FLAG( - re->status, - ROUTE_ENTRY_NEXTHOPS_CHANGED); - - nexthop_set_resolved( - afi, newhop, nexthop); - } - resolved = 1; + for (ALL_NEXTHOPS(match->nexthop, newhop)) { + if (newhop->type == NEXTHOP_TYPE_BLACKHOLE) + continue; + if (!CHECK_FLAG(newhop->flags, + NEXTHOP_FLAG_FIB)) + continue; + if (CHECK_FLAG(newhop->flags, + NEXTHOP_FLAG_RECURSIVE)) + continue; + + if (set) { + SET_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE); + SET_FLAG(re->status, + ROUTE_ENTRY_NEXTHOPS_CHANGED); + nexthop_set_resolved(afi, newhop, + nexthop); } + resolved = 1; + } if (resolved && set) re->nexthop_mtu = match->mtu; return resolved; } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; - for (ALL_NEXTHOPS(match->nexthop, newhop)) - if (CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_FIB)) { - if (set) { - SET_FLAG( - nexthop->flags, - NEXTHOP_FLAG_RECURSIVE); + for (ALL_NEXTHOPS(match->nexthop, newhop)) { + if (newhop->type == NEXTHOP_TYPE_BLACKHOLE) + continue; + if (!CHECK_FLAG(newhop->flags, + NEXTHOP_FLAG_FIB)) + continue; - nexthop_set_resolved( - afi, newhop, nexthop); - } - resolved = 1; + if (set) { + SET_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE); + nexthop_set_resolved(afi, newhop, + nexthop); } + resolved = 1; + } if (resolved && set) re->nexthop_mtu = match->mtu; return resolved; @@ -2061,10 +2061,9 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, is_srcdst ? prefix2str(src_pp, srcaddr, sizeof(srcaddr)) : "", re->vrf_id); - zlog_debug( - "%s: refcnt == %lu, uptime == %lu, type == %u, instance == %d, table == %d", - func, re->refcnt, (unsigned long)re->uptime, re->type, - re->instance, re->table); + zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d", + func, (unsigned long)re->uptime, re->type, re->instance, + re->table); zlog_debug( "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", func, re->metric, re->mtu, re->distance, re->flags, re->status); @@ -2273,16 +2272,15 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, int flags, struct prefix *p, - struct prefix_ipv6 *src_p, union g_addr *gate, - ifindex_t ifindex, u_int32_t table_id, - u_int32_t metric) + struct prefix_ipv6 *src_p, const struct nexthop *nh, + u_int32_t table_id, u_int32_t metric) { struct route_table *table; struct route_node *rn; struct route_entry *re; struct route_entry *fib = NULL; struct route_entry *same = NULL; - struct nexthop *nexthop; + struct nexthop *rtnh; char buf2[INET6_ADDRSTRLEN]; assert(!src_p || afi == AFI_IP6); @@ -2332,29 +2330,21 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric) continue; - if (re->type == ZEBRA_ROUTE_CONNECT && (nexthop = re->nexthop) - && nexthop->type == NEXTHOP_TYPE_IFINDEX) { - if (nexthop->ifindex != ifindex) + if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->nexthop) + && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { + if (rtnh->ifindex != nh->ifindex) continue; - if (re->refcnt) { - re->refcnt--; - route_unlock_node(rn); - route_unlock_node(rn); - return; - } same = re; break; } /* Make sure that the route found has the same gateway. */ else { - if (gate == NULL) { + if (nh == NULL) { same = re; break; } - for (ALL_NEXTHOPS(re->nexthop, nexthop)) - if (IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4) - || IPV6_ADDR_SAME(&nexthop->gate.ipv6, - gate)) { + for (ALL_NEXTHOPS(re->nexthop, rtnh)) + if (nexthop_same_no_recurse(rtnh, nh)) { same = re; break; } @@ -2375,9 +2365,9 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, } if (allow_delete) { /* Unset flags. */ - for (nexthop = fib->nexthop; nexthop; - nexthop = nexthop->next) - UNSET_FLAG(nexthop->flags, + for (rtnh = fib->nexthop; rtnh; + rtnh = rtnh->next) + UNSET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB); UNSET_FLAG(fib->status, @@ -2391,22 +2381,22 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, } } else { if (IS_ZEBRA_DEBUG_RIB) { - if (gate) + if (nh) rnode_debug( rn, vrf_id, "via %s ifindex %d type %d " "doesn't exist in rib", inet_ntop( - family2afi(afi), gate, - buf2, + family2afi(afi), + &nh->gate, buf2, INET_ADDRSTRLEN), /* FIXME */ - ifindex, type); + nh->ifindex, type); else rnode_debug( rn, vrf_id, - "ifindex %d type %d doesn't exist in rib", - ifindex, type); + "type %d doesn't exist in rib", + type); } route_unlock_node(rn); return; @@ -2423,15 +2413,14 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, - union g_addr *gate, union g_addr *src, ifindex_t ifindex, - u_int32_t table_id, u_int32_t metric, u_int32_t mtu, - u_char distance) + const struct nexthop *nh, u_int32_t table_id, u_int32_t metric, + u_int32_t mtu, u_char distance) { struct route_entry *re; struct route_entry *same = NULL; struct route_table *table; struct route_node *rn; - struct nexthop *nexthop; + struct nexthop *rtnh; assert(!src_p || afi == AFI_IP6); @@ -2480,13 +2469,16 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, break; } /* Duplicate system route comes in. */ - else if ((nexthop = re->nexthop) - && nexthop->type == NEXTHOP_TYPE_IFINDEX - && nexthop->ifindex == ifindex - && !CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) { - re->refcnt++; + rtnh = re->nexthop; + if (nexthop_same_no_recurse(rtnh, nh)) return 0; - } + /* + * Nexthop is different. Remove the old route unless it's + * a link-local route. + */ + else if (afi != AFI_IP6 + || !IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) + same = re; } /* Allocate new re structure. */ @@ -2503,29 +2495,14 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, re->nexthop_num = 0; re->uptime = time(NULL); - /* Nexthop settings. */ - if (gate) { - if (afi == AFI_IP6) { - if (ifindex) - route_entry_nexthop_ipv6_ifindex_add( - re, &gate->ipv6, ifindex); - else - route_entry_nexthop_ipv6_add(re, &gate->ipv6); - } else { - if (ifindex) - route_entry_nexthop_ipv4_ifindex_add( - re, &gate->ipv4, &src->ipv4, ifindex); - else - route_entry_nexthop_ipv4_add(re, &gate->ipv4, - &src->ipv4); - } - } else - route_entry_nexthop_ifindex_add(re, ifindex); + rtnh = nexthop_new(); + *rtnh = *nh; + route_entry_nexthop_add(re, rtnh); /* If this route is kernel route, set FIB flag to the route. */ if (RIB_SYSTEM_ROUTE(re)) - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + for (rtnh = re->nexthop; rtnh; rtnh = rtnh->next) + SET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB); /* Link new rib to node.*/ if (IS_ZEBRA_DEBUG_RIB) { @@ -2745,23 +2722,27 @@ unsigned long rib_score_proto(u_char proto, u_short instance) void rib_close_table(struct route_table *table) { struct route_node *rn; - rib_table_info_t *info = table->info; + rib_table_info_t *info; struct route_entry *re; - if (table) - for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) - RNODE_FOREACH_RE(rn, re) - { - if (!CHECK_FLAG(re->status, - ROUTE_ENTRY_SELECTED_FIB)) - continue; + if (!table) + return; - if (info->safi == SAFI_UNICAST) - hook_call(rib_update, rn, NULL); + info = table->info; - if (!RIB_SYSTEM_ROUTE(re)) - rib_uninstall_kernel(rn, re); - } + for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) + RNODE_FOREACH_RE(rn, re) + { + if (!CHECK_FLAG(re->status, + ROUTE_ENTRY_SELECTED_FIB)) + continue; + + if (info->safi == SAFI_UNICAST) + hook_call(rib_update, rn, NULL); + + if (!RIB_SYSTEM_ROUTE(re)) + rib_uninstall_kernel(rn, re); + } } /* Routing information base initialize. */ diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index c738cde0ac..0fa616bef9 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -62,23 +62,26 @@ static int zebra_route_match_add(struct vty *vty, const char *command, { VTY_DECLVAR_CONTEXT(route_map_index, index); int ret; + int retval = CMD_SUCCESS; ret = route_map_add_match(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% Zebra Can't find rule.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% Zebra Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% Zebra Can't find rule.\n"); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, "%% Zebra Argument is malformed.\n"); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + if (type != RMAP_EVENT_MATCH_ADDED) { + route_map_upd8_dependency(type, arg, index->map->name); } + break; } - if (type != RMAP_EVENT_MATCH_ADDED) { - route_map_upd8_dependency(type, arg, index->map->name); - } - return CMD_SUCCESS; + return retval; } /* Delete zebra route map rule. */ @@ -87,6 +90,7 @@ static int zebra_route_match_delete(struct vty *vty, const char *command, { VTY_DECLVAR_CONTEXT(route_map_index, index); int ret; + int retval = CMD_SUCCESS; char *dep_name = NULL; const char *tmpstr; char *rmap_name = NULL; @@ -105,26 +109,27 @@ static int zebra_route_match_delete(struct vty *vty, const char *command, } ret = route_map_delete_match(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% Zebra Can't find rule.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% Zebra Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; - } + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% Zebra Can't find rule.\n"); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, "%% Zebra Argument is malformed.\n"); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + if (type != RMAP_EVENT_MATCH_DELETED && dep_name) + route_map_upd8_dependency(type, dep_name, rmap_name); + break; } - if (type != RMAP_EVENT_MATCH_DELETED && dep_name) - route_map_upd8_dependency(type, dep_name, rmap_name); - if (dep_name) XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); if (rmap_name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); - return CMD_SUCCESS; + return retval; } /* 'match tag TAG' diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 6815916faf..ec6d406325 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -91,7 +91,8 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, si->ifindex); break; case STATIC_BLACKHOLE: - nexthop = route_entry_nexthop_blackhole_add(re); + nexthop = route_entry_nexthop_blackhole_add( + re, si->bh_type); break; case STATIC_IPV6_GATEWAY: nexthop = route_entry_nexthop_ipv6_add(re, @@ -166,7 +167,8 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, si->ifindex); break; case STATIC_BLACKHOLE: - nexthop = route_entry_nexthop_blackhole_add(re); + nexthop = route_entry_nexthop_blackhole_add( + re, si->bh_type); break; case STATIC_IPV6_GATEWAY: nexthop = route_entry_nexthop_ipv6_add(re, @@ -187,9 +189,6 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, si->snh_label.num_labels, &si->snh_label.label[0]); - /* Save the flags of this static routes (reject, blackhole) */ - re->flags = si->flags; - if (IS_ZEBRA_DEBUG_RIB) { char buf[INET6_ADDRSTRLEN]; if (IS_ZEBRA_DEBUG_RIB) { @@ -364,7 +363,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p, int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, - const char *ifname, u_char flags, + const char *ifname, enum blackhole_type bh_type, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label) { @@ -405,7 +404,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, if ((distance == si->distance) && (tag == si->tag) && !memcmp(&si->snh_label, snh_label, sizeof(struct static_nh_label)) - && si->flags == flags) { + && si->bh_type == bh_type) { route_unlock_node(rn); return 0; } else @@ -424,7 +423,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, si->type = type; si->distance = distance; - si->flags = flags; + si->bh_type = bh_type; si->tag = tag; si->vrf_id = zvrf_id(zvrf); if (ifname) diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h index ff9f0f59e7..458594a289 100644 --- a/zebra/zebra_static.h +++ b/zebra/zebra_static.h @@ -61,18 +61,12 @@ struct static_route { /* * Nexthop value. */ + enum blackhole_type bh_type; union g_addr addr; ifindex_t ifindex; char ifname[INTERFACE_NAMSIZ + 1]; - /* bit flags */ - u_char flags; - /* - see ZEBRA_FLAG_REJECT - ZEBRA_FLAG_BLACKHOLE - */ - /* Label information */ struct static_nh_label snh_label; }; @@ -86,7 +80,7 @@ extern void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p, extern int static_add_route(afi_t, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, - const char *ifname, u_char flags, + const char *ifname, enum blackhole_type bh_type, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label); diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index ff140bad67..0a26ac6ad7 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -470,7 +470,11 @@ static int vrf_config_write(struct vty *vty) RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { zvrf = vrf->info; - if (!zvrf || strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { + + if (!zvrf) + continue; + + if (strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); vty_out(vty, "!\n"); } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 9f887e8401..95ba19b1f6 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -74,7 +74,7 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, union g_addr gate; union g_addr *gatep = NULL; struct in_addr mask; - u_char flag = 0; + enum blackhole_type bh_type = 0; route_tag_t tag = 0; struct zebra_vrf *zvrf; u_char type; @@ -165,28 +165,18 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, } } - /* Null0 static route. */ - if ((ifname != NULL) - && (strncasecmp(ifname, "Null0", strlen(ifname)) == 0)) { - if (flag_str) { - vty_out(vty, "%% can not have flag %s with Null0\n", - flag_str); - return CMD_WARNING_CONFIG_FAILED; - } - SET_FLAG(flag, ZEBRA_FLAG_BLACKHOLE); - ifname = NULL; - } - /* Route flags */ if (flag_str) { switch (flag_str[0]) { case 'r': case 'R': /* XXX */ - SET_FLAG(flag, ZEBRA_FLAG_REJECT); + bh_type = BLACKHOLE_REJECT; break; + case 'n': + case 'N' /* XXX */: case 'b': case 'B': /* XXX */ - SET_FLAG(flag, ZEBRA_FLAG_BLACKHOLE); + bh_type = BLACKHOLE_NULL; break; default: vty_out(vty, "%% Malformed flag %s \n", flag_str); @@ -221,7 +211,7 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, if (!negate) static_add_route(afi, safi, type, &p, src_p, gatep, ifname, - flag, tag, distance, zvrf, &snh_label); + bh_type, tag, distance, zvrf, &snh_label); else static_delete_route(afi, safi, type, &p, src_p, gatep, ifname, tag, distance, zvrf, &snh_label); @@ -340,14 +330,12 @@ DEFUN (show_ip_rpf_addr, } /* Static route configuration. */ -DEFPY (ip_route, - ip_route_cmd, - "[no] ip route\ +DEFPY(ip_route, ip_route_cmd, + "[no] ip route\ <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask>\ <\ {A.B.C.D$gate|INTERFACE$ifname}\ - |null0$ifname\ - |<reject|blackhole>$flag\ + |<null0|reject|blackhole>$flag\ >\ [{\ tag (1-4294967295)\ @@ -355,22 +343,21 @@ DEFPY (ip_route, |vrf NAME\ |label WORD\ }]", - NO_STR - IP_STR - "Establish static routes\n" - "IP destination prefix (e.g. 10.0.0.0/8)\n" - "IP destination prefix\n" - "IP destination prefix mask\n" - "IP gateway address\n" - "IP gateway interface name\n" - "Null interface\n" - "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this route\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR + MPLS_LABEL_HELPSTR) { return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, NULL, gate_str, ifname, flag, @@ -415,12 +402,6 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, } if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) vty_out(vty, ", best"); - if (re->refcnt) - vty_out(vty, ", refcnt %ld", re->refcnt); - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out(vty, ", blackhole"); - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_REJECT)) - vty_out(vty, ", reject"); vty_out(vty, "\n"); if (re->type == ZEBRA_ROUTE_RIP || re->type == ZEBRA_ROUTE_OSPF @@ -485,7 +466,21 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, re->vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: - vty_out(vty, " directly connected, Null0"); + vty_out(vty, " unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + vty_out(vty, " (ICMP unreachable)"); + break; + case BLACKHOLE_ADMINPROHIB: + vty_out(vty, + " (ICMP admin-prohibited)"); + break; + case BLACKHOLE_NULL: + vty_out(vty, " (blackhole)"); + break; + case BLACKHOLE_UNSPEC: + break; + } break; default: break; @@ -580,12 +575,6 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_int_add(json_route, "metric", re->metric); } - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_BLACKHOLE)) - json_object_boolean_true_add(json_route, "blackhole"); - - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_REJECT)) - json_object_boolean_true_add(json_route, "reject"); - if (re->type == ZEBRA_ROUTE_RIP || re->type == ZEBRA_ROUTE_OSPF || re->type == ZEBRA_ROUTE_ISIS || re->type == ZEBRA_ROUTE_NHRP @@ -671,7 +660,24 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, break; case NEXTHOP_TYPE_BLACKHOLE: json_object_boolean_true_add(json_nexthop, - "blackhole"); + "unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + json_object_boolean_true_add( + json_nexthop, "reject"); + break; + case BLACKHOLE_ADMINPROHIB: + json_object_boolean_true_add( + json_nexthop, + "admin-prohibited"); + break; + case BLACKHOLE_NULL: + json_object_boolean_true_add( + json_nexthop, "blackhole"); + break; + case BLACKHOLE_UNSPEC: + break; + } break; default: break; @@ -796,7 +802,20 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, ifindex2ifname(nexthop->ifindex, re->vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: - vty_out(vty, " is directly connected, Null0"); + vty_out(vty, " unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + vty_out(vty, " (ICMP unreachable)"); + break; + case BLACKHOLE_ADMINPROHIB: + vty_out(vty, " (ICMP admin-prohibited)"); + break; + case BLACKHOLE_NULL: + vty_out(vty, " (blackhole)"); + break; + case BLACKHOLE_UNSPEC: + break; + } break; default: break; @@ -839,11 +858,6 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, sizeof buf, 1)); } - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out(vty, ", bh"); - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_REJECT)) - vty_out(vty, ", rej"); - if (re->type == ZEBRA_ROUTE_RIP || re->type == ZEBRA_ROUTE_OSPF || re->type == ZEBRA_ROUTE_ISIS || re->type == ZEBRA_ROUTE_NHRP @@ -1181,7 +1195,10 @@ DEFUN (show_ip_route, tag = strtoul(argv[idx + 1]->arg, NULL, 10); else if (argv_find(argv, argc, "A.B.C.D/M", &idx)) { - str2prefix(argv[idx]->arg, &p); + if (str2prefix(argv[idx]->arg, &p) <= 0) { + vty_out(vty, "%% Malformed prefix\n"); + return CMD_WARNING; + } longer_prefixes = true; } @@ -1693,12 +1710,15 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, case STATIC_IFNAME: vty_out(vty, " %s", si->ifname); break; - /* blackhole and Null0 mean the same thing */ case STATIC_BLACKHOLE: - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) + switch (si->bh_type) { + case BLACKHOLE_REJECT: vty_out(vty, " reject"); - else - vty_out(vty, " Null0"); + break; + default: + vty_out(vty, " blackhole"); + break; + } break; case STATIC_IPV4_GATEWAY_IFNAME: vty_out(vty, " %s %s", @@ -1716,19 +1736,6 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, break; } - /* flags are incompatible with STATIC_BLACKHOLE - */ - if (si->type != STATIC_BLACKHOLE) { - if (CHECK_FLAG(si->flags, - ZEBRA_FLAG_REJECT)) - vty_out(vty, " %s", "reject"); - - if (CHECK_FLAG(si->flags, - ZEBRA_FLAG_BLACKHOLE)) - vty_out(vty, " %s", - "blackhole"); - } - if (si->tag) vty_out(vty, " tag %" ROUTE_TAG_PRI, si->tag); @@ -1758,13 +1765,12 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, return write; } -DEFPY (ipv6_route, - ipv6_route_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M]\ +DEFPY(ipv6_route, + ipv6_route_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M]\ <\ {X:X::X:X$gate|INTERFACE$ifname}\ - |null0$ifname\ - |<reject|blackhole>$flag\ + |<null0|reject|blackhole>$flag\ >\ [{\ tag (1-4294967295)\ @@ -1772,22 +1778,22 @@ DEFPY (ipv6_route, |vrf NAME\ |label WORD\ }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" - "Null interface\n" - "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Null interface\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR + MPLS_LABEL_HELPSTR) { return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, from_str, gate_str, ifname, flag, @@ -1834,7 +1840,10 @@ DEFUN (show_ipv6_route, tag = strtoul(argv[idx + 1]->arg, NULL, 10); else if (argv_find(argv, argc, "X:X::X:X/M", &idx)) { - str2prefix(argv[idx]->arg, &p); + if (str2prefix(argv[idx]->arg, &p) <= 0) { + vty_out(vty, "%% Malformed prefix\n"); + return CMD_WARNING; + } longer_prefixes = true; } @@ -2572,6 +2581,8 @@ DEFUN (ip_zebra_import_table_distance, vty_out(vty, "Invalid routing table ID, %d. Must be in range 1-252\n", table_id); + if (rmap) + XFREE(MTYPE_ROUTE_MAP_NAME, rmap); return CMD_WARNING; } @@ -2579,6 +2590,8 @@ DEFUN (ip_zebra_import_table_distance, vty_out(vty, "Invalid routing table ID, %d. Must be non-default table\n", table_id); + if (rmap) + XFREE(MTYPE_ROUTE_MAP_NAME, rmap); return CMD_WARNING; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index f99c16ae91..a3f43f947a 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -204,13 +204,18 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) if (json == NULL) { vty_out(vty, " Remote VTEP: %s", inet_ntoa(n->r_vtep_ip)); - vty_out(vty, " State: %s", IS_ZEBRA_NEIGH_ACTIVE(n) - ? "Active" - : "Inactive"); } else json_object_string_add(json, "remoteVtep", inet_ntoa(n->r_vtep_ip)); } + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { + if (!json) { + vty_out(vty, "\n"); + vty_out(vty, " State: %s", + IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active" + : "Inactive"); + } + } if (json == NULL) vty_out(vty, "\n"); } @@ -384,8 +389,8 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt) } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { vty_out(vty, " Auto Mac "); } - vty_out(vty, " ARP ref: %u\n", mac->neigh_refcnt); + vty_out(vty, "\n"); /* print all the associated neigh */ vty_out(vty, " Neighbors:\n"); if (!listcount(mac->neigh_list)) @@ -1155,14 +1160,15 @@ static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n) if (!(n->flags & ZEBRA_NEIGH_REMOTE)) return 0; - zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); - assert(zvrf); if (!zvni->vxlan_if) { zlog_err("VNI %u hash %p couldn't be uninstalled - no intf", zvni->vni, zvni); return -1; } + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + assert(zvrf); + zif = zvni->vxlan_if->info; if (!zif) return -1; @@ -1343,8 +1349,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, zlog_err( "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)), - prefix_mac2str(macaddr, NULL, - ETHER_ADDR_STRLEN), + prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, ifp->ifindex, zvni->vni); return -1; } @@ -1355,14 +1360,11 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, memcpy(&n->emac, macaddr, ETH_ALEN); n->ifindex = ifp->ifindex; - /* We have a neigh associated to mac increment the refcnt*/ - mac->neigh_refcnt++; - if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s add to BGP", ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni, - prefix_mac2str(macaddr, NULL, ETHER_ADDR_STRLEN), + prefix_mac2str(macaddr, buf, sizeof(buf)), ipaddr2str(ip, buf2, sizeof(buf2))); zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, macaddr, @@ -1380,6 +1382,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, struct zebra_vrf *zvrf = NULL; zebra_neigh_t *n = NULL; zebra_mac_t *mac = NULL; + char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); @@ -1393,11 +1396,13 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, /* mac entry should be present */ mac = zvni_mac_lookup(zvni, &n->emac); - if (!mac) - zlog_err("%u: MAC %s doesnt exsists for neigh %s on VNI %u", + if (!mac) { + zlog_err("%u: MAC %s doesnt exists for neigh %s on VNI %u", ifp->vrf_id, - prefix_mac2str(&n->emac, NULL, ETHER_ADDR_STRLEN), + prefix_mac2str(&n->emac, buf1, sizeof(buf1)), ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni); + return -1; + } /* If the entry is not local nothing to do*/ if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) @@ -1407,7 +1412,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, zlog_debug( "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni, - prefix_mac2str(&(n->emac), NULL, ETHER_ADDR_STRLEN), + prefix_mac2str(&(n->emac), buf1, sizeof(buf1)), ipaddr2str(ip, buf2, sizeof(buf2))); /* Remove neighbor from BGP. */ @@ -1418,7 +1423,8 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, zvni_neigh_del(zvni, n); /* see if the mac needs to be deleted as well*/ - zvni_deref_ip2mac(zvni, mac, 0); + if (mac) + zvni_deref_ip2mac(zvni, mac, 0); return 0; } @@ -1431,13 +1437,22 @@ static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, struct zebra_l2info_vxlan zl2_info; struct interface *vlan_if = NULL; struct interface *vrr_if = NULL; + struct interface *ifp; /* Add primary SVI MAC*/ zvni = (zebra_vni_t *)backet->data; if (!zvni) return; - zif = zvni->vxlan_if->info; + ifp = zvni->vxlan_if; + if (!ifp) + return; + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return; + zl2_info = zif->l2info.vxl; vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan, @@ -1464,6 +1479,7 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, struct zebra_l2info_vxlan zl2_info; struct interface *vlan_if = NULL; struct interface *vrr_if = NULL; + struct interface *ifp = NULL; zvni = (zebra_vni_t *)backet->data; if (!zvni) @@ -1472,7 +1488,14 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, if (!advertise_gw_macip_enabled(zvrf, zvni)) return; - zif = zvni->vxlan_if->info; + ifp = zvni->vxlan_if; + if (!ifp) + return; + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return; zl2_info = zif->l2info.vxl; vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan, @@ -1758,6 +1781,9 @@ static zebra_vni_t *zvni_map_svi(struct interface *ifp, struct interface *br_if) vlanid_t vid = 0; zebra_vni_t *zvni; + if (!br_if) + return NULL; + /* Make sure the linked interface is a bridge. */ if (!IS_ZEBRA_IF_BRIDGE(br_if)) return NULL; @@ -1827,6 +1853,10 @@ static struct interface *zvni_map_to_svi(struct zebra_vrf *zvrf, vlanid_t vid, struct zebra_l2info_vlan *vl; u_char bridge_vlan_aware; + /* Defensive check, caller expected to invoke only with valid bridge. */ + if (!br_if) + return NULL; + /* Determine if bridge is VLAN-aware or not */ zif = br_if->info; assert(zif); @@ -1943,10 +1973,8 @@ static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt) static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac, int uninstall) { - if (mac->neigh_refcnt) - mac->neigh_refcnt--; - - if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) || mac->neigh_refcnt > 0) + if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) + || !list_isempty(mac->neigh_list)) return; if (uninstall) @@ -2853,7 +2881,7 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp, /* see if the AUTO mac needs to be deleted */ if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO) - || !listcount(zmac->neigh_list)) + && !listcount(zmac->neigh_list)) zvni_mac_del(zvni, zmac); return 0; @@ -2872,10 +2900,9 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, zebra_vni_t *zvni; zebra_neigh_t *n; struct zebra_vrf *zvrf; - zebra_mac_t *zmac; + zebra_mac_t *zmac, *old_zmac; char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; - int send_upd = 1, send_del = 0; /* We are only interested in neighbors on an SVI that resides on top * of a VxLAN bridge. @@ -2930,19 +2957,33 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, if (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0) { - if (n->ifindex == ifp->ifindex) - /* we're not interested in whatever has - * changed. */ - return 0; - /* client doesn't care about a purely local - * change. */ - send_upd = 0; - } else - /* If the MAC has changed, issue a delete first - * as this means a - * different MACIP route. + /* Update any params and return - client doesn't + * care about a purely local change. */ - send_del = 1; + n->ifindex = ifp->ifindex; + return 0; + } + + /* If the MAC has changed, + * need to issue a delete first + * as this means a different MACIP route. + * Also, need to do some unlinking/relinking. + */ + zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, + &n->emac, 0); + old_zmac = zvni_mac_lookup(zvni, &n->emac); + if (old_zmac) { + listnode_delete(old_zmac->neigh_list, n); + zvni_deref_ip2mac(zvni, old_zmac, 0); + } + + /* Set "local" forwarding info. */ + SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); + n->ifindex = ifp->ifindex; + memcpy(&n->emac, macaddr, ETH_ALEN); + + /* Link to new MAC */ + listnode_add_sort(zmac->neigh_list, n); } else if (ext_learned) /* The neighbor is remote and that is the notification we got. */ @@ -2954,6 +2995,8 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, { UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); n->r_vtep_ip.s_addr = 0; + SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); + n->ifindex = ifp->ifindex; } } else { n = zvni_neigh_add(zvni, ip, macaddr); @@ -2965,17 +3008,11 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, ifp->name, ifp->ifindex, zvni->vni); return -1; } + /* Set "local" forwarding info. */ + SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); + n->ifindex = ifp->ifindex; } - /* Issue delete for older info, if needed. */ - if (send_del) - zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, - 0); - - /* Set "local" forwarding info. */ - SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); - n->ifindex = ifp->ifindex; - /* Before we program this in BGP, we need to check if MAC is locally * learnt as well */ if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) { @@ -2989,23 +3026,18 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, return 0; } - /* Inform BGP if required. */ - if (send_upd) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "%u: neigh %s (MAC %s) is now ACTIVE on VNI %u", - ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)), - prefix_mac2str(macaddr, buf, sizeof(buf)), - zvni->vni); - - ZEBRA_NEIGH_SET_ACTIVE(n); - return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, - macaddr, 0); - } + /* Inform BGP. */ + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%u: neigh %s (MAC %s) is now ACTIVE on VNI %u", + ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)), + prefix_mac2str(macaddr, buf, sizeof(buf)), + zvni->vni); - return 0; + ZEBRA_NEIGH_SET_ACTIVE(n); + return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, macaddr, 0); } + /* * Handle message from client to delete a remote MACIP for a VNI. */ @@ -3023,6 +3055,8 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, u_short l = 0, ipa_len; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; + struct interface *ifp = NULL; + struct zebra_if *zif = NULL; s = client->ibuf; @@ -3065,12 +3099,18 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, zvrf_id(zvrf), vni); continue; } - if (!zvni->vxlan_if) { + ifp = zvni->vxlan_if; + if (!ifp) { zlog_err( "VNI %u hash %p doesn't have intf upon remote MACIP DEL", vni, zvni); continue; } + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + continue; /* The remote VTEP specified is normally expected to exist, but * it is @@ -3083,12 +3123,6 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, if (!zvni_vtep_find(zvni, &vtep_ip)) continue; - /* If the local VxLAN interface is not up (should be a transient - * event), there's nothing more to do. - */ - if (!if_is_operative(zvni->vxlan_if)) - continue; - mac = zvni_mac_lookup(zvni, &macaddr); if (ipa_len) n = zvni_neigh_lookup(zvni, &ip); @@ -3132,7 +3166,7 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, zvni_process_neigh_on_remote_mac_del(zvrf, zvni, mac); - if (!mac->neigh_refcnt) { + if (list_isempty(mac->neigh_list)) { zvni_mac_uninstall(zvni, mac, 0); zvni_mac_del(zvni, mac); } else @@ -3166,6 +3200,8 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; u_char sticky; + struct interface *ifp = NULL; + struct zebra_if *zif = NULL; assert(EVPN_ENABLED(zvrf)); @@ -3213,16 +3249,17 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, zvrf_id(zvrf), vni); continue; } - if (!zvni->vxlan_if) { + ifp = zvni->vxlan_if; + if (!ifp) { zlog_err( "VNI %u hash %p doesn't have intf upon remote MACIP add", vni, zvni); continue; } - /* If the local VxLAN interface is not up (should be a transient - * event), there's nothing more to do. - */ - if (!if_is_operative(zvni->vxlan_if)) + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) continue; /* The remote VTEP specified should normally exist, but it is @@ -3272,9 +3309,6 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, /* Is this MAC created for a MACIP? */ if (ipa_len) SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); - } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { - /* Moving from local to remote, issue delete. */ - zvni_mac_uninstall(zvni, mac, 1); } /* Set "auto" and "remote" forwarding info. */ @@ -3326,16 +3360,16 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, return -1; } - /* New neighbor referring to this MAC. */ - mac->neigh_refcnt++; } else if (memcmp(&n->emac, &macaddr, sizeof(macaddr)) != 0) { - /* MAC change, update ref counts for old and new - * MAC. */ + /* MAC change, update neigh list for old and new + * mac */ old_mac = zvni_mac_lookup(zvni, &n->emac); - if (old_mac) + if (old_mac) { + listnode_delete(old_mac->neigh_list, n); zvni_deref_ip2mac(zvni, old_mac, 1); - mac->neigh_refcnt++; + } + listnode_add_sort(mac->neigh_list, n); memcpy(&n->emac, &macaddr, ETH_ALEN); } @@ -3687,6 +3721,8 @@ int zebra_vxlan_remote_vtep_del(struct zserv *client, int sock, u_short length, struct in_addr vtep_ip; zebra_vni_t *zvni; zebra_vtep_t *zvtep; + struct interface *ifp; + struct zebra_if *zif; s = client->ibuf; @@ -3713,6 +3749,19 @@ int zebra_vxlan_remote_vtep_del(struct zserv *client, int sock, u_short length, continue; } + ifp = zvni->vxlan_if; + if (!ifp) { + zlog_err( + "VNI %u hash %p doesn't have intf upon remote VTEP DEL", + zvni->vni, zvni); + continue; + } + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + continue; + /* If the remote VTEP does not exist, there's nothing more to * do. * Otherwise, uninstall any remote MACs pointing to this VTEP @@ -3743,6 +3792,8 @@ int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock, u_short length, vni_t vni; struct in_addr vtep_ip; zebra_vni_t *zvni; + struct interface *ifp; + struct zebra_if *zif; assert(EVPN_ENABLED(zvrf)); @@ -3768,24 +3819,24 @@ int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock, u_short length, zvrf_id(zvrf), vni); continue; } - if (!zvni->vxlan_if) { + + ifp = zvni->vxlan_if; + if (!ifp) { zlog_err( "VNI %u hash %p doesn't have intf upon remote VTEP ADD", zvni->vni, zvni); continue; } + zif = ifp->info; - /* If the remote VTEP already exists, or the local VxLAN - * interface is - * not up (should be a transient event), there's nothing more - * to do. - * Otherwise, add and install the entry. - */ - if (zvni_vtep_find(zvni, &vtep_ip)) + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) continue; - if (!if_is_operative(zvni->vxlan_if)) + /* If the remote VTEP already exists, + there's nothing more to do. */ + if (zvni_vtep_find(zvni, &vtep_ip)) continue; if (zvni_vtep_add(zvni, &vtep_ip) == NULL) { @@ -3839,7 +3890,11 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, if (!ifp_zif) return -1; - svi_if = ifp_zif->link; + /* + * for a MACVLAN interface the link represents the svi_if + */ + svi_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + ifp_zif->link_ifindex); if (!svi_if) { zlog_err("%u:MACVLAN %s(%u) without link information", ifp->vrf_id, ifp->name, ifp->ifindex); @@ -3847,19 +3902,37 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, } if (IS_ZEBRA_IF_VLAN(svi_if)) { + /* + * If it is a vlan aware bridge then the link gives the + * bridge information + */ + struct interface *svi_if_link = NULL; + svi_if_zif = svi_if->info; - if (svi_if_zif) - zvni = zvni_map_svi(svi_if, svi_if_zif->link); + if (svi_if_zif) { + svi_if_link = if_lookup_by_index_per_ns( + zebra_ns_lookup(NS_DEFAULT), + svi_if_zif->link_ifindex); + zvni = zvni_map_svi(svi_if, svi_if_link); + } } else if (IS_ZEBRA_IF_BRIDGE(svi_if)) { + /* + * If it is a vlan unaware bridge then svi is the bridge + * itself + */ zvni = zvni_map_svi(svi_if, svi_if); } } else if (IS_ZEBRA_IF_VLAN(ifp)) { struct zebra_if *svi_if_zif = - NULL; /* Zebra daemon specific info for SVI*/ + NULL; /* Zebra daemon specific info for SVI */ + struct interface *svi_if_link = + NULL; /* link info for the SVI = bridge info */ svi_if_zif = ifp->info; - if (svi_if_zif) - zvni = zvni_map_svi(ifp, svi_if_zif->link); + svi_if_link = if_lookup_by_index_per_ns( + zebra_ns_lookup(NS_DEFAULT), svi_if_zif->link_ifindex); + if (svi_if_zif && svi_if_link) + zvni = zvni_map_svi(ifp, svi_if_link); } else if (IS_ZEBRA_IF_BRIDGE(ifp)) { zvni = zvni_map_svi(ifp, ifp); } @@ -4141,7 +4214,7 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) vxl->access_vlan, inet_ntoa(vxl->vtep_ip), zif->brslave_info.bridge_ifindex, chgflags); - /* Removed from bridge? */ + /* Removed from bridge? Cleanup and return */ if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { /* Delete from client, remove all remote VTEPs */ @@ -4150,7 +4223,11 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) zvni_neigh_del_all(zvrf, zvni, 1, 0, DEL_ALL_NEIGH); zvni_mac_del_all(zvrf, zvni, 1, 0, DEL_ALL_MAC); zvni_vtep_del_all(zvni, 1); - } else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + return 0; + } + + /* Handle other changes. */ + if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { /* Remove all existing local neighbors and MACs for this VNI * (including from BGP) */ @@ -4268,6 +4345,7 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock, int advertise; vni_t vni = 0; zebra_vni_t *zvni = NULL; + struct interface *ifp = NULL; s = client->ibuf; advertise = stream_getc(s); @@ -4318,7 +4396,16 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock, zvni->advertise_gw_macip = advertise; - zif = zvni->vxlan_if->info; + ifp = zvni->vxlan_if; + if (!ifp) + return 0; + + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return 0; + zl2_info = zif->l2info.vxl; vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan, diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 8539311eab..fa7d0e9457 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -114,8 +114,6 @@ struct zebra_mac_t_ { struct in_addr r_vtep_ip; } fwd_info; - u_int32_t neigh_refcnt; - /* List of neigh associated with this mac */ struct list *neigh_list; }; diff --git a/zebra/zserv.c b/zebra/zserv.c index 0e0cc78bbe..ef289f3960 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -626,6 +626,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p, api_nh->type = nexthop->type; switch (nexthop->type) { case NEXTHOP_TYPE_BLACKHOLE: + api_nh->bh_type = nexthop->bh_type; break; case NEXTHOP_TYPE_IPV4: api_nh->gate.ipv4 = nexthop->gate.ipv4; @@ -1093,7 +1094,8 @@ static int zread_route_add(struct zserv *client, u_short length, api_nh->ifindex); break; case NEXTHOP_TYPE_BLACKHOLE: - route_entry_nexthop_blackhole_add(re); + route_entry_nexthop_blackhole_add( + re, api_nh->bh_type); break; } @@ -1163,7 +1165,7 @@ static int zread_route_del(struct zserv *client, u_short length, src_p = &api.src_prefix; rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance, - api.flags, &api.prefix, src_p, NULL, 0, zvrf->table_id, + api.flags, &api.prefix, src_p, NULL, zvrf->table_id, api.metric); /* Stats */ @@ -1201,6 +1203,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, 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 = client->ibuf; @@ -1264,7 +1267,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, stream_forward_getp(s, IPV6_MAX_BYTELEN); break; case NEXTHOP_TYPE_BLACKHOLE: - route_entry_nexthop_blackhole_add(re); + route_entry_nexthop_blackhole_add(re, bh_type); break; } } @@ -1329,7 +1332,7 @@ static int zread_ipv4_delete(struct zserv *client, u_short length, table_id = zvrf->table_id; rib_delete(AFI_IP, api.safi, zvrf_id(zvrf), api.type, api.instance, - api.flags, &p, NULL, NULL, 0, table_id, 0); + api.flags, &p, NULL, NULL, table_id, 0); client->v4_route_del_cnt++; return 0; } @@ -1367,6 +1370,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, 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 = client->ibuf; @@ -1434,7 +1438,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, } break; case NEXTHOP_TYPE_BLACKHOLE: - route_entry_nexthop_blackhole_add(re); + route_entry_nexthop_blackhole_add(re, bh_type); break; } } @@ -1516,6 +1520,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, 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 = client->ibuf; @@ -1594,7 +1599,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, } break; case NEXTHOP_TYPE_BLACKHOLE: - route_entry_nexthop_blackhole_add(re); + route_entry_nexthop_blackhole_add(re, bh_type); break; } } @@ -1674,7 +1679,7 @@ static int zread_ipv6_delete(struct zserv *client, u_short length, api.safi = stream_getw(s); /* IPv4 prefix. */ - memset(&p, 0, sizeof(struct prefix_ipv6)); + memset(&p, 0, sizeof(struct prefix)); p.family = AF_INET6; p.prefixlen = stream_getc(s); stream_get(&p.u.prefix6, s, PSIZE(p.prefixlen)); @@ -1689,7 +1694,7 @@ static int zread_ipv6_delete(struct zserv *client, u_short length, src_pp = NULL; rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type, api.instance, - api.flags, &p, src_pp, NULL, 0, client->rtm_table, 0); + api.flags, &p, src_pp, NULL, client->rtm_table, 0); client->v6_route_del_cnt++; return 0; |
