diff options
author | Anuradha Karuppiah <anuradhak@cumulusnetworks.com> | 2020-03-29 17:43:55 +0200 |
---|---|---|
committer | Anuradha Karuppiah <anuradhak@cumulusnetworks.com> | 2020-08-05 15:46:13 +0200 |
commit | b169fd6fd59ed0c745c6f32a878d7fcc981e8d33 (patch) | |
tree | 66008622a7ea65e760099daf6218473f34c61402 /zebra/zebra_evpn_mh.c | |
parent | zebra: debug flags for MAC-IP sync (diff) | |
download | frr-b169fd6fd59ed0c745c6f32a878d7fcc981e8d33.tar.xz frr-b169fd6fd59ed0c745c6f32a878d7fcc981e8d33.zip |
zebra: support for MAC-IP sync routes
MAC-IP routes are used for syncing local entries across redundant
switches in an EVPN-MH setup. A path from a peer that has a local
ES as destination is tagged as a SYNC path. The SYNC path results in the
addition of local MAC and/or local neigh entry in zebra and in the
dataplane.
Implementation overview
=======================
1. Three new flags "local-inactive", "peer-active" and "peer-proxy"
are maintained per-local-MAC and per-local-Neigh entry.
2. The "peer-XXX" flags are set and cleared via SYNC path updates
from BGP. Proxy sync paths result in the setting of "peer-proxy" flag
(and non-proxies result in the "peer-active").
3. A neigh entry that has a "peer-XXX" flag set is programmed as
"static" in the dataplane.
4. A MAC entry that has a "peer-XXX" flag set or is referenced by
a sync-neigh entry (that has a "peer-XXX" flags set) is programmed
as "static" in the dataplane.
5. The sync-seq number is used to normalize the MM seq number across
all the redundant switches i.e. the max MM seq number across all
switches is used by each of the switches. This commit also includes
the changes needed for extended MM seq syncing.
6. A MAC/neigh entry has to be local-active or peer-active to sent to
BGP. An entry that is NOT local-active is sent with the proxy flag (so
BGP can "proxy" advertise it).
7. The "peer-active" flag is aged out by zebra by using a hold_timer
(this is instead of being abruptly dropped on SYNC path delete). This
age-out is needed to handle peer-switch restart (procedures are specified
in draft-rbickhart-evpn-ip-mac-proxy-adv). The holdtime needs to be
sufficiently long to allow an external neighmgr daemon or the dataplane
component to independently probe and establish local reachability of a
host. The MAC and neigh hold time values are configurable.
PS: In the future this probing may happen in FRR itself.
CLI changes to display sync info
================================
MAC
===
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
root@torm-11:mgmt:~# net show evpn mac vni 1000
Number of MACs (local and remote) known for this VNI: 6
Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy
MAC Type Flags Intf/Remote ES/VTEP VLAN Seq #'s
00:02:00:00:00:25 local vlan1000 1000 0/0
02:02:00:00:00:02 local PI hostbond1 1000 0/0
02:02:00:00:00:06 remote 03:00:00:00:00:02:11:00:00:01 0/0
02:02:00:00:00:01 local X hostbond1 1000 0/0
00:00:00:00:00:11 local PI hostbond1 1000 0/0
02:02:00:00:00:05 remote 03:00:00:00:00:02:11:00:00:01 0/0
root@torm-11:mgmt:~#
root@torm-11:mgmt:~# net show evpn mac vni 1000 mac 00:00:00:00:00:11
MAC: 00:00:00:00:00:11
ESI: 03:00:00:00:00:01:11:00:00:01
Intf: hostbond1(58) VLAN: 1000
Sync-info: neigh#: 0 local-inactive peer-active >>>>>>>>>>>>
Local Seq: 0 Remote Seq: 0
Neighbors:
No Neighbors
root@torm-11:mgmt:~#
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
neigh
=====
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
root@torm-11:mgmt:~# net show evpn arp vni 1003
Number of ARPs (local and remote) known for this VNI: 4
Flags: I=local-inactive, P=peer-active, X=peer-proxy
Neighbor Type Flags State MAC Remote ES/VTEP Seq #'s
2001:fee1:0:3::6 local active 00:02:00:00:00:25 0/0
45.0.3.66 local P active 00:02:00:00:00:66 0/0
45.0.3.6 local active 00:02:00:00:00:25 0/0
fe80::202:ff:fe00:25 local active 00:02:00:00:00:25 0/0
root@torm-11:mgmt:~#
root@torm-11:mgmt:~# net show evpn arp vni 1003 ip 45.0.3.66
IP: 45.0.3.66
Type: local
State: active
MAC: 00:02:00:00:00:66
Sync-info: peer-active >>>>>>>>>>>>>>>>
Local Seq: 0 Remote Seq: 0
root@torm-11:mgmt:~#
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Diffstat (limited to 'zebra/zebra_evpn_mh.c')
-rw-r--r-- | zebra/zebra_evpn_mh.c | 91 |
1 files changed, 81 insertions, 10 deletions
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index c55e9d3ec..435e11021 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -1085,6 +1085,10 @@ static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi) listset_app_node_mem(es->es_vtep_list); es->es_vtep_list->cmp = zebra_evpn_es_vtep_cmp; + /* mac entries associated with the ES */ + es->mac_list = list_new(); + listset_app_node_mem(es->mac_list); + /* reserve a NHG */ es->nhg_id = zebra_evpn_nhid_alloc(true); @@ -1098,15 +1102,15 @@ static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi) * This just frees appropriate memory, caller should have taken other * needed actions. */ -static void zebra_evpn_es_free(struct zebra_evpn_es *es) +static struct zebra_evpn_es *zebra_evpn_es_free(struct zebra_evpn_es *es) { /* If the ES has a local or remote reference it cannot be freed. * Free is also prevented if there are MAC entries referencing * it. */ if ((es->flags & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE)) || - es->mac_cnt) - return; + listcount(es->mac_list)) + return es; if (IS_ZEBRA_DEBUG_EVPN_MH_ES) zlog_debug("es %s free", es->esi_str); @@ -1121,11 +1125,14 @@ static void zebra_evpn_es_free(struct zebra_evpn_es *es) /* cleanup resources maintained against the ES */ list_delete(&es->es_evi_list); list_delete(&es->es_vtep_list); + list_delete(&es->mac_list); /* remove from the VNI-ESI rb tree */ RB_REMOVE(zebra_es_rb_head, &zmh_info->es_rb_tree, es); XFREE(MTYPE_ZES, es); + + return NULL; } /* Inform BGP about local ES addition */ @@ -1278,6 +1285,21 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es) } } +static void zebra_evpn_es_local_mac_update(struct zebra_evpn_es *es, + bool force_clear_static) +{ + zebra_mac_t *mac; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) { + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) { + zebra_vxlan_sync_mac_dp_install(mac, + false /* set_inactive */, + force_clear_static, __func__); + } + } +} + static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es, struct zebra_if *zif) { @@ -1314,6 +1336,12 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es, * the zif */ zebra_evpn_es_setup_evis(es); + /* if there any local macs referring to the ES as dest we + * need to set the static reference on them if the MAC is + * synced from an ES peer + */ + zebra_evpn_es_local_mac_update(es, + false /* force_clear_static */); } static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es *es) @@ -1324,6 +1352,12 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es *es) return; es->flags &= ~ZEBRA_EVPNES_LOCAL; + /* if there any local macs referring to the ES as dest we + * need to clear the static reference on them + */ + zebra_evpn_es_local_mac_update(es, + true /* force_clear_static */); + /* clear the es from the parent interface */ zif = es->zif; zif->es_info.es = NULL; @@ -1539,11 +1573,11 @@ void zebra_evpn_es_mac_deref_entry(zebra_mac_t *mac) struct zebra_evpn_es *es = mac->es; mac->es = NULL; - if (!es || !es->mac_cnt) + if (!es) return; - --es->mac_cnt; - if (!es->mac_cnt) + list_delete_node(es->mac_list, &mac->es_listnode); + if (!listcount(es->mac_list)) zebra_evpn_es_free(es); } @@ -1562,11 +1596,13 @@ bool zebra_evpn_es_mac_ref_entry(zebra_mac_t *mac, struct zebra_evpn_es *es) return true; mac->es = es; - ++es->mac_cnt; + listnode_init(&mac->es_listnode, mac); + listnode_add(es->mac_list, &mac->es_listnode); + return true; } -void zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi) +bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi) { struct zebra_evpn_es *es; @@ -1577,7 +1613,7 @@ void zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi) zlog_debug("auto es %s add on mac ref", es->esi_str); } - zebra_evpn_es_mac_ref_entry(mac, es); + return zebra_evpn_es_mac_ref_entry(mac, es); } /* Inform BGP about local ES-EVI add or del */ @@ -1769,7 +1805,7 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty, (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) ? "yes" : "no"); vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list)); - vty_out(vty, " MAC Count: %d\n", es->mac_cnt); + vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list)); vty_out(vty, " Nexthop group: 0x%x\n", es->nhg_id); vty_out(vty, " VTEPs:\n"); for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, zvtep)) @@ -2037,6 +2073,39 @@ static void zebra_evpn_es_get_one_base_vni(void) } /*****************************************************************************/ +void zebra_evpn_mh_config_write(struct vty *vty) +{ + if (zmh_info->mac_hold_time != EVPN_MH_MAC_HOLD_TIME_DEF) + vty_out(vty, "evpn mh mac-holdtime %ld\n", + zmh_info->mac_hold_time); + + if (zmh_info->neigh_hold_time != EVPN_MH_NEIGH_HOLD_TIME_DEF) + vty_out(vty, "evpn mh neigh-holdtime %ld\n", + zmh_info->neigh_hold_time); +} + +int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty, + uint32_t duration, bool set_default) +{ + if (set_default) + zmh_info->neigh_hold_time = EVPN_MH_NEIGH_HOLD_TIME_DEF; + + zmh_info->neigh_hold_time = duration; + + return 0; +} + +int zebra_evpn_mh_mac_holdtime_update(struct vty *vty, + uint32_t duration, bool set_default) +{ + if (set_default) + duration = EVPN_MH_MAC_HOLD_TIME_DEF; + + zmh_info->mac_hold_time = duration; + + return 0; +} + void zebra_evpn_interface_init(void) { install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd); @@ -2047,6 +2116,8 @@ void zebra_evpn_mh_init(void) { zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info)); + zmh_info->mac_hold_time = EVPN_MH_MAC_HOLD_TIME_DEF; + zmh_info->neigh_hold_time = EVPN_MH_NEIGH_HOLD_TIME_DEF; /* setup ES tables */ RB_INIT(zebra_es_rb_head, &zmh_info->es_rb_tree); zmh_info->local_es_list = list_new(); |