From d7d970105eb9d2e973879de9e15e522c0e4ebeca Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Thu, 27 Jul 2017 17:11:48 -0700 Subject: [PATCH 01/27] bgpd: notify zebra if advertise-gw-macip is enabled when VNI comes up Ticket: CM-17281 Review: CCR-6517 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 0560dc46f9..109c98f81c 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -45,6 +45,7 @@ #include "bgpd/bgp_encap_types.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_zebra.h" /* * Definitions and external declarations. @@ -2725,6 +2726,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; } From 23341a05841f1acbd83367e23eb14464c26683ba Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Tue, 1 Aug 2017 17:34:51 -0700 Subject: [PATCH 02/27] Zebra: replace mac entry in kernel when it moves from local to remote Until now, we had to delete the local mac entries when a mac moved from local to remote, with the new kernel patch that is no longer necessary. Ticket:CM-16094 Reviewed By:CCR-6470 Testing Done: Manual Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index f99c16ae91..676cf8334e 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3272,9 +3272,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. */ From 0a97666de7e5a803deb3a3db3c5d0459bca0fdaa Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 9 Aug 2017 14:28:39 -0700 Subject: [PATCH 03/27] zebra: Use neigh_list instead of neigh_refcnt for zebra_mac and zebra_neigh binding Ticket: CM-17500 Review: CCR-6584 Testing: Manual Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 25 ++++++++++--------------- zebra/zebra_vxlan_private.h | 2 -- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 676cf8334e..80a2ea1309 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -384,8 +384,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)) @@ -1355,9 +1355,6 @@ 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", @@ -1943,10 +1940,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) @@ -3132,7 +3127,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 @@ -3323,16 +3318,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); } 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; }; From db0e1937ca356d8181b2d2e8856159e3ea80d87f Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 16 Aug 2017 23:19:58 -0700 Subject: [PATCH 04/27] bgpd: Ignore EVPN routes from CLAG peer when VNI comes up There are two parts to this commit: 1. create a database of self tunnel-ip for used in martian nexthop check In a CLAG setup, the tunnel-ip (VNI UP) notification comes before the clag-anycast-ip comes up in the system. This was causing our self next hop check to fail and we were instaling routes with martian nexthop in zebra. We need to keep this info in a seperate database for all local tunnel-ip. This database will be used in parallel with the self next hop database to martian nexthop checks. 2. When a local VNI comes up, update the tunnel-ip database and filter routes in the RD table if necessary In case of EVPN we might receive routes from clag peer before the clag-anycast ip and VNI is up on the system. We will store the routes in the RD table for later processing. When VNI comes UP, we loop thorugh all the routes and install them in zebra if required. However, we were missing the martian nexthop check in this code path. From now onwards, when a VNI comes UP, we will first update the tunnel-ip database We then loop through all the routes in RD table and apply martian next hop filter if required. Things not covered in this commit but are required: This processing is needed in general when an address becomes a connected address. We need to loop through all the routes in BGP and apply martian nexthop filter if necessary. This will be taken care in a seperate bug Ticket:CM-17271/CM-16911 Reviewed By: ccr-6542 Testing Done: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 109 +++++++++++++++++++++++++++++++++++++++++---- bgpd/bgp_evpn.h | 1 + bgpd/bgp_memory.c | 1 + bgpd/bgp_memory.h | 1 + bgpd/bgp_nexthop.c | 91 ++++++++++++++++++++++++++++++++++--- bgpd/bgp_nexthop.h | 16 +++++++ bgpd/bgp_route.c | 2 +- bgpd/bgp_route.h | 2 + bgpd/bgp_zebra.c | 8 ++-- bgpd/bgpd.c | 2 + bgpd/bgpd.h | 4 ++ 11 files changed, 219 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 109c98f81c..d9735e7ffa 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -46,6 +46,7 @@ #include "bgpd/bgp_debug.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_nexthop.h" /* * Definitions and external declarations. @@ -1200,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. */ @@ -1392,12 +1400,12 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, bgp_evpn_route_type rtype, int install) { - afi_t afi; - safi_t safi; - struct bgp_node *rd_rn, *rn; - struct bgp_table *table; - struct bgp_info *ri; - int ret; + afi_t afi; + safi_t safi; + struct bgp_node *rd_rn, *rn; + struct bgp_table *table; + struct bgp_info *ri; + int ret; afi = AFI_L2VPN; safi = SAFI_EVPN; @@ -1432,7 +1440,7 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, if (is_route_matching_for_vni(bgp, vpn, ri)) { if (install) ret = install_evpn_route_entry( - bgp, vpn, evp, ri); + bgp, vpn, evp, ri); else ret = uninstall_evpn_route_entry( bgp, vpn, evp, ri); @@ -2563,6 +2571,79 @@ 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 seld" + "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. */ @@ -2658,6 +2739,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)) @@ -2703,15 +2789,22 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, bgp->vrf_id, vni); return -1; } + } - /* 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)) { diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index e9b7857212..ef63199395 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -38,6 +38,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_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..b988fbf738 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_route.c b/bgpd/bgp_route.c index 35f793f861..fc22642833 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2384,7 +2384,7 @@ 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, +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); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 1a1817bad3..93d79e5059 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -293,6 +293,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); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 2fc75ea5a2..ad73f96d55 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2107,10 +2107,10 @@ static void bgp_zebra_connected(struct zclient *zclient) static int bgp_zebra_process_local_vni(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { - struct stream *s; - vni_t vni; - struct bgp *bgp; - struct in_addr vtep_ip; + struct stream *s; + vni_t vni; + struct bgp *bgp; + struct in_addr vtep_ip; s = zclient->ibuf; vni = stream_getl(s); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d7733fbacd..f48ba6af24 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2934,6 +2934,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; @@ -3158,6 +3159,7 @@ static void bgp_free(struct bgp *bgp) bgp_scan_finish(bgp); bgp_address_destroy(bgp); + bgp_tip_hash_destroy(bgp); bgp_evpn_cleanup(bgp); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index bfdddc69b1..344b850fb4 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -318,6 +318,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]; From acf716660f15f3ae4876ce14acee50ef93870fc2 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 2 Aug 2017 13:54:17 -0700 Subject: [PATCH 05/27] bgpd: show command for martian nexthop db Ticket:CM-17271/CM-16911 Reviewed By: ccr-6542 Testing Done: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_vty.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 01c27920f5..de30311e01 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6424,6 +6424,59 @@ 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", @@ -12285,6 +12338,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); From 9c92b5f76819eb346d6143f81a812c4dade83e5c Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Thu, 20 Jul 2017 17:42:20 -0700 Subject: [PATCH 06/27] bgpd: Json support for evpn commands Ticket:CM-16241 Reviewed By:CCR-6451 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 55 ++ bgpd/bgp_evpn.h | 2 + bgpd/bgp_evpn_private.h | 2 + bgpd/bgp_evpn_vty.c | 1156 +++++++++++++++++++++++++++++---------- bgpd/bgp_route.c | 49 +- 5 files changed, 958 insertions(+), 306 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index d9735e7ffa..707728f9da 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2187,6 +2187,61 @@ char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len) return buf; } +/* + * 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 * ETHER_ADDR_LEN); + 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 * ETHER_ADDR_LEN); + 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. */ + } + + return; +} + + /* * Function to convert evpn route to string. * NOTE: We don't use prefix2str as the output here is a bit different. diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index ef63199395..01474b09d8 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -28,6 +28,8 @@ 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, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 9dc459cd4e..7102038f17 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..2ba8f29260 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,6 +47,7 @@ struct vni_walk_ctx { struct bgp *bgp; struct vty *vty; struct in_addr vtep_ip; + json_object *json; }; struct evpn_config_write { @@ -54,7 +56,8 @@ struct evpn_config_write { }; #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 +71,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 +98,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 +113,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 +132,103 @@ 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); + } + + if (json) { + json_object_object_add(json_rt, "vnis", json_vnis); + json_object_object_add(json, rt_buf, json_rt); + } - for (ALL_LIST_ELEMENTS(irt->vnis, node, nnode, tmp_vpn)) - vty_out(vty, " %u\n", tmp_vpn->vni); } -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; + + vty = args[0]; + json = args[1]; + display_import_rt(vty, irt); + + 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 +241,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; - vty_out(vty, "VNI: %d", vpn->vni); - if (is_vni_live(vpn)) - vty_out(vty, " (known to the kernel)"); - vty_out(vty, "\n"); + 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, " 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 +329,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 +409,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]; - vty_out(vty, "\nVNI: %d\n\n", vpn->vni); - show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip); + 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); + } + + 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 +442,91 @@ 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 */ @@ -1281,19 +1487,26 @@ 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 +1518,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 +1528,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 +1538,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 +1554,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 +1598,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 +1607,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 +1615,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 +1624,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 +1668,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 +1692,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 +1700,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 +1711,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 +1756,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 +1767,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 +1821,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 +1899,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 +1936,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); } /* @@ -1863,19 +2278,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 +2304,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 +2352,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 +2369,236 @@ 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 ]", - 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 ] [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 ]", - 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 ] [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; + struct bgp *bgp; + int ret; + struct prefix_rd prd; + struct ethaddr mac; + struct ipaddr ip; + 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) [ | 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) [ | 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 +2606,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 +2624,231 @@ 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; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index fc22642833..40d6fd7bfd 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6227,7 +6227,8 @@ 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; @@ -6250,23 +6251,29 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty) 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 + } else { 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 { @@ -6370,9 +6377,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 */ @@ -6668,7 +6677,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) { @@ -6801,7 +6810,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, " "); } @@ -6916,7 +6925,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, " "); @@ -6985,7 +6994,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, " "); } @@ -7054,7 +7063,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, " "); } @@ -8336,6 +8345,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; @@ -8357,10 +8367,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) From c6462ff4b3134fb986310852d8001d8f9917a621 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 26 Jul 2017 14:14:07 -0700 Subject: [PATCH 07/27] bgpd: Fix json output Ticket: CM-17259 Review: CCR-6512 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_route.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 40d6fd7bfd..3a3da6fc4e 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6235,17 +6235,26 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty, 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 (!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); + 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); @@ -6262,9 +6271,11 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty, 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); + if (!json) + len = vty_out(vty, "%s/%d", + inet_ntop(p->family, &p->u.prefix, buf, + BUFSIZ), + p->prefixlen); } if (!json) { From d77114b704bf6dd9a767e31f75af44dd5259cdcc Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 7 Aug 2017 13:54:57 -0700 Subject: [PATCH 08/27] bgpd: display hostname capabilities as advertised and received Ticket: CM-17250 Review: CCR-6567 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_vty.c | 84 ++++++++++++++++++++++++++++++++++++++++---------- bgpd/bgpd.c | 21 +++++++++++-- 2 files changed, 85 insertions(+), 20 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index de30311e01..cabbade525 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -8651,6 +8651,46 @@ 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, @@ -8984,25 +9024,35 @@ 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, " 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"); + vty_out(vty, + " Hostname Capability:"); + + if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) { + vty_out(vty, " 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, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index f48ba6af24..c58e4e70cd 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2735,9 +2735,12 @@ static int bgp_startup_timer_expire(struct thread *thread) static struct bgp *bgp_create(as_t *as, const char *name, enum bgp_instance_type inst_type) { - struct bgp *bgp; - afi_t afi; - safi_t safi; + struct bgp *bgp; + afi_t afi; + safi_t safi; + struct utsname names; + + uname(&names); if ((bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp))) == NULL) return NULL; @@ -2762,6 +2765,18 @@ 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 (bgp->peer_self->domainname != NULL) { + XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname); + bgp->peer_self->domainname = NULL; + } + bgp->peer_self->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, names.nodename); + bgp->peer_self->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, + names.domainname); bgp->peer = list_new(); bgp->peer->cmp = (int (*)(void *, void *))peer_cmp; bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, NULL); From dff8f48da3690880f9bfc4bb5bda2ac9933a7891 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 7 Aug 2017 13:57:44 -0700 Subject: [PATCH 09/27] bgpd: Add advertsie-all-vni in show bgp neighbor Ticket: CM-17249 Review: CCR-6558 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 81 +++++++++++++++++++++++++-------------------- bgpd/bgp_evpn_vty.c | 2 +- bgpd/bgp_vty.c | 36 +++++++++++++------- 3 files changed, 71 insertions(+), 48 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 707728f9da..5da773d7a3 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2200,43 +2200,54 @@ bgp_evpn_route2json (struct prefix_evpn *p, json_object *json) 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 * ETHER_ADDR_LEN); - json_object_string_add (json, "mac", prefix_mac2str (&p->prefix.mac, buf1, sizeof (buf1))); - } - else - { - u_char family; + 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; + 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 * ETHER_ADDR_LEN); - 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. */ - } + 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. */ + } return; } diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 2ba8f29260..af34c33946 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -174,7 +174,7 @@ static void show_import_rt_entry(struct hash_backet *backet, void *args[]) vty = args[0]; json = args[1]; - display_import_rt(vty, irt); + display_import_rt(vty, irt, json); return; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index cabbade525..80daac236d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7396,14 +7396,14 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, safi_t safi, u_char use_json, json_object *json_neigh) { - struct bgp_filter *filter; - struct peer_af *paf; - char orf_pfx_name[BUFSIZ]; - int orf_pfx_count; - json_object *json_af = NULL; - json_object *json_prefA = NULL; - json_object *json_prefB = NULL; - json_object *json_addr = NULL; + struct bgp_filter *filter; + struct peer_af *paf; + char orf_pfx_name[BUFSIZ]; + int orf_pfx_count; + json_object *json_af = NULL; + json_object *json_prefA = NULL; + json_object *json_prefB = NULL; + json_object *json_addr = NULL; if (use_json) { json_addr = json_object_new_object(); @@ -7602,6 +7602,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 @@ -7867,6 +7873,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 @@ -9768,10 +9780,10 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, static void bgp_show_all_instances_neighbors_vty(struct vty *vty, u_char use_json) { - struct listnode *node, *nnode; - struct bgp *bgp; - json_object *json = NULL; - int is_first = 1; + struct listnode *node, *nnode; + struct bgp *bgp; + json_object *json = NULL; + int is_first = 1; if (use_json) vty_out(vty, "{\n"); From b5ebdc9ba5baa21b6447daf9dc7cb0f20fc46847 Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 20 Jul 2017 02:46:28 -0700 Subject: [PATCH 10/27] zebra: Handle MACIP requests when in transient conditions When multiple events are happening, it is possible that remote MACIP or other requests may be received when an interface is down or removed from a bridge. Handle this correctly. Signed-off-by: Vivek Venkatraman --- zebra/zebra_vxlan.c | 99 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 24 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 80a2ea1309..7e456cc7c1 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1428,13 +1428,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, @@ -1461,6 +1470,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) @@ -1469,7 +1479,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, @@ -1824,6 +1841,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); @@ -3018,6 +3039,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; @@ -3060,12 +3083,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 @@ -3078,12 +3107,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); @@ -3161,6 +3184,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)); @@ -3208,16 +3233,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 @@ -3679,6 +3705,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; @@ -3705,6 +3733,18 @@ 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 @@ -3735,6 +3775,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)); @@ -3760,24 +3802,23 @@ 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) { @@ -4260,6 +4301,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); @@ -4310,7 +4352,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, From af026ae40eeeccea0b178f22b519bf9ba6862bb2 Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 20 Jul 2017 09:54:46 -0700 Subject: [PATCH 11/27] zebra: Fix VxLAN interface add-del to bridge Ensure that removal and addition of VxLAN interface from/to bridge is handled correctly. Signed-off-by: Vivek Venkatraman --- zebra/zebra_l2.c | 22 ++++++++++++++-------- zebra/zebra_vxlan.c | 10 +++++++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 5d059a4502..452bab003a 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -224,12 +224,18 @@ 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) - zebra_l2_map_slave_to_bridge(&zif->brslave_info); - else if (old_bridge_ifindex != IFINDEX_INTERNAL) - 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); + if (bridge_ifindex != IFINDEX_INTERNAL) { + zebra_l2_map_slave_to_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); + } 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); + } } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 7e456cc7c1..5e7ffb108e 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3084,7 +3084,7 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, continue; } ifp = zvni->vxlan_if; - if (!ifp) + if (!ifp) { zlog_err( "VNI %u hash %p doesn't have intf upon remote MACIP DEL", vni, zvni); @@ -4174,7 +4174,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 */ @@ -4183,7 +4183,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) */ From c65f709ec66579c7d8bd175b9cef4b4848ed585f Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 9 Aug 2017 17:17:00 -0700 Subject: [PATCH 12/27] zebra: Refresh remote neighbors when they go stale If we get an ageout notification from the kernel for EVPN-installed neighbors, ensure that they are readded. Otherwise, while entries in STALE state are usable, based on other kernel parameters they can get deleted and adding them back only at delete can have other undesirable performance consequences. Note: This is the current Linux kernel behavior (to ageout EVPN installed neighbors). Signed-off-by: Vivek Venkatraman Reviewed-by: Mitesh Kanjariya Ticket: CM-15623, CM-17490 Reviewed By: CCR-6586 Testing Done: Manual, evpn-min --- zebra/zebra_vxlan.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 5e7ffb108e..2240d7c763 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2876,8 +2876,9 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp, } /* - * Handle neighbor add or update (on a VLAN device / L3 interface) - * from the kernel. + * Handle neighbor add or update from the kernel. This is typically + * for a local neighbor on a VLAN device (L3 interface) but can also + * be the ageout notification for a remote neighbor. */ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, struct interface *link_if, @@ -2963,7 +2964,9 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, /* The neighbor is remote and that is the notification we got. */ { - /* TODO: Evaluate if we need to do anything here. */ + /* If the kernel has aged this entry, re-install. */ + if (state & NUD_STALE) + zvni_neigh_install(zvni, n); return 0; } else /* Neighbor has moved from remote to local. */ From ee7ca6c05986a86967b7e92fc6213a2f33dd498a Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 9 Aug 2017 17:32:19 -0700 Subject: [PATCH 13/27] bgpd: Cleanup NHT state when underlying VRF goes down When the underlying VRF is deleted, ensure that state for the next hops that BGP registers with zebra for tracking purposes is properly updated. Otherwise BGP will not re-register the next hop when the VRF is re-created, resulting in the next hop staying unresolved. Signed-off-by: Vivek Venkatraman Reviewed-by: Don Slice Ticket: CM-17456 Reviewed By: CCR-6587 Testing Done: Manual, bgp-min, vrf --- bgpd/bgp_nht.c | 27 +++++++++++++++++++++++++++ bgpd/bgp_nht.h | 6 ++++++ bgpd/bgpd.c | 3 +++ 3 files changed, 36 insertions(+) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 3a7a60b14d..55a2f10132 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -482,6 +482,33 @@ 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)) { + if ((bnc = rn->info) == NULL) + 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/bgpd.c b/bgpd/bgpd.c index c58e4e70cd..a017c4fa26 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3031,6 +3031,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. */ From cb499ebbaafac55514984077f6ea18e9d19fb901 Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 10 Aug 2017 08:43:06 -0700 Subject: [PATCH 14/27] bgpd: Register for label only the default instance Ensure that the registration for the "in" label for a unicast prefix is done only in the default instance. The zebra label manager as well as other code in BGP only has support for assigning labels in the default instance. Signed-off-by: Vivek Venkatraman Reviewed-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-17110 Reviewed By: CCR-6588 Testing Done: Manual tests, mpls --- bgpd/bgp_route.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3a3da6fc4e..e9bf574331 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2044,11 +2044,12 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data) /* 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. + * NOTE: This is only relevant for the default instance. */ - if (safi == SAFI_UNICAST) { + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT + && safi == SAFI_UNICAST) { if (new_select) { if (!old_select || bgp_label_index_differs(new_select, old_select) From b682f6de5a4249c84f7a6467c1792d210385504f Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 13 Aug 2017 21:52:04 -0700 Subject: [PATCH 15/27] zebra: Fix MAC change handling for a neighbor When the MAC changes for a local neighbor, ensure that the neighbor data structure as well as the link between the neighbor and MAC data structures is updated correctly. Signed-off-by: Vivek Venkatraman Reviewed-by: Mitesh Kanjariya Reviewed-by: Donald Sharp Ticket: CM-17565 Reviewed By: CCR-6605 Testing Done: Manual, evpn-smoke --- bgpd/bgp_evpn.c | 75 +++++++++++++++---------------- bgpd/bgp_evpn.h | 3 +- bgpd/bgp_evpn_vty.c | 5 ++- bgpd/bgp_route.c | 23 +++++----- bgpd/bgp_vty.c | 6 +-- zebra/zebra_l2.c | 14 +++--- zebra/zebra_vxlan.c | 105 ++++++++++++++++++++++++-------------------- 7 files changed, 118 insertions(+), 113 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 5da773d7a3..ad000e3f12 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2192,58 +2192,58 @@ char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len) * 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) +bgp_evpn_route2json(struct prefix_evpn *p, json_object *json) { - char buf1[ETHER_ADDR_STRLEN]; - char buf2[PREFIX2STR_BUFFER]; + char buf1[ETHER_ADDR_STRLEN]; + char buf2[PREFIX2STR_BUFFER]; - if (!json) - return; + 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) ? + 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)); + 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))); + 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", + 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) ? + 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)); + 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. */ @@ -2683,10 +2683,7 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp) if (bgp_debug_update(ri->peer, &rn->p, NULL, 1)) zlog_debug( - "%u: prefix %s with " - "attr %s - DENIED" - "due to martian or seld" - "nexthop", + "%u: prefix %s with attr %s - DENIED due to martian or self nexthop", bgp->vrf_id, prefix2str( &rn->p, diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 01474b09d8..985f41f586 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -28,8 +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_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, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index af34c33946..a198e65128 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -76,8 +76,8 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt, char rt_buf[RT_ADDRSTRLEN]; if (json) { - json_rt = json_object_new_object (); - json_vnis = json_object_new_array (); + json_rt = json_object_new_object(); + json_vnis = json_object_new_array(); } /* TODO: This needs to go into a function */ @@ -521,6 +521,7 @@ static void show_vni_entry(struct hash_backet *backet, void *args[]) 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); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e9bf574331..a2a7d2ae1d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6246,7 +6246,8 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty, || (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. */ + /* When mask is natural, + mask is not displayed. */ } else len += vty_out(vty, "/%d", p->prefixlen); } else { @@ -6261,12 +6262,12 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty, len = vty_out(vty, "%s", buf); } else if (p->family == AF_EVPN) { #if defined(HAVE_CUMULUS) - 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); + 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); @@ -6393,7 +6394,7 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo, else vty_out(vty, "%*s", 17, " "); } else { - route_vty_out_route (p, vty, json_path); + route_vty_out_route(p, vty, json_path); } /* Print attribute */ @@ -8379,9 +8380,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", - prefix2str (p, prefix_str, - sizeof (prefix_str))); + json_object_string_add(json, "prefix", + prefix2str(p, prefix_str, + sizeof(prefix_str))); } else { #if defined(HAVE_CUMULUS) if (safi == SAFI_EVPN) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 80daac236d..5d44c0a142 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9040,8 +9040,7 @@ 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)) { - vty_out(vty, " advertised (name: %s, " - "domain name: %s)", + vty_out(vty, " advertised (name: %s,domain name: %s)", bgp->peer_self->hostname ? bgp->peer_self->hostname : "n/a", @@ -9053,8 +9052,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json, } if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) { - vty_out(vty, " received (name: %s, " - "domain name: %s)", + vty_out(vty, " received (name: %s,domain name: %s)", p->hostname ? p->hostname : "n/a", p->domainname ? diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 452bab003a..7281622e33 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -225,17 +225,17 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp, /* Set up or remove link with master */ if (bridge_ifindex != IFINDEX_INTERNAL) { - zebra_l2_map_slave_to_bridge (&zif->brslave_info); + zebra_l2_map_slave_to_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); + 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. + /* 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); + zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE); + zebra_l2_unmap_slave_from_bridge(&zif->brslave_info); } } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 2240d7c763..4a5fc38493 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1441,7 +1441,7 @@ static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, zif = ifp->info; /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative (ifp) || !zif->brslave_info.br_if) + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) return; zl2_info = zif->l2info.vxl; @@ -1485,7 +1485,7 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, zif = ifp->info; /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative (ifp) || !zif->brslave_info.br_if) + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) return; zl2_info = zif->l2info.vxl; @@ -2889,10 +2889,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. @@ -2947,19 +2946,35 @@ 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; + } else { + /* If the MAC has changed, + * need to issue a delete first + * as this means a different MACIP route. + * Also, need to do some unlinking/relinking. + */ + 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. */ @@ -2973,6 +2988,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); @@ -2984,17 +3001,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)) { @@ -3008,23 +3019,20 @@ 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); + /* 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); - ZEBRA_NEIGH_SET_ACTIVE(n); - return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, - macaddr, 0); - } - - 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. */ @@ -3096,7 +3104,7 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, zif = ifp->info; /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative (ifp) || !zif->brslave_info.br_if) + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) continue; /* The remote VTEP specified is normally expected to exist, but @@ -3246,7 +3254,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, zif = ifp->info; /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative (ifp) || !zif->brslave_info.br_if) + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) continue; /* The remote VTEP specified should normally exist, but it is @@ -3738,14 +3746,14 @@ int zebra_vxlan_remote_vtep_del(struct zserv *client, int sock, u_short length, ifp = zvni->vxlan_if; if (!ifp) { - zlog_err ("VNI %u hash %p doesn't have intf upon remote VTEP DEL", - zvni->vni, zvni); - continue; + 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) + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) continue; /* If the remote VTEP does not exist, there's nothing more to @@ -3817,10 +3825,11 @@ int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock, u_short length, zif = ifp->info; /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative (ifp) || !zif->brslave_info.br_if) + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) continue; - /* If the remote VTEP already exists, there's nothing more to do. */ + /* If the remote VTEP already exists, + there's nothing more to do. */ if (zvni_vtep_find(zvni, &vtep_ip)) continue; @@ -4366,7 +4375,7 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock, zif = ifp->info; /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative (ifp) || !zif->brslave_info.br_if) + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) return 0; zl2_info = zif->l2info.vxl; From 859b32c0307b3753cc4008ee03e5eee571b8d8c7 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Thu, 17 Aug 2017 17:39:20 -0700 Subject: [PATCH 16/27] zebra: Revert the fix for zebra: Refresh remote neighbors when they go stale NUD_STALE flag is causing a build breakage, we might have to define it somewhere in frr. Reverting the fix for now untill we decide how to handle it correctly. Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 4a5fc38493..6bf33806b8 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2876,9 +2876,8 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp, } /* - * Handle neighbor add or update from the kernel. This is typically - * for a local neighbor on a VLAN device (L3 interface) but can also - * be the ageout notification for a remote neighbor. + * Handle neighbor add or update (on a VLAN device / L3 interface) + * from the kernel. */ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, struct interface *link_if, @@ -2979,9 +2978,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, /* The neighbor is remote and that is the notification we got. */ { - /* If the kernel has aged this entry, re-install. */ - if (state & NUD_STALE) - zvni_neigh_install(zvni, n); + /* TODO: Evaluate if we need to do anything here. */ return 0; } else /* Neighbor has moved from remote to local. */ From 36127a7f9c950ebc04242ad7a0b527b5966e914d Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Thu, 17 Aug 2017 21:08:33 -0700 Subject: [PATCH 17/27] bgpd: use macro HAVE_STRUCT_UTSNAME_DOMAINNAME to avoid compilation failures Signed-off-by: Mitesh Kanjariya --- bgpd/bgpd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a017c4fa26..6cad2e97ad 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2769,14 +2769,16 @@ static struct bgp *bgp_create(as_t *as, const char *name, XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname); bgp->peer_self->hostname = NULL; } + bgp->peer_self->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, names.nodename); if (bgp->peer_self->domainname != NULL) { XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname); bgp->peer_self->domainname = NULL; } - bgp->peer_self->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, names.nodename); +#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME bgp->peer_self->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, names.domainname); +#endif bgp->peer = list_new(); bgp->peer->cmp = (int (*)(void *, void *))peer_cmp; bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, NULL); From 57f7feb64ff6eebbb2e21bd769950b9ac11525ec Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Fri, 18 Aug 2017 17:23:30 -0700 Subject: [PATCH 18/27] Fix coding style. Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 71 ++++++++++++++++++++++----------------------- bgpd/bgp_nht.c | 3 +- bgpd/bgp_route.c | 12 ++++---- bgpd/bgp_vty.c | 6 ++-- zebra/zebra_l2.c | 7 +++-- zebra/zebra_vxlan.c | 46 ++++++++++++++--------------- 6 files changed, 74 insertions(+), 71 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ad000e3f12..f509d869a3 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2191,8 +2191,7 @@ 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) +void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json) { char buf1[ETHER_ADDR_STRLEN]; char buf2[PREFIX2STR_BUFFER]; @@ -2203,56 +2202,56 @@ bgp_evpn_route2json(struct prefix_evpn *p, json_object *json) 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_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) { + 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))); + 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; + 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 */ + 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_int_add(json, "macLen", 8 * ETH_ALEN); json_object_string_add(json, "mac", - prefix_mac2str (&p->prefix.mac, - buf1, - sizeof (buf1))); + 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)); + 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. */ } - - return; } - /* * Function to convert evpn route to string. * NOTE: We don't use prefix2str as the output here is a bit different. diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 55a2f10132..a0fc10c745 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -498,7 +498,8 @@ void bgp_cleanup_nexthops(struct bgp *bgp) for (rn = bgp_table_top(bgp->nexthop_cache_table[afi]); rn; rn = bgp_route_next(rn)) { - if ((bnc = rn->info) == NULL) + bnc = rn->info; + if (!bnc) continue; /* Clear relevant flags. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a2a7d2ae1d..428b4f3626 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6262,12 +6262,12 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty, len = vty_out(vty, "%s", buf); } else if (p->family == AF_EVPN) { #if defined(HAVE_CUMULUS) - 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); + 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); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 5d44c0a142..60361adbb6 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9040,7 +9040,8 @@ 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)) { - vty_out(vty, " advertised (name: %s,domain name: %s)", + vty_out(vty, + " advertised (name: %s,domain name: %s)", bgp->peer_self->hostname ? bgp->peer_self->hostname : "n/a", @@ -9052,7 +9053,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json, } if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) { - vty_out(vty, " received (name: %s,domain name: %s)", + vty_out(vty, + " received (name: %s,domain name: %s)", p->hostname ? p->hostname : "n/a", p->domainname ? diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 7281622e33..3d505857c2 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -230,9 +230,10 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp, 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. + /* + * 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); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 6bf33806b8..c2ea8ab58c 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2950,30 +2950,30 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, */ n->ifindex = ifp->ifindex; return 0; - } else { - /* If the MAC has changed, - * need to issue a delete first - * as this means a different MACIP route. - * Also, need to do some unlinking/relinking. - */ - 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); } + + /* 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. */ From 0291c246dbf3e2e598a3a93c835a40cd6bcbb845 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Fri, 18 Aug 2017 22:43:09 -0700 Subject: [PATCH 19/27] fix coding style Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 22 +++++++++++----------- bgpd/bgp_evpn_vty.c | 20 ++++++++++---------- bgpd/bgp_nexthop.c | 18 +++++++++--------- bgpd/bgp_route.c | 2 +- bgpd/bgp_vty.c | 30 +++++++++++++++--------------- bgpd/bgp_zebra.c | 8 ++++---- bgpd/bgpd.c | 8 ++++---- 7 files changed, 54 insertions(+), 54 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index f509d869a3..20955fb83c 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1400,12 +1400,12 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, bgp_evpn_route_type rtype, int install) { - afi_t afi; - safi_t safi; - struct bgp_node *rd_rn, *rn; - struct bgp_table *table; - struct bgp_info *ri; - int ret; + afi_t afi; + safi_t safi; + struct bgp_node *rd_rn, *rn; + struct bgp_table *table; + struct bgp_info *ri; + int ret; afi = AFI_L2VPN; safi = SAFI_EVPN; @@ -2639,11 +2639,11 @@ int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi, /* 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_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; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index a198e65128..e8e986d1fc 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2505,16 +2505,16 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip, "IP address (IPv4 or IPv6)\n" JSON_STR) { - struct bgp *bgp; - int ret; - struct prefix_rd prd; - struct ethaddr mac; - struct ipaddr ip; - int rd_idx = 0; - int mac_idx = 0; - int ip_idx = 0; - int uj = 0; - json_object *json = NULL; + struct bgp *bgp; + int ret; + struct prefix_rd prd; + struct ethaddr mac; + struct ipaddr ip; + 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)); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index b988fbf738..69c4ee1b67 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -90,8 +90,8 @@ static void bgp_nexthop_cache_reset(struct bgp_table *table) static void *bgp_tip_hash_alloc(void *p) { - const struct in_addr *val = (const struct in_addr *)p; - struct tip_addr *addr; + 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; @@ -107,15 +107,15 @@ static void bgp_tip_hash_free(void *addr) static unsigned int bgp_tip_hash_key_make(void *p) { - const struct tip_addr *addr = 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; + const struct tip_addr *addr1 = p1; + const struct tip_addr *addr2 = p2; return addr1->addr.s_addr == addr2->addr.s_addr; } @@ -137,8 +137,8 @@ void bgp_tip_hash_destroy(struct bgp *bgp) void bgp_tip_add(struct bgp *bgp, struct in_addr *tip) { - struct tip_addr tmp; - struct tip_addr *addr; + struct tip_addr tmp; + struct tip_addr *addr; tmp.addr = *tip; @@ -151,8 +151,8 @@ void bgp_tip_add(struct bgp *bgp, struct in_addr *tip) void bgp_tip_del(struct bgp *bgp, struct in_addr *tip) { - struct tip_addr tmp; - struct tip_addr *addr; + struct tip_addr tmp; + struct tip_addr *addr; tmp.addr = *tip; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 428b4f3626..36063af7cd 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8358,7 +8358,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]; + char prefix_str[BUFSIZ]; int count = 0; int best = 0; int suppress = 0; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 60361adbb6..c333d4df2c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6426,7 +6426,7 @@ DEFUN (show_bgp_vrfs, static void show_address_entry(struct hash_backet *backet, void *args) { - struct vty *vty = (struct vty *) args; + struct vty *vty = (struct vty *) args; struct bgp_addr *addr = (struct bgp_addr *) backet->data; vty_out(vty, "addr: %s, count: %d\n", @@ -6436,7 +6436,7 @@ static void show_address_entry(struct hash_backet *backet, void *args) static void show_tip_entry(struct hash_backet *backet, void *args) { - struct vty *vty = (struct vty *)args; + struct vty *vty = (struct vty *)args; struct tip_addr *tip = (struct tip_addr *) backet->data; vty_out(vty, "addr: %s, count: %d\n", @@ -6465,7 +6465,7 @@ DEFUN (show_bgp_martian_nexthop_db, "martian next-hops\n" "martian next-hop database\n") { - struct bgp *bgp = NULL; + struct bgp *bgp = NULL; bgp = bgp_get_default(); if (!bgp) { @@ -7396,14 +7396,14 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, safi_t safi, u_char use_json, json_object *json_neigh) { - struct bgp_filter *filter; - struct peer_af *paf; - char orf_pfx_name[BUFSIZ]; - int orf_pfx_count; - json_object *json_af = NULL; - json_object *json_prefA = NULL; - json_object *json_prefB = NULL; - json_object *json_addr = NULL; + struct bgp_filter *filter; + struct peer_af *paf; + char orf_pfx_name[BUFSIZ]; + int orf_pfx_count; + json_object *json_af = NULL; + json_object *json_prefA = NULL; + json_object *json_prefB = NULL; + json_object *json_addr = NULL; if (use_json) { json_addr = json_object_new_object(); @@ -9780,10 +9780,10 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, static void bgp_show_all_instances_neighbors_vty(struct vty *vty, u_char use_json) { - struct listnode *node, *nnode; - struct bgp *bgp; - json_object *json = NULL; - int is_first = 1; + struct listnode *node, *nnode; + struct bgp *bgp; + json_object *json = NULL; + int is_first = 1; if (use_json) vty_out(vty, "{\n"); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index ad73f96d55..2fc75ea5a2 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2107,10 +2107,10 @@ static void bgp_zebra_connected(struct zclient *zclient) static int bgp_zebra_process_local_vni(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { - struct stream *s; - vni_t vni; - struct bgp *bgp; - struct in_addr vtep_ip; + struct stream *s; + vni_t vni; + struct bgp *bgp; + struct in_addr vtep_ip; s = zclient->ibuf; vni = stream_getl(s); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6cad2e97ad..24d4ea36b7 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2735,10 +2735,10 @@ static int bgp_startup_timer_expire(struct thread *thread) static struct bgp *bgp_create(as_t *as, const char *name, enum bgp_instance_type inst_type) { - struct bgp *bgp; - afi_t afi; - safi_t safi; - struct utsname names; + struct bgp *bgp; + afi_t afi; + safi_t safi; + struct utsname names; uname(&names); From f51d8a274b68b97c7d618d3763b3fbafab4ac716 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Fri, 18 Aug 2017 17:40:52 -0700 Subject: [PATCH 20/27] zebra: Delete AUTO macs when neigh list is empty Ticket: CM-17660 Review: CCR-6624 Testing: Manual Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index c2ea8ab58c..86c3ce1d00 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"); } @@ -2869,7 +2874,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; From 71349e0358634c099b1c2b3d63a5dca3ad103578 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Sat, 19 Aug 2017 17:28:58 -0700 Subject: [PATCH 21/27] zebra: lookup link by ifindex Frr has an assumption that when interface A links to B, we already know about B. But that might be true always. It is probably purely depends on the configuration and how the interfaces are hashed in Kernel. FRR seems to sometimes get "A is linked to B" before it knows about B, in that case, the linkage between the data structure for A & B won't be proper. Ticket: CM-17679 Review: ccr-6628 Testing: Manual Signed-off-by: Mitesh Kanjariya --- zebra/interface.c | 6 ++++-- zebra/rt_netlink.c | 3 ++- zebra/zebra_vxlan.c | 39 +++++++++++++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index c4d0363994..8456984330 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -874,7 +874,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); } @@ -902,7 +903,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); } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index e28fe5630a..6763a9a82e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2005,7 +2005,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/zebra_vxlan.c b/zebra/zebra_vxlan.c index 86c3ce1d00..32c0e20a91 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1777,6 +1777,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; @@ -3886,7 +3889,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); @@ -3894,19 +3901,39 @@ 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); } From 419cd5a03f8bbf3d068ab99d1497dfe183753899 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 21 Aug 2017 14:56:06 -0700 Subject: [PATCH 22/27] lib/bgpd: provide/use API to get hostname/domainname Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_open.c | 27 ++++++++------------------- bgpd/bgpd.c | 10 +++------- isisd/isis_dynhn.c | 2 +- isisd/isis_lsp.c | 6 +++--- isisd/isis_misc.c | 20 +------------------- isisd/isis_misc.h | 1 - isisd/isisd.c | 2 +- lib/command.c | 35 +++++++++++++++++++++++++++++++---- lib/command.h | 5 +++++ lib/grammar_sandbox_main.c | 1 + lib/vty.c | 11 ++--------- vtysh/vtysh.c | 14 +------------- vtysh/vtysh_config.c | 5 ++--- 13 files changed, 59 insertions(+), 80 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 3ee865e3ba..2e0cc2a8d0 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 (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,22 @@ 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(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, hostname_get(), len); + if ((host.domainname) + && (strcmp(host.domainname, "(none)") != 0)) { + len = strlen(host.domainname); if (len > BGP_MAX_HOSTNAME) len = BGP_MAX_HOSTNAME; stream_putc(s, len); - stream_put(s, names.domainname, len); + stream_put(s, host.domainname, len); } else -#endif - { stream_putc(s, 0); /* 0 length */ - } /* Set the lengths straight */ len = stream_get_endp(s) - rcapp - 1; @@ -1478,14 +1472,9 @@ 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, hostname_get(), host.domainname); } /* Sending base graceful-restart capability irrespective of the config diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 24d4ea36b7..c64ebf1222 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2738,9 +2738,6 @@ static struct bgp *bgp_create(as_t *as, const char *name, struct bgp *bgp; afi_t afi; safi_t safi; - struct utsname names; - - uname(&names); if ((bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp))) == NULL) return NULL; @@ -2769,16 +2766,15 @@ static struct bgp *bgp_create(as_t *as, const char *name, XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname); bgp->peer_self->hostname = NULL; } - bgp->peer_self->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, names.nodename); + bgp->peer_self->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, + hostname_get()); if (bgp->peer_self->domainname != NULL) { XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname); bgp->peer_self->domainname = NULL; } -#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME bgp->peer_self->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, - names.domainname); -#endif + 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); diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index 6fa7988304..40ac1919fd 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()); + hostname_get()); return; } diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 6bf6e45d92..bf6968c955 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -600,7 +600,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", hostname_get()); else memcpy(id, sysid_print(lsp_id), 15); if (frag) @@ -880,9 +880,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, hostname_get()); lsp_debug("ISIS (%s): Adding dynamic hostname '%s'", - area->area_tag, unix_hostname()); + area->area_tag, 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..37724e17bb 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -431,24 +431,6 @@ struct in_addr newprefix2inaddr(u_char *prefix_start, u_char prefix_masklen) return new_prefix; } -/* - * 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 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/isisd.c b/isisd/isisd.c index 60b9367da9..0283ec3d00 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1440,7 +1440,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(hostname_get(), sysid, 15) == 0) { memcpy(lspid, isis->sysid, diff --git a/lib/command.c b/lib/command.c index 45b5593a3e..2d262c1146 100644 --- a/lib/command.c +++ b/lib/command.c @@ -124,6 +124,23 @@ vector cmdvec = NULL; /* Host information structure. */ struct host host; +/* + * Returns host.name if any, otherwise + * it returns the system hostname. + */ +const char *hostname_get(void) +{ + return host.name; +} + +/* + * Returns unix domainname + */ +const char *domainname_get(void) +{ + return host.domainname; +} + /* Standard command node structures. */ static struct cmd_node auth_node = { AUTH_NODE, "Password: ", @@ -470,8 +487,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 (hostname_get()) + vty_out(vty, "hostname %s\n", hostname_get()); if (host.encrypt) { if (host.password_encrypt) @@ -1403,7 +1420,7 @@ DEFUN (show_version, "Displays zebra version\n") { vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION, - host.name ? host.name : ""); + hostname_get() ? hostname_get() : ""); vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO); vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS); @@ -2496,9 +2513,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(); @@ -2507,7 +2527,12 @@ 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 + host.domainname = XSTRDUP(MTYPE_HOST, names.domainname); +#else + host.domainname = NULL; +#endif host.password = NULL; host.enable = NULL; host.logfile = NULL; @@ -2623,6 +2648,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..92220dd7b9 100644 --- a/lib/command.h +++ b/lib/command.h @@ -41,6 +41,9 @@ struct host { /* Host name of this router. */ char *name; + /* Domain name of this router */ + char *domainname; + /* Password for vty interface. */ char *password; char *password_encrypt; @@ -399,6 +402,8 @@ extern void cmd_exit(struct vty *vty); extern int cmd_list_cmds(struct vty *vty, int do_permute); extern int cmd_hostname_set(const char *hostname); +extern const char *hostname_get(void); +extern const char *domainname_get(void); /* NOT safe for general use; call this only if DEV_BUILD! */ extern void grammar_sandbox_init(void); 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/vty.c b/lib/vty.c index 59a8825357..0caded4a87 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -250,16 +250,9 @@ 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), + hostname_get()); } } diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index f971c171bc..2ac667f0b0 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2879,21 +2879,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), hostname_get()); return buf; } diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index c561b5222f..c331e45886 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -420,10 +420,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 (hostname_get()) { + sprintf(line, "hostname %s", hostname_get()); vtysh_config_parse_line(NULL, line); } if (vtysh_write_integrated == WRITE_INTEGRATED_NO) From 6f9d219ae6cd65c8bdeda34f28805c7380ceed41 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 21 Aug 2017 14:56:06 -0700 Subject: [PATCH 23/27] provide/use API to get hostname/domainname Set default hostname in frr to unix hostname. Provide APIs to get the hostname/domaninanme Use this APIs where needed Signed-off-by: Mitesh Kanjariya --- lib/command.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/command.h b/lib/command.h index 92220dd7b9..70401eced0 100644 --- a/lib/command.h +++ b/lib/command.h @@ -41,7 +41,7 @@ struct host { /* Host name of this router. */ char *name; - /* Domain name of this router */ + /* Domainname of this router */ char *domainname; /* Password for vty interface. */ From 4a48f1b70b5afe6371fc188811c09541afd6008d Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Fri, 25 Aug 2017 15:26:33 -0700 Subject: [PATCH 24/27] lib: Fix make check failures Signed-off-by: Mitesh Kanjariya --- lib/command.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/command.c b/lib/command.c index 2d262c1146..13fee70c62 100644 --- a/lib/command.c +++ b/lib/command.c @@ -130,6 +130,12 @@ struct host host; */ const char *hostname_get(void) { + struct utsname names; + + if (!host.name) { + uname(&names); + host.name = XSTRDUP(MTYPE_HOST, names.nodename); + } return host.name; } @@ -138,6 +144,12 @@ const char *hostname_get(void) */ const char *domainname_get(void) { + struct utsname names; + + if (!host.name || !host.domainname) { + uname(&names); + host.domainname = XSTRDUP(MTYPE_HOST, names.domainname); + } return host.domainname; } From 1f53ef552de070d22a69558baafca8f8c5b9eecd Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Fri, 25 Aug 2017 15:51:16 -0700 Subject: [PATCH 25/27] Fix compilation errors for domainname Signed-off-by: Mitesh Kanjariya --- lib/command.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/command.c b/lib/command.c index 13fee70c62..78d8dbdc62 100644 --- a/lib/command.c +++ b/lib/command.c @@ -147,8 +147,10 @@ const char *domainname_get(void) struct utsname names; if (!host.name || !host.domainname) { +#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME uname(&names); host.domainname = XSTRDUP(MTYPE_HOST, names.domainname); +#endif } return host.domainname; } From 0802e118dd634b37d580effb7e5df4d4c26fa35c Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Fri, 25 Aug 2017 16:36:31 -0700 Subject: [PATCH 26/27] Handle hostname/domainname properly for FreeBSD Signed-off-by: Mitesh Kanjariya --- bgpd/bgpd.c | 10 ++++++---- lib/command.c | 14 -------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index c64ebf1222..8b70c24ac2 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2766,15 +2766,17 @@ static struct bgp *bgp_create(as_t *as, const char *name, XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname); bgp->peer_self->hostname = NULL; } - bgp->peer_self->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, - hostname_get()); + if (hostname_get()) + bgp->peer_self->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, + hostname_get()); if (bgp->peer_self->domainname != NULL) { XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname); bgp->peer_self->domainname = NULL; } - bgp->peer_self->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, - domainname_get()); + if (domainname_get()) + bgp->peer_self->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, + 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); diff --git a/lib/command.c b/lib/command.c index 78d8dbdc62..2d262c1146 100644 --- a/lib/command.c +++ b/lib/command.c @@ -130,12 +130,6 @@ struct host host; */ const char *hostname_get(void) { - struct utsname names; - - if (!host.name) { - uname(&names); - host.name = XSTRDUP(MTYPE_HOST, names.nodename); - } return host.name; } @@ -144,14 +138,6 @@ const char *hostname_get(void) */ const char *domainname_get(void) { - struct utsname names; - - if (!host.name || !host.domainname) { -#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME - uname(&names); - host.domainname = XSTRDUP(MTYPE_HOST, names.domainname); -#endif - } return host.domainname; } From 6b3ee3a0b013e580abbce83ae46e4ed2bcf5f7a7 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 28 Aug 2017 16:52:29 -0700 Subject: [PATCH 27/27] lib: new APIs for get/set system hostname/domainname 1. Change hostname_get to cmd_hostname_get 2. Change domainname_get to cmd_domainname_get 3. New API to set domainname 3. Provide a CLI command to set domainname Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_open.c | 16 +++++++------- bgpd/bgpd.c | 8 +++---- isisd/isis_dynhn.c | 2 +- isisd/isis_lsp.c | 6 +++--- isisd/isis_misc.c | 2 +- isisd/isisd.c | 2 +- lib/command.c | 51 ++++++++++++++++++++++++++++++++++++++------ lib/command.h | 5 +++-- lib/vty.c | 2 +- vtysh/vtysh.c | 2 +- vtysh/vtysh_config.c | 4 ++-- 11 files changed, 70 insertions(+), 30 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 2e0cc2a8d0..5c9ba89a57 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -1440,7 +1440,7 @@ void bgp_open_capability(struct stream *s, struct peer *peer) } /* Hostname capability */ - if (hostname_get()) { + 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 */ @@ -1448,20 +1448,19 @@ 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(hostname_get()); + len = strlen(cmd_hostname_get()); if (len > BGP_MAX_HOSTNAME) len = BGP_MAX_HOSTNAME; stream_putc(s, len); - stream_put(s, hostname_get(), len); - if ((host.domainname) - && (strcmp(host.domainname, "(none)") != 0)) { - len = strlen(host.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, host.domainname, len); + stream_put(s, cmd_domainname_get(), len); } else stream_putc(s, 0); /* 0 length */ @@ -1474,7 +1473,8 @@ void bgp_open_capability(struct stream *s, struct peer *peer) if (bgp_debug_neighbor_events(peer)) zlog_debug( "%s Sending hostname cap with hn = %s, dn = %s", - peer->host, hostname_get(), host.domainname); + peer->host, cmd_hostname_get(), + cmd_domainname_get()); } /* Sending base graceful-restart capability irrespective of the config diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 8b70c24ac2..b6a48c9928 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2766,17 +2766,17 @@ static struct bgp *bgp_create(as_t *as, const char *name, XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname); bgp->peer_self->hostname = NULL; } - if (hostname_get()) + if (cmd_hostname_get()) bgp->peer_self->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, - hostname_get()); + cmd_hostname_get()); if (bgp->peer_self->domainname != NULL) { XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname); bgp->peer_self->domainname = NULL; } - if (domainname_get()) + if (cmd_domainname_get()) bgp->peer_self->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, - domainname_get()); + 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); diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index 40ac1919fd..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), - hostname_get()); + cmd_hostname_get()); return; } diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index bf6968c955..cb979dd0db 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -600,7 +600,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", hostname_get()); + sprintf((char *)id, "%.14s", cmd_hostname_get()); else memcpy(id, sysid_print(lsp_id), 15); if (frag) @@ -880,9 +880,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, hostname_get()); + isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get()); lsp_debug("ISIS (%s): Adding dynamic hostname '%s'", - area->area_tag, hostname_get()); + 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 37724e17bb..0a1d9aaa1a 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -444,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 hostname_get(); + return cmd_hostname_get(); dyn = dynhn_find_by_id(sysid); if (dyn) diff --git a/isisd/isisd.c b/isisd/isisd.c index 0283ec3d00..e654f8557c 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1440,7 +1440,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(hostname_get(), + } else if (strncmp(cmd_hostname_get(), sysid, 15) == 0) { memcpy(lspid, isis->sysid, diff --git a/lib/command.c b/lib/command.c index 2d262c1146..9421fadc0b 100644 --- a/lib/command.c +++ b/lib/command.c @@ -128,7 +128,7 @@ struct host host; * Returns host.name if any, otherwise * it returns the system hostname. */ -const char *hostname_get(void) +const char *cmd_hostname_get(void) { return host.name; } @@ -136,7 +136,7 @@ const char *hostname_get(void) /* * Returns unix domainname */ -const char *domainname_get(void) +const char *cmd_domainname_get(void) { return host.domainname; } @@ -487,8 +487,8 @@ static char *zencrypt(const char *passwd) /* This function write configuration of this host. */ static int config_write_host(struct vty *vty) { - if (hostname_get()) - vty_out(vty, "hostname %s\n", hostname_get()); + if (cmd_hostname_get()) + vty_out(vty, "hostname %s\n", cmd_hostname_get()); if (host.encrypt) { if (host.password_encrypt) @@ -1420,7 +1420,7 @@ DEFUN (show_version, "Displays zebra version\n") { vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION, - hostname_get() ? hostname_get() : ""); + 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); @@ -1754,6 +1754,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); @@ -2529,7 +2563,10 @@ void cmd_init(int terminal) /* Default host value settings. */ host.name = XSTRDUP(MTYPE_HOST, names.nodename); #ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME - host.domainname = XSTRDUP(MTYPE_HOST, names.domainname); + if ((strcmp(names.domainname, "(none)") == 0)) + host.domainname = NULL; + else + host.domainname = XSTRDUP(MTYPE_HOST, names.domainname); #else host.domainname = NULL; #endif @@ -2584,6 +2621,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); if (terminal > 0) { diff --git a/lib/command.h b/lib/command.h index 70401eced0..1c6938523c 100644 --- a/lib/command.h +++ b/lib/command.h @@ -401,9 +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 *hostname_get(void); -extern const char *domainname_get(void); +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/vty.c b/lib/vty.c index 0caded4a87..cec5a916f3 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -252,7 +252,7 @@ static void vty_prompt(struct vty *vty) { if (vty->type == VTY_TERM) { vty_out(vty, cmd_prompt(vty->node), - hostname_get()); + cmd_hostname_get()); } } diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 2ac667f0b0..9939a7fae9 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2881,7 +2881,7 @@ char *vtysh_prompt(void) { static char buf[100]; - snprintf(buf, sizeof buf, cmd_prompt(vty->node), hostname_get()); + snprintf(buf, sizeof buf, cmd_prompt(vty->node), cmd_hostname_get()); return buf; } diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index c331e45886..1ce065fccf 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -421,8 +421,8 @@ void vtysh_config_write() { char line[81]; - if (hostname_get()) { - sprintf(line, "hostname %s", hostname_get()); + if (cmd_hostname_get()) { + sprintf(line, "hostname %s", cmd_hostname_get()); vtysh_config_parse_line(NULL, line); } if (vtysh_write_integrated == WRITE_INTEGRATED_NO)