diff options
Diffstat (limited to 'bgpd/bgp_evpn.c')
| -rw-r--r-- | bgpd/bgp_evpn.c | 4190 |
1 files changed, 2048 insertions, 2142 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 46e97cc50d..f0081e6d02 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -57,12 +57,10 @@ DEFINE_QOBJ_TYPE(bgpevpn) /* * Static function declarations */ -static void -delete_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, - afi_t afi, safi_t safi, struct bgp_node *rn, - struct bgp_info **ri); -static int -delete_all_vni_routes (struct bgp *bgp, struct bgpevpn *vpn); +static void delete_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, + afi_t afi, safi_t safi, struct bgp_node *rn, + struct bgp_info **ri); +static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn); /* * Private functions. @@ -71,241 +69,226 @@ delete_all_vni_routes (struct bgp *bgp, struct bgpevpn *vpn); /* * Make vni hash key. */ -static unsigned int -vni_hash_key_make(void *p) +static unsigned int vni_hash_key_make(void *p) { - struct bgpevpn *vpn = p; - return (jhash_1word(vpn->vni, 0)); + struct bgpevpn *vpn = p; + return (jhash_1word(vpn->vni, 0)); } /* * Comparison function for vni hash */ -static int -vni_hash_cmp (const void *p1, const void *p2) +static int vni_hash_cmp(const void *p1, const void *p2) { - const struct bgpevpn *vpn1 = p1; - const struct bgpevpn *vpn2 = p2; + const struct bgpevpn *vpn1 = p1; + const struct bgpevpn *vpn2 = p2; - if (!vpn1 && !vpn2) - return 1; - if (!vpn1 || !vpn2) - return 0; - return(vpn1->vni == vpn2->vni); + if (!vpn1 && !vpn2) + return 1; + if (!vpn1 || !vpn2) + return 0; + return (vpn1->vni == vpn2->vni); } /* * Make import route target hash key. */ -static unsigned int -import_rt_hash_key_make (void *p) +static unsigned int import_rt_hash_key_make(void *p) { - struct irt_node *irt = p; - char *pnt = irt->rt.val; - unsigned int key = 0; - int c=0; + struct irt_node *irt = p; + char *pnt = irt->rt.val; + unsigned int key = 0; + int c = 0; - key += pnt[c]; - key += pnt[c + 1]; - key += pnt[c + 2]; - key += pnt[c + 3]; - key += pnt[c + 4]; - key += pnt[c + 5]; - key += pnt[c + 6]; - key += pnt[c + 7]; + key += pnt[c]; + key += pnt[c + 1]; + key += pnt[c + 2]; + key += pnt[c + 3]; + key += pnt[c + 4]; + key += pnt[c + 5]; + key += pnt[c + 6]; + key += pnt[c + 7]; - return (key); + return (key); } /* * Comparison function for import rt hash */ -static int -import_rt_hash_cmp (const void *p1, const void *p2) +static int import_rt_hash_cmp(const void *p1, const void *p2) { - const struct irt_node *irt1 = p1; - const struct irt_node *irt2 = p2; + const struct irt_node *irt1 = p1; + const struct irt_node *irt2 = p2; - if (irt1 == NULL && irt2 == NULL) - return 1; + if (irt1 == NULL && irt2 == NULL) + return 1; - if (irt1 == NULL || irt2 == NULL) - return 0; + if (irt1 == NULL || irt2 == NULL) + return 0; - return(memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0); + return (memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0); } /* * Create a new import_rt */ -static struct irt_node * -import_rt_new (struct bgp *bgp, struct ecommunity_val *rt) +static struct irt_node *import_rt_new(struct bgp *bgp, + struct ecommunity_val *rt) { - struct irt_node *irt; + struct irt_node *irt; - if (!bgp) - return NULL; + if (!bgp) + return NULL; - irt = XCALLOC (MTYPE_BGP_EVPN_IMPORT_RT, sizeof (struct irt_node)); - if (!irt) - return NULL; + irt = XCALLOC(MTYPE_BGP_EVPN_IMPORT_RT, sizeof(struct irt_node)); + if (!irt) + return NULL; - irt->rt = *rt; - irt->vnis = list_new (); + irt->rt = *rt; + irt->vnis = list_new(); - /* Add to hash */ - if (!hash_get(bgp->import_rt_hash, irt, hash_alloc_intern)) - { - XFREE(MTYPE_BGP_EVPN_IMPORT_RT, irt); - return NULL; - } + /* Add to hash */ + if (!hash_get(bgp->import_rt_hash, irt, hash_alloc_intern)) { + XFREE(MTYPE_BGP_EVPN_IMPORT_RT, irt); + return NULL; + } - return irt; + return irt; } /* * Free the import rt node */ -static void -import_rt_free (struct bgp *bgp, struct irt_node *irt) +static void import_rt_free(struct bgp *bgp, struct irt_node *irt) { - hash_release(bgp->import_rt_hash, irt); - XFREE(MTYPE_BGP_EVPN_IMPORT_RT, irt); + hash_release(bgp->import_rt_hash, irt); + XFREE(MTYPE_BGP_EVPN_IMPORT_RT, irt); } /* * Function to lookup Import RT node - used to map a RT to set of * VNIs importing routes with that RT. */ -static struct irt_node * -lookup_import_rt (struct bgp *bgp, struct ecommunity_val *rt) +static struct irt_node *lookup_import_rt(struct bgp *bgp, + struct ecommunity_val *rt) { - struct irt_node *irt; - struct irt_node tmp; + struct irt_node *irt; + struct irt_node tmp; - memset(&tmp, 0, sizeof(struct irt_node)); - memcpy(&tmp.rt, rt, ECOMMUNITY_SIZE); - irt = hash_lookup(bgp->import_rt_hash, &tmp); - return irt; + memset(&tmp, 0, sizeof(struct irt_node)); + memcpy(&tmp.rt, rt, ECOMMUNITY_SIZE); + irt = hash_lookup(bgp->import_rt_hash, &tmp); + return irt; } /* * Is specified VNI present on the RT's list of "importing" VNIs? */ -static int -is_vni_present_in_irt_vnis (struct list *vnis, struct bgpevpn *vpn) +static int is_vni_present_in_irt_vnis(struct list *vnis, struct bgpevpn *vpn) { - struct listnode *node, *nnode; - struct bgpevpn *tmp_vpn; + struct listnode *node, *nnode; + struct bgpevpn *tmp_vpn; - for (ALL_LIST_ELEMENTS (vnis, node, nnode, tmp_vpn)) - { - if (tmp_vpn == vpn) - return 1; - } + for (ALL_LIST_ELEMENTS(vnis, node, nnode, tmp_vpn)) { + if (tmp_vpn == vpn) + return 1; + } - return 0; + return 0; } /* * Compare Route Targets. */ -static int -evpn_route_target_cmp (struct ecommunity *ecom1, struct ecommunity *ecom2) +static int evpn_route_target_cmp(struct ecommunity *ecom1, + struct ecommunity *ecom2) { - if (ecom1 && !ecom2) - return -1; + if (ecom1 && !ecom2) + return -1; - if (!ecom1 && ecom2) - return 1; + if (!ecom1 && ecom2) + return 1; - if (!ecom1 && !ecom2) - return 0; + if (!ecom1 && !ecom2) + return 0; - if (ecom1->str && !ecom2->str) - return -1; + if (ecom1->str && !ecom2->str) + return -1; - if (!ecom1->str && ecom2->str) - return 1; + if (!ecom1->str && ecom2->str) + return 1; - if (!ecom1->str && !ecom2->str) - return 0; + if (!ecom1->str && !ecom2->str) + return 0; - return strcmp(ecom1->str, ecom2->str); + return strcmp(ecom1->str, ecom2->str); } /* * Mask off global-admin field of specified extended community (RT), * just retain the local-admin field. */ -static inline void -mask_ecom_global_admin (struct ecommunity_val *dst, - struct ecommunity_val *src) +static inline void mask_ecom_global_admin(struct ecommunity_val *dst, + struct ecommunity_val *src) { - u_char type; + u_char type; - type = src->val[0]; - dst->val[0] = 0; - if (type == ECOMMUNITY_ENCODE_AS) - { - dst->val[2] = dst->val[3] = 0; - } - else if (type == ECOMMUNITY_ENCODE_AS4 || - type == ECOMMUNITY_ENCODE_IP) - { - dst->val[2] = dst->val[3] = 0; - dst->val[4] = dst->val[5] = 0; - } + type = src->val[0]; + dst->val[0] = 0; + if (type == ECOMMUNITY_ENCODE_AS) { + dst->val[2] = dst->val[3] = 0; + } else if (type == ECOMMUNITY_ENCODE_AS4 + || type == ECOMMUNITY_ENCODE_IP) { + dst->val[2] = dst->val[3] = 0; + dst->val[4] = dst->val[5] = 0; + } } /* * Map one RT to specified VNI. */ -static void -map_vni_to_rt (struct bgp *bgp, struct bgpevpn *vpn, - struct ecommunity_val *eval) +static void map_vni_to_rt(struct bgp *bgp, struct bgpevpn *vpn, + struct ecommunity_val *eval) { - struct irt_node *irt; - struct ecommunity_val eval_tmp; + struct irt_node *irt; + struct ecommunity_val eval_tmp; - /* If using "automatic" RT, we only care about the local-admin sub-field. - * This is to facilitate using VNI as the RT for EBGP peering too. - */ - memcpy (&eval_tmp, eval, ECOMMUNITY_SIZE); - if (!is_import_rt_configured (vpn)) - mask_ecom_global_admin (&eval_tmp, eval); + /* If using "automatic" RT, we only care about the local-admin + * sub-field. + * This is to facilitate using VNI as the RT for EBGP peering too. + */ + memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE); + if (!is_import_rt_configured(vpn)) + mask_ecom_global_admin(&eval_tmp, eval); - irt = lookup_import_rt (bgp, &eval_tmp); - if (irt && irt->vnis) - if (is_vni_present_in_irt_vnis (irt->vnis, vpn)) - /* Already mapped. */ - return; + irt = lookup_import_rt(bgp, &eval_tmp); + if (irt && irt->vnis) + if (is_vni_present_in_irt_vnis(irt->vnis, vpn)) + /* Already mapped. */ + return; - if (!irt) - { - irt = import_rt_new (bgp, &eval_tmp); - assert (irt); - } + if (!irt) { + irt = import_rt_new(bgp, &eval_tmp); + assert(irt); + } - /* Add VNI to the hash list for this RT. */ - listnode_add (irt->vnis, vpn); + /* Add VNI to the hash list for this RT. */ + listnode_add(irt->vnis, vpn); } /* * Unmap specified VNI from specified RT. If there are no other * VNIs for this RT, then the RT hash is deleted. */ -static void -unmap_vni_from_rt (struct bgp *bgp, struct bgpevpn *vpn, - struct irt_node *irt) +static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn, + struct irt_node *irt) { - /* Delete VNI from hash list for this RT. */ - listnode_delete (irt->vnis, vpn); - if (!listnode_head (irt->vnis)) - { - list_free (irt->vnis); - import_rt_free (bgp, irt); - } + /* Delete VNI from hash list for this RT. */ + listnode_delete(irt->vnis, vpn); + if (!listnode_head(irt->vnis)) { + list_free(irt->vnis); + import_rt_free(bgp, irt); + } } /* @@ -316,257 +299,253 @@ unmap_vni_from_rt (struct bgp *bgp, struct bgpevpn *vpn, * VNIs but the same across routers (in the same AS) for a particular * VNI. */ -static void -form_auto_rt (struct bgp *bgp, struct bgpevpn *vpn, - struct list *rtl) +static void form_auto_rt(struct bgp *bgp, struct bgpevpn *vpn, struct list *rtl) { - struct ecommunity_val eval; - struct ecommunity *ecomadd; + struct ecommunity_val eval; + struct ecommunity *ecomadd; - encode_route_target_as ((bgp->as & 0xFFFF), vpn->vni, &eval); + encode_route_target_as((bgp->as & 0xFFFF), vpn->vni, &eval); - ecomadd = ecommunity_new (); - ecommunity_add_val (ecomadd, &eval); - listnode_add_sort (rtl, ecomadd); + ecomadd = ecommunity_new(); + ecommunity_add_val(ecomadd, &eval); + listnode_add_sort(rtl, ecomadd); } /* * Derive RD and RT for a VNI automatically. Invoked at the time of * creation of a VNI. */ -static void -derive_rd_rt_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { - bgp_evpn_derive_auto_rd (bgp, vpn); - bgp_evpn_derive_auto_rt_import (bgp, vpn); - bgp_evpn_derive_auto_rt_export (bgp, vpn); + bgp_evpn_derive_auto_rd(bgp, vpn); + bgp_evpn_derive_auto_rt_import(bgp, vpn); + bgp_evpn_derive_auto_rt_export(bgp, vpn); } /* * Add (update) or delete MACIP from zebra. */ -static int -bgp_zebra_send_remote_macip (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, - struct in_addr remote_vtep_ip, - int add, u_char sticky) -{ - struct stream *s; - int ipa_len; - char buf1[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; - char buf3[INET6_ADDRSTRLEN]; - - /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; - - /* Don't try to register if Zebra doesn't know of this instance. */ - if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) - return 0; - - s = zclient->obuf; - stream_reset (s); - - zclient_create_header (s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, - bgp->vrf_id); - stream_putl(s, vpn->vni); - stream_put (s, &p->prefix.mac.octet, ETHER_ADDR_LEN); /* Mac Addr */ - /* IP address length and IP address, if any. */ - if (IS_EVPN_PREFIX_IPADDR_NONE(p)) - stream_putl(s, 0); - else - { - ipa_len = IS_EVPN_PREFIX_IPADDR_V4(p) ? - IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; - stream_putl(s, ipa_len); - stream_put (s, &p->prefix.ip.ip.addr, ipa_len); - } - stream_put_in_addr(s, &remote_vtep_ip); - - /* TX MAC sticky status */ - if (add) - stream_putc (s, sticky); - - stream_putw_at (s, 0, stream_get_endp (s)); - - if (bgp_debug_zebra (NULL)) - zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s", - add ? "ADD" : "DEL", vpn->vni, - sticky ? "sticky " : "", - prefix_mac2str (&p->prefix.mac, buf1, sizeof(buf1)), - ipaddr2str (&p->prefix.ip, buf3, sizeof(buf3)), - inet_ntop(AF_INET, &remote_vtep_ip, buf2, sizeof(buf2))); - - return zclient_send_message(zclient); +static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, + struct in_addr remote_vtep_ip, int add, + u_char sticky) +{ + struct stream *s; + int ipa_len; + char buf1[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + char buf3[INET6_ADDRSTRLEN]; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header( + s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, + bgp->vrf_id); + stream_putl(s, vpn->vni); + stream_put(s, &p->prefix.mac.octet, ETHER_ADDR_LEN); /* Mac Addr */ + /* IP address length and IP address, if any. */ + if (IS_EVPN_PREFIX_IPADDR_NONE(p)) + stream_putl(s, 0); + else { + ipa_len = IS_EVPN_PREFIX_IPADDR_V4(p) ? IPV4_MAX_BYTELEN + : IPV6_MAX_BYTELEN; + stream_putl(s, ipa_len); + stream_put(s, &p->prefix.ip.ip.addr, ipa_len); + } + stream_put_in_addr(s, &remote_vtep_ip); + + /* TX MAC sticky status */ + if (add) + stream_putc(s, sticky); + + stream_putw_at(s, 0, stream_get_endp(s)); + + if (bgp_debug_zebra(NULL)) + zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s", + add ? "ADD" : "DEL", vpn->vni, + sticky ? "sticky " : "", + prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1)), + ipaddr2str(&p->prefix.ip, buf3, sizeof(buf3)), + inet_ntop(AF_INET, &remote_vtep_ip, buf2, + sizeof(buf2))); + + return zclient_send_message(zclient); } /* * Add (update) or delete remote VTEP from zebra. */ -static int -bgp_zebra_send_remote_vtep (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, int add) +static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, int add) { - struct stream *s; + struct stream *s; - /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; - /* Don't try to register if Zebra doesn't know of this instance. */ - if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) - return 0; + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; - s = zclient->obuf; - stream_reset (s); + s = zclient->obuf; + stream_reset(s); - zclient_create_header (s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL, - bgp->vrf_id); - stream_putl(s, vpn->vni); - if (IS_EVPN_PREFIX_IPADDR_V4(p)) - stream_put_in_addr(s, &p->prefix.ip.ipaddr_v4); - else if (IS_EVPN_PREFIX_IPADDR_V6(p)) - { - zlog_err ("Bad remote IP when trying to %s remote VTEP for VNI %u", - add ? "ADD" : "DEL", vpn->vni); - return -1; - } + zclient_create_header( + s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL, + bgp->vrf_id); + stream_putl(s, vpn->vni); + if (IS_EVPN_PREFIX_IPADDR_V4(p)) + stream_put_in_addr(s, &p->prefix.ip.ipaddr_v4); + else if (IS_EVPN_PREFIX_IPADDR_V6(p)) { + zlog_err( + "Bad remote IP when trying to %s remote VTEP for VNI %u", + add ? "ADD" : "DEL", vpn->vni); + return -1; + } - stream_putw_at (s, 0, stream_get_endp (s)); + stream_putw_at(s, 0, stream_get_endp(s)); - if (bgp_debug_zebra (NULL)) - zlog_debug("Tx %s Remote VTEP, VNI %u remote VTEP %s", - add ? "ADD" : "DEL", vpn->vni, - inet_ntoa (p->prefix.ip.ipaddr_v4)); + if (bgp_debug_zebra(NULL)) + zlog_debug("Tx %s Remote VTEP, VNI %u remote VTEP %s", + add ? "ADD" : "DEL", vpn->vni, + inet_ntoa(p->prefix.ip.ipaddr_v4)); - return zclient_send_message(zclient); + return zclient_send_message(zclient); } /* * Build extended communities for EVPN route. RT and ENCAP are * applicable to all routes. */ -static void -build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr) +static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr) { - struct ecommunity ecom_encap; - struct ecommunity ecom_sticky; - struct ecommunity_val eval; - struct ecommunity_val eval_sticky; - bgp_encap_types tnl_type; - struct listnode *node, *nnode; - struct ecommunity *ecom; - u_int32_t seqnum; + struct ecommunity ecom_encap; + struct ecommunity ecom_sticky; + struct ecommunity_val eval; + struct ecommunity_val eval_sticky; + bgp_encap_types tnl_type; + struct listnode *node, *nnode; + struct ecommunity *ecom; + u_int32_t seqnum; - /* Encap */ - tnl_type = BGP_ENCAP_TYPE_VXLAN; - memset (&ecom_encap, 0, sizeof (ecom_encap)); - encode_encap_extcomm (tnl_type, &eval); - ecom_encap.size = 1; - ecom_encap.val = (u_int8_t *)eval.val; + /* Encap */ + tnl_type = BGP_ENCAP_TYPE_VXLAN; + memset(&ecom_encap, 0, sizeof(ecom_encap)); + encode_encap_extcomm(tnl_type, &eval); + ecom_encap.size = 1; + ecom_encap.val = (u_int8_t *)eval.val; - /* Add Encap */ - attr->ecommunity = ecommunity_dup (&ecom_encap); + /* Add Encap */ + attr->ecommunity = ecommunity_dup(&ecom_encap); - /* Add the export RTs */ - for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) - attr->ecommunity = ecommunity_merge (attr->ecommunity, ecom); + /* Add the export RTs */ + for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) + attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom); - if (attr->sticky) - { - seqnum = 0; - memset (&ecom_sticky, 0, sizeof (ecom_sticky)); - encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); - ecom_sticky.size = 1; - ecom_sticky.val = (u_int8_t *)eval_sticky.val; - attr->ecommunity = ecommunity_merge (attr->ecommunity, &ecom_sticky); - } + if (attr->sticky) { + seqnum = 0; + memset(&ecom_sticky, 0, sizeof(ecom_sticky)); + encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); + ecom_sticky.size = 1; + ecom_sticky.val = (u_int8_t *)eval_sticky.val; + attr->ecommunity = + ecommunity_merge(attr->ecommunity, &ecom_sticky); + } - attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } /* * Add MAC mobility extended community to attribute. */ -static void -add_mac_mobility_to_attr (u_int32_t seq_num, struct attr *attr) -{ - struct ecommunity ecom_tmp; - struct ecommunity_val eval; - struct ecommunity *ecom_mm; - int i; - u_int8_t *pnt; - int type = 0; - int sub_type = 0; - - /* Build MM */ - encode_mac_mobility_extcomm (0, seq_num, &eval); - - /* Find current MM ecommunity */ - ecom_mm = NULL; - - if (attr->ecommunity) - { - for (i = 0; i < attr->ecommunity->size; i++) - { - pnt = attr->ecommunity->val + (i * 8); - type = *pnt++; - sub_type = *pnt++; - - if (type == ECOMMUNITY_ENCODE_EVPN && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) - { - ecom_mm = (struct ecommunity*) attr->ecommunity->val + (i * 8); - break; - } - } - } - - /* Update the existing MM ecommunity */ - if (ecom_mm) - { - memcpy(ecom_mm->val, eval.val, sizeof(char) * ECOMMUNITY_SIZE); - } - /* Add MM to existing */ - else - { - memset (&ecom_tmp, 0, sizeof (ecom_tmp)); - ecom_tmp.size = 1; - ecom_tmp.val = (u_int8_t *)eval.val; - - attr->ecommunity = ecommunity_merge (attr->ecommunity, &ecom_tmp); - } +static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr) +{ + struct ecommunity ecom_tmp; + struct ecommunity_val eval; + struct ecommunity *ecom_mm; + int i; + u_int8_t *pnt; + int type = 0; + int sub_type = 0; + + /* Build MM */ + encode_mac_mobility_extcomm(0, seq_num, &eval); + + /* Find current MM ecommunity */ + ecom_mm = NULL; + + if (attr->ecommunity) { + for (i = 0; i < attr->ecommunity->size; i++) { + pnt = attr->ecommunity->val + (i * 8); + type = *pnt++; + sub_type = *pnt++; + + if (type == ECOMMUNITY_ENCODE_EVPN + && sub_type + == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) { + ecom_mm = (struct ecommunity *) + attr->ecommunity->val + + (i * 8); + break; + } + } + } + + /* Update the existing MM ecommunity */ + if (ecom_mm) { + memcpy(ecom_mm->val, eval.val, sizeof(char) * ECOMMUNITY_SIZE); + } + /* Add MM to existing */ + else { + memset(&ecom_tmp, 0, sizeof(ecom_tmp)); + ecom_tmp.size = 1; + ecom_tmp.val = (u_int8_t *)eval.val; + + attr->ecommunity = + ecommunity_merge(attr->ecommunity, &ecom_tmp); + } } /* Install EVPN route into zebra. */ -static int -evpn_zebra_install (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, struct in_addr remote_vtep_ip, - u_char sticky) +static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, + struct in_addr remote_vtep_ip, u_char sticky) { - int ret; + int ret; - if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 1, sticky); - else - ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 1); + if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) + ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip, + 1, sticky); + else + ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1); - return ret; + return ret; } /* Uninstall EVPN route from zebra. */ -static int -evpn_zebra_uninstall (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, struct in_addr remote_vtep_ip) +static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, + struct in_addr remote_vtep_ip) { - int ret; + int ret; - if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 0, 0); - else - ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 0); + if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) + ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip, + 0, 0); + else + ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 0); - return ret; + return ret; } /* @@ -574,600 +553,583 @@ evpn_zebra_uninstall (struct bgp *bgp, struct bgpevpn *vpn, * by a "remote" best route. The prior route has to be deleted and withdrawn * from peers. */ -static void -evpn_delete_old_local_route (struct bgp *bgp, struct bgpevpn *vpn, - struct bgp_node *rn, struct bgp_info *old_local) +static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_node *rn, + struct bgp_info *old_local) { - struct bgp_node *global_rn; - struct bgp_info *ri; - afi_t afi = AFI_L2VPN; - safi_t safi = SAFI_EVPN; + struct bgp_node *global_rn; + struct bgp_info *ri; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; - /* Locate route node in the global EVPN routing table. Note that - * this table is a 2-level tree (RD-level + Prefix-level) similar to - * L3VPN routes. - */ - global_rn = bgp_afi_node_lookup (bgp->rib[afi][safi], afi, safi, - (struct prefix *)&rn->p, &vpn->prd); - if (global_rn) - { - /* Delete route entry in the global EVPN table. */ - delete_evpn_route_entry (bgp, vpn, afi, safi, global_rn, &ri); + /* Locate route node in the global EVPN routing table. Note that + * this table is a 2-level tree (RD-level + Prefix-level) similar to + * L3VPN routes. + */ + global_rn = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi, + (struct prefix *)&rn->p, &vpn->prd); + if (global_rn) { + /* Delete route entry in the global EVPN table. */ + delete_evpn_route_entry(bgp, vpn, afi, safi, global_rn, &ri); - /* Schedule for processing - withdraws to peers happen from - * this table. - */ - if (ri) - bgp_process (bgp, global_rn, afi, safi); - bgp_unlock_node (global_rn); - } + /* Schedule for processing - withdraws to peers happen from + * this table. + */ + if (ri) + bgp_process(bgp, global_rn, afi, safi); + bgp_unlock_node(global_rn); + } - /* Delete route entry in the VNI route table, caller to remove. */ - bgp_info_delete (rn, old_local); + /* Delete route entry in the VNI route table, caller to remove. */ + bgp_info_delete(rn, old_local); } /* * Calculate the best path for an EVPN route. Install/update best path in zebra, * if appropriate. */ -static int -evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn, - struct bgp_node *rn) -{ - struct bgp_info *old_select, *new_select; - struct bgp_info_pair old_and_new; - afi_t afi = AFI_L2VPN; - safi_t safi = SAFI_EVPN; - int ret = 0; - - /* Compute the best path. */ - bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], - &old_and_new, afi, safi); - old_select = old_and_new.old; - new_select = old_and_new.new; - - /* If the best path hasn't changed - see if there is still something to update - * to zebra RIB. - */ - if (old_select && old_select == new_select && - old_select->type == ZEBRA_ROUTE_BGP && - old_select->sub_type == BGP_ROUTE_NORMAL && - !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) && - !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) && - !bgp->addpath_tx_used[afi][safi]) - { - if (bgp_zebra_has_route_changed (rn, old_select)) - ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *)&rn->p, - old_select->attr->nexthop, - old_select->attr->sticky); - UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); - bgp_zebra_clear_route_change_flags (rn); - return ret; - } - - /* If the user did a "clear" this flag will be set */ - UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR); - - /* bestpath has changed; update relevant fields and install or uninstall - * into the zebra RIB. - */ - if (old_select || new_select) - bgp_bump_version(rn); - - if (old_select) - bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); - if (new_select) - { - bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); - bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); - UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); - } - - if (new_select - && new_select->type == ZEBRA_ROUTE_BGP - && new_select->sub_type == BGP_ROUTE_NORMAL) - { - ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *) &rn->p, - new_select->attr->nexthop, - new_select->attr->sticky); - /* If an old best existed and it was a "local" route, the only reason - * it would be supplanted is due to MAC mobility procedures. So, we - * need to do an implicit delete and withdraw that route from peers. - */ - if (old_select - && old_select->peer == bgp->peer_self - && old_select->type == ZEBRA_ROUTE_BGP - && old_select->sub_type == BGP_ROUTE_STATIC) - evpn_delete_old_local_route (bgp, vpn, rn, old_select); - } - else - { - if (old_select - && old_select->type == ZEBRA_ROUTE_BGP - && old_select->sub_type == BGP_ROUTE_NORMAL) - ret = evpn_zebra_uninstall (bgp, vpn, (struct prefix_evpn *) &rn->p, - old_select->attr->nexthop); - } - - /* Clear any route change flags. */ - bgp_zebra_clear_route_change_flags (rn); - - /* Reap old select bgp_info, if it has been removed */ - if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) - bgp_info_reap (rn, old_select); - - return ret; +static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_node *rn) +{ + struct bgp_info *old_select, *new_select; + struct bgp_info_pair old_and_new; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + int ret = 0; + + /* Compute the best path. */ + bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new, + afi, safi); + old_select = old_and_new.old; + new_select = old_and_new.new; + + /* If the best path hasn't changed - see if there is still something to + * update + * to zebra RIB. + */ + if (old_select && old_select == new_select + && old_select->type == ZEBRA_ROUTE_BGP + && old_select->sub_type == BGP_ROUTE_NORMAL + && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) + && !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) + && !bgp->addpath_tx_used[afi][safi]) { + if (bgp_zebra_has_route_changed(rn, old_select)) + ret = evpn_zebra_install(bgp, vpn, + (struct prefix_evpn *)&rn->p, + old_select->attr->nexthop, + old_select->attr->sticky); + UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG); + bgp_zebra_clear_route_change_flags(rn); + return ret; + } + + /* If the user did a "clear" this flag will be set */ + UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR); + + /* bestpath has changed; update relevant fields and install or uninstall + * into the zebra RIB. + */ + if (old_select || new_select) + bgp_bump_version(rn); + + if (old_select) + bgp_info_unset_flag(rn, old_select, BGP_INFO_SELECTED); + if (new_select) { + bgp_info_set_flag(rn, new_select, BGP_INFO_SELECTED); + bgp_info_unset_flag(rn, new_select, BGP_INFO_ATTR_CHANGED); + UNSET_FLAG(new_select->flags, BGP_INFO_MULTIPATH_CHG); + } + + if (new_select && new_select->type == ZEBRA_ROUTE_BGP + && new_select->sub_type == BGP_ROUTE_NORMAL) { + ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, + new_select->attr->nexthop, + new_select->attr->sticky); + /* If an old best existed and it was a "local" route, the only + * reason + * it would be supplanted is due to MAC mobility procedures. So, + * we + * need to do an implicit delete and withdraw that route from + * peers. + */ + if (old_select && old_select->peer == bgp->peer_self + && old_select->type == ZEBRA_ROUTE_BGP + && old_select->sub_type == BGP_ROUTE_STATIC) + evpn_delete_old_local_route(bgp, vpn, rn, old_select); + } else { + if (old_select && old_select->type == ZEBRA_ROUTE_BGP + && old_select->sub_type == BGP_ROUTE_NORMAL) + ret = evpn_zebra_uninstall(bgp, vpn, + (struct prefix_evpn *)&rn->p, + old_select->attr->nexthop); + } + + /* Clear any route change flags. */ + bgp_zebra_clear_route_change_flags(rn); + + /* Reap old select bgp_info, if it has been removed */ + if (old_select && CHECK_FLAG(old_select->flags, BGP_INFO_REMOVED)) + bgp_info_reap(rn, old_select); + + return ret; } /* * Return true if the local ri for this rn has sticky set */ -static int -evpn_route_is_sticky (struct bgp *bgp, struct bgp_node *rn) +static int evpn_route_is_sticky(struct bgp *bgp, struct bgp_node *rn) { - struct bgp_info *tmp_ri; - struct bgp_info *local_ri; + struct bgp_info *tmp_ri; + struct bgp_info *local_ri; - local_ri = NULL; - for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) - { - if (tmp_ri->peer == bgp->peer_self - && tmp_ri->type == ZEBRA_ROUTE_BGP - && tmp_ri->sub_type == BGP_ROUTE_STATIC) - local_ri = tmp_ri; - } + local_ri = NULL; + for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) { + if (tmp_ri->peer == bgp->peer_self + && tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_STATIC) + local_ri = tmp_ri; + } - if (!local_ri) - return 0; + if (!local_ri) + return 0; - return local_ri->attr->sticky; + return local_ri->attr->sticky; } /* * Create or update EVPN route entry. This could be in the VNI route table * or the global route table. */ -static int -update_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, afi_t afi, - safi_t safi, struct bgp_node *rn, struct attr *attr, - int add, int vni_table, struct bgp_info **ri) -{ - struct bgp_info *tmp_ri; - struct bgp_info *local_ri, *remote_ri; - struct attr *attr_new; - mpls_label_t label = MPLS_INVALID_LABEL; - int route_change = 1; - u_char sticky = 0; - - *ri = NULL; - - /* See if this is an update of an existing route, or a new add. Also, - * identify if already known from remote, and if so, the one with the - * highest sequence number; this is only when adding to the VNI routing - * table. - */ - local_ri = remote_ri = NULL; - for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) - { - if (tmp_ri->peer == bgp->peer_self - && tmp_ri->type == ZEBRA_ROUTE_BGP - && tmp_ri->sub_type == BGP_ROUTE_STATIC) - local_ri = tmp_ri; - if (vni_table) - { - if (tmp_ri->type == ZEBRA_ROUTE_BGP - && tmp_ri->sub_type == BGP_ROUTE_NORMAL - && CHECK_FLAG (tmp_ri->flags, BGP_INFO_VALID)) - { - if (!remote_ri) - remote_ri = tmp_ri; - else if (mac_mobility_seqnum (tmp_ri->attr) > - mac_mobility_seqnum (remote_ri->attr)) - remote_ri = tmp_ri; - } - } - } - - /* If route doesn't exist already, create a new one, if told to. - * Otherwise act based on whether the attributes of the route have - * changed or not. - */ - if (!local_ri && !add) - return 0; - - if (!local_ri) - { - /* When learnt locally for the first time but already known from - * remote, we have to initiate appropriate MAC mobility steps. This - * is applicable when updating the VNI routing table. - */ - if (remote_ri) - { - u_int32_t cur_seqnum; - - /* Add MM extended community to route. */ - cur_seqnum = mac_mobility_seqnum (remote_ri->attr); - add_mac_mobility_to_attr (cur_seqnum + 1, attr); - } - - /* Add (or update) attribute to hash. */ - attr_new = bgp_attr_intern (attr); - - /* Extract MAC mobility sequence number, if any. */ - attr_new->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr_new, &sticky); - attr_new->sticky = sticky; - - /* Create new route with its attribute. */ - tmp_ri = info_make (ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0, - bgp->peer_self, attr_new, rn); - SET_FLAG (tmp_ri->flags, BGP_INFO_VALID); - bgp_info_extra_get(tmp_ri); - - /* The VNI goes into the 'label' field of the route */ - vni2label (vpn->vni, &label); - - memcpy (&tmp_ri->extra->label, &label, BGP_LABEL_BYTES); - bgp_info_add (rn, tmp_ri); - } - else - { - tmp_ri = local_ri; - if (attrhash_cmp (tmp_ri->attr, attr) && - !CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED)) - route_change = 0; - else - { - /* The attribute has changed. */ - /* Add (or update) attribute to hash. */ - attr_new = bgp_attr_intern (attr); - bgp_info_set_flag (rn, tmp_ri, BGP_INFO_ATTR_CHANGED); - - /* Restore route, if needed. */ - if (CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED)) - bgp_info_restore(rn, tmp_ri); - - /* Unintern existing, set to new. */ - bgp_attr_unintern (&tmp_ri->attr); - tmp_ri->attr = attr_new; - tmp_ri->uptime = bgp_clock (); - } - } - - /* Return back the route entry. */ - *ri = tmp_ri; - return route_change; +static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, + afi_t afi, safi_t safi, struct bgp_node *rn, + struct attr *attr, int add, int vni_table, + struct bgp_info **ri) +{ + struct bgp_info *tmp_ri; + struct bgp_info *local_ri, *remote_ri; + struct attr *attr_new; + mpls_label_t label = MPLS_INVALID_LABEL; + int route_change = 1; + u_char sticky = 0; + + *ri = NULL; + + /* See if this is an update of an existing route, or a new add. Also, + * identify if already known from remote, and if so, the one with the + * highest sequence number; this is only when adding to the VNI routing + * table. + */ + local_ri = remote_ri = NULL; + for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) { + if (tmp_ri->peer == bgp->peer_self + && tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_STATIC) + local_ri = tmp_ri; + if (vni_table) { + if (tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_NORMAL + && CHECK_FLAG(tmp_ri->flags, BGP_INFO_VALID)) { + if (!remote_ri) + remote_ri = tmp_ri; + else if (mac_mobility_seqnum(tmp_ri->attr) + > mac_mobility_seqnum(remote_ri->attr)) + remote_ri = tmp_ri; + } + } + } + + /* If route doesn't exist already, create a new one, if told to. + * Otherwise act based on whether the attributes of the route have + * changed or not. + */ + if (!local_ri && !add) + return 0; + + if (!local_ri) { + /* When learnt locally for the first time but already known from + * remote, we have to initiate appropriate MAC mobility steps. + * This + * is applicable when updating the VNI routing table. + */ + if (remote_ri) { + u_int32_t cur_seqnum; + + /* Add MM extended community to route. */ + cur_seqnum = mac_mobility_seqnum(remote_ri->attr); + add_mac_mobility_to_attr(cur_seqnum + 1, attr); + } + + /* Add (or update) attribute to hash. */ + attr_new = bgp_attr_intern(attr); + + /* Extract MAC mobility sequence number, if any. */ + attr_new->mm_seqnum = + bgp_attr_mac_mobility_seqnum(attr_new, &sticky); + attr_new->sticky = sticky; + + /* Create new route with its attribute. */ + tmp_ri = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0, + bgp->peer_self, attr_new, rn); + SET_FLAG(tmp_ri->flags, BGP_INFO_VALID); + bgp_info_extra_get(tmp_ri); + + /* The VNI goes into the 'label' field of the route */ + vni2label(vpn->vni, &label); + + memcpy(&tmp_ri->extra->label, &label, BGP_LABEL_BYTES); + bgp_info_add(rn, tmp_ri); + } else { + tmp_ri = local_ri; + if (attrhash_cmp(tmp_ri->attr, attr) + && !CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED)) + route_change = 0; + else { + /* The attribute has changed. */ + /* Add (or update) attribute to hash. */ + attr_new = bgp_attr_intern(attr); + bgp_info_set_flag(rn, tmp_ri, BGP_INFO_ATTR_CHANGED); + + /* Restore route, if needed. */ + if (CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED)) + bgp_info_restore(rn, tmp_ri); + + /* Unintern existing, set to new. */ + bgp_attr_unintern(&tmp_ri->attr); + tmp_ri->attr = attr_new; + tmp_ri->uptime = bgp_clock(); + } + } + + /* Return back the route entry. */ + *ri = tmp_ri; + return route_change; } /* * Create or update EVPN route (of type based on prefix) for specified VNI * and schedule for processing. */ -static int -update_evpn_route (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, u_char sticky) +static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, u_char sticky) { - struct bgp_node *rn; - struct attr attr; - struct attr *attr_new; - struct bgp_info *ri; - afi_t afi = AFI_L2VPN; - safi_t safi = SAFI_EVPN; - int route_change; + struct bgp_node *rn; + struct attr attr; + struct attr *attr_new; + struct bgp_info *ri; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + int route_change; - memset (&attr, 0, sizeof (struct attr)); + memset(&attr, 0, sizeof(struct attr)); - /* Build path-attribute for this route. */ - bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); - attr.nexthop = vpn->originator_ip; - attr.mp_nexthop_global_in = vpn->originator_ip; - attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = sticky; + /* Build path-attribute for this route. */ + bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); + attr.nexthop = vpn->originator_ip; + attr.mp_nexthop_global_in = vpn->originator_ip; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr.sticky = sticky; - /* Set up RT and ENCAP extended community. */ - build_evpn_route_extcomm (vpn, &attr); + /* Set up RT and ENCAP extended community. */ + build_evpn_route_extcomm(vpn, &attr); - /* First, create (or fetch) route node within the VNI. */ - /* NOTE: There is no RD here. */ - rn = bgp_node_get (vpn->route_table, (struct prefix *)p); + /* First, create (or fetch) route node within the VNI. */ + /* NOTE: There is no RD here. */ + rn = bgp_node_get(vpn->route_table, (struct prefix *)p); - /* Create or update route entry. */ - route_change = update_evpn_route_entry (bgp, vpn, afi, safi, - rn, &attr, 1, 1, &ri); - assert (ri); - attr_new = ri->attr; + /* Create or update route entry. */ + route_change = update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, + 1, 1, &ri); + assert(ri); + attr_new = ri->attr; - /* Perform route selection; this is just to set the flags correctly - * as local route in the VNI always wins. - */ - evpn_route_select_install (bgp, vpn, rn); - bgp_unlock_node (rn); + /* Perform route selection; this is just to set the flags correctly + * as local route in the VNI always wins. + */ + evpn_route_select_install(bgp, vpn, rn); + bgp_unlock_node(rn); - /* If this is a new route or some attribute has changed, export the - * route to the global table. The route will be advertised to peers - * from there. Note that this table is a 2-level tree (RD-level + - * Prefix-level) similar to L3VPN routes. - */ - if (route_change) - { - struct bgp_info *global_ri; + /* If this is a new route or some attribute has changed, export the + * route to the global table. The route will be advertised to peers + * from there. Note that this table is a 2-level tree (RD-level + + * Prefix-level) similar to L3VPN routes. + */ + if (route_change) { + struct bgp_info *global_ri; - rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, - (struct prefix *)p, &vpn->prd); - update_evpn_route_entry (bgp, vpn, afi, safi, rn, - attr_new, 1, 0, &global_ri); + rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, + (struct prefix *)p, &vpn->prd); + update_evpn_route_entry(bgp, vpn, afi, safi, rn, attr_new, 1, 0, + &global_ri); - /* Schedule for processing and unlock node. */ - bgp_process (bgp, rn, afi, safi); - bgp_unlock_node (rn); - } + /* Schedule for processing and unlock node. */ + bgp_process(bgp, rn, afi, safi); + bgp_unlock_node(rn); + } - /* Unintern temporary. */ - aspath_unintern (&attr.aspath); + /* Unintern temporary. */ + aspath_unintern(&attr.aspath); - return 0; + return 0; } /* * Delete EVPN route entry. This could be in the VNI route table * or the global route table. */ -static void -delete_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, - afi_t afi, safi_t safi, struct bgp_node *rn, - struct bgp_info **ri) +static void delete_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, + afi_t afi, safi_t safi, struct bgp_node *rn, + struct bgp_info **ri) { - struct bgp_info *tmp_ri; + struct bgp_info *tmp_ri; - *ri = NULL; + *ri = NULL; - /* Now, find matching route. */ - for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) - if (tmp_ri->peer == bgp->peer_self - && tmp_ri->type == ZEBRA_ROUTE_BGP - && tmp_ri->sub_type == BGP_ROUTE_STATIC) - break; + /* Now, find matching route. */ + for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) + if (tmp_ri->peer == bgp->peer_self + && tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_STATIC) + break; - *ri = tmp_ri; + *ri = tmp_ri; - /* Mark route for delete. */ - if (tmp_ri) - bgp_info_delete (rn, tmp_ri); + /* Mark route for delete. */ + if (tmp_ri) + bgp_info_delete(rn, tmp_ri); } /* * Delete EVPN route (of type based on prefix) for specified VNI and * schedule for processing. */ -static int -delete_evpn_route (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p) -{ - struct bgp_node *rn, *global_rn; - struct bgp_info *ri; - afi_t afi = AFI_L2VPN; - safi_t safi = SAFI_EVPN; - - /* First, locate the route node within the VNI. If it doesn't exist, there - * is nothing further to do. - */ - /* NOTE: There is no RD here. */ - rn = bgp_node_lookup (vpn->route_table, (struct prefix *)p); - if (!rn) - return 0; - - /* Next, locate route node in the global EVPN routing table. Note that - * this table is a 2-level tree (RD-level + Prefix-level) similar to - * L3VPN routes. - */ - global_rn = bgp_afi_node_lookup (bgp->rib[afi][safi], afi, safi, - (struct prefix *)p, &vpn->prd); - if (global_rn) - { - /* Delete route entry in the global EVPN table. */ - delete_evpn_route_entry (bgp, vpn, afi, safi, global_rn, &ri); - - /* Schedule for processing - withdraws to peers happen from - * this table. - */ - if (ri) - bgp_process (bgp, global_rn, afi, safi); - bgp_unlock_node (global_rn); - } - - /* Delete route entry in the VNI route table. This can just be removed. */ - delete_evpn_route_entry (bgp, vpn, afi, safi, rn, &ri); - if (ri) - bgp_info_reap (rn, ri); - bgp_unlock_node (rn); - - return 0; +static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p) +{ + struct bgp_node *rn, *global_rn; + struct bgp_info *ri; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + + /* First, locate the route node within the VNI. If it doesn't exist, + * there + * is nothing further to do. + */ + /* NOTE: There is no RD here. */ + rn = bgp_node_lookup(vpn->route_table, (struct prefix *)p); + if (!rn) + return 0; + + /* Next, locate route node in the global EVPN routing table. Note that + * this table is a 2-level tree (RD-level + Prefix-level) similar to + * L3VPN routes. + */ + global_rn = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi, + (struct prefix *)p, &vpn->prd); + if (global_rn) { + /* Delete route entry in the global EVPN table. */ + delete_evpn_route_entry(bgp, vpn, afi, safi, global_rn, &ri); + + /* Schedule for processing - withdraws to peers happen from + * this table. + */ + if (ri) + bgp_process(bgp, global_rn, afi, safi); + bgp_unlock_node(global_rn); + } + + /* Delete route entry in the VNI route table. This can just be removed. + */ + delete_evpn_route_entry(bgp, vpn, afi, safi, rn, &ri); + if (ri) + bgp_info_reap(rn, ri); + bgp_unlock_node(rn); + + return 0; } /* * Update all type-2 (MACIP) local routes for this VNI - these should also * be scheduled for advertise to peers. */ -static int -update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) -{ - afi_t afi; - safi_t safi; - struct bgp_node *rn; - struct bgp_info *ri; - struct attr attr; - struct attr attr_sticky; - struct attr *attr_new; - - afi = AFI_L2VPN; - safi = SAFI_EVPN; - memset (&attr, 0, sizeof (struct attr)); - memset (&attr_sticky, 0, sizeof (struct attr)); - - /* Build path-attribute - all type-2 routes for this VNI will share the - * same path attribute. - */ - bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); - bgp_attr_default_set (&attr_sticky, BGP_ORIGIN_IGP); - attr.nexthop = vpn->originator_ip; - attr.mp_nexthop_global_in = vpn->originator_ip; - attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr_sticky.nexthop = vpn->originator_ip; - attr_sticky.mp_nexthop_global_in = vpn->originator_ip; - attr_sticky.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr_sticky.sticky = 1; - - /* Set up RT, ENCAP and sticky MAC extended community. */ - build_evpn_route_extcomm (vpn, &attr); - build_evpn_route_extcomm (vpn, &attr_sticky); - - /* Walk this VNI's route table and update local type-2 routes. For any - * routes updated, update corresponding entry in the global table too. - */ - for (rn = bgp_table_top (vpn->route_table); rn; rn = bgp_route_next (rn)) - { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; - struct bgp_node *rd_rn; - struct bgp_info *global_ri; - - if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) - continue; - - if (evpn_route_is_sticky (bgp, rn)) - update_evpn_route_entry (bgp, vpn, afi, safi, rn, &attr_sticky, 0, 1, &ri); - else - update_evpn_route_entry (bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri); - - /* If a local route exists for this prefix, we need to update - * the global routing table too. - */ - if (!ri) - continue; - - /* Perform route selection; this is just to set the flags correctly - * as local route in the VNI always wins. - */ - evpn_route_select_install (bgp, vpn, rn); - - attr_new = ri->attr; - - /* Update route in global routing table. */ - rd_rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, - (struct prefix *)evp, &vpn->prd); - assert (rd_rn); - update_evpn_route_entry (bgp, vpn, afi, safi, rd_rn, - attr_new, 0, 0, &global_ri); - - /* Schedule for processing and unlock node. */ - bgp_process (bgp, rd_rn, afi, safi); - bgp_unlock_node (rd_rn); - } - - /* Unintern temporary. */ - aspath_unintern (&attr.aspath); - aspath_unintern (&attr_sticky.aspath); - - return 0; +static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) +{ + afi_t afi; + safi_t safi; + struct bgp_node *rn; + struct bgp_info *ri; + struct attr attr; + struct attr attr_sticky; + struct attr *attr_new; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + memset(&attr, 0, sizeof(struct attr)); + memset(&attr_sticky, 0, sizeof(struct attr)); + + /* Build path-attribute - all type-2 routes for this VNI will share the + * same path attribute. + */ + bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); + bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP); + attr.nexthop = vpn->originator_ip; + attr.mp_nexthop_global_in = vpn->originator_ip; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr_sticky.nexthop = vpn->originator_ip; + attr_sticky.mp_nexthop_global_in = vpn->originator_ip; + attr_sticky.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr_sticky.sticky = 1; + + /* Set up RT, ENCAP and sticky MAC extended community. */ + build_evpn_route_extcomm(vpn, &attr); + build_evpn_route_extcomm(vpn, &attr_sticky); + + /* Walk this VNI's route table and update local type-2 routes. For any + * routes updated, update corresponding entry in the global table too. + */ + for (rn = bgp_table_top(vpn->route_table); rn; + rn = bgp_route_next(rn)) { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + struct bgp_node *rd_rn; + struct bgp_info *global_ri; + + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + continue; + + if (evpn_route_is_sticky(bgp, rn)) + update_evpn_route_entry(bgp, vpn, afi, safi, rn, + &attr_sticky, 0, 1, &ri); + else + update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, + 0, 1, &ri); + + /* If a local route exists for this prefix, we need to update + * the global routing table too. + */ + if (!ri) + continue; + + /* Perform route selection; this is just to set the flags + * correctly + * as local route in the VNI always wins. + */ + evpn_route_select_install(bgp, vpn, rn); + + attr_new = ri->attr; + + /* Update route in global routing table. */ + rd_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, + (struct prefix *)evp, &vpn->prd); + assert(rd_rn); + update_evpn_route_entry(bgp, vpn, afi, safi, rd_rn, attr_new, 0, + 0, &global_ri); + + /* Schedule for processing and unlock node. */ + bgp_process(bgp, rd_rn, afi, safi); + bgp_unlock_node(rd_rn); + } + + /* Unintern temporary. */ + aspath_unintern(&attr.aspath); + aspath_unintern(&attr_sticky.aspath); + + return 0; } /* * Delete all type-2 (MACIP) local routes for this VNI - only from the * global routing table. These are also scheduled for withdraw from peers. */ -static int -delete_global_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) +static int delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) { - afi_t afi; - safi_t safi; - struct bgp_node *rdrn, *rn; - struct bgp_table *table; - struct bgp_info *ri; + afi_t afi; + safi_t safi; + struct bgp_node *rdrn, *rn; + struct bgp_table *table; + struct bgp_info *ri; - afi = AFI_L2VPN; - safi = SAFI_EVPN; + afi = AFI_L2VPN; + safi = SAFI_EVPN; - rdrn = bgp_node_lookup (bgp->rib[afi][safi], (struct prefix *) &vpn->prd); - if (rdrn && rdrn->info) - { - table = (struct bgp_table *)rdrn->info; - for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) - { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + rdrn = bgp_node_lookup(bgp->rib[afi][safi], (struct prefix *)&vpn->prd); + if (rdrn && rdrn->info) { + table = (struct bgp_table *)rdrn->info; + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; - if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) - continue; + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + continue; - delete_evpn_route_entry (bgp, vpn, afi, safi, rn, &ri); - if (ri) - bgp_process (bgp, rn, afi, safi); - } - } + delete_evpn_route_entry(bgp, vpn, afi, safi, rn, &ri); + if (ri) + bgp_process(bgp, rn, afi, safi); + } + } - /* Unlock RD node. */ - if (rdrn) - bgp_unlock_node (rdrn); + /* Unlock RD node. */ + if (rdrn) + bgp_unlock_node(rdrn); - return 0; + return 0; } /* * Delete all type-2 (MACIP) local routes for this VNI - from the global * table as well as the per-VNI route table. */ -static int -delete_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) +static int delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) { - afi_t afi; - safi_t safi; - struct bgp_node *rn; - struct bgp_info *ri; + afi_t afi; + safi_t safi; + struct bgp_node *rn; + struct bgp_info *ri; - afi = AFI_L2VPN; - safi = SAFI_EVPN; + afi = AFI_L2VPN; + safi = SAFI_EVPN; - /* First, walk the global route table for this VNI's type-2 local routes. - * EVPN routes are a 2-level table, first get the RD table. - */ - delete_global_type2_routes (bgp, vpn); + /* First, walk the global route table for this VNI's type-2 local + * routes. + * EVPN routes are a 2-level table, first get the RD table. + */ + delete_global_type2_routes(bgp, vpn); - /* Next, walk this VNI's route table and delete local type-2 routes. */ - for (rn = bgp_table_top (vpn->route_table); rn; rn = bgp_route_next (rn)) - { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + /* Next, walk this VNI's route table and delete local type-2 routes. */ + for (rn = bgp_table_top(vpn->route_table); rn; + rn = bgp_route_next(rn)) { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; - if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) - continue; + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + continue; - delete_evpn_route_entry (bgp, vpn, afi, safi, rn, &ri); + delete_evpn_route_entry(bgp, vpn, afi, safi, rn, &ri); - /* Route entry in local table gets deleted immediately. */ - if (ri) - bgp_info_reap (rn, ri); - } + /* Route entry in local table gets deleted immediately. */ + if (ri) + bgp_info_reap(rn, ri); + } - return 0; + return 0; } /* * Delete all routes in the per-VNI route table. */ -static int -delete_all_vni_routes (struct bgp *bgp, struct bgpevpn *vpn) +static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) { - struct bgp_node *rn; - struct bgp_info *ri, *nextri; + struct bgp_node *rn; + struct bgp_info *ri, *nextri; - /* Walk this VNI's route table and delete all routes. */ - for (rn = bgp_table_top (vpn->route_table); rn; rn = bgp_route_next (rn)) - { - for (ri = rn->info; (ri != NULL) && (nextri = ri->next, 1); ri = nextri) - { - bgp_info_delete (rn, ri); - bgp_info_reap (rn, ri); - } - } + /* Walk this VNI's route table and delete all routes. */ + for (rn = bgp_table_top(vpn->route_table); rn; + rn = bgp_route_next(rn)) { + for (ri = rn->info; (ri != NULL) && (nextri = ri->next, 1); + ri = nextri) { + bgp_info_delete(rn, ri); + bgp_info_reap(rn, ri); + } + } - return 0; + return 0; } /* @@ -1176,21 +1138,20 @@ delete_all_vni_routes (struct bgp *bgp, struct bgpevpn *vpn) * situations need the route in the per-VNI table as well as the global * table to be updated (as attributes change). */ -static int -update_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +static int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { - int ret; - struct prefix_evpn p; + int ret; + struct prefix_evpn p; - /* Update and advertise the type-3 route (only one) followed by the - * locally learnt type-2 routes (MACIP) - for this VNI. - */ - build_evpn_type3_prefix (&p, vpn->originator_ip); - ret = update_evpn_route (bgp, vpn, &p, 0); - if (ret) - return ret; + /* Update and advertise the type-3 route (only one) followed by the + * locally learnt type-2 routes (MACIP) - for this VNI. + */ + build_evpn_type3_prefix(&p, vpn->originator_ip); + ret = update_evpn_route(bgp, vpn, &p, 0); + if (ret) + return ret; - return update_all_type2_routes (bgp, vpn); + return update_all_type2_routes(bgp, vpn); } /* @@ -1199,289 +1160,291 @@ update_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) * the per-VNI table. Invoked upon the VNI being deleted or EVPN * (advertise-all-vni) being disabled. */ -static int -delete_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { - int ret; - struct prefix_evpn p; + int ret; + struct prefix_evpn p; - /* Delete and withdraw locally learnt type-2 routes (MACIP) - * followed by type-3 routes (only one) - for this VNI. - */ - ret = delete_all_type2_routes (bgp, vpn); - if (ret) - return ret; + /* Delete and withdraw locally learnt type-2 routes (MACIP) + * followed by type-3 routes (only one) - for this VNI. + */ + ret = delete_all_type2_routes(bgp, vpn); + if (ret) + return ret; - build_evpn_type3_prefix (&p, vpn->originator_ip); - ret = delete_evpn_route (bgp, vpn, &p); - if (ret) - return ret; + build_evpn_type3_prefix(&p, vpn->originator_ip); + ret = delete_evpn_route(bgp, vpn, &p); + if (ret) + return ret; - /* Delete all routes from the per-VNI table. */ - return delete_all_vni_routes (bgp, vpn); + /* Delete all routes from the per-VNI table. */ + return delete_all_vni_routes(bgp, vpn); } /* * There is a tunnel endpoint IP address change for this VNI, * need to re-advertise routes with the new nexthop. */ -static int -handle_tunnel_ip_change (struct bgp *bgp, struct bgpevpn *vpn, - struct in_addr originator_ip) +static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn, + struct in_addr originator_ip) { - struct prefix_evpn p; + struct prefix_evpn p; - /* Need to withdraw type-3 route as the originator IP is part - * of the key. - */ - build_evpn_type3_prefix (&p, vpn->originator_ip); - delete_evpn_route (bgp, vpn, &p); + /* Need to withdraw type-3 route as the originator IP is part + * of the key. + */ + build_evpn_type3_prefix(&p, vpn->originator_ip); + delete_evpn_route(bgp, vpn, &p); - /* Update the tunnel IP and re-advertise all routes for this VNI. */ - vpn->originator_ip = originator_ip; - return update_routes_for_vni (bgp, vpn); + /* Update the tunnel IP and re-advertise all routes for this VNI. */ + vpn->originator_ip = originator_ip; + return update_routes_for_vni(bgp, vpn); } /* * Install route entry into the VNI routing table and invoke route selection. */ -static int -install_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, struct bgp_info *parent_ri) -{ - struct bgp_node *rn; - struct bgp_info *ri; - struct attr *attr_new; - int ret; - - /* Create (or fetch) route within the VNI. */ - /* NOTE: There is no RD here. */ - rn = bgp_node_get (vpn->route_table, (struct prefix *)p); - - /* Check if route entry is already present. */ - for (ri = rn->info; ri; ri = ri->next) - if (ri->extra && - (struct bgp_info *)ri->extra->parent == parent_ri) - break; - - if (!ri) - { - /* Add (or update) attribute to hash. */ - attr_new = bgp_attr_intern (parent_ri->attr); - - /* Create new route with its attribute. */ - ri = info_make (parent_ri->type, parent_ri->sub_type, 0, - parent_ri->peer, attr_new, rn); - SET_FLAG (ri->flags, BGP_INFO_VALID); - bgp_info_extra_get(ri); - ri->extra->parent = parent_ri; - if (parent_ri->extra) - memcpy (&ri->extra->label, &parent_ri->extra->label, BGP_LABEL_BYTES); - bgp_info_add (rn, ri); - } - else - { - if (attrhash_cmp (ri->attr, parent_ri->attr) && - !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) - { - bgp_unlock_node (rn); - return 0; - } - /* The attribute has changed. */ - /* Add (or update) attribute to hash. */ - attr_new = bgp_attr_intern (parent_ri->attr); - - /* Restore route, if needed. */ - if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) - bgp_info_restore(rn, ri); - - /* Mark if nexthop has changed. */ - if (!IPV4_ADDR_SAME (&ri->attr->nexthop, &attr_new->nexthop)) - SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED); - - /* Unintern existing, set to new. */ - bgp_attr_unintern (&ri->attr); - ri->attr = attr_new; - ri->uptime = bgp_clock (); - } - - /* Perform route selection and update zebra, if required. */ - ret = evpn_route_select_install (bgp, vpn, rn); - - return ret; +static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, + struct bgp_info *parent_ri) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct attr *attr_new; + int ret; + + /* Create (or fetch) route within the VNI. */ + /* NOTE: There is no RD here. */ + rn = bgp_node_get(vpn->route_table, (struct prefix *)p); + + /* Check if route entry is already present. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->extra + && (struct bgp_info *)ri->extra->parent == parent_ri) + break; + + if (!ri) { + /* Add (or update) attribute to hash. */ + attr_new = bgp_attr_intern(parent_ri->attr); + + /* Create new route with its attribute. */ + ri = info_make(parent_ri->type, parent_ri->sub_type, 0, + parent_ri->peer, attr_new, rn); + SET_FLAG(ri->flags, BGP_INFO_VALID); + bgp_info_extra_get(ri); + ri->extra->parent = parent_ri; + if (parent_ri->extra) + memcpy(&ri->extra->label, &parent_ri->extra->label, + BGP_LABEL_BYTES); + bgp_info_add(rn, ri); + } else { + if (attrhash_cmp(ri->attr, parent_ri->attr) + && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { + bgp_unlock_node(rn); + return 0; + } + /* The attribute has changed. */ + /* Add (or update) attribute to hash. */ + attr_new = bgp_attr_intern(parent_ri->attr); + + /* Restore route, if needed. */ + if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + bgp_info_restore(rn, ri); + + /* Mark if nexthop has changed. */ + if (!IPV4_ADDR_SAME(&ri->attr->nexthop, &attr_new->nexthop)) + SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED); + + /* Unintern existing, set to new. */ + bgp_attr_unintern(&ri->attr); + ri->attr = attr_new; + ri->uptime = bgp_clock(); + } + + /* Perform route selection and update zebra, if required. */ + ret = evpn_route_select_install(bgp, vpn, rn); + + return ret; } /* * Uninstall route entry from the VNI routing table and send message * to zebra, if appropriate. */ -static int -uninstall_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, struct bgp_info *parent_ri) +static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, + struct bgp_info *parent_ri) { - struct bgp_node *rn; - struct bgp_info *ri; - int ret; + struct bgp_node *rn; + struct bgp_info *ri; + int ret; - /* Locate route within the VNI. */ - /* NOTE: There is no RD here. */ - rn = bgp_node_lookup (vpn->route_table, (struct prefix *)p); - if (!rn) - return 0; + /* Locate route within the VNI. */ + /* NOTE: There is no RD here. */ + rn = bgp_node_lookup(vpn->route_table, (struct prefix *)p); + if (!rn) + return 0; - /* Find matching route entry. */ - for (ri = rn->info; ri; ri = ri->next) - if (ri->extra && - (struct bgp_info *)ri->extra->parent == parent_ri) - break; + /* Find matching route entry. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->extra + && (struct bgp_info *)ri->extra->parent == parent_ri) + break; - if (!ri) - return 0; + if (!ri) + return 0; - /* Mark entry for deletion */ - bgp_info_delete (rn, ri); + /* Mark entry for deletion */ + bgp_info_delete(rn, ri); - /* Perform route selection and update zebra, if required. */ - ret = evpn_route_select_install (bgp, vpn, rn); + /* Perform route selection and update zebra, if required. */ + ret = evpn_route_select_install(bgp, vpn, rn); - /* Unlock route node. */ - bgp_unlock_node (rn); + /* Unlock route node. */ + bgp_unlock_node(rn); - return ret; + return ret; } /* * Given a route entry and a VNI, see if this route entry should be * imported into the VNI i.e., RTs match. */ -static int -is_route_matching_for_vni (struct bgp *bgp, struct bgpevpn *vpn, - struct bgp_info *ri) -{ - struct attr *attr = ri->attr; - struct ecommunity *ecom; - int i; - - assert (attr); - /* Route should have valid RT to be even considered. */ - if (!(attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) - return 0; - - ecom = attr->ecommunity; - if (!ecom || !ecom->size) - return 0; - - /* For each extended community RT, see if it matches this VNI. If any RT - * matches, we're done. - */ - for (i = 0; i < ecom->size; i++) - { - u_char *pnt; - u_char type, sub_type; - struct ecommunity_val *eval; - struct ecommunity_val eval_tmp; - struct irt_node *irt; - - /* Only deal with RTs */ - pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); - eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); - type = *pnt++; - sub_type = *pnt++; - if (sub_type != ECOMMUNITY_ROUTE_TARGET) - continue; - - /* See if this RT matches specified VNIs import RTs */ - irt = lookup_import_rt (bgp, eval); - if (irt && irt->vnis) - if (is_vni_present_in_irt_vnis (irt->vnis, vpn)) - return 1; - - /* Also check for non-exact match. In this, we mask out the AS and - * only check on the local-admin sub-field. This is to facilitate using - * VNI as the RT for EBGP peering too. - */ - irt = NULL; - if (type == ECOMMUNITY_ENCODE_AS || - type == ECOMMUNITY_ENCODE_AS4 || - type == ECOMMUNITY_ENCODE_IP) - { - memcpy (&eval_tmp, eval, ECOMMUNITY_SIZE); - mask_ecom_global_admin (&eval_tmp, eval); - irt = lookup_import_rt (bgp, &eval_tmp); - } - if (irt && irt->vnis) - if (is_vni_present_in_irt_vnis (irt->vnis, vpn)) - return 1; - } - - return 0; +static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_info *ri) +{ + struct attr *attr = ri->attr; + struct ecommunity *ecom; + int i; + + assert(attr); + /* Route should have valid RT to be even considered. */ + if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) + return 0; + + ecom = attr->ecommunity; + if (!ecom || !ecom->size) + return 0; + + /* For each extended community RT, see if it matches this VNI. If any RT + * matches, we're done. + */ + for (i = 0; i < ecom->size; i++) { + u_char *pnt; + u_char type, sub_type; + struct ecommunity_val *eval; + struct ecommunity_val eval_tmp; + struct irt_node *irt; + + /* Only deal with RTs */ + pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + eval = (struct ecommunity_val *)(ecom->val + + (i * ECOMMUNITY_SIZE)); + type = *pnt++; + sub_type = *pnt++; + if (sub_type != ECOMMUNITY_ROUTE_TARGET) + continue; + + /* See if this RT matches specified VNIs import RTs */ + irt = lookup_import_rt(bgp, eval); + if (irt && irt->vnis) + if (is_vni_present_in_irt_vnis(irt->vnis, vpn)) + return 1; + + /* Also check for non-exact match. In this, we mask out the AS + * and + * only check on the local-admin sub-field. This is to + * facilitate using + * VNI as the RT for EBGP peering too. + */ + irt = NULL; + if (type == ECOMMUNITY_ENCODE_AS + || type == ECOMMUNITY_ENCODE_AS4 + || type == ECOMMUNITY_ENCODE_IP) { + memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE); + mask_ecom_global_admin(&eval_tmp, eval); + irt = lookup_import_rt(bgp, &eval_tmp); + } + if (irt && irt->vnis) + if (is_vni_present_in_irt_vnis(irt->vnis, vpn)) + return 1; + } + + return 0; } /* * Install or uninstall routes of specified type that are appropriate for this * particular VNI. */ -static int -install_uninstall_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn, - bgp_evpn_route_type rtype, int install) -{ - afi_t afi; - safi_t safi; - struct bgp_node *rd_rn, *rn; - struct bgp_table *table; - struct bgp_info *ri; - int ret; - - afi = AFI_L2VPN; - safi = SAFI_EVPN; - - /* Walk entire global routing table and evaluate routes which could be - * imported into this VPN. Note that we cannot just look at the routes for - * the VNI's RD - remote routes applicable for this VNI could have any RD. - */ - /* EVPN routes are a 2-level table. */ - for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn; rd_rn = bgp_route_next (rd_rn)) - { - table = (struct bgp_table *)(rd_rn->info); - if (!table) - continue; - - for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) - { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; - - if (evp->prefix.route_type != rtype) - continue; - - for (ri = rn->info; ri; ri = ri->next) - { - /* Consider "valid" remote routes applicable for this VNI. */ - if (!(CHECK_FLAG (ri->flags, BGP_INFO_VALID) - && ri->type == ZEBRA_ROUTE_BGP - && ri->sub_type == BGP_ROUTE_NORMAL)) - continue; - - if (is_route_matching_for_vni (bgp, vpn, ri)) - { - if (install) - ret = install_evpn_route_entry (bgp, vpn, evp, ri); - else - ret = uninstall_evpn_route_entry (bgp, vpn, evp, ri); - - if (ret) - { - zlog_err ("%u: Failed to %s EVPN %s route in VNI %u", - bgp->vrf_id, install ? "install" : "uninstall", - rtype == BGP_EVPN_MAC_IP_ROUTE ? \ - "MACIP" : "IMET", vpn->vni); - return ret; - } - } - } - } - } - - return 0; +static int install_uninstall_routes_for_vni(struct bgp *bgp, + struct bgpevpn *vpn, + bgp_evpn_route_type rtype, + int install) +{ + afi_t afi; + safi_t safi; + struct bgp_node *rd_rn, *rn; + struct bgp_table *table; + struct bgp_info *ri; + int ret; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + + /* Walk entire global routing table and evaluate routes which could be + * imported into this VPN. Note that we cannot just look at the routes + * for + * the VNI's RD - remote routes applicable for this VNI could have any + * RD. + */ + /* EVPN routes are a 2-level table. */ + for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn; + rd_rn = bgp_route_next(rd_rn)) { + table = (struct bgp_table *)(rd_rn->info); + if (!table) + continue; + + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + + if (evp->prefix.route_type != rtype) + continue; + + for (ri = rn->info; ri; ri = ri->next) { + /* Consider "valid" remote routes applicable for + * this VNI. */ + if (!(CHECK_FLAG(ri->flags, BGP_INFO_VALID) + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_NORMAL)) + continue; + + if (is_route_matching_for_vni(bgp, vpn, ri)) { + if (install) + ret = install_evpn_route_entry( + bgp, vpn, evp, ri); + else + ret = uninstall_evpn_route_entry( + bgp, vpn, evp, ri); + + if (ret) { + zlog_err( + "%u: Failed to %s EVPN %s route in VNI %u", + bgp->vrf_id, + install ? "install" + : "uninstall", + rtype == BGP_EVPN_MAC_IP_ROUTE + ? "MACIP" + : "IMET", + vpn->vni); + return ret; + } + } + } + } + } + + return 0; } /* @@ -1489,148 +1452,151 @@ install_uninstall_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn, * routing table. This is invoked when a VNI becomes "live" or its Import * RT is changed. */ -static int -install_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +static int install_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { - int ret; + int ret; - /* Install type-3 routes followed by type-2 routes - the ones applicable - * for this VNI. - */ - ret = install_uninstall_routes_for_vni (bgp, vpn, BGP_EVPN_IMET_ROUTE, 1); - if (ret) - return ret; + /* Install type-3 routes followed by type-2 routes - the ones applicable + * for this VNI. + */ + ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_IMET_ROUTE, + 1); + if (ret) + return ret; - return install_uninstall_routes_for_vni (bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, 1); + return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, + 1); } /* * Uninstall any existing remote routes for this VNI. One scenario in which * this is invoked is upon an import RT change. */ -static int -uninstall_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { - int ret; + int ret; - /* Uninstall type-2 routes followed by type-3 routes - the ones applicable - * for this VNI. - */ - ret = install_uninstall_routes_for_vni (bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, 0); - if (ret) - return ret; + /* Uninstall type-2 routes followed by type-3 routes - the ones + * applicable + * for this VNI. + */ + ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, + 0); + if (ret) + return ret; - return install_uninstall_routes_for_vni (bgp, vpn, BGP_EVPN_IMET_ROUTE, 0); + return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_IMET_ROUTE, + 0); } /* * Install or uninstall route in matching VNIs (list). */ -static int -install_uninstall_route_in_vnis (struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix_evpn *evp, struct bgp_info *ri, - struct list *vnis, int install) +static int install_uninstall_route_in_vnis(struct bgp *bgp, afi_t afi, + safi_t safi, struct prefix_evpn *evp, + struct bgp_info *ri, + struct list *vnis, int install) { - struct bgpevpn *vpn; - struct listnode *node, *nnode; + struct bgpevpn *vpn; + struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS (vnis, node, nnode, vpn)) - { - int ret; + for (ALL_LIST_ELEMENTS(vnis, node, nnode, vpn)) { + int ret; - if (!is_vni_live (vpn)) - continue; + if (!is_vni_live(vpn)) + continue; - if (install) - ret = install_evpn_route_entry (bgp, vpn, evp, ri); - else - ret = uninstall_evpn_route_entry (bgp, vpn, evp, ri); + if (install) + ret = install_evpn_route_entry(bgp, vpn, evp, ri); + else + ret = uninstall_evpn_route_entry(bgp, vpn, evp, ri); - if (ret) - { - zlog_err ("%u: Failed to %s EVPN %s route in VNI %u", - bgp->vrf_id, install ? "install" : "uninstall", - evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ? \ - "MACIP" : "IMET", vpn->vni); - return ret; - } - } + if (ret) { + zlog_err("%u: Failed to %s EVPN %s route in VNI %u", + bgp->vrf_id, install ? "install" : "uninstall", + evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE + ? "MACIP" + : "IMET", + vpn->vni); + return ret; + } + } - return 0; + return 0; } /* * Install or uninstall route for appropriate VNIs. */ -static int -install_uninstall_evpn_route (struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix *p, struct bgp_info *ri, - int import) -{ - struct prefix_evpn *evp = (struct prefix_evpn *)p; - struct attr *attr = ri->attr; - struct ecommunity *ecom; - int i; - - assert (attr); - - /* Only type-2 and type-3 routes go into a L2 VNI. */ - if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE || - evp->prefix.route_type == BGP_EVPN_IMET_ROUTE)) - return 0; - - /* If we don't have Route Target, nothing much to do. */ - if (!(attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) - return 0; - - ecom = attr->ecommunity; - if (!ecom || !ecom->size) - return -1; - - /* For each extended community RT, see which VNIs match and import - * the route into matching VNIs. - */ - for (i = 0; i < ecom->size; i++) - { - u_char *pnt; - u_char type, sub_type; - struct ecommunity_val *eval; - struct ecommunity_val eval_tmp; - struct irt_node *irt; - - /* Only deal with RTs */ - pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); - eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); - type = *pnt++; - sub_type = *pnt++; - if (sub_type != ECOMMUNITY_ROUTE_TARGET) - continue; - - /* Are we interested in this RT? */ - irt = lookup_import_rt (bgp, eval); - if (irt && irt->vnis) - install_uninstall_route_in_vnis (bgp, afi, safi, evp, - ri, irt->vnis, import); - - /* Also check for non-exact match. In this, we mask out the AS and - * only check on the local-admin sub-field. This is to facilitate using - * VNI as the RT for EBGP peering too. - */ - irt = NULL; - if (type == ECOMMUNITY_ENCODE_AS || - type == ECOMMUNITY_ENCODE_AS4 || - type == ECOMMUNITY_ENCODE_IP) - { - memcpy (&eval_tmp, eval, ECOMMUNITY_SIZE); - mask_ecom_global_admin (&eval_tmp, eval); - irt = lookup_import_rt (bgp, &eval_tmp); - } - if (irt && irt->vnis) - install_uninstall_route_in_vnis (bgp, afi, safi, evp, - ri, irt->vnis, import); - } - - return 0; +static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi, + struct prefix *p, struct bgp_info *ri, + int import) +{ + struct prefix_evpn *evp = (struct prefix_evpn *)p; + struct attr *attr = ri->attr; + struct ecommunity *ecom; + int i; + + assert(attr); + + /* Only type-2 and type-3 routes go into a L2 VNI. */ + if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE + || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE)) + return 0; + + /* If we don't have Route Target, nothing much to do. */ + if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) + return 0; + + ecom = attr->ecommunity; + if (!ecom || !ecom->size) + return -1; + + /* For each extended community RT, see which VNIs match and import + * the route into matching VNIs. + */ + for (i = 0; i < ecom->size; i++) { + u_char *pnt; + u_char type, sub_type; + struct ecommunity_val *eval; + struct ecommunity_val eval_tmp; + struct irt_node *irt; + + /* Only deal with RTs */ + pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + eval = (struct ecommunity_val *)(ecom->val + + (i * ECOMMUNITY_SIZE)); + type = *pnt++; + sub_type = *pnt++; + if (sub_type != ECOMMUNITY_ROUTE_TARGET) + continue; + + /* Are we interested in this RT? */ + irt = lookup_import_rt(bgp, eval); + if (irt && irt->vnis) + install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri, + irt->vnis, import); + + /* Also check for non-exact match. In this, we mask out the AS + * and + * only check on the local-admin sub-field. This is to + * facilitate using + * VNI as the RT for EBGP peering too. + */ + irt = NULL; + if (type == ECOMMUNITY_ENCODE_AS + || type == ECOMMUNITY_ENCODE_AS4 + || type == ECOMMUNITY_ENCODE_IP) { + memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE); + mask_ecom_global_admin(&eval_tmp, eval); + irt = lookup_import_rt(bgp, &eval_tmp); + } + if (irt && irt->vnis) + install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri, + irt->vnis, import); + } + + return 0; } /* @@ -1638,118 +1604,114 @@ install_uninstall_evpn_route (struct bgp *bgp, afi_t afi, safi_t safi, * change. Note that the processing is done only on the global route table * using routes that already exist in the per-VNI table. */ -static int -update_advertise_vni_routes (struct bgp *bgp, struct bgpevpn *vpn) -{ - struct prefix_evpn p; - struct bgp_node *rn, *global_rn; - struct bgp_info *ri, *global_ri; - struct attr *attr; - afi_t afi = AFI_L2VPN; - safi_t safi = SAFI_EVPN; - - /* Locate type-3 route for VNI in the per-VNI table and use its - * attributes to create and advertise the type-3 route for this VNI - * in the global table. - */ - build_evpn_type3_prefix (&p, vpn->originator_ip); - rn = bgp_node_lookup (vpn->route_table, (struct prefix *)&p); - if (!rn) /* unexpected */ - return 0; - for (ri = rn->info; ri; ri = ri->next) - if (ri->peer == bgp->peer_self - && ri->type == ZEBRA_ROUTE_BGP - && ri->sub_type == BGP_ROUTE_STATIC) - break; - if (!ri) /* unexpected */ - return 0; - attr = ri->attr; - - global_rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, - (struct prefix *)&p, &vpn->prd); - update_evpn_route_entry (bgp, vpn, afi, safi, global_rn, - attr, 1, 0, &ri); - - /* Schedule for processing and unlock node. */ - bgp_process (bgp, global_rn, afi, safi); - bgp_unlock_node (global_rn); - - /* Now, walk this VNI's route table and use the route and its attribute - * to create and schedule route in global table. - */ - for (rn = bgp_table_top (vpn->route_table); rn; rn = bgp_route_next (rn)) - { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; - - /* Identify MAC-IP local routes. */ - if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) - continue; - - for (ri = rn->info; ri; ri = ri->next) - if (ri->peer == bgp->peer_self - && ri->type == ZEBRA_ROUTE_BGP - && ri->sub_type == BGP_ROUTE_STATIC) - break; - if (!ri) - continue; - - /* Create route in global routing table using this route entry's - * attribute. - */ - attr = ri->attr; - global_rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, - (struct prefix *)evp, &vpn->prd); - assert (global_rn); - update_evpn_route_entry (bgp, vpn, afi, safi, global_rn, - attr, 1, 0, &global_ri); - - /* Schedule for processing and unlock node. */ - bgp_process (bgp, global_rn, afi, safi); - bgp_unlock_node (global_rn); - } - - return 0; +static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) +{ + struct prefix_evpn p; + struct bgp_node *rn, *global_rn; + struct bgp_info *ri, *global_ri; + struct attr *attr; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + + /* Locate type-3 route for VNI in the per-VNI table and use its + * attributes to create and advertise the type-3 route for this VNI + * in the global table. + */ + build_evpn_type3_prefix(&p, vpn->originator_ip); + rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p); + if (!rn) /* unexpected */ + return 0; + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + if (!ri) /* unexpected */ + return 0; + attr = ri->attr; + + global_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, + (struct prefix *)&p, &vpn->prd); + update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, 0, + &ri); + + /* Schedule for processing and unlock node. */ + bgp_process(bgp, global_rn, afi, safi); + bgp_unlock_node(global_rn); + + /* Now, walk this VNI's route table and use the route and its attribute + * to create and schedule route in global table. + */ + for (rn = bgp_table_top(vpn->route_table); rn; + rn = bgp_route_next(rn)) { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + + /* Identify MAC-IP local routes. */ + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + continue; + + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + if (!ri) + continue; + + /* Create route in global routing table using this route entry's + * attribute. + */ + attr = ri->attr; + global_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, + (struct prefix *)evp, &vpn->prd); + assert(global_rn); + update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, + 0, &global_ri); + + /* Schedule for processing and unlock node. */ + bgp_process(bgp, global_rn, afi, safi); + bgp_unlock_node(global_rn); + } + + return 0; } /* * Delete (and withdraw) local routes for a VNI - only from the global * table. Invoked upon router-id change. */ -static int -delete_withdraw_vni_routes (struct bgp *bgp, struct bgpevpn *vpn) +static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) { - int ret; - struct prefix_evpn p; - struct bgp_node *global_rn; - struct bgp_info *ri; - afi_t afi = AFI_L2VPN; - safi_t safi = SAFI_EVPN; + int ret; + struct prefix_evpn p; + struct bgp_node *global_rn; + struct bgp_info *ri; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; - /* Delete and withdraw locally learnt type-2 routes (MACIP) - * for this VNI - from the global table. - */ - ret = delete_global_type2_routes (bgp, vpn); - if (ret) - return ret; + /* Delete and withdraw locally learnt type-2 routes (MACIP) + * for this VNI - from the global table. + */ + ret = delete_global_type2_routes(bgp, vpn); + if (ret) + return ret; - /* Remove type-3 route for this VNI from global table. */ - build_evpn_type3_prefix (&p, vpn->originator_ip); - global_rn = bgp_afi_node_lookup (bgp->rib[afi][safi], afi, safi, - (struct prefix *)&p, &vpn->prd); - if (global_rn) - { - /* Delete route entry in the global EVPN table. */ - delete_evpn_route_entry (bgp, vpn, afi, safi, global_rn, &ri); + /* Remove type-3 route for this VNI from global table. */ + build_evpn_type3_prefix(&p, vpn->originator_ip); + global_rn = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi, + (struct prefix *)&p, &vpn->prd); + if (global_rn) { + /* Delete route entry in the global EVPN table. */ + delete_evpn_route_entry(bgp, vpn, afi, safi, global_rn, &ri); - /* Schedule for processing - withdraws to peers happen from - * this table. - */ - if (ri) - bgp_process (bgp, global_rn, afi, safi); - bgp_unlock_node (global_rn); - } + /* Schedule for processing - withdraws to peers happen from + * this table. + */ + if (ri) + bgp_process(bgp, global_rn, afi, safi); + bgp_unlock_node(global_rn); + } - return 0; + return 0; } /* @@ -1758,26 +1720,23 @@ delete_withdraw_vni_routes (struct bgp *bgp, struct bgpevpn *vpn) * router-id. The routes in the per-VNI table are used to create routes in * the global table and schedule them. */ -static void -update_router_id_vni (struct hash_backet *backet, struct bgp *bgp) +static void update_router_id_vni(struct hash_backet *backet, struct bgp *bgp) { - struct bgpevpn *vpn; + struct bgpevpn *vpn; - vpn = (struct bgpevpn *) backet->data; + vpn = (struct bgpevpn *)backet->data; - if (!vpn) - { - zlog_warn ("%s: VNI hash entry for VNI not found", - __FUNCTION__); - return; - } + if (!vpn) { + zlog_warn("%s: VNI hash entry for VNI not found", __FUNCTION__); + return; + } - /* Skip VNIs with configured RD. */ - if (is_rd_configured (vpn)) - return; + /* Skip VNIs with configured RD. */ + if (is_rd_configured(vpn)) + return; - bgp_evpn_derive_auto_rd (bgp, vpn); - update_advertise_vni_routes (bgp, vpn); + bgp_evpn_derive_auto_rd(bgp, vpn); + update_advertise_vni_routes(bgp, vpn); } /* @@ -1786,365 +1745,349 @@ update_router_id_vni (struct hash_backet *backet, struct bgp *bgp) * the router-id and is done only on the global route table, the routes * are needed in the per-VNI table to re-advertise with new router id. */ -static void -withdraw_router_id_vni (struct hash_backet *backet, struct bgp *bgp) +static void withdraw_router_id_vni(struct hash_backet *backet, struct bgp *bgp) { - struct bgpevpn *vpn; + struct bgpevpn *vpn; - vpn = (struct bgpevpn *) backet->data; + vpn = (struct bgpevpn *)backet->data; - if (!vpn) - { - zlog_warn ("%s: VNI hash entry for VNI not found", - __FUNCTION__); - return; - } + if (!vpn) { + zlog_warn("%s: VNI hash entry for VNI not found", __FUNCTION__); + return; + } - /* Skip VNIs with configured RD. */ - if (is_rd_configured (vpn)) - return; + /* Skip VNIs with configured RD. */ + if (is_rd_configured(vpn)) + return; - delete_withdraw_vni_routes (bgp, vpn); + delete_withdraw_vni_routes(bgp, vpn); } /* * Process received EVPN type-2 route (advertise or withdraw). */ -static int -process_type2_route (struct peer *peer, afi_t afi, safi_t safi, - struct attr *attr, u_char *pfx, int psize, - u_int32_t addpath_id) -{ - struct prefix_rd prd; - struct prefix_evpn p; - u_char ipaddr_len; - u_char macaddr_len; - mpls_label_t *label_pnt; - int ret; - - /* Type-2 route should be either 33, 37 or 49 bytes or an - * additional 3 bytes if there is a second label (VNI): - * RD (8), ESI (10), Eth Tag (4), MAC Addr Len (1), - * MAC Addr (6), IP len (1), IP (0, 4 or 16), - * MPLS Lbl1 (3), MPLS Lbl2 (0 or 3) - */ - if (psize != 33 && psize != 37 && psize != 49 && - psize != 36 && psize != 40 && psize != 52) - { - zlog_err ("%u:%s - Rx EVPN Type-2 NLRI with invalid length %d", - peer->bgp->vrf_id, peer->host, psize); - return -1; - } - - /* Make prefix_rd */ - prd.family = AF_UNSPEC; - prd.prefixlen = 64; - memcpy (&prd.val, pfx, 8); - pfx += 8; - - /* Make EVPN prefix. */ - memset (&p, 0, sizeof (struct prefix_evpn)); - p.family = AF_ETHERNET; - p.prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; - p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; - - /* Skip over Ethernet Seg Identifier for now. */ - pfx += 10; - - /* Skip over Ethernet Tag for now. */ - pfx += 4; - - /* Get the MAC Addr len */ - macaddr_len = *pfx++; - - /* Get the MAC Addr */ - if (macaddr_len == (ETHER_ADDR_LEN * 8)) - { - memcpy (&p.prefix.mac.octet, pfx, ETHER_ADDR_LEN); - pfx += ETHER_ADDR_LEN; - } - else - { - zlog_err ("%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d", - peer->bgp->vrf_id, peer->host, macaddr_len); - return -1; - } - - - /* Get the IP. */ - ipaddr_len = *pfx++; - if (ipaddr_len != 0 && - ipaddr_len != IPV4_MAX_BITLEN && - ipaddr_len != IPV6_MAX_BITLEN) - { - zlog_err ("%u:%s - Rx EVPN Type-2 NLRI with unsupported IP address length %d", - peer->bgp->vrf_id, peer->host, ipaddr_len); - return -1; - } - - if (ipaddr_len) - { - ipaddr_len /= 8; /* Convert to bytes. */ - p.prefix.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN) ? - IPADDR_V4 : IPADDR_V6; - memcpy (&p.prefix.ip.ip.addr, pfx, ipaddr_len); - } - pfx += ipaddr_len; - - /* Get the VNI (in MPLS label field). */ - /* Note: We ignore the second VNI, if any. */ - label_pnt = (mpls_label_t *) pfx; - - /* Process the route. */ - if (attr) - ret = bgp_update (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, label_pnt, 0, NULL); - else - ret = bgp_withdraw (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, label_pnt, NULL); - return ret; +static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, + struct attr *attr, u_char *pfx, int psize, + u_int32_t addpath_id) +{ + struct prefix_rd prd; + struct prefix_evpn p; + u_char ipaddr_len; + u_char macaddr_len; + mpls_label_t *label_pnt; + int ret; + + /* Type-2 route should be either 33, 37 or 49 bytes or an + * additional 3 bytes if there is a second label (VNI): + * RD (8), ESI (10), Eth Tag (4), MAC Addr Len (1), + * MAC Addr (6), IP len (1), IP (0, 4 or 16), + * MPLS Lbl1 (3), MPLS Lbl2 (0 or 3) + */ + if (psize != 33 && psize != 37 && psize != 49 && psize != 36 + && psize != 40 && psize != 52) { + zlog_err("%u:%s - Rx EVPN Type-2 NLRI with invalid length %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memcpy(&prd.val, pfx, 8); + pfx += 8; + + /* Make EVPN prefix. */ + memset(&p, 0, sizeof(struct prefix_evpn)); + p.family = AF_ETHERNET; + p.prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; + p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; + + /* Skip over Ethernet Seg Identifier for now. */ + pfx += 10; + + /* Skip over Ethernet Tag for now. */ + pfx += 4; + + /* Get the MAC Addr len */ + macaddr_len = *pfx++; + + /* Get the MAC Addr */ + if (macaddr_len == (ETHER_ADDR_LEN * 8)) { + memcpy(&p.prefix.mac.octet, pfx, ETHER_ADDR_LEN); + pfx += ETHER_ADDR_LEN; + } else { + zlog_err( + "%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d", + peer->bgp->vrf_id, peer->host, macaddr_len); + return -1; + } + + + /* Get the IP. */ + ipaddr_len = *pfx++; + if (ipaddr_len != 0 && ipaddr_len != IPV4_MAX_BITLEN + && ipaddr_len != IPV6_MAX_BITLEN) { + zlog_err( + "%u:%s - Rx EVPN Type-2 NLRI with unsupported IP address length %d", + peer->bgp->vrf_id, peer->host, ipaddr_len); + return -1; + } + + if (ipaddr_len) { + ipaddr_len /= 8; /* Convert to bytes. */ + p.prefix.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN) + ? IPADDR_V4 + : IPADDR_V6; + memcpy(&p.prefix.ip.ip.addr, pfx, ipaddr_len); + } + pfx += ipaddr_len; + + /* Get the VNI (in MPLS label field). */ + /* Note: We ignore the second VNI, if any. */ + label_pnt = (mpls_label_t *)pfx; + + /* Process the route. */ + if (attr) + ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, + afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + &prd, label_pnt, 0, NULL); + else + ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, + afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + &prd, label_pnt, NULL); + return ret; } /* * Process received EVPN type-3 route (advertise or withdraw). */ -static int -process_type3_route (struct peer *peer, afi_t afi, safi_t safi, - struct attr *attr, u_char *pfx, int psize, - u_int32_t addpath_id) -{ - struct prefix_rd prd; - struct prefix_evpn p; - u_char ipaddr_len; - int ret; - - /* Type-3 route should be either 17 or 29 bytes: RD (8), Eth Tag (4), - * IP len (1) and IP (4 or 16). - */ - if (psize != 17 && psize != 29) - { - zlog_err ("%u:%s - Rx EVPN Type-3 NLRI with invalid length %d", - peer->bgp->vrf_id, peer->host, psize); - return -1; - } - - /* Make prefix_rd */ - prd.family = AF_UNSPEC; - prd.prefixlen = 64; - memcpy (&prd.val, pfx, 8); - pfx += 8; - - /* Make EVPN prefix. */ - memset (&p, 0, sizeof (struct prefix_evpn)); - p.family = AF_ETHERNET; - p.prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN; - p.prefix.route_type = BGP_EVPN_IMET_ROUTE; - - /* Skip over Ethernet Tag for now. */ - pfx += 4; - - /* Get the IP. */ - ipaddr_len = *pfx++; - if (ipaddr_len == IPV4_MAX_BITLEN) - { - p.prefix.ip.ipa_type = IPADDR_V4; - memcpy (&p.prefix.ip.ip.addr, pfx, IPV4_MAX_BYTELEN); - } - else - { - zlog_err ("%u:%s - Rx EVPN Type-3 NLRI with unsupported IP address length %d", - peer->bgp->vrf_id, peer->host, ipaddr_len); - return -1; - } - - /* Process the route. */ - if (attr) - ret = bgp_update (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, NULL); - else - ret = bgp_withdraw (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, NULL); - return ret; +static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi, + struct attr *attr, u_char *pfx, int psize, + u_int32_t addpath_id) +{ + struct prefix_rd prd; + struct prefix_evpn p; + u_char ipaddr_len; + int ret; + + /* Type-3 route should be either 17 or 29 bytes: RD (8), Eth Tag (4), + * IP len (1) and IP (4 or 16). + */ + if (psize != 17 && psize != 29) { + zlog_err("%u:%s - Rx EVPN Type-3 NLRI with invalid length %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memcpy(&prd.val, pfx, 8); + pfx += 8; + + /* Make EVPN prefix. */ + memset(&p, 0, sizeof(struct prefix_evpn)); + p.family = AF_ETHERNET; + p.prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN; + p.prefix.route_type = BGP_EVPN_IMET_ROUTE; + + /* Skip over Ethernet Tag for now. */ + pfx += 4; + + /* Get the IP. */ + ipaddr_len = *pfx++; + if (ipaddr_len == IPV4_MAX_BITLEN) { + p.prefix.ip.ipa_type = IPADDR_V4; + memcpy(&p.prefix.ip.ip.addr, pfx, IPV4_MAX_BYTELEN); + } else { + zlog_err( + "%u:%s - Rx EVPN Type-3 NLRI with unsupported IP address length %d", + peer->bgp->vrf_id, peer->host, ipaddr_len); + return -1; + } + + /* Process the route. */ + if (attr) + ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, + afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + &prd, NULL, 0, NULL); + else + ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, + afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + &prd, NULL, NULL); + return ret; } /* * Process received EVPN type-5 route (advertise or withdraw). */ -static int -process_type5_route (struct peer *peer, afi_t afi, safi_t safi, - struct attr *attr, u_char *pfx, int psize, - u_int32_t addpath_id, int withdraw) -{ - struct prefix_rd prd; - struct prefix_evpn p; - struct bgp_route_evpn evpn; - u_char ippfx_len; - u_int32_t eth_tag; - mpls_label_t *label_pnt; - int ret; - - /* Type-5 route should be 34 or 58 bytes: - * RD (8), ESI (10), Eth Tag (4), IP len (1), IP (4 or 16), - * GW (4 or 16) and VNI (3). - * Note that the IP and GW should both be IPv4 or both IPv6. - */ - if (psize != 34 && psize != 58) - { - zlog_err ("%u:%s - Rx EVPN Type-5 NLRI with invalid length %d", - peer->bgp->vrf_id, peer->host, psize); - return -1; - } - - /* Make prefix_rd */ - prd.family = AF_UNSPEC; - prd.prefixlen = 64; - memcpy (&prd.val, pfx, 8); - pfx += 8; - - /* Make EVPN prefix. */ - memset (&p, 0, sizeof (struct prefix_evpn)); - p.family = AF_ETHERNET; - p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE; - - /* Additional information outside of prefix - ESI and GW IP */ - memset(&evpn, 0, sizeof(evpn)); - - /* Fetch ESI */ - memcpy (&evpn.eth_s_id.val, pfx, 10); - pfx += 10; - - /* Fetch Ethernet Tag. */ - memcpy (ð_tag, pfx, 4); - p.prefix.eth_tag = ntohl (eth_tag); - pfx += 4; - - /* Fetch IP prefix length. */ - ippfx_len = *pfx++; - if (ippfx_len > IPV6_MAX_BITLEN) - { - zlog_err ("%u:%s - Rx EVPN Type-5 NLRI with invalid IP Prefix length %d", - peer->bgp->vrf_id, peer->host, ippfx_len); - return -1; - } - p.prefix.ip_prefix_length = ippfx_len; - - /* Determine IPv4 or IPv6 prefix */ - /* Since the address and GW are from the same family, this just becomes - * a simple check on the total size. - */ - if (psize == 34) - { - SET_IPADDR_V4 (&p.prefix.ip); - memcpy (&p.prefix.ip.ipaddr_v4, pfx, 4); - pfx += 4; - memcpy (&evpn.gw_ip.ipv4, pfx, 4); - pfx += 4; - p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV4; - } - else - { - SET_IPADDR_V6 (&p.prefix.ip); - memcpy (&p.prefix.ip.ipaddr_v6, pfx, 16); - pfx += 16; - memcpy (&evpn.gw_ip.ipv6, pfx, 16); - pfx += 16; - p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6; - } - - label_pnt = (mpls_label_t *) pfx; - - /* Process the route. */ - if (!withdraw) - ret = bgp_update (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, label_pnt, 0, &evpn); - else - ret = bgp_withdraw (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, label_pnt, &evpn); - - return ret; -} - -static void -evpn_mpattr_encode_type5 (struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t * label, - struct attr *attr) -{ - int len; - char temp[16]; - struct evpn_addr *p_evpn_p; - - memset(&temp, 0, 16); - if (p->family != AF_ETHERNET) - return; - p_evpn_p = &(p->u.prefix_evpn); - - if (IS_IPADDR_V4(&p_evpn_p->ip)) - len = 8; /* ipv4 */ - else - len = 32; /* ipv6 */ - stream_putc(s, BGP_EVPN_IP_PREFIX_ROUTE); - /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */ - stream_putc(s, 8 + 10 + 4 + 1 + len + 3); - stream_put(s, prd->val, 8); - if (attr && attr) - stream_put(s, &(attr->evpn_overlay.eth_s_id), 10); - else - stream_put(s, &temp, 10); - stream_putl(s, p_evpn_p->eth_tag); - stream_putc(s, p_evpn_p->ip_prefix_length); - if (IS_IPADDR_V4(&p_evpn_p->ip)) - stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr); - else - stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16); - if (attr && attr) - { - if (IS_IPADDR_V4(&p_evpn_p->ip)) - stream_put_ipv4(s, attr->evpn_overlay.gw_ip.ipv4. s_addr); - else - stream_put(s, &(attr->evpn_overlay.gw_ip.ipv6), 16); - } - else - { - if (IS_IPADDR_V4(&p_evpn_p->ip)) - stream_put_ipv4(s, 0); - else - stream_put(s, &temp, 16); - } - - if (label) - stream_put(s, label, 3); - else - stream_put3(s, 0); +static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, + struct attr *attr, u_char *pfx, int psize, + u_int32_t addpath_id, int withdraw) +{ + struct prefix_rd prd; + struct prefix_evpn p; + struct bgp_route_evpn evpn; + u_char ippfx_len; + u_int32_t eth_tag; + mpls_label_t *label_pnt; + int ret; + + /* Type-5 route should be 34 or 58 bytes: + * RD (8), ESI (10), Eth Tag (4), IP len (1), IP (4 or 16), + * GW (4 or 16) and VNI (3). + * Note that the IP and GW should both be IPv4 or both IPv6. + */ + if (psize != 34 && psize != 58) { + zlog_err("%u:%s - Rx EVPN Type-5 NLRI with invalid length %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memcpy(&prd.val, pfx, 8); + pfx += 8; + + /* Make EVPN prefix. */ + memset(&p, 0, sizeof(struct prefix_evpn)); + p.family = AF_ETHERNET; + p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE; + + /* Additional information outside of prefix - ESI and GW IP */ + memset(&evpn, 0, sizeof(evpn)); + + /* Fetch ESI */ + memcpy(&evpn.eth_s_id.val, pfx, 10); + pfx += 10; + + /* Fetch Ethernet Tag. */ + memcpy(ð_tag, pfx, 4); + p.prefix.eth_tag = ntohl(eth_tag); + pfx += 4; + + /* Fetch IP prefix length. */ + ippfx_len = *pfx++; + if (ippfx_len > IPV6_MAX_BITLEN) { + zlog_err( + "%u:%s - Rx EVPN Type-5 NLRI with invalid IP Prefix length %d", + peer->bgp->vrf_id, peer->host, ippfx_len); + return -1; + } + p.prefix.ip_prefix_length = ippfx_len; + + /* Determine IPv4 or IPv6 prefix */ + /* Since the address and GW are from the same family, this just becomes + * a simple check on the total size. + */ + if (psize == 34) { + SET_IPADDR_V4(&p.prefix.ip); + memcpy(&p.prefix.ip.ipaddr_v4, pfx, 4); + pfx += 4; + memcpy(&evpn.gw_ip.ipv4, pfx, 4); + pfx += 4; + p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV4; + } else { + SET_IPADDR_V6(&p.prefix.ip); + memcpy(&p.prefix.ip.ipaddr_v6, pfx, 16); + pfx += 16; + memcpy(&evpn.gw_ip.ipv6, pfx, 16); + pfx += 16; + p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6; + } + + label_pnt = (mpls_label_t *)pfx; + + /* Process the route. */ + if (!withdraw) + ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, + afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + &prd, label_pnt, 0, &evpn); + else + ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, + afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + &prd, label_pnt, &evpn); + + return ret; +} + +static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, + struct prefix_rd *prd, mpls_label_t *label, + struct attr *attr) +{ + int len; + char temp[16]; + struct evpn_addr *p_evpn_p; + + memset(&temp, 0, 16); + if (p->family != AF_ETHERNET) + return; + p_evpn_p = &(p->u.prefix_evpn); + + if (IS_IPADDR_V4(&p_evpn_p->ip)) + len = 8; /* ipv4 */ + else + len = 32; /* ipv6 */ + stream_putc(s, BGP_EVPN_IP_PREFIX_ROUTE); + /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */ + stream_putc(s, 8 + 10 + 4 + 1 + len + 3); + stream_put(s, prd->val, 8); + if (attr && attr) + stream_put(s, &(attr->evpn_overlay.eth_s_id), 10); + else + stream_put(s, &temp, 10); + stream_putl(s, p_evpn_p->eth_tag); + stream_putc(s, p_evpn_p->ip_prefix_length); + if (IS_IPADDR_V4(&p_evpn_p->ip)) + stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr); + else + stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16); + if (attr && attr) { + if (IS_IPADDR_V4(&p_evpn_p->ip)) + stream_put_ipv4(s, + attr->evpn_overlay.gw_ip.ipv4.s_addr); + else + stream_put(s, &(attr->evpn_overlay.gw_ip.ipv6), 16); + } else { + if (IS_IPADDR_V4(&p_evpn_p->ip)) + stream_put_ipv4(s, 0); + else + stream_put(s, &temp, 16); + } + + if (label) + stream_put(s, label, 3); + else + stream_put3(s, 0); } /* * Cleanup specific VNI upon EVPN (advertise-all-vni) being disabled. */ -static void -cleanup_vni_on_disable (struct hash_backet *backet, struct bgp *bgp) +static void cleanup_vni_on_disable(struct hash_backet *backet, struct bgp *bgp) { - struct bgpevpn *vpn = (struct bgpevpn *) backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)backet->data; - /* Remove EVPN routes and schedule for processing. */ - delete_routes_for_vni (bgp, vpn); + /* Remove EVPN routes and schedule for processing. */ + delete_routes_for_vni(bgp, vpn); - /* Clear "live" flag and see if hash needs to be freed. */ - UNSET_FLAG (vpn->flags, VNI_FLAG_LIVE); - if (!is_vni_configured (vpn)) - bgp_evpn_free (bgp, vpn); + /* Clear "live" flag and see if hash needs to be freed. */ + UNSET_FLAG(vpn->flags, VNI_FLAG_LIVE); + if (!is_vni_configured(vpn)) + bgp_evpn_free(bgp, vpn); } /* * Free a VNI entry; iterator function called during cleanup. */ -static void -free_vni_entry (struct hash_backet *backet, struct bgp *bgp) +static void free_vni_entry(struct hash_backet *backet, struct bgp *bgp) { - struct bgpevpn *vpn; + struct bgpevpn *vpn; - vpn = (struct bgpevpn *) backet->data; - delete_all_vni_routes (bgp, vpn); - bgp_evpn_free(bgp, vpn); + vpn = (struct bgpevpn *)backet->data; + delete_all_vni_routes(bgp, vpn); + bgp_evpn_free(bgp, vpn); } @@ -2159,26 +2102,26 @@ free_vni_entry (struct hash_backet *backet, struct bgp *bgp) * local routes for all VNIs being deleted and withdrawn and the next * will result in the routes being re-advertised. */ -void -bgp_evpn_handle_router_id_update (struct bgp *bgp, int withdraw) +void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) { - if (withdraw) - hash_iterate (bgp->vnihash, - (void (*) (struct hash_backet *, void *)) - withdraw_router_id_vni, bgp); - else - hash_iterate (bgp->vnihash, - (void (*) (struct hash_backet *, void *)) - update_router_id_vni, bgp); + if (withdraw) + hash_iterate(bgp->vnihash, + (void (*)(struct hash_backet *, + void *))withdraw_router_id_vni, + bgp); + else + hash_iterate(bgp->vnihash, + (void (*)(struct hash_backet *, + void *))update_router_id_vni, + bgp); } /* * Handle change to export RT - update and advertise local routes. */ -int -bgp_evpn_handle_export_rt_change (struct bgp *bgp, struct bgpevpn *vpn) +int bgp_evpn_handle_export_rt_change(struct bgp *bgp, struct bgpevpn *vpn) { - return update_routes_for_vni (bgp, vpn); + return update_routes_for_vni(bgp, vpn); } /* @@ -2188,254 +2131,242 @@ bgp_evpn_handle_export_rt_change (struct bgp *bgp, struct bgpevpn *vpn) * of this VNI being deleted and withdrawn and the next will result * in the routes being re-advertised. */ -void -bgp_evpn_handle_rd_change (struct bgp *bgp, struct bgpevpn *vpn, - int withdraw) +void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn, + int withdraw) { - if (withdraw) - delete_withdraw_vni_routes (bgp, vpn); - else - update_advertise_vni_routes (bgp, vpn); + if (withdraw) + delete_withdraw_vni_routes(bgp, vpn); + else + update_advertise_vni_routes(bgp, vpn); } /* * Install routes for this VNI. Invoked upon change to Import RT. */ -int -bgp_evpn_install_routes (struct bgp *bgp, struct bgpevpn *vpn) +int bgp_evpn_install_routes(struct bgp *bgp, struct bgpevpn *vpn) { - return install_routes_for_vni (bgp, vpn); + return install_routes_for_vni(bgp, vpn); } /* * Uninstall all routes installed for this VNI. Invoked upon change * to Import RT. */ -int -bgp_evpn_uninstall_routes (struct bgp *bgp, struct bgpevpn *vpn) +int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn) { - return uninstall_routes_for_vni (bgp, vpn); + return uninstall_routes_for_vni(bgp, vpn); } /* * Function to display "tag" in route as a VNI. */ -char * -bgp_evpn_label2str (mpls_label_t *label, char *buf, int len) +char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len) { - vni_t vni; + vni_t vni; - vni = label2vni (label); - snprintf (buf, len, "%u", vni); - return buf; + vni = label2vni(label); + snprintf(buf, len, "%u", vni); + return buf; } /* * Function to convert evpn route to string. * NOTE: We don't use prefix2str as the output here is a bit different. */ -char * -bgp_evpn_route2str (struct prefix_evpn *p, char *buf, int len) -{ - char buf1[ETHER_ADDR_STRLEN]; - char buf2[PREFIX2STR_BUFFER]; - - if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) - { - snprintf (buf, len, "[%d]:[0]:[%d]:[%s]", - p->prefix.route_type, IS_EVPN_PREFIX_IPADDR_V4(p) ? \ - IPV4_MAX_BITLEN : IPV6_MAX_BITLEN, - inet_ntoa(p->prefix.ip.ipaddr_v4)); - } - else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - { - if (IS_EVPN_PREFIX_IPADDR_NONE(p)) - snprintf (buf, len, "[%d]:[0]:[0]:[%d]:[%s]", - p->prefix.route_type, 8*ETHER_ADDR_LEN, - prefix_mac2str (&p->prefix.mac, buf1, sizeof(buf1))); - else - { - u_char family; - - family = IS_EVPN_PREFIX_IPADDR_V4(p) ? \ - AF_INET : AF_INET6; - snprintf (buf, len, "[%d]:[0]:[0]:[%d]:[%s]:[%d]:[%s]", - p->prefix.route_type, 8*ETHER_ADDR_LEN, - prefix_mac2str (&p->prefix.mac, buf1, sizeof(buf1)), - family == AF_INET ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN, - inet_ntop (family, &p->prefix.ip.ip.addr, - buf2, PREFIX2STR_BUFFER)); - } - } - else - { - /* Currently, this is to cater to other AF_ETHERNET code. */ - } - - return(buf); +char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) +{ + char buf1[ETHER_ADDR_STRLEN]; + char buf2[PREFIX2STR_BUFFER]; + + if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) { + snprintf(buf, len, "[%d]:[0]:[%d]:[%s]", p->prefix.route_type, + IS_EVPN_PREFIX_IPADDR_V4(p) ? IPV4_MAX_BITLEN + : IPV6_MAX_BITLEN, + inet_ntoa(p->prefix.ip.ipaddr_v4)); + } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + if (IS_EVPN_PREFIX_IPADDR_NONE(p)) + snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]", + p->prefix.route_type, 8 * ETHER_ADDR_LEN, + prefix_mac2str(&p->prefix.mac, buf1, + sizeof(buf1))); + else { + u_char family; + + family = IS_EVPN_PREFIX_IPADDR_V4(p) ? AF_INET + : AF_INET6; + snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]:[%d]:[%s]", + p->prefix.route_type, 8 * ETHER_ADDR_LEN, + prefix_mac2str(&p->prefix.mac, buf1, + sizeof(buf1)), + family == AF_INET ? IPV4_MAX_BITLEN + : IPV6_MAX_BITLEN, + inet_ntop(family, &p->prefix.ip.ip.addr, buf2, + PREFIX2STR_BUFFER)); + } + } else { + /* Currently, this is to cater to other AF_ETHERNET code. */ + } + + return (buf); } /* * Encode EVPN prefix in Update (MP_REACH) */ -void -bgp_evpn_encode_prefix (struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t *label, - struct attr *attr, int addpath_encode, - u_int32_t addpath_tx_id) -{ - struct prefix_evpn *evp = (struct prefix_evpn *)p; - int ipa_len = 0; - - if (addpath_encode) - stream_putl (s, addpath_tx_id); - - /* Route type */ - stream_putc (s, evp->prefix.route_type); - - switch (evp->prefix.route_type) - { - case BGP_EVPN_MAC_IP_ROUTE: - if (IS_EVPN_PREFIX_IPADDR_V4(evp)) - ipa_len = IPV4_MAX_BYTELEN; - else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) - ipa_len = IPV6_MAX_BYTELEN; - stream_putc (s, 33 + ipa_len); // 1 VNI - stream_put (s, prd->val, 8); /* RD */ - stream_put (s, 0, 10); /* ESI */ - stream_putl (s, 0); /* Ethernet Tag ID */ - stream_putc (s, 8*ETHER_ADDR_LEN); /* Mac Addr Len - bits */ - stream_put (s, evp->prefix.mac.octet, 6); /* Mac Addr */ - stream_putc (s, 8*ipa_len); /* IP address Length */ - if (ipa_len) - stream_put (s, &evp->prefix.ip.ip.addr, ipa_len); /* IP */ - stream_put (s, label, BGP_LABEL_BYTES); /* VNI is contained in 'tag' */ - break; - - case BGP_EVPN_IMET_ROUTE: - stream_putc (s, 17); // TODO: length - assumes IPv4 address - stream_put (s, prd->val, 8); /* RD */ - stream_putl (s, 0); /* Ethernet Tag ID */ - stream_putc (s, IPV4_MAX_BITLEN); /* IP address Length - bits */ - /* Originating Router's IP Addr */ - stream_put_in_addr (s, &evp->prefix.ip.ipaddr_v4); - break; - - case BGP_EVPN_IP_PREFIX_ROUTE: - /* TODO: AddPath support. */ - evpn_mpattr_encode_type5 (s, p, prd, label, attr); - break; - - default: - break; - } -} - -int -bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int withdraw) -{ - u_char *pnt; - u_char *lim; - afi_t afi; - safi_t safi; - u_int32_t addpath_id; - int addpath_encoded; - int psize = 0; - u_char rtype; - u_char rlen; - struct prefix p; - - /* Check peer status. */ - if (peer->status != Established) - { - zlog_err ("%u:%s - EVPN update received in state %d", - peer->bgp->vrf_id, peer->host, peer->status); - return -1; - } - - /* Start processing the NLRI - there may be multiple in the MP_REACH */ - pnt = packet->nlri; - lim = pnt + packet->length; - afi = packet->afi; - safi = packet->safi; - addpath_id = 0; - - addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) && - CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV)); - - for (; pnt < lim; pnt += psize) - { - /* Clear prefix structure. */ - memset (&p, 0, sizeof (struct prefix)); - - /* Deal with path-id if AddPath is supported. */ - if (addpath_encoded) - { - /* When packet overflow occurs return immediately. */ - if (pnt + BGP_ADDPATH_ID_LEN > lim) - return -1; - - addpath_id = ntohl(*((uint32_t*) pnt)); - pnt += BGP_ADDPATH_ID_LEN; - } - - /* All EVPN NLRI types start with type and length. */ - if (pnt + 2 > lim) - return -1; - - rtype = *pnt++; - psize = rlen = *pnt++; - - /* When packet overflow occur return immediately. */ - if (pnt + psize > lim) - return -1; - - switch (rtype) - { - case BGP_EVPN_MAC_IP_ROUTE: - if (process_type2_route (peer, afi, safi, - withdraw ? NULL : attr, - pnt, psize, addpath_id)) - { - zlog_err ("%u:%s - Error in processing EVPN type-2 NLRI size %d", - peer->bgp->vrf_id, peer->host, psize); - return -1; - } - break; - - case BGP_EVPN_IMET_ROUTE: - if (process_type3_route (peer, afi, safi, - withdraw ? NULL : attr, - pnt, psize, addpath_id)) - { - zlog_err ("%u:%s - Error in processing EVPN type-3 NLRI size %d", - peer->bgp->vrf_id, peer->host, psize); - return -1; - } - break; - - case BGP_EVPN_IP_PREFIX_ROUTE: - if (process_type5_route (peer, afi, safi, attr, - pnt, psize, addpath_id, withdraw)) - { - zlog_err ("%u:%s - Error in processing EVPN type-5 NLRI size %d", - peer->bgp->vrf_id, peer->host, psize); - return -1; - } - break; - - default: - break; - } - - } - - /* Packet length consistency check. */ - if (pnt != lim) - return -1; - - return 0; +void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, + struct prefix_rd *prd, mpls_label_t *label, + struct attr *attr, int addpath_encode, + u_int32_t addpath_tx_id) +{ + struct prefix_evpn *evp = (struct prefix_evpn *)p; + int ipa_len = 0; + + if (addpath_encode) + stream_putl(s, addpath_tx_id); + + /* Route type */ + stream_putc(s, evp->prefix.route_type); + + switch (evp->prefix.route_type) { + case BGP_EVPN_MAC_IP_ROUTE: + if (IS_EVPN_PREFIX_IPADDR_V4(evp)) + ipa_len = IPV4_MAX_BYTELEN; + else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) + ipa_len = IPV6_MAX_BYTELEN; + stream_putc(s, 33 + ipa_len); // 1 VNI + stream_put(s, prd->val, 8); /* RD */ + stream_put(s, 0, 10); /* ESI */ + stream_putl(s, 0); /* Ethernet Tag ID */ + stream_putc(s, 8 * ETHER_ADDR_LEN); /* Mac Addr Len - bits */ + stream_put(s, evp->prefix.mac.octet, 6); /* Mac Addr */ + stream_putc(s, 8 * ipa_len); /* IP address Length */ + if (ipa_len) + stream_put(s, &evp->prefix.ip.ip.addr, + ipa_len); /* IP */ + stream_put(s, label, + BGP_LABEL_BYTES); /* VNI is contained in 'tag' */ + break; + + case BGP_EVPN_IMET_ROUTE: + stream_putc(s, 17); // TODO: length - assumes IPv4 address + stream_put(s, prd->val, 8); /* RD */ + stream_putl(s, 0); /* Ethernet Tag ID */ + stream_putc(s, IPV4_MAX_BITLEN); /* IP address Length - bits */ + /* Originating Router's IP Addr */ + stream_put_in_addr(s, &evp->prefix.ip.ipaddr_v4); + break; + + case BGP_EVPN_IP_PREFIX_ROUTE: + /* TODO: AddPath support. */ + evpn_mpattr_encode_type5(s, p, prd, label, attr); + break; + + default: + break; + } +} + +int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw) +{ + u_char *pnt; + u_char *lim; + afi_t afi; + safi_t safi; + u_int32_t addpath_id; + int addpath_encoded; + int psize = 0; + u_char rtype; + u_char rlen; + struct prefix p; + + /* Check peer status. */ + if (peer->status != Established) { + zlog_err("%u:%s - EVPN update received in state %d", + peer->bgp->vrf_id, peer->host, peer->status); + return -1; + } + + /* Start processing the NLRI - there may be multiple in the MP_REACH */ + pnt = packet->nlri; + lim = pnt + packet->length; + afi = packet->afi; + safi = packet->safi; + addpath_id = 0; + + addpath_encoded = + (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) + && CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV)); + + for (; pnt < lim; pnt += psize) { + /* Clear prefix structure. */ + memset(&p, 0, sizeof(struct prefix)); + + /* Deal with path-id if AddPath is supported. */ + if (addpath_encoded) { + /* When packet overflow occurs return immediately. */ + if (pnt + BGP_ADDPATH_ID_LEN > lim) + return -1; + + addpath_id = ntohl(*((uint32_t *)pnt)); + pnt += BGP_ADDPATH_ID_LEN; + } + + /* All EVPN NLRI types start with type and length. */ + if (pnt + 2 > lim) + return -1; + + rtype = *pnt++; + psize = rlen = *pnt++; + + /* When packet overflow occur return immediately. */ + if (pnt + psize > lim) + return -1; + + switch (rtype) { + case BGP_EVPN_MAC_IP_ROUTE: + if (process_type2_route(peer, afi, safi, + withdraw ? NULL : attr, pnt, + psize, addpath_id)) { + zlog_err( + "%u:%s - Error in processing EVPN type-2 NLRI size %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + break; + + case BGP_EVPN_IMET_ROUTE: + if (process_type3_route(peer, afi, safi, + withdraw ? NULL : attr, pnt, + psize, addpath_id)) { + zlog_err( + "%u:%s - Error in processing EVPN type-3 NLRI size %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + break; + + case BGP_EVPN_IP_PREFIX_ROUTE: + if (process_type5_route(peer, afi, safi, attr, pnt, + psize, addpath_id, withdraw)) { + zlog_err( + "%u:%s - Error in processing EVPN type-5 NLRI size %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + break; + + default: + break; + } + } + + /* Packet length consistency check. */ + if (pnt != lim) + return -1; + + return 0; } @@ -2443,150 +2374,145 @@ bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, * Map the RTs (configured or automatically derived) of a VNI to the VNI. * The mapping will be used during route processing. */ -void -bgp_evpn_map_vni_to_its_rts (struct bgp *bgp, struct bgpevpn *vpn) +void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn) { - int i; - struct ecommunity_val *eval; - struct listnode *node, *nnode; - struct ecommunity *ecom; + int i; + struct ecommunity_val *eval; + struct listnode *node, *nnode; + struct ecommunity *ecom; - for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) - { - for (i = 0; i < ecom->size; i++) - { - eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); - map_vni_to_rt (bgp, vpn, eval); - } - } + for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) { + for (i = 0; i < ecom->size; i++) { + eval = (struct ecommunity_val *)(ecom->val + + (i + * ECOMMUNITY_SIZE)); + map_vni_to_rt(bgp, vpn, eval); + } + } } /* * Unmap the RTs (configured or automatically derived) of a VNI from the VNI. */ -void -bgp_evpn_unmap_vni_from_its_rts (struct bgp *bgp, struct bgpevpn *vpn) +void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp, struct bgpevpn *vpn) { - int i; - struct ecommunity_val *eval; - struct listnode *node, *nnode; - struct ecommunity *ecom; + int i; + struct ecommunity_val *eval; + struct listnode *node, *nnode; + struct ecommunity *ecom; - for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) - { - for (i = 0; i < ecom->size; i++) - { - struct irt_node *irt; - struct ecommunity_val eval_tmp; + for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) { + for (i = 0; i < ecom->size; i++) { + struct irt_node *irt; + struct ecommunity_val eval_tmp; - eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); - /* If using "automatic" RT, we only care about the local-admin sub-field. - * This is to facilitate using VNI as the RT for EBGP peering too. - */ - memcpy (&eval_tmp, eval, ECOMMUNITY_SIZE); - if (!is_import_rt_configured (vpn)) - mask_ecom_global_admin (&eval_tmp, eval); + eval = (struct ecommunity_val *)(ecom->val + + (i + * ECOMMUNITY_SIZE)); + /* If using "automatic" RT, we only care about the + * local-admin sub-field. + * This is to facilitate using VNI as the RT for EBGP + * peering too. + */ + memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE); + if (!is_import_rt_configured(vpn)) + mask_ecom_global_admin(&eval_tmp, eval); - irt = lookup_import_rt (bgp, &eval_tmp); - if (irt) - unmap_vni_from_rt (bgp, vpn, irt); - } - } + irt = lookup_import_rt(bgp, &eval_tmp); + if (irt) + unmap_vni_from_rt(bgp, vpn, irt); + } + } } /* * Derive Import RT automatically for VNI and map VNI to RT. * The mapping will be used during route processing. */ -void -bgp_evpn_derive_auto_rt_import (struct bgp *bgp, struct bgpevpn *vpn) +void bgp_evpn_derive_auto_rt_import(struct bgp *bgp, struct bgpevpn *vpn) { - form_auto_rt (bgp, vpn, vpn->import_rtl); - UNSET_FLAG (vpn->flags, VNI_FLAG_IMPRT_CFGD); + form_auto_rt(bgp, vpn, vpn->import_rtl); + UNSET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD); - /* Map RT to VNI */ - bgp_evpn_map_vni_to_its_rts (bgp, vpn); + /* Map RT to VNI */ + bgp_evpn_map_vni_to_its_rts(bgp, vpn); } /* * Derive Export RT automatically for VNI. */ -void -bgp_evpn_derive_auto_rt_export (struct bgp *bgp, struct bgpevpn *vpn) +void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn) { - form_auto_rt (bgp, vpn, vpn->export_rtl); - UNSET_FLAG (vpn->flags, VNI_FLAG_EXPRT_CFGD); + form_auto_rt(bgp, vpn, vpn->export_rtl); + UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD); } /* * Derive RD automatically for VNI using passed information - it * is of the form RouterId:unique-id-for-vni. */ -void -bgp_evpn_derive_auto_rd (struct bgp *bgp, struct bgpevpn *vpn) +void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn) { - char buf[100]; + char buf[100]; - vpn->prd.family = AF_UNSPEC; - vpn->prd.prefixlen = 64; - sprintf (buf, "%s:%hu", inet_ntoa (bgp->router_id), vpn->rd_id); - str2prefix_rd (buf, &vpn->prd); - UNSET_FLAG (vpn->flags, VNI_FLAG_RD_CFGD); + vpn->prd.family = AF_UNSPEC; + vpn->prd.prefixlen = 64; + sprintf(buf, "%s:%hu", inet_ntoa(bgp->router_id), vpn->rd_id); + str2prefix_rd(buf, &vpn->prd); + UNSET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD); } /* * Lookup VNI. */ -struct bgpevpn * -bgp_evpn_lookup_vni (struct bgp *bgp, vni_t vni) +struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni) { - struct bgpevpn *vpn; - struct bgpevpn tmp; + struct bgpevpn *vpn; + struct bgpevpn tmp; - memset(&tmp, 0, sizeof(struct bgpevpn)); - tmp.vni = vni; - vpn = hash_lookup (bgp->vnihash, &tmp); - return vpn; + memset(&tmp, 0, sizeof(struct bgpevpn)); + tmp.vni = vni; + vpn = hash_lookup(bgp->vnihash, &tmp); + return vpn; } /* * Create a new vpn - invoked upon configuration or zebra notification. */ -struct bgpevpn * -bgp_evpn_new (struct bgp *bgp, vni_t vni, struct in_addr originator_ip) +struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni, + struct in_addr originator_ip) { - struct bgpevpn *vpn; + struct bgpevpn *vpn; - if (!bgp) - return NULL; + if (!bgp) + return NULL; - vpn = XCALLOC (MTYPE_BGP_EVPN, sizeof (struct bgpevpn)); - if (!vpn) - return NULL; + vpn = XCALLOC(MTYPE_BGP_EVPN, sizeof(struct bgpevpn)); + if (!vpn) + return NULL; - /* Set values - RD and RT set to defaults. */ - vpn->vni = vni; - vpn->originator_ip = originator_ip; + /* Set values - RD and RT set to defaults. */ + vpn->vni = vni; + vpn->originator_ip = originator_ip; - /* Initialize route-target import and export lists */ - vpn->import_rtl = list_new (); - vpn->import_rtl->cmp = (int (*)(void *, void *)) evpn_route_target_cmp; - vpn->export_rtl = list_new (); - vpn->export_rtl->cmp = (int (*)(void *, void *)) evpn_route_target_cmp; - bf_assign_index(bgp->rd_idspace, vpn->rd_id); - derive_rd_rt_for_vni (bgp, vpn); + /* Initialize route-target import and export lists */ + vpn->import_rtl = list_new(); + vpn->import_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp; + vpn->export_rtl = list_new(); + vpn->export_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp; + bf_assign_index(bgp->rd_idspace, vpn->rd_id); + derive_rd_rt_for_vni(bgp, vpn); - /* Initialize EVPN route table. */ - vpn->route_table = bgp_table_init (AFI_L2VPN, SAFI_EVPN); + /* Initialize EVPN route table. */ + vpn->route_table = bgp_table_init(AFI_L2VPN, SAFI_EVPN); - /* Add to hash */ - if (!hash_get(bgp->vnihash, vpn, hash_alloc_intern)) - { - XFREE(MTYPE_BGP_EVPN, vpn); - return NULL; - } - QOBJ_REG (vpn, bgpevpn); - return vpn; + /* Add to hash */ + if (!hash_get(bgp->vnihash, vpn, hash_alloc_intern)) { + XFREE(MTYPE_BGP_EVPN, vpn); + return NULL; + } + QOBJ_REG(vpn, bgpevpn); + return vpn; } /* @@ -2595,243 +2521,225 @@ bgp_evpn_new (struct bgp *bgp, vni_t vni, struct in_addr originator_ip) * This just frees appropriate memory, caller should have taken other * needed actions. */ -void -bgp_evpn_free (struct bgp *bgp, struct bgpevpn *vpn) +void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) { - bgp_table_unlock (vpn->route_table); - bgp_evpn_unmap_vni_from_its_rts (bgp, vpn); - list_delete (vpn->import_rtl); - list_delete (vpn->export_rtl); - vpn->import_rtl = NULL; - vpn->export_rtl = NULL; - bf_release_index(bgp->rd_idspace, vpn->rd_id); - hash_release (bgp->vnihash, vpn); - QOBJ_UNREG (vpn); - XFREE(MTYPE_BGP_EVPN, vpn); + bgp_table_unlock(vpn->route_table); + bgp_evpn_unmap_vni_from_its_rts(bgp, vpn); + list_delete(vpn->import_rtl); + list_delete(vpn->export_rtl); + vpn->import_rtl = NULL; + vpn->export_rtl = NULL; + bf_release_index(bgp->rd_idspace, vpn->rd_id); + hash_release(bgp->vnihash, vpn); + QOBJ_UNREG(vpn); + XFREE(MTYPE_BGP_EVPN, vpn); } /* * Import route into matching VNI(s). */ -int -bgp_evpn_import_route (struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix *p, struct bgp_info *ri) +int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi, + struct prefix *p, struct bgp_info *ri) { - return install_uninstall_evpn_route (bgp, afi, safi, p, ri, 1); + return install_uninstall_evpn_route(bgp, afi, safi, p, ri, 1); } /* * Unimport route from matching VNI(s). */ -int -bgp_evpn_unimport_route (struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix *p, struct bgp_info *ri) +int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi, + struct prefix *p, struct bgp_info *ri) { - return install_uninstall_evpn_route (bgp, afi, safi, p, ri, 0); + return install_uninstall_evpn_route(bgp, afi, safi, p, ri, 0); } /* * Handle del of a local MACIP. */ -int -bgp_evpn_local_macip_del (struct bgp *bgp, vni_t vni, - struct ethaddr *mac, struct ipaddr *ip) +int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac, + struct ipaddr *ip) { - struct bgpevpn *vpn; - struct prefix_evpn p; + struct bgpevpn *vpn; + struct prefix_evpn p; - if (!bgp->vnihash) - { - zlog_err ("%u: VNI hash not created", bgp->vrf_id); - return -1; - } + if (!bgp->vnihash) { + zlog_err("%u: VNI hash not created", bgp->vrf_id); + return -1; + } - /* Lookup VNI hash - should exist. */ - vpn = bgp_evpn_lookup_vni (bgp, vni); - if (!vpn || !is_vni_live (vpn)) - { - zlog_warn ("%u: VNI hash entry for VNI %u %s at MACIP DEL", - bgp->vrf_id, vni, vpn ? "not live" : "not found"); - return -1; - } + /* Lookup VNI hash - should exist. */ + vpn = bgp_evpn_lookup_vni(bgp, vni); + if (!vpn || !is_vni_live(vpn)) { + zlog_warn("%u: VNI hash entry for VNI %u %s at MACIP DEL", + bgp->vrf_id, vni, vpn ? "not live" : "not found"); + return -1; + } - /* Remove EVPN type-2 route and schedule for processing. */ - build_evpn_type2_prefix (&p, mac, ip); - delete_evpn_route (bgp, vpn, &p); + /* Remove EVPN type-2 route and schedule for processing. */ + build_evpn_type2_prefix(&p, mac, ip); + delete_evpn_route(bgp, vpn, &p); - return 0; + return 0; } /* * Handle add of a local MACIP. */ -int -bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni, - struct ethaddr *mac, struct ipaddr *ip, - u_char sticky) +int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, + struct ipaddr *ip, u_char sticky) { - struct bgpevpn *vpn; - struct prefix_evpn p; + struct bgpevpn *vpn; + struct prefix_evpn p; - if (!bgp->vnihash) - { - zlog_err ("%u: VNI hash not created", bgp->vrf_id); - return -1; - } + if (!bgp->vnihash) { + zlog_err("%u: VNI hash not created", bgp->vrf_id); + return -1; + } - /* Lookup VNI hash - should exist. */ - vpn = bgp_evpn_lookup_vni (bgp, vni); - if (!vpn || !is_vni_live (vpn)) - { - zlog_warn ("%u: VNI hash entry for VNI %u %s at MACIP ADD", - bgp->vrf_id, vni, vpn ? "not live" : "not found"); - return -1; - } + /* Lookup VNI hash - should exist. */ + vpn = bgp_evpn_lookup_vni(bgp, vni); + if (!vpn || !is_vni_live(vpn)) { + zlog_warn("%u: VNI hash entry for VNI %u %s at MACIP ADD", + bgp->vrf_id, vni, vpn ? "not live" : "not found"); + return -1; + } - /* Create EVPN type-2 route and schedule for processing. */ - build_evpn_type2_prefix (&p, mac, ip); - if (update_evpn_route (bgp, vpn, &p, sticky)) - { - char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; + /* Create EVPN type-2 route and schedule for processing. */ + build_evpn_type2_prefix(&p, mac, ip); + if (update_evpn_route(bgp, vpn, &p, sticky)) { + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; - zlog_err ("%u:Failed to create Type-2 route, VNI %u %sMAC %s IP %s", - bgp->vrf_id, vpn->vni, - sticky ? "sticky" : "", - prefix_mac2str (mac, buf, sizeof (buf)), - ipaddr2str (ip, buf2, sizeof(buf2))); - return -1; - } + zlog_err( + "%u:Failed to create Type-2 route, VNI %u %sMAC %s IP %s", + bgp->vrf_id, vpn->vni, sticky ? "sticky" : "", + prefix_mac2str(mac, buf, sizeof(buf)), + ipaddr2str(ip, buf2, sizeof(buf2))); + return -1; + } - return 0; + return 0; } /* * Handle del of a local VNI. */ -int -bgp_evpn_local_vni_del (struct bgp *bgp, vni_t vni) +int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni) { - struct bgpevpn *vpn; + struct bgpevpn *vpn; - if (!bgp->vnihash) - { - zlog_err ("%u: VNI hash not created", bgp->vrf_id); - return -1; - } + if (!bgp->vnihash) { + zlog_err("%u: VNI hash not created", bgp->vrf_id); + return -1; + } - /* Locate VNI hash */ - vpn = bgp_evpn_lookup_vni (bgp, vni); - if (!vpn) - { - zlog_warn ("%u: VNI hash entry for VNI %u not found at DEL", - bgp->vrf_id, vni); - return 0; - } + /* Locate VNI hash */ + vpn = bgp_evpn_lookup_vni(bgp, vni); + if (!vpn) { + zlog_warn("%u: VNI hash entry for VNI %u not found at DEL", + bgp->vrf_id, vni); + return 0; + } - /* Remove all local EVPN routes and schedule for processing (to - * withdraw from peers). - */ - delete_routes_for_vni (bgp, vpn); + /* Remove all local EVPN routes and schedule for processing (to + * withdraw from peers). + */ + delete_routes_for_vni(bgp, vpn); - /* Clear "live" flag and see if hash needs to be freed. */ - UNSET_FLAG (vpn->flags, VNI_FLAG_LIVE); - if (!is_vni_configured (vpn)) - bgp_evpn_free (bgp, vpn); + /* Clear "live" flag and see if hash needs to be freed. */ + UNSET_FLAG(vpn->flags, VNI_FLAG_LIVE); + if (!is_vni_configured(vpn)) + bgp_evpn_free(bgp, vpn); - return 0; + return 0; } /* * Handle add (or update) of a local VNI. The only VNI change we care * about is change to local-tunnel-ip. */ -int -bgp_evpn_local_vni_add (struct bgp *bgp, vni_t vni, struct in_addr originator_ip) -{ - struct bgpevpn *vpn; - struct prefix_evpn p; - - if (!bgp->vnihash) - { - zlog_err ("%u: VNI hash not created", bgp->vrf_id); - return -1; - } - - /* Lookup VNI. If present and no change, exit. */ - vpn = bgp_evpn_lookup_vni (bgp, vni); - if (vpn && is_vni_live (vpn)) - { - if (IPV4_ADDR_SAME (&vpn->originator_ip, &originator_ip)) - /* Probably some other param has changed that we don't care about. */ - return 0; - - /* Local tunnel endpoint IP address has changed */ - return handle_tunnel_ip_change (bgp, vpn, originator_ip); - } - - /* Create or update as appropriate. */ - if (!vpn) - { - vpn = bgp_evpn_new (bgp, vni, originator_ip); - if (!vpn) - { - zlog_err ("%u: Failed to allocate VNI entry for VNI %u - at Add", - bgp->vrf_id, vni); - return -1; - } - } - - /* Mark as "live" */ - SET_FLAG (vpn->flags, VNI_FLAG_LIVE); - - /* Create EVPN type-3 route and schedule for processing. */ - build_evpn_type3_prefix (&p, vpn->originator_ip); - if (update_evpn_route (bgp, vpn, &p, 0)) - { - zlog_err ("%u: Type3 route creation failure for VNI %u", - bgp->vrf_id, vni); - return -1; - } - - /* If we have learnt and retained remote routes (VTEPs, MACs) for this VNI, - * install them. - */ - install_routes_for_vni (bgp, vpn); - - return 0; +int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, + struct in_addr originator_ip) +{ + struct bgpevpn *vpn; + struct prefix_evpn p; + + if (!bgp->vnihash) { + zlog_err("%u: VNI hash not created", bgp->vrf_id); + return -1; + } + + /* Lookup VNI. If present and no change, exit. */ + vpn = bgp_evpn_lookup_vni(bgp, vni); + if (vpn && is_vni_live(vpn)) { + if (IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)) + /* Probably some other param has changed that we don't + * care about. */ + return 0; + + /* Local tunnel endpoint IP address has changed */ + return handle_tunnel_ip_change(bgp, vpn, originator_ip); + } + + /* Create or update as appropriate. */ + if (!vpn) { + vpn = bgp_evpn_new(bgp, vni, originator_ip); + if (!vpn) { + zlog_err( + "%u: Failed to allocate VNI entry for VNI %u - at Add", + bgp->vrf_id, vni); + return -1; + } + } + + /* Mark as "live" */ + SET_FLAG(vpn->flags, VNI_FLAG_LIVE); + + /* Create EVPN type-3 route and schedule for processing. */ + build_evpn_type3_prefix(&p, vpn->originator_ip); + if (update_evpn_route(bgp, vpn, &p, 0)) { + zlog_err("%u: Type3 route creation failure for VNI %u", + bgp->vrf_id, vni); + return -1; + } + + /* If we have learnt and retained remote routes (VTEPs, MACs) for this + * VNI, + * install them. + */ + install_routes_for_vni(bgp, vpn); + + return 0; } /* * Cleanup EVPN information on disable - Need to delete and withdraw * EVPN routes from peers. */ -void -bgp_evpn_cleanup_on_disable (struct bgp *bgp) +void bgp_evpn_cleanup_on_disable(struct bgp *bgp) { - hash_iterate (bgp->vnihash, - (void (*) (struct hash_backet *, void *)) - cleanup_vni_on_disable, bgp); + hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, + void *))cleanup_vni_on_disable, + bgp); } /* * Cleanup EVPN information - invoked at the time of bgpd exit or when the * BGP instance (default) is being freed. */ -void -bgp_evpn_cleanup (struct bgp *bgp) +void bgp_evpn_cleanup(struct bgp *bgp) { - if (bgp->vnihash) - hash_iterate (bgp->vnihash, - (void (*) (struct hash_backet *, void *)) - free_vni_entry, bgp); - if (bgp->import_rt_hash) - hash_free (bgp->import_rt_hash); - bgp->import_rt_hash = NULL; - if (bgp->vnihash) - hash_free (bgp->vnihash); - bgp->vnihash = NULL; - bf_free (bgp->rd_idspace); + if (bgp->vnihash) + hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, + void *))free_vni_entry, + bgp); + if (bgp->import_rt_hash) + hash_free(bgp->import_rt_hash); + bgp->import_rt_hash = NULL; + if (bgp->vnihash) + hash_free(bgp->vnihash); + bgp->vnihash = NULL; + bf_free(bgp->rd_idspace); } /* @@ -2841,16 +2749,14 @@ bgp_evpn_cleanup (struct bgp *bgp) * hash for RT to VNI * unique rd id space for auto derivation of RD for VNIs */ -void -bgp_evpn_init (struct bgp *bgp) -{ - bgp->vnihash = hash_create (vni_hash_key_make, - vni_hash_cmp, - "BGP VNI Hash"); - bgp->import_rt_hash = hash_create (import_rt_hash_key_make, - import_rt_hash_cmp, - "BGP Import RT Hash"); - bf_init (bgp->rd_idspace, UINT16_MAX); - /*assign 0th index in the bitfield, so that we start with id 1*/ - bf_assign_zero_index (bgp->rd_idspace); +void bgp_evpn_init(struct bgp *bgp) +{ + bgp->vnihash = + hash_create(vni_hash_key_make, vni_hash_cmp, "BGP VNI Hash"); + bgp->import_rt_hash = + hash_create(import_rt_hash_key_make, import_rt_hash_cmp, + "BGP Import RT Hash"); + bf_init(bgp->rd_idspace, UINT16_MAX); + /*assign 0th index in the bitfield, so that we start with id 1*/ + bf_assign_zero_index(bgp->rd_idspace); } |
