1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* EVPN header for multihoming procedures
4 * Copyright (C) 2019 Cumulus Networks
9 #ifndef _FRR_BGP_EVPN_MH_H
10 #define _FRR_BGP_EVPN_MH_H
15 #include "bgp_evpn_private.h"
17 #define BGP_EVPN_AD_ES_ETH_TAG 0xffffffff
18 #define BGP_EVPN_AD_EVI_ETH_TAG 0
20 #define BGP_EVPNES_INCONS_STR_SZ 80
21 #define BGP_EVPN_VTEPS_FLAG_STR_SZ (BGP_EVPN_FLAG_STR_SZ * ES_VTEP_MAX_CNT)
23 #define BGP_EVPN_CONS_CHECK_INTERVAL 60
25 #define BGP_EVPN_MH_USE_ES_L3NHG_DEF true
28 #define BGP_EVPN_MAX_EVI_PER_ES_FRAG 128
30 /* An ES can result in multiple EAD-per-ES route. Each EAD fragment is
31 * associated with an unique RD
33 struct bgp_evpn_es_frag
{
34 /* frag is associated with a parent ES */
35 struct bgp_evpn_es
*es
;
37 /* Id for deriving the RD automatically for this ES fragment */
39 /* RD for this ES fragment */
42 /* Memory used for linking bgp_evpn_es_frag to
43 * bgp_evpn_es->es_frag_list
45 struct listnode es_listnode
;
47 /* List of ES-EVIs associated with this fragment */
48 struct list
*es_evi_frag_list
;
51 /* Ethernet Segment entry -
52 * - Local and remote ESs are maintained in a global RB tree,
53 * bgp_mh_info->es_rb_tree using ESI as key
54 * - Local ESs are received from zebra (BGP_EVPNES_LOCAL)
55 * - Remotes ESs are implicitly created (by reference) by a remote ES-EVI
57 * - An ES can be simultaneously LOCAL and REMOTE; infact all LOCAL ESs are
58 * expected to have REMOTE ES peers.
61 /* Ethernet Segment Identifier */
63 char esi_str
[ESI_STR_LEN
];
67 /* created via zebra config */
68 #define BGP_EVPNES_LOCAL (1 << 0)
69 /* created implicitly by a remote ES-EVI reference */
70 #define BGP_EVPNES_REMOTE (1 << 1)
71 /* local ES link is oper-up */
72 #define BGP_EVPNES_OPER_UP (1 << 2)
73 /* enable generation of EAD-EVI routes */
74 #define BGP_EVPNES_ADV_EVI (1 << 3)
75 /* consistency checks pending */
76 #define BGP_EVPNES_CONS_CHECK_PEND (1 << 4)
77 /* ES is in LACP bypass mode - don't advertise EAD-ES or ESR */
78 #define BGP_EVPNES_BYPASS (1 << 5)
79 /* bits needed for printing the flags + null */
80 #define BGP_EVPN_FLAG_STR_SZ 7
82 /* memory used for adding the es to bgp->es_rb_tree */
83 RB_ENTRY(bgp_evpn_es
) rb_node
;
85 /* [EVPNES_LOCAL] memory used for linking the es to
86 * bgp_mh_info->local_es_list
88 struct listnode es_listnode
;
90 /* memory used for linking the es to "processing" pending list
91 * bgp_mh_info->pend_es_list
93 struct listnode pend_es_listnode
;
95 /* [EVPNES_LOCAL] List of RDs for this ES (bgp_evpn_es_frag) */
96 struct list
*es_frag_list
;
97 struct bgp_evpn_es_frag
*es_base_frag
;
99 /* [EVPNES_LOCAL] originator ip address */
100 struct in_addr originator_ip
;
102 /* [EVPNES_LOCAL] Route table for EVPN routes for this ESI-
103 * - Type-4 local and remote routes
104 * - Type-1 local routes
106 struct bgp_table
*route_table
;
108 /* list of PEs (bgp_evpn_es_vtep) attached to the ES */
109 struct list
*es_vtep_list
;
111 /* List of ES-EVIs associated with this ES */
112 struct list
*es_evi_list
;
114 /* List of ES-VRFs associated with this ES */
115 struct list
*es_vrf_list
;
117 /* List of MAC-IP VNI paths using this ES as destination -
118 * element is bgp_path_info_extra->es_info
119 * Note: Only local/zebra-added MACIP paths in the VNI
120 * routing table are linked to this list
122 struct list
*macip_evi_path_list
;
124 /* List of MAC-IP paths in the global routing table using this
125 * ES as destination - data is bgp_path_info_extra->es_info
126 * Note: Only non-local/imported MACIP paths in the global
127 * routing table are linked to this list
129 struct list
*macip_global_path_list
;
131 /* Number of remote VNIs referencing this ES */
132 uint32_t remote_es_evi_cnt
;
134 uint32_t inconsistencies
;
135 /* there are one or more EVIs whose VTEP list doesn't match
136 * with the ES's VTEP list
138 #define BGP_EVPNES_INCONS_VTEP_LIST (1 << 0)
140 /* number of es-evi entries whose VTEP list doesn't match
143 uint32_t incons_evi_vtep_cnt
;
145 /* preference config for BUM-DF election. advertised via the ESR. */
150 DECLARE_QOBJ_TYPE(bgp_evpn_es
);
151 RB_HEAD(bgp_es_rb_head
, bgp_evpn_es
);
152 RB_PROTOTYPE(bgp_es_rb_head
, bgp_evpn_es
, rb_node
, bgp_es_rb_cmp
);
154 /* PE attached to an ES */
155 struct bgp_evpn_es_vtep
{
156 struct bgp_evpn_es
*es
; /* parent ES */
157 struct in_addr vtep_ip
;
159 char vtep_str
[INET6_ADDRSTRLEN
];
162 /* Rxed a Type4 route from this PE */
163 #define BGP_EVPNES_VTEP_ESR (1 << 0)
164 /* Active (rxed EAD-ES and EAD-EVI) and can be included as
167 #define BGP_EVPNES_VTEP_ACTIVE (1 << 1)
169 uint32_t evi_cnt
; /* es_evis referencing this vtep as an active path */
171 /* Algorithm and preference for DF election. Rxed via the ESR */
175 /* memory used for adding the entry to es->es_vtep_list */
176 struct listnode es_listnode
;
179 /* ES-VRF element needed for managing L3 NHGs. It is implicitly created
180 * when an ES-EVI is associated with a tenant VRF
182 struct bgp_evpn_es_vrf
{
183 struct bgp_evpn_es
*es
;
187 /* NHG can only be activated if there are active VTEPs in the ES and
188 * there is a valid L3-VNI associated with the VRF
190 #define BGP_EVPNES_VRF_NHG_ACTIVE (1 << 0)
192 /* memory used for adding the es_vrf to
193 * es_vrf->bgp_vrf->es_vrf_rb_tree
195 RB_ENTRY(bgp_evpn_es_vrf
) rb_node
;
197 /* memory used for linking the es_vrf to es_vrf->es->es_vrf_list */
198 struct listnode es_listnode
;
203 /* Number of ES-EVI entries associated with this ES-VRF */
208 * - ES-EVIs are maintained per-L2-VNI (vpn->es_evi_rb_tree)
209 * - ES-EVIs are also linked to the parent ES (es->es_evi_list)
210 * - Local ES-EVIs are created by zebra (via config). They are linked to a
211 * per-VNI list (vpn->local_es_evi_list) for quick access
212 * - Remote ES-EVIs are created implicitly when a bgp_evpn_es_evi_vtep
215 struct bgp_evpn_es_evi
{
216 struct bgp_evpn_es
*es
;
217 /* Only applicableif EVI_LOCAL */
218 struct bgp_evpn_es_frag
*es_frag
;
223 /* local ES-EVI, created by zebra */
224 #define BGP_EVPNES_EVI_LOCAL (1 << 0)
225 /* created via a remote VTEP imported by BGP */
226 #define BGP_EVPNES_EVI_REMOTE (1 << 1)
227 #define BGP_EVPNES_EVI_INCONS_VTEP_LIST (1 << 2)
229 /* memory used for adding the es_evi to es_evi->vpn->es_evi_rb_tree */
230 RB_ENTRY(bgp_evpn_es_evi
) rb_node
;
231 /* memory used for linking the es_evi to
232 * es_evi->vpn->local_es_evi_list
234 struct listnode l2vni_listnode
;
235 /* memory used for linking the es_evi to
236 * es_evi->es->es_evi_list
238 struct listnode es_listnode
;
240 /* memory used for linking the es_evi to
241 * es_evi->es_frag->es_evi_frag_list
243 struct listnode es_frag_listnode
;
244 /* list of PEs (bgp_evpn_es_evi_vtep) attached to the ES for this VNI */
245 struct list
*es_evi_vtep_list
;
247 struct bgp_evpn_es_vrf
*es_vrf
;
250 /* PE attached to an ES for a VNI. This entry is created when an EAD-per-ES
251 * or EAD-per-EVI Type1 route is imported into the VNI.
253 struct bgp_evpn_es_evi_vtep
{
254 struct bgp_evpn_es_evi
*es_evi
; /* parent ES-EVI */
255 struct in_addr vtep_ip
;
258 /* Rxed an EAD-per-ES route from the PE */
259 #define BGP_EVPN_EVI_VTEP_EAD_PER_ES (1 << 0) /* rxed EAD-per-ES */
260 /* Rxed an EAD-per-EVI route from the PE */
261 #define BGP_EVPN_EVI_VTEP_EAD_PER_EVI (1 << 1) /* rxed EAD-per-EVI */
262 /* VTEP is active i.e. will result in the creation of an es-vtep */
263 #define BGP_EVPN_EVI_VTEP_ACTIVE (1 << 2)
264 #define BGP_EVPN_EVI_VTEP_EAD (BGP_EVPN_EVI_VTEP_EAD_PER_ES |\
265 BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
267 /* memory used for adding the entry to es_evi->es_evi_vtep_list */
268 struct listnode es_evi_listnode
;
269 struct bgp_evpn_es_vtep
*es_vtep
;
272 /* A nexthop is created when a path (imported from an EVPN type-2 route)
273 * is added to the VRF route table using that nexthop.
274 * It is added on first pi reference and removed on last pi deref.
277 /* backpointer to the VRF */
279 /* nexthop/VTEP IP */
281 /* description for easy logging */
282 char nh_str
[INET6_ADDRSTRLEN
];
284 /* pi from which we are pulling the nh RMAC */
285 struct bgp_path_info
*ref_pi
;
286 /* List of VRF paths using this nexthop */
287 struct list
*pi_list
;
289 #define BGP_EVPN_NH_READY_FOR_ZEBRA (1 << 0)
292 /* multihoming information stored in bgp_master */
293 #define bgp_mh_info (bm->mh_info)
294 struct bgp_evpn_mh_info
{
295 /* RB tree of Ethernet segments (used for EVPN-MH) */
296 struct bgp_es_rb_head es_rb_tree
;
297 /* List of local ESs */
298 struct list
*local_es_list
;
299 /* List of ESs with pending/periodic processing */
300 struct list
*pend_es_list
;
301 /* periodic timer for running background consistency checks */
302 struct thread
*t_cons_check
;
304 /* config knobs for optimizing or interop */
305 /* Generate EAD-EVI routes even if the ES is oper-down. This can be
306 * enabled as an optimization to avoid a storm of updates when an ES
309 bool ead_evi_adv_for_down_links
;
310 /* Enable ES consistency checking */
311 bool consistency_checking
;
312 /* Use L3 NHGs for host routes in symmetric IRB */
313 bool host_routes_use_l3nhg
;
314 /* Some vendors are not generating the EAD-per-EVI route. This knob
315 * can be turned off to activate a remote ES-PE when the EAD-per-ES
316 * route is rxed i.e. not wait on the EAD-per-EVI route
319 #define BGP_EVPN_MH_EAD_EVI_RX_DEF true
320 /* Skip EAD-EVI advertisements by turning off this knob */
322 #define BGP_EVPN_MH_EAD_EVI_TX_DEF true
323 /* If the Local ES is inactive we advertise the MAC-IP without the
326 bool suppress_l3_ecomm_on_inactive_es
;
327 /* Setup EVPN PE nexthops and their RMAC in bgpd */
328 bool bgp_evpn_nh_setup
;
330 /* If global export-rts are configured that is used for sending
331 * sending the ead-per-es route instead of the L2-VNI(s) RTs
333 struct list
*ead_es_export_rtl
;
335 /* Number of EVIs in an ES fragment - used of EAD-per-ES route
338 uint32_t evi_per_es_frag
;
341 /****************************************************************************/
342 static inline int bgp_evpn_is_es_local(struct bgp_evpn_es
*es
)
344 return CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
) ? 1 : 0;
347 extern esi_t
*zero_esi
;
348 static inline bool bgp_evpn_is_esi_valid(esi_t
*esi
)
350 return !!memcmp(esi
, zero_esi
, sizeof(esi_t
));
353 static inline esi_t
*bgp_evpn_attr_get_esi(struct attr
*attr
)
355 return attr
? &attr
->esi
: zero_esi
;
358 static inline bool bgp_evpn_attr_is_sync(struct attr
*attr
)
360 return attr
? !!(attr
->es_flags
&
361 (ATTR_ES_PEER_PROXY
| ATTR_ES_PEER_ACTIVE
)) : false;
364 static inline uint32_t bgp_evpn_attr_get_sync_seq(struct attr
*attr
)
366 return attr
? attr
->mm_sync_seqnum
: 0;
369 static inline bool bgp_evpn_attr_is_active_on_peer(struct attr
*attr
)
372 !!(attr
->es_flags
& ATTR_ES_PEER_ACTIVE
) : false;
375 static inline bool bgp_evpn_attr_is_router_on_peer(struct attr
*attr
)
378 !!(attr
->es_flags
& ATTR_ES_PEER_ROUTER
) : false;
381 static inline bool bgp_evpn_attr_is_proxy(struct attr
*attr
)
383 return attr
? !!(attr
->es_flags
& ATTR_ES_PROXY_ADVERT
) : false;
386 static inline bool bgp_evpn_attr_is_local_es(struct attr
*attr
)
388 return attr
? !!(attr
->es_flags
& ATTR_ES_IS_LOCAL
) : false;
391 static inline uint32_t bgp_evpn_attr_get_df_pref(struct attr
*attr
)
393 return (attr
) ? attr
->df_pref
: 0;
396 static inline bool bgp_evpn_local_es_is_active(struct bgp_evpn_es
*es
)
398 return (es
->flags
& BGP_EVPNES_OPER_UP
)
399 && !(es
->flags
& BGP_EVPNES_BYPASS
);
402 /****************************************************************************/
403 extern int bgp_evpn_es_route_install_uninstall(struct bgp
*bgp
,
404 struct bgp_evpn_es
*es
, afi_t afi
, safi_t safi
,
405 struct prefix_evpn
*evp
, struct bgp_path_info
*pi
,
407 extern void update_type1_routes_for_evi(struct bgp
*bgp
, struct bgpevpn
*vpn
);
408 extern int delete_global_ead_evi_routes(struct bgp
*bgp
, struct bgpevpn
*vpn
);
409 extern int bgp_evpn_mh_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
410 struct bgpevpn
*vpn
, afi_t afi
, safi_t safi
,
411 struct bgp_dest
*dest
, struct attr
*attr
,
412 struct bgp_path_info
**ri
,
414 int bgp_evpn_type1_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
415 struct attr
*attr
, uint8_t *pfx
, int psize
,
416 uint32_t addpath_id
);
417 int bgp_evpn_type4_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
418 struct attr
*attr
, uint8_t *pfx
, int psize
,
419 uint32_t addpath_id
);
420 extern int bgp_evpn_local_es_add(struct bgp
*bgp
, esi_t
*esi
,
421 struct in_addr originator_ip
, bool oper_up
,
422 uint16_t df_pref
, bool bypass
);
423 extern int bgp_evpn_local_es_del(struct bgp
*bgp
, esi_t
*esi
);
424 extern int bgp_evpn_local_es_evi_add(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
);
425 extern int bgp_evpn_local_es_evi_del(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
);
426 extern int bgp_evpn_remote_es_evi_add(struct bgp
*bgp
, struct bgpevpn
*vpn
,
427 const struct prefix_evpn
*p
);
428 extern int bgp_evpn_remote_es_evi_del(struct bgp
*bgp
, struct bgpevpn
*vpn
,
429 const struct prefix_evpn
*p
);
430 extern void bgp_evpn_mh_init(void);
431 extern void bgp_evpn_mh_finish(void);
432 void bgp_evpn_vni_es_init(struct bgpevpn
*vpn
);
433 void bgp_evpn_vni_es_cleanup(struct bgpevpn
*vpn
);
434 void bgp_evpn_es_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
);
435 void bgp_evpn_es_show(struct vty
*vty
, bool uj
, bool detail
);
436 void bgp_evpn_es_evi_show_vni(struct vty
*vty
, vni_t vni
,
437 bool uj
, bool detail
);
438 void bgp_evpn_es_evi_show(struct vty
*vty
, bool uj
, bool detail
);
439 struct bgp_evpn_es
*bgp_evpn_es_find(const esi_t
*esi
);
440 extern void bgp_evpn_vrf_es_init(struct bgp
*bgp_vrf
);
441 extern bool bgp_evpn_is_esi_local_and_non_bypass(esi_t
*esi
);
442 extern void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi
*es_evi
);
443 extern void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi
*es_evi
,
444 struct bgp
*bgp_vrf
);
445 extern void bgp_evpn_path_mh_info_free(struct bgp_path_mh_info
*mh_info
);
446 extern void bgp_evpn_path_es_link(struct bgp_path_info
*pi
, vni_t vni
,
448 extern bool bgp_evpn_path_es_use_nhg(struct bgp
*bgp_vrf
,
449 struct bgp_path_info
*pi
, uint32_t *nhg_p
);
450 extern void bgp_evpn_es_vrf_show(struct vty
*vty
, bool uj
,
451 struct bgp_evpn_es
*es
);
452 extern void bgp_evpn_es_vrf_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
);
453 extern void bgp_evpn_switch_ead_evi_rx(void);
454 extern bool bgp_evpn_es_add_l3_ecomm_ok(esi_t
*esi
);
455 extern void bgp_evpn_es_vrf_use_nhg(struct bgp
*bgp_vrf
, esi_t
*esi
,
456 bool *use_l3nhg
, bool *is_l3nhg_active
,
457 struct bgp_evpn_es_vrf
**es_vrf_p
);
458 extern void bgp_evpn_nh_init(struct bgp
*bgp_vrf
);
459 extern void bgp_evpn_nh_finish(struct bgp
*bgp_vrf
);
460 extern void bgp_evpn_nh_show(struct vty
*vty
, bool uj
);
461 extern void bgp_evpn_path_nh_add(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
);
462 extern void bgp_evpn_path_nh_del(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
);
463 extern void bgp_evpn_mh_config_ead_export_rt(struct bgp
*bgp
,
464 struct ecommunity
*ecom
, bool del
);
466 #endif /* _FRR_BGP_EVPN_MH_H */