diff options
57 files changed, 1303 insertions, 371 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 9c23f3caab..92c37fabd2 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -212,6 +212,9 @@ static struct assegment *assegment_append_asns(struct assegment *seg, { as_t *newas; + if (!seg) + return seg; + newas = XREALLOC(MTYPE_AS_SEG_DATA, seg->as, ASSEGMENT_DATA_SIZE(seg->length + num, 1)); @@ -1370,7 +1373,8 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2) while (last && last->next) last = last->next; - last->next = as2->segments; + if (last) + last->next = as2->segments; as2->segments = new; aspath_str_update(as2, false); return as2; @@ -1445,7 +1449,8 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) * bypass the merged seg2, and attach any chain after it * to chain descending from as2's head */ - as2segtail->next = as2seghead->next; + if (as2segtail) + as2segtail->next = as2seghead->next; /* as2->segments is now referenceless and useless */ assegment_free(as2seghead); @@ -2094,3 +2099,110 @@ void aspath_print_all_vty(struct vty *vty) void *))aspath_show_all_iterator, vty); } + +static struct aspath *bgp_aggr_aspath_lookup(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + return hash_lookup(aggregate->aspath_hash, aspath); +} + +static void *bgp_aggr_aspath_hash_alloc(void *p) +{ + struct aspath *ref = (struct aspath *)p; + struct aspath *aspath = NULL; + + aspath = aspath_dup(ref); + return aspath; +} + +static void bgp_aggr_aspath_prepare(struct hash_backet *hb, void *arg) +{ + struct aspath *asmerge = NULL; + struct aspath *hb_aspath = hb->data; + struct aspath **aggr_aspath = arg; + + if (*aggr_aspath) { + asmerge = aspath_aggregate(*aggr_aspath, hb_aspath); + aspath_free(*aggr_aspath); + *aggr_aspath = asmerge; + } else + *aggr_aspath = aspath_dup(hb_aspath); +} + +void bgp_aggr_aspath_remove(void *arg) +{ + struct aspath *aspath = arg; + + aspath_free(aspath); +} + +void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + struct aspath *aggr_aspath = NULL; + + if ((aggregate == NULL) || (aspath == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->aspath_hash == NULL) + aggregate->aspath_hash = hash_create( + aspath_key_make, aspath_cmp, + "BGP Aggregator as-path hash"); + + aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); + if (aggr_aspath == NULL) { + /* Insert as-path into hash. + */ + aggr_aspath = hash_get(aggregate->aspath_hash, aspath, + bgp_aggr_aspath_hash_alloc); + + /* Compute aggregate's as-path. + */ + hash_iterate(aggregate->aspath_hash, + bgp_aggr_aspath_prepare, + &aggregate->aspath); + } + + /* Increment refernce counter. + */ + aggr_aspath->refcnt++; +} + +void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + struct aspath *aggr_aspath = NULL; + struct aspath *ret_aspath = NULL; + + if ((aggregate == NULL) || (aspath == NULL)) + return; + + if (aggregate->aspath_hash == NULL) + return; + + /* Look-up the aspath in the hash. + */ + aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); + if (aggr_aspath) { + aggr_aspath->refcnt--; + + if (aggr_aspath->refcnt == 0) { + ret_aspath = hash_release(aggregate->aspath_hash, + aggr_aspath); + aspath_free(ret_aspath); + + /* Remove aggregate's old as-path. + */ + aspath_free(aggregate->aspath); + aggregate->aspath = NULL; + + /* Compute aggregate's as-path. + */ + hash_iterate(aggregate->aspath_hash, + bgp_aggr_aspath_prepare, + &aggregate->aspath); + } + } +} diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 9c9c687a6b..be5725c1ae 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_ASPATH_H #include "lib/json.h" +#include "bgpd/bgp_route.h" /* AS path segment type. */ #define AS_SET 1 @@ -130,4 +131,10 @@ extern unsigned int aspath_has_as4(struct aspath *); /* For SNMP BGP4PATHATTRASPATHSEGMENT, might be useful for debug */ extern uint8_t *aspath_snmp_pathseg(struct aspath *, size_t *); +extern void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, + struct aspath *aspath); +extern void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, + struct aspath *aspath); +extern void bgp_aggr_aspath_remove(void *arg); + #endif /* _QUAGGA_BGP_ASPATH_H */ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e44424e080..226bf99d2c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -54,6 +54,7 @@ #include "bgp_encap_types.h" #include "bgp_evpn.h" #include "bgp_flowspec_private.h" +#include "bgp_mac.h" /* Attribute strings for logging. */ static const struct message attr_str[] = { @@ -1942,7 +1943,18 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) bgp_attr_evpn_na_flag(attr, &attr->router_flag); /* Extract the Rmac, if any */ - bgp_attr_rmac(attr, &attr->rmac); + if (bgp_attr_rmac(attr, &attr->rmac)) { + if (bgp_debug_update(peer, NULL, NULL, 1) && + bgp_mac_exist(&attr->rmac)) { + char buf1[ETHER_ADDR_STRLEN]; + + zlog_debug("%s: router mac %s is self mac", + __func__, + prefix_mac2str(&attr->rmac, buf1, + sizeof(buf1))); + } + + } return BGP_ATTR_PARSE_PROCEED; } diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index ca04ebf550..15fa322159 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -106,14 +106,14 @@ char *ecom_mac2str(char *ecom_mac) } /* Fetch router-mac from extended community */ -void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) +bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) { int i = 0; struct ecommunity *ecom; ecom = attr->ecommunity; if (!ecom || !ecom->size) - return; + return false; /* If there is a router mac extended community, set RMAC in attr */ for (i = 0; i < ecom->size; i++) { @@ -130,7 +130,9 @@ void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) continue; memcpy(rmac, pnt, ETH_ALEN); + return true; } + return false; } /* diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index b036702151..5b0ce1da28 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -60,7 +60,7 @@ extern void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac); extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, struct prefix *dst); -extern void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); +extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky); extern uint8_t bgp_attr_default_gw(struct attr *attr); diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index d3c5a8ef14..67cd2be214 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -907,3 +907,112 @@ void community_finish(void) hash_free(comhash); comhash = NULL; } + +static struct community *bgp_aggr_community_lookup( + struct bgp_aggregate *aggregate, + struct community *community) +{ + return hash_lookup(aggregate->community_hash, community); +} + +static void *bgp_aggr_communty_hash_alloc(void *p) +{ + struct community *ref = (struct community *)p; + struct community *community = NULL; + + community = community_dup(ref); + return community; +} + +static void bgp_aggr_community_prepare(struct hash_backet *hb, void *arg) +{ + struct community *commerge = NULL; + struct community *hb_community = hb->data; + struct community **aggr_community = arg; + + if (*aggr_community) { + commerge = community_merge(*aggr_community, hb_community); + *aggr_community = community_uniq_sort(commerge); + community_free(&commerge); + } else + *aggr_community = community_dup(hb_community); +} + +void bgp_aggr_community_remove(void *arg) +{ + struct community *community = arg; + + community_free(&community); +} + +void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, + struct community *community) +{ + struct community *aggr_community = NULL; + + if ((aggregate == NULL) || (community == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->community_hash == NULL) + aggregate->community_hash = hash_create( + (unsigned int (*)(void *))community_hash_make, + (bool (*)(const void *, const void *))community_cmp, + "BGP Aggregator community hash"); + + aggr_community = bgp_aggr_community_lookup(aggregate, community); + if (aggr_community == NULL) { + /* Insert community into hash. + */ + aggr_community = hash_get(aggregate->community_hash, community, + bgp_aggr_communty_hash_alloc); + + /* Re-compute aggregate's community. + */ + if (aggregate->community) + community_free(&aggregate->community); + + hash_iterate(aggregate->community_hash, + bgp_aggr_community_prepare, + &aggregate->community); + } + + /* Increment refernce counter. + */ + aggr_community->refcnt++; +} + +void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, + struct community *community) +{ + struct community *aggr_community = NULL; + struct community *ret_comm = NULL; + + if ((aggregate == NULL) || (community == NULL)) + return; + + if (aggregate->community_hash == NULL) + return; + + /* Look-up the community in the hash. + */ + aggr_community = bgp_aggr_community_lookup(aggregate, community); + if (aggr_community) { + aggr_community->refcnt--; + + if (aggr_community->refcnt == 0) { + ret_comm = hash_release(aggregate->community_hash, + aggr_community); + community_free(&ret_comm); + + community_free(&aggregate->community); + + /* Compute aggregate's community. + */ + hash_iterate(aggregate->community_hash, + bgp_aggr_community_prepare, + &aggregate->community); + } + } +} diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index e1545249d7..4ff4d214a5 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_COMMUNITY_H #include "lib/json.h" +#include "bgpd/bgp_route.h" /* Communities attribute. */ struct community { @@ -89,5 +90,10 @@ extern void community_del_val(struct community *, uint32_t *); extern unsigned long community_count(void); extern struct hash *community_hash(void); extern uint32_t community_val_get(struct community *com, int i); +extern void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, + struct community *community); +extern void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, + struct community *community); +extern void bgp_aggr_community_remove(void *arg); #endif /* _QUAGGA_BGP_COMMUNITY_H */ diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 2a8d27ba24..8ef398952d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1023,3 +1023,112 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, return -1; return 0; } + +static struct ecommunity *bgp_aggr_ecommunity_lookup( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + return hash_lookup(aggregate->ecommunity_hash, ecommunity); +} + +static void *bgp_aggr_ecommunty_hash_alloc(void *p) +{ + struct ecommunity *ref = (struct ecommunity *)p; + struct ecommunity *ecommunity = NULL; + + ecommunity = ecommunity_dup(ref); + return ecommunity; +} + +static void bgp_aggr_ecommunity_prepare(struct hash_backet *hb, void *arg) +{ + struct ecommunity *ecommerge = NULL; + struct ecommunity *hb_ecommunity = hb->data; + struct ecommunity **aggr_ecommunity = arg; + + if (*aggr_ecommunity) { + ecommerge = ecommunity_merge(*aggr_ecommunity, hb_ecommunity); + *aggr_ecommunity = ecommunity_uniq_sort(ecommerge); + ecommunity_free(&ecommerge); + } else + *aggr_ecommunity = ecommunity_dup(hb_ecommunity); +} + +void bgp_aggr_ecommunity_remove(void *arg) +{ + struct ecommunity *ecommunity = arg; + + ecommunity_free(&ecommunity); +} + +void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + struct ecommunity *aggr_ecommunity = NULL; + + if ((aggregate == NULL) || (ecommunity == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->ecommunity_hash == NULL) + aggregate->ecommunity_hash = hash_create( + ecommunity_hash_make, ecommunity_cmp, + "BGP Aggregator ecommunity hash"); + + aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity); + if (aggr_ecommunity == NULL) { + /* Insert ecommunity into hash. + */ + aggr_ecommunity = hash_get(aggregate->ecommunity_hash, + ecommunity, + bgp_aggr_ecommunty_hash_alloc); + + /* Re-compute aggregate's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + + hash_iterate(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_prepare, + &aggregate->ecommunity); + } + + /* Increment refernce counter. + */ + aggr_ecommunity->refcnt++; +} + +void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + struct ecommunity *aggr_ecommunity = NULL; + struct ecommunity *ret_ecomm = NULL; + + if ((aggregate == NULL) || (ecommunity == NULL)) + return; + + if (aggregate->ecommunity_hash == NULL) + return; + + /* Look-up the ecommunity in the hash. + */ + aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity); + if (aggr_ecommunity) { + aggr_ecommunity->refcnt--; + + if (aggr_ecommunity->refcnt == 0) { + ret_ecomm = hash_release(aggregate->ecommunity_hash, + aggr_ecommunity); + ecommunity_free(&ret_ecomm); + + ecommunity_free(&aggregate->ecommunity); + + /* Compute aggregate's ecommunity. + */ + hash_iterate(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_prepare, + &aggregate->ecommunity); + } + } +} diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 519991da5a..62b2137753 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -21,6 +21,8 @@ #ifndef _QUAGGA_BGP_ECOMMUNITY_H #define _QUAGGA_BGP_ECOMMUNITY_H +#include "bgpd/bgp_route.h" + /* High-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ENCODE_AS 0x00 #define ECOMMUNITY_ENCODE_IP 0x01 @@ -184,4 +186,12 @@ struct bgp_pbr_entry_action; extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, struct bgp_pbr_entry_action *api); +extern void bgp_compute_aggregate_ecommunity( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_remove_ecommunity_from_aggregate( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_aggr_ecommunity_remove(void *arg); + #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 214aaeac5b..84f3649758 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -3929,7 +3929,7 @@ static int process_type4_route(struct peer *peer, afi_t afi, safi_t safi, */ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, struct attr *attr, uint8_t *pfx, int psize, - uint32_t addpath_id, int withdraw) + uint32_t addpath_id) { struct prefix_rd prd; struct prefix_evpn p; @@ -4015,7 +4015,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, */ /* Process the route. */ - if (!withdraw) + if (attr) ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1, 0, &evpn); @@ -4867,8 +4867,9 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, break; case BGP_EVPN_IP_PREFIX_ROUTE: - if (process_type5_route(peer, afi, safi, attr, pnt, - psize, addpath_id, withdraw)) { + if (process_type5_route(peer, afi, safi, + withdraw ? NULL : attr, pnt, + psize, addpath_id)) { flog_err( EC_BGP_PKT_PROCESS, "%u:%s - Error in processing EVPN type-5 NLRI size %d", @@ -5386,7 +5387,8 @@ static void link_l2vni_hash_to_l3vni(struct hash_bucket *bucket, } int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, - struct in_addr originator_ip, int filter) + struct in_addr originator_ip, int filter, + ifindex_t svi_ifindex) { struct bgp *bgp_vrf = NULL; /* bgp VRF instance */ struct bgp *bgp_def = NULL; /* default bgp instance */ @@ -5434,14 +5436,11 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO); } - /* associate with l3vni */ + /* associate the vrf with l3vni and related parameters */ bgp_vrf->l3vni = l3vni; - - /* set the router mac - to be used in mac-ip routes for this vrf */ memcpy(&bgp_vrf->rmac, rmac, sizeof(struct ethaddr)); - - /* set the originator ip */ bgp_vrf->originator_ip = originator_ip; + bgp_vrf->l3vni_svi_ifindex = svi_ifindex; /* set the right filter - are we using l3vni only for prefix routes? */ if (filter) diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 5c3d4ce3aa..fbf30083e1 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -136,7 +136,8 @@ extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, uint8_t flags, uint32_t seq); extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id, struct ethaddr *rmac, - struct in_addr originator_ip, int filter); + struct in_addr originator_ip, int filter, + ifindex_t svi_ifindex); extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index edc364ec27..44766c9b6e 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -534,3 +534,112 @@ void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr) i++; } } + +static struct lcommunity *bgp_aggr_lcommunity_lookup( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + return hash_lookup(aggregate->lcommunity_hash, lcommunity); +} + +static void *bgp_aggr_lcommunty_hash_alloc(void *p) +{ + struct lcommunity *ref = (struct lcommunity *)p; + struct lcommunity *lcommunity = NULL; + + lcommunity = lcommunity_dup(ref); + return lcommunity; +} + +static void bgp_aggr_lcommunity_prepare(struct hash_backet *hb, void *arg) +{ + struct lcommunity *lcommerge = NULL; + struct lcommunity *hb_lcommunity = hb->data; + struct lcommunity **aggr_lcommunity = arg; + + if (*aggr_lcommunity) { + lcommerge = lcommunity_merge(*aggr_lcommunity, hb_lcommunity); + *aggr_lcommunity = lcommunity_uniq_sort(lcommerge); + lcommunity_free(&lcommerge); + } else + *aggr_lcommunity = lcommunity_dup(hb_lcommunity); +} + +void bgp_aggr_lcommunity_remove(void *arg) +{ + struct lcommunity *lcommunity = arg; + + lcommunity_free(&lcommunity); +} + +void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; + + if ((aggregate == NULL) || (lcommunity == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->lcommunity_hash == NULL) + aggregate->lcommunity_hash = hash_create( + lcommunity_hash_make, lcommunity_cmp, + "BGP Aggregator lcommunity hash"); + + aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity); + if (aggr_lcommunity == NULL) { + /* Insert lcommunity into hash. + */ + aggr_lcommunity = hash_get(aggregate->lcommunity_hash, + lcommunity, + bgp_aggr_lcommunty_hash_alloc); + + /* Re-compute aggregate's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + + hash_iterate(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_prepare, + &aggregate->lcommunity); + } + + /* Increment refernce counter. + */ + aggr_lcommunity->refcnt++; +} + +void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; + struct lcommunity *ret_lcomm = NULL; + + if ((aggregate == NULL) || (lcommunity == NULL)) + return; + + if (aggregate->lcommunity_hash == NULL) + return; + + /* Look-up the lcommunity in the hash. + */ + aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity); + if (aggr_lcommunity) { + aggr_lcommunity->refcnt--; + + if (aggr_lcommunity->refcnt == 0) { + ret_lcomm = hash_release(aggregate->lcommunity_hash, + aggr_lcommunity); + lcommunity_free(&ret_lcomm); + + lcommunity_free(&aggregate->lcommunity); + + /* Compute aggregate's lcommunity. + */ + hash_iterate(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_prepare, + &aggregate->lcommunity); + } + } +} diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h index 23c777d9fd..aa4e8c69fe 100644 --- a/bgpd/bgp_lcommunity.h +++ b/bgpd/bgp_lcommunity.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_LCOMMUNITY_H #include "lib/json.h" +#include "bgpd/bgp_route.h" /* Large Communities value is twelve octets long. */ #define LCOMMUNITY_SIZE 12 @@ -70,4 +71,13 @@ extern int lcommunity_match(const struct lcommunity *, extern char *lcommunity_str(struct lcommunity *, bool make_json); extern int lcommunity_include(struct lcommunity *lcom, uint8_t *ptr); extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr); + +extern void bgp_compute_aggregate_lcommunity( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); +extern void bgp_remove_lcommunity_from_aggregate( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); +extern void bgp_aggr_lcommunity_remove(void *arg); + #endif /* _QUAGGA_BGP_LCOMMUNITY_H */ diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index 4a408df858..49b5854020 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -311,11 +311,35 @@ void bgp_mac_del_mac_entry(struct interface *ifp) bgp_mac_remove_ifp_internal(bsm, ifp->name); } -bool bgp_mac_entry_exists(struct prefix *p) +/* This API checks MAC address against any of local + * assigned (SVIs) MAC address. + * An example: router-mac attribute in any of evpn update + * requires to compare against local mac. + */ +bool bgp_mac_exist(struct ethaddr *mac) { - struct prefix_evpn *pevpn = (struct prefix_evpn *)p; struct bgp_self_mac lookup; struct bgp_self_mac *bsm; + static uint8_t tmp [ETHER_ADDR_STRLEN] = {0}; + + if (memcmp(mac, &tmp, ETH_ALEN) == 0) + return false; + + memcpy(&lookup.macaddr, mac, ETH_ALEN); + bsm = hash_lookup(bm->self_mac_hash, &lookup); + if (!bsm) + return false; + + return true; +} + +/* This API checks EVPN type-2 prefix and comapares + * mac against any of local assigned (SVIs) MAC + * address. + */ +bool bgp_mac_entry_exists(struct prefix *p) +{ + struct prefix_evpn *pevpn = (struct prefix_evpn *)p; if (pevpn->family != AF_EVPN) return false; @@ -323,10 +347,7 @@ bool bgp_mac_entry_exists(struct prefix *p) if (pevpn->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) return false; - memcpy(&lookup.macaddr, &p->u.prefix_evpn.macip_addr.mac, ETH_ALEN); - bsm = hash_lookup(bm->self_mac_hash, &lookup); - if (!bsm) - return false; + return bgp_mac_exist(&p->u.prefix_evpn.macip_addr.mac); return true; } diff --git a/bgpd/bgp_mac.h b/bgpd/bgp_mac.h index 1dd987ef12..68449b574a 100644 --- a/bgpd/bgp_mac.h +++ b/bgpd/bgp_mac.h @@ -37,5 +37,6 @@ void bgp_mac_dump_table(struct vty *vty); * Function to lookup the prefix and see if we have a matching mac */ bool bgp_mac_entry_exists(struct prefix *p); +bool bgp_mac_exist(struct ethaddr *mac); #endif diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 4baac3e57a..765170d1a5 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1092,8 +1092,6 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ */ uint8_t nhfamily = NEXTHOP_FAMILY(path_vpn->attr->mp_nexthop_len); - if (nhfamily != AF_UNSPEC) - static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); memset(&nexthop_orig, 0, sizeof(nexthop_orig)); nexthop_orig.family = nhfamily; @@ -1113,6 +1111,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ static_attr.mp_nexthop_len = path_vpn->attr->mp_nexthop_len; } + static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); break; case AF_INET6: /* save */ diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 3018124f45..7af5827d00 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -49,7 +49,7 @@ So there is many configurable point. First of all we want set each peer whether we send capability negotiation to the peer or not. - Next, if we send capability to the peer we want to set my capabilty + Next, if we send capability to the peer we want to set my capability inforation at each peer. */ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 0fc321bdf3..8359f59a41 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -49,7 +49,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_DYNAMIC_OLD 66 /* Dynamic Capability, deprecated since 2003 */ #define CAPABILITY_CODE_DYNAMIC 67 /* Dynamic Capability */ #define CAPABILITY_CODE_ADDPATH 69 /* Addpath Capability */ -#define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capabilty */ +#define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capability */ #define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */ #define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */ #define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 38047f97ac..90a8f8cec5 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2490,6 +2490,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, bgp_evpn_advertise_type5_route( bgp, &rn->p, new_select->attr, afi, safi); + else + bgp_evpn_withdraw_type5_route( + bgp, &rn->p, afi, safi); } else { bgp_evpn_advertise_type5_route(bgp, &rn->p, @@ -3091,7 +3094,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, goto filtered; } - if (bgp_mac_entry_exists(p)) { + if (bgp_mac_entry_exists(p) || bgp_mac_exist(&attr->rmac)) { reason = "self mac;"; goto filtered; } @@ -3280,7 +3283,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, extra = bgp_path_info_extra_get(pi); if (extra->label != label) { memcpy(&extra->label, label, - num_labels * sizeof(mpls_label_t)); + num_labels * sizeof(mpls_label_t)); extra->num_labels = num_labels; } if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) @@ -3452,7 +3455,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, if (has_valid_label) { extra = bgp_path_info_extra_get(new); if (extra->label != label) { - memcpy(&extra->label, label, num_labels * sizeof(mpls_label_t)); + memcpy(&extra->label, label, + num_labels * sizeof(mpls_label_t)); extra->num_labels = num_labels; } if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) @@ -5570,33 +5574,6 @@ DEFPY(ipv6_bgp_network, label_index ? (uint32_t)label_index : BGP_INVALID_LABEL_INDEX); } -/* Aggreagete address: - - advertise-map Set condition to advertise attribute - as-set Generate AS set path information - attribute-map Set attributes of aggregate - route-map Set parameters of aggregate - summary-only Filter more specific routes from updates - suppress-map Conditionally filter more specific routes from updates - <cr> - */ -struct bgp_aggregate { - /* Summary-only flag. */ - uint8_t summary_only; - - /* AS set generation. */ - uint8_t as_set; - - /* Route-map for aggregated route. */ - struct route_map *map; - - /* Suppress-count. */ - unsigned long count; - - /* SAFI configuration. */ - safi_t safi; -}; - static struct bgp_aggregate *bgp_aggregate_new(void) { return XCALLOC(MTYPE_BGP_AGGREGATE, sizeof(struct bgp_aggregate)); @@ -5722,8 +5699,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, /* Update an aggregate as routes are added/removed from the BGP table */ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, - struct bgp_path_info *pinew, afi_t afi, - safi_t safi, struct bgp_path_info *del, + afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; @@ -5731,13 +5707,9 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, struct bgp_node *rn; uint8_t origin; struct aspath *aspath = NULL; - struct aspath *asmerge = NULL; struct community *community = NULL; - struct community *commerge = NULL; struct ecommunity *ecommunity = NULL; - struct ecommunity *ecommerge = NULL; struct lcommunity *lcommunity = NULL; - struct lcommunity *lcommerge = NULL; struct bgp_path_info *pi; unsigned long match = 0; uint8_t atomic_aggregate = 0; @@ -5766,9 +5738,6 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, if (BGP_PATH_HOLDDOWN(pi)) continue; - if (del && pi == del) - continue; - if (pi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) atomic_aggregate = 1; @@ -5799,8 +5768,18 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, * route MUST have the ORIGIN attribute with the value * EGP. */ - if (origin < pi->attr->origin) - origin = pi->attr->origin; + switch (pi->attr->origin) { + case BGP_ORIGIN_INCOMPLETE: + aggregate->incomplete_origin_count++; + break; + case BGP_ORIGIN_EGP: + aggregate->egp_origin_count++; + break; + default: + /*Do nothing. + */ + break; + } if (!aggregate->as_set) continue; @@ -5809,130 +5788,68 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, * as-set aggregate route generate origin, as path, * and community aggregation. */ - if (aspath) { - asmerge = aspath_aggregate(aspath, - pi->attr->aspath); - aspath_free(aspath); - aspath = asmerge; - } else - aspath = aspath_dup(pi->attr->aspath); - - if (pi->attr->community) { - if (community) { - commerge = community_merge( - community, pi->attr->community); - community = - community_uniq_sort(commerge); - community_free(&commerge); - } else - community = community_dup( - pi->attr->community); - } - - if (pi->attr->ecommunity) { - if (ecommunity) { - ecommerge = ecommunity_merge( - ecommunity, - pi->attr->ecommunity); - ecommunity = - ecommunity_uniq_sort(ecommerge); - ecommunity_free(&ecommerge); - } else - ecommunity = ecommunity_dup( - pi->attr->ecommunity); - } - - if (pi->attr->lcommunity) { - if (lcommunity) { - lcommerge = lcommunity_merge( - lcommunity, - pi->attr->lcommunity); - lcommunity = - lcommunity_uniq_sort(lcommerge); - lcommunity_free(&lcommerge); - } else - lcommunity = lcommunity_dup( - pi->attr->lcommunity); - } + /* Compute aggregate route's as-path. + */ + bgp_compute_aggregate_aspath(aggregate, + pi->attr->aspath); + + /* Compute aggregate route's community. + */ + if (pi->attr->community) + bgp_compute_aggregate_community( + aggregate, + pi->attr->community); + + /* Compute aggregate route's extended community. + */ + if (pi->attr->ecommunity) + bgp_compute_aggregate_ecommunity( + aggregate, + pi->attr->ecommunity); + + /* Compute aggregate route's large community. + */ + if (pi->attr->lcommunity) + bgp_compute_aggregate_lcommunity( + aggregate, + pi->attr->lcommunity); } if (match) bgp_process(bgp, rn, afi, safi); } bgp_unlock_node(top); - if (pinew) { - aggregate->count++; - if (aggregate->summary_only) - (bgp_path_info_extra_get(pinew))->suppress++; + if (aggregate->incomplete_origin_count > 0) + origin = BGP_ORIGIN_INCOMPLETE; + else if (aggregate->egp_origin_count > 0) + origin = BGP_ORIGIN_EGP; - if (origin < pinew->attr->origin) - origin = pinew->attr->origin; + if (aggregate->as_set) { + if (aggregate->aspath) + /* Retrieve aggregate route's as-path. + */ + aspath = aspath_dup(aggregate->aspath); - if (aggregate->as_set) { - if (aspath) { - asmerge = aspath_aggregate(aspath, - pinew->attr->aspath); - aspath_free(aspath); - aspath = asmerge; - } else - aspath = aspath_dup(pinew->attr->aspath); + if (aggregate->community) + /* Retrieve aggregate route's community. + */ + community = community_dup(aggregate->community); - if (pinew->attr->community) { - if (community) { - commerge = community_merge( - community, - pinew->attr->community); - community = - community_uniq_sort(commerge); - community_free(&commerge); - } else - community = community_dup( - pinew->attr->community); - } + if (aggregate->ecommunity) + /* Retrieve aggregate route's ecommunity. + */ + ecommunity = ecommunity_dup(aggregate->ecommunity); - if (pinew->attr->ecommunity) { - if (ecommunity) { - ecommerge = ecommunity_merge( - ecommunity, - pinew->attr->ecommunity); - ecommunity = - ecommunity_uniq_sort(ecommerge); - ecommunity_free(&ecommerge); - } else - ecommunity = ecommunity_dup( - pinew->attr->ecommunity); - } - - if (pinew->attr->lcommunity) { - if (lcommunity) { - lcommerge = lcommunity_merge( - lcommunity, - pinew->attr->lcommunity); - lcommunity = - lcommunity_uniq_sort(lcommerge); - lcommunity_free(&lcommerge); - } else - lcommunity = lcommunity_dup( - pinew->attr->lcommunity); - } - } + if (aggregate->lcommunity) + /* Retrieve aggregate route's lcommunity. + */ + lcommunity = lcommunity_dup(aggregate->lcommunity); } bgp_aggregate_install(bgp, afi, safi, p, origin, aspath, community, ecommunity, lcommunity, atomic_aggregate, aggregate); - - if (aggregate->count == 0) { - if (aspath) - aspath_free(aspath); - if (community) - community_free(&community); - if (ecommunity) - ecommunity_free(&ecommunity); - if (lcommunity) - lcommunity_free(&lcommunity); - } } static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, @@ -5971,6 +5888,41 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, } } aggregate->count--; + + if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE) + aggregate->incomplete_origin_count--; + else if (pi->attr->origin == BGP_ORIGIN_EGP) + aggregate->egp_origin_count--; + + if (aggregate->as_set) { + /* Remove as-path from aggregate. + */ + bgp_remove_aspath_from_aggregate( + aggregate, + pi->attr->aspath); + + if (pi->attr->community) + /* Remove community from aggregate. + */ + bgp_remove_community_from_aggregate( + aggregate, + pi->attr->community); + + if (pi->attr->ecommunity) + /* Remove ecommunity from aggregate. + */ + bgp_remove_ecommunity_from_aggregate( + aggregate, + pi->attr->ecommunity); + + if (pi->attr->lcommunity) + /* Remove lcommunity from aggregate. + */ + bgp_remove_lcommunity_from_aggregate( + aggregate, + pi->attr->lcommunity); + } + } /* If this node was suppressed, process the change. */ @@ -5980,6 +5932,210 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, bgp_unlock_node(top); } +static void bgp_add_route_to_aggregate(struct bgp *bgp, struct prefix *aggr_p, + struct bgp_path_info *pinew, afi_t afi, + safi_t safi, + struct bgp_aggregate *aggregate) +{ + uint8_t origin; + struct aspath *aspath = NULL; + uint8_t atomic_aggregate = 0; + struct community *community = NULL; + struct ecommunity *ecommunity = NULL; + struct lcommunity *lcommunity = NULL; + + /* ORIGIN attribute: If at least one route among routes that are + * aggregated has ORIGIN with the value INCOMPLETE, then the + * aggregated route must have the ORIGIN attribute with the value + * INCOMPLETE. Otherwise, if at least one route among routes that + * are aggregated has ORIGIN with the value EGP, then the aggregated + * route must have the origin attribute with the value EGP. In all + * other case the value of the ORIGIN attribute of the aggregated + * route is INTERNAL. + */ + origin = BGP_ORIGIN_IGP; + + aggregate->count++; + + if (aggregate->summary_only) + (bgp_path_info_extra_get(pinew))->suppress++; + + switch (pinew->attr->origin) { + case BGP_ORIGIN_INCOMPLETE: + aggregate->incomplete_origin_count++; + break; + case BGP_ORIGIN_EGP: + aggregate->egp_origin_count++; + break; + default: + /* Do nothing. + */ + break; + } + + if (aggregate->incomplete_origin_count > 0) + origin = BGP_ORIGIN_INCOMPLETE; + else if (aggregate->egp_origin_count > 0) + origin = BGP_ORIGIN_EGP; + + if (aggregate->as_set) { + /* Compute aggregate route's as-path. + */ + bgp_compute_aggregate_aspath(aggregate, + pinew->attr->aspath); + + /* Compute aggregate route's community. + */ + if (pinew->attr->community) + bgp_compute_aggregate_community( + aggregate, + pinew->attr->community); + + /* Compute aggregate route's extended community. + */ + if (pinew->attr->ecommunity) + bgp_compute_aggregate_ecommunity( + aggregate, + pinew->attr->ecommunity); + + /* Compute aggregate route's large community. + */ + if (pinew->attr->lcommunity) + bgp_compute_aggregate_lcommunity( + aggregate, + pinew->attr->lcommunity); + + /* Retrieve aggregate route's as-path. + */ + if (aggregate->aspath) + aspath = aspath_dup(aggregate->aspath); + + /* Retrieve aggregate route's community. + */ + if (aggregate->community) + community = community_dup(aggregate->community); + + /* Retrieve aggregate route's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity = ecommunity_dup(aggregate->ecommunity); + + /* Retrieve aggregate route's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity = lcommunity_dup(aggregate->lcommunity); + } + + bgp_aggregate_install(bgp, afi, safi, aggr_p, origin, + aspath, community, ecommunity, + lcommunity, atomic_aggregate, aggregate); +} + +static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, + safi_t safi, + struct bgp_path_info *pi, + struct bgp_aggregate *aggregate, + struct prefix *aggr_p) +{ + uint8_t origin; + struct aspath *aspath = NULL; + uint8_t atomic_aggregate = 0; + struct community *community = NULL; + struct ecommunity *ecommunity = NULL; + struct lcommunity *lcommunity = NULL; + unsigned long match = 0; + + if (BGP_PATH_HOLDDOWN(pi)) + return; + + if (pi->sub_type == BGP_ROUTE_AGGREGATE) + return; + + if (aggregate->summary_only + && pi->extra + && pi->extra->suppress > 0) { + pi->extra->suppress--; + + if (pi->extra->suppress == 0) { + bgp_path_info_set_flag(pi->net, pi, + BGP_PATH_ATTR_CHANGED); + match++; + } + } + + if (aggregate->count > 0) + aggregate->count--; + + if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE) + aggregate->incomplete_origin_count--; + else if (pi->attr->origin == BGP_ORIGIN_EGP) + aggregate->egp_origin_count--; + + if (aggregate->as_set) { + /* Remove as-path from aggregate. + */ + bgp_remove_aspath_from_aggregate(aggregate, + pi->attr->aspath); + + if (pi->attr->community) + /* Remove community from aggregate. + */ + bgp_remove_community_from_aggregate( + aggregate, + pi->attr->community); + + if (pi->attr->ecommunity) + /* Remove ecommunity from aggregate. + */ + bgp_remove_ecommunity_from_aggregate( + aggregate, + pi->attr->ecommunity); + + if (pi->attr->lcommunity) + /* Remove lcommunity from aggregate. + */ + bgp_remove_lcommunity_from_aggregate( + aggregate, + pi->attr->lcommunity); + } + + /* If this node was suppressed, process the change. */ + if (match) + bgp_process(bgp, pi->net, afi, safi); + + origin = BGP_ORIGIN_IGP; + if (aggregate->incomplete_origin_count > 0) + origin = BGP_ORIGIN_INCOMPLETE; + else if (aggregate->egp_origin_count > 0) + origin = BGP_ORIGIN_EGP; + + if (aggregate->as_set) { + /* Retrieve aggregate route's as-path. + */ + if (aggregate->aspath) + aspath = aspath_dup(aggregate->aspath); + + /* Retrieve aggregate route's community. + */ + if (aggregate->community) + community = community_dup(aggregate->community); + + /* Retrieve aggregate route's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity = ecommunity_dup(aggregate->ecommunity); + + /* Retrieve aggregate route's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity = lcommunity_dup(aggregate->lcommunity); + } + + bgp_aggregate_install(bgp, afi, safi, aggr_p, origin, + aspath, community, ecommunity, + lcommunity, atomic_aggregate, aggregate); +} + void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, struct bgp_path_info *pi, afi_t afi, safi_t safi) { @@ -6006,9 +6162,8 @@ void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) { aggregate = bgp_node_get_bgp_aggregate_info(rn); if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) { - bgp_aggregate_delete(bgp, &rn->p, afi, safi, aggregate); - bgp_aggregate_route(bgp, &rn->p, pi, afi, safi, NULL, - aggregate); + bgp_add_route_to_aggregate(bgp, &rn->p, pi, afi, + safi, aggregate); } } bgp_unlock_node(child); @@ -6037,9 +6192,8 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) { aggregate = bgp_node_get_bgp_aggregate_info(rn); if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) { - bgp_aggregate_delete(bgp, &rn->p, afi, safi, aggregate); - bgp_aggregate_route(bgp, &rn->p, NULL, afi, safi, del, - aggregate); + bgp_remove_route_from_aggregate(bgp, afi, safi, + del, aggregate, &rn->p); } } bgp_unlock_node(child); @@ -6081,6 +6235,59 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, /* Unlock aggregate address configuration. */ bgp_node_set_bgp_aggregate_info(rn, NULL); + + if (aggregate->community) + community_free(&aggregate->community); + + if (aggregate->community_hash) { + /* Delete all communities in the hash. + */ + hash_clean(aggregate->community_hash, + bgp_aggr_community_remove); + /* Free up the community_hash. + */ + hash_free(aggregate->community_hash); + } + + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + + if (aggregate->ecommunity_hash) { + /* Delete all ecommunities in the hash. + */ + hash_clean(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_remove); + /* Free up the ecommunity_hash. + */ + hash_free(aggregate->ecommunity_hash); + } + + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + + if (aggregate->lcommunity_hash) { + /* Delete all lcommunities in the hash. + */ + hash_clean(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_remove); + /* Free up the lcommunity_hash. + */ + hash_free(aggregate->lcommunity_hash); + } + + if (aggregate->aspath) + aspath_free(aggregate->aspath); + + if (aggregate->aspath_hash) { + /* Delete all as-paths in the hash. + */ + hash_clean(aggregate->aspath_hash, + bgp_aggr_aspath_remove); + /* Free up the aspath_hash. + */ + hash_free(aggregate->aspath_hash); + } + bgp_aggregate_free(aggregate); bgp_unlock_node(rn); bgp_unlock_node(rn); @@ -6134,7 +6341,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, bgp_node_set_bgp_aggregate_info(rn, aggregate); /* Aggregate address insert into BGP routing table. */ - bgp_aggregate_route(bgp, &p, NULL, afi, safi, NULL, aggregate); + bgp_aggregate_route(bgp, &p, afi, safi, aggregate); return CMD_SUCCESS; } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 85325a93cf..04a3c85f2c 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -272,6 +272,71 @@ struct bgp_static { struct prefix gatewayIp; }; +/* Aggreagete address: + * + * advertise-map Set condition to advertise attribute + * as-set Generate AS set path information + * attribute-map Set attributes of aggregate + * route-map Set parameters of aggregate + * summary-only Filter more specific routes from updates + * suppress-map Conditionally filter more specific routes from updates + * <cr> + */ +struct bgp_aggregate { + /* Summary-only flag. */ + uint8_t summary_only; + + /* AS set generation. */ + uint8_t as_set; + + /* Route-map for aggregated route. */ + struct route_map *map; + + /* Suppress-count. */ + unsigned long count; + + /* Count of routes of origin type incomplete under this aggregate. */ + unsigned long incomplete_origin_count; + + /* Count of routes of origin type egp under this aggregate. */ + unsigned long egp_origin_count; + + /* Hash containing the communities of all the + * routes under this aggregate. + */ + struct hash *community_hash; + + /* Hash containing the extended communities of all the + * routes under this aggregate. + */ + struct hash *ecommunity_hash; + + /* Hash containing the large communities of all the + * routes under this aggregate. + */ + struct hash *lcommunity_hash; + + /* Hash containing the AS-Path of all the + * routes under this aggregate. + */ + struct hash *aspath_hash; + + /* Aggregate route's community. */ + struct community *community; + + /* Aggregate route's extended community. */ + struct ecommunity *ecommunity; + + /* Aggregate route's large community. */ + struct lcommunity *lcommunity; + + /* Aggregate route's as-path. */ + struct aspath *aspath; + + /* SAFI configuration. */ + safi_t safi; +}; + #define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \ ((nhlen) < IPV4_MAX_BYTELEN \ ? 0 \ @@ -279,7 +344,10 @@ struct bgp_static { #define BGP_ATTR_NEXTHOP_AFI_IP6(attr) \ (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) \ - && ((attr)->mp_nexthop_len == 16 || (attr)->mp_nexthop_len == 32)) + && ((attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL \ + || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL \ + || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL \ + || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)) #define BGP_PATH_COUNTABLE(BI) \ (!CHECK_FLAG((BI)->flags, BGP_PATH_HISTORY) \ && !CHECK_FLAG((BI)->flags, BGP_PATH_REMOVED)) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index de24458671..d426e65c53 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7163,7 +7163,7 @@ DEFUN_NOSH (address_family_vpnv6, vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } -#endif +#endif /* KEEP_OLD_VPN_COMMANDS */ DEFUN_NOSH (address_family_evpn, address_family_evpn_cmd, diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 1df5f642b3..5f0b20e029 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -945,14 +945,17 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex) struct in6_addr *nexthop = NULL; /* Only global address nexthop exists. */ - if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) { + if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL + || path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL) { nexthop = &path->attr->mp_nexthop_global; if (IN6_IS_ADDR_LINKLOCAL(nexthop)) *ifindex = path->attr->nh_ifindex; } /* If both global and link-local address present. */ - if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL + || path->attr->mp_nexthop_len + == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ if (path->attr->mp_nexthop_prefer_global) { nexthop = &path->attr->mp_nexthop_global; @@ -1111,20 +1114,24 @@ int bgp_zebra_get_table_range(uint32_t chunk_size, } static int update_ipv4nh_for_route_install(int nh_othervrf, + struct bgp *nh_bgp, struct in_addr *nexthop, struct attr *attr, bool is_evpn, struct zapi_nexthop *api_nh) { api_nh->gate.ipv4 = *nexthop; + api_nh->vrf_id = nh_bgp->vrf_id; /* Need to set fields appropriately for EVPN routes imported into * a VRF (which are programmed as onlink on l3-vni SVI) as well as * connected routes leaked into a VRF. */ - if (is_evpn) + if (is_evpn) { api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; - else if (nh_othervrf && + api_nh->onlink = true; + api_nh->ifindex = nh_bgp->l3vni_svi_ifindex; + } else if (nh_othervrf && api_nh->gate.ipv4.s_addr == INADDR_ANY) { api_nh->type = NEXTHOP_TYPE_IFINDEX; api_nh->ifindex = attr->nh_ifindex; @@ -1135,7 +1142,8 @@ static int update_ipv4nh_for_route_install(int nh_othervrf, } static int -update_ipv6nh_for_route_install(int nh_othervrf, struct in6_addr *nexthop, +update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, + struct in6_addr *nexthop, ifindex_t ifindex, struct bgp_path_info *pi, struct bgp_path_info *best_pi, bool is_evpn, struct zapi_nexthop *api_nh) @@ -1143,10 +1151,13 @@ update_ipv6nh_for_route_install(int nh_othervrf, struct in6_addr *nexthop, struct attr *attr; attr = pi->attr; + api_nh->vrf_id = nh_bgp->vrf_id; - if (is_evpn) + if (is_evpn) { api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; - else if (nh_othervrf) { + api_nh->onlink = true; + api_nh->ifindex = nh_bgp->l3vni_svi_ifindex; + } else if (nh_othervrf) { if (IN6_IS_ADDR_UNSPECIFIED(nexthop)) { api_nh->type = NEXTHOP_TYPE_IFINDEX; api_nh->ifindex = attr->nh_ifindex; @@ -1297,8 +1308,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, continue; api_nh = &api.nexthops[valid_nh_count]; - api_nh->vrf_id = nh_othervrf ? info->extra->bgp_orig->vrf_id - : bgp->vrf_id; if (nh_family == AF_INET) { if (bgp_debug_zebra(&api.prefix)) { if (mpinfo->extra) { @@ -1338,6 +1347,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, nh_updated = update_ipv4nh_for_route_install( nh_othervrf, + nh_othervrf ? + info->extra->bgp_orig : bgp, &mpinfo_cp->attr->nexthop, mpinfo_cp->attr, is_evpn, api_nh); } else { @@ -1372,7 +1383,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, nexthop = bgp_path_info_to_ipv6_nexthop(mpinfo_cp, &ifindex); nh_updated = update_ipv6nh_for_route_install( - nh_othervrf, nexthop, ifindex, + nh_othervrf, nh_othervrf ? + info->extra->bgp_orig : bgp, + nexthop, ifindex, mpinfo, info, is_evpn, api_nh); } @@ -2483,6 +2496,7 @@ static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient, struct ethaddr rmac; struct in_addr originator_ip; struct stream *s; + ifindex_t svi_ifindex; memset(&rmac, 0, sizeof(struct ethaddr)); memset(&originator_ip, 0, sizeof(struct in_addr)); @@ -2492,20 +2506,24 @@ static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient, stream_get(&rmac, s, sizeof(struct ethaddr)); originator_ip.s_addr = stream_get_ipv4(s); stream_get(&filter, s, sizeof(int)); - } + svi_ifindex = stream_getl(s); - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s filter %s", - (cmd == ZEBRA_L3VNI_ADD) ? "add" : "del", - vrf_id_to_name(vrf_id), l3vni, - prefix_mac2str(&rmac, buf, sizeof(buf)), - filter ? "prefix-routes-only" : "none"); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Rx L3-VNI ADD VRF %s VNI %u RMAC %s filter %s svi-if %u", + vrf_id_to_name(vrf_id), l3vni, + prefix_mac2str(&rmac, buf, sizeof(buf)), + filter ? "prefix-routes-only" : "none", + svi_ifindex); - if (cmd == ZEBRA_L3VNI_ADD) bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip, - filter); - else + filter, svi_ifindex); + } else { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Rx L3-VNI DEL VRF %s VNI %u", + vrf_id_to_name(vrf_id), l3vni); + bgp_evpn_local_l3vni_del(l3vni, vrf_id); + } return 0; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 8e397f0c0e..d99b402e28 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3799,6 +3799,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset}, {PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset}, {PEER_FLAG_ENFORCE_FIRST_AS, 0, peer_change_reset_in}, + {PEER_FLAG_IFPEER_V6ONLY, 0, peer_change_reset}, {PEER_FLAG_ROUTEADV, 0, peer_change_none}, {PEER_FLAG_TIMER, 0, peer_change_none}, {PEER_FLAG_TIMER_CONNECT, 0, peer_change_none}, diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index dde1501d30..c7d137c76c 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -517,6 +517,9 @@ struct bgp { /* originator ip - to be used as NH for type-5 routes */ struct in_addr originator_ip; + /* SVI associated with the L3-VNI corresponding to this vrf */ + ifindex_t l3vni_svi_ifindex; + /* vrf flags */ uint32_t vrf_flags; #define BGP_VRF_AUTO (1 << 0) diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 55775f384f..93729c1476 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -2190,7 +2190,7 @@ static void rfapiItBiIndexDump(struct agg_node *rn) prefix2str(&k->extra->vnc.import.aux_prefix, buf_aux_pfx, sizeof(buf_aux_pfx)); } else - strncpy(buf_aux_pfx, "(none)", PREFIX_STRLEN); + strlcpy(buf_aux_pfx, "(none)", sizeof(buf_aux_pfx)); vnc_zlog_debug_verbose("bpi %p, peer %p, rd %s, aux_prefix %s", k, k->peer, buf, buf_aux_pfx); @@ -2221,7 +2221,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch( prefix2str(aux_prefix, buf_aux_pfx, sizeof(buf_aux_pfx)); } else - strncpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx)); + strlcpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx)); vnc_zlog_debug_verbose("%s want prd=%s, peer=%p, aux_prefix=%s", __func__, diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index b19b383e65..3db59a838b 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -211,10 +211,7 @@ int main(int argc, char **argv, char **envp) /*eigrp_route_map_init(); route_map_add_hook (eigrp_rmap_update); route_map_delete_hook (eigrp_rmap_update);*/ - /*if_rmap_init (EIGRP_NODE); - if_rmap_hook_add (eigrp_if_rmap_update); - if_rmap_hook_delete (eigrp_if_rmap_update);*/ - + /*if_rmap_init (EIGRP_NODE); */ /* Distribute list install. */ distribute_list_init(EIGRP_NODE); diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c index 69d947e59f..93f8b6f90e 100644 --- a/eigrpd/eigrpd.c +++ b/eigrpd/eigrpd.c @@ -206,6 +206,13 @@ static struct eigrp *eigrp_new(const char *AS) eigrp_distribute_update); distribute_list_delete_hook(eigrp->distribute_ctx, eigrp_distribute_update); + + /* + eigrp->if_rmap_ctx = if_rmap_ctx_create( + VRF_DEFAULT_NAME); + if_rmap_hook_add (eigrp_if_rmap_update); + if_rmap_hook_delete (eigrp_if_rmap_update); + */ QOBJ_REG(eigrp, eigrp); return eigrp; } diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 36d4a0d7c0..8377638b92 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1305,8 +1305,8 @@ ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit) return ferr_ok(); } -static int isis_circuit_passwd_set(struct isis_circuit *circuit, - uint8_t passwd_type, const char *passwd) +ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit, + uint8_t passwd_type, const char *passwd) { int len; @@ -1319,7 +1319,8 @@ static int isis_circuit_passwd_set(struct isis_circuit *circuit, "circuit password too long (max 254 chars)"); circuit->passwd.len = len; - strncpy((char *)circuit->passwd.passwd, passwd, 255); + strlcpy((char *)circuit->passwd.passwd, passwd, + sizeof(circuit->passwd.passwd)); circuit->passwd.type = passwd_type; return ferr_ok(); } diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 73ead8f7da..e0ea4f78b4 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -190,6 +190,8 @@ ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level, int metric); ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit); +ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit, + uint8_t passwd_type, const char *passwd); ferr_r isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit, const char *passwd); ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index 3364a9f0be..2d1d6f5927 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -2092,8 +2092,8 @@ lib_interface_isis_password_password_modify(enum nb_event event, password = yang_dnode_get_string(dnode, NULL); circuit = yang_dnode_get_entry(dnode, true); - circuit->passwd.len = strlen(password); - strncpy((char *)circuit->passwd.passwd, password, 255); + + isis_circuit_passwd_set(circuit, circuit->passwd.type, password); return NB_OK; } diff --git a/isisd/isisd.c b/isisd/isisd.c index 13cd510dd1..ad02220438 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1363,7 +1363,7 @@ struct isis_lsp *lsp_for_arg(const char *argv, dict_t *lspdb) * xxxx.xxxx.xxxx */ if (argv) - strncpy(sysid, argv, 254); + strlcpy(sysid, argv, sizeof(sysid)); if (argv && strlen(argv) > 3) { pos = argv + strlen(argv) - 3; if (strncmp(pos, "-", 1) == 0) { @@ -1639,7 +1639,8 @@ static int isis_area_passwd_set(struct isis_area *area, int level, return -1; modified.len = len; - strncpy((char *)modified.passwd, passwd, 255); + strlcpy((char *)modified.passwd, passwd, + sizeof(modified.passwd)); modified.type = passwd_type; modified.snp_auth = snp_auth; } diff --git a/lib/event_counter.c b/lib/event_counter.c index c520937a38..57dbfb5fd1 100644 --- a/lib/event_counter.c +++ b/lib/event_counter.c @@ -62,7 +62,7 @@ const char *event_counter_format(const struct event_counter *counter) || strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %T %z", last_change) == 0) { - strncpy(timebuf, "???", sizeof(timebuf)); + strlcpy(timebuf, "???", sizeof(timebuf)); } snprintf(rv, sizeof(rv), "%5llu last: %s", counter->count, diff --git a/lib/if_rmap.c b/lib/if_rmap.c index f8e500f43d..955c1417c4 100644 --- a/lib/if_rmap.c +++ b/lib/if_rmap.c @@ -26,14 +26,12 @@ #include "if.h" #include "if_rmap.h" +DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container") +DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME, "Interface route map container name") DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map") DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name") -struct hash *ifrmaphash; - -/* Hook functions. */ -static void (*if_rmap_add_hook)(struct if_rmap *) = NULL; -static void (*if_rmap_delete_hook)(struct if_rmap *) = NULL; +struct list *if_rmap_ctx_list; static struct if_rmap *if_rmap_new(void) { @@ -54,7 +52,7 @@ static void if_rmap_free(struct if_rmap *if_rmap) XFREE(MTYPE_IF_RMAP, if_rmap); } -struct if_rmap *if_rmap_lookup(const char *ifname) +struct if_rmap *if_rmap_lookup(struct if_rmap_ctx *ctx, const char *ifname) { struct if_rmap key; struct if_rmap *if_rmap; @@ -62,21 +60,25 @@ struct if_rmap *if_rmap_lookup(const char *ifname) /* temporary copy */ key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL; - if_rmap = hash_lookup(ifrmaphash, &key); + if_rmap = hash_lookup(ctx->ifrmaphash, &key); XFREE(MTYPE_IF_RMAP_NAME, key.ifname); return if_rmap; } -void if_rmap_hook_add(void (*func)(struct if_rmap *)) +void if_rmap_hook_add(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)) { - if_rmap_add_hook = func; + ctx->if_rmap_add_hook = func; } -void if_rmap_hook_delete(void (*func)(struct if_rmap *)) +void if_rmap_hook_delete(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)) { - if_rmap_delete_hook = func; + ctx->if_rmap_delete_hook = func; } static void *if_rmap_hash_alloc(void *arg) @@ -90,7 +92,7 @@ static void *if_rmap_hash_alloc(void *arg) return if_rmap; } -static struct if_rmap *if_rmap_get(const char *ifname) +static struct if_rmap *if_rmap_get(struct if_rmap_ctx *ctx, const char *ifname) { struct if_rmap key; struct if_rmap *ret; @@ -98,7 +100,7 @@ static struct if_rmap *if_rmap_get(const char *ifname) /* temporary copy */ key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL; - ret = hash_get(ifrmaphash, &key, if_rmap_hash_alloc); + ret = hash_get(ctx->ifrmaphash, &key, if_rmap_hash_alloc); XFREE(MTYPE_IF_RMAP_NAME, key.ifname); @@ -120,12 +122,13 @@ static bool if_rmap_hash_cmp(const void *arg1, const void *arg2) return strcmp(if_rmap1->ifname, if_rmap2->ifname) == 0; } -static struct if_rmap *if_rmap_set(const char *ifname, enum if_rmap_type type, +static struct if_rmap *if_rmap_set(struct if_rmap_ctx *ctx, + const char *ifname, enum if_rmap_type type, const char *routemap_name) { struct if_rmap *if_rmap; - if_rmap = if_rmap_get(ifname); + if_rmap = if_rmap_get(ctx, ifname); if (type == IF_RMAP_IN) { XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); @@ -138,18 +141,19 @@ static struct if_rmap *if_rmap_set(const char *ifname, enum if_rmap_type type, XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name); } - if (if_rmap_add_hook) - (*if_rmap_add_hook)(if_rmap); + if (ctx->if_rmap_add_hook) + (ctx->if_rmap_add_hook)(ctx, if_rmap); return if_rmap; } -static int if_rmap_unset(const char *ifname, enum if_rmap_type type, +static int if_rmap_unset(struct if_rmap_ctx *ctx, + const char *ifname, enum if_rmap_type type, const char *routemap_name) { struct if_rmap *if_rmap; - if_rmap = if_rmap_lookup(ifname); + if_rmap = if_rmap_lookup(ctx, ifname); if (!if_rmap) return 0; @@ -173,12 +177,12 @@ static int if_rmap_unset(const char *ifname, enum if_rmap_type type, if_rmap->routemap[IF_RMAP_OUT] = NULL; } - if (if_rmap_delete_hook) - (*if_rmap_delete_hook)(if_rmap); + if (ctx->if_rmap_delete_hook) + ctx->if_rmap_delete_hook(ctx, if_rmap); if (if_rmap->routemap[IF_RMAP_IN] == NULL && if_rmap->routemap[IF_RMAP_OUT] == NULL) { - hash_release(ifrmaphash, if_rmap); + hash_release(ctx->ifrmaphash, if_rmap); if_rmap_free(if_rmap); } @@ -198,6 +202,8 @@ DEFUN (if_rmap, int idx_in_out = 2; int idx_ifname = 3; enum if_rmap_type type; + struct if_rmap_ctx *ctx = + (struct if_rmap_ctx *)listnode_head(if_rmap_ctx_list); if (strncmp(argv[idx_in_out]->text, "in", 1) == 0) type = IF_RMAP_IN; @@ -208,7 +214,8 @@ DEFUN (if_rmap, return CMD_WARNING_CONFIG_FAILED; } - if_rmap_set(argv[idx_ifname]->arg, type, argv[idx_rmap_name]->arg); + if_rmap_set(ctx, argv[idx_ifname]->arg, + type, argv[idx_rmap_name]->arg); return CMD_SUCCESS; } @@ -228,6 +235,8 @@ DEFUN (no_if_rmap, int idx_ifname = 4; int ret; enum if_rmap_type type; + struct if_rmap_ctx *ctx = + (struct if_rmap_ctx *)listnode_head(if_rmap_ctx_list); if (strncmp(argv[idx_in_out]->arg, "i", 1) == 0) type = IF_RMAP_IN; @@ -238,7 +247,7 @@ DEFUN (no_if_rmap, return CMD_WARNING_CONFIG_FAILED; } - ret = if_rmap_unset(argv[idx_ifname]->arg, type, + ret = if_rmap_unset(ctx, argv[idx_ifname]->arg, type, argv[idx_routemap_name]->arg); if (!ret) { vty_out(vty, "route-map doesn't exist\n"); @@ -249,11 +258,13 @@ DEFUN (no_if_rmap, /* Configuration write function. */ -int config_write_if_rmap(struct vty *vty) +int config_write_if_rmap(struct vty *vty, + struct if_rmap_ctx *ctx) { unsigned int i; struct hash_bucket *mp; int write = 0; + struct hash *ifrmaphash = ctx->ifrmaphash; for (i = 0; i < ifrmaphash->size; i++) for (mp = ifrmaphash->index[i]; mp; mp = mp->next) { @@ -278,18 +289,44 @@ int config_write_if_rmap(struct vty *vty) return write; } -void if_rmap_reset(void) +void if_rmap_ctx_delete(struct if_rmap_ctx *ctx) +{ + hash_clean(ctx->ifrmaphash, (void (*)(void *))if_rmap_free); + if (ctx->name) + XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx); + XFREE(MTYPE_IF_RMAP_CTX, ctx); +} + +/* name is optional: either vrf name, or other */ +struct if_rmap_ctx *if_rmap_ctx_create(const char *name) { - hash_clean(ifrmaphash, (void (*)(void *))if_rmap_free); + struct if_rmap_ctx *ctx; + + ctx = XCALLOC(MTYPE_IF_RMAP_CTX, sizeof(struct if_rmap_ctx)); + + if (ctx->name) + ctx->name = XSTRDUP(MTYPE_IF_RMAP_CTX_NAME, name); + ctx->ifrmaphash = hash_create_size(4, if_rmap_hash_make, if_rmap_hash_cmp, + "Interface Route-Map Hash"); + if (!if_rmap_ctx_list) + if_rmap_ctx_list = list_new(); + listnode_add(if_rmap_ctx_list, ctx); + return ctx; } void if_rmap_init(int node) { - ifrmaphash = hash_create_size(4, if_rmap_hash_make, if_rmap_hash_cmp, - "Interface Route-Map Hash"); if (node == RIPNG_NODE) { } else if (node == RIP_NODE) { install_element(RIP_NODE, &if_rmap_cmd); install_element(RIP_NODE, &no_if_rmap_cmd); } + if_rmap_ctx_list = list_new(); +} + +void if_rmap_terminate(void) +{ + if (!if_rmap_ctx_list) + return; + list_delete(&if_rmap_ctx_list); } diff --git a/lib/if_rmap.h b/lib/if_rmap.h index 8dded2cb48..dfc7298823 100644 --- a/lib/if_rmap.h +++ b/lib/if_rmap.h @@ -34,12 +34,33 @@ struct if_rmap { char *routemap[IF_RMAP_MAX]; }; -extern void if_rmap_init(int); -extern void if_rmap_reset(void); -extern void if_rmap_hook_add(void (*)(struct if_rmap *)); -extern void if_rmap_hook_delete(void (*)(struct if_rmap *)); -extern struct if_rmap *if_rmap_lookup(const char *); -extern int config_write_if_rmap(struct vty *); +struct if_rmap_ctx { + /* if_rmap */ + struct hash *ifrmaphash; + + /* Hook functions. */ + void (*if_rmap_add_hook)(struct if_rmap_ctx *ctx, + struct if_rmap *ifrmap); + void (*if_rmap_delete_hook)(struct if_rmap_ctx *ctx, + struct if_rmap *ifrmap); + + /* naming information */ + char *name; +}; + +extern struct if_rmap_ctx *if_rmap_ctx_create(const char *name); +extern void if_rmap_ctx_delete(struct if_rmap_ctx *ctx); +extern void if_rmap_init(int node); +extern void if_rmap_terminate(void); +void if_rmap_hook_add(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)); +void if_rmap_hook_delete(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)); +extern struct if_rmap *if_rmap_lookup(struct if_rmap_ctx *ctx, + const char *ifname); +extern int config_write_if_rmap(struct vty *, struct if_rmap_ctx *ctx); #ifdef __cplusplus } diff --git a/lib/nexthop.h b/lib/nexthop.h index c79ec590a8..fd27ca207b 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -83,7 +83,6 @@ struct nexthop { #define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */ #define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */ #define NEXTHOP_FLAG_DUPLICATE (1 << 6) /* nexthop duplicates another active one */ -#define NEXTHOP_FLAG_EVPN_RVTEP (1 << 7) /* EVPN remote vtep nexthop */ #define NEXTHOP_IS_ACTIVE(flags) \ (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \ && !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE)) diff --git a/lib/prefix.c b/lib/prefix.c index 365a9ba38f..52bb266f11 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -866,7 +866,7 @@ int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p) return ret; } else { cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); - strncpy(cp, str, pnt - str); + memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_aton(cp, &p->prefix); XFREE(MTYPE_TMP, cp); @@ -913,7 +913,7 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) } cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); - strncpy(cp, str, pnt - str); + memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; str_addr = cp; @@ -1029,7 +1029,7 @@ int str2prefix_ipv6(const char *str, struct prefix_ipv6 *p) int plen; cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); - strncpy(cp, str, pnt - str); + memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_pton(AF_INET6, cp, &p->prefix); XFREE(MTYPE_TMP, cp); diff --git a/lib/yang_translator.c b/lib/yang_translator.c index 6d6f92836f..76a6cc5fd1 100644 --- a/lib/yang_translator.c +++ b/lib/yang_translator.c @@ -511,7 +511,7 @@ static void str_replace(char *o_string, const char *s_string, if (!ch) return; - strncpy(buffer, o_string, ch - o_string); + memcpy(buffer, o_string, ch - o_string); buffer[ch - o_string] = 0; sprintf(buffer + (ch - o_string), "%s%s", r_string, diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 48d210d279..f74d9733ee 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -538,8 +538,7 @@ static void ospf_header_dump(struct ospf_header *ospfh) case OSPF_AUTH_NULL: break; case OSPF_AUTH_SIMPLE: - memset(buf, 0, 9); - strncpy(buf, (char *)ospfh->u.auth_data, 8); + strlcpy(buf, (char *)ospfh->u.auth_data, sizeof(buf)); zlog_debug(" Simple Password %s", buf); break; case OSPF_AUTH_CRYPTOGRAPHIC: diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index c1dc1f0d6f..bb22f211a7 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -954,8 +954,9 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data, if (vl_config->auth_key) { memset(IF_DEF_PARAMS(ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1); - strncpy((char *)IF_DEF_PARAMS(ifp)->auth_simple, - vl_config->auth_key, OSPF_AUTH_SIMPLE_SIZE); + strlcpy((char *)IF_DEF_PARAMS(ifp)->auth_simple, + vl_config->auth_key, + sizeof(IF_DEF_PARAMS(ifp)->auth_simple)); } else if (vl_config->md5_key) { if (ospf_crypt_key_lookup(IF_DEF_PARAMS(ifp)->auth_crypt, vl_config->crypto_key_id) @@ -967,8 +968,8 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data, ck = ospf_crypt_key_new(); ck->key_id = vl_config->crypto_key_id; memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE + 1); - strncpy((char *)ck->auth_key, vl_config->md5_key, - OSPF_AUTH_MD5_SIZE); + strlcpy((char *)ck->auth_key, vl_config->md5_key, + sizeof(ck->auth_key)); ospf_crypt_key_add(IF_DEF_PARAMS(ifp)->auth_crypt, ck); } else if (vl_config->crypto_key_id != 0) { @@ -1147,14 +1148,12 @@ DEFUN (ospf_area_vlink, if (vl_config.crypto_key_id < 0) return CMD_WARNING_CONFIG_FAILED; - memset(md5_key, 0, OSPF_AUTH_MD5_SIZE + 1); - strncpy(md5_key, argv[idx + 3]->arg, OSPF_AUTH_MD5_SIZE); + strlcpy(md5_key, argv[idx + 3]->arg, sizeof(md5_key)); vl_config.md5_key = md5_key; } if (argv_find(argv, argc, "authentication-key", &idx)) { - memset(auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1); - strncpy(auth_key, argv[idx + 1]->arg, OSPF_AUTH_SIMPLE_SIZE); + strlcpy(auth_key, argv[idx + 1]->arg, sizeof(auth_key)); vl_config.auth_key = auth_key; } @@ -6895,9 +6894,8 @@ DEFUN (ip_ospf_authentication_key, ospf_if_update_params(ifp, addr); } - memset(params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1); - strncpy((char *)params->auth_simple, argv[3]->arg, - OSPF_AUTH_SIMPLE_SIZE); + strlcpy((char *)params->auth_simple, argv[3]->arg, + sizeof(params->auth_simple)); SET_IF_PARAM(params, auth_simple); return CMD_SUCCESS; @@ -7006,8 +7004,7 @@ DEFUN (ip_ospf_message_digest_key, ck = ospf_crypt_key_new(); ck->key_id = (uint8_t)key_id; - memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE + 1); - strncpy((char *)ck->auth_key, cryptkey, OSPF_AUTH_MD5_SIZE); + strlcpy((char *)ck->auth_key, cryptkey, sizeof(ck->auth_key)); ospf_crypt_key_add(params->auth_crypt, ck); SET_IF_PARAM(params, auth_crypt); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index a18e2de725..073a51561b 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -234,8 +234,12 @@ static struct ospf *ospf_new(unsigned short instance, const char *name) new->instance = instance; new->router_id.s_addr = htonl(0); new->router_id_static.s_addr = htonl(0); - if (name && !strmatch(name, VRF_DEFAULT_NAME)) { - new->vrf_id = VRF_UNKNOWN; + if (name) { + vrf = vrf_lookup_by_name(name); + if (vrf) + new->vrf_id = vrf->vrf_id; + else + new->vrf_id = VRF_UNKNOWN; /* Freed in ospf_finish_final */ new->name = XSTRDUP(MTYPE_OSPF_TOP, name); if (IS_DEBUG_OSPF_EVENT) diff --git a/pimd/pim_register.c b/pimd/pim_register.c index b9908ae22b..4b402de634 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -189,8 +189,8 @@ void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src, if (PIM_DEBUG_PIM_REG) { char rp_str[INET_ADDRSTRLEN]; - strncpy(rp_str, inet_ntoa(rpg->rpf_addr.u.prefix4), - INET_ADDRSTRLEN - 1); + strlcpy(rp_str, inet_ntoa(rpg->rpf_addr.u.prefix4), + sizeof(rp_str)); zlog_debug("%s: Sending %s %sRegister Packet to %s on %s", __PRETTY_FUNCTION__, up->sg_str, null_register ? "NULL " : "", rp_str, ifp->name); diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 6d18c005b9..78b1f7c87c 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -162,7 +162,7 @@ BuildRequires: make BuildRequires: ncurses-devel BuildRequires: readline-devel BuildRequires: texinfo -BuildRequires: libyang >= 0.16.7 +BuildRequires: libyang-devel >= 0.16.74 %if 0%{?rhel} && 0%{?rhel} < 7 #python27-devel is available from ius community repo for RedHat/CentOS 6 BuildRequires: python27-devel @@ -624,7 +624,6 @@ fi %{_libdir}/frr/modules/bgpd_rpki.so %endif %{_libdir}/frr/modules/zebra_irdp.so -%{_libdir}/frr/libyang_plugins/frr_user_types.so %{_bindir}/* %config(noreplace) %{configdir}/[!v]*.conf* %config(noreplace) %attr(750,%{frr_user},%{frr_user}) %{configdir}/daemons diff --git a/ripd/ripd.c b/ripd/ripd.c index 38b4aed5bc..d2fc9eb303 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -71,6 +71,9 @@ static int rip_update_jitter(unsigned long); static void rip_distribute_update(struct distribute_ctx *ctx, struct distribute *dist); +static void rip_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap); + /* RIP output routes type. */ enum { rip_all_route, rip_changed_route }; @@ -851,7 +854,7 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, MD5_CTX ctx; uint8_t digest[RIP_AUTH_MD5_SIZE]; uint16_t packet_len; - char auth_str[RIP_AUTH_MD5_SIZE]; + char auth_str[RIP_AUTH_MD5_SIZE] = {}; if (IS_RIP_DEBUG_EVENT) zlog_debug("RIPv2 MD5 authentication from %s", @@ -895,8 +898,6 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, /* retrieve authentication data */ md5data = (struct rip_md5_data *)(((uint8_t *)packet) + packet_len); - memset(auth_str, 0, RIP_AUTH_MD5_SIZE); - if (ri->key_chain) { keychain = keychain_lookup(ri->key_chain); if (keychain == NULL) @@ -906,9 +907,9 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, if (key == NULL || key->string == NULL) return 0; - strncpy(auth_str, key->string, RIP_AUTH_MD5_SIZE); + strlcpy(auth_str, key->string, sizeof(auth_str)); } else if (ri->auth_str) - strncpy(auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE); + strlcpy(auth_str, ri->auth_str, sizeof(auth_str)); if (auth_str[0] == 0) return 0; @@ -941,9 +942,9 @@ static void rip_auth_prepare_str_send(struct rip_interface *ri, struct key *key, memset(auth_str, 0, len); if (key && key->string) - strncpy(auth_str, key->string, len); + strlcpy(auth_str, key->string, len); else if (ri->auth_str) - strncpy(auth_str, ri->auth_str, len); + strlcpy(auth_str, ri->auth_str, len); return; } @@ -1389,13 +1390,12 @@ static int rip_send_packet(uint8_t *buf, int size, struct sockaddr_in *to, if (IS_RIP_DEBUG_PACKET) { #define ADDRESS_SIZE 20 char dst[ADDRESS_SIZE]; - dst[ADDRESS_SIZE - 1] = '\0'; if (to) { - strncpy(dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1); + strlcpy(dst, inet_ntoa(to->sin_addr), sizeof(dst)); } else { sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); - strncpy(dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1); + strlcpy(dst, inet_ntoa(sin.sin_addr), sizeof(dst)); } #undef ADDRESS_SIZE zlog_debug("rip_send_packet %s > %s (%s)", @@ -2100,8 +2100,7 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to, key = key_lookup_for_send(keychain); } /* to be passed to auth functions later */ - rip_auth_prepare_str_send(ri, key, auth_str, - RIP_AUTH_SIMPLE_SIZE); + rip_auth_prepare_str_send(ri, key, auth_str, sizeof(auth_str)); if (strlen(auth_str) == 0) return; } @@ -2712,6 +2711,12 @@ int rip_create(int socket) rip_distribute_update); distribute_list_delete_hook(rip->distribute_ctx, rip_distribute_update); + + /* if rmap install. */ + rip->if_rmap_ctx = if_rmap_ctx_create(VRF_DEFAULT_NAME); + if_rmap_hook_add(rip->if_rmap_ctx, rip_if_rmap_update); + if_rmap_hook_delete(rip->if_rmap_ctx, rip_if_rmap_update); + return 0; } @@ -3228,7 +3233,7 @@ static int config_write_rip(struct vty *vty) rip->distribute_ctx); /* Interface routemap configuration */ - write += config_write_if_rmap(vty); + write += config_write_if_rmap(vty, rip->if_rmap_ctx); } return write; } @@ -3381,25 +3386,33 @@ void rip_clean(void) route_table_finish(rip->neighbor); distribute_list_delete(&rip->distribute_ctx); + + if_rmap_ctx_delete(rip->if_rmap_ctx); + XFREE(MTYPE_RIP, rip); rip = NULL; } - rip_clean_network(); rip_passive_nondefault_clean(); rip_offset_clean(); rip_interfaces_clean(); rip_distance_reset(); rip_redistribute_clean(); + if_rmap_terminate(); } -static void rip_if_rmap_update(struct if_rmap *if_rmap) +static void rip_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap) { - struct interface *ifp; + struct interface *ifp = NULL; struct rip_interface *ri; struct route_map *rmap; + struct vrf *vrf = NULL; - ifp = if_lookup_by_name(if_rmap->ifname, VRF_DEFAULT); + if (ctx->name) + vrf = vrf_lookup_by_name(ctx->name); + if (vrf) + ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id); if (ifp == NULL) return; @@ -3426,10 +3439,18 @@ static void rip_if_rmap_update(struct if_rmap *if_rmap) void rip_if_rmap_update_interface(struct interface *ifp) { struct if_rmap *if_rmap; + struct if_rmap_ctx *ctx; - if_rmap = if_rmap_lookup(ifp->name); + if (!rip) + return; + if (ifp->vrf_id != VRF_DEFAULT) + return; + ctx = rip->if_rmap_ctx; + if (!ctx) + return; + if_rmap = if_rmap_lookup(ctx, ifp->name); if (if_rmap) - rip_if_rmap_update(if_rmap); + rip_if_rmap_update(ctx, if_rmap); } static void rip_routemap_update_redistribute(void) @@ -3497,8 +3518,6 @@ void rip_init(void) route_map_delete_hook(rip_routemap_update); if_rmap_init(RIP_NODE); - if_rmap_hook_add(rip_if_rmap_update); - if_rmap_hook_delete(rip_if_rmap_update); /* Distance control. */ rip_distance_table = route_table_init(); diff --git a/ripd/ripd.h b/ripd/ripd.h index 7b8fe3a906..383df3707b 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -154,6 +154,9 @@ struct rip { /* For distribute-list container */ struct distribute_ctx *distribute_ctx; + + /* For if_rmap container */ + struct if_rmap_ctx *if_rmap_ctx; }; /* RIP routing table entry which belong to rip_packet. */ @@ -419,8 +422,7 @@ extern void rip_zebra_ipv4_add(struct route_node *); extern void rip_zebra_ipv4_delete(struct route_node *); extern void rip_interface_multicast_set(int, struct connected *); extern void rip_distribute_update_interface(struct interface *); -extern void rip_if_rmap_update_interface(struct interface *); - +extern void rip_if_rmap_update_interface(struct interface *ifp); extern int rip_show_network_config(struct vty *); extern void rip_show_redistribute_config(struct vty *); diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 70655beff1..9faebcf0d0 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -60,6 +60,9 @@ void ripng_output_process(struct interface *, struct sockaddr_in6 *, int); int ripng_triggered_update(struct thread *); +static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap); + /* RIPng next hop specification. */ struct ripng_nexthop { enum ripng_nexthop_type { @@ -1816,6 +1819,12 @@ int ripng_create(int socket) ripng_distribute_update); distribute_list_delete_hook(ripng->distribute_ctx, ripng_distribute_update); + + /* if rmap install. */ + ripng->if_rmap_ctx = if_rmap_ctx_create(VRF_DEFAULT_NAME); + if_rmap_hook_add(ripng->if_rmap_ctx, ripng_if_rmap_update); + if_rmap_hook_delete(ripng->if_rmap_ctx, ripng_if_rmap_update); + /* Make socket. */ ripng->sock = socket; @@ -2303,7 +2312,7 @@ static int ripng_config_write(struct vty *vty) config_write_distribute(vty, ripng->distribute_ctx); - config_write_if_rmap(vty); + config_write_if_rmap(vty, ripng->if_rmap_ctx); write = 1; } @@ -2474,15 +2483,21 @@ void ripng_clean(void) ripng_offset_clean(); ripng_interface_clean(); ripng_redistribute_clean(); + if_rmap_terminate(); } -static void ripng_if_rmap_update(struct if_rmap *if_rmap) +static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap) { - struct interface *ifp; + struct interface *ifp = NULL; struct ripng_interface *ri; struct route_map *rmap; + struct vrf *vrf = NULL; - ifp = if_lookup_by_name(if_rmap->ifname, VRF_DEFAULT); + if (ctx->name) + vrf = vrf_lookup_by_name(ctx->name); + if (vrf) + ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id); if (ifp == NULL) return; @@ -2510,10 +2525,18 @@ static void ripng_if_rmap_update(struct if_rmap *if_rmap) void ripng_if_rmap_update_interface(struct interface *ifp) { struct if_rmap *if_rmap; + struct if_rmap_ctx *ctx; - if_rmap = if_rmap_lookup(ifp->name); + if (ifp->vrf_id != VRF_DEFAULT) + return; + if (!ripng) + return; + ctx = ripng->if_rmap_ctx; + if (!ctx) + return; + if_rmap = if_rmap_lookup(ctx, ifp->name); if (if_rmap) - ripng_if_rmap_update(if_rmap); + ripng_if_rmap_update(ctx, if_rmap); } static void ripng_routemap_update_redistribute(void) @@ -2590,6 +2613,4 @@ void ripng_init(void) route_map_delete_hook(ripng_routemap_update); if_rmap_init(RIPNG_NODE); - if_rmap_hook_add(ripng_if_rmap_update); - if_rmap_hook_delete(ripng_if_rmap_update); } diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 1db7a83b11..3f0ef13a05 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -132,6 +132,9 @@ struct ripng { /* For distribute-list container */ struct distribute_ctx *distribute_ctx; + + /* For if_rmap container */ + struct if_rmap_ctx *if_rmap_ctx; }; /* Routing table entry. */ diff --git a/tools/frr-reload.py b/tools/frr-reload.py index c48c8b97ad..59f1bcf52b 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -300,13 +300,11 @@ class Config(object): ''' More fixups in user specification and what running config shows. - "null0" in routes must be replaced by Null0, and "blackhole" must - be replaced by Null0 as well. + "null0" in routes must be replaced by Null0. ''' if (key[0].startswith('ip route') or key[0].startswith('ipv6 route') and - 'null0' in key[0] or 'blackhole' in key[0]): + 'null0' in key[0]): key[0] = re.sub(r'\s+null0(\s*$)', ' Null0', key[0]) - key[0] = re.sub(r'\s+blackhole(\s*$)', ' Null0', key[0]) if lines: if tuple(key) not in self.contexts: @@ -435,7 +433,7 @@ end self.save_contexts(ctx_keys, current_context_lines) new_ctx = True - elif line in ["end", "exit-vrf"]: + elif line == "end": self.save_contexts(ctx_keys, current_context_lines) log.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys) @@ -445,6 +443,17 @@ end ctx_keys = [] current_context_lines = [] + elif line == "exit-vrf": + self.save_contexts(ctx_keys, current_context_lines) + current_context_lines.append(line) + log.debug('LINE %-50s: append to current_context_lines, %-50s', line, ctx_keys) + + #Start a new context + new_ctx = True + main_ctx_key = [] + ctx_keys = [] + current_context_lines = [] + elif line in ["exit-address-family", "exit", "exit-vnc"]: # if this exit is for address-family ipv4 unicast, ignore the pop if main_ctx_key: diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 9ff869e503..1f1152d364 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1305,6 +1305,7 @@ DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd, return CMD_SUCCESS; } +#ifdef KEEP_OLD_VPN_COMMANDS DEFUNSH(VTYSH_BGPD, address_family_vpnv4, address_family_vpnv4_cmd, "address-family vpnv4 [unicast]", "Enter Address Family command mode\n" @@ -1324,6 +1325,7 @@ DEFUNSH(VTYSH_BGPD, address_family_vpnv6, address_family_vpnv6_cmd, vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } +#endif /* KEEP_OLD_VPN_COMMANDS */ DEFUNSH(VTYSH_BGPD, address_family_ipv4, address_family_ipv4_cmd, "address-family ipv4 [unicast]", @@ -3735,8 +3737,10 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &router_isis_cmd); install_element(CONFIG_NODE, &router_openfabric_cmd); install_element(CONFIG_NODE, &router_bgp_cmd); +#ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv4_cmd); install_element(BGP_NODE, &address_family_vpnv6_cmd); +#endif /* KEEP_OLD_VPN_COMMANDS */ #if defined(ENABLE_BGP_VNC) install_element(BGP_NODE, &vnc_vrf_policy_cmd); install_element(BGP_NODE, &vnc_defaults_cmd); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index debc151d75..8bec256355 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -147,7 +147,7 @@ static int if_get_hwaddr(struct interface *ifp) struct ifreq ifreq; int i; - strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); ifreq.ifr_addr.sa_family = AF_INET; /* Fetch Hardware address if available. */ diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 2c29930c3f..8b539a9049 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -247,7 +247,8 @@ static int if_get_addr(struct interface *ifp, struct sockaddr *addr, * We need to use the logical interface name / label, if we've been * given one, in order to get the right address */ - strncpy(lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ); + strlcpy(lifreq.lifr_name, (label ? label : ifp->name), + sizeof(lifreq.lifr_name)); /* Interface's address. */ memcpy(&lifreq.lifr_addr, addr, ADDRLEN(addr)); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 23c86f35c0..b2f470bc8d 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -68,6 +68,7 @@ #include "zebra/kernel_netlink.h" #include "zebra/if_netlink.h" #include "zebra/zebra_errors.h" +#include "zebra/zebra_vxlan.h" extern struct zebra_privs_t zserv_privs; @@ -1111,6 +1112,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifindex_t bridge_ifindex = IFINDEX_INTERNAL; ifindex_t bond_ifindex = IFINDEX_INTERNAL; ifindex_t link_ifindex = IFINDEX_INTERNAL; + uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; zns = zebra_ns_lookup(ns_id); @@ -1311,6 +1313,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp); zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); + memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX); + netlink_interface_update_hw_addr(tb, ifp); if (if_is_no_ptm_operative(ifp)) { @@ -1329,6 +1333,22 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) "Intf %s(%u) PTM up, notifying clients", name, ifp->ifindex); zebra_interface_up_update(ifp); + + /* Update EVPN VNI when SVI MAC change + */ + if (IS_ZEBRA_IF_VLAN(ifp) && + memcmp(old_hw_addr, ifp->hw_addr, + INTERFACE_HWADDR_MAX)) { + struct interface *link_if; + + link_if = + if_lookup_by_index_per_ns( + zebra_ns_lookup(NS_DEFAULT), + link_ifindex); + if (link_if) + zebra_vxlan_svi_up(ifp, + link_if); + } } } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; diff --git a/zebra/ioctl.c b/zebra/ioctl.c index ebe1edcaef..9499c731ef 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -213,7 +213,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc) rib_lookup_and_pushup(p, ifp->vrf_id); memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr = p->prefix; @@ -267,7 +267,7 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv4 *)ifc->address; memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr = p->prefix; @@ -412,7 +412,7 @@ void if_get_flags(struct interface *ifp) if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) { (void)memset(&ifmr, 0, sizeof(ifmr)); - strncpy(ifmr.ifm_name, ifp->name, IFNAMSIZ); + strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); /* Seems not all interfaces implement this ioctl */ if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1 && @@ -514,7 +514,7 @@ int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv6 *)ifc->address; memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = p->prefix; @@ -557,7 +557,7 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv6 *)ifc->address; memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = p->prefix; diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index fc554219bc..c523ee983d 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -44,7 +44,7 @@ extern struct zebra_privs_t zserv_privs; /* clear and set interface name string */ void lifreq_set_name(struct lifreq *lifreq, const char *ifname) { - strncpy(lifreq->lifr_name, ifname, IFNAMSIZ); + strlcpy(lifreq->lifr_name, ifname, sizeof(lifreq->lifr_name)); } int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id) @@ -199,7 +199,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc) ifaddr = *p; - strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); addr.sin_addr = p->prefix; addr.sin_family = p->family; @@ -250,7 +250,7 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv4 *)ifc->address; - strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = p->family; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3868412b20..18cf389d5e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1466,10 +1466,9 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { - if ((p->family == AF_INET) || v6_rr_semantics) - req.n.nlmsg_flags |= NLM_F_REPLACE; - } + if ((cmd == RTM_NEWROUTE) && + ((p->family == AF_INET) || v6_rr_semantics)) + req.n.nlmsg_flags |= NLM_F_REPLACE; req.n.nlmsg_type = cmd; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 9b91289dec..9f2bbcf426 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1432,12 +1432,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) case NEXTHOP_TYPE_IPV4_IFINDEX: memset(&vtep_ip, 0, sizeof(struct ipaddr)); - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - ifindex = get_l3vni_svi_ifindex(vrf_id); - } else { - ifindex = api_nh->ifindex; - } - + ifindex = api_nh->ifindex; if (IS_ZEBRA_DEBUG_RECV) { char nhbuf[INET6_ADDRSTRLEN] = {0}; @@ -1452,12 +1447,10 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) re, &api_nh->gate.ipv4, NULL, ifindex, api_nh->vrf_id); - /* if this an EVPN route entry, - * program the nh as neigh + /* Special handling for IPv4 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. */ if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - SET_FLAG(nexthop->flags, - NEXTHOP_FLAG_EVPN_RVTEP); vtep_ip.ipa_type = IPADDR_V4; memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4), @@ -1473,22 +1466,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) break; case NEXTHOP_TYPE_IPV6_IFINDEX: memset(&vtep_ip, 0, sizeof(struct ipaddr)); - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - ifindex = get_l3vni_svi_ifindex(vrf_id); - } else { - ifindex = api_nh->ifindex; - } - + ifindex = api_nh->ifindex; nexthop = route_entry_nexthop_ipv6_ifindex_add( re, &api_nh->gate.ipv6, ifindex, api_nh->vrf_id); - /* if this an EVPN route entry, - * program the nh as neigh + /* Special handling for IPv6 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. */ if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - SET_FLAG(nexthop->flags, - NEXTHOP_FLAG_EVPN_RVTEP); vtep_ip.ipa_type = IPADDR_V6; memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), sizeof(struct in6_addr)); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index a739b0a683..2014aa3bed 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -276,10 +276,8 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re, /*Pending: need to think if null ifp here is ok during bootup? There was a crash because ifp here was coming to be NULL */ if (ifp) - if (connected_is_unnumbered(ifp) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) { + if (connected_is_unnumbered(ifp)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - } route_entry_nexthop_add(re, nexthop); @@ -314,8 +312,6 @@ struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re, nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->gate.ipv6 = *ipv6; nexthop->ifindex = ifindex; - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); route_entry_nexthop_add(re, nexthop); @@ -433,10 +429,6 @@ static int nexthop_active(afi_t afi, struct route_entry *re, re->nexthop_mtu = 0; } - /* Next hops (remote VTEPs) for EVPN routes are fully resolved. */ - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP)) - return 1; - /* * If the kernel has sent us a route, then * by golly gee whiz it's a good route. @@ -459,6 +451,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re, * Check to see if we should trust the passed in information * for UNNUMBERED interfaces as that we won't find the GW * address in the routing table. + * This check should suffice to handle IPv4 or IPv6 routes + * sourced from EVPN routes which are installed with the + * next hop as the remote VTEP IP. */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) { ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); @@ -2937,6 +2932,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, return; } + /* Special handling for IPv4 or IPv6 routes sourced from + * EVPN - the nexthop (and associated MAC) need to be + * uninstalled if no more refs. + */ if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { struct nexthop *tmp_nh; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 33a7583123..16a47f9c4c 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -767,8 +767,7 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) n->detect_start_time.tv_sec); char tmp_buf[30]; - memset(tmp_buf, 0, 30); - strncpy(tmp_buf, buf, strlen(buf) - 1); + strlcpy(tmp_buf, buf, sizeof(tmp_buf)); vty_out(vty, " Duplicate detection started at %s, detection count %u\n", tmp_buf, n->dad_count); @@ -1148,7 +1147,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) struct vty *vty; zebra_neigh_t *n = NULL; struct listnode *node = NULL; - char buf1[20]; + char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; struct zebra_vrf *zvrf; struct timeval detect_start_time = {0, 0}; @@ -1289,8 +1288,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) mac->detect_start_time.tv_sec); char tmp_buf[30]; - memset(tmp_buf, 0, 30); - strncpy(tmp_buf, buf, strlen(buf) - 1); + strlcpy(tmp_buf, buf, sizeof(tmp_buf)); vty_out(vty, " Duplicate detection started at %s, detection count %u\n", tmp_buf, mac->dad_count); @@ -1323,7 +1321,7 @@ static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt) struct vty *vty; json_object *json_mac_hdr = NULL, *json_mac = NULL; zebra_mac_t *mac; - char buf1[20]; + char buf1[ETHER_ADDR_STRLEN]; struct mac_walk_ctx *wctx = ctxt; vty = wctx->vty; @@ -1445,7 +1443,7 @@ static void zvni_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) json_object *json_mac_hdr = NULL; zebra_mac_t *mac; struct mac_walk_ctx *wctx = ctxt; - char buf1[20]; + char buf1[ETHER_ADDR_STRLEN]; vty = wctx->vty; json_mac_hdr = wctx->json; @@ -4871,6 +4869,7 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) stream_put(s, &rmac, sizeof(struct ethaddr)); stream_put_in_addr(s, &zl3vni->local_vtep_ip); stream_put(s, &zl3vni->filter, sizeof(int)); + stream_putl(s, zl3vni->svi_if->ifindex); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -7086,9 +7085,10 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, zes.zvrf = zvrf; /* Display all L2-VNIs */ - hash_iterate(zvrf->vni_table, (void (*)(struct hash_bucket *, - void *))zvni_print_hash_detail, - &zes); + hash_iterate( + zvrf->vni_table, + (void (*)(struct hash_bucket *, void *))zvni_print_hash_detail, + &zes); /* Display all L3-VNIs */ hash_iterate(zrouter.l3vni_table, @@ -7097,8 +7097,9 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, &zes); if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } } |
