]>
Commit | Line | Data |
---|---|---|
13d60d35 | 1 | /* |
2 | * Zebra EVPN for VxLAN code | |
3 | * Copyright (C) 2016, 2017 Cumulus Networks, Inc. | |
4 | * | |
5 | * This file is part of FRR. | |
6 | * | |
7 | * FRR is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2, or (at your option) any | |
10 | * later version. | |
11 | * | |
12 | * FRR is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with FRR; see the file COPYING. If not, write to the Free | |
19 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
20 | * 02111-1307, USA. | |
21 | */ | |
22 | ||
23 | #include <zebra.h> | |
24 | ||
43e52561 | 25 | #include "hash.h" |
13d60d35 | 26 | #include "if.h" |
43e52561 | 27 | #include "jhash.h" |
13d60d35 | 28 | #include "linklist.h" |
43e52561 QY |
29 | #include "log.h" |
30 | #include "memory.h" | |
31 | #include "prefix.h" | |
13d60d35 | 32 | #include "stream.h" |
43e52561 | 33 | #include "table.h" |
13d60d35 | 34 | #include "vlan.h" |
35 | #include "vxlan.h" | |
68e33151 CS |
36 | #ifdef GNU_LINUX |
37 | #include <linux/neighbour.h> | |
38 | #endif | |
9bee0232 | 39 | #include "lib/printfrr.h" |
13d60d35 | 40 | |
89272910 | 41 | #include "zebra/zebra_router.h" |
43e52561 QY |
42 | #include "zebra/debug.h" |
43 | #include "zebra/interface.h" | |
13d60d35 | 44 | #include "zebra/rib.h" |
45 | #include "zebra/rt.h" | |
43e52561 QY |
46 | #include "zebra/rt_netlink.h" |
47 | #include "zebra/zebra_errors.h" | |
48 | #include "zebra/zebra_l2.h" | |
49 | #include "zebra/zebra_memory.h" | |
13d60d35 | 50 | #include "zebra/zebra_ns.h" |
13d60d35 | 51 | #include "zebra/zebra_vrf.h" |
13d60d35 | 52 | #include "zebra/zebra_vxlan.h" |
b2998086 PR |
53 | #include "zebra/zebra_evpn.h" |
54 | #include "zebra/zebra_evpn_mac.h" | |
55 | #include "zebra/zebra_evpn_neigh.h" | |
43e52561 | 56 | #include "zebra/zebra_vxlan_private.h" |
ce5160c0 | 57 | #include "zebra/zebra_evpn_mh.h" |
8b5fdf2e | 58 | #include "zebra/zebra_evpn_vxlan.h" |
3801e764 | 59 | #include "zebra/zebra_router.h" |
13d60d35 | 60 | |
6134fd82 | 61 | DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix"); |
b7cfce93 | 62 | DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash"); |
b2998086 | 63 | DEFINE_MTYPE_STATIC(ZEBRA, L3VNI_MAC, "EVPN L3VNI MAC"); |
7cbae20a | 64 | DEFINE_MTYPE_STATIC(ZEBRA, L3NEIGH, "EVPN Neighbor"); |
8a93734c | 65 | DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group"); |
13d60d35 | 66 | |
a780a738 AD |
67 | DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, |
68 | bool delete, const char *reason), (rmac, zl3vni, delete, reason)) | |
69 | ||
13d60d35 | 70 | /* static function declarations */ |
87d76d54 PR |
71 | static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket, |
72 | void **args); | |
c0e519d3 MK |
73 | static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty, |
74 | json_object *json); | |
316f4ca4 MK |
75 | static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, |
76 | json_object *json); | |
87d76d54 | 77 | static void zevpn_print_mac_hash_all_evpn(struct hash_bucket *bucket, void *ctxt); |
d62a17ae | 78 | |
b7cfce93 | 79 | /* l3-vni next-hop neigh related APIs */ |
2dbad57f | 80 | static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, |
e4a1ec74 | 81 | const struct ipaddr *ip); |
b7cfce93 MK |
82 | static void *zl3vni_nh_alloc(void *p); |
83 | static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, | |
e4a1ec74 MS |
84 | const struct ipaddr *vtep_ip, |
85 | const struct ethaddr *rmac); | |
b7cfce93 MK |
86 | static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); |
87 | static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); | |
2dbad57f | 88 | static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); |
b7cfce93 MK |
89 | |
90 | /* l3-vni rmac related APIs */ | |
e3b78da8 | 91 | static void zl3vni_print_rmac_hash(struct hash_bucket *, void *); |
2dbad57f | 92 | static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, |
e4a1ec74 | 93 | const struct ethaddr *rmac); |
b7cfce93 MK |
94 | static void *zl3vni_rmac_alloc(void *p); |
95 | static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, | |
e4a1ec74 | 96 | const struct ethaddr *rmac); |
b7cfce93 MK |
97 | static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); |
98 | static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); | |
996c9314 | 99 | static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); |
b7cfce93 MK |
100 | |
101 | /* l3-vni related APIs*/ | |
b7cfce93 MK |
102 | static void *zl3vni_alloc(void *p); |
103 | static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id); | |
104 | static int zl3vni_del(zebra_l3vni_t *zl3vni); | |
b7cfce93 MK |
105 | static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni); |
106 | static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni); | |
107 | ||
87d76d54 | 108 | static void zevpn_build_hash_table(void); |
d8b87afe | 109 | static unsigned int zebra_vxlan_sg_hash_key_make(const void *p); |
015d264c AK |
110 | static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2); |
111 | static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, | |
112 | struct in_addr sip, struct in_addr mcast_grp); | |
113 | static zebra_vxlan_sg_t *zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf, | |
114 | struct in_addr sip, struct in_addr mcast_grp); | |
abfa0a96 AK |
115 | static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, |
116 | struct in_addr mcast_grp); | |
117 | static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, | |
118 | struct in_addr mcast_grp); | |
0c16fb72 | 119 | static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf); |
13d60d35 | 120 | |
b2ee2b71 AK |
121 | bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf) |
122 | { | |
123 | return zvrf->dup_addr_detect && zebra_evpn_mh_do_dup_addr_detect(); | |
124 | } | |
125 | ||
13d60d35 | 126 | /* Private functions */ |
5e1b0650 | 127 | static int host_rb_entry_compare(const struct host_rb_entry *hle1, |
85442b09 | 128 | const struct host_rb_entry *hle2) |
5e1b0650 DS |
129 | { |
130 | if (hle1->p.family < hle2->p.family) | |
131 | return -1; | |
132 | ||
133 | if (hle1->p.family > hle2->p.family) | |
134 | return 1; | |
135 | ||
136 | if (hle1->p.prefixlen < hle2->p.prefixlen) | |
137 | return -1; | |
138 | ||
139 | if (hle1->p.prefixlen > hle2->p.prefixlen) | |
140 | return 1; | |
141 | ||
142 | if (hle1->p.family == AF_INET) { | |
143 | if (hle1->p.u.prefix4.s_addr < hle2->p.u.prefix4.s_addr) | |
144 | return -1; | |
145 | ||
146 | if (hle1->p.u.prefix4.s_addr > hle2->p.u.prefix4.s_addr) | |
147 | return 1; | |
148 | ||
149 | return 0; | |
2acc2310 DS |
150 | } else if (hle1->p.family == AF_INET6) { |
151 | return memcmp(&hle1->p.u.prefix6, &hle2->p.u.prefix6, | |
152 | IPV6_MAX_BYTELEN); | |
5e1b0650 | 153 | } else { |
15569c58 DA |
154 | zlog_debug("%s: Unexpected family type: %d", __func__, |
155 | hle1->p.family); | |
5e1b0650 DS |
156 | return 0; |
157 | } | |
158 | } | |
85442b09 | 159 | RB_GENERATE(host_rb_tree_entry, host_rb_entry, hl_entry, host_rb_entry_compare); |
5e1b0650 | 160 | |
85442b09 | 161 | static uint32_t rb_host_count(struct host_rb_tree_entry *hrbe) |
5e1b0650 DS |
162 | { |
163 | struct host_rb_entry *hle; | |
164 | uint32_t count = 0; | |
165 | ||
85442b09 | 166 | RB_FOREACH (hle, host_rb_tree_entry, hrbe) |
5e1b0650 DS |
167 | count++; |
168 | ||
169 | return count; | |
170 | } | |
13d60d35 | 171 | |
cec2e17d | 172 | /* |
87d76d54 | 173 | * Print neighbors for all EVPN. |
cec2e17d | 174 | */ |
87d76d54 | 175 | static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket, |
cd233079 | 176 | void **args) |
cec2e17d | 177 | { |
d62a17ae | 178 | struct vty *vty; |
87d76d54 PR |
179 | json_object *json = NULL, *json_evpn = NULL; |
180 | zebra_evpn_t *zevpn; | |
d7c0a89a | 181 | uint32_t num_neigh; |
d62a17ae | 182 | struct neigh_walk_ctx wctx; |
cd233079 | 183 | char vni_str[VNI_STR_LEN]; |
1374d4db | 184 | uint32_t print_dup; |
cd233079 CS |
185 | |
186 | vty = (struct vty *)args[0]; | |
187 | json = (json_object *)args[1]; | |
1374d4db | 188 | print_dup = (uint32_t)(uintptr_t)args[2]; |
cec2e17d | 189 | |
87d76d54 | 190 | zevpn = (zebra_evpn_t *)bucket->data; |
9ea660be | 191 | |
87d76d54 | 192 | num_neigh = hashcount(zevpn->neigh_table); |
1374d4db CS |
193 | |
194 | if (print_dup) | |
87d76d54 | 195 | num_neigh = num_dup_detected_neighs(zevpn); |
1374d4db | 196 | |
68e33151 | 197 | if (json == NULL) { |
cd233079 CS |
198 | vty_out(vty, |
199 | "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n", | |
87d76d54 | 200 | zevpn->vni, num_neigh); |
68e33151 | 201 | } else { |
87d76d54 PR |
202 | json_evpn = json_object_new_object(); |
203 | json_object_int_add(json_evpn, "numArpNd", num_neigh); | |
204 | snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni); | |
cd233079 | 205 | } |
1374d4db | 206 | |
cd233079 CS |
207 | if (!num_neigh) { |
208 | if (json) | |
87d76d54 | 209 | json_object_object_add(json, vni_str, json_evpn); |
d62a17ae | 210 | return; |
cd233079 | 211 | } |
cec2e17d | 212 | |
d62a17ae | 213 | /* Since we have IPv6 addresses to deal with which can vary widely in |
214 | * size, we try to be a bit more elegant in display by first computing | |
215 | * the maximum width. | |
216 | */ | |
217 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); | |
87d76d54 | 218 | wctx.zevpn = zevpn; |
d62a17ae | 219 | wctx.vty = vty; |
220 | wctx.addr_width = 15; | |
87d76d54 | 221 | wctx.json = json_evpn; |
7cbae20a PR |
222 | hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width, |
223 | &wctx); | |
cec2e17d | 224 | |
b169fd6f | 225 | if (json == NULL) |
7cbae20a | 226 | zebra_evpn_print_neigh_hdr(vty, &wctx); |
b169fd6f | 227 | |
1374d4db | 228 | if (print_dup) |
7cbae20a PR |
229 | hash_iterate(zevpn->neigh_table, |
230 | zebra_evpn_print_dad_neigh_hash, &wctx); | |
1374d4db | 231 | else |
7cbae20a PR |
232 | hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash, |
233 | &wctx); | |
cd233079 CS |
234 | |
235 | if (json) | |
87d76d54 | 236 | json_object_object_add(json, vni_str, json_evpn); |
cec2e17d | 237 | } |
238 | ||
e3fac919 | 239 | /* |
87d76d54 | 240 | * Print neighbors for all EVPNs in detail. |
e3fac919 | 241 | */ |
87d76d54 | 242 | static void zevpn_print_neigh_hash_all_evpn_detail(struct hash_bucket *bucket, |
e3fac919 NS |
243 | void **args) |
244 | { | |
245 | struct vty *vty; | |
87d76d54 PR |
246 | json_object *json = NULL, *json_evpn = NULL; |
247 | zebra_evpn_t *zevpn; | |
e3fac919 NS |
248 | uint32_t num_neigh; |
249 | struct neigh_walk_ctx wctx; | |
250 | char vni_str[VNI_STR_LEN]; | |
251 | uint32_t print_dup; | |
252 | ||
253 | vty = (struct vty *)args[0]; | |
254 | json = (json_object *)args[1]; | |
255 | print_dup = (uint32_t)(uintptr_t)args[2]; | |
256 | ||
87d76d54 PR |
257 | zevpn = (zebra_evpn_t *)bucket->data; |
258 | if (!zevpn) { | |
e3fac919 NS |
259 | if (json) |
260 | vty_out(vty, "{}\n"); | |
261 | return; | |
262 | } | |
87d76d54 | 263 | num_neigh = hashcount(zevpn->neigh_table); |
e3fac919 | 264 | |
87d76d54 | 265 | if (print_dup && num_dup_detected_neighs(zevpn) == 0) |
e3fac919 NS |
266 | return; |
267 | ||
268 | if (json == NULL) { | |
269 | vty_out(vty, | |
270 | "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n", | |
87d76d54 | 271 | zevpn->vni, num_neigh); |
e3fac919 | 272 | } else { |
87d76d54 PR |
273 | json_evpn = json_object_new_object(); |
274 | json_object_int_add(json_evpn, "numArpNd", num_neigh); | |
275 | snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni); | |
e3fac919 NS |
276 | } |
277 | if (!num_neigh) { | |
278 | if (json) | |
87d76d54 | 279 | json_object_object_add(json, vni_str, json_evpn); |
e3fac919 NS |
280 | return; |
281 | } | |
282 | ||
283 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); | |
87d76d54 | 284 | wctx.zevpn = zevpn; |
e3fac919 NS |
285 | wctx.vty = vty; |
286 | wctx.addr_width = 15; | |
87d76d54 | 287 | wctx.json = json_evpn; |
e3fac919 NS |
288 | |
289 | if (print_dup) | |
87d76d54 | 290 | hash_iterate(zevpn->neigh_table, |
7cbae20a | 291 | zebra_evpn_print_dad_neigh_hash_detail, &wctx); |
e3fac919 | 292 | else |
7cbae20a PR |
293 | hash_iterate(zevpn->neigh_table, |
294 | zebra_evpn_print_neigh_hash_detail, &wctx); | |
e3fac919 NS |
295 | |
296 | if (json) | |
87d76d54 | 297 | json_object_object_add(json, vni_str, json_evpn); |
e3fac919 NS |
298 | } |
299 | ||
9aa741ea | 300 | /* print a specific next hop for an l3vni */ |
996c9314 | 301 | static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty, |
c0e519d3 | 302 | json_object *json) |
9aa741ea MK |
303 | { |
304 | char buf1[ETHER_ADDR_STRLEN]; | |
305 | char buf2[INET6_ADDRSTRLEN]; | |
c0e519d3 | 306 | json_object *json_hosts = NULL; |
f2a503f0 | 307 | struct host_rb_entry *hle; |
9aa741ea | 308 | |
c0e519d3 MK |
309 | if (!json) { |
310 | vty_out(vty, "Ip: %s\n", | |
311 | ipaddr2str(&n->ip, buf2, sizeof(buf2))); | |
312 | vty_out(vty, " RMAC: %s\n", | |
996c9314 | 313 | prefix_mac2str(&n->emac, buf1, sizeof(buf1))); |
f2a503f0 DS |
314 | vty_out(vty, " Refcount: %d\n", |
315 | rb_host_count(&n->host_rb)); | |
4cce389e | 316 | vty_out(vty, " Prefixes:\n"); |
85442b09 | 317 | RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb) |
2dbe669b | 318 | vty_out(vty, " %pFX\n", &hle->p); |
c0e519d3 MK |
319 | } else { |
320 | json_hosts = json_object_new_array(); | |
996c9314 LB |
321 | json_object_string_add( |
322 | json, "ip", ipaddr2str(&(n->ip), buf2, sizeof(buf2))); | |
323 | json_object_string_add( | |
324 | json, "routerMac", | |
325 | prefix_mac2str(&n->emac, buf2, sizeof(buf2))); | |
f2a503f0 DS |
326 | json_object_int_add(json, "refCount", |
327 | rb_host_count(&n->host_rb)); | |
85442b09 | 328 | RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb) |
c0e519d3 | 329 | json_object_array_add(json_hosts, |
996c9314 | 330 | json_object_new_string(prefix2str( |
f2a503f0 | 331 | &hle->p, buf2, sizeof(buf2)))); |
4cce389e | 332 | json_object_object_add(json, "prefixList", json_hosts); |
c0e519d3 | 333 | } |
9aa741ea MK |
334 | } |
335 | ||
336 | /* Print a specific RMAC entry */ | |
996c9314 | 337 | static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, |
316f4ca4 | 338 | json_object *json) |
9aa741ea MK |
339 | { |
340 | char buf1[ETHER_ADDR_STRLEN]; | |
341 | char buf2[PREFIX_STRLEN]; | |
316f4ca4 | 342 | json_object *json_hosts = NULL; |
5e1b0650 | 343 | struct host_rb_entry *hle; |
9aa741ea | 344 | |
316f4ca4 MK |
345 | if (!json) { |
346 | vty_out(vty, "MAC: %s\n", | |
347 | prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); | |
9bcef951 MS |
348 | vty_out(vty, " Remote VTEP: %pI4\n", |
349 | &zrmac->fwd_info.r_vtep_ip); | |
41db76c2 | 350 | vty_out(vty, " Refcount: %d\n", rb_host_count(&zrmac->host_rb)); |
4cce389e | 351 | vty_out(vty, " Prefixes:\n"); |
85442b09 | 352 | RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb) |
2dbe669b | 353 | vty_out(vty, " %pFX\n", &hle->p); |
316f4ca4 MK |
354 | } else { |
355 | json_hosts = json_object_new_array(); | |
996c9314 LB |
356 | json_object_string_add( |
357 | json, "routerMac", | |
358 | prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); | |
4cce389e | 359 | json_object_string_add(json, "vtepIp", |
9bcef951 MS |
360 | inet_ntop(AF_INET, |
361 | &zrmac->fwd_info.r_vtep_ip, | |
362 | buf1, sizeof(buf1))); | |
41db76c2 DS |
363 | json_object_int_add(json, "refCount", |
364 | rb_host_count(&zrmac->host_rb)); | |
1a8c5c38 | 365 | json_object_int_add(json, "localSequence", zrmac->loc_seq); |
366 | json_object_int_add(json, "remoteSequence", zrmac->rem_seq); | |
85442b09 | 367 | RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb) |
5e1b0650 DS |
368 | json_object_array_add( |
369 | json_hosts, | |
370 | json_object_new_string(prefix2str( | |
371 | &hle->p, buf2, sizeof(buf2)))); | |
4cce389e | 372 | json_object_object_add(json, "prefixList", json_hosts); |
316f4ca4 | 373 | } |
9aa741ea MK |
374 | } |
375 | ||
cec2e17d | 376 | /* |
87d76d54 | 377 | * Print MACs for all EVPNs. |
cec2e17d | 378 | */ |
87d76d54 | 379 | static void zevpn_print_mac_hash_all_evpn(struct hash_bucket *bucket, void *ctxt) |
cec2e17d | 380 | { |
d62a17ae | 381 | struct vty *vty; |
87d76d54 | 382 | json_object *json = NULL, *json_evpn = NULL; |
cd233079 | 383 | json_object *json_mac = NULL; |
87d76d54 | 384 | zebra_evpn_t *zevpn; |
d7c0a89a | 385 | uint32_t num_macs; |
d62a17ae | 386 | struct mac_walk_ctx *wctx = ctxt; |
cd233079 | 387 | char vni_str[VNI_STR_LEN]; |
cec2e17d | 388 | |
c4efd0f4 DA |
389 | vty = wctx->vty; |
390 | json = wctx->json; | |
cec2e17d | 391 | |
87d76d54 PR |
392 | zevpn = (zebra_evpn_t *)bucket->data; |
393 | wctx->zevpn = zevpn; | |
cec2e17d | 394 | |
d62a17ae | 395 | /*We are iterating over a new VNI, set the count to 0*/ |
396 | wctx->count = 0; | |
cec2e17d | 397 | |
87d76d54 | 398 | num_macs = num_valid_macs(zevpn); |
d62a17ae | 399 | if (!num_macs) |
400 | return; | |
cd233079 | 401 | |
1374d4db | 402 | if (wctx->print_dup) |
87d76d54 | 403 | num_macs = num_dup_detected_macs(zevpn); |
1374d4db | 404 | |
cd233079 | 405 | if (json) { |
87d76d54 | 406 | json_evpn = json_object_new_object(); |
cd233079 | 407 | json_mac = json_object_new_object(); |
87d76d54 | 408 | snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni); |
d62a17ae | 409 | } |
cec2e17d | 410 | |
cd233079 CS |
411 | if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) { |
412 | if (json == NULL) { | |
413 | vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n", | |
87d76d54 | 414 | zevpn->vni, num_macs); |
b169fd6f AK |
415 | vty_out(vty, |
416 | "Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n"); | |
417 | vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC", | |
418 | "Type", "Flags", "Intf/Remote ES/VTEP", | |
419 | "VLAN", "Seq #'s"); | |
cd233079 | 420 | } else |
87d76d54 | 421 | json_object_int_add(json_evpn, "numMacs", num_macs); |
cd233079 | 422 | } |
1374d4db CS |
423 | |
424 | if (!num_macs) { | |
425 | if (json) { | |
87d76d54 PR |
426 | json_object_int_add(json_evpn, "numMacs", num_macs); |
427 | json_object_object_add(json, vni_str, json_evpn); | |
1374d4db CS |
428 | } |
429 | return; | |
430 | } | |
431 | ||
87d76d54 PR |
432 | /* assign per-evpn to wctx->json object to fill macs |
433 | * under the evpn. Re-assign primary json object to fill | |
434 | * next evpn information. | |
cd233079 CS |
435 | */ |
436 | wctx->json = json_mac; | |
1374d4db | 437 | if (wctx->print_dup) |
b2998086 PR |
438 | hash_iterate(zevpn->mac_table, zebra_evpn_print_dad_mac_hash, |
439 | wctx); | |
1374d4db | 440 | else |
b2998086 | 441 | hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash, wctx); |
cd233079 CS |
442 | wctx->json = json; |
443 | if (json) { | |
444 | if (wctx->count) | |
87d76d54 PR |
445 | json_object_object_add(json_evpn, "macs", json_mac); |
446 | json_object_object_add(json, vni_str, json_evpn); | |
cd233079 | 447 | } |
cec2e17d | 448 | } |
449 | ||
cffe7580 | 450 | /* |
87d76d54 | 451 | * Print MACs in detail for all EVPNs. |
cffe7580 | 452 | */ |
87d76d54 | 453 | static void zevpn_print_mac_hash_all_evpn_detail(struct hash_bucket *bucket, |
cffe7580 NS |
454 | void *ctxt) |
455 | { | |
456 | struct vty *vty; | |
87d76d54 | 457 | json_object *json = NULL, *json_evpn = NULL; |
cffe7580 | 458 | json_object *json_mac = NULL; |
87d76d54 | 459 | zebra_evpn_t *zevpn; |
cffe7580 NS |
460 | uint32_t num_macs; |
461 | struct mac_walk_ctx *wctx = ctxt; | |
462 | char vni_str[VNI_STR_LEN]; | |
463 | ||
c4efd0f4 DA |
464 | vty = wctx->vty; |
465 | json = wctx->json; | |
cffe7580 | 466 | |
87d76d54 PR |
467 | zevpn = (zebra_evpn_t *)bucket->data; |
468 | if (!zevpn) { | |
cffe7580 NS |
469 | if (json) |
470 | vty_out(vty, "{}\n"); | |
471 | return; | |
472 | } | |
87d76d54 | 473 | wctx->zevpn = zevpn; |
cffe7580 | 474 | |
87d76d54 | 475 | /*We are iterating over a new EVPN, set the count to 0*/ |
cffe7580 NS |
476 | wctx->count = 0; |
477 | ||
87d76d54 | 478 | num_macs = num_valid_macs(zevpn); |
cffe7580 NS |
479 | if (!num_macs) |
480 | return; | |
481 | ||
87d76d54 | 482 | if (wctx->print_dup && (num_dup_detected_macs(zevpn) == 0)) |
cffe7580 NS |
483 | return; |
484 | ||
485 | if (json) { | |
87d76d54 | 486 | json_evpn = json_object_new_object(); |
cffe7580 | 487 | json_mac = json_object_new_object(); |
87d76d54 | 488 | snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni); |
cffe7580 NS |
489 | } |
490 | ||
491 | if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) { | |
492 | if (json == NULL) { | |
493 | vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n", | |
87d76d54 | 494 | zevpn->vni, num_macs); |
cffe7580 | 495 | } else |
87d76d54 | 496 | json_object_int_add(json_evpn, "numMacs", num_macs); |
cffe7580 | 497 | } |
87d76d54 PR |
498 | /* assign per-evpn to wctx->json object to fill macs |
499 | * under the evpn. Re-assign primary json object to fill | |
500 | * next evpn information. | |
cffe7580 NS |
501 | */ |
502 | wctx->json = json_mac; | |
503 | if (wctx->print_dup) | |
b2998086 PR |
504 | hash_iterate(zevpn->mac_table, |
505 | zebra_evpn_print_dad_mac_hash_detail, wctx); | |
cffe7580 | 506 | else |
b2998086 PR |
507 | hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash_detail, |
508 | wctx); | |
cffe7580 NS |
509 | wctx->json = json; |
510 | if (json) { | |
511 | if (wctx->count) | |
87d76d54 PR |
512 | json_object_object_add(json_evpn, "macs", json_mac); |
513 | json_object_object_add(json, vni_str, json_evpn); | |
cffe7580 NS |
514 | } |
515 | } | |
516 | ||
e3b78da8 | 517 | static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx) |
b7cfce93 MK |
518 | { |
519 | struct nh_walk_ctx *wctx = NULL; | |
520 | struct vty *vty = NULL; | |
87d76d54 | 521 | struct json_object *json_evpn = NULL; |
b7cfce93 MK |
522 | struct json_object *json_nh = NULL; |
523 | zebra_neigh_t *n = NULL; | |
524 | char buf1[ETHER_ADDR_STRLEN]; | |
2dbad57f | 525 | char buf2[INET6_ADDRSTRLEN]; |
b7cfce93 MK |
526 | |
527 | wctx = (struct nh_walk_ctx *)ctx; | |
528 | vty = wctx->vty; | |
87d76d54 PR |
529 | json_evpn = wctx->json; |
530 | if (json_evpn) | |
b7cfce93 | 531 | json_nh = json_object_new_object(); |
e3b78da8 | 532 | n = (zebra_neigh_t *)bucket->data; |
b7cfce93 | 533 | |
87d76d54 | 534 | if (!json_evpn) { |
4cce389e | 535 | vty_out(vty, "%-15s %-17s\n", |
2dbad57f | 536 | ipaddr2str(&(n->ip), buf2, sizeof(buf2)), |
4cce389e | 537 | prefix_mac2str(&n->emac, buf1, sizeof(buf1))); |
b7cfce93 | 538 | } else { |
4cce389e | 539 | json_object_string_add(json_nh, "nexthopIp", |
32798965 | 540 | ipaddr2str(&n->ip, buf2, sizeof(buf2))); |
996c9314 LB |
541 | json_object_string_add( |
542 | json_nh, "routerMac", | |
543 | prefix_mac2str(&n->emac, buf1, sizeof(buf1))); | |
87d76d54 | 544 | json_object_object_add(json_evpn, |
32798965 MK |
545 | ipaddr2str(&(n->ip), buf2, sizeof(buf2)), |
546 | json_nh); | |
b7cfce93 MK |
547 | } |
548 | } | |
549 | ||
e3b78da8 | 550 | static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket, |
32798965 | 551 | void **args) |
2dbad57f | 552 | { |
553 | struct vty *vty = NULL; | |
554 | json_object *json = NULL; | |
87d76d54 | 555 | json_object *json_evpn = NULL; |
2dbad57f | 556 | zebra_l3vni_t *zl3vni = NULL; |
557 | uint32_t num_nh = 0; | |
32798965 | 558 | struct nh_walk_ctx wctx; |
2dbad57f | 559 | char vni_str[VNI_STR_LEN]; |
560 | ||
32798965 MK |
561 | vty = (struct vty *)args[0]; |
562 | json = (struct json_object *)args[1]; | |
2dbad57f | 563 | |
e3b78da8 | 564 | zl3vni = (zebra_l3vni_t *)bucket->data; |
2dbad57f | 565 | |
566 | num_nh = hashcount(zl3vni->nh_table); | |
567 | if (!num_nh) | |
568 | return; | |
569 | ||
570 | if (json) { | |
87d76d54 PR |
571 | json_evpn = json_object_new_object(); |
572 | snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni); | |
2dbad57f | 573 | } |
574 | ||
575 | if (json == NULL) { | |
996c9314 | 576 | vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", zl3vni->vni, num_nh); |
4cce389e | 577 | vty_out(vty, "%-15s %-17s\n", "IP", "RMAC"); |
2dbad57f | 578 | } else |
87d76d54 | 579 | json_object_int_add(json_evpn, "numNextHops", num_nh); |
2dbad57f | 580 | |
32798965 MK |
581 | memset(&wctx, 0, sizeof(struct nh_walk_ctx)); |
582 | wctx.vty = vty; | |
87d76d54 | 583 | wctx.json = json_evpn; |
32798965 MK |
584 | hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx); |
585 | if (json) | |
87d76d54 | 586 | json_object_object_add(json, vni_str, json_evpn); |
2dbad57f | 587 | } |
588 | ||
e3b78da8 | 589 | static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket, |
c0b4eaa4 | 590 | void **args) |
b7cfce93 MK |
591 | { |
592 | struct vty *vty = NULL; | |
593 | json_object *json = NULL; | |
87d76d54 | 594 | json_object *json_evpn = NULL; |
b7cfce93 | 595 | zebra_l3vni_t *zl3vni = NULL; |
d7c0a89a | 596 | uint32_t num_rmacs; |
c0b4eaa4 | 597 | struct rmac_walk_ctx wctx; |
b7cfce93 MK |
598 | char vni_str[VNI_STR_LEN]; |
599 | ||
c0b4eaa4 MK |
600 | vty = (struct vty *)args[0]; |
601 | json = (struct json_object *)args[1]; | |
b7cfce93 | 602 | |
e3b78da8 | 603 | zl3vni = (zebra_l3vni_t *)bucket->data; |
b7cfce93 MK |
604 | |
605 | num_rmacs = hashcount(zl3vni->rmac_table); | |
606 | if (!num_rmacs) | |
607 | return; | |
608 | ||
609 | if (json) { | |
87d76d54 PR |
610 | json_evpn = json_object_new_object(); |
611 | snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni); | |
b7cfce93 MK |
612 | } |
613 | ||
614 | if (json == NULL) { | |
996c9314 | 615 | vty_out(vty, "\nVNI %u #RMACs %u\n\n", zl3vni->vni, num_rmacs); |
4cce389e | 616 | vty_out(vty, "%-17s %-21s\n", "RMAC", "Remote VTEP"); |
b7cfce93 | 617 | } else |
87d76d54 | 618 | json_object_int_add(json_evpn, "numRmacs", num_rmacs); |
b7cfce93 MK |
619 | |
620 | /* assign per-vni to wctx->json object to fill macs | |
621 | * under the vni. Re-assign primary json object to fill | |
622 | * next vni information. | |
623 | */ | |
c0b4eaa4 MK |
624 | memset(&wctx, 0, sizeof(struct rmac_walk_ctx)); |
625 | wctx.vty = vty; | |
87d76d54 | 626 | wctx.json = json_evpn; |
c0b4eaa4 MK |
627 | hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx); |
628 | if (json) | |
87d76d54 | 629 | json_object_object_add(json, vni_str, json_evpn); |
b7cfce93 MK |
630 | } |
631 | ||
e3b78da8 | 632 | static void zl3vni_print_rmac_hash(struct hash_bucket *bucket, void *ctx) |
b7cfce93 MK |
633 | { |
634 | zebra_mac_t *zrmac = NULL; | |
635 | struct rmac_walk_ctx *wctx = NULL; | |
636 | struct vty *vty = NULL; | |
637 | struct json_object *json = NULL; | |
638 | struct json_object *json_rmac = NULL; | |
9bcef951 | 639 | char buf[PREFIX_STRLEN]; |
b7cfce93 MK |
640 | |
641 | wctx = (struct rmac_walk_ctx *)ctx; | |
642 | vty = wctx->vty; | |
643 | json = wctx->json; | |
644 | if (json) | |
645 | json_rmac = json_object_new_object(); | |
e3b78da8 | 646 | zrmac = (zebra_mac_t *)bucket->data; |
b7cfce93 MK |
647 | |
648 | if (!json) { | |
9bcef951 | 649 | vty_out(vty, "%-17s %-21pI4\n", |
b7cfce93 | 650 | prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), |
9bcef951 | 651 | &zrmac->fwd_info.r_vtep_ip); |
b7cfce93 | 652 | } else { |
996c9314 LB |
653 | json_object_string_add( |
654 | json_rmac, "routerMac", | |
655 | prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf))); | |
4cce389e | 656 | json_object_string_add(json_rmac, "vtepIp", |
9bcef951 MS |
657 | inet_ntop(AF_INET, |
658 | &zrmac->fwd_info.r_vtep_ip, | |
659 | buf, sizeof(buf))); | |
996c9314 LB |
660 | json_object_object_add( |
661 | json, prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), | |
662 | json_rmac); | |
b7cfce93 MK |
663 | } |
664 | } | |
665 | ||
666 | /* print a specific L3 VNI entry */ | |
667 | static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx) | |
668 | { | |
9bcef951 | 669 | char buf[PREFIX_STRLEN]; |
b7cfce93 MK |
670 | struct vty *vty = NULL; |
671 | json_object *json = NULL; | |
87d76d54 PR |
672 | zebra_evpn_t *zevpn = NULL; |
673 | json_object *json_evpn_list = NULL; | |
b7cfce93 MK |
674 | struct listnode *node = NULL, *nnode = NULL; |
675 | ||
676 | vty = ctx[0]; | |
677 | json = ctx[1]; | |
678 | ||
679 | if (!json) { | |
680 | vty_out(vty, "VNI: %u\n", zl3vni->vni); | |
4cce389e | 681 | vty_out(vty, " Type: %s\n", "L3"); |
996c9314 | 682 | vty_out(vty, " Tenant VRF: %s\n", zl3vni_vrf_name(zl3vni)); |
9bcef951 MS |
683 | vty_out(vty, " Local Vtep Ip: %pI4\n", |
684 | &zl3vni->local_vtep_ip); | |
b7cfce93 MK |
685 | vty_out(vty, " Vxlan-Intf: %s\n", |
686 | zl3vni_vxlan_if_name(zl3vni)); | |
996c9314 LB |
687 | vty_out(vty, " SVI-If: %s\n", zl3vni_svi_if_name(zl3vni)); |
688 | vty_out(vty, " State: %s\n", zl3vni_state2str(zl3vni)); | |
c48d9f5f | 689 | vty_out(vty, " VNI Filter: %s\n", |
996c9314 LB |
690 | CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) |
691 | ? "prefix-routes-only" | |
692 | : "none"); | |
28ad0501 CS |
693 | vty_out(vty, " System MAC: %s\n", |
694 | zl3vni_sysmac2str(zl3vni, buf, sizeof(buf))); | |
4cce389e | 695 | vty_out(vty, " Router MAC: %s\n", |
b7cfce93 | 696 | zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); |
4cce389e | 697 | vty_out(vty, " L2 VNIs: "); |
87d76d54 PR |
698 | for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zevpn)) |
699 | vty_out(vty, "%u ", zevpn->vni); | |
b7cfce93 MK |
700 | vty_out(vty, "\n"); |
701 | } else { | |
87d76d54 | 702 | json_evpn_list = json_object_new_array(); |
b7cfce93 | 703 | json_object_int_add(json, "vni", zl3vni->vni); |
4cce389e | 704 | json_object_string_add(json, "type", "L3"); |
9bcef951 MS |
705 | json_object_string_add( |
706 | json, "localVtepIp", | |
707 | inet_ntop(AF_INET, &zl3vni->local_vtep_ip, buf, | |
708 | sizeof(buf))); | |
4cce389e | 709 | json_object_string_add(json, "vxlanIntf", |
b7cfce93 | 710 | zl3vni_vxlan_if_name(zl3vni)); |
4cce389e | 711 | json_object_string_add(json, "sviIntf", |
b7cfce93 | 712 | zl3vni_svi_if_name(zl3vni)); |
996c9314 LB |
713 | json_object_string_add(json, "state", zl3vni_state2str(zl3vni)); |
714 | json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni)); | |
28ad0501 CS |
715 | json_object_string_add( |
716 | json, "sysMac", | |
717 | zl3vni_sysmac2str(zl3vni, buf, sizeof(buf))); | |
996c9314 LB |
718 | json_object_string_add( |
719 | json, "routerMac", | |
720 | zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); | |
721 | json_object_string_add( | |
722 | json, "vniFilter", | |
723 | CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) | |
724 | ? "prefix-routes-only" | |
725 | : "none"); | |
87d76d54 PR |
726 | for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zevpn)) { |
727 | json_object_array_add(json_evpn_list, | |
728 | json_object_new_int(zevpn->vni)); | |
b7cfce93 | 729 | } |
87d76d54 | 730 | json_object_object_add(json, "l2Vnis", json_evpn_list); |
b7cfce93 MK |
731 | } |
732 | } | |
733 | ||
b7cfce93 | 734 | /* print a L3 VNI hash entry */ |
e3b78da8 | 735 | static void zl3vni_print_hash(struct hash_bucket *bucket, void *ctx[]) |
b7cfce93 | 736 | { |
b7cfce93 MK |
737 | struct vty *vty = NULL; |
738 | json_object *json = NULL; | |
87d76d54 | 739 | json_object *json_evpn = NULL; |
b7cfce93 MK |
740 | zebra_l3vni_t *zl3vni = NULL; |
741 | ||
51d8de8f MK |
742 | vty = (struct vty *)ctx[0]; |
743 | json = (json_object *)ctx[1]; | |
b7cfce93 | 744 | |
e3b78da8 | 745 | zl3vni = (zebra_l3vni_t *)bucket->data; |
b7cfce93 MK |
746 | |
747 | if (!json) { | |
996c9314 LB |
748 | vty_out(vty, "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n", |
749 | zl3vni->vni, "L3", zl3vni_vxlan_if_name(zl3vni), | |
4cce389e | 750 | hashcount(zl3vni->rmac_table), |
996c9314 | 751 | hashcount(zl3vni->nh_table), "n/a", |
4cce389e | 752 | zl3vni_vrf_name(zl3vni)); |
b7cfce93 | 753 | } else { |
51d8de8f MK |
754 | char vni_str[VNI_STR_LEN]; |
755 | ||
87d76d54 PR |
756 | snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni); |
757 | json_evpn = json_object_new_object(); | |
758 | json_object_int_add(json_evpn, "vni", zl3vni->vni); | |
759 | json_object_string_add(json_evpn, "vxlanIf", | |
b7cfce93 | 760 | zl3vni_vxlan_if_name(zl3vni)); |
87d76d54 | 761 | json_object_int_add(json_evpn, "numMacs", |
4cce389e | 762 | hashcount(zl3vni->rmac_table)); |
87d76d54 | 763 | json_object_int_add(json_evpn, "numArpNd", |
4cce389e | 764 | hashcount(zl3vni->nh_table)); |
87d76d54 PR |
765 | json_object_string_add(json_evpn, "numRemoteVteps", "n/a"); |
766 | json_object_string_add(json_evpn, "type", "L3"); | |
767 | json_object_string_add(json_evpn, "tenantVrf", | |
b7cfce93 | 768 | zl3vni_vrf_name(zl3vni)); |
87d76d54 | 769 | json_object_object_add(json, vni_str, json_evpn); |
b7cfce93 | 770 | } |
b7cfce93 MK |
771 | } |
772 | ||
09af6961 | 773 | /* print a L3 VNI hash entry in detail*/ |
e3b78da8 | 774 | static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data) |
09af6961 NS |
775 | { |
776 | struct vty *vty = NULL; | |
777 | zebra_l3vni_t *zl3vni = NULL; | |
06931fdb | 778 | json_object *json_array = NULL; |
09af6961 | 779 | bool use_json = false; |
8b5fdf2e | 780 | struct zebra_evpn_show *zes = data; |
09af6961 NS |
781 | |
782 | vty = zes->vty; | |
06931fdb LK |
783 | json_array = zes->json; |
784 | use_json = zes->use_json; | |
09af6961 | 785 | |
e3b78da8 | 786 | zl3vni = (zebra_l3vni_t *)bucket->data; |
09af6961 | 787 | |
06931fdb LK |
788 | zebra_vxlan_print_vni(vty, zes->zvrf, zl3vni->vni, |
789 | use_json, json_array); | |
790 | ||
791 | if (!use_json) | |
792 | vty_out(vty, "\n"); | |
09af6961 NS |
793 | } |
794 | ||
2961d060 | 795 | static int zvni_map_to_svi_ns(struct ns *ns, |
a237058f PG |
796 | void *_in_param, |
797 | void **_p_ifp) | |
798 | { | |
2961d060 | 799 | struct zebra_ns *zns = ns->info; |
a237058f PG |
800 | struct route_node *rn; |
801 | struct zebra_from_svi_param *in_param = | |
802 | (struct zebra_from_svi_param *)_in_param; | |
803 | struct zebra_l2info_vlan *vl; | |
804 | struct interface *tmp_if = NULL; | |
805 | struct interface **p_ifp = (struct interface **)_p_ifp; | |
806 | struct zebra_if *zif; | |
807 | ||
808 | if (!in_param) | |
2961d060 | 809 | return NS_WALK_STOP; |
a237058f PG |
810 | |
811 | /* TODO: Optimize with a hash. */ | |
812 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { | |
813 | tmp_if = (struct interface *)rn->info; | |
814 | /* Check oper status of the SVI. */ | |
815 | if (!tmp_if || !if_is_operative(tmp_if)) | |
816 | continue; | |
817 | zif = tmp_if->info; | |
818 | if (!zif || zif->zif_type != ZEBRA_IF_VLAN | |
819 | || zif->link != in_param->br_if) | |
820 | continue; | |
821 | vl = (struct zebra_l2info_vlan *)&zif->l2info.vl; | |
822 | ||
823 | if (vl->vid == in_param->vid) { | |
824 | if (p_ifp) | |
825 | *p_ifp = tmp_if; | |
2961d060 | 826 | return NS_WALK_STOP; |
a237058f PG |
827 | } |
828 | } | |
2961d060 | 829 | return NS_WALK_CONTINUE; |
a237058f PG |
830 | } |
831 | ||
8b5fdf2e PR |
832 | /* Map to SVI on bridge corresponding to specified VLAN. This can be one |
833 | * of two cases: | |
834 | * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface | |
835 | * linked to the bridge | |
836 | * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge interface | |
837 | * itself | |
09af6961 | 838 | */ |
8b5fdf2e | 839 | struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if) |
13d60d35 | 840 | { |
7cbae20a | 841 | struct interface *tmp_if = NULL; |
8b5fdf2e PR |
842 | struct zebra_if *zif; |
843 | struct zebra_l2info_bridge *br; | |
a237058f PG |
844 | struct zebra_from_svi_param in_param; |
845 | struct interface **p_ifp; | |
8b5fdf2e PR |
846 | /* Defensive check, caller expected to invoke only with valid bridge. */ |
847 | if (!br_if) | |
848 | return NULL; | |
1a98c087 | 849 | |
8b5fdf2e PR |
850 | /* Determine if bridge is VLAN-aware or not */ |
851 | zif = br_if->info; | |
852 | assert(zif); | |
853 | br = &zif->l2info.br; | |
a237058f | 854 | in_param.bridge_vlan_aware = br->vlan_aware; |
8b5fdf2e | 855 | /* Check oper status of the SVI. */ |
a237058f | 856 | if (!in_param.bridge_vlan_aware) |
8b5fdf2e | 857 | return if_is_operative(br_if) ? br_if : NULL; |
d62a17ae | 858 | |
a237058f PG |
859 | in_param.vid = vid; |
860 | in_param.br_if = br_if; | |
861 | in_param.zif = NULL; | |
862 | p_ifp = &tmp_if; | |
bf69e212 | 863 | /* Identify corresponding VLAN interface. */ |
2961d060 PG |
864 | ns_walk_func(zvni_map_to_svi_ns, (void *)&in_param, |
865 | (void **)p_ifp); | |
a237058f | 866 | return tmp_if; |
8b5fdf2e | 867 | } |
2232a77c | 868 | |
8b5fdf2e PR |
869 | static int zebra_evpn_vxlan_del(zebra_evpn_t *zevpn) |
870 | { | |
871 | zevpn_vxlan_if_set(zevpn, zevpn->vxlan_if, false /* set */); | |
2232a77c | 872 | |
8b5fdf2e PR |
873 | /* Remove references to the BUM mcast grp */ |
874 | zebra_vxlan_sg_deref(zevpn->local_vtep_ip, zevpn->mcast_grp); | |
2232a77c | 875 | |
8b5fdf2e | 876 | return zebra_evpn_del(zevpn); |
2232a77c | 877 | } |
07509878 | 878 | |
2961d060 | 879 | static int zevpn_build_hash_table_zns(struct ns *ns, |
07509878 PG |
880 | void *param_in __attribute__((unused)), |
881 | void **param_out __attribute__((unused))) | |
2232a77c | 882 | { |
2961d060 | 883 | struct zebra_ns *zns = ns->info; |
2853fed6 | 884 | struct route_node *rn; |
d62a17ae | 885 | struct interface *ifp; |
07509878 PG |
886 | struct zebra_vrf *zvrf; |
887 | ||
888 | zvrf = zebra_vrf_get_evpn(); | |
889 | ||
890 | if (!zvrf) | |
2961d060 | 891 | return NS_WALK_STOP; |
2232a77c | 892 | |
87d76d54 | 893 | /* Walk VxLAN interfaces and create EVPN hash. */ |
2853fed6 | 894 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { |
b7cfce93 | 895 | vni_t vni; |
87d76d54 | 896 | zebra_evpn_t *zevpn = NULL; |
643215ce | 897 | zebra_l3vni_t *zl3vni = NULL; |
d62a17ae | 898 | struct zebra_if *zif; |
899 | struct zebra_l2info_vxlan *vxl; | |
2232a77c | 900 | |
2853fed6 | 901 | ifp = (struct interface *)rn->info; |
902 | if (!ifp) | |
903 | continue; | |
d62a17ae | 904 | zif = ifp->info; |
905 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
906 | continue; | |
2232a77c | 907 | |
b7cfce93 | 908 | vxl = &zif->l2info.vxl; |
d62a17ae | 909 | vni = vxl->vni; |
07509878 PG |
910 | /* link of VXLAN interface should be in zebra_evpn_vrf */ |
911 | if (zvrf->zns->ns_id != vxl->link_nsid) { | |
912 | if (IS_ZEBRA_DEBUG_VXLAN) | |
913 | zlog_debug( | |
914 | "Intf %s(%u) VNI %u, link not in same " | |
915 | "namespace than BGP EVPN core instance ", | |
916 | ifp->name, ifp->ifindex, vni); | |
917 | continue; | |
918 | } | |
643215ce | 919 | /* L3-VNI and L2-VNI are handled seperately */ |
920 | zl3vni = zl3vni_lookup(vni); | |
921 | if (zl3vni) { | |
2232a77c | 922 | |
b7cfce93 | 923 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
924 | zlog_debug( |
925 | "create L3-VNI hash for Intf %s(%u) L3-VNI %u", | |
926 | ifp->name, ifp->ifindex, vni); | |
2232a77c | 927 | |
b7cfce93 | 928 | /* associate with vxlan_if */ |
b67a60d2 | 929 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
b7cfce93 | 930 | zl3vni->vxlan_if = ifp; |
2232a77c | 931 | |
523cafc4 | 932 | /* |
933 | * we need to associate with SVI. | |
b7cfce93 | 934 | * we can associate with svi-if only after association |
523cafc4 | 935 | * with vxlan-intf is complete |
936 | */ | |
b7cfce93 MK |
937 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); |
938 | ||
06d9cde5 CS |
939 | /* Associate l3vni to mac-vlan and extract VRR MAC */ |
940 | zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); | |
941 | ||
942 | if (IS_ZEBRA_DEBUG_VXLAN) | |
943 | zlog_debug("create l3vni %u svi_if %s mac_vlan_if %s", | |
944 | vni, zl3vni->svi_if ? zl3vni->svi_if->name | |
945 | : "NIL", | |
946 | zl3vni->mac_vlan_if ? | |
947 | zl3vni->mac_vlan_if->name : "NIL"); | |
948 | ||
b7cfce93 MK |
949 | if (is_l3vni_oper_up(zl3vni)) |
950 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
951 | ||
952 | } else { | |
b7cfce93 MK |
953 | struct interface *vlan_if = NULL; |
954 | ||
955 | if (IS_ZEBRA_DEBUG_VXLAN) | |
956 | zlog_debug( | |
9bcef951 | 957 | "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %pI4", |
b7cfce93 | 958 | ifp->name, ifp->ifindex, vni, |
9bcef951 | 959 | &vxl->vtep_ip); |
b7cfce93 | 960 | |
87d76d54 | 961 | /* EVPN hash entry is expected to exist, if the BGP process is killed */ |
8b5fdf2e | 962 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 963 | if (zevpn) { |
9df414fe | 964 | zlog_debug( |
87d76d54 | 965 | "EVPN hash already present for IF %s(%u) L2-VNI %u", |
b7cfce93 | 966 | ifp->name, ifp->ifindex, vni); |
b7cfce93 | 967 | |
27627f9a KA |
968 | /* |
969 | * Inform BGP if intf is up and mapped to | |
970 | * bridge. | |
971 | */ | |
972 | if (if_is_operative(ifp) && | |
973 | zif->brslave_info.br_if) | |
8b5fdf2e | 974 | zebra_evpn_send_add_to_client(zevpn); |
b7cfce93 | 975 | |
27627f9a | 976 | /* Send Local MAC-entries to client */ |
b2998086 | 977 | zebra_evpn_send_mac_list_to_client(zevpn); |
27627f9a KA |
978 | |
979 | /* Send Loval Neighbor entries to client */ | |
7cbae20a | 980 | zebra_evpn_send_neigh_to_client(zevpn); |
27627f9a | 981 | } else { |
8b5fdf2e | 982 | zevpn = zebra_evpn_add(vni); |
87d76d54 | 983 | if (!zevpn) { |
27627f9a | 984 | zlog_debug( |
87d76d54 | 985 | "Failed to add EVPN hash, IF %s(%u) L2-VNI %u", |
27627f9a | 986 | ifp->name, ifp->ifindex, vni); |
2961d060 | 987 | return NS_WALK_CONTINUE; |
27627f9a | 988 | } |
b7cfce93 | 989 | |
87d76d54 | 990 | if (zevpn->local_vtep_ip.s_addr != |
27627f9a | 991 | vxl->vtep_ip.s_addr || |
87d76d54 | 992 | zevpn->mcast_grp.s_addr != |
27627f9a KA |
993 | vxl->mcast_grp.s_addr) { |
994 | zebra_vxlan_sg_deref( | |
87d76d54 PR |
995 | zevpn->local_vtep_ip, |
996 | zevpn->mcast_grp); | |
27627f9a KA |
997 | zebra_vxlan_sg_ref(vxl->vtep_ip, |
998 | vxl->mcast_grp); | |
87d76d54 PR |
999 | zevpn->local_vtep_ip = vxl->vtep_ip; |
1000 | zevpn->mcast_grp = vxl->mcast_grp; | |
ce5160c0 AK |
1001 | /* on local vtep-ip check if ES |
1002 | * orig-ip needs to be updated | |
1003 | */ | |
87d76d54 | 1004 | zebra_evpn_es_set_base_evpn(zevpn); |
27627f9a | 1005 | } |
87d76d54 | 1006 | zevpn_vxlan_if_set(zevpn, ifp, true /* set */); |
7cbae20a PR |
1007 | vlan_if = zvni_map_to_svi( |
1008 | vxl->access_vlan, | |
1009 | zif->brslave_info.br_if); | |
27627f9a | 1010 | if (vlan_if) { |
87d76d54 | 1011 | zevpn->vrf_id = vlan_if->vrf_id; |
27627f9a KA |
1012 | zl3vni = zl3vni_from_vrf( |
1013 | vlan_if->vrf_id); | |
1014 | if (zl3vni) | |
1015 | listnode_add_sort( | |
87d76d54 | 1016 | zl3vni->l2vnis, zevpn); |
27627f9a | 1017 | } |
b7cfce93 | 1018 | |
27627f9a KA |
1019 | /* |
1020 | * Inform BGP if intf is up and mapped to | |
1021 | * bridge. | |
1022 | */ | |
1023 | if (if_is_operative(ifp) && | |
1024 | zif->brslave_info.br_if) | |
8b5fdf2e | 1025 | zebra_evpn_send_add_to_client(zevpn); |
27627f9a | 1026 | } |
b7cfce93 | 1027 | } |
d62a17ae | 1028 | } |
2961d060 | 1029 | return NS_WALK_CONTINUE; |
07509878 PG |
1030 | } |
1031 | ||
1032 | /* | |
1033 | * Build the VNI hash table by going over the VxLAN interfaces. This | |
1034 | * is called when EVPN (advertise-all-vni) is enabled. | |
1035 | */ | |
1036 | ||
1037 | static void zevpn_build_hash_table(void) | |
1038 | { | |
2961d060 PG |
1039 | ns_walk_func(zevpn_build_hash_table_zns, |
1040 | (void *)NULL, | |
1041 | (void **)NULL); | |
2232a77c | 1042 | } |
1043 | ||
2232a77c | 1044 | /* |
87d76d54 | 1045 | * Cleanup EVPN/VTEP and update kernel |
2232a77c | 1046 | */ |
8b5fdf2e | 1047 | static void zebra_evpn_vxlan_cleanup_all(struct hash_bucket *bucket, void *arg) |
2232a77c | 1048 | { |
87d76d54 | 1049 | zebra_evpn_t *zevpn = NULL; |
b7cfce93 | 1050 | zebra_l3vni_t *zl3vni = NULL; |
84915b0a | 1051 | struct zebra_vrf *zvrf = (struct zebra_vrf *)arg; |
2232a77c | 1052 | |
87d76d54 | 1053 | zevpn = (zebra_evpn_t *)bucket->data; |
2232a77c | 1054 | |
b7cfce93 | 1055 | /* remove from l3-vni list */ |
84915b0a | 1056 | if (zvrf->l3vni) |
1057 | zl3vni = zl3vni_lookup(zvrf->l3vni); | |
b7cfce93 | 1058 | if (zl3vni) |
87d76d54 | 1059 | listnode_delete(zl3vni->l2vnis, zevpn); |
b7cfce93 | 1060 | |
8b5fdf2e | 1061 | zebra_evpn_cleanup_all(bucket, arg); |
2232a77c | 1062 | } |
1063 | ||
655b04d1 | 1064 | /* cleanup L3VNI */ |
e3b78da8 | 1065 | static void zl3vni_cleanup_all(struct hash_bucket *bucket, void *args) |
655b04d1 MK |
1066 | { |
1067 | zebra_l3vni_t *zl3vni = NULL; | |
1068 | ||
e3b78da8 | 1069 | zl3vni = (zebra_l3vni_t *)bucket->data; |
655b04d1 MK |
1070 | |
1071 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
1072 | } | |
1073 | ||
85442b09 | 1074 | static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe, |
e4a1ec74 | 1075 | const struct prefix *host) |
5e1b0650 DS |
1076 | { |
1077 | struct host_rb_entry lookup; | |
1078 | struct host_rb_entry *hle; | |
1079 | ||
1080 | memset(&lookup, 0, sizeof(lookup)); | |
1081 | memcpy(&lookup.p, host, sizeof(*host)); | |
1082 | ||
85442b09 | 1083 | hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup); |
5e1b0650 DS |
1084 | if (hle) |
1085 | return; | |
1086 | ||
1087 | hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry)); | |
1088 | memcpy(hle, &lookup, sizeof(lookup)); | |
1089 | ||
85442b09 | 1090 | RB_INSERT(host_rb_tree_entry, hrbe, hle); |
5e1b0650 DS |
1091 | } |
1092 | ||
85442b09 | 1093 | static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host) |
5e1b0650 DS |
1094 | { |
1095 | struct host_rb_entry lookup; | |
1096 | struct host_rb_entry *hle; | |
1097 | ||
1098 | memset(&lookup, 0, sizeof(lookup)); | |
1099 | memcpy(&lookup.p, host, sizeof(*host)); | |
1100 | ||
85442b09 | 1101 | hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup); |
10ac2516 | 1102 | if (hle) { |
85442b09 | 1103 | RB_REMOVE(host_rb_tree_entry, hrbe, hle); |
10ac2516 DS |
1104 | XFREE(MTYPE_HOST_PREFIX, hle); |
1105 | } | |
5e1b0650 DS |
1106 | |
1107 | return; | |
1108 | } | |
1109 | ||
b7cfce93 MK |
1110 | /* |
1111 | * Look up MAC hash entry. | |
1112 | */ | |
2dbad57f | 1113 | static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, |
e4a1ec74 | 1114 | const struct ethaddr *rmac) |
b7cfce93 MK |
1115 | { |
1116 | zebra_mac_t tmp; | |
1117 | zebra_mac_t *pmac; | |
1118 | ||
1119 | memset(&tmp, 0, sizeof(tmp)); | |
1120 | memcpy(&tmp.macaddr, rmac, ETH_ALEN); | |
1121 | pmac = hash_lookup(zl3vni->rmac_table, &tmp); | |
2232a77c | 1122 | |
b7cfce93 | 1123 | return pmac; |
2dbad57f | 1124 | } |
2232a77c | 1125 | |
cec2e17d | 1126 | /* |
b7cfce93 | 1127 | * Callback to allocate RMAC hash entry. |
cec2e17d | 1128 | */ |
2dbad57f | 1129 | static void *zl3vni_rmac_alloc(void *p) |
d62a17ae | 1130 | { |
b7cfce93 MK |
1131 | const zebra_mac_t *tmp_rmac = p; |
1132 | zebra_mac_t *zrmac; | |
d62a17ae | 1133 | |
b2998086 | 1134 | zrmac = XCALLOC(MTYPE_L3VNI_MAC, sizeof(zebra_mac_t)); |
b7cfce93 | 1135 | *zrmac = *tmp_rmac; |
d62a17ae | 1136 | |
b7cfce93 | 1137 | return ((void *)zrmac); |
2dbad57f | 1138 | } |
cd233079 | 1139 | |
b7cfce93 MK |
1140 | /* |
1141 | * Add RMAC entry to l3-vni | |
1142 | */ | |
e4a1ec74 MS |
1143 | static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, |
1144 | const struct ethaddr *rmac) | |
b7cfce93 MK |
1145 | { |
1146 | zebra_mac_t tmp_rmac; | |
1147 | zebra_mac_t *zrmac = NULL; | |
d62a17ae | 1148 | |
b7cfce93 MK |
1149 | memset(&tmp_rmac, 0, sizeof(zebra_mac_t)); |
1150 | memcpy(&tmp_rmac.macaddr, rmac, ETH_ALEN); | |
1151 | zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc); | |
1152 | assert(zrmac); | |
d62a17ae | 1153 | |
85442b09 | 1154 | RB_INIT(host_rb_tree_entry, &zrmac->host_rb); |
b7cfce93 | 1155 | |
2dbad57f | 1156 | SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE); |
1157 | SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC); | |
1158 | ||
b7cfce93 | 1159 | return zrmac; |
2dbad57f | 1160 | } |
cec2e17d | 1161 | |
1162 | /* | |
b7cfce93 | 1163 | * Delete MAC entry. |
cec2e17d | 1164 | */ |
996c9314 | 1165 | static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) |
cec2e17d | 1166 | { |
b7cfce93 | 1167 | zebra_mac_t *tmp_rmac; |
5e1b0650 | 1168 | struct host_rb_entry *hle; |
cd233079 | 1169 | |
85442b09 DS |
1170 | while (!RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) { |
1171 | hle = RB_ROOT(host_rb_tree_entry, &zrmac->host_rb); | |
5e1b0650 | 1172 | |
85442b09 | 1173 | RB_REMOVE(host_rb_tree_entry, &zrmac->host_rb, hle); |
5e1b0650 DS |
1174 | XFREE(MTYPE_HOST_PREFIX, hle); |
1175 | } | |
cd233079 | 1176 | |
b7cfce93 | 1177 | tmp_rmac = hash_release(zl3vni->rmac_table, zrmac); |
b2998086 | 1178 | XFREE(MTYPE_L3VNI_MAC, tmp_rmac); |
cd233079 | 1179 | |
b7cfce93 | 1180 | return 0; |
2dbad57f | 1181 | } |
cec2e17d | 1182 | |
1183 | /* | |
036d93c0 | 1184 | * Install remote RMAC into the forwarding plane. |
cec2e17d | 1185 | */ |
996c9314 | 1186 | static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) |
cec2e17d | 1187 | { |
478566d6 MS |
1188 | const struct zebra_if *zif = NULL, *br_zif = NULL; |
1189 | const struct zebra_l2info_vxlan *vxl = NULL; | |
1190 | const struct interface *br_ifp; | |
036d93c0 | 1191 | enum zebra_dplane_result res; |
478566d6 | 1192 | vlanid_t vid; |
cec2e17d | 1193 | |
996c9314 LB |
1194 | if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) |
1195 | || !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) | |
b7cfce93 MK |
1196 | return 0; |
1197 | ||
1198 | zif = zl3vni->vxlan_if->info; | |
1199 | if (!zif) | |
1200 | return -1; | |
1201 | ||
478566d6 MS |
1202 | br_ifp = zif->brslave_info.br_if; |
1203 | if (br_ifp == NULL) | |
1204 | return -1; | |
1205 | ||
b7cfce93 MK |
1206 | vxl = &zif->l2info.vxl; |
1207 | ||
478566d6 MS |
1208 | br_zif = (const struct zebra_if *)br_ifp->info; |
1209 | ||
1210 | if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) | |
1211 | vid = vxl->access_vlan; | |
1212 | else | |
1213 | vid = 0; | |
1214 | ||
f188e68e AK |
1215 | res = dplane_rem_mac_add(zl3vni->vxlan_if, br_ifp, vid, |
1216 | &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0, 0, | |
1217 | false /*was_static*/); | |
036d93c0 MS |
1218 | if (res != ZEBRA_DPLANE_REQUEST_FAILURE) |
1219 | return 0; | |
1220 | else | |
1221 | return -1; | |
2dbad57f | 1222 | } |
b7cfce93 MK |
1223 | |
1224 | /* | |
036d93c0 | 1225 | * Uninstall remote RMAC from the forwarding plane. |
b7cfce93 | 1226 | */ |
996c9314 | 1227 | static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) |
b7cfce93 MK |
1228 | { |
1229 | char buf[ETHER_ADDR_STRLEN]; | |
478566d6 MS |
1230 | const struct zebra_if *zif = NULL, *br_zif; |
1231 | const struct zebra_l2info_vxlan *vxl = NULL; | |
1232 | const struct interface *br_ifp; | |
1233 | vlanid_t vid; | |
036d93c0 | 1234 | enum zebra_dplane_result res; |
b7cfce93 | 1235 | |
996c9314 LB |
1236 | if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) |
1237 | || !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) | |
b7cfce93 MK |
1238 | return 0; |
1239 | ||
1240 | if (!zl3vni->vxlan_if) { | |
e0e140a7 MS |
1241 | if (IS_ZEBRA_DEBUG_VXLAN) |
1242 | zlog_debug( | |
1243 | "RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if", | |
1244 | prefix_mac2str(&zrmac->macaddr, | |
1245 | buf, sizeof(buf)), | |
1246 | zl3vni->vni, zl3vni); | |
b7cfce93 MK |
1247 | return -1; |
1248 | } | |
1249 | ||
1250 | zif = zl3vni->vxlan_if->info; | |
1251 | if (!zif) | |
1252 | return -1; | |
1253 | ||
478566d6 MS |
1254 | br_ifp = zif->brslave_info.br_if; |
1255 | if (br_ifp == NULL) | |
1256 | return -1; | |
1257 | ||
b7cfce93 MK |
1258 | vxl = &zif->l2info.vxl; |
1259 | ||
478566d6 MS |
1260 | br_zif = (const struct zebra_if *)br_ifp->info; |
1261 | if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) | |
1262 | vid = vxl->access_vlan; | |
1263 | else | |
1264 | vid = 0; | |
1265 | ||
f188e68e | 1266 | res = dplane_rem_mac_del(zl3vni->vxlan_if, br_ifp, vid, |
036d93c0 MS |
1267 | &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip); |
1268 | if (res != ZEBRA_DPLANE_REQUEST_FAILURE) | |
1269 | return 0; | |
1270 | else | |
1271 | return -1; | |
2dbad57f | 1272 | } |
1273 | ||
1274 | /* handle rmac add */ | |
e4a1ec74 MS |
1275 | static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, |
1276 | const struct ethaddr *rmac, | |
1277 | const struct ipaddr *vtep_ip, | |
1278 | const struct prefix *host_prefix) | |
2dbad57f | 1279 | { |
1280 | char buf[ETHER_ADDR_STRLEN]; | |
1281 | char buf1[INET6_ADDRSTRLEN]; | |
1282 | zebra_mac_t *zrmac = NULL; | |
1283 | ||
1284 | zrmac = zl3vni_rmac_lookup(zl3vni, rmac); | |
1285 | if (!zrmac) { | |
1286 | ||
651fa905 | 1287 | /* Create the RMAC entry, or update its vtep, if necessary. */ |
2dbad57f | 1288 | zrmac = zl3vni_rmac_add(zl3vni, rmac); |
1289 | if (!zrmac) { | |
9df414fe | 1290 | zlog_debug( |
2dbe669b | 1291 | "Failed to add RMAC %s L3VNI %u Remote VTEP %s, prefix %pFX", |
996c9314 LB |
1292 | prefix_mac2str(rmac, buf, sizeof(buf)), |
1293 | zl3vni->vni, | |
651fa905 | 1294 | ipaddr2str(vtep_ip, buf1, sizeof(buf1)), |
2dbe669b | 1295 | host_prefix); |
2dbad57f | 1296 | return -1; |
1297 | } | |
1298 | memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); | |
1299 | zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; | |
1300 | ||
a780a738 AD |
1301 | /* Send RMAC for FPM processing */ |
1302 | hook_call(zebra_rmac_update, zrmac, zl3vni, false, | |
1303 | "new RMAC added"); | |
1304 | ||
651fa905 CS |
1305 | /* install rmac in kernel */ |
1306 | zl3vni_rmac_install(zl3vni, zrmac); | |
1307 | } else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, | |
1308 | &vtep_ip->ipaddr_v4)) { | |
1309 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1310 | zlog_debug( | |
9bcef951 | 1311 | "L3VNI %u Remote VTEP change(%pI4 -> %s) for RMAC %s, prefix %pFX", |
651fa905 | 1312 | zl3vni->vni, |
9bcef951 | 1313 | &zrmac->fwd_info.r_vtep_ip, |
651fa905 CS |
1314 | ipaddr2str(vtep_ip, buf1, sizeof(buf1)), |
1315 | prefix_mac2str(rmac, buf, sizeof(buf)), | |
2dbe669b | 1316 | host_prefix); |
651fa905 CS |
1317 | |
1318 | zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; | |
1319 | ||
2dbad57f | 1320 | /* install rmac in kernel */ |
1321 | zl3vni_rmac_install(zl3vni, zrmac); | |
1322 | } | |
6134fd82 | 1323 | |
41db76c2 | 1324 | rb_find_or_add_host(&zrmac->host_rb, host_prefix); |
5e1b0650 | 1325 | |
2dbad57f | 1326 | return 0; |
1327 | } | |
1328 | ||
1329 | ||
1330 | /* handle rmac delete */ | |
22e63104 | 1331 | static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac, |
6134fd82 | 1332 | struct prefix *host_prefix) |
2dbad57f | 1333 | { |
41db76c2 | 1334 | rb_delete_host(&zrmac->host_rb, host_prefix); |
2dbad57f | 1335 | |
85442b09 | 1336 | if (RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) { |
2dbad57f | 1337 | /* uninstall from kernel */ |
1338 | zl3vni_rmac_uninstall(zl3vni, zrmac); | |
1339 | ||
a780a738 AD |
1340 | /* Send RMAC for FPM processing */ |
1341 | hook_call(zebra_rmac_update, zrmac, zl3vni, true, | |
1342 | "RMAC deleted"); | |
1343 | ||
2dbad57f | 1344 | /* del the rmac entry */ |
1345 | zl3vni_rmac_del(zl3vni, zrmac); | |
1346 | } | |
2dbad57f | 1347 | } |
b7cfce93 MK |
1348 | |
1349 | /* | |
1350 | * Look up nh hash entry on a l3-vni. | |
1351 | */ | |
e4a1ec74 MS |
1352 | static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, |
1353 | const struct ipaddr *ip) | |
b7cfce93 MK |
1354 | { |
1355 | zebra_neigh_t tmp; | |
1356 | zebra_neigh_t *n; | |
1357 | ||
1358 | memset(&tmp, 0, sizeof(tmp)); | |
1359 | memcpy(&tmp.ip, ip, sizeof(struct ipaddr)); | |
1360 | n = hash_lookup(zl3vni->nh_table, &tmp); | |
1361 | ||
1362 | return n; | |
2dbad57f | 1363 | } |
b7cfce93 MK |
1364 | |
1365 | ||
1366 | /* | |
1367 | * Callback to allocate NH hash entry on L3-VNI. | |
1368 | */ | |
2dbad57f | 1369 | static void *zl3vni_nh_alloc(void *p) |
b7cfce93 MK |
1370 | { |
1371 | const zebra_neigh_t *tmp_n = p; | |
1372 | zebra_neigh_t *n; | |
1373 | ||
7cbae20a | 1374 | n = XCALLOC(MTYPE_L3NEIGH, sizeof(zebra_neigh_t)); |
b7cfce93 MK |
1375 | *n = *tmp_n; |
1376 | ||
1377 | return ((void *)n); | |
2dbad57f | 1378 | } |
b7cfce93 MK |
1379 | |
1380 | /* | |
1381 | * Add neighbor entry. | |
1382 | */ | |
e4a1ec74 MS |
1383 | static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, |
1384 | const struct ipaddr *ip, | |
1385 | const struct ethaddr *mac) | |
b7cfce93 MK |
1386 | { |
1387 | zebra_neigh_t tmp_n; | |
1388 | zebra_neigh_t *n = NULL; | |
1389 | ||
1390 | memset(&tmp_n, 0, sizeof(zebra_neigh_t)); | |
1391 | memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr)); | |
1392 | n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc); | |
1393 | assert(n); | |
1394 | ||
85442b09 | 1395 | RB_INIT(host_rb_tree_entry, &n->host_rb); |
6134fd82 | 1396 | |
b7cfce93 | 1397 | memcpy(&n->emac, mac, ETH_ALEN); |
2dbad57f | 1398 | SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); |
1399 | SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE_NH); | |
b7cfce93 MK |
1400 | |
1401 | return n; | |
2dbad57f | 1402 | } |
b7cfce93 MK |
1403 | |
1404 | /* | |
1405 | * Delete neighbor entry. | |
1406 | */ | |
996c9314 | 1407 | static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) |
b7cfce93 MK |
1408 | { |
1409 | zebra_neigh_t *tmp_n; | |
f2a503f0 | 1410 | struct host_rb_entry *hle; |
b7cfce93 | 1411 | |
85442b09 DS |
1412 | while (!RB_EMPTY(host_rb_tree_entry, &n->host_rb)) { |
1413 | hle = RB_ROOT(host_rb_tree_entry, &n->host_rb); | |
f2a503f0 | 1414 | |
85442b09 | 1415 | RB_REMOVE(host_rb_tree_entry, &n->host_rb, hle); |
f2a503f0 DS |
1416 | XFREE(MTYPE_HOST_PREFIX, hle); |
1417 | } | |
55aabf6f | 1418 | |
b7cfce93 | 1419 | tmp_n = hash_release(zl3vni->nh_table, n); |
7cbae20a | 1420 | XFREE(MTYPE_L3NEIGH, tmp_n); |
b7cfce93 MK |
1421 | |
1422 | return 0; | |
2dbad57f | 1423 | } |
b7cfce93 MK |
1424 | |
1425 | /* | |
1426 | * Install remote nh as neigh into the kernel. | |
1427 | */ | |
996c9314 | 1428 | static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) |
b7cfce93 | 1429 | { |
68e33151 CS |
1430 | uint8_t flags; |
1431 | int ret = 0; | |
1432 | ||
b7cfce93 MK |
1433 | if (!is_l3vni_oper_up(zl3vni)) |
1434 | return -1; | |
1435 | ||
996c9314 LB |
1436 | if (!(n->flags & ZEBRA_NEIGH_REMOTE) |
1437 | || !(n->flags & ZEBRA_NEIGH_REMOTE_NH)) | |
b7cfce93 | 1438 | return 0; |
931fa60c MS |
1439 | |
1440 | flags = DPLANE_NTF_EXT_LEARNED; | |
68e33151 | 1441 | if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG) |
931fa60c MS |
1442 | flags |= DPLANE_NTF_ROUTER; |
1443 | ||
f188e68e AK |
1444 | dplane_rem_neigh_add(zl3vni->svi_if, &n->ip, &n->emac, flags, |
1445 | false /*was_static*/); | |
931fa60c | 1446 | |
68e33151 | 1447 | return ret; |
2dbad57f | 1448 | } |
b7cfce93 MK |
1449 | |
1450 | /* | |
1451 | * Uninstall remote nh from the kernel. | |
1452 | */ | |
996c9314 | 1453 | static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) |
b7cfce93 | 1454 | { |
996c9314 LB |
1455 | if (!(n->flags & ZEBRA_NEIGH_REMOTE) |
1456 | || !(n->flags & ZEBRA_NEIGH_REMOTE_NH)) | |
b7cfce93 MK |
1457 | return 0; |
1458 | ||
fa409e1e | 1459 | if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if)) |
1460 | return 0; | |
1461 | ||
f188e68e | 1462 | dplane_rem_neigh_delete(zl3vni->svi_if, &n->ip); |
931fa60c MS |
1463 | |
1464 | return 0; | |
2dbad57f | 1465 | } |
1466 | ||
1467 | /* add remote vtep as a neigh entry */ | |
e4a1ec74 MS |
1468 | static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, |
1469 | const struct ipaddr *vtep_ip, | |
1470 | const struct ethaddr *rmac, | |
1471 | const struct prefix *host_prefix) | |
2dbad57f | 1472 | { |
1473 | char buf[ETHER_ADDR_STRLEN]; | |
651fa905 CS |
1474 | char buf1[ETHER_ADDR_STRLEN]; |
1475 | char buf2[INET6_ADDRSTRLEN]; | |
2dbad57f | 1476 | zebra_neigh_t *nh = NULL; |
1477 | ||
651fa905 | 1478 | /* Create the next hop entry, or update its mac, if necessary. */ |
2dbad57f | 1479 | nh = zl3vni_nh_lookup(zl3vni, vtep_ip); |
1480 | if (!nh) { | |
1481 | nh = zl3vni_nh_add(zl3vni, vtep_ip, rmac); | |
1482 | if (!nh) { | |
9df414fe | 1483 | zlog_debug( |
2dbe669b | 1484 | "Failed to add NH %s as Neigh (RMAC %s L3-VNI %u prefix %pFX)", |
651fa905 | 1485 | ipaddr2str(vtep_ip, buf1, sizeof(buf2)), |
996c9314 | 1486 | prefix_mac2str(rmac, buf, sizeof(buf)), |
2dbe669b | 1487 | zl3vni->vni, host_prefix); |
2dbad57f | 1488 | return -1; |
1489 | } | |
1490 | ||
1491 | /* install the nh neigh in kernel */ | |
1492 | zl3vni_nh_install(zl3vni, nh); | |
651fa905 CS |
1493 | } else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) { |
1494 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2dbe669b DA |
1495 | zlog_debug( |
1496 | "L3VNI %u RMAC change(%s --> %s) for nexthop %s, prefix %pFX", | |
1497 | zl3vni->vni, | |
1498 | prefix_mac2str(&nh->emac, buf, sizeof(buf)), | |
1499 | prefix_mac2str(rmac, buf1, sizeof(buf1)), | |
1500 | ipaddr2str(vtep_ip, buf2, sizeof(buf2)), | |
1501 | host_prefix); | |
651fa905 CS |
1502 | |
1503 | memcpy(&nh->emac, rmac, ETH_ALEN); | |
1504 | /* install (update) the nh neigh in kernel */ | |
1505 | zl3vni_nh_install(zl3vni, nh); | |
2dbad57f | 1506 | } |
6134fd82 | 1507 | |
f2a503f0 | 1508 | rb_find_or_add_host(&nh->host_rb, host_prefix); |
6134fd82 | 1509 | |
2dbad57f | 1510 | return 0; |
1511 | } | |
1512 | ||
1513 | /* handle nh neigh delete */ | |
22e63104 | 1514 | static void zl3vni_remote_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *nh, |
1515 | struct prefix *host_prefix) | |
2dbad57f | 1516 | { |
f2a503f0 | 1517 | rb_delete_host(&nh->host_rb, host_prefix); |
2dbad57f | 1518 | |
85442b09 | 1519 | if (RB_EMPTY(host_rb_tree_entry, &nh->host_rb)) { |
2dbad57f | 1520 | /* uninstall from kernel */ |
1521 | zl3vni_nh_uninstall(zl3vni, nh); | |
1522 | ||
1523 | /* delete the nh entry */ | |
1524 | zl3vni_nh_del(zl3vni, nh); | |
1525 | } | |
2dbad57f | 1526 | } |
b7cfce93 | 1527 | |
3bcbba10 | 1528 | /* handle neigh update from kernel - the only thing of interest is to |
1529 | * readd stale entries. | |
1530 | */ | |
996c9314 | 1531 | static int zl3vni_local_nh_add_update(zebra_l3vni_t *zl3vni, struct ipaddr *ip, |
d7c0a89a | 1532 | uint16_t state) |
3bcbba10 | 1533 | { |
c05a738b | 1534 | #ifdef GNU_LINUX |
3bcbba10 | 1535 | zebra_neigh_t *n = NULL; |
1536 | ||
1537 | n = zl3vni_nh_lookup(zl3vni, ip); | |
1538 | if (!n) | |
1539 | return 0; | |
1540 | ||
1541 | /* all next hop neigh are remote and installed by frr. | |
1542 | * If the kernel has aged this entry, re-install. | |
1543 | */ | |
1544 | if (state & NUD_STALE) | |
1545 | zl3vni_nh_install(zl3vni, n); | |
c05a738b | 1546 | #endif |
3bcbba10 | 1547 | return 0; |
1548 | } | |
1549 | ||
8c9b80b9 | 1550 | /* handle neigh delete from kernel */ |
996c9314 | 1551 | static int zl3vni_local_nh_del(zebra_l3vni_t *zl3vni, struct ipaddr *ip) |
8c9b80b9 MK |
1552 | { |
1553 | zebra_neigh_t *n = NULL; | |
1554 | ||
1555 | n = zl3vni_nh_lookup(zl3vni, ip); | |
1556 | if (!n) | |
1557 | return 0; | |
1558 | ||
1559 | /* all next hop neigh are remote and installed by frr. | |
1560 | * If we get an age out notification for these neigh entries, we have to | |
523cafc4 | 1561 | * install it back |
1562 | */ | |
8c9b80b9 MK |
1563 | zl3vni_nh_install(zl3vni, n); |
1564 | ||
1565 | return 0; | |
1566 | } | |
1567 | ||
b7cfce93 MK |
1568 | /* |
1569 | * Hash function for L3 VNI. | |
1570 | */ | |
d8b87afe | 1571 | static unsigned int l3vni_hash_keymake(const void *p) |
b7cfce93 MK |
1572 | { |
1573 | const zebra_l3vni_t *zl3vni = p; | |
1574 | ||
1575 | return jhash_1word(zl3vni->vni, 0); | |
1576 | } | |
1577 | ||
1578 | /* | |
1579 | * Compare 2 L3 VNI hash entries. | |
1580 | */ | |
74df8d6d | 1581 | static bool l3vni_hash_cmp(const void *p1, const void *p2) |
b7cfce93 MK |
1582 | { |
1583 | const zebra_l3vni_t *zl3vni1 = p1; | |
1584 | const zebra_l3vni_t *zl3vni2 = p2; | |
1585 | ||
1586 | return (zl3vni1->vni == zl3vni2->vni); | |
1587 | } | |
1588 | ||
1589 | /* | |
1590 | * Callback to allocate L3 VNI hash entry. | |
1591 | */ | |
1592 | static void *zl3vni_alloc(void *p) | |
1593 | { | |
1594 | zebra_l3vni_t *zl3vni = NULL; | |
1595 | const zebra_l3vni_t *tmp_l3vni = p; | |
1596 | ||
1597 | zl3vni = XCALLOC(MTYPE_ZL3VNI, sizeof(zebra_l3vni_t)); | |
1598 | zl3vni->vni = tmp_l3vni->vni; | |
1599 | return ((void *)zl3vni); | |
1600 | } | |
1601 | ||
1602 | /* | |
1603 | * Look up L3 VNI hash entry. | |
1604 | */ | |
e2bcfa39 | 1605 | zebra_l3vni_t *zl3vni_lookup(vni_t vni) |
b7cfce93 | 1606 | { |
b7cfce93 MK |
1607 | zebra_l3vni_t tmp_l3vni; |
1608 | zebra_l3vni_t *zl3vni = NULL; | |
1609 | ||
b7cfce93 MK |
1610 | memset(&tmp_l3vni, 0, sizeof(zebra_l3vni_t)); |
1611 | tmp_l3vni.vni = vni; | |
89272910 | 1612 | zl3vni = hash_lookup(zrouter.l3vni_table, &tmp_l3vni); |
b7cfce93 MK |
1613 | |
1614 | return zl3vni; | |
1615 | } | |
1616 | ||
1617 | /* | |
1618 | * Add L3 VNI hash entry. | |
1619 | */ | |
1620 | static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id) | |
1621 | { | |
1622 | zebra_l3vni_t tmp_zl3vni; | |
b7cfce93 MK |
1623 | zebra_l3vni_t *zl3vni = NULL; |
1624 | ||
b7cfce93 MK |
1625 | memset(&tmp_zl3vni, 0, sizeof(zebra_l3vni_t)); |
1626 | tmp_zl3vni.vni = vni; | |
1627 | ||
89272910 | 1628 | zl3vni = hash_get(zrouter.l3vni_table, &tmp_zl3vni, zl3vni_alloc); |
b7cfce93 MK |
1629 | assert(zl3vni); |
1630 | ||
1631 | zl3vni->vrf_id = vrf_id; | |
1632 | zl3vni->svi_if = NULL; | |
1633 | zl3vni->vxlan_if = NULL; | |
1634 | zl3vni->l2vnis = list_new(); | |
8b5fdf2e | 1635 | zl3vni->l2vnis->cmp = zebra_evpn_list_cmp; |
b7cfce93 MK |
1636 | |
1637 | /* Create hash table for remote RMAC */ | |
b2998086 | 1638 | zl3vni->rmac_table = zebra_mac_db_create("Zebra L3-VNI RMAC-Table"); |
b7cfce93 MK |
1639 | |
1640 | /* Create hash table for neighbors */ | |
7cbae20a | 1641 | zl3vni->nh_table = zebra_neigh_db_create("Zebra L3-VNI next-hop table"); |
b7cfce93 MK |
1642 | |
1643 | return zl3vni; | |
1644 | } | |
1645 | ||
1646 | /* | |
1647 | * Delete L3 VNI hash entry. | |
1648 | */ | |
1649 | static int zl3vni_del(zebra_l3vni_t *zl3vni) | |
1650 | { | |
b7cfce93 MK |
1651 | zebra_l3vni_t *tmp_zl3vni; |
1652 | ||
b7cfce93 | 1653 | /* free the list of l2vnis */ |
6a154c88 | 1654 | list_delete(&zl3vni->l2vnis); |
b7cfce93 MK |
1655 | zl3vni->l2vnis = NULL; |
1656 | ||
1657 | /* Free the rmac table */ | |
1658 | hash_free(zl3vni->rmac_table); | |
1659 | zl3vni->rmac_table = NULL; | |
1660 | ||
1661 | /* Free the nh table */ | |
1662 | hash_free(zl3vni->nh_table); | |
1663 | zl3vni->nh_table = NULL; | |
1664 | ||
1665 | /* Free the VNI hash entry and allocated memory. */ | |
89272910 | 1666 | tmp_zl3vni = hash_release(zrouter.l3vni_table, zl3vni); |
0a22ddfb | 1667 | XFREE(MTYPE_ZL3VNI, tmp_zl3vni); |
b7cfce93 MK |
1668 | |
1669 | return 0; | |
1670 | } | |
1671 | ||
2961d060 PG |
1672 | static int zl3vni_map_to_vxlan_if_ns(struct ns *ns, |
1673 | void *_zl3vni, | |
1674 | void **_pifp) | |
b7cfce93 | 1675 | { |
2961d060 | 1676 | struct zebra_ns *zns = ns->info; |
07509878 | 1677 | zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)_zl3vni; |
b7cfce93 MK |
1678 | struct route_node *rn = NULL; |
1679 | struct interface *ifp = NULL; | |
07509878 PG |
1680 | struct zebra_vrf *zvrf; |
1681 | ||
1682 | zvrf = zebra_vrf_get_evpn(); | |
1683 | ||
1684 | if (!zvrf) | |
2961d060 | 1685 | return NS_WALK_STOP; |
b7cfce93 MK |
1686 | |
1687 | /* loop through all vxlan-interface */ | |
b7cfce93 MK |
1688 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { |
1689 | ||
1690 | struct zebra_if *zif = NULL; | |
1691 | struct zebra_l2info_vxlan *vxl = NULL; | |
1692 | ||
1693 | ifp = (struct interface *)rn->info; | |
1694 | if (!ifp) | |
1695 | continue; | |
1696 | ||
1697 | zif = ifp->info; | |
1698 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
1699 | continue; | |
1700 | ||
1701 | vxl = &zif->l2info.vxl; | |
07509878 PG |
1702 | if (vxl->vni != zl3vni->vni) |
1703 | continue; | |
1704 | ||
1705 | /* link of VXLAN interface should be in zebra_evpn_vrf */ | |
1706 | if (zvrf->zns->ns_id != vxl->link_nsid) { | |
1707 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1708 | zlog_debug( | |
1709 | "Intf %s(%u) VNI %u, link not in same " | |
1710 | "namespace than BGP EVPN core instance ", | |
1711 | ifp->name, ifp->ifindex, vxl->vni); | |
1712 | continue; | |
b67a60d2 | 1713 | } |
07509878 PG |
1714 | |
1715 | ||
1716 | zl3vni->local_vtep_ip = vxl->vtep_ip; | |
1717 | if (_pifp) | |
1718 | *_pifp = (void *)ifp; | |
2961d060 | 1719 | return NS_WALK_STOP; |
b7cfce93 MK |
1720 | } |
1721 | ||
2961d060 | 1722 | return NS_WALK_CONTINUE; |
07509878 PG |
1723 | } |
1724 | ||
1725 | struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni) | |
1726 | { | |
1727 | struct interface **p_ifp; | |
1728 | struct interface *ifp = NULL; | |
1729 | ||
1730 | p_ifp = &ifp; | |
1731 | ||
2961d060 PG |
1732 | ns_walk_func(zl3vni_map_to_vxlan_if_ns, |
1733 | (void *)zl3vni, (void **)p_ifp); | |
07509878 | 1734 | return ifp; |
b7cfce93 MK |
1735 | } |
1736 | ||
a780a738 | 1737 | struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni) |
b7cfce93 | 1738 | { |
996c9314 | 1739 | struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */ |
b7cfce93 MK |
1740 | struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */ |
1741 | ||
2aeb403d | 1742 | if (!zl3vni) |
1743 | return NULL; | |
1744 | ||
b7cfce93 MK |
1745 | if (!zl3vni->vxlan_if) |
1746 | return NULL; | |
1747 | ||
1748 | zif = zl3vni->vxlan_if->info; | |
1749 | if (!zif) | |
1750 | return NULL; | |
1751 | ||
1752 | vxl = &zif->l2info.vxl; | |
1753 | ||
7cbae20a | 1754 | return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); |
b7cfce93 MK |
1755 | } |
1756 | ||
06d9cde5 CS |
1757 | struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni) |
1758 | { | |
1759 | struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */ | |
1760 | ||
1761 | if (!zl3vni) | |
1762 | return NULL; | |
1763 | ||
1764 | if (!zl3vni->vxlan_if) | |
1765 | return NULL; | |
1766 | ||
1767 | zif = zl3vni->vxlan_if->info; | |
1768 | if (!zif) | |
1769 | return NULL; | |
1770 | ||
8b5fdf2e PR |
1771 | return zebra_evpn_map_to_macvlan(zif->brslave_info.br_if, |
1772 | zl3vni->svi_if); | |
06d9cde5 CS |
1773 | } |
1774 | ||
1775 | ||
9d21b7c6 | 1776 | zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id) |
b7cfce93 MK |
1777 | { |
1778 | struct zebra_vrf *zvrf = NULL; | |
1779 | ||
1780 | zvrf = zebra_vrf_lookup_by_id(vrf_id); | |
1781 | if (!zvrf) | |
1782 | return NULL; | |
1783 | ||
1784 | return zl3vni_lookup(zvrf->l3vni); | |
1785 | } | |
1786 | ||
1787 | /* | |
1788 | * Map SVI and associated bridge to a VNI. This is invoked upon getting | |
1789 | * neighbor notifications, to see if they are of interest. | |
1790 | */ | |
1791 | static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp, | |
1792 | struct interface *br_if) | |
1793 | { | |
1794 | int found = 0; | |
1795 | vlanid_t vid = 0; | |
d7c0a89a | 1796 | uint8_t bridge_vlan_aware = 0; |
b7cfce93 MK |
1797 | zebra_l3vni_t *zl3vni = NULL; |
1798 | struct zebra_ns *zns = NULL; | |
1799 | struct route_node *rn = NULL; | |
1800 | struct zebra_if *zif = NULL; | |
1801 | struct interface *tmp_if = NULL; | |
1802 | struct zebra_l2info_bridge *br = NULL; | |
1803 | struct zebra_l2info_vxlan *vxl = NULL; | |
1804 | ||
1805 | if (!br_if) | |
1806 | return NULL; | |
1807 | ||
1808 | /* Make sure the linked interface is a bridge. */ | |
1809 | if (!IS_ZEBRA_IF_BRIDGE(br_if)) | |
1810 | return NULL; | |
1811 | ||
1812 | /* Determine if bridge is VLAN-aware or not */ | |
1813 | zif = br_if->info; | |
1814 | assert(zif); | |
1815 | br = &zif->l2info.br; | |
1816 | bridge_vlan_aware = br->vlan_aware; | |
1817 | if (bridge_vlan_aware) { | |
1818 | struct zebra_l2info_vlan *vl; | |
1819 | ||
1820 | if (!IS_ZEBRA_IF_VLAN(ifp)) | |
1821 | return NULL; | |
1822 | ||
1823 | zif = ifp->info; | |
1824 | assert(zif); | |
1825 | vl = &zif->l2info.vl; | |
1826 | vid = vl->vid; | |
1827 | } | |
1828 | ||
1829 | /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ | |
1830 | /* TODO: Optimize with a hash. */ | |
1831 | zns = zebra_ns_lookup(NS_DEFAULT); | |
1832 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { | |
1833 | tmp_if = (struct interface *)rn->info; | |
1834 | if (!tmp_if) | |
1835 | continue; | |
1836 | zif = tmp_if->info; | |
1837 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
1838 | continue; | |
1839 | if (!if_is_operative(tmp_if)) | |
1840 | continue; | |
1841 | vxl = &zif->l2info.vxl; | |
1842 | ||
1843 | if (zif->brslave_info.br_if != br_if) | |
1844 | continue; | |
1845 | ||
1846 | if (!bridge_vlan_aware || vxl->access_vlan == vid) { | |
1847 | found = 1; | |
1848 | break; | |
1849 | } | |
1850 | } | |
1851 | ||
1852 | if (!found) | |
1853 | return NULL; | |
1854 | ||
1855 | zl3vni = zl3vni_lookup(vxl->vni); | |
1856 | return zl3vni; | |
1857 | } | |
1858 | ||
06d9cde5 CS |
1859 | static inline void zl3vni_get_vrr_rmac(zebra_l3vni_t *zl3vni, |
1860 | struct ethaddr *rmac) | |
1861 | { | |
1862 | if (!zl3vni) | |
1863 | return; | |
1864 | ||
1865 | if (!is_l3vni_oper_up(zl3vni)) | |
1866 | return; | |
1867 | ||
1868 | if (zl3vni->mac_vlan_if && if_is_operative(zl3vni->mac_vlan_if)) | |
1869 | memcpy(rmac->octet, zl3vni->mac_vlan_if->hw_addr, ETH_ALEN); | |
1870 | } | |
1871 | ||
b7cfce93 MK |
1872 | /* |
1873 | * Inform BGP about l3-vni. | |
1874 | */ | |
1875 | static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) | |
1876 | { | |
1877 | struct stream *s = NULL; | |
1878 | struct zserv *client = NULL; | |
06d9cde5 CS |
1879 | struct ethaddr svi_rmac, vrr_rmac = {.octet = {0} }; |
1880 | struct zebra_vrf *zvrf; | |
b7cfce93 | 1881 | char buf[ETHER_ADDR_STRLEN]; |
06d9cde5 CS |
1882 | char buf1[ETHER_ADDR_STRLEN]; |
1883 | bool is_anycast_mac = true; | |
b7cfce93 | 1884 | |
21ccc0cf | 1885 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); |
b7cfce93 MK |
1886 | /* BGP may not be running. */ |
1887 | if (!client) | |
1888 | return 0; | |
1889 | ||
06d9cde5 CS |
1890 | zvrf = zebra_vrf_lookup_by_id(zl3vni->vrf_id); |
1891 | assert(zvrf); | |
1892 | ||
1893 | /* get the svi and vrr rmac values */ | |
1894 | memset(&svi_rmac, 0, sizeof(struct ethaddr)); | |
1895 | zl3vni_get_svi_rmac(zl3vni, &svi_rmac); | |
1896 | zl3vni_get_vrr_rmac(zl3vni, &vrr_rmac); | |
1897 | ||
1898 | /* In absence of vrr mac use svi mac as anycast MAC value */ | |
1899 | if (is_zero_mac(&vrr_rmac)) { | |
1900 | memcpy(&vrr_rmac, &svi_rmac, ETH_ALEN); | |
1901 | is_anycast_mac = false; | |
1902 | } | |
b7cfce93 | 1903 | |
1002497a | 1904 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
b7cfce93 | 1905 | |
06d9cde5 CS |
1906 | /* The message is used for both vni add and/or update like |
1907 | * vrr mac is added for l3vni SVI. | |
1908 | */ | |
996c9314 | 1909 | zclient_create_header(s, ZEBRA_L3VNI_ADD, zl3vni_vrf_id(zl3vni)); |
b7cfce93 | 1910 | stream_putl(s, zl3vni->vni); |
06d9cde5 | 1911 | stream_put(s, &svi_rmac, sizeof(struct ethaddr)); |
b67a60d2 | 1912 | stream_put_in_addr(s, &zl3vni->local_vtep_ip); |
c48d9f5f | 1913 | stream_put(s, &zl3vni->filter, sizeof(int)); |
0483af6e | 1914 | stream_putl(s, zl3vni->svi_if->ifindex); |
06d9cde5 CS |
1915 | stream_put(s, &vrr_rmac, sizeof(struct ethaddr)); |
1916 | stream_putl(s, is_anycast_mac); | |
b7cfce93 MK |
1917 | |
1918 | /* Write packet size. */ | |
1919 | stream_putw_at(s, 0, stream_get_endp(s)); | |
1920 | ||
1921 | if (IS_ZEBRA_DEBUG_VXLAN) | |
c48d9f5f | 1922 | zlog_debug( |
9bcef951 | 1923 | "Send L3_VNI_ADD %u VRF %s RMAC %s VRR %s local-ip %pI4 filter %s to %s", |
996c9314 | 1924 | zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), |
06d9cde5 CS |
1925 | prefix_mac2str(&svi_rmac, buf, sizeof(buf)), |
1926 | prefix_mac2str(&vrr_rmac, buf1, sizeof(buf1)), | |
9bcef951 | 1927 | &zl3vni->local_vtep_ip, |
996c9314 LB |
1928 | CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) |
1929 | ? "prefix-routes-only" | |
1930 | : "none", | |
1931 | zebra_route_string(client->proto)); | |
b7cfce93 MK |
1932 | |
1933 | client->l3vniadd_cnt++; | |
21ccc0cf | 1934 | return zserv_send_message(client, s); |
b7cfce93 MK |
1935 | } |
1936 | ||
1937 | /* | |
1938 | * Inform BGP about local l3-VNI deletion. | |
1939 | */ | |
1940 | static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni) | |
1941 | { | |
1942 | struct stream *s = NULL; | |
1943 | struct zserv *client = NULL; | |
1944 | ||
21ccc0cf | 1945 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); |
b7cfce93 MK |
1946 | /* BGP may not be running. */ |
1947 | if (!client) | |
1948 | return 0; | |
1949 | ||
1002497a | 1950 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
b7cfce93 | 1951 | |
996c9314 | 1952 | zclient_create_header(s, ZEBRA_L3VNI_DEL, zl3vni_vrf_id(zl3vni)); |
b7cfce93 MK |
1953 | stream_putl(s, zl3vni->vni); |
1954 | ||
1955 | /* Write packet size. */ | |
1956 | stream_putw_at(s, 0, stream_get_endp(s)); | |
1957 | ||
1958 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 | 1959 | zlog_debug("Send L3_VNI_DEL %u VRF %s to %s", zl3vni->vni, |
b7cfce93 MK |
1960 | vrf_id_to_name(zl3vni_vrf_id(zl3vni)), |
1961 | zebra_route_string(client->proto)); | |
1962 | ||
1963 | client->l3vnidel_cnt++; | |
21ccc0cf | 1964 | return zserv_send_message(client, s); |
b7cfce93 MK |
1965 | } |
1966 | ||
1967 | static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni) | |
1968 | { | |
2aeb403d | 1969 | if (!zl3vni) |
1970 | return; | |
1971 | ||
b7cfce93 MK |
1972 | /* send l3vni add to BGP */ |
1973 | zl3vni_send_add_to_client(zl3vni); | |
1974 | } | |
1975 | ||
1976 | static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni) | |
1977 | { | |
2aeb403d | 1978 | if (!zl3vni) |
1979 | return; | |
1980 | ||
b7cfce93 MK |
1981 | /* send l3-vni del to BGP*/ |
1982 | zl3vni_send_del_to_client(zl3vni); | |
1983 | } | |
1984 | ||
7cbae20a | 1985 | static void zevpn_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt) |
b169fd6f | 1986 | { |
7cbae20a PR |
1987 | zebra_evpn_t *zevpn = (zebra_evpn_t *)bucket->data; |
1988 | zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)ctxt; | |
b169fd6f | 1989 | |
7cbae20a PR |
1990 | if (zevpn->vrf_id == zl3vni_vrf_id(zl3vni)) |
1991 | listnode_add_sort(zl3vni->l2vnis, zevpn); | |
b169fd6f AK |
1992 | } |
1993 | ||
7cbae20a | 1994 | /* |
3b0a590b AD |
1995 | * Handle transition of vni from l2 to l3 and vice versa. |
1996 | * This function handles only the L2VNI add/delete part of | |
1997 | * the above transition. | |
1998 | * L3VNI add/delete is handled by the calling functions. | |
7cbae20a PR |
1999 | */ |
2000 | static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni, | |
2001 | int add) | |
b169fd6f | 2002 | { |
7cbae20a | 2003 | zebra_evpn_t *zevpn = NULL; |
b169fd6f | 2004 | |
7cbae20a PR |
2005 | /* There is a possibility that VNI notification was already received |
2006 | * from kernel and we programmed it as L2-VNI | |
2007 | * In such a case we need to delete this L2-VNI first, so | |
2008 | * that it can be reprogrammed as L3-VNI in the system. It is also | |
2009 | * possible that the vrf-vni mapping is removed from FRR while the vxlan | |
2010 | * interface is still present in kernel. In this case to keep it | |
2011 | * symmetric, we will delete the l3-vni and reprogram it as l2-vni | |
2012 | */ | |
2013 | if (add) { | |
2014 | /* Locate hash entry */ | |
8b5fdf2e | 2015 | zevpn = zebra_evpn_lookup(vni); |
7cbae20a PR |
2016 | if (!zevpn) |
2017 | return 0; | |
b169fd6f | 2018 | |
7cbae20a PR |
2019 | if (IS_ZEBRA_DEBUG_VXLAN) |
2020 | zlog_debug("Del L2-VNI %u - transition to L3-VNI", vni); | |
b169fd6f | 2021 | |
7cbae20a | 2022 | /* Delete EVPN from BGP. */ |
8b5fdf2e | 2023 | zebra_evpn_send_del_to_client(zevpn); |
b169fd6f | 2024 | |
7cbae20a PR |
2025 | zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH); |
2026 | zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC); | |
b169fd6f | 2027 | |
7cbae20a | 2028 | /* Free up all remote VTEPs, if any. */ |
8b5fdf2e | 2029 | zebra_evpn_vtep_del_all(zevpn, 0); |
b169fd6f | 2030 | |
7cbae20a | 2031 | /* Delete the hash entry. */ |
8b5fdf2e | 2032 | if (zebra_evpn_vxlan_del(zevpn)) { |
7cbae20a PR |
2033 | flog_err(EC_ZEBRA_VNI_DEL_FAILED, |
2034 | "Failed to del EVPN hash %p, VNI %u", zevpn, | |
2035 | zevpn->vni); | |
2036 | return -1; | |
b169fd6f | 2037 | } |
7cbae20a | 2038 | } else { |
3b0a590b AD |
2039 | struct zebra_ns *zns; |
2040 | struct route_node *rn; | |
2041 | struct interface *ifp; | |
2042 | struct zebra_if *zif; | |
2043 | struct zebra_l2info_vxlan *vxl; | |
2044 | struct interface *vlan_if; | |
2045 | bool found = false; | |
2046 | ||
2047 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2048 | zlog_debug("Adding L2-VNI %u - transition from L3-VNI", | |
2049 | vni); | |
2050 | ||
2051 | /* Find VxLAN interface for this VNI. */ | |
2052 | zns = zebra_ns_lookup(NS_DEFAULT); | |
2053 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { | |
2054 | ifp = (struct interface *)rn->info; | |
2055 | if (!ifp) | |
2056 | continue; | |
2057 | zif = ifp->info; | |
2058 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
2059 | continue; | |
2060 | ||
2061 | vxl = &zif->l2info.vxl; | |
2062 | if (vxl->vni == vni) { | |
2063 | found = true; | |
2064 | break; | |
2065 | } | |
2066 | } | |
2067 | ||
2068 | if (!found) { | |
2069 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2070 | zlog_err( | |
2071 | "Adding L2-VNI - Failed to find VxLAN interface for VNI %u", | |
2072 | vni); | |
2073 | return -1; | |
2074 | } | |
2075 | ||
2076 | /* Create VNI hash entry for L2VNI */ | |
2077 | zevpn = zebra_evpn_lookup(vni); | |
2078 | if (zevpn) | |
2079 | return 0; | |
2080 | ||
2081 | zevpn = zebra_evpn_add(vni); | |
2082 | if (!zevpn) { | |
2083 | flog_err(EC_ZEBRA_VNI_ADD_FAILED, | |
2084 | "Adding L2-VNI - Failed to add VNI hash, VNI %u", | |
2085 | vni); | |
2086 | ||
2087 | return -1; | |
2088 | } | |
2089 | ||
2090 | /* Find bridge interface for the VNI */ | |
2091 | vlan_if = zvni_map_to_svi(vxl->access_vlan, | |
2092 | zif->brslave_info.br_if); | |
2093 | if (vlan_if) | |
2094 | zevpn->vrf_id = vlan_if->vrf_id; | |
2095 | ||
2096 | zevpn->vxlan_if = ifp; | |
2097 | zevpn->local_vtep_ip = vxl->vtep_ip; | |
2098 | ||
2099 | /* Inform BGP if the VNI is up and mapped to a bridge. */ | |
2100 | if (if_is_operative(ifp) && zif->brslave_info.br_if) { | |
2101 | zebra_evpn_send_add_to_client(zevpn); | |
2102 | zebra_evpn_read_mac_neigh(zevpn, ifp); | |
2103 | } | |
b169fd6f AK |
2104 | } |
2105 | ||
7cbae20a | 2106 | return 0; |
b169fd6f AK |
2107 | } |
2108 | ||
7cbae20a PR |
2109 | /* delete and uninstall rmac hash entry */ |
2110 | static void zl3vni_del_rmac_hash_entry(struct hash_bucket *bucket, void *ctx) | |
b169fd6f | 2111 | { |
7cbae20a PR |
2112 | zebra_mac_t *zrmac = NULL; |
2113 | zebra_l3vni_t *zl3vni = NULL; | |
b169fd6f | 2114 | |
7cbae20a PR |
2115 | zrmac = (zebra_mac_t *)bucket->data; |
2116 | zl3vni = (zebra_l3vni_t *)ctx; | |
2117 | zl3vni_rmac_uninstall(zl3vni, zrmac); | |
b169fd6f | 2118 | |
7cbae20a PR |
2119 | /* Send RMAC for FPM processing */ |
2120 | hook_call(zebra_rmac_update, zrmac, zl3vni, true, "RMAC deleted"); | |
b169fd6f | 2121 | |
7cbae20a | 2122 | zl3vni_rmac_del(zl3vni, zrmac); |
b169fd6f AK |
2123 | } |
2124 | ||
7cbae20a PR |
2125 | /* delete and uninstall nh hash entry */ |
2126 | static void zl3vni_del_nh_hash_entry(struct hash_bucket *bucket, void *ctx) | |
b169fd6f | 2127 | { |
7cbae20a PR |
2128 | zebra_neigh_t *n = NULL; |
2129 | zebra_l3vni_t *zl3vni = NULL; | |
b169fd6f | 2130 | |
7cbae20a PR |
2131 | n = (zebra_neigh_t *)bucket->data; |
2132 | zl3vni = (zebra_l3vni_t *)ctx; | |
2133 | zl3vni_nh_uninstall(zl3vni, n); | |
2134 | zl3vni_nh_del(zl3vni, n); | |
2135 | } | |
b169fd6f | 2136 | |
7cbae20a PR |
2137 | /* re-add remote rmac if needed */ |
2138 | static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni, | |
2139 | struct ethaddr *rmac) | |
2140 | { | |
2141 | char buf[ETHER_ADDR_STRLEN]; | |
2142 | zebra_mac_t *zrmac = NULL; | |
2143 | ||
2144 | zrmac = zl3vni_rmac_lookup(zl3vni, rmac); | |
2145 | if (!zrmac) | |
2146 | return 0; | |
2147 | ||
2148 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2149 | zlog_debug("Del remote RMAC %s L3VNI %u - readd", | |
2150 | prefix_mac2str(rmac, buf, sizeof(buf)), zl3vni->vni); | |
2151 | ||
2152 | zl3vni_rmac_install(zl3vni, zrmac); | |
2153 | return 0; | |
b169fd6f AK |
2154 | } |
2155 | ||
b7cfce93 MK |
2156 | /* Public functions */ |
2157 | ||
c48d9f5f MK |
2158 | int is_l3vni_for_prefix_routes_only(vni_t vni) |
2159 | { | |
2160 | zebra_l3vni_t *zl3vni = NULL; | |
2161 | ||
2162 | zl3vni = zl3vni_lookup(vni); | |
2163 | if (!zl3vni) | |
2164 | return 0; | |
2165 | ||
2166 | return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0; | |
2167 | } | |
2168 | ||
2dbad57f | 2169 | /* handle evpn route in vrf table */ |
e4a1ec74 MS |
2170 | void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, |
2171 | const struct ipaddr *vtep_ip, | |
2172 | const struct prefix *host_prefix) | |
2dbad57f | 2173 | { |
2174 | zebra_l3vni_t *zl3vni = NULL; | |
f50dc5e6 | 2175 | struct ipaddr ipv4_vtep; |
2dbad57f | 2176 | |
2177 | zl3vni = zl3vni_from_vrf(vrf_id); | |
2178 | if (!zl3vni || !is_l3vni_oper_up(zl3vni)) | |
2179 | return; | |
2180 | ||
3518f352 | 2181 | /* |
f50dc5e6 MK |
2182 | * add the next hop neighbor - |
2183 | * neigh to be installed is the ipv6 nexthop neigh | |
2184 | */ | |
3518f352 | 2185 | zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); |
2dbad57f | 2186 | |
f50dc5e6 MK |
2187 | /* |
2188 | * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 | |
2189 | * address. Rmac is programmed against the ipv4 vtep because we only | |
2190 | * support ipv4 tunnels in the h/w right now | |
2191 | */ | |
2192 | memset(&ipv4_vtep, 0, sizeof(struct ipaddr)); | |
2193 | ipv4_vtep.ipa_type = IPADDR_V4; | |
2194 | if (vtep_ip->ipa_type == IPADDR_V6) | |
2195 | ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, | |
2196 | &(ipv4_vtep.ipaddr_v4)); | |
2197 | else | |
2198 | memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, | |
2199 | sizeof(struct in_addr)); | |
2200 | ||
3518f352 DS |
2201 | /* |
2202 | * add the rmac - remote rmac to be installed is against the ipv4 | |
f50dc5e6 MK |
2203 | * nexthop address |
2204 | */ | |
3518f352 | 2205 | zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix); |
2dbad57f | 2206 | } |
2207 | ||
2208 | /* handle evpn vrf route delete */ | |
22e63104 | 2209 | void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id, |
996c9314 LB |
2210 | struct ipaddr *vtep_ip, |
2211 | struct prefix *host_prefix) | |
2dbad57f | 2212 | { |
2213 | zebra_l3vni_t *zl3vni = NULL; | |
22e63104 | 2214 | zebra_neigh_t *nh = NULL; |
2215 | zebra_mac_t *zrmac = NULL; | |
2dbad57f | 2216 | |
2217 | zl3vni = zl3vni_from_vrf(vrf_id); | |
5e06422c | 2218 | if (!zl3vni) |
2dbad57f | 2219 | return; |
2220 | ||
22e63104 | 2221 | /* find the next hop entry and rmac entry */ |
2222 | nh = zl3vni_nh_lookup(zl3vni, vtep_ip); | |
2223 | if (!nh) | |
2224 | return; | |
2225 | zrmac = zl3vni_rmac_lookup(zl3vni, &nh->emac); | |
2226 | ||
2dbad57f | 2227 | /* delete the next hop entry */ |
22e63104 | 2228 | zl3vni_remote_nh_del(zl3vni, nh, host_prefix); |
2dbad57f | 2229 | |
2230 | /* delete the rmac entry */ | |
22e63104 | 2231 | if (zrmac) |
2232 | zl3vni_remote_rmac_del(zl3vni, zrmac, host_prefix); | |
2233 | ||
2dbad57f | 2234 | } |
2235 | ||
996c9314 | 2236 | void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni, |
9f049418 | 2237 | struct ethaddr *rmac, bool use_json) |
9aa741ea MK |
2238 | { |
2239 | zebra_l3vni_t *zl3vni = NULL; | |
2240 | zebra_mac_t *zrmac = NULL; | |
316f4ca4 | 2241 | json_object *json = NULL; |
9aa741ea | 2242 | |
316f4ca4 MK |
2243 | if (!is_evpn_enabled()) { |
2244 | if (use_json) | |
2245 | vty_out(vty, "{}\n"); | |
9aa741ea | 2246 | return; |
316f4ca4 MK |
2247 | } |
2248 | ||
2249 | if (use_json) | |
2250 | json = json_object_new_object(); | |
9aa741ea MK |
2251 | |
2252 | zl3vni = zl3vni_lookup(l3vni); | |
2253 | if (!zl3vni) { | |
316f4ca4 MK |
2254 | if (use_json) |
2255 | vty_out(vty, "{}\n"); | |
2256 | else | |
0437e105 | 2257 | vty_out(vty, "%% L3-VNI %u doesn't exist\n", l3vni); |
9aa741ea MK |
2258 | return; |
2259 | } | |
2260 | ||
2261 | zrmac = zl3vni_rmac_lookup(zl3vni, rmac); | |
2262 | if (!zrmac) { | |
316f4ca4 MK |
2263 | if (use_json) |
2264 | vty_out(vty, "{}\n"); | |
2265 | else | |
2266 | vty_out(vty, | |
0437e105 | 2267 | "%% Requested RMAC doesn't exist in L3-VNI %u", |
316f4ca4 | 2268 | l3vni); |
9aa741ea MK |
2269 | return; |
2270 | } | |
2271 | ||
316f4ca4 MK |
2272 | zl3vni_print_rmac(zrmac, vty, json); |
2273 | ||
2274 | if (use_json) { | |
2275 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2276 | json, JSON_C_TO_STRING_PRETTY)); | |
2277 | json_object_free(json); | |
2278 | } | |
9aa741ea | 2279 | } |
2dbad57f | 2280 | |
9f049418 | 2281 | void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t l3vni, bool use_json) |
b7cfce93 MK |
2282 | { |
2283 | zebra_l3vni_t *zl3vni; | |
d7c0a89a | 2284 | uint32_t num_rmacs; |
b7cfce93 MK |
2285 | struct rmac_walk_ctx wctx; |
2286 | json_object *json = NULL; | |
b7cfce93 MK |
2287 | |
2288 | if (!is_evpn_enabled()) | |
2289 | return; | |
2290 | ||
2291 | zl3vni = zl3vni_lookup(l3vni); | |
2292 | if (!zl3vni) { | |
2293 | if (use_json) | |
2294 | vty_out(vty, "{}\n"); | |
2295 | else | |
2296 | vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); | |
2297 | return; | |
2298 | } | |
2299 | num_rmacs = hashcount(zl3vni->rmac_table); | |
2300 | if (!num_rmacs) | |
2301 | return; | |
2302 | ||
75223c9e | 2303 | if (use_json) |
b7cfce93 | 2304 | json = json_object_new_object(); |
b7cfce93 MK |
2305 | |
2306 | memset(&wctx, 0, sizeof(struct rmac_walk_ctx)); | |
2307 | wctx.vty = vty; | |
75223c9e | 2308 | wctx.json = json; |
b7cfce93 | 2309 | if (!use_json) { |
996c9314 | 2310 | vty_out(vty, "Number of Remote RMACs known for this VNI: %u\n", |
b7cfce93 | 2311 | num_rmacs); |
4cce389e | 2312 | vty_out(vty, "%-17s %-21s\n", "MAC", "Remote VTEP"); |
b7cfce93 MK |
2313 | } else |
2314 | json_object_int_add(json, "numRmacs", num_rmacs); | |
2315 | ||
2316 | hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx); | |
2317 | ||
2318 | if (use_json) { | |
b7cfce93 MK |
2319 | vty_out(vty, "%s\n", json_object_to_json_string_ext( |
2320 | json, JSON_C_TO_STRING_PRETTY)); | |
2321 | json_object_free(json); | |
2322 | } | |
2323 | } | |
2324 | ||
9f049418 | 2325 | void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json) |
b7cfce93 | 2326 | { |
b7cfce93 | 2327 | json_object *json = NULL; |
c0b4eaa4 | 2328 | void *args[2]; |
b7cfce93 MK |
2329 | |
2330 | if (!is_evpn_enabled()) { | |
2331 | if (use_json) | |
2332 | vty_out(vty, "{}\n"); | |
2333 | return; | |
2334 | } | |
2335 | ||
b7cfce93 MK |
2336 | if (use_json) |
2337 | json = json_object_new_object(); | |
2338 | ||
c0b4eaa4 MK |
2339 | args[0] = vty; |
2340 | args[1] = json; | |
89272910 | 2341 | hash_iterate(zrouter.l3vni_table, |
e3b78da8 | 2342 | (void (*)(struct hash_bucket *, |
c0b4eaa4 MK |
2343 | void *))zl3vni_print_rmac_hash_all_vni, |
2344 | args); | |
b7cfce93 MK |
2345 | |
2346 | if (use_json) { | |
2347 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2348 | json, JSON_C_TO_STRING_PRETTY)); | |
2349 | json_object_free(json); | |
2350 | } | |
2351 | } | |
2352 | ||
996c9314 | 2353 | void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, |
9f049418 | 2354 | struct ipaddr *ip, bool use_json) |
9aa741ea MK |
2355 | { |
2356 | zebra_l3vni_t *zl3vni = NULL; | |
2357 | zebra_neigh_t *n = NULL; | |
c0e519d3 | 2358 | json_object *json = NULL; |
9aa741ea | 2359 | |
c0e519d3 MK |
2360 | if (!is_evpn_enabled()) { |
2361 | if (use_json) | |
2362 | vty_out(vty, "{}\n"); | |
9aa741ea | 2363 | return; |
c0e519d3 MK |
2364 | } |
2365 | ||
2366 | if (use_json) | |
2367 | json = json_object_new_object(); | |
9aa741ea MK |
2368 | |
2369 | zl3vni = zl3vni_lookup(l3vni); | |
2370 | if (!zl3vni) { | |
c0e519d3 MK |
2371 | if (use_json) |
2372 | vty_out(vty, "{}\n"); | |
2373 | else | |
2374 | vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); | |
9aa741ea MK |
2375 | return; |
2376 | } | |
2377 | ||
2378 | n = zl3vni_nh_lookup(zl3vni, ip); | |
2379 | if (!n) { | |
c0e519d3 MK |
2380 | if (use_json) |
2381 | vty_out(vty, "{}\n"); | |
2382 | else | |
2383 | vty_out(vty, | |
2384 | "%% Requested next-hop not present for L3-VNI %u", | |
2385 | l3vni); | |
9aa741ea MK |
2386 | return; |
2387 | } | |
2388 | ||
c0e519d3 MK |
2389 | zl3vni_print_nh(n, vty, json); |
2390 | ||
2391 | if (use_json) { | |
2392 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2393 | json, JSON_C_TO_STRING_PRETTY)); | |
2394 | json_object_free(json); | |
2395 | } | |
9aa741ea MK |
2396 | } |
2397 | ||
9f049418 | 2398 | void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json) |
b7cfce93 | 2399 | { |
d7c0a89a | 2400 | uint32_t num_nh; |
2dbad57f | 2401 | struct nh_walk_ctx wctx; |
b7cfce93 | 2402 | json_object *json = NULL; |
b7cfce93 MK |
2403 | zebra_l3vni_t *zl3vni = NULL; |
2404 | ||
2405 | if (!is_evpn_enabled()) | |
2406 | return; | |
2407 | ||
2408 | zl3vni = zl3vni_lookup(l3vni); | |
2409 | if (!zl3vni) { | |
2410 | if (use_json) | |
2411 | vty_out(vty, "{}\n"); | |
2412 | else | |
2413 | vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); | |
2414 | return; | |
2415 | } | |
2416 | ||
2417 | num_nh = hashcount(zl3vni->nh_table); | |
2418 | if (!num_nh) | |
2419 | return; | |
2420 | ||
9187f600 | 2421 | if (use_json) |
b7cfce93 | 2422 | json = json_object_new_object(); |
b7cfce93 | 2423 | |
2dbad57f | 2424 | wctx.vty = vty; |
9187f600 | 2425 | wctx.json = json; |
b7cfce93 | 2426 | if (!use_json) { |
996c9314 | 2427 | vty_out(vty, "Number of NH Neighbors known for this VNI: %u\n", |
b7cfce93 | 2428 | num_nh); |
4cce389e | 2429 | vty_out(vty, "%-15s %-17s\n", "IP", "RMAC"); |
b7cfce93 | 2430 | } else |
4cce389e | 2431 | json_object_int_add(json, "numNextHops", num_nh); |
b7cfce93 MK |
2432 | |
2433 | hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx); | |
2434 | ||
2435 | if (use_json) { | |
b7cfce93 MK |
2436 | vty_out(vty, "%s\n", json_object_to_json_string_ext( |
2437 | json, JSON_C_TO_STRING_PRETTY)); | |
2438 | json_object_free(json); | |
2439 | } | |
2440 | } | |
2441 | ||
9f049418 | 2442 | void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json) |
b7cfce93 | 2443 | { |
2dbad57f | 2444 | json_object *json = NULL; |
32798965 | 2445 | void *args[2]; |
2dbad57f | 2446 | |
2447 | if (!is_evpn_enabled()) { | |
2448 | if (use_json) | |
2449 | vty_out(vty, "{}\n"); | |
2450 | return; | |
2451 | } | |
2452 | ||
2dbad57f | 2453 | if (use_json) |
2454 | json = json_object_new_object(); | |
2455 | ||
32798965 MK |
2456 | args[0] = vty; |
2457 | args[1] = json; | |
89272910 | 2458 | hash_iterate(zrouter.l3vni_table, |
e3b78da8 | 2459 | (void (*)(struct hash_bucket *, |
32798965 MK |
2460 | void *))zl3vni_print_nh_hash_all_vni, |
2461 | args); | |
2dbad57f | 2462 | |
2463 | if (use_json) { | |
2464 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2465 | json, JSON_C_TO_STRING_PRETTY)); | |
2466 | json_object_free(json); | |
2467 | } | |
b7cfce93 MK |
2468 | } |
2469 | ||
2470 | /* | |
2471 | * Display L3 VNI information (VTY command handler). | |
2472 | */ | |
9f049418 | 2473 | void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json) |
b7cfce93 MK |
2474 | { |
2475 | void *args[2]; | |
2476 | json_object *json = NULL; | |
2477 | zebra_l3vni_t *zl3vni = NULL; | |
2478 | ||
b2ee5a13 MK |
2479 | if (!is_evpn_enabled()) { |
2480 | if (use_json) | |
2481 | vty_out(vty, "{}\n"); | |
b7cfce93 | 2482 | return; |
b2ee5a13 | 2483 | } |
b7cfce93 MK |
2484 | |
2485 | zl3vni = zl3vni_lookup(vni); | |
2486 | if (!zl3vni) { | |
2487 | if (use_json) | |
2488 | vty_out(vty, "{}\n"); | |
2489 | else | |
2490 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
2491 | return; | |
2492 | } | |
2493 | ||
2494 | if (use_json) | |
2495 | json = json_object_new_object(); | |
2496 | ||
b2ee5a13 MK |
2497 | args[0] = vty; |
2498 | args[1] = json; | |
b7cfce93 MK |
2499 | zl3vni_print(zl3vni, (void *)args); |
2500 | ||
2501 | if (use_json) { | |
2502 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2503 | json, JSON_C_TO_STRING_PRETTY)); | |
2504 | json_object_free(json); | |
2505 | } | |
2506 | } | |
2507 | ||
4cce389e MK |
2508 | void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf, |
2509 | json_object *json_vrfs) | |
b7cfce93 | 2510 | { |
4cce389e MK |
2511 | char buf[ETHER_ADDR_STRLEN]; |
2512 | zebra_l3vni_t *zl3vni = NULL; | |
b7cfce93 | 2513 | |
4cce389e MK |
2514 | zl3vni = zl3vni_lookup(zvrf->l3vni); |
2515 | if (!zl3vni) | |
b7cfce93 | 2516 | return; |
b7cfce93 | 2517 | |
4cce389e MK |
2518 | if (!json_vrfs) { |
2519 | vty_out(vty, "%-37s %-10u %-20s %-20s %-5s %-18s\n", | |
996c9314 | 2520 | zvrf_name(zvrf), zl3vni->vni, |
4cce389e | 2521 | zl3vni_vxlan_if_name(zl3vni), |
996c9314 | 2522 | zl3vni_svi_if_name(zl3vni), zl3vni_state2str(zl3vni), |
4cce389e | 2523 | zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); |
b7cfce93 | 2524 | } else { |
4cce389e | 2525 | json_object *json_vrf = NULL; |
9df2b997 | 2526 | |
4cce389e | 2527 | json_vrf = json_object_new_object(); |
996c9314 | 2528 | json_object_string_add(json_vrf, "vrf", zvrf_name(zvrf)); |
4cce389e MK |
2529 | json_object_int_add(json_vrf, "vni", zl3vni->vni); |
2530 | json_object_string_add(json_vrf, "vxlanIntf", | |
2531 | zl3vni_vxlan_if_name(zl3vni)); | |
2532 | json_object_string_add(json_vrf, "sviIntf", | |
2533 | zl3vni_svi_if_name(zl3vni)); | |
2534 | json_object_string_add(json_vrf, "state", | |
2535 | zl3vni_state2str(zl3vni)); | |
996c9314 LB |
2536 | json_object_string_add( |
2537 | json_vrf, "routerMac", | |
2538 | zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); | |
4cce389e | 2539 | json_object_array_add(json_vrfs, json_vrf); |
b7cfce93 MK |
2540 | } |
2541 | } | |
2542 | ||
2543 | /* | |
2544 | * Display Neighbors for a VNI (VTY command handler). | |
2545 | */ | |
2546 | void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, | |
9f049418 | 2547 | vni_t vni, bool use_json) |
b7cfce93 | 2548 | { |
87d76d54 | 2549 | zebra_evpn_t *zevpn; |
d7c0a89a | 2550 | uint32_t num_neigh; |
b7cfce93 MK |
2551 | struct neigh_walk_ctx wctx; |
2552 | json_object *json = NULL; | |
2553 | ||
2554 | if (!is_evpn_enabled()) | |
2555 | return; | |
8b5fdf2e | 2556 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 2557 | if (!zevpn) { |
b7cfce93 MK |
2558 | if (use_json) |
2559 | vty_out(vty, "{}\n"); | |
2560 | else | |
2561 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
2562 | return; | |
2563 | } | |
87d76d54 | 2564 | num_neigh = hashcount(zevpn->neigh_table); |
b7cfce93 MK |
2565 | if (!num_neigh) |
2566 | return; | |
2567 | ||
2568 | if (use_json) | |
2569 | json = json_object_new_object(); | |
2570 | ||
2571 | /* Since we have IPv6 addresses to deal with which can vary widely in | |
2572 | * size, we try to be a bit more elegant in display by first computing | |
2573 | * the maximum width. | |
2574 | */ | |
2575 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); | |
87d76d54 | 2576 | wctx.zevpn = zevpn; |
b7cfce93 MK |
2577 | wctx.vty = vty; |
2578 | wctx.addr_width = 15; | |
2579 | wctx.json = json; | |
7cbae20a PR |
2580 | hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width, |
2581 | &wctx); | |
b7cfce93 MK |
2582 | |
2583 | if (!use_json) { | |
2584 | vty_out(vty, | |
2585 | "Number of ARPs (local and remote) known for this VNI: %u\n", | |
2586 | num_neigh); | |
7cbae20a | 2587 | zebra_evpn_print_neigh_hdr(vty, &wctx); |
b7cfce93 MK |
2588 | } else |
2589 | json_object_int_add(json, "numArpNd", num_neigh); | |
2590 | ||
7cbae20a | 2591 | hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash, &wctx); |
b7cfce93 MK |
2592 | if (use_json) { |
2593 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2594 | json, JSON_C_TO_STRING_PRETTY)); | |
2595 | json_object_free(json); | |
2596 | } | |
2597 | } | |
2598 | ||
2599 | /* | |
2600 | * Display neighbors across all VNIs (VTY command handler). | |
2601 | */ | |
2602 | void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, | |
1374d4db | 2603 | bool print_dup, bool use_json) |
b7cfce93 MK |
2604 | { |
2605 | json_object *json = NULL; | |
1374d4db | 2606 | void *args[3]; |
b7cfce93 MK |
2607 | |
2608 | if (!is_evpn_enabled()) | |
2609 | return; | |
2610 | ||
2611 | if (use_json) | |
2612 | json = json_object_new_object(); | |
2613 | ||
2614 | args[0] = vty; | |
2615 | args[1] = json; | |
1374d4db CS |
2616 | args[2] = (void *)(ptrdiff_t)print_dup; |
2617 | ||
87d76d54 | 2618 | hash_iterate(zvrf->evpn_table, |
e3b78da8 | 2619 | (void (*)(struct hash_bucket *, |
87d76d54 | 2620 | void *))zevpn_print_neigh_hash_all_evpn, |
b7cfce93 MK |
2621 | args); |
2622 | if (use_json) { | |
2623 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2624 | json, JSON_C_TO_STRING_PRETTY)); | |
2625 | json_object_free(json); | |
2626 | } | |
2627 | } | |
2628 | ||
e3fac919 NS |
2629 | /* |
2630 | * Display neighbors across all VNIs in detail(VTY command handler). | |
2631 | */ | |
2632 | void zebra_vxlan_print_neigh_all_vni_detail(struct vty *vty, | |
2633 | struct zebra_vrf *zvrf, | |
2634 | bool print_dup, bool use_json) | |
2635 | { | |
2636 | json_object *json = NULL; | |
2637 | void *args[3]; | |
2638 | ||
2639 | if (!is_evpn_enabled()) | |
2640 | return; | |
2641 | ||
2642 | if (use_json) | |
2643 | json = json_object_new_object(); | |
2644 | ||
2645 | args[0] = vty; | |
2646 | args[1] = json; | |
2647 | args[2] = (void *)(ptrdiff_t)print_dup; | |
2648 | ||
87d76d54 | 2649 | hash_iterate(zvrf->evpn_table, |
e3b78da8 | 2650 | (void (*)(struct hash_bucket *, |
87d76d54 | 2651 | void *))zevpn_print_neigh_hash_all_evpn_detail, |
e3fac919 NS |
2652 | args); |
2653 | if (use_json) { | |
2654 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2655 | json, JSON_C_TO_STRING_PRETTY)); | |
2656 | json_object_free(json); | |
2657 | } | |
2658 | } | |
2659 | ||
b7cfce93 MK |
2660 | /* |
2661 | * Display specific neighbor for a VNI, if present (VTY command handler). | |
2662 | */ | |
2663 | void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, | |
2664 | struct zebra_vrf *zvrf, vni_t vni, | |
9f049418 | 2665 | struct ipaddr *ip, bool use_json) |
b7cfce93 | 2666 | { |
87d76d54 | 2667 | zebra_evpn_t *zevpn; |
b7cfce93 MK |
2668 | zebra_neigh_t *n; |
2669 | json_object *json = NULL; | |
2670 | ||
2671 | if (!is_evpn_enabled()) | |
2672 | return; | |
8b5fdf2e | 2673 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 2674 | if (!zevpn) { |
b7cfce93 | 2675 | if (use_json) |
cd233079 CS |
2676 | vty_out(vty, "{}\n"); |
2677 | else | |
2678 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2679 | return; |
2680 | } | |
7cbae20a | 2681 | n = zebra_evpn_neigh_lookup(zevpn, ip); |
d62a17ae | 2682 | if (!n) { |
cd233079 CS |
2683 | if (!use_json) |
2684 | vty_out(vty, | |
2685 | "%% Requested neighbor does not exist in VNI %u\n", | |
2686 | vni); | |
d62a17ae | 2687 | return; |
2688 | } | |
cd233079 CS |
2689 | if (use_json) |
2690 | json = json_object_new_object(); | |
2691 | ||
7cbae20a | 2692 | zebra_evpn_print_neigh(n, vty, json); |
cec2e17d | 2693 | |
cd233079 CS |
2694 | if (use_json) { |
2695 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2696 | json, JSON_C_TO_STRING_PRETTY)); | |
2697 | json_object_free(json); | |
2698 | } | |
cec2e17d | 2699 | } |
2700 | ||
2701 | /* | |
2702 | * Display neighbors for a VNI from specific VTEP (VTY command handler). | |
2703 | * By definition, these are remote neighbors. | |
2704 | */ | |
d62a17ae | 2705 | void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, |
cd233079 | 2706 | vni_t vni, struct in_addr vtep_ip, |
9f049418 | 2707 | bool use_json) |
cec2e17d | 2708 | { |
87d76d54 | 2709 | zebra_evpn_t *zevpn; |
d7c0a89a | 2710 | uint32_t num_neigh; |
d62a17ae | 2711 | struct neigh_walk_ctx wctx; |
cd233079 | 2712 | json_object *json = NULL; |
cec2e17d | 2713 | |
2853fed6 | 2714 | if (!is_evpn_enabled()) |
d62a17ae | 2715 | return; |
8b5fdf2e | 2716 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 2717 | if (!zevpn) { |
cd233079 CS |
2718 | if (use_json) |
2719 | vty_out(vty, "{}\n"); | |
2720 | else | |
2721 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2722 | return; |
2723 | } | |
87d76d54 | 2724 | num_neigh = hashcount(zevpn->neigh_table); |
d62a17ae | 2725 | if (!num_neigh) |
2726 | return; | |
cec2e17d | 2727 | |
1cc5b093 PR |
2728 | if (use_json) |
2729 | json = json_object_new_object(); | |
2730 | ||
d62a17ae | 2731 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); |
87d76d54 | 2732 | wctx.zevpn = zevpn; |
d62a17ae | 2733 | wctx.vty = vty; |
68e33151 | 2734 | wctx.addr_width = 15; |
d62a17ae | 2735 | wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP; |
2736 | wctx.r_vtep_ip = vtep_ip; | |
cd233079 | 2737 | wctx.json = json; |
7cbae20a PR |
2738 | hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width, |
2739 | &wctx); | |
2740 | hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash, &wctx); | |
cd233079 CS |
2741 | |
2742 | if (use_json) { | |
2743 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2744 | json, JSON_C_TO_STRING_PRETTY)); | |
2745 | json_object_free(json); | |
2746 | } | |
cec2e17d | 2747 | } |
2748 | ||
1374d4db CS |
2749 | /* |
2750 | * Display Duplicate detected Neighbors for a VNI | |
2751 | * (VTY command handler). | |
2752 | */ | |
2753 | void zebra_vxlan_print_neigh_vni_dad(struct vty *vty, | |
2754 | struct zebra_vrf *zvrf, | |
2755 | vni_t vni, | |
2756 | bool use_json) | |
2757 | { | |
87d76d54 | 2758 | zebra_evpn_t *zevpn; |
1374d4db CS |
2759 | uint32_t num_neigh; |
2760 | struct neigh_walk_ctx wctx; | |
2761 | json_object *json = NULL; | |
2762 | ||
2763 | if (!is_evpn_enabled()) | |
2764 | return; | |
2765 | ||
8b5fdf2e | 2766 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 2767 | if (!zevpn) { |
1374d4db CS |
2768 | vty_out(vty, "%% VNI %u does not exist\n", vni); |
2769 | return; | |
2770 | } | |
2771 | ||
87d76d54 | 2772 | num_neigh = hashcount(zevpn->neigh_table); |
1374d4db CS |
2773 | if (!num_neigh) |
2774 | return; | |
2775 | ||
87d76d54 | 2776 | num_neigh = num_dup_detected_neighs(zevpn); |
1374d4db CS |
2777 | if (!num_neigh) |
2778 | return; | |
2779 | ||
2780 | if (use_json) | |
2781 | json = json_object_new_object(); | |
2782 | ||
2783 | /* Since we have IPv6 addresses to deal with which can vary widely in | |
2784 | * size, we try to be a bit more elegant in display by first computing | |
2785 | * the maximum width. | |
2786 | */ | |
2787 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); | |
87d76d54 | 2788 | wctx.zevpn = zevpn; |
1374d4db CS |
2789 | wctx.vty = vty; |
2790 | wctx.addr_width = 15; | |
2791 | wctx.json = json; | |
7cbae20a PR |
2792 | hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width, |
2793 | &wctx); | |
1374d4db CS |
2794 | |
2795 | if (!use_json) { | |
2796 | vty_out(vty, | |
2797 | "Number of ARPs (local and remote) known for this VNI: %u\n", | |
2798 | num_neigh); | |
ce5160c0 | 2799 | vty_out(vty, "%*s %-6s %-8s %-17s %-30s\n", |
1374d4db | 2800 | -wctx.addr_width, "IP", "Type", |
ce5160c0 | 2801 | "State", "MAC", "Remote ES/VTEP"); |
1374d4db CS |
2802 | } else |
2803 | json_object_int_add(json, "numArpNd", num_neigh); | |
2804 | ||
7cbae20a PR |
2805 | hash_iterate(zevpn->neigh_table, zebra_evpn_print_dad_neigh_hash, |
2806 | &wctx); | |
1374d4db CS |
2807 | |
2808 | if (use_json) { | |
2809 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2810 | json, JSON_C_TO_STRING_PRETTY)); | |
2811 | json_object_free(json); | |
2812 | } | |
2813 | } | |
2814 | ||
cec2e17d | 2815 | /* |
2816 | * Display MACs for a VNI (VTY command handler). | |
2817 | */ | |
d62a17ae | 2818 | void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, |
9f049418 | 2819 | vni_t vni, bool use_json) |
cec2e17d | 2820 | { |
87d76d54 | 2821 | zebra_evpn_t *zevpn; |
d7c0a89a | 2822 | uint32_t num_macs; |
d62a17ae | 2823 | struct mac_walk_ctx wctx; |
cd233079 CS |
2824 | json_object *json = NULL; |
2825 | json_object *json_mac = NULL; | |
cec2e17d | 2826 | |
2853fed6 | 2827 | if (!is_evpn_enabled()) |
d62a17ae | 2828 | return; |
8b5fdf2e | 2829 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 2830 | if (!zevpn) { |
cd233079 CS |
2831 | if (use_json) |
2832 | vty_out(vty, "{}\n"); | |
2833 | else | |
2834 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2835 | return; |
2836 | } | |
87d76d54 | 2837 | num_macs = num_valid_macs(zevpn); |
d62a17ae | 2838 | if (!num_macs) |
2839 | return; | |
cec2e17d | 2840 | |
cd233079 CS |
2841 | if (use_json) { |
2842 | json = json_object_new_object(); | |
2843 | json_mac = json_object_new_object(); | |
2844 | } | |
2845 | ||
d62a17ae | 2846 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
87d76d54 | 2847 | wctx.zevpn = zevpn; |
d62a17ae | 2848 | wctx.vty = vty; |
cd233079 | 2849 | wctx.json = json_mac; |
cec2e17d | 2850 | |
cd233079 CS |
2851 | if (!use_json) { |
2852 | vty_out(vty, | |
2853 | "Number of MACs (local and remote) known for this VNI: %u\n", | |
2854 | num_macs); | |
b169fd6f AK |
2855 | vty_out(vty, |
2856 | "Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n"); | |
2857 | vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC", | |
2858 | "Type", "Flags", "Intf/Remote ES/VTEP", | |
2859 | "VLAN", "Seq #'s"); | |
cd233079 CS |
2860 | } else |
2861 | json_object_int_add(json, "numMacs", num_macs); | |
cec2e17d | 2862 | |
b2998086 | 2863 | hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash, &wctx); |
cd233079 CS |
2864 | |
2865 | if (use_json) { | |
2866 | json_object_object_add(json, "macs", json_mac); | |
2867 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2868 | json, JSON_C_TO_STRING_PRETTY)); | |
2869 | json_object_free(json); | |
2870 | } | |
cec2e17d | 2871 | } |
2872 | ||
2873 | /* | |
2874 | * Display MACs for all VNIs (VTY command handler). | |
2875 | */ | |
cd233079 | 2876 | void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf, |
1374d4db | 2877 | bool print_dup, bool use_json) |
cec2e17d | 2878 | { |
d62a17ae | 2879 | struct mac_walk_ctx wctx; |
cd233079 | 2880 | json_object *json = NULL; |
cec2e17d | 2881 | |
2853fed6 | 2882 | if (!is_evpn_enabled()) { |
cd233079 CS |
2883 | if (use_json) |
2884 | vty_out(vty, "{}\n"); | |
d62a17ae | 2885 | return; |
cd233079 CS |
2886 | } |
2887 | if (use_json) | |
2888 | json = json_object_new_object(); | |
2889 | ||
d62a17ae | 2890 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
2891 | wctx.vty = vty; | |
cd233079 | 2892 | wctx.json = json; |
1374d4db | 2893 | wctx.print_dup = print_dup; |
87d76d54 | 2894 | hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn, &wctx); |
cd233079 CS |
2895 | |
2896 | if (use_json) { | |
2897 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2898 | json, JSON_C_TO_STRING_PRETTY)); | |
2899 | json_object_free(json); | |
2900 | } | |
cec2e17d | 2901 | } |
2902 | ||
cffe7580 NS |
2903 | /* |
2904 | * Display MACs in detail for all VNIs (VTY command handler). | |
2905 | */ | |
2906 | void zebra_vxlan_print_macs_all_vni_detail(struct vty *vty, | |
2907 | struct zebra_vrf *zvrf, | |
2908 | bool print_dup, bool use_json) | |
2909 | { | |
2910 | struct mac_walk_ctx wctx; | |
2911 | json_object *json = NULL; | |
2912 | ||
2913 | if (!is_evpn_enabled()) { | |
2914 | if (use_json) | |
2915 | vty_out(vty, "{}\n"); | |
2916 | return; | |
2917 | } | |
2918 | if (use_json) | |
2919 | json = json_object_new_object(); | |
2920 | ||
2921 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); | |
2922 | wctx.vty = vty; | |
2923 | wctx.json = json; | |
2924 | wctx.print_dup = print_dup; | |
87d76d54 | 2925 | hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn_detail, |
cffe7580 NS |
2926 | &wctx); |
2927 | ||
2928 | if (use_json) { | |
2929 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2930 | json, JSON_C_TO_STRING_PRETTY)); | |
2931 | json_object_free(json); | |
2932 | } | |
2933 | } | |
2934 | ||
cec2e17d | 2935 | /* |
2936 | * Display MACs for all VNIs (VTY command handler). | |
2937 | */ | |
d62a17ae | 2938 | void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty, |
2939 | struct zebra_vrf *zvrf, | |
9f049418 | 2940 | struct in_addr vtep_ip, bool use_json) |
cec2e17d | 2941 | { |
d62a17ae | 2942 | struct mac_walk_ctx wctx; |
cd233079 | 2943 | json_object *json = NULL; |
cec2e17d | 2944 | |
2853fed6 | 2945 | if (!is_evpn_enabled()) |
d62a17ae | 2946 | return; |
cd233079 CS |
2947 | |
2948 | if (use_json) | |
2949 | json = json_object_new_object(); | |
2950 | ||
d62a17ae | 2951 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
2952 | wctx.vty = vty; | |
2953 | wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; | |
2954 | wctx.r_vtep_ip = vtep_ip; | |
cd233079 | 2955 | wctx.json = json; |
87d76d54 | 2956 | hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn, &wctx); |
cd233079 CS |
2957 | |
2958 | if (use_json) { | |
2959 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2960 | json, JSON_C_TO_STRING_PRETTY)); | |
2961 | json_object_free(json); | |
2962 | } | |
cec2e17d | 2963 | } |
2964 | ||
2965 | /* | |
2966 | * Display specific MAC for a VNI, if present (VTY command handler). | |
2967 | */ | |
d62a17ae | 2968 | void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf, |
24cdbd0d DS |
2969 | vni_t vni, struct ethaddr *macaddr, |
2970 | bool use_json) | |
cec2e17d | 2971 | { |
87d76d54 | 2972 | zebra_evpn_t *zevpn; |
d62a17ae | 2973 | zebra_mac_t *mac; |
24cdbd0d | 2974 | json_object *json = NULL; |
cec2e17d | 2975 | |
2853fed6 | 2976 | if (!is_evpn_enabled()) |
d62a17ae | 2977 | return; |
24cdbd0d | 2978 | |
8b5fdf2e | 2979 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 2980 | if (!zevpn) { |
24cdbd0d DS |
2981 | if (use_json) |
2982 | vty_out(vty, "{}\n"); | |
2983 | else | |
2984 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2985 | return; |
2986 | } | |
b2998086 | 2987 | mac = zebra_evpn_mac_lookup(zevpn, macaddr); |
d62a17ae | 2988 | if (!mac) { |
24cdbd0d DS |
2989 | if (use_json) |
2990 | vty_out(vty, "{}\n"); | |
2991 | else | |
2992 | vty_out(vty, | |
2993 | "%% Requested MAC does not exist in VNI %u\n", | |
2994 | vni); | |
d62a17ae | 2995 | return; |
2996 | } | |
cec2e17d | 2997 | |
24cdbd0d DS |
2998 | if (use_json) |
2999 | json = json_object_new_object(); | |
3000 | ||
b2998086 | 3001 | zebra_evpn_print_mac(mac, vty, json); |
cffe7580 NS |
3002 | if (use_json) { |
3003 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
3004 | json, JSON_C_TO_STRING_PRETTY)); | |
3005 | json_object_free(json); | |
3006 | } | |
cec2e17d | 3007 | } |
3008 | ||
1374d4db CS |
3009 | /* Print Duplicate MACs per VNI */ |
3010 | void zebra_vxlan_print_macs_vni_dad(struct vty *vty, | |
3011 | struct zebra_vrf *zvrf, | |
3012 | vni_t vni, bool use_json) | |
3013 | { | |
87d76d54 | 3014 | zebra_evpn_t *zevpn; |
1374d4db CS |
3015 | struct mac_walk_ctx wctx; |
3016 | uint32_t num_macs; | |
3017 | json_object *json = NULL; | |
3018 | json_object *json_mac = NULL; | |
3019 | ||
3020 | if (!is_evpn_enabled()) | |
3021 | return; | |
3022 | ||
8b5fdf2e | 3023 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 3024 | if (!zevpn) { |
1374d4db CS |
3025 | vty_out(vty, "%% VNI %u does not exist\n", vni); |
3026 | return; | |
3027 | } | |
3028 | ||
87d76d54 | 3029 | num_macs = num_valid_macs(zevpn); |
1374d4db CS |
3030 | if (!num_macs) |
3031 | return; | |
3032 | ||
87d76d54 | 3033 | num_macs = num_dup_detected_macs(zevpn); |
1374d4db CS |
3034 | if (!num_macs) |
3035 | return; | |
3036 | ||
3037 | if (use_json) { | |
3038 | json = json_object_new_object(); | |
3039 | json_mac = json_object_new_object(); | |
3040 | } | |
3041 | ||
3042 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); | |
87d76d54 | 3043 | wctx.zevpn = zevpn; |
1374d4db CS |
3044 | wctx.vty = vty; |
3045 | wctx.json = json_mac; | |
3046 | ||
3047 | if (!use_json) { | |
3048 | vty_out(vty, | |
3049 | "Number of MACs (local and remote) known for this VNI: %u\n", | |
3050 | num_macs); | |
b169fd6f AK |
3051 | vty_out(vty, "%-17s %-6s %-5s %-30s %-5s\n", "MAC", "Type", |
3052 | "Flags", "Intf/Remote ES/VTEP", "VLAN"); | |
1374d4db CS |
3053 | } else |
3054 | json_object_int_add(json, "numMacs", num_macs); | |
3055 | ||
b2998086 | 3056 | hash_iterate(zevpn->mac_table, zebra_evpn_print_dad_mac_hash, &wctx); |
1374d4db CS |
3057 | |
3058 | if (use_json) { | |
3059 | json_object_object_add(json, "macs", json_mac); | |
3060 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
3061 | json, JSON_C_TO_STRING_PRETTY)); | |
3062 | json_object_free(json); | |
3063 | } | |
3064 | ||
3065 | } | |
3066 | ||
e20755b2 | 3067 | int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni, |
9bee0232 CS |
3068 | struct ethaddr *macaddr, char *errmsg, |
3069 | size_t errmsg_len) | |
09de9258 | 3070 | { |
87d76d54 | 3071 | zebra_evpn_t *zevpn; |
09de9258 CS |
3072 | zebra_mac_t *mac; |
3073 | struct listnode *node = NULL; | |
3074 | zebra_neigh_t *nbr = NULL; | |
3075 | ||
3076 | if (!is_evpn_enabled()) | |
e20755b2 | 3077 | return 0; |
1883de66 | 3078 | |
8b5fdf2e | 3079 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 3080 | if (!zevpn) { |
9bee0232 | 3081 | snprintfrr(errmsg, errmsg_len, "VNI %u does not exist", vni); |
e20755b2 | 3082 | return -1; |
09de9258 CS |
3083 | } |
3084 | ||
b2998086 | 3085 | mac = zebra_evpn_mac_lookup(zevpn, macaddr); |
09de9258 | 3086 | if (!mac) { |
9bee0232 CS |
3087 | snprintf(errmsg, errmsg_len, |
3088 | "Requested MAC does not exist in VNI %u\n", vni); | |
e20755b2 | 3089 | return -1; |
09de9258 CS |
3090 | } |
3091 | ||
3092 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { | |
9bee0232 CS |
3093 | snprintfrr(errmsg, errmsg_len, |
3094 | "Requested MAC is not duplicate detected\n"); | |
e20755b2 | 3095 | return -1; |
09de9258 CS |
3096 | } |
3097 | ||
3098 | /* Remove all IPs as duplicate associcated with this MAC */ | |
3099 | for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) { | |
3100 | /* For local neigh mark inactive so MACIP update is generated | |
3101 | * to BGP. This is a scenario where MAC update received | |
3102 | * and detected as duplicate which marked neigh as duplicate. | |
3103 | * Later local neigh update did not get a chance to relay | |
3104 | * to BGP. Similarly remote macip update, neigh needs to be | |
3105 | * installed locally. | |
3106 | */ | |
d4199657 CS |
3107 | if (zvrf->dad_freeze && |
3108 | CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) { | |
09de9258 CS |
3109 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) |
3110 | ZEBRA_NEIGH_SET_INACTIVE(nbr); | |
3111 | else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) | |
b2998086 PR |
3112 | zebra_evpn_rem_neigh_install( |
3113 | zevpn, nbr, false /*was_static*/); | |
09de9258 CS |
3114 | } |
3115 | ||
3116 | UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
3117 | nbr->dad_count = 0; | |
3118 | nbr->detect_start_time.tv_sec = 0; | |
3119 | nbr->dad_dup_detect_time = 0; | |
3120 | } | |
3121 | ||
3122 | UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE); | |
3123 | mac->dad_count = 0; | |
3124 | mac->detect_start_time.tv_sec = 0; | |
3125 | mac->detect_start_time.tv_usec = 0; | |
3126 | mac->dad_dup_detect_time = 0; | |
3127 | THREAD_OFF(mac->dad_mac_auto_recovery_timer); | |
3128 | ||
d4199657 CS |
3129 | /* warn-only action return */ |
3130 | if (!zvrf->dad_freeze) | |
e20755b2 | 3131 | return 0; |
d4199657 | 3132 | |
09de9258 CS |
3133 | /* Local: Notify Peer VTEPs, Remote: Install the entry */ |
3134 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
3135 | /* Inform to BGP */ | |
b2998086 PR |
3136 | if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr, |
3137 | mac->flags, mac->loc_seq, | |
3138 | mac->es)) | |
e20755b2 | 3139 | return 0; |
09de9258 CS |
3140 | |
3141 | /* Process all neighbors associated with this MAC. */ | |
b2998086 PR |
3142 | zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, |
3143 | 0 /*es_change*/); | |
09de9258 CS |
3144 | |
3145 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { | |
b2998086 | 3146 | zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac); |
09de9258 CS |
3147 | |
3148 | /* Install the entry. */ | |
b2998086 | 3149 | zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */); |
09de9258 CS |
3150 | } |
3151 | ||
e20755b2 | 3152 | return 0; |
09de9258 CS |
3153 | } |
3154 | ||
e20755b2 | 3155 | int zebra_vxlan_clear_dup_detect_vni_ip(struct zebra_vrf *zvrf, vni_t vni, |
9bee0232 CS |
3156 | struct ipaddr *ip, char *errmsg, |
3157 | size_t errmsg_len) | |
09de9258 | 3158 | { |
87d76d54 | 3159 | zebra_evpn_t *zevpn; |
09de9258 CS |
3160 | zebra_neigh_t *nbr; |
3161 | zebra_mac_t *mac; | |
3162 | char buf[INET6_ADDRSTRLEN]; | |
3163 | char buf2[ETHER_ADDR_STRLEN]; | |
3164 | ||
3165 | if (!is_evpn_enabled()) | |
e20755b2 | 3166 | return 0; |
09de9258 | 3167 | |
8b5fdf2e | 3168 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 3169 | if (!zevpn) { |
9bee0232 | 3170 | snprintfrr(errmsg, errmsg_len, "VNI %u does not exist\n", vni); |
e20755b2 | 3171 | return -1; |
09de9258 CS |
3172 | } |
3173 | ||
7cbae20a | 3174 | nbr = zebra_evpn_neigh_lookup(zevpn, ip); |
09de9258 | 3175 | if (!nbr) { |
9bee0232 CS |
3176 | snprintfrr(errmsg, errmsg_len, |
3177 | "Requested host IP does not exist in VNI %u\n", vni); | |
e20755b2 | 3178 | return -1; |
09de9258 CS |
3179 | } |
3180 | ||
3181 | ipaddr2str(&nbr->ip, buf, sizeof(buf)); | |
3182 | ||
3183 | if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) { | |
9bee0232 CS |
3184 | snprintfrr(errmsg, errmsg_len, |
3185 | "Requested host IP %s is not duplicate detected\n", | |
3186 | buf); | |
e20755b2 | 3187 | return -1; |
09de9258 CS |
3188 | } |
3189 | ||
b2998086 | 3190 | mac = zebra_evpn_mac_lookup(zevpn, &nbr->emac); |
09de9258 CS |
3191 | |
3192 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { | |
9bee0232 CS |
3193 | snprintfrr( |
3194 | errmsg, errmsg_len, | |
e20755b2 | 3195 | "Requested IP's associated MAC %s is still in duplicate state\n", |
09de9258 | 3196 | prefix_mac2str(&nbr->emac, buf2, sizeof(buf2))); |
e20755b2 | 3197 | return -1; |
09de9258 CS |
3198 | } |
3199 | ||
3200 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3201 | zlog_debug("%s: clear neigh %s in dup state, flags 0x%x seq %u", | |
15569c58 | 3202 | __func__, buf, nbr->flags, nbr->loc_seq); |
09de9258 CS |
3203 | |
3204 | UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
3205 | nbr->dad_count = 0; | |
3206 | nbr->detect_start_time.tv_sec = 0; | |
3207 | nbr->detect_start_time.tv_usec = 0; | |
3208 | nbr->dad_dup_detect_time = 0; | |
3209 | THREAD_OFF(nbr->dad_ip_auto_recovery_timer); | |
3210 | ||
3211 | if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) { | |
7cbae20a PR |
3212 | zebra_evpn_neigh_send_add_to_client(zevpn->vni, ip, &nbr->emac, |
3213 | nbr->mac, nbr->flags, | |
3214 | nbr->loc_seq); | |
09de9258 | 3215 | } else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) { |
b2998086 | 3216 | zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/); |
09de9258 CS |
3217 | } |
3218 | ||
e20755b2 | 3219 | return 0; |
09de9258 CS |
3220 | } |
3221 | ||
87d76d54 | 3222 | static void zevpn_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt) |
09de9258 CS |
3223 | { |
3224 | struct mac_walk_ctx *wctx = ctxt; | |
3225 | zebra_mac_t *mac; | |
87d76d54 | 3226 | zebra_evpn_t *zevpn; |
09de9258 CS |
3227 | struct listnode *node = NULL; |
3228 | zebra_neigh_t *nbr = NULL; | |
3229 | ||
e3b78da8 | 3230 | mac = (zebra_mac_t *)bucket->data; |
09de9258 CS |
3231 | if (!mac) |
3232 | return; | |
3233 | ||
87d76d54 | 3234 | zevpn = wctx->zevpn; |
09de9258 CS |
3235 | |
3236 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) | |
3237 | return; | |
3238 | ||
3239 | UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE); | |
3240 | mac->dad_count = 0; | |
3241 | mac->detect_start_time.tv_sec = 0; | |
3242 | mac->detect_start_time.tv_usec = 0; | |
3243 | mac->dad_dup_detect_time = 0; | |
3244 | THREAD_OFF(mac->dad_mac_auto_recovery_timer); | |
3245 | ||
3246 | /* Remove all IPs as duplicate associcated with this MAC */ | |
3247 | for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) { | |
3248 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL) | |
3249 | && nbr->dad_count) | |
3250 | ZEBRA_NEIGH_SET_INACTIVE(nbr); | |
3251 | ||
3252 | UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
3253 | nbr->dad_count = 0; | |
3254 | nbr->detect_start_time.tv_sec = 0; | |
3255 | nbr->dad_dup_detect_time = 0; | |
3256 | } | |
3257 | ||
3258 | /* Local: Notify Peer VTEPs, Remote: Install the entry */ | |
3259 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
3260 | /* Inform to BGP */ | |
b2998086 PR |
3261 | if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr, |
3262 | mac->flags, mac->loc_seq, | |
3263 | mac->es)) | |
09de9258 CS |
3264 | return; |
3265 | ||
3266 | /* Process all neighbors associated with this MAC. */ | |
b2998086 PR |
3267 | zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, |
3268 | 0 /*es_change*/); | |
09de9258 CS |
3269 | |
3270 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { | |
b2998086 | 3271 | zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac); |
09de9258 CS |
3272 | |
3273 | /* Install the entry. */ | |
b2998086 | 3274 | zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */); |
09de9258 CS |
3275 | } |
3276 | } | |
3277 | ||
87d76d54 | 3278 | static void zevpn_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket, |
09de9258 CS |
3279 | void **args) |
3280 | { | |
87d76d54 | 3281 | zebra_evpn_t *zevpn; |
09de9258 CS |
3282 | struct zebra_vrf *zvrf; |
3283 | struct mac_walk_ctx m_wctx; | |
3284 | struct neigh_walk_ctx n_wctx; | |
3285 | ||
87d76d54 PR |
3286 | zevpn = (zebra_evpn_t *)bucket->data; |
3287 | if (!zevpn) | |
09de9258 CS |
3288 | return; |
3289 | ||
e20755b2 | 3290 | zvrf = (struct zebra_vrf *)args[0]; |
09de9258 | 3291 | |
87d76d54 | 3292 | if (hashcount(zevpn->neigh_table)) { |
09de9258 | 3293 | memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); |
87d76d54 | 3294 | n_wctx.zevpn = zevpn; |
09de9258 | 3295 | n_wctx.zvrf = zvrf; |
7cbae20a PR |
3296 | hash_iterate(zevpn->neigh_table, |
3297 | zebra_evpn_clear_dup_neigh_hash, &n_wctx); | |
09de9258 CS |
3298 | } |
3299 | ||
87d76d54 | 3300 | if (num_valid_macs(zevpn)) { |
09de9258 | 3301 | memset(&m_wctx, 0, sizeof(struct mac_walk_ctx)); |
87d76d54 | 3302 | m_wctx.zevpn = zevpn; |
09de9258 | 3303 | m_wctx.zvrf = zvrf; |
87d76d54 | 3304 | hash_iterate(zevpn->mac_table, zevpn_clear_dup_mac_hash, &m_wctx); |
09de9258 CS |
3305 | } |
3306 | ||
3307 | } | |
3308 | ||
e20755b2 | 3309 | int zebra_vxlan_clear_dup_detect_vni_all(struct zebra_vrf *zvrf) |
09de9258 | 3310 | { |
e20755b2 | 3311 | void *args[1]; |
09de9258 CS |
3312 | |
3313 | if (!is_evpn_enabled()) | |
e20755b2 | 3314 | return 0; |
09de9258 | 3315 | |
e20755b2 | 3316 | args[0] = zvrf; |
09de9258 | 3317 | |
87d76d54 | 3318 | hash_iterate(zvrf->evpn_table, |
e3b78da8 | 3319 | (void (*)(struct hash_bucket *, void *)) |
87d76d54 | 3320 | zevpn_clear_dup_detect_hash_vni_all, args); |
09de9258 | 3321 | |
e20755b2 | 3322 | return 0; |
09de9258 CS |
3323 | } |
3324 | ||
e20755b2 | 3325 | int zebra_vxlan_clear_dup_detect_vni(struct zebra_vrf *zvrf, vni_t vni) |
09de9258 | 3326 | { |
87d76d54 | 3327 | zebra_evpn_t *zevpn; |
09de9258 CS |
3328 | struct mac_walk_ctx m_wctx; |
3329 | struct neigh_walk_ctx n_wctx; | |
3330 | ||
3331 | if (!is_evpn_enabled()) | |
e20755b2 | 3332 | return 0; |
09de9258 | 3333 | |
8b5fdf2e | 3334 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 3335 | if (!zevpn) { |
e20755b2 | 3336 | zlog_warn("VNI %u does not exist\n", vni); |
87d76d54 | 3337 | return CMD_WARNING; |
09de9258 CS |
3338 | } |
3339 | ||
87d76d54 | 3340 | if (hashcount(zevpn->neigh_table)) { |
09de9258 | 3341 | memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); |
87d76d54 | 3342 | n_wctx.zevpn = zevpn; |
09de9258 | 3343 | n_wctx.zvrf = zvrf; |
7cbae20a PR |
3344 | hash_iterate(zevpn->neigh_table, |
3345 | zebra_evpn_clear_dup_neigh_hash, &n_wctx); | |
09de9258 CS |
3346 | } |
3347 | ||
87d76d54 | 3348 | if (num_valid_macs(zevpn)) { |
09de9258 | 3349 | memset(&m_wctx, 0, sizeof(struct mac_walk_ctx)); |
87d76d54 | 3350 | m_wctx.zevpn = zevpn; |
09de9258 | 3351 | m_wctx.zvrf = zvrf; |
87d76d54 | 3352 | hash_iterate(zevpn->mac_table, zevpn_clear_dup_mac_hash, &m_wctx); |
09de9258 CS |
3353 | } |
3354 | ||
e20755b2 | 3355 | return 0; |
09de9258 CS |
3356 | } |
3357 | ||
cec2e17d | 3358 | /* |
3359 | * Display MACs for a VNI from specific VTEP (VTY command handler). | |
3360 | */ | |
d62a17ae | 3361 | void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, |
cd233079 | 3362 | vni_t vni, struct in_addr vtep_ip, |
9f049418 | 3363 | bool use_json) |
cec2e17d | 3364 | { |
87d76d54 | 3365 | zebra_evpn_t *zevpn; |
d7c0a89a | 3366 | uint32_t num_macs; |
d62a17ae | 3367 | struct mac_walk_ctx wctx; |
cd233079 CS |
3368 | json_object *json = NULL; |
3369 | json_object *json_mac = NULL; | |
cec2e17d | 3370 | |
2853fed6 | 3371 | if (!is_evpn_enabled()) |
d62a17ae | 3372 | return; |
8b5fdf2e | 3373 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 3374 | if (!zevpn) { |
cd233079 CS |
3375 | if (use_json) |
3376 | vty_out(vty, "{}\n"); | |
3377 | else | |
3378 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 3379 | return; |
3380 | } | |
87d76d54 | 3381 | num_macs = num_valid_macs(zevpn); |
d62a17ae | 3382 | if (!num_macs) |
3383 | return; | |
cd233079 CS |
3384 | |
3385 | if (use_json) { | |
3386 | json = json_object_new_object(); | |
3387 | json_mac = json_object_new_object(); | |
3388 | } | |
3389 | ||
d62a17ae | 3390 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
87d76d54 | 3391 | wctx.zevpn = zevpn; |
d62a17ae | 3392 | wctx.vty = vty; |
3393 | wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; | |
3394 | wctx.r_vtep_ip = vtep_ip; | |
cd233079 | 3395 | wctx.json = json_mac; |
b2998086 | 3396 | hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash, &wctx); |
cd233079 CS |
3397 | |
3398 | if (use_json) { | |
3399 | json_object_int_add(json, "numMacs", wctx.count); | |
3400 | if (wctx.count) | |
3401 | json_object_object_add(json, "macs", json_mac); | |
3402 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
3403 | json, JSON_C_TO_STRING_PRETTY)); | |
3404 | json_object_free(json); | |
3405 | } | |
cec2e17d | 3406 | } |
3407 | ||
3408 | ||
3409 | /* | |
3410 | * Display VNI information (VTY command handler). | |
06931fdb LK |
3411 | * |
3412 | * use_json flag indicates that output should be in JSON format. | |
3413 | * json_array is non NULL when JSON output needs to be aggregated (by the | |
3414 | * caller) and then printed, otherwise, JSON evpn vni info is printed | |
3415 | * right away. | |
cec2e17d | 3416 | */ |
cd233079 | 3417 | void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, |
06931fdb | 3418 | bool use_json, json_object *json_array) |
cec2e17d | 3419 | { |
cd233079 CS |
3420 | json_object *json = NULL; |
3421 | void *args[2]; | |
1f2129ec | 3422 | zebra_l3vni_t *zl3vni = NULL; |
87d76d54 | 3423 | zebra_evpn_t *zevpn = NULL; |
cec2e17d | 3424 | |
2853fed6 | 3425 | if (!is_evpn_enabled()) |
d62a17ae | 3426 | return; |
4cce389e | 3427 | |
cd233079 CS |
3428 | if (use_json) |
3429 | json = json_object_new_object(); | |
06931fdb | 3430 | |
cd233079 CS |
3431 | args[0] = vty; |
3432 | args[1] = json; | |
4cce389e | 3433 | |
1f2129ec | 3434 | zl3vni = zl3vni_lookup(vni); |
3435 | if (zl3vni) { | |
4cce389e MK |
3436 | zl3vni_print(zl3vni, (void *)args); |
3437 | } else { | |
8b5fdf2e | 3438 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 3439 | if (zevpn) |
8b5fdf2e | 3440 | zebra_evpn_print(zevpn, (void *)args); |
06931fdb LK |
3441 | else if (!json) |
3442 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
4cce389e MK |
3443 | } |
3444 | ||
cd233079 | 3445 | if (use_json) { |
06931fdb LK |
3446 | /* |
3447 | * Each "json" object contains info about 1 VNI. | |
3448 | * When "json_array" is non-null, we aggreggate the json output | |
3449 | * into json_array and print it as a JSON array. | |
3450 | */ | |
3451 | if (json_array) | |
3452 | json_object_array_add(json_array, json); | |
3453 | else { | |
3454 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
3455 | json, JSON_C_TO_STRING_PRETTY)); | |
3456 | json_object_free(json); | |
3457 | } | |
cd233079 | 3458 | } |
cec2e17d | 3459 | } |
3460 | ||
4cce389e | 3461 | /* Display all global details for EVPN */ |
088f1098 | 3462 | void zebra_vxlan_print_evpn(struct vty *vty, bool uj) |
cec2e17d | 3463 | { |
4cce389e MK |
3464 | int num_l2vnis = 0; |
3465 | int num_l3vnis = 0; | |
d4454626 | 3466 | int num_vnis = 0; |
cd233079 | 3467 | json_object *json = NULL; |
4cce389e | 3468 | struct zebra_vrf *zvrf = NULL; |
cec2e17d | 3469 | |
2853fed6 | 3470 | if (!is_evpn_enabled()) |
d62a17ae | 3471 | return; |
4cce389e | 3472 | |
530db8dc | 3473 | zvrf = zebra_vrf_get_evpn(); |
4cce389e MK |
3474 | if (!zvrf) |
3475 | return; | |
3476 | ||
89272910 | 3477 | num_l3vnis = hashcount(zrouter.l3vni_table); |
87d76d54 | 3478 | num_l2vnis = hashcount(zvrf->evpn_table); |
d4454626 | 3479 | num_vnis = num_l2vnis + num_l3vnis; |
4cce389e MK |
3480 | |
3481 | if (uj) { | |
cd233079 | 3482 | json = json_object_new_object(); |
ddd16ed5 MK |
3483 | json_object_string_add(json, "advertiseGatewayMacip", |
3484 | zvrf->advertise_gw_macip ? "Yes" : "No"); | |
d4454626 | 3485 | json_object_int_add(json, "numVnis", num_vnis); |
4cce389e MK |
3486 | json_object_int_add(json, "numL2Vnis", num_l2vnis); |
3487 | json_object_int_add(json, "numL3Vnis", num_l3vnis); | |
b2ee2b71 | 3488 | if (zebra_evpn_do_dup_addr_detect(zvrf)) |
61d46eda CS |
3489 | json_object_boolean_true_add(json, |
3490 | "isDuplicateAddrDetection"); | |
3491 | else | |
3492 | json_object_boolean_false_add(json, | |
3493 | "isDuplicateAddrDetection"); | |
3494 | json_object_int_add(json, "maxMoves", zvrf->dad_max_moves); | |
3495 | json_object_int_add(json, "detectionTime", zvrf->dad_time); | |
3496 | json_object_int_add(json, "detectionFreezeTime", | |
3497 | zvrf->dad_freeze_time); | |
c36e442c | 3498 | zebra_evpn_mh_json(json); |
cd233079 | 3499 | } else { |
4cce389e MK |
3500 | vty_out(vty, "L2 VNIs: %u\n", num_l2vnis); |
3501 | vty_out(vty, "L3 VNIs: %u\n", num_l3vnis); | |
ddd16ed5 MK |
3502 | vty_out(vty, "Advertise gateway mac-ip: %s\n", |
3503 | zvrf->advertise_gw_macip ? "Yes" : "No"); | |
278e26de CS |
3504 | vty_out(vty, "Advertise svi mac-ip: %s\n", |
3505 | zvrf->advertise_svi_macip ? "Yes" : "No"); | |
61d46eda | 3506 | vty_out(vty, "Duplicate address detection: %s\n", |
b2ee2b71 AK |
3507 | zebra_evpn_do_dup_addr_detect(zvrf) ? "Enable" |
3508 | : "Disable"); | |
61d46eda CS |
3509 | vty_out(vty, " Detection max-moves %u, time %d\n", |
3510 | zvrf->dad_max_moves, zvrf->dad_time); | |
3511 | if (zvrf->dad_freeze) { | |
3512 | if (zvrf->dad_freeze_time) | |
3513 | vty_out(vty, " Detection freeze %u\n", | |
3514 | zvrf->dad_freeze_time); | |
3515 | else | |
3516 | vty_out(vty, " Detection freeze %s\n", | |
3517 | "permanent"); | |
3518 | } | |
c36e442c | 3519 | zebra_evpn_mh_print(vty); |
cd233079 | 3520 | } |
4cce389e MK |
3521 | |
3522 | if (uj) { | |
3523 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
3524 | json, JSON_C_TO_STRING_PRETTY)); | |
3525 | json_object_free(json); | |
3526 | } | |
3527 | } | |
3528 | ||
3529 | /* | |
3530 | * Display VNI hash table (VTY command handler). | |
3531 | */ | |
3532 | void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, | |
9f049418 | 3533 | bool use_json) |
4cce389e MK |
3534 | { |
3535 | json_object *json = NULL; | |
4cce389e MK |
3536 | void *args[2]; |
3537 | ||
3538 | if (!is_evpn_enabled()) | |
3539 | return; | |
3540 | ||
4cce389e MK |
3541 | if (use_json) |
3542 | json = json_object_new_object(); | |
3543 | else | |
996c9314 LB |
3544 | vty_out(vty, "%-10s %-4s %-21s %-8s %-8s %-15s %-37s\n", "VNI", |
3545 | "Type", "VxLAN IF", "# MACs", "# ARPs", | |
3546 | "# Remote VTEPs", "Tenant VRF"); | |
4cce389e | 3547 | |
cd233079 CS |
3548 | args[0] = vty; |
3549 | args[1] = json; | |
3550 | ||
4cce389e | 3551 | /* Display all L2-VNIs */ |
8b5fdf2e PR |
3552 | hash_iterate( |
3553 | zvrf->evpn_table, | |
3554 | (void (*)(struct hash_bucket *, void *))zebra_evpn_print_hash, | |
3555 | args); | |
cd233079 | 3556 | |
4cce389e | 3557 | /* Display all L3-VNIs */ |
89272910 | 3558 | hash_iterate(zrouter.l3vni_table, |
e3b78da8 | 3559 | (void (*)(struct hash_bucket *, void *))zl3vni_print_hash, |
4cce389e MK |
3560 | args); |
3561 | ||
cd233079 CS |
3562 | if (use_json) { |
3563 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
3564 | json, JSON_C_TO_STRING_PRETTY)); | |
3565 | json_object_free(json); | |
3566 | } | |
cec2e17d | 3567 | } |
3568 | ||
3950b52c CS |
3569 | void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS) |
3570 | { | |
3571 | struct stream *s; | |
3572 | int time = 0; | |
3573 | uint32_t max_moves = 0; | |
3574 | uint32_t freeze_time = 0; | |
3575 | bool dup_addr_detect = false; | |
3576 | bool freeze = false; | |
b2ee2b71 | 3577 | bool old_addr_detect; |
3950b52c CS |
3578 | |
3579 | s = msg; | |
3580 | STREAM_GETL(s, dup_addr_detect); | |
3581 | STREAM_GETL(s, time); | |
3582 | STREAM_GETL(s, max_moves); | |
3583 | STREAM_GETL(s, freeze); | |
3584 | STREAM_GETL(s, freeze_time); | |
3585 | ||
b2ee2b71 AK |
3586 | old_addr_detect = zebra_evpn_do_dup_addr_detect(zvrf); |
3587 | zvrf->dup_addr_detect = dup_addr_detect; | |
3588 | dup_addr_detect = zebra_evpn_do_dup_addr_detect(zvrf); | |
3589 | ||
09de9258 CS |
3590 | /* DAD previous state was enabled, and new state is disable, |
3591 | * clear all duplicate detected addresses. | |
3592 | */ | |
b2ee2b71 | 3593 | if (old_addr_detect && !dup_addr_detect) |
e20755b2 | 3594 | zebra_vxlan_clear_dup_detect_vni_all(zvrf); |
09de9258 | 3595 | |
3950b52c CS |
3596 | zvrf->dad_time = time; |
3597 | zvrf->dad_max_moves = max_moves; | |
3598 | zvrf->dad_freeze = freeze; | |
3599 | zvrf->dad_freeze_time = freeze_time; | |
3600 | ||
3601 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3602 | zlog_debug( | |
6005fe55 CS |
3603 | "VRF %s duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u", |
3604 | vrf_id_to_name(zvrf->vrf->vrf_id), | |
b2ee2b71 AK |
3605 | dup_addr_detect ? "enable" : "disable", |
3606 | zvrf->dad_max_moves, zvrf->dad_time, | |
3950b52c CS |
3607 | zvrf->dad_freeze ? "enable" : "disable", |
3608 | zvrf->dad_freeze_time); | |
3609 | ||
3610 | stream_failure: | |
3611 | return; | |
3612 | } | |
3613 | ||
09af6961 NS |
3614 | /* |
3615 | * Display VNI hash table in detail(VTY command handler). | |
3616 | */ | |
3617 | void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, | |
3618 | bool use_json) | |
3619 | { | |
06931fdb | 3620 | json_object *json_array = NULL; |
09af6961 | 3621 | struct zebra_ns *zns = NULL; |
8b5fdf2e | 3622 | struct zebra_evpn_show zes; |
09af6961 NS |
3623 | |
3624 | if (!is_evpn_enabled()) | |
3625 | return; | |
3626 | ||
3627 | zns = zebra_ns_lookup(NS_DEFAULT); | |
3628 | if (!zns) | |
3629 | return; | |
3630 | ||
09af6961 | 3631 | if (use_json) |
06931fdb | 3632 | json_array = json_object_new_array(); |
09af6961 NS |
3633 | |
3634 | zes.vty = vty; | |
06931fdb | 3635 | zes.json = json_array; |
09af6961 | 3636 | zes.zvrf = zvrf; |
06931fdb | 3637 | zes.use_json = use_json; |
09af6961 NS |
3638 | |
3639 | /* Display all L2-VNIs */ | |
8b5fdf2e PR |
3640 | hash_iterate(zvrf->evpn_table, |
3641 | (void (*)(struct hash_bucket *, | |
3642 | void *))zebra_evpn_print_hash_detail, | |
3643 | &zes); | |
09af6961 NS |
3644 | |
3645 | /* Display all L3-VNIs */ | |
3646 | hash_iterate(zrouter.l3vni_table, | |
e3b78da8 | 3647 | (void (*)(struct hash_bucket *, |
09af6961 NS |
3648 | void *))zl3vni_print_hash_detail, |
3649 | &zes); | |
3650 | ||
3651 | if (use_json) { | |
2bcb1a7f QY |
3652 | vty_out(vty, "%s\n", |
3653 | json_object_to_json_string_ext( | |
06931fdb LK |
3654 | json_array, JSON_C_TO_STRING_PRETTY)); |
3655 | json_object_free(json_array); | |
09af6961 NS |
3656 | } |
3657 | } | |
3658 | ||
2232a77c | 3659 | /* |
ee69da27 MK |
3660 | * Handle neighbor delete notification from the kernel (on a VLAN device |
3661 | * / L3 interface). This may result in either the neighbor getting deleted | |
3662 | * from our database or being re-added to the kernel (if it is a valid | |
2232a77c | 3663 | * remote neighbor). |
3664 | */ | |
ee69da27 MK |
3665 | int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, |
3666 | struct interface *link_if, | |
3667 | struct ipaddr *ip) | |
d62a17ae | 3668 | { |
d62a17ae | 3669 | char buf[INET6_ADDRSTRLEN]; |
87d76d54 | 3670 | zebra_evpn_t *zevpn = NULL; |
8c9b80b9 | 3671 | zebra_l3vni_t *zl3vni = NULL; |
b7cfce93 | 3672 | |
8c9b80b9 | 3673 | /* check if this is a remote neigh entry corresponding to remote |
523cafc4 | 3674 | * next-hop |
3675 | */ | |
8c9b80b9 MK |
3676 | zl3vni = zl3vni_from_svi(ifp, link_if); |
3677 | if (zl3vni) | |
3678 | return zl3vni_local_nh_del(zl3vni, ip); | |
d62a17ae | 3679 | |
3680 | /* We are only interested in neighbors on an SVI that resides on top | |
3681 | * of a VxLAN bridge. | |
3682 | */ | |
8b5fdf2e | 3683 | zevpn = zebra_evpn_from_svi(ifp, link_if); |
87d76d54 | 3684 | if (!zevpn) { |
6041b686 | 3685 | if (IS_ZEBRA_DEBUG_VXLAN) |
15569c58 | 3686 | zlog_debug( |
87d76d54 | 3687 | "%s: Del neighbor %s EVPN is not present for interface %s", |
15569c58 DA |
3688 | __func__, ipaddr2str(ip, buf, sizeof(buf)), |
3689 | ifp->name); | |
d62a17ae | 3690 | return 0; |
6041b686 | 3691 | } |
8c9b80b9 | 3692 | |
87d76d54 | 3693 | if (!zevpn->vxlan_if) { |
9df414fe | 3694 | zlog_debug( |
d62a17ae | 3695 | "VNI %u hash %p doesn't have intf upon local neighbor DEL", |
87d76d54 | 3696 | zevpn->vni, zevpn); |
d62a17ae | 3697 | return -1; |
3698 | } | |
3699 | ||
3700 | if (IS_ZEBRA_DEBUG_VXLAN) | |
8c9b80b9 | 3701 | zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u", |
996c9314 | 3702 | ipaddr2str(ip, buf, sizeof(buf)), ifp->name, |
87d76d54 | 3703 | ifp->ifindex, zevpn->vni); |
d62a17ae | 3704 | |
33064a62 | 3705 | return zebra_evpn_neigh_del_ip(zevpn, ip); |
2232a77c | 3706 | } |
3707 | ||
3708 | /* | |
ee69da27 MK |
3709 | * Handle neighbor add or update notification from the kernel (on a VLAN |
3710 | * device / L3 interface). This is typically for a local neighbor but can | |
3711 | * also be for a remote neighbor (e.g., ageout notification). It could | |
3712 | * also be a "move" scenario. | |
2232a77c | 3713 | */ |
ee69da27 MK |
3714 | int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, |
3715 | struct interface *link_if, | |
3716 | struct ipaddr *ip, | |
3717 | struct ethaddr *macaddr, | |
3718 | uint16_t state, | |
a37f4598 | 3719 | bool is_ext, |
b169fd6f AK |
3720 | bool is_router, |
3721 | bool local_inactive, bool dp_static) | |
d62a17ae | 3722 | { |
d62a17ae | 3723 | char buf[ETHER_ADDR_STRLEN]; |
3724 | char buf2[INET6_ADDRSTRLEN]; | |
87d76d54 | 3725 | zebra_evpn_t *zevpn = NULL; |
3bcbba10 | 3726 | zebra_l3vni_t *zl3vni = NULL; |
3727 | ||
3728 | /* check if this is a remote neigh entry corresponding to remote | |
3729 | * next-hop | |
3730 | */ | |
3731 | zl3vni = zl3vni_from_svi(ifp, link_if); | |
3732 | if (zl3vni) | |
3733 | return zl3vni_local_nh_add_update(zl3vni, ip, state); | |
b7cfce93 | 3734 | |
d62a17ae | 3735 | /* We are only interested in neighbors on an SVI that resides on top |
3736 | * of a VxLAN bridge. | |
3737 | */ | |
8b5fdf2e | 3738 | zevpn = zebra_evpn_from_svi(ifp, link_if); |
87d76d54 | 3739 | if (!zevpn) |
d62a17ae | 3740 | return 0; |
3741 | ||
b169fd6f | 3742 | if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) |
d62a17ae | 3743 | zlog_debug( |
7c0e4dc6 | 3744 | "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s%s%s%s-> L2-VNI %u", |
2853fed6 | 3745 | ipaddr2str(ip, buf2, sizeof(buf2)), |
d62a17ae | 3746 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, |
a37f4598 | 3747 | ifp->ifindex, state, is_ext ? "ext-learned " : "", |
3748 | is_router ? "router " : "", | |
b169fd6f | 3749 | local_inactive ? "local_inactive " : "", |
7c0e4dc6 | 3750 | dp_static ? "peer_sync " : "", zevpn->vni); |
d62a17ae | 3751 | |
ee69da27 | 3752 | /* Is this about a local neighbor or a remote one? */ |
a37f4598 | 3753 | if (!is_ext) |
7cbae20a PR |
3754 | return zebra_evpn_local_neigh_update(zevpn, ifp, ip, macaddr, |
3755 | is_router, local_inactive, | |
3756 | dp_static); | |
b7cfce93 | 3757 | |
7cbae20a | 3758 | return zebra_evpn_remote_neigh_update(zevpn, ifp, ip, macaddr, state); |
2232a77c | 3759 | } |
3760 | ||
0bd371c6 DS |
3761 | static int32_t |
3762 | zebra_vxlan_remote_macip_helper(bool add, struct stream *s, vni_t *vni, | |
3763 | struct ethaddr *macaddr, uint16_t *ipa_len, | |
3764 | struct ipaddr *ip, struct in_addr *vtep_ip, | |
ce5160c0 | 3765 | uint8_t *flags, uint32_t *seq, esi_t *esi) |
0bd371c6 DS |
3766 | { |
3767 | uint16_t l = 0; | |
3768 | ||
3769 | /* | |
3770 | * Obtain each remote MACIP and process. | |
3771 | * Message contains VNI, followed by MAC followed by IP (if any) | |
3772 | * followed by remote VTEP IP. | |
3773 | */ | |
3774 | memset(ip, 0, sizeof(*ip)); | |
3775 | STREAM_GETL(s, *vni); | |
3776 | STREAM_GET(macaddr->octet, s, ETH_ALEN); | |
3777 | STREAM_GETL(s, *ipa_len); | |
3778 | ||
3779 | if (*ipa_len) { | |
3780 | if (*ipa_len == IPV4_MAX_BYTELEN) | |
3781 | ip->ipa_type = IPADDR_V4; | |
3782 | else if (*ipa_len == IPV6_MAX_BYTELEN) | |
3783 | ip->ipa_type = IPADDR_V6; | |
3784 | else { | |
3785 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3786 | zlog_debug( | |
3787 | "ipa_len *must* be %d or %d bytes in length not %d", | |
3788 | IPV4_MAX_BYTELEN, IPV6_MAX_BYTELEN, | |
3789 | *ipa_len); | |
3790 | goto stream_failure; | |
3791 | } | |
3792 | ||
3793 | STREAM_GET(&ip->ip.addr, s, *ipa_len); | |
3794 | } | |
3795 | l += 4 + ETH_ALEN + 4 + *ipa_len; | |
3796 | STREAM_GET(&vtep_ip->s_addr, s, IPV4_MAX_BYTELEN); | |
3797 | l += IPV4_MAX_BYTELEN; | |
3798 | ||
3799 | if (add) { | |
3800 | STREAM_GETC(s, *flags); | |
3801 | STREAM_GETL(s, *seq); | |
3802 | l += 5; | |
ce5160c0 AK |
3803 | STREAM_GET(esi, s, sizeof(esi_t)); |
3804 | l += sizeof(esi_t); | |
0bd371c6 DS |
3805 | } |
3806 | ||
3807 | return l; | |
3808 | ||
3809 | stream_failure: | |
3810 | return -1; | |
3811 | } | |
b682f6de | 3812 | |
2232a77c | 3813 | /* |
3814 | * Handle message from client to delete a remote MACIP for a VNI. | |
3815 | */ | |
89f4e507 | 3816 | void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS) |
d62a17ae | 3817 | { |
3818 | struct stream *s; | |
3819 | vni_t vni; | |
3820 | struct ethaddr macaddr; | |
3821 | struct ipaddr ip; | |
3822 | struct in_addr vtep_ip; | |
9df2b997 | 3823 | uint16_t l = 0, ipa_len; |
d62a17ae | 3824 | char buf[ETHER_ADDR_STRLEN]; |
3825 | char buf1[INET6_ADDRSTRLEN]; | |
3826 | ||
b7cfce93 | 3827 | memset(&macaddr, 0, sizeof(struct ethaddr)); |
b7cfce93 MK |
3828 | memset(&ip, 0, sizeof(struct ipaddr)); |
3829 | memset(&vtep_ip, 0, sizeof(struct in_addr)); | |
3830 | ||
1002497a | 3831 | s = msg; |
d62a17ae | 3832 | |
89f4e507 | 3833 | while (l < hdr->length) { |
0bd371c6 DS |
3834 | int res_length = zebra_vxlan_remote_macip_helper( |
3835 | false, s, &vni, &macaddr, &ipa_len, &ip, &vtep_ip, NULL, | |
ce5160c0 | 3836 | NULL, NULL); |
4824d144 | 3837 | |
0bd371c6 DS |
3838 | if (res_length == -1) |
3839 | goto stream_failure; | |
d62a17ae | 3840 | |
0bd371c6 | 3841 | l += res_length; |
d62a17ae | 3842 | if (IS_ZEBRA_DEBUG_VXLAN) |
3843 | zlog_debug( | |
9bcef951 | 3844 | "Recv MACIP DEL VNI %u MAC %s%s%s Remote VTEP %pI4 from %s", |
f07e1c99 | 3845 | vni, |
d62a17ae | 3846 | prefix_mac2str(&macaddr, buf, sizeof(buf)), |
f07e1c99 | 3847 | ipa_len ? " IP " : "", |
3848 | ipa_len ? | |
3849 | ipaddr2str(&ip, buf1, sizeof(buf1)) : "", | |
9bcef951 | 3850 | &vtep_ip, zebra_route_string(client->proto)); |
d62a17ae | 3851 | |
f07e1c99 | 3852 | process_remote_macip_del(vni, &macaddr, ipa_len, &ip, vtep_ip); |
d62a17ae | 3853 | } |
3854 | ||
ec93aa12 | 3855 | stream_failure: |
8068a649 | 3856 | return; |
2232a77c | 3857 | } |
3858 | ||
3859 | /* | |
3860 | * Handle message from client to add a remote MACIP for a VNI. This | |
3861 | * could be just the add of a MAC address or the add of a neighbor | |
3862 | * (IP+MAC). | |
3863 | */ | |
89f4e507 | 3864 | void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) |
d62a17ae | 3865 | { |
3866 | struct stream *s; | |
3867 | vni_t vni; | |
3868 | struct ethaddr macaddr; | |
3869 | struct ipaddr ip; | |
3870 | struct in_addr vtep_ip; | |
9df2b997 | 3871 | uint16_t l = 0, ipa_len; |
f07e1c99 | 3872 | uint8_t flags = 0; |
3873 | uint32_t seq; | |
d62a17ae | 3874 | char buf[ETHER_ADDR_STRLEN]; |
3875 | char buf1[INET6_ADDRSTRLEN]; | |
ce5160c0 AK |
3876 | esi_t esi; |
3877 | char esi_buf[ESI_STR_LEN]; | |
d62a17ae | 3878 | |
b7cfce93 | 3879 | memset(&macaddr, 0, sizeof(struct ethaddr)); |
b7cfce93 MK |
3880 | memset(&ip, 0, sizeof(struct ipaddr)); |
3881 | memset(&vtep_ip, 0, sizeof(struct in_addr)); | |
3882 | ||
ec93aa12 | 3883 | if (!EVPN_ENABLED(zvrf)) { |
9df414fe | 3884 | zlog_debug("EVPN not enabled, ignoring remote MACIP ADD"); |
8068a649 | 3885 | return; |
ec93aa12 | 3886 | } |
d62a17ae | 3887 | |
1002497a | 3888 | s = msg; |
d62a17ae | 3889 | |
89f4e507 | 3890 | while (l < hdr->length) { |
0bd371c6 DS |
3891 | int res_length = zebra_vxlan_remote_macip_helper( |
3892 | true, s, &vni, &macaddr, &ipa_len, &ip, &vtep_ip, | |
ce5160c0 | 3893 | &flags, &seq, &esi); |
d62a17ae | 3894 | |
0bd371c6 DS |
3895 | if (res_length == -1) |
3896 | goto stream_failure; | |
d62a17ae | 3897 | |
0bd371c6 | 3898 | l += res_length; |
ce5160c0 AK |
3899 | if (IS_ZEBRA_DEBUG_VXLAN) { |
3900 | if (memcmp(&esi, zero_esi, sizeof(esi_t))) | |
3901 | esi_to_str(&esi, esi_buf, sizeof(esi_buf)); | |
3902 | else | |
9e0c2fd1 | 3903 | strlcpy(esi_buf, "-", ESI_STR_LEN); |
d62a17ae | 3904 | zlog_debug( |
9bcef951 | 3905 | "Recv %sMACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %pI4 ESI %s from %s", |
b169fd6f AK |
3906 | (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) ? |
3907 | "sync-" : "", | |
f07e1c99 | 3908 | vni, |
d62a17ae | 3909 | prefix_mac2str(&macaddr, buf, sizeof(buf)), |
f07e1c99 | 3910 | ipa_len ? " IP " : "", |
3911 | ipa_len ? | |
3912 | ipaddr2str(&ip, buf1, sizeof(buf1)) : "", | |
9bcef951 | 3913 | flags, seq, &vtep_ip, esi_buf, |
d62a17ae | 3914 | zebra_route_string(client->proto)); |
ce5160c0 | 3915 | } |
d62a17ae | 3916 | |
f07e1c99 | 3917 | process_remote_macip_add(vni, &macaddr, ipa_len, &ip, |
ce5160c0 | 3918 | flags, seq, vtep_ip, &esi); |
d62a17ae | 3919 | } |
3920 | ||
ec93aa12 | 3921 | stream_failure: |
8068a649 | 3922 | return; |
13d60d35 | 3923 | } |
3924 | ||
4b3f26f4 | 3925 | /* |
3926 | * Handle remote vtep delete by kernel; re-add the vtep if we have it | |
3927 | */ | |
3928 | int zebra_vxlan_check_readd_vtep(struct interface *ifp, | |
3929 | struct in_addr vtep_ip) | |
3930 | { | |
3931 | struct zebra_if *zif; | |
3932 | struct zebra_vrf *zvrf = NULL; | |
3933 | struct zebra_l2info_vxlan *vxl; | |
3934 | vni_t vni; | |
87d76d54 | 3935 | zebra_evpn_t *zevpn = NULL; |
4b3f26f4 | 3936 | zebra_vtep_t *zvtep = NULL; |
3937 | ||
3938 | zif = ifp->info; | |
3939 | assert(zif); | |
3940 | vxl = &zif->l2info.vxl; | |
3941 | vni = vxl->vni; | |
3942 | ||
3943 | /* If EVPN is not enabled, nothing to do. */ | |
3944 | if (!is_evpn_enabled()) | |
3945 | return 0; | |
3946 | ||
3947 | /* Locate VRF corresponding to interface. */ | |
3948 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
3949 | if (!zvrf) | |
3950 | return -1; | |
3951 | ||
3952 | /* Locate hash entry; it is expected to exist. */ | |
8b5fdf2e | 3953 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 3954 | if (!zevpn) |
4b3f26f4 | 3955 | return 0; |
3956 | ||
3957 | /* If the remote vtep entry doesn't exists nothing to do */ | |
8b5fdf2e | 3958 | zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); |
4b3f26f4 | 3959 | if (!zvtep) |
3960 | return 0; | |
3961 | ||
3962 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3963 | zlog_debug( | |
9bcef951 MS |
3964 | "Del MAC for remote VTEP %pI4 intf %s(%u) VNI %u - readd", |
3965 | &vtep_ip, ifp->name, ifp->ifindex, vni); | |
4b3f26f4 | 3966 | |
8b5fdf2e | 3967 | zebra_evpn_vtep_install(zevpn, zvtep); |
4b3f26f4 | 3968 | return 0; |
3969 | } | |
3970 | ||
13d60d35 | 3971 | /* |
2232a77c | 3972 | * Handle notification of MAC add/update over VxLAN. If the kernel is notifying |
3973 | * us, this must involve a multihoming scenario. Treat this as implicit delete | |
3974 | * of any prior local MAC. | |
13d60d35 | 3975 | */ |
15400f95 AK |
3976 | static int zebra_vxlan_check_del_local_mac(struct interface *ifp, |
3977 | struct interface *br_if, | |
3978 | struct ethaddr *macaddr, | |
3979 | vlanid_t vid) | |
13d60d35 | 3980 | { |
d62a17ae | 3981 | struct zebra_if *zif; |
d62a17ae | 3982 | struct zebra_l2info_vxlan *vxl; |
3983 | vni_t vni; | |
87d76d54 | 3984 | zebra_evpn_t *zevpn; |
d62a17ae | 3985 | zebra_mac_t *mac; |
3986 | char buf[ETHER_ADDR_STRLEN]; | |
13d60d35 | 3987 | |
d62a17ae | 3988 | zif = ifp->info; |
3989 | assert(zif); | |
3990 | vxl = &zif->l2info.vxl; | |
3991 | vni = vxl->vni; | |
13d60d35 | 3992 | |
2853fed6 | 3993 | /* Check if EVPN is enabled. */ |
3994 | if (!is_evpn_enabled()) | |
d62a17ae | 3995 | return 0; |
13d60d35 | 3996 | |
d62a17ae | 3997 | /* Locate hash entry; it is expected to exist. */ |
8b5fdf2e | 3998 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 3999 | if (!zevpn) |
d62a17ae | 4000 | return 0; |
13d60d35 | 4001 | |
d62a17ae | 4002 | /* If entry doesn't exist, nothing to do. */ |
b2998086 | 4003 | mac = zebra_evpn_mac_lookup(zevpn, macaddr); |
d62a17ae | 4004 | if (!mac) |
4005 | return 0; | |
13d60d35 | 4006 | |
d62a17ae | 4007 | /* Is it a local entry? */ |
4008 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) | |
4009 | return 0; | |
13d60d35 | 4010 | |
d62a17ae | 4011 | if (IS_ZEBRA_DEBUG_VXLAN) |
4012 | zlog_debug( | |
5756dd1d | 4013 | "Add/update remote MAC %s intf %s(%u) VNI %u flags 0x%x - del local", |
996c9314 | 4014 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, |
5756dd1d | 4015 | ifp->ifindex, vni, mac->flags); |
13d60d35 | 4016 | |
d62a17ae | 4017 | /* Remove MAC from BGP. */ |
b2998086 PR |
4018 | zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, mac->flags, |
4019 | false /* force */); | |
13d60d35 | 4020 | |
b6938a74 MK |
4021 | /* |
4022 | * If there are no neigh associated with the mac delete the mac | |
4023 | * else mark it as AUTO for forward reference | |
4024 | */ | |
4025 | if (!listcount(mac->neigh_list)) { | |
b2998086 | 4026 | zebra_evpn_mac_del(zevpn, mac); |
b6938a74 | 4027 | } else { |
b169fd6f | 4028 | UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS); |
5756dd1d | 4029 | UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); |
b6938a74 MK |
4030 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); |
4031 | } | |
13d60d35 | 4032 | |
d62a17ae | 4033 | return 0; |
13d60d35 | 4034 | } |
4035 | ||
15400f95 AK |
4036 | /* MAC notification from the dataplane with a network dest port - |
4037 | * 1. This can be a local MAC on a down ES (if fast-failover is not possible | |
4038 | * 2. Or it can be a remote MAC | |
4039 | */ | |
4040 | int zebra_vxlan_dp_network_mac_add(struct interface *ifp, | |
4041 | struct interface *br_if, | |
4042 | struct ethaddr *macaddr, vlanid_t vid, | |
4043 | uint32_t nhg_id, bool sticky, bool dp_static) | |
4044 | { | |
4045 | struct zebra_evpn_es *es; | |
4046 | struct interface *acc_ifp; | |
4047 | ||
4048 | /* if remote mac delete the local entry */ | |
4049 | if (!nhg_id || !zebra_evpn_nhg_is_local_es(nhg_id, &es) | |
4050 | || !zebra_evpn_es_local_mac_via_network_port(es)) { | |
4051 | if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) | |
4052 | zlog_debug("dpAdd remote MAC %pEA VID %u", macaddr, | |
4053 | vid); | |
4054 | return zebra_vxlan_check_del_local_mac(ifp, br_if, macaddr, | |
4055 | vid); | |
4056 | } | |
4057 | ||
4058 | /* If local MAC on a down local ES translate the network-mac-add | |
4059 | * to a local-inactive-mac-add | |
4060 | */ | |
4061 | if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) | |
4062 | zlog_debug("dpAdd local-nw-MAC %pEA VID %u", macaddr, vid); | |
4063 | acc_ifp = es->zif->ifp; | |
4064 | return zebra_vxlan_local_mac_add_update( | |
4065 | acc_ifp, br_if, macaddr, vid, sticky, | |
4066 | false /* local_inactive */, dp_static); | |
4067 | } | |
4068 | ||
13d60d35 | 4069 | /* |
15400f95 AK |
4070 | * Handle network MAC delete by kernel - |
4071 | * 1. readd the remote MAC if we have it | |
4072 | * 2. local MAC with does ES may also need to be re-installed | |
13d60d35 | 4073 | */ |
15400f95 AK |
4074 | static int zebra_vxlan_do_local_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac); |
4075 | int zebra_vxlan_dp_network_mac_del(struct interface *ifp, | |
4076 | struct interface *br_if, | |
4077 | struct ethaddr *macaddr, vlanid_t vid) | |
13d60d35 | 4078 | { |
a9a76262 MK |
4079 | struct zebra_if *zif = NULL; |
4080 | struct zebra_l2info_vxlan *vxl = NULL; | |
d62a17ae | 4081 | vni_t vni; |
87d76d54 | 4082 | zebra_evpn_t *zevpn = NULL; |
a9a76262 MK |
4083 | zebra_l3vni_t *zl3vni = NULL; |
4084 | zebra_mac_t *mac = NULL; | |
2232a77c | 4085 | |
d62a17ae | 4086 | zif = ifp->info; |
4087 | assert(zif); | |
4088 | vxl = &zif->l2info.vxl; | |
4089 | vni = vxl->vni; | |
2232a77c | 4090 | |
2853fed6 | 4091 | /* Check if EVPN is enabled. */ |
4092 | if (!is_evpn_enabled()) | |
d62a17ae | 4093 | return 0; |
2232a77c | 4094 | |
a9a76262 MK |
4095 | /* check if this is a remote RMAC and readd simillar to remote macs */ |
4096 | zl3vni = zl3vni_lookup(vni); | |
4097 | if (zl3vni) | |
4098 | return zebra_vxlan_readd_remote_rmac(zl3vni, macaddr); | |
4099 | ||
d62a17ae | 4100 | /* Locate hash entry; it is expected to exist. */ |
8b5fdf2e | 4101 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 4102 | if (!zevpn) |
d62a17ae | 4103 | return 0; |
13d60d35 | 4104 | |
d62a17ae | 4105 | /* If entry doesn't exist, nothing to do. */ |
b2998086 | 4106 | mac = zebra_evpn_mac_lookup(zevpn, macaddr); |
d62a17ae | 4107 | if (!mac) |
4108 | return 0; | |
2232a77c | 4109 | |
15400f95 AK |
4110 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { |
4111 | /* If remote entry simply re-install */ | |
4112 | if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) | |
4113 | zlog_debug( | |
4114 | "dpDel remote MAC %pEA intf %s(%u) VNI %u - readd", | |
4115 | macaddr, ifp->name, ifp->ifindex, vni); | |
4116 | zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */); | |
4117 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && mac->es | |
4118 | && zebra_evpn_es_local_mac_via_network_port(mac->es)) { | |
4119 | /* If local entry via nw-port call local-del which will | |
4120 | * re-install entry in the dataplane is needed | |
4121 | */ | |
4122 | if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) | |
4123 | zlog_debug("dpDel local-nw-MAC %pEA VNI %u", macaddr, | |
4124 | vni); | |
4125 | zebra_vxlan_do_local_mac_del(zevpn, mac); | |
4126 | } | |
4127 | ||
4128 | return 0; | |
4129 | } | |
4130 | ||
4131 | static int zebra_vxlan_do_local_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac) | |
4132 | { | |
4133 | bool old_bgp_ready; | |
4134 | bool new_bgp_ready; | |
2232a77c | 4135 | |
d62a17ae | 4136 | if (IS_ZEBRA_DEBUG_VXLAN) |
15400f95 AK |
4137 | zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u", |
4138 | &mac->macaddr, zevpn->vni, mac->loc_seq, mac->flags, | |
4139 | listcount(mac->neigh_list)); | |
4140 | ||
4141 | old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); | |
4142 | if (zebra_evpn_mac_is_static(mac)) { | |
4143 | /* this is a synced entry and can only be removed when the | |
4144 | * es-peers stop advertising it. | |
4145 | */ | |
4146 | memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); | |
4147 | ||
4148 | if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) | |
4149 | zlog_debug( | |
4150 | "re-add sync-mac vni %u mac %pEA es %s seq %d f 0x%x", | |
4151 | zevpn->vni, &mac->macaddr, | |
4152 | mac->es ? mac->es->esi_str : "-", mac->loc_seq, | |
4153 | mac->flags); | |
4154 | ||
4155 | /* inform-bgp about change in local-activity if any */ | |
4156 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) { | |
4157 | SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE); | |
4158 | new_bgp_ready = | |
4159 | zebra_evpn_mac_is_ready_for_bgp(mac->flags); | |
4160 | zebra_evpn_mac_send_add_del_to_client( | |
4161 | mac, old_bgp_ready, new_bgp_ready); | |
4162 | } | |
4163 | ||
4164 | /* re-install the entry in the kernel */ | |
4165 | zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, | |
4166 | false /* force_clear_static */, | |
4167 | __func__); | |
4168 | ||
4169 | return 0; | |
4170 | } | |
4171 | ||
4172 | /* Update all the neigh entries associated with this mac */ | |
4173 | zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac); | |
4174 | ||
4175 | /* Remove MAC from BGP. */ | |
4176 | zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags, | |
4177 | false /* force */); | |
4178 | ||
4179 | zebra_evpn_es_mac_deref_entry(mac); | |
4180 | ||
4181 | /* | |
4182 | * If there are no neigh associated with the mac delete the mac | |
4183 | * else mark it as AUTO for forward reference | |
4184 | */ | |
4185 | if (!listcount(mac->neigh_list)) { | |
4186 | zebra_evpn_mac_del(zevpn, mac); | |
4187 | } else { | |
4188 | UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS); | |
4189 | UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
4190 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
4191 | } | |
13d60d35 | 4192 | |
d62a17ae | 4193 | return 0; |
13d60d35 | 4194 | } |
4195 | ||
4196 | /* | |
2232a77c | 4197 | * Handle local MAC delete (on a port or VLAN corresponding to this VNI). |
13d60d35 | 4198 | */ |
d62a17ae | 4199 | int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, |
4200 | struct ethaddr *macaddr, vlanid_t vid) | |
13d60d35 | 4201 | { |
87d76d54 | 4202 | zebra_evpn_t *zevpn; |
15400f95 | 4203 | zebra_mac_t *mac; |
13d60d35 | 4204 | |
d62a17ae | 4205 | /* We are interested in MACs only on ports or (port, VLAN) that |
4206 | * map to a VNI. | |
4207 | */ | |
8b5fdf2e | 4208 | zevpn = zebra_evpn_map_vlan(ifp, br_if, vid); |
87d76d54 | 4209 | if (!zevpn) |
d62a17ae | 4210 | return 0; |
87d76d54 | 4211 | if (!zevpn->vxlan_if) { |
9df414fe QY |
4212 | zlog_debug( |
4213 | "VNI %u hash %p doesn't have intf upon local MAC DEL", | |
87d76d54 | 4214 | zevpn->vni, zevpn); |
d62a17ae | 4215 | return -1; |
4216 | } | |
13d60d35 | 4217 | |
15400f95 AK |
4218 | /* If entry doesn't exist, nothing to do. */ |
4219 | mac = zebra_evpn_mac_lookup(zevpn, macaddr); | |
4220 | if (!mac) | |
4221 | return 0; | |
4222 | ||
4223 | /* Is it a local entry? */ | |
4224 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) | |
4225 | return 0; | |
4226 | ||
4227 | return zebra_vxlan_do_local_mac_del(zevpn, mac); | |
13d60d35 | 4228 | } |
4229 | ||
4230 | /* | |
2232a77c | 4231 | * Handle local MAC add (on a port or VLAN corresponding to this VNI). |
13d60d35 | 4232 | */ |
d62a17ae | 4233 | int zebra_vxlan_local_mac_add_update(struct interface *ifp, |
4234 | struct interface *br_if, | |
4235 | struct ethaddr *macaddr, vlanid_t vid, | |
b169fd6f AK |
4236 | bool sticky, bool local_inactive, |
4237 | bool dp_static) | |
d62a17ae | 4238 | { |
87d76d54 | 4239 | zebra_evpn_t *zevpn; |
e22a946a | 4240 | struct zebra_vrf *zvrf; |
d62a17ae | 4241 | char buf[ETHER_ADDR_STRLEN]; |
d62a17ae | 4242 | |
2bdd4461 | 4243 | assert(ifp); |
b7895aad | 4244 | |
d62a17ae | 4245 | /* We are interested in MACs only on ports or (port, VLAN) that |
87d76d54 | 4246 | * map to an EVPN. |
d62a17ae | 4247 | */ |
8b5fdf2e | 4248 | zevpn = zebra_evpn_map_vlan(ifp, br_if, vid); |
87d76d54 | 4249 | if (!zevpn) { |
d62a17ae | 4250 | if (IS_ZEBRA_DEBUG_VXLAN) |
4251 | zlog_debug( | |
87d76d54 | 4252 | " Add/Update %sMAC %s intf %s(%u) VID %u, could not find EVPN", |
2853fed6 | 4253 | sticky ? "sticky " : "", |
d62a17ae | 4254 | prefix_mac2str(macaddr, buf, sizeof(buf)), |
4255 | ifp->name, ifp->ifindex, vid); | |
4256 | return 0; | |
4257 | } | |
4258 | ||
87d76d54 | 4259 | if (!zevpn->vxlan_if) { |
28bd0652 DS |
4260 | if (IS_ZEBRA_DEBUG_VXLAN) |
4261 | zlog_debug( | |
d6951e5e | 4262 | " VNI %u hash %p doesn't have intf upon local MAC ADD", |
87d76d54 | 4263 | zevpn->vni, zevpn); |
d62a17ae | 4264 | return -1; |
4265 | } | |
4266 | ||
d6bf8f13 | 4267 | zvrf = zebra_vrf_get_evpn(); |
28bd0652 DS |
4268 | if (!zvrf) { |
4269 | if (IS_ZEBRA_DEBUG_VXLAN) | |
d6bf8f13 | 4270 | zlog_debug(" No Evpn Global Vrf found"); |
e22a946a | 4271 | return -1; |
28bd0652 | 4272 | } |
e22a946a | 4273 | |
d9d3455e PR |
4274 | return zebra_evpn_add_update_local_mac(zvrf, zevpn, ifp, macaddr, vid, |
4275 | sticky, local_inactive, | |
4276 | dp_static); | |
2232a77c | 4277 | } |
13d60d35 | 4278 | |
4279 | /* | |
87d76d54 | 4280 | * Handle message from client to delete a remote VTEP for an EVPN. |
13d60d35 | 4281 | */ |
89f4e507 | 4282 | void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS) |
d62a17ae | 4283 | { |
4284 | struct stream *s; | |
d7c0a89a | 4285 | unsigned short l = 0; |
d62a17ae | 4286 | vni_t vni; |
4287 | struct in_addr vtep_ip; | |
87d76d54 | 4288 | zebra_evpn_t *zevpn; |
d62a17ae | 4289 | zebra_vtep_t *zvtep; |
b5ebdc9b | 4290 | struct interface *ifp; |
4291 | struct zebra_if *zif; | |
d62a17ae | 4292 | |
ec93aa12 | 4293 | if (!is_evpn_enabled()) { |
9df414fe | 4294 | zlog_debug( |
996c9314 | 4295 | "%s: EVPN is not enabled yet we have received a vtep del command", |
15569c58 | 4296 | __func__); |
8068a649 | 4297 | return; |
ec93aa12 DS |
4298 | } |
4299 | ||
986512a3 | 4300 | if (!EVPN_ENABLED(zvrf)) { |
a0b0b5c8 T |
4301 | zlog_debug("Recv MACIP DEL for non-EVPN VRF %u", |
4302 | zvrf_id(zvrf)); | |
8068a649 | 4303 | return; |
2853fed6 | 4304 | } |
4305 | ||
1002497a | 4306 | s = msg; |
d62a17ae | 4307 | |
89f4e507 | 4308 | while (l < hdr->length) { |
694bd4ce | 4309 | int flood_control __attribute__((unused)); |
8a64de72 | 4310 | |
d62a17ae | 4311 | /* Obtain each remote VTEP and process. */ |
ec93aa12 | 4312 | STREAM_GETL(s, vni); |
d62a17ae | 4313 | l += 4; |
ec93aa12 | 4314 | STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); |
d62a17ae | 4315 | l += IPV4_MAX_BYTELEN; |
4316 | ||
8a64de72 DS |
4317 | /* Flood control is intentionally ignored right now */ |
4318 | STREAM_GETL(s, flood_control); | |
4319 | l += 4; | |
4320 | ||
d62a17ae | 4321 | if (IS_ZEBRA_DEBUG_VXLAN) |
9bcef951 MS |
4322 | zlog_debug("Recv VTEP_DEL %pI4 VNI %u from %s", |
4323 | &vtep_ip, vni, | |
d62a17ae | 4324 | zebra_route_string(client->proto)); |
4325 | ||
4326 | /* Locate VNI hash entry - expected to exist. */ | |
8b5fdf2e | 4327 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 4328 | if (!zevpn) { |
d62a17ae | 4329 | if (IS_ZEBRA_DEBUG_VXLAN) |
4330 | zlog_debug( | |
3efd0893 | 4331 | "Failed to locate VNI hash upon remote VTEP DEL, VNI %u", |
2853fed6 | 4332 | vni); |
d62a17ae | 4333 | continue; |
4334 | } | |
4335 | ||
87d76d54 | 4336 | ifp = zevpn->vxlan_if; |
b5ebdc9b | 4337 | if (!ifp) { |
9df414fe | 4338 | zlog_debug( |
60466a63 | 4339 | "VNI %u hash %p doesn't have intf upon remote VTEP DEL", |
87d76d54 | 4340 | zevpn->vni, zevpn); |
b682f6de | 4341 | continue; |
b5ebdc9b | 4342 | } |
4343 | zif = ifp->info; | |
4344 | ||
4345 | /* If down or not mapped to a bridge, we're done. */ | |
b682f6de | 4346 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
b5ebdc9b | 4347 | continue; |
4348 | ||
d62a17ae | 4349 | /* If the remote VTEP does not exist, there's nothing more to |
4350 | * do. | |
4351 | * Otherwise, uninstall any remote MACs pointing to this VTEP | |
4352 | * and | |
4353 | * then, the VTEP entry itself and remove it. | |
4354 | */ | |
8b5fdf2e | 4355 | zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); |
d62a17ae | 4356 | if (!zvtep) |
4357 | continue; | |
4358 | ||
8b5fdf2e PR |
4359 | zebra_evpn_vtep_uninstall(zevpn, &vtep_ip); |
4360 | zebra_evpn_vtep_del(zevpn, zvtep); | |
d62a17ae | 4361 | } |
4362 | ||
ec93aa12 | 4363 | stream_failure: |
8068a649 | 4364 | return; |
13d60d35 | 4365 | } |
4366 | ||
4367 | /* | |
87d76d54 | 4368 | * Handle message from client to add a remote VTEP for an EVPN. |
13d60d35 | 4369 | */ |
89f4e507 | 4370 | void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS) |
d62a17ae | 4371 | { |
4372 | struct stream *s; | |
d7c0a89a | 4373 | unsigned short l = 0; |
d62a17ae | 4374 | vni_t vni; |
4375 | struct in_addr vtep_ip; | |
87d76d54 | 4376 | zebra_evpn_t *zevpn; |
b5ebdc9b | 4377 | struct interface *ifp; |
4378 | struct zebra_if *zif; | |
9718c54e AK |
4379 | int flood_control; |
4380 | zebra_vtep_t *zvtep; | |
d62a17ae | 4381 | |
ec93aa12 | 4382 | if (!is_evpn_enabled()) { |
9df414fe | 4383 | zlog_debug( |
996c9314 | 4384 | "%s: EVPN not enabled yet we received a vtep_add zapi call", |
15569c58 | 4385 | __func__); |
8068a649 | 4386 | return; |
ec93aa12 DS |
4387 | } |
4388 | ||
986512a3 | 4389 | if (!EVPN_ENABLED(zvrf)) { |
a0b0b5c8 T |
4390 | zlog_debug("Recv MACIP ADD for non-EVPN VRF %u", |
4391 | zvrf_id(zvrf)); | |
8068a649 | 4392 | return; |
2853fed6 | 4393 | } |
d62a17ae | 4394 | |
1002497a | 4395 | s = msg; |
d62a17ae | 4396 | |
89f4e507 | 4397 | while (l < hdr->length) { |
d62a17ae | 4398 | /* Obtain each remote VTEP and process. */ |
ec93aa12 | 4399 | STREAM_GETL(s, vni); |
d62a17ae | 4400 | l += 4; |
ec93aa12 | 4401 | STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); |
9718c54e | 4402 | STREAM_GETL(s, flood_control); |
8a64de72 | 4403 | l += IPV4_MAX_BYTELEN + 4; |
d62a17ae | 4404 | |
4405 | if (IS_ZEBRA_DEBUG_VXLAN) | |
9bcef951 MS |
4406 | zlog_debug("Recv VTEP_ADD %pI4 VNI %u flood %d from %s", |
4407 | &vtep_ip, vni, flood_control, | |
9718c54e | 4408 | zebra_route_string(client->proto)); |
d62a17ae | 4409 | |
4410 | /* Locate VNI hash entry - expected to exist. */ | |
8b5fdf2e | 4411 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 4412 | if (!zevpn) { |
af4c2728 | 4413 | flog_err( |
e914ccbe | 4414 | EC_ZEBRA_VTEP_ADD_FAILED, |
87d76d54 | 4415 | "Failed to locate EVPN hash upon remote VTEP ADD, VNI %u", |
2853fed6 | 4416 | vni); |
d62a17ae | 4417 | continue; |
4418 | } | |
b5ebdc9b | 4419 | |
87d76d54 | 4420 | ifp = zevpn->vxlan_if; |
b5ebdc9b | 4421 | if (!ifp) { |
af4c2728 | 4422 | flog_err( |
e914ccbe | 4423 | EC_ZEBRA_VTEP_ADD_FAILED, |
d62a17ae | 4424 | "VNI %u hash %p doesn't have intf upon remote VTEP ADD", |
87d76d54 | 4425 | zevpn->vni, zevpn); |
d62a17ae | 4426 | continue; |
4427 | } | |
4428 | ||
b5ebdc9b | 4429 | zif = ifp->info; |
d62a17ae | 4430 | |
b5ebdc9b | 4431 | /* If down or not mapped to a bridge, we're done. */ |
b682f6de | 4432 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
d62a17ae | 4433 | continue; |
4434 | ||
8b5fdf2e | 4435 | zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); |
9718c54e AK |
4436 | if (zvtep) { |
4437 | /* If the remote VTEP already exists check if | |
4438 | * the flood mode has changed | |
4439 | */ | |
4440 | if (zvtep->flood_control != flood_control) { | |
4441 | if (zvtep->flood_control | |
4442 | == VXLAN_FLOOD_DISABLED) | |
4443 | /* old mode was head-end-replication but | |
4444 | * is no longer; get rid of the HER fdb | |
4445 | * entry installed before | |
4446 | */ | |
8b5fdf2e PR |
4447 | zebra_evpn_vtep_uninstall(zevpn, |
4448 | &vtep_ip); | |
9718c54e | 4449 | zvtep->flood_control = flood_control; |
8b5fdf2e | 4450 | zebra_evpn_vtep_install(zevpn, zvtep); |
9718c54e AK |
4451 | } |
4452 | } else { | |
8b5fdf2e PR |
4453 | zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, |
4454 | flood_control); | |
9718c54e | 4455 | if (zvtep) |
8b5fdf2e | 4456 | zebra_evpn_vtep_install(zevpn, zvtep); |
9718c54e AK |
4457 | else |
4458 | flog_err(EC_ZEBRA_VTEP_ADD_FAILED, | |
87d76d54 PR |
4459 | "Failed to add remote VTEP, VNI %u zevpn %p", |
4460 | vni, zevpn); | |
d62a17ae | 4461 | } |
d62a17ae | 4462 | } |
4463 | ||
ec93aa12 | 4464 | stream_failure: |
8068a649 | 4465 | return; |
13d60d35 | 4466 | } |
4467 | ||
1a98c087 MK |
4468 | /* |
4469 | * Add/Del gateway macip to evpn | |
4470 | * g/w can be: | |
4471 | * 1. SVI interface on a vlan aware bridge | |
4472 | * 2. SVI interface on a vlan unaware bridge | |
4473 | * 3. vrr interface (MACVLAN) associated to a SVI | |
4474 | * We advertise macip routes for an interface if it is associated to VxLan vlan | |
4475 | */ | |
4476 | int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, | |
4477 | int add) | |
4478 | { | |
4479 | struct ipaddr ip; | |
4480 | struct ethaddr macaddr; | |
87d76d54 | 4481 | zebra_evpn_t *zevpn = NULL; |
1a98c087 MK |
4482 | |
4483 | memset(&ip, 0, sizeof(struct ipaddr)); | |
4484 | memset(&macaddr, 0, sizeof(struct ethaddr)); | |
4485 | ||
2853fed6 | 4486 | /* Check if EVPN is enabled. */ |
4487 | if (!is_evpn_enabled()) | |
297a21b6 MK |
4488 | return 0; |
4489 | ||
1a98c087 MK |
4490 | if (IS_ZEBRA_IF_MACVLAN(ifp)) { |
4491 | struct interface *svi_if = | |
4492 | NULL; /* SVI corresponding to the MACVLAN */ | |
4493 | struct zebra_if *ifp_zif = | |
4494 | NULL; /* Zebra daemon specific info for MACVLAN */ | |
4495 | struct zebra_if *svi_if_zif = | |
4496 | NULL; /* Zebra daemon specific info for SVI*/ | |
4497 | ||
4498 | ifp_zif = ifp->info; | |
4499 | if (!ifp_zif) | |
4500 | return -1; | |
4501 | ||
71349e03 MK |
4502 | /* |
4503 | * for a MACVLAN interface the link represents the svi_if | |
4504 | */ | |
4505 | svi_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), | |
4506 | ifp_zif->link_ifindex); | |
1a98c087 | 4507 | if (!svi_if) { |
9df414fe QY |
4508 | zlog_debug("MACVLAN %s(%u) without link information", |
4509 | ifp->name, ifp->ifindex); | |
1a98c087 MK |
4510 | return -1; |
4511 | } | |
4512 | ||
4513 | if (IS_ZEBRA_IF_VLAN(svi_if)) { | |
71349e03 MK |
4514 | /* |
4515 | * If it is a vlan aware bridge then the link gives the | |
4516 | * bridge information | |
4517 | */ | |
4518 | struct interface *svi_if_link = NULL; | |
4519 | ||
1a98c087 | 4520 | svi_if_zif = svi_if->info; |
71349e03 MK |
4521 | if (svi_if_zif) { |
4522 | svi_if_link = if_lookup_by_index_per_ns( | |
60466a63 QY |
4523 | zebra_ns_lookup(NS_DEFAULT), |
4524 | svi_if_zif->link_ifindex); | |
8b5fdf2e PR |
4525 | zevpn = zebra_evpn_from_svi(svi_if, |
4526 | svi_if_link); | |
71349e03 | 4527 | } |
1a98c087 | 4528 | } else if (IS_ZEBRA_IF_BRIDGE(svi_if)) { |
71349e03 MK |
4529 | /* |
4530 | * If it is a vlan unaware bridge then svi is the bridge | |
4531 | * itself | |
4532 | */ | |
8b5fdf2e | 4533 | zevpn = zebra_evpn_from_svi(svi_if, svi_if); |
1a98c087 MK |
4534 | } |
4535 | } else if (IS_ZEBRA_IF_VLAN(ifp)) { | |
4536 | struct zebra_if *svi_if_zif = | |
71349e03 MK |
4537 | NULL; /* Zebra daemon specific info for SVI */ |
4538 | struct interface *svi_if_link = | |
4539 | NULL; /* link info for the SVI = bridge info */ | |
1a98c087 MK |
4540 | |
4541 | svi_if_zif = ifp->info; | |
e3bb770c IS |
4542 | if (svi_if_zif) { |
4543 | svi_if_link = if_lookup_by_index_per_ns( | |
cef91a18 QY |
4544 | zebra_ns_lookup(NS_DEFAULT), |
4545 | svi_if_zif->link_ifindex); | |
e3bb770c | 4546 | if (svi_if_link) |
8b5fdf2e | 4547 | zevpn = zebra_evpn_from_svi(ifp, svi_if_link); |
e3bb770c | 4548 | } |
1a98c087 | 4549 | } else if (IS_ZEBRA_IF_BRIDGE(ifp)) { |
8b5fdf2e | 4550 | zevpn = zebra_evpn_from_svi(ifp, ifp); |
1a98c087 MK |
4551 | } |
4552 | ||
87d76d54 | 4553 | if (!zevpn) |
1a98c087 MK |
4554 | return 0; |
4555 | ||
87d76d54 | 4556 | if (!zevpn->vxlan_if) { |
9df414fe | 4557 | zlog_debug("VNI %u hash %p doesn't have intf upon MACVLAN up", |
87d76d54 | 4558 | zevpn->vni, zevpn); |
1a98c087 MK |
4559 | return -1; |
4560 | } | |
4561 | ||
1a98c087 | 4562 | |
1a98c087 MK |
4563 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); |
4564 | ||
4565 | if (p->family == AF_INET) { | |
4566 | ip.ipa_type = IPADDR_V4; | |
4567 | memcpy(&(ip.ipaddr_v4), &(p->u.prefix4), | |
4568 | sizeof(struct in_addr)); | |
4569 | } else if (p->family == AF_INET6) { | |
4570 | ip.ipa_type = IPADDR_V6; | |
4571 | memcpy(&(ip.ipaddr_v6), &(p->u.prefix6), | |
4572 | sizeof(struct in6_addr)); | |
4573 | } | |
4574 | ||
4575 | ||
4576 | if (add) | |
8b5fdf2e | 4577 | zebra_evpn_gw_macip_add(ifp, zevpn, &macaddr, &ip); |
1a98c087 | 4578 | else |
8b5fdf2e | 4579 | zebra_evpn_gw_macip_del(ifp, zevpn, &ip); |
1a98c087 MK |
4580 | |
4581 | return 0; | |
4582 | } | |
4583 | ||
2232a77c | 4584 | /* |
b7cfce93 MK |
4585 | * Handle SVI interface going down. |
4586 | * SVI can be associated to either L3-VNI or L2-VNI. | |
4587 | * For L2-VNI: At this point, this is a NOP since | |
4588 | * the kernel deletes the neighbor entries on this SVI (if any). | |
87d76d54 | 4589 | * We only need to update the vrf corresponding to zevpn. |
b7cfce93 MK |
4590 | * For L3-VNI: L3-VNI is operationally down, update mac-ip routes and delete |
4591 | * from bgp | |
2232a77c | 4592 | */ |
d62a17ae | 4593 | int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if) |
2232a77c | 4594 | { |
b7cfce93 MK |
4595 | zebra_l3vni_t *zl3vni = NULL; |
4596 | ||
4597 | zl3vni = zl3vni_from_svi(ifp, link_if); | |
4598 | if (zl3vni) { | |
4599 | ||
4600 | /* process l3-vni down */ | |
4601 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
4602 | ||
4603 | /* remove association with svi-if */ | |
4604 | zl3vni->svi_if = NULL; | |
4605 | } else { | |
87d76d54 | 4606 | zebra_evpn_t *zevpn = NULL; |
b7cfce93 | 4607 | |
87d76d54 | 4608 | /* since we dont have svi corresponding to zevpn, we associate it |
b7cfce93 MK |
4609 | * to default vrf. Note: the corresponding neigh entries on the |
4610 | * SVI would have already been deleted */ | |
8b5fdf2e | 4611 | zevpn = zebra_evpn_from_svi(ifp, link_if); |
87d76d54 PR |
4612 | if (zevpn) { |
4613 | zevpn->vrf_id = VRF_DEFAULT; | |
b7cfce93 MK |
4614 | |
4615 | /* update the tenant vrf in BGP */ | |
8b5fdf2e | 4616 | zebra_evpn_send_add_to_client(zevpn); |
b7cfce93 MK |
4617 | } |
4618 | } | |
d62a17ae | 4619 | return 0; |
2232a77c | 4620 | } |
4621 | ||
4622 | /* | |
b7cfce93 MK |
4623 | * Handle SVI interface coming up. |
4624 | * SVI can be associated to L3-VNI (l3vni vxlan interface) or L2-VNI (l2-vni | |
4625 | * vxlan intf). | |
4626 | * For L2-VNI: we need to install any remote neighbors entried (used for | |
4627 | * apr-suppression) | |
4628 | * For L3-VNI: SVI will be used to get the rmac to be used with L3-VNI | |
2232a77c | 4629 | */ |
d62a17ae | 4630 | int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) |
2232a77c | 4631 | { |
87d76d54 | 4632 | zebra_evpn_t *zevpn = NULL; |
b7cfce93 | 4633 | zebra_l3vni_t *zl3vni = NULL; |
2232a77c | 4634 | |
b7cfce93 MK |
4635 | zl3vni = zl3vni_from_svi(ifp, link_if); |
4636 | if (zl3vni) { | |
2232a77c | 4637 | |
b7cfce93 MK |
4638 | /* associate with svi */ |
4639 | zl3vni->svi_if = ifp; | |
2232a77c | 4640 | |
b7cfce93 MK |
4641 | /* process oper-up */ |
4642 | if (is_l3vni_oper_up(zl3vni)) | |
4643 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
4644 | } else { | |
4645 | ||
4646 | /* process SVI up for l2-vni */ | |
4647 | struct neigh_walk_ctx n_wctx; | |
4648 | ||
8b5fdf2e | 4649 | zevpn = zebra_evpn_from_svi(ifp, link_if); |
87d76d54 | 4650 | if (!zevpn) |
b7cfce93 MK |
4651 | return 0; |
4652 | ||
87d76d54 | 4653 | if (!zevpn->vxlan_if) { |
9df414fe | 4654 | zlog_debug( |
43e52561 | 4655 | "VNI %u hash %p doesn't have intf upon SVI up", |
87d76d54 | 4656 | zevpn->vni, zevpn); |
b7cfce93 MK |
4657 | return -1; |
4658 | } | |
4659 | ||
4660 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 LB |
4661 | zlog_debug( |
4662 | "SVI %s(%u) VNI %u VRF %s is UP, installing neighbors", | |
87d76d54 | 4663 | ifp->name, ifp->ifindex, zevpn->vni, |
a36898e7 | 4664 | vrf_id_to_name(ifp->vrf_id)); |
2232a77c | 4665 | |
b7cfce93 | 4666 | /* update the vrf information for l2-vni and inform bgp */ |
87d76d54 | 4667 | zevpn->vrf_id = ifp->vrf_id; |
8b5fdf2e | 4668 | zebra_evpn_send_add_to_client(zevpn); |
b7cfce93 MK |
4669 | |
4670 | /* Install any remote neighbors for this VNI. */ | |
4671 | memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); | |
87d76d54 | 4672 | n_wctx.zevpn = zevpn; |
7cbae20a | 4673 | hash_iterate(zevpn->neigh_table, zebra_evpn_install_neigh_hash, |
b7cfce93 MK |
4674 | &n_wctx); |
4675 | } | |
2232a77c | 4676 | |
d62a17ae | 4677 | return 0; |
2232a77c | 4678 | } |
4679 | ||
0056f687 CS |
4680 | /* |
4681 | * Handle MAC-VLAN interface going down. | |
4682 | * L3VNI: When MAC-VLAN interface goes down, | |
4683 | * find its associated SVI and update type2/type-5 routes | |
4684 | * with SVI as RMAC | |
4685 | */ | |
4686 | void zebra_vxlan_macvlan_down(struct interface *ifp) | |
4687 | { | |
4688 | zebra_l3vni_t *zl3vni = NULL; | |
4689 | struct zebra_if *zif, *link_zif; | |
4690 | struct interface *link_ifp, *link_if; | |
4691 | ||
4692 | zif = ifp->info; | |
4693 | assert(zif); | |
4694 | link_ifp = zif->link; | |
59260d4a | 4695 | if (!link_ifp) { |
65e76a9b CS |
4696 | if (IS_ZEBRA_DEBUG_VXLAN) { |
4697 | struct interface *ifp; | |
4698 | ||
4699 | ifp = if_lookup_by_index_all_vrf(zif->link_ifindex); | |
c1c292e7 CS |
4700 | zlog_debug("macvlan parent link is not found. Parent index %d ifp %s", |
4701 | zif->link_ifindex, ifp ? ifp->name : " "); | |
65e76a9b | 4702 | } |
59260d4a CS |
4703 | return; |
4704 | } | |
0056f687 CS |
4705 | link_zif = link_ifp->info; |
4706 | assert(link_zif); | |
4707 | ||
4708 | link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), | |
4709 | link_zif->link_ifindex); | |
4710 | ||
4711 | zl3vni = zl3vni_from_svi(link_ifp, link_if); | |
4712 | if (zl3vni) { | |
4713 | zl3vni->mac_vlan_if = NULL; | |
4714 | if (is_l3vni_oper_up(zl3vni)) | |
4715 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
4716 | } | |
4717 | } | |
4718 | ||
4719 | /* | |
4720 | * Handle MAC-VLAN interface going up. | |
4721 | * L3VNI: When MAC-VLAN interface comes up, | |
4722 | * find its associated SVI and update type-2 routes | |
4723 | * with MAC-VLAN's MAC as RMAC and for type-5 routes | |
4724 | * use SVI's MAC as RMAC. | |
4725 | */ | |
4726 | void zebra_vxlan_macvlan_up(struct interface *ifp) | |
4727 | { | |
4728 | zebra_l3vni_t *zl3vni = NULL; | |
4729 | struct zebra_if *zif, *link_zif; | |
4730 | struct interface *link_ifp, *link_if; | |
4731 | ||
4732 | zif = ifp->info; | |
4733 | assert(zif); | |
4734 | link_ifp = zif->link; | |
4735 | link_zif = link_ifp->info; | |
4736 | assert(link_zif); | |
4737 | ||
4738 | link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), | |
4739 | link_zif->link_ifindex); | |
4740 | zl3vni = zl3vni_from_svi(link_ifp, link_if); | |
4741 | if (zl3vni) { | |
4742 | /* associate with macvlan (VRR) interface */ | |
4743 | zl3vni->mac_vlan_if = ifp; | |
4744 | ||
4745 | /* process oper-up */ | |
4746 | if (is_l3vni_oper_up(zl3vni)) | |
4747 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
4748 | } | |
4749 | } | |
4750 | ||
13d60d35 | 4751 | /* |
b7cfce93 | 4752 | * Handle VxLAN interface down |
13d60d35 | 4753 | */ |
d62a17ae | 4754 | int zebra_vxlan_if_down(struct interface *ifp) |
13d60d35 | 4755 | { |
d62a17ae | 4756 | vni_t vni; |
b7cfce93 MK |
4757 | struct zebra_if *zif = NULL; |
4758 | struct zebra_l2info_vxlan *vxl = NULL; | |
643215ce | 4759 | zebra_l3vni_t *zl3vni = NULL; |
87d76d54 | 4760 | zebra_evpn_t *zevpn; |
13d60d35 | 4761 | |
2853fed6 | 4762 | /* Check if EVPN is enabled. */ |
4763 | if (!is_evpn_enabled()) | |
d62a17ae | 4764 | return 0; |
13d60d35 | 4765 | |
d62a17ae | 4766 | zif = ifp->info; |
4767 | assert(zif); | |
4768 | vxl = &zif->l2info.vxl; | |
4769 | vni = vxl->vni; | |
13d60d35 | 4770 | |
643215ce | 4771 | zl3vni = zl3vni_lookup(vni); |
4772 | if (zl3vni) { | |
b7cfce93 | 4773 | /* process-if-down for l3-vni */ |
b7cfce93 | 4774 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
4775 | zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name, |
4776 | ifp->ifindex, vni); | |
b7cfce93 | 4777 | |
b7cfce93 | 4778 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
b7cfce93 MK |
4779 | } else { |
4780 | /* process if-down for l2-vni */ | |
b7cfce93 | 4781 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
4782 | zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name, |
4783 | ifp->ifindex, vni); | |
13d60d35 | 4784 | |
b7cfce93 | 4785 | /* Locate hash entry; it is expected to exist. */ |
8b5fdf2e | 4786 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 4787 | if (!zevpn) { |
9df414fe | 4788 | zlog_debug( |
b7cfce93 MK |
4789 | "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u", |
4790 | ifp->name, ifp->ifindex, vni); | |
4791 | return -1; | |
4792 | } | |
13d60d35 | 4793 | |
87d76d54 | 4794 | assert(zevpn->vxlan_if == ifp); |
13d60d35 | 4795 | |
c7e83a4e CS |
4796 | /* remove from l3-vni list */ |
4797 | zl3vni = zl3vni_from_vrf(zevpn->vrf_id); | |
4798 | if (zl3vni) | |
4799 | listnode_delete(zl3vni->l2vnis, zevpn); | |
4800 | ||
b7cfce93 | 4801 | /* Delete this VNI from BGP. */ |
8b5fdf2e | 4802 | zebra_evpn_send_del_to_client(zevpn); |
2232a77c | 4803 | |
b7cfce93 | 4804 | /* Free up all neighbors and MACs, if any. */ |
7cbae20a | 4805 | zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); |
b2998086 | 4806 | zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); |
13d60d35 | 4807 | |
b7cfce93 | 4808 | /* Free up all remote VTEPs, if any. */ |
8b5fdf2e | 4809 | zebra_evpn_vtep_del_all(zevpn, 1); |
b7cfce93 | 4810 | } |
d62a17ae | 4811 | return 0; |
13d60d35 | 4812 | } |
4813 | ||
4814 | /* | |
4815 | * Handle VxLAN interface up - update BGP if required. | |
4816 | */ | |
d62a17ae | 4817 | int zebra_vxlan_if_up(struct interface *ifp) |
13d60d35 | 4818 | { |
d62a17ae | 4819 | vni_t vni; |
b7cfce93 MK |
4820 | struct zebra_if *zif = NULL; |
4821 | struct zebra_l2info_vxlan *vxl = NULL; | |
87d76d54 | 4822 | zebra_evpn_t *zevpn = NULL; |
643215ce | 4823 | zebra_l3vni_t *zl3vni = NULL; |
13d60d35 | 4824 | |
2853fed6 | 4825 | /* Check if EVPN is enabled. */ |
4826 | if (!is_evpn_enabled()) | |
d62a17ae | 4827 | return 0; |
13d60d35 | 4828 | |
d62a17ae | 4829 | zif = ifp->info; |
4830 | assert(zif); | |
4831 | vxl = &zif->l2info.vxl; | |
4832 | vni = vxl->vni; | |
13d60d35 | 4833 | |
643215ce | 4834 | zl3vni = zl3vni_lookup(vni); |
4835 | if (zl3vni) { | |
b7cfce93 | 4836 | /* we need to associate with SVI, if any, we can associate with |
523cafc4 | 4837 | * svi-if only after association with vxlan-intf is complete |
4838 | */ | |
b7cfce93 | 4839 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); |
06d9cde5 CS |
4840 | zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); |
4841 | ||
4842 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4843 | zlog_debug("Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s" | |
4844 | , ifp->name, ifp->ifindex, vni, | |
4845 | zl3vni->svi_if ? zl3vni->svi_if->name : "NIL", | |
4846 | zl3vni->mac_vlan_if ? | |
4847 | zl3vni->mac_vlan_if->name : "NIL"); | |
b7cfce93 MK |
4848 | |
4849 | if (is_l3vni_oper_up(zl3vni)) | |
4850 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
4851 | } else { | |
4852 | /* Handle L2-VNI add */ | |
b7cfce93 MK |
4853 | struct interface *vlan_if = NULL; |
4854 | ||
4855 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 LB |
4856 | zlog_debug("Intf %s(%u) L2-VNI %u is UP", ifp->name, |
4857 | ifp->ifindex, vni); | |
b7cfce93 MK |
4858 | |
4859 | /* Locate hash entry; it is expected to exist. */ | |
8b5fdf2e | 4860 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 4861 | if (!zevpn) { |
9df414fe | 4862 | zlog_debug( |
87d76d54 | 4863 | "Failed to locate EVPN hash at UP, IF %s(%u) VNI %u", |
b7cfce93 MK |
4864 | ifp->name, ifp->ifindex, vni); |
4865 | return -1; | |
4866 | } | |
4867 | ||
87d76d54 | 4868 | assert(zevpn->vxlan_if == ifp); |
7cbae20a | 4869 | vlan_if = zvni_map_to_svi(vxl->access_vlan, |
b7cfce93 MK |
4870 | zif->brslave_info.br_if); |
4871 | if (vlan_if) { | |
87d76d54 | 4872 | zevpn->vrf_id = vlan_if->vrf_id; |
a36898e7 | 4873 | zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); |
b7cfce93 | 4874 | if (zl3vni) |
c7e83a4e | 4875 | listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); |
b7cfce93 MK |
4876 | } |
4877 | ||
4878 | /* If part of a bridge, inform BGP about this VNI. */ | |
4879 | /* Also, read and populate local MACs and neighbors. */ | |
4880 | if (zif->brslave_info.br_if) { | |
8b5fdf2e PR |
4881 | zebra_evpn_send_add_to_client(zevpn); |
4882 | zebra_evpn_read_mac_neigh(zevpn, ifp); | |
b7cfce93 | 4883 | } |
d62a17ae | 4884 | } |
13d60d35 | 4885 | |
d62a17ae | 4886 | return 0; |
13d60d35 | 4887 | } |
4888 | ||
4889 | /* | |
4890 | * Handle VxLAN interface delete. Locate and remove entry in hash table | |
4891 | * and update BGP, if required. | |
4892 | */ | |
d62a17ae | 4893 | int zebra_vxlan_if_del(struct interface *ifp) |
13d60d35 | 4894 | { |
d62a17ae | 4895 | vni_t vni; |
b7cfce93 MK |
4896 | struct zebra_if *zif = NULL; |
4897 | struct zebra_l2info_vxlan *vxl = NULL; | |
87d76d54 | 4898 | zebra_evpn_t *zevpn = NULL; |
643215ce | 4899 | zebra_l3vni_t *zl3vni = NULL; |
13d60d35 | 4900 | |
2853fed6 | 4901 | /* Check if EVPN is enabled. */ |
4902 | if (!is_evpn_enabled()) | |
d62a17ae | 4903 | return 0; |
13d60d35 | 4904 | |
d62a17ae | 4905 | zif = ifp->info; |
4906 | assert(zif); | |
4907 | vxl = &zif->l2info.vxl; | |
4908 | vni = vxl->vni; | |
13d60d35 | 4909 | |
643215ce | 4910 | zl3vni = zl3vni_lookup(vni); |
4911 | if (zl3vni) { | |
b7cfce93 MK |
4912 | |
4913 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 LB |
4914 | zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name, |
4915 | ifp->ifindex); | |
13d60d35 | 4916 | |
b7cfce93 MK |
4917 | /* process oper-down for l3-vni */ |
4918 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
2232a77c | 4919 | |
b7cfce93 | 4920 | /* remove the association with vxlan_if */ |
b67a60d2 | 4921 | memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr)); |
b7cfce93 MK |
4922 | zl3vni->vxlan_if = NULL; |
4923 | } else { | |
13d60d35 | 4924 | |
b7cfce93 | 4925 | /* process if-del for l2-vni*/ |
b7cfce93 | 4926 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
4927 | zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name, |
4928 | ifp->ifindex); | |
b7cfce93 MK |
4929 | |
4930 | /* Locate hash entry; it is expected to exist. */ | |
8b5fdf2e | 4931 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 4932 | if (!zevpn) { |
9df414fe | 4933 | zlog_debug( |
b7cfce93 MK |
4934 | "Failed to locate VNI hash at del, IF %s(%u) VNI %u", |
4935 | ifp->name, ifp->ifindex, vni); | |
4936 | return 0; | |
4937 | } | |
4938 | ||
4939 | /* remove from l3-vni list */ | |
87d76d54 | 4940 | zl3vni = zl3vni_from_vrf(zevpn->vrf_id); |
b7cfce93 | 4941 | if (zl3vni) |
87d76d54 | 4942 | listnode_delete(zl3vni->l2vnis, zevpn); |
b7cfce93 | 4943 | /* Delete VNI from BGP. */ |
8b5fdf2e | 4944 | zebra_evpn_send_del_to_client(zevpn); |
b7cfce93 MK |
4945 | |
4946 | /* Free up all neighbors and MAC, if any. */ | |
7cbae20a | 4947 | zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH); |
b2998086 | 4948 | zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC); |
b7cfce93 MK |
4949 | |
4950 | /* Free up all remote VTEPs, if any. */ | |
8b5fdf2e | 4951 | zebra_evpn_vtep_del_all(zevpn, 0); |
b7cfce93 MK |
4952 | |
4953 | /* Delete the hash entry. */ | |
8b5fdf2e | 4954 | if (zebra_evpn_vxlan_del(zevpn)) { |
e914ccbe | 4955 | flog_err(EC_ZEBRA_VNI_DEL_FAILED, |
87d76d54 PR |
4956 | "Failed to del EVPN hash %p, IF %s(%u) VNI %u", |
4957 | zevpn, ifp->name, ifp->ifindex, zevpn->vni); | |
b7cfce93 MK |
4958 | return -1; |
4959 | } | |
d62a17ae | 4960 | } |
d62a17ae | 4961 | return 0; |
13d60d35 | 4962 | } |
4963 | ||
4964 | /* | |
4965 | * Handle VxLAN interface update - change to tunnel IP, master or VLAN. | |
4966 | */ | |
d7c0a89a | 4967 | int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags) |
d62a17ae | 4968 | { |
d62a17ae | 4969 | vni_t vni; |
b7cfce93 MK |
4970 | struct zebra_if *zif = NULL; |
4971 | struct zebra_l2info_vxlan *vxl = NULL; | |
87d76d54 | 4972 | zebra_evpn_t *zevpn = NULL; |
643215ce | 4973 | zebra_l3vni_t *zl3vni = NULL; |
d62a17ae | 4974 | |
2853fed6 | 4975 | /* Check if EVPN is enabled. */ |
4976 | if (!is_evpn_enabled()) | |
d62a17ae | 4977 | return 0; |
4978 | ||
4979 | zif = ifp->info; | |
4980 | assert(zif); | |
4981 | vxl = &zif->l2info.vxl; | |
4982 | vni = vxl->vni; | |
4983 | ||
643215ce | 4984 | zl3vni = zl3vni_lookup(vni); |
4985 | if (zl3vni) { | |
af026ae4 | 4986 | |
b7cfce93 MK |
4987 | if (IS_ZEBRA_DEBUG_VXLAN) |
4988 | zlog_debug( | |
9bcef951 | 4989 | "Update L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x", |
996c9314 | 4990 | vni, ifp->name, ifp->ifindex, vxl->access_vlan, |
9bcef951 | 4991 | &vxl->vtep_ip, |
b7cfce93 MK |
4992 | zif->brslave_info.bridge_ifindex, chgflags); |
4993 | ||
4994 | /* Removed from bridge? Cleanup and return */ | |
4995 | if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) | |
4996 | && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { | |
4997 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
4998 | return 0; | |
4999 | } | |
5000 | ||
5001 | /* access-vlan change - process oper down, associate with new | |
523cafc4 | 5002 | * svi_if and then process oper up again |
5003 | */ | |
b7cfce93 MK |
5004 | if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { |
5005 | if (if_is_operative(ifp)) { | |
5006 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
5007 | zl3vni->svi_if = NULL; | |
5008 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); | |
06d9cde5 CS |
5009 | zl3vni->mac_vlan_if = |
5010 | zl3vni_map_to_mac_vlan_if(zl3vni); | |
bca63dc8 | 5011 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
b7cfce93 MK |
5012 | if (is_l3vni_oper_up(zl3vni)) |
5013 | zebra_vxlan_process_l3vni_oper_up( | |
996c9314 | 5014 | zl3vni); |
b7cfce93 MK |
5015 | } |
5016 | } | |
d62a17ae | 5017 | |
12eeac84 MK |
5018 | /* |
5019 | * local-ip change - process oper down, associate with new | |
5020 | * local-ip and then process oper up again | |
5021 | */ | |
5022 | if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { | |
5023 | if (if_is_operative(ifp)) { | |
5024 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
5025 | zl3vni->local_vtep_ip = vxl->vtep_ip; | |
5026 | if (is_l3vni_oper_up(zl3vni)) | |
5027 | zebra_vxlan_process_l3vni_oper_up( | |
996c9314 | 5028 | zl3vni); |
12eeac84 MK |
5029 | } |
5030 | } | |
5031 | ||
bca63dc8 MK |
5032 | /* Update local tunnel IP. */ |
5033 | zl3vni->local_vtep_ip = vxl->vtep_ip; | |
5034 | ||
12eeac84 MK |
5035 | /* if we have a valid new master, process l3-vni oper up */ |
5036 | if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { | |
5037 | if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) | |
b7cfce93 MK |
5038 | zebra_vxlan_process_l3vni_oper_up(zl3vni); |
5039 | } | |
5040 | } else { | |
d62a17ae | 5041 | |
b7cfce93 | 5042 | /* Update VNI hash. */ |
8b5fdf2e | 5043 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 5044 | if (!zevpn) { |
9df414fe | 5045 | zlog_debug( |
87d76d54 | 5046 | "Failed to find EVPN hash on update, IF %s(%u) VNI %u", |
b7cfce93 MK |
5047 | ifp->name, ifp->ifindex, vni); |
5048 | return -1; | |
5049 | } | |
d62a17ae | 5050 | |
b7cfce93 MK |
5051 | if (IS_ZEBRA_DEBUG_VXLAN) |
5052 | zlog_debug( | |
9bcef951 | 5053 | "Update L2-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x", |
996c9314 | 5054 | vni, ifp->name, ifp->ifindex, vxl->access_vlan, |
9bcef951 | 5055 | &vxl->vtep_ip, |
b7cfce93 MK |
5056 | zif->brslave_info.bridge_ifindex, chgflags); |
5057 | ||
5058 | /* Removed from bridge? Cleanup and return */ | |
5059 | if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) | |
5060 | && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { | |
5061 | /* Delete from client, remove all remote VTEPs */ | |
5062 | /* Also, free up all MACs and neighbors. */ | |
8b5fdf2e | 5063 | zebra_evpn_send_del_to_client(zevpn); |
7cbae20a | 5064 | zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); |
b2998086 | 5065 | zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); |
8b5fdf2e | 5066 | zebra_evpn_vtep_del_all(zevpn, 1); |
b7cfce93 MK |
5067 | return 0; |
5068 | } | |
d62a17ae | 5069 | |
b7cfce93 MK |
5070 | /* Handle other changes. */ |
5071 | if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { | |
5072 | /* Remove all existing local neigh and MACs for this VNI | |
5073 | * (including from BGP) | |
5074 | */ | |
7cbae20a | 5075 | zebra_evpn_neigh_del_all(zevpn, 0, 1, DEL_LOCAL_MAC); |
b2998086 | 5076 | zebra_evpn_mac_del_all(zevpn, 0, 1, DEL_LOCAL_MAC); |
b7cfce93 | 5077 | } |
d62a17ae | 5078 | |
87d76d54 PR |
5079 | if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr || |
5080 | zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) { | |
5081 | zebra_vxlan_sg_deref(zevpn->local_vtep_ip, | |
5082 | zevpn->mcast_grp); | |
abfa0a96 | 5083 | zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp); |
87d76d54 PR |
5084 | zevpn->local_vtep_ip = vxl->vtep_ip; |
5085 | zevpn->mcast_grp = vxl->mcast_grp; | |
ce5160c0 AK |
5086 | /* on local vtep-ip check if ES orig-ip |
5087 | * needs to be updated | |
5088 | */ | |
87d76d54 | 5089 | zebra_evpn_es_set_base_evpn(zevpn); |
abfa0a96 | 5090 | } |
87d76d54 | 5091 | zevpn_vxlan_if_set(zevpn, ifp, true /* set */); |
b7cfce93 MK |
5092 | /* Take further actions needed. |
5093 | * Note that if we are here, there is a change of interest. | |
5094 | */ | |
5095 | /* If down or not mapped to a bridge, we're done. */ | |
5096 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
5097 | return 0; | |
d62a17ae | 5098 | |
b7cfce93 MK |
5099 | /* Inform BGP, if there is a change of interest. */ |
5100 | if (chgflags | |
39c46ff1 AK |
5101 | & (ZEBRA_VXLIF_MASTER_CHANGE | |
5102 | ZEBRA_VXLIF_LOCAL_IP_CHANGE | | |
5103 | ZEBRA_VXLIF_MCAST_GRP_CHANGE)) | |
8b5fdf2e | 5104 | zebra_evpn_send_add_to_client(zevpn); |
b7cfce93 MK |
5105 | |
5106 | /* If there is a valid new master or a VLAN mapping change, | |
5107 | * read and populate local MACs and neighbors. | |
5108 | * Also, reinstall any remote MACs and neighbors | |
5109 | * for this VNI (based on new VLAN). | |
5110 | */ | |
5111 | if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) | |
8b5fdf2e | 5112 | zebra_evpn_read_mac_neigh(zevpn, ifp); |
b7cfce93 MK |
5113 | else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { |
5114 | struct mac_walk_ctx m_wctx; | |
5115 | struct neigh_walk_ctx n_wctx; | |
5116 | ||
8b5fdf2e | 5117 | zebra_evpn_read_mac_neigh(zevpn, ifp); |
b7cfce93 MK |
5118 | |
5119 | memset(&m_wctx, 0, sizeof(struct mac_walk_ctx)); | |
87d76d54 | 5120 | m_wctx.zevpn = zevpn; |
8b5fdf2e PR |
5121 | hash_iterate(zevpn->mac_table, |
5122 | zebra_evpn_install_mac_hash, &m_wctx); | |
b7cfce93 MK |
5123 | |
5124 | memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); | |
87d76d54 | 5125 | n_wctx.zevpn = zevpn; |
7cbae20a PR |
5126 | hash_iterate(zevpn->neigh_table, |
5127 | zebra_evpn_install_neigh_hash, &n_wctx); | |
b7cfce93 | 5128 | } |
d62a17ae | 5129 | } |
5130 | ||
5131 | return 0; | |
13d60d35 | 5132 | } |
5133 | ||
5134 | /* | |
5135 | * Handle VxLAN interface add. | |
5136 | */ | |
d62a17ae | 5137 | int zebra_vxlan_if_add(struct interface *ifp) |
13d60d35 | 5138 | { |
d62a17ae | 5139 | vni_t vni; |
b7cfce93 MK |
5140 | struct zebra_if *zif = NULL; |
5141 | struct zebra_l2info_vxlan *vxl = NULL; | |
87d76d54 | 5142 | zebra_evpn_t *zevpn = NULL; |
643215ce | 5143 | zebra_l3vni_t *zl3vni = NULL; |
13d60d35 | 5144 | |
2853fed6 | 5145 | /* Check if EVPN is enabled. */ |
5146 | if (!is_evpn_enabled()) | |
d62a17ae | 5147 | return 0; |
13d60d35 | 5148 | |
d62a17ae | 5149 | zif = ifp->info; |
5150 | assert(zif); | |
5151 | vxl = &zif->l2info.vxl; | |
5152 | vni = vxl->vni; | |
13d60d35 | 5153 | |
643215ce | 5154 | zl3vni = zl3vni_lookup(vni); |
5155 | if (zl3vni) { | |
13d60d35 | 5156 | |
b7cfce93 | 5157 | /* process if-add for l3-vni*/ |
b7cfce93 MK |
5158 | if (IS_ZEBRA_DEBUG_VXLAN) |
5159 | zlog_debug( | |
9bcef951 | 5160 | "Add L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u", |
996c9314 | 5161 | vni, ifp->name, ifp->ifindex, vxl->access_vlan, |
9bcef951 | 5162 | &vxl->vtep_ip, |
b7cfce93 MK |
5163 | zif->brslave_info.bridge_ifindex); |
5164 | ||
b7cfce93 | 5165 | /* associate with vxlan_if */ |
b67a60d2 | 5166 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
b7cfce93 MK |
5167 | zl3vni->vxlan_if = ifp; |
5168 | ||
5169 | /* Associate with SVI, if any. We can associate with svi-if only | |
5170 | * after association with vxlan_if is complete */ | |
5171 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); | |
5172 | ||
06d9cde5 CS |
5173 | zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); |
5174 | ||
b7cfce93 MK |
5175 | if (is_l3vni_oper_up(zl3vni)) |
5176 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
5177 | } else { | |
5178 | ||
5179 | /* process if-add for l2-vni */ | |
b7cfce93 MK |
5180 | struct interface *vlan_if = NULL; |
5181 | ||
87d76d54 | 5182 | /* Create or update EVPN hash. */ |
8b5fdf2e | 5183 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 5184 | if (!zevpn) { |
8b5fdf2e | 5185 | zevpn = zebra_evpn_add(vni); |
87d76d54 | 5186 | if (!zevpn) { |
af4c2728 | 5187 | flog_err( |
e914ccbe | 5188 | EC_ZEBRA_VNI_ADD_FAILED, |
87d76d54 | 5189 | "Failed to add EVPN hash, IF %s(%u) VNI %u", |
b7cfce93 MK |
5190 | ifp->name, ifp->ifindex, vni); |
5191 | return -1; | |
5192 | } | |
5193 | } | |
5194 | ||
87d76d54 PR |
5195 | if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr || |
5196 | zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) { | |
5197 | zebra_vxlan_sg_deref(zevpn->local_vtep_ip, | |
5198 | zevpn->mcast_grp); | |
abfa0a96 | 5199 | zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp); |
87d76d54 PR |
5200 | zevpn->local_vtep_ip = vxl->vtep_ip; |
5201 | zevpn->mcast_grp = vxl->mcast_grp; | |
ce5160c0 AK |
5202 | /* on local vtep-ip check if ES orig-ip |
5203 | * needs to be updated | |
5204 | */ | |
87d76d54 | 5205 | zebra_evpn_es_set_base_evpn(zevpn); |
abfa0a96 | 5206 | } |
87d76d54 | 5207 | zevpn_vxlan_if_set(zevpn, ifp, true /* set */); |
7cbae20a | 5208 | vlan_if = zvni_map_to_svi(vxl->access_vlan, |
b7cfce93 MK |
5209 | zif->brslave_info.br_if); |
5210 | if (vlan_if) { | |
87d76d54 | 5211 | zevpn->vrf_id = vlan_if->vrf_id; |
a36898e7 | 5212 | zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); |
b7cfce93 | 5213 | if (zl3vni) |
c7e83a4e | 5214 | listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); |
b7cfce93 MK |
5215 | } |
5216 | ||
39c46ff1 AK |
5217 | if (IS_ZEBRA_DEBUG_VXLAN) { |
5218 | char addr_buf1[INET_ADDRSTRLEN]; | |
5219 | char addr_buf2[INET_ADDRSTRLEN]; | |
5220 | ||
5221 | inet_ntop(AF_INET, &vxl->vtep_ip, | |
5222 | addr_buf1, INET_ADDRSTRLEN); | |
5223 | inet_ntop(AF_INET, &vxl->mcast_grp, | |
5224 | addr_buf2, INET_ADDRSTRLEN); | |
5225 | ||
b7cfce93 | 5226 | zlog_debug( |
aa0677b4 | 5227 | "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s mcast_grp %s master %u", |
b7cfce93 | 5228 | vni, |
a36898e7 | 5229 | vlan_if ? vrf_id_to_name(vlan_if->vrf_id) |
08ab35fe | 5230 | : VRF_DEFAULT_NAME, |
996c9314 | 5231 | ifp->name, ifp->ifindex, vxl->access_vlan, |
39c46ff1 | 5232 | addr_buf1, addr_buf2, |
b7cfce93 | 5233 | zif->brslave_info.bridge_ifindex); |
39c46ff1 | 5234 | } |
b7cfce93 MK |
5235 | |
5236 | /* If down or not mapped to a bridge, we're done. */ | |
5237 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
5238 | return 0; | |
5239 | ||
5240 | /* Inform BGP */ | |
8b5fdf2e | 5241 | zebra_evpn_send_add_to_client(zevpn); |
b7cfce93 MK |
5242 | |
5243 | /* Read and populate local MACs and neighbors */ | |
8b5fdf2e | 5244 | zebra_evpn_read_mac_neigh(zevpn, ifp); |
b7cfce93 MK |
5245 | } |
5246 | ||
5247 | return 0; | |
5248 | } | |
5249 | ||
996c9314 LB |
5250 | int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, |
5251 | char *err, int err_str_sz, int filter, | |
5252 | int add) | |
b7cfce93 MK |
5253 | { |
5254 | zebra_l3vni_t *zl3vni = NULL; | |
5e53dce3 | 5255 | struct zebra_vrf *zvrf_evpn = NULL; |
b7cfce93 | 5256 | |
5e53dce3 T |
5257 | zvrf_evpn = zebra_vrf_get_evpn(); |
5258 | if (!zvrf_evpn) | |
b7cfce93 MK |
5259 | return -1; |
5260 | ||
5261 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 | 5262 | zlog_debug("vrf %s vni %u %s", zvrf_name(zvrf), vni, |
b7cfce93 MK |
5263 | add ? "ADD" : "DEL"); |
5264 | ||
5265 | if (add) { | |
5266 | ||
3b0a590b | 5267 | /* Remove L2VNI if present */ |
b7cfce93 MK |
5268 | zebra_vxlan_handle_vni_transition(zvrf, vni, add); |
5269 | ||
5270 | /* check if the vni is already present under zvrf */ | |
5271 | if (zvrf->l3vni) { | |
3f02fbab | 5272 | snprintf(err, err_str_sz, |
b7cfce93 MK |
5273 | "VNI is already configured under the vrf"); |
5274 | return -1; | |
5275 | } | |
5276 | ||
5277 | /* check if this VNI is already present in the system */ | |
5278 | zl3vni = zl3vni_lookup(vni); | |
5279 | if (zl3vni) { | |
3f02fbab | 5280 | snprintf(err, err_str_sz, |
b7cfce93 MK |
5281 | "VNI is already configured as L3-VNI"); |
5282 | return -1; | |
5283 | } | |
5284 | ||
5285 | /* add the L3-VNI to the global table */ | |
5286 | zl3vni = zl3vni_add(vni, zvrf_id(zvrf)); | |
5287 | if (!zl3vni) { | |
996c9314 | 5288 | snprintf(err, err_str_sz, "Could not add L3-VNI"); |
b7cfce93 MK |
5289 | return -1; |
5290 | } | |
5291 | ||
5292 | /* associate the vrf with vni */ | |
5293 | zvrf->l3vni = vni; | |
5294 | ||
c48d9f5f MK |
5295 | /* set the filter in l3vni to denote if we are using l3vni only |
5296 | * for prefix routes | |
5297 | */ | |
5298 | if (filter) | |
5299 | SET_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY); | |
5300 | ||
b7cfce93 | 5301 | /* associate with vxlan-intf; |
523cafc4 | 5302 | * we need to associate with the vxlan-intf first |
5303 | */ | |
b7cfce93 MK |
5304 | zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni); |
5305 | ||
5306 | /* associate with corresponding SVI interface, we can associate | |
5307 | * with svi-if only after vxlan interface association is | |
523cafc4 | 5308 | * complete |
5309 | */ | |
b7cfce93 MK |
5310 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); |
5311 | ||
06d9cde5 CS |
5312 | zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); |
5313 | ||
5314 | if (IS_ZEBRA_DEBUG_VXLAN) | |
15569c58 DA |
5315 | zlog_debug( |
5316 | "%s: l3vni %u svi_if %s mac_vlan_if %s", | |
5317 | __func__, vni, | |
5318 | zl3vni->svi_if ? zl3vni->svi_if->name : "NIL", | |
5319 | zl3vni->mac_vlan_if ? zl3vni->mac_vlan_if->name | |
5320 | : "NIL"); | |
06d9cde5 | 5321 | |
b7cfce93 | 5322 | /* formulate l2vni list */ |
87d76d54 | 5323 | hash_iterate(zvrf_evpn->evpn_table, zevpn_add_to_l3vni_list, |
996c9314 | 5324 | zl3vni); |
b7cfce93 MK |
5325 | |
5326 | if (is_l3vni_oper_up(zl3vni)) | |
5327 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
5328 | ||
5329 | } else { | |
5330 | zl3vni = zl3vni_lookup(vni); | |
5331 | if (!zl3vni) { | |
3f02fbab | 5332 | snprintf(err, err_str_sz, "VNI doesn't exist"); |
d62a17ae | 5333 | return -1; |
5334 | } | |
b7cfce93 | 5335 | |
7a6ca8a6 KA |
5336 | if (zvrf->l3vni != vni) { |
5337 | snprintf(err, err_str_sz, | |
5338 | "VNI %d doesn't exist in VRF: %s", | |
5339 | vni, zvrf->vrf->name); | |
5340 | return -1; | |
5341 | } | |
5342 | ||
cf299714 MK |
5343 | if (filter && !CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)) { |
5344 | snprintf(err, ERR_STR_SZ, | |
5345 | "prefix-routes-only is not set for the vni"); | |
5346 | return -1; | |
5347 | } | |
5348 | ||
b7cfce93 MK |
5349 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
5350 | ||
5e06422c | 5351 | /* delete and uninstall all rmacs */ |
996c9314 | 5352 | hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry, |
5e06422c MK |
5353 | zl3vni); |
5354 | ||
5355 | /* delete and uninstall all next-hops */ | |
996c9314 | 5356 | hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry, |
5e06422c MK |
5357 | zl3vni); |
5358 | ||
b7cfce93 MK |
5359 | zvrf->l3vni = 0; |
5360 | zl3vni_del(zl3vni); | |
5361 | ||
3b0a590b | 5362 | /* Add L2VNI for this VNI */ |
b7cfce93 | 5363 | zebra_vxlan_handle_vni_transition(zvrf, vni, add); |
d62a17ae | 5364 | } |
b7cfce93 MK |
5365 | return 0; |
5366 | } | |
13d60d35 | 5367 | |
84915b0a | 5368 | int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf) |
5369 | { | |
5370 | zebra_l3vni_t *zl3vni = NULL; | |
5371 | ||
5372 | if (zvrf->l3vni) | |
5373 | zl3vni = zl3vni_lookup(zvrf->l3vni); | |
5374 | if (!zl3vni) | |
5375 | return 0; | |
5376 | ||
5377 | zl3vni->vrf_id = zvrf_id(zvrf); | |
5378 | if (is_l3vni_oper_up(zl3vni)) | |
5379 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
5380 | return 0; | |
5381 | } | |
5382 | ||
5383 | int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf) | |
b7cfce93 MK |
5384 | { |
5385 | zebra_l3vni_t *zl3vni = NULL; | |
13d60d35 | 5386 | |
84915b0a | 5387 | if (zvrf->l3vni) |
5388 | zl3vni = zl3vni_lookup(zvrf->l3vni); | |
b7cfce93 | 5389 | if (!zl3vni) |
d62a17ae | 5390 | return 0; |
13d60d35 | 5391 | |
b7cfce93 | 5392 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
92475ca4 CS |
5393 | |
5394 | /* delete and uninstall all rmacs */ | |
5395 | hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry, zl3vni); | |
5396 | /* delete and uninstall all next-hops */ | |
5397 | hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry, zl3vni); | |
5398 | ||
5399 | zl3vni->vrf_id = VRF_UNKNOWN; | |
5400 | ||
84915b0a | 5401 | return 0; |
5402 | } | |
5403 | ||
5404 | int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf) | |
5405 | { | |
5406 | zebra_l3vni_t *zl3vni = NULL; | |
5407 | vni_t vni; | |
5408 | ||
5409 | if (zvrf->l3vni) | |
5410 | zl3vni = zl3vni_lookup(zvrf->l3vni); | |
5411 | if (!zl3vni) | |
5412 | return 0; | |
5413 | ||
5414 | vni = zl3vni->vni; | |
b7cfce93 | 5415 | zl3vni_del(zl3vni); |
84915b0a | 5416 | zebra_vxlan_handle_vni_transition(zvrf, vni, 0); |
2232a77c | 5417 | |
d62a17ae | 5418 | return 0; |
13d60d35 | 5419 | } |
5420 | ||
fbac9605 DS |
5421 | /* |
5422 | * Handle message from client to specify the flooding mechanism for | |
5423 | * BUM packets. The default is to do head-end (ingress) replication | |
5424 | * and the other supported option is to disable it. This applies to | |
5425 | * all BUM traffic and disabling it applies to both the transmit and | |
5426 | * receive direction. | |
5427 | */ | |
5428 | void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS) | |
5429 | { | |
5430 | struct stream *s; | |
5431 | enum vxlan_flood_control flood_ctrl; | |
5432 | ||
986512a3 | 5433 | if (!EVPN_ENABLED(zvrf)) { |
a0b0b5c8 | 5434 | zlog_err("EVPN flood control for non-EVPN VRF %u", |
fbac9605 DS |
5435 | zvrf_id(zvrf)); |
5436 | return; | |
5437 | } | |
5438 | ||
5439 | s = msg; | |
5440 | STREAM_GETC(s, flood_ctrl); | |
5441 | ||
5442 | if (IS_ZEBRA_DEBUG_VXLAN) | |
5443 | zlog_debug("EVPN flood control %u, currently %u", | |
5444 | flood_ctrl, zvrf->vxlan_flood_ctrl); | |
5445 | ||
5446 | if (zvrf->vxlan_flood_ctrl == flood_ctrl) | |
5447 | return; | |
5448 | ||
5449 | zvrf->vxlan_flood_ctrl = flood_ctrl; | |
5450 | ||
5451 | /* Install or uninstall flood entries corresponding to | |
5452 | * remote VTEPs. | |
5453 | */ | |
8b5fdf2e | 5454 | hash_iterate(zvrf->evpn_table, zebra_evpn_handle_flooding_remote_vteps, |
fbac9605 DS |
5455 | zvrf); |
5456 | ||
5457 | stream_failure: | |
5458 | return; | |
5459 | } | |
5460 | ||
278e26de CS |
5461 | /* |
5462 | * Handle message from client to enable/disable advertisement of svi macip | |
5463 | * routes | |
5464 | */ | |
5465 | void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) | |
5466 | { | |
5467 | struct stream *s; | |
5468 | int advertise; | |
5469 | vni_t vni = 0; | |
87d76d54 | 5470 | zebra_evpn_t *zevpn = NULL; |
278e26de CS |
5471 | struct interface *ifp = NULL; |
5472 | ||
986512a3 | 5473 | if (!EVPN_ENABLED(zvrf)) { |
27627f9a | 5474 | zlog_debug("EVPN SVI-MACIP Adv for non-EVPN VRF %u", |
a0b0b5c8 | 5475 | zvrf_id(zvrf)); |
278e26de CS |
5476 | return; |
5477 | } | |
5478 | ||
5479 | s = msg; | |
5480 | STREAM_GETC(s, advertise); | |
5481 | STREAM_GETL(s, vni); | |
5482 | ||
5483 | if (!vni) { | |
5484 | if (IS_ZEBRA_DEBUG_VXLAN) | |
27627f9a | 5485 | zlog_debug("EVPN SVI-MACIP Adv %s, currently %s", |
278e26de | 5486 | advertise ? "enabled" : "disabled", |
838cef6d | 5487 | advertise_svi_macip_enabled(NULL) |
278e26de CS |
5488 | ? "enabled" |
5489 | : "disabled"); | |
5490 | ||
5491 | if (zvrf->advertise_svi_macip == advertise) | |
5492 | return; | |
5493 | ||
5494 | ||
5495 | if (advertise) { | |
5496 | zvrf->advertise_svi_macip = advertise; | |
87d76d54 | 5497 | hash_iterate(zvrf->evpn_table, |
8b5fdf2e PR |
5498 | zebra_evpn_gw_macip_add_for_evpn_hash, |
5499 | NULL); | |
278e26de | 5500 | } else { |
87d76d54 | 5501 | hash_iterate(zvrf->evpn_table, |
8b5fdf2e PR |
5502 | zebra_evpn_svi_macip_del_for_evpn_hash, |
5503 | NULL); | |
278e26de CS |
5504 | zvrf->advertise_svi_macip = advertise; |
5505 | } | |
5506 | ||
5507 | } else { | |
5508 | struct zebra_if *zif = NULL; | |
5509 | struct zebra_l2info_vxlan zl2_info; | |
5510 | struct interface *vlan_if = NULL; | |
5511 | ||
8b5fdf2e | 5512 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 5513 | if (!zevpn) |
278e26de CS |
5514 | return; |
5515 | ||
5516 | if (IS_ZEBRA_DEBUG_VXLAN) | |
5517 | zlog_debug( | |
5518 | "EVPN SVI macip Adv %s on VNI %d , currently %s", | |
5519 | advertise ? "enabled" : "disabled", vni, | |
87d76d54 | 5520 | advertise_svi_macip_enabled(zevpn) |
278e26de CS |
5521 | ? "enabled" |
5522 | : "disabled"); | |
5523 | ||
87d76d54 | 5524 | if (zevpn->advertise_svi_macip == advertise) |
278e26de CS |
5525 | return; |
5526 | ||
3dacbb9d CS |
5527 | /* Store flag even though SVI is not present. |
5528 | * Once SVI comes up triggers self MAC-IP route add. | |
5529 | */ | |
87d76d54 | 5530 | zevpn->advertise_svi_macip = advertise; |
3dacbb9d | 5531 | |
87d76d54 | 5532 | ifp = zevpn->vxlan_if; |
278e26de CS |
5533 | if (!ifp) |
5534 | return; | |
5535 | ||
5536 | zif = ifp->info; | |
5537 | ||
5538 | /* If down or not mapped to a bridge, we're done. */ | |
5539 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
5540 | return; | |
5541 | ||
5542 | zl2_info = zif->l2info.vxl; | |
7cbae20a | 5543 | vlan_if = zvni_map_to_svi(zl2_info.access_vlan, |
278e26de CS |
5544 | zif->brslave_info.br_if); |
5545 | if (!vlan_if) | |
5546 | return; | |
5547 | ||
5548 | if (advertise) { | |
278e26de | 5549 | /* Add primary SVI MAC-IP */ |
8b5fdf2e | 5550 | zebra_evpn_add_macip_for_intf(vlan_if, zevpn); |
278e26de | 5551 | } else { |
3dacbb9d | 5552 | /* Del primary SVI MAC-IP */ |
8b5fdf2e | 5553 | zebra_evpn_del_macip_for_intf(vlan_if, zevpn); |
278e26de CS |
5554 | } |
5555 | } | |
5556 | ||
5557 | stream_failure: | |
5558 | return; | |
5559 | } | |
5560 | ||
31310b25 MK |
5561 | /* |
5562 | * Handle message from client to enable/disable advertisement of g/w macip | |
5563 | * routes | |
5564 | */ | |
89f4e507 | 5565 | void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS) |
31310b25 MK |
5566 | { |
5567 | struct stream *s; | |
5568 | int advertise; | |
5569 | vni_t vni = 0; | |
87d76d54 | 5570 | zebra_evpn_t *zevpn = NULL; |
31310b25 MK |
5571 | struct interface *ifp = NULL; |
5572 | struct zebra_if *zif = NULL; | |
5573 | struct zebra_l2info_vxlan zl2_info; | |
5574 | struct interface *vlan_if = NULL; | |
5575 | ||
986512a3 | 5576 | if (!EVPN_ENABLED(zvrf)) { |
a0b0b5c8 T |
5577 | zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u", |
5578 | zvrf_id(zvrf)); | |
8068a649 | 5579 | return; |
31310b25 MK |
5580 | } |
5581 | ||
1002497a | 5582 | s = msg; |
2017b3ea | 5583 | STREAM_GETC(s, advertise); |
7fb29f49 | 5584 | STREAM_GET(&vni, s, 3); |
31310b25 | 5585 | |
8b5fdf2e | 5586 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 5587 | if (!zevpn) |
8068a649 | 5588 | return; |
31310b25 | 5589 | |
87d76d54 | 5590 | if (zevpn->advertise_subnet == advertise) |
8068a649 | 5591 | return; |
31310b25 MK |
5592 | |
5593 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 LB |
5594 | zlog_debug("EVPN subnet Adv %s on VNI %d , currently %s", |
5595 | advertise ? "enabled" : "disabled", vni, | |
87d76d54 | 5596 | zevpn->advertise_subnet ? "enabled" : "disabled"); |
31310b25 MK |
5597 | |
5598 | ||
87d76d54 | 5599 | zevpn->advertise_subnet = advertise; |
31310b25 | 5600 | |
87d76d54 | 5601 | ifp = zevpn->vxlan_if; |
31310b25 | 5602 | if (!ifp) |
8068a649 | 5603 | return; |
31310b25 MK |
5604 | |
5605 | zif = ifp->info; | |
5606 | ||
5607 | /* If down or not mapped to a bridge, we're done. */ | |
5608 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
8068a649 | 5609 | return; |
31310b25 MK |
5610 | |
5611 | zl2_info = zif->l2info.vxl; | |
5612 | ||
996c9314 | 5613 | vlan_if = |
7cbae20a | 5614 | zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); |
31310b25 | 5615 | if (!vlan_if) |
8068a649 | 5616 | return; |
31310b25 | 5617 | |
87d76d54 | 5618 | if (zevpn->advertise_subnet) |
8b5fdf2e | 5619 | zebra_evpn_advertise_subnet(zevpn, vlan_if, 1); |
31310b25 | 5620 | else |
8b5fdf2e | 5621 | zebra_evpn_advertise_subnet(zevpn, vlan_if, 0); |
2017b3ea DS |
5622 | |
5623 | stream_failure: | |
5624 | return; | |
31310b25 MK |
5625 | } |
5626 | ||
1a98c087 MK |
5627 | /* |
5628 | * Handle message from client to enable/disable advertisement of g/w macip | |
5629 | * routes | |
5630 | */ | |
89f4e507 | 5631 | void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS) |
1a98c087 MK |
5632 | { |
5633 | struct stream *s; | |
5634 | int advertise; | |
5635 | vni_t vni = 0; | |
87d76d54 | 5636 | zebra_evpn_t *zevpn = NULL; |
b5ebdc9b | 5637 | struct interface *ifp = NULL; |
1a98c087 | 5638 | |
986512a3 | 5639 | if (!EVPN_ENABLED(zvrf)) { |
a0b0b5c8 | 5640 | zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u", |
9df414fe | 5641 | zvrf_id(zvrf)); |
8068a649 | 5642 | return; |
2853fed6 | 5643 | } |
5644 | ||
1002497a | 5645 | s = msg; |
ec93aa12 | 5646 | STREAM_GETC(s, advertise); |
cc6d5476 | 5647 | STREAM_GETL(s, vni); |
1a98c087 MK |
5648 | |
5649 | if (!vni) { | |
5650 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2853fed6 | 5651 | zlog_debug("EVPN gateway macip Adv %s, currently %s", |
1a98c087 | 5652 | advertise ? "enabled" : "disabled", |
2853fed6 | 5653 | advertise_gw_macip_enabled(NULL) |
1a98c087 MK |
5654 | ? "enabled" |
5655 | : "disabled"); | |
5656 | ||
5657 | if (zvrf->advertise_gw_macip == advertise) | |
8068a649 | 5658 | return; |
1a98c087 MK |
5659 | |
5660 | zvrf->advertise_gw_macip = advertise; | |
5661 | ||
87d76d54 PR |
5662 | if (advertise_gw_macip_enabled(zevpn)) |
5663 | hash_iterate(zvrf->evpn_table, | |
8b5fdf2e PR |
5664 | zebra_evpn_gw_macip_add_for_evpn_hash, |
5665 | NULL); | |
1a98c087 | 5666 | else |
87d76d54 | 5667 | hash_iterate(zvrf->evpn_table, |
8b5fdf2e PR |
5668 | zebra_evpn_gw_macip_del_for_evpn_hash, |
5669 | NULL); | |
1a98c087 MK |
5670 | |
5671 | } else { | |
5672 | struct zebra_if *zif = NULL; | |
5673 | struct zebra_l2info_vxlan zl2_info; | |
5674 | struct interface *vlan_if = NULL; | |
5675 | struct interface *vrr_if = NULL; | |
5676 | ||
8b5fdf2e | 5677 | zevpn = zebra_evpn_lookup(vni); |
87d76d54 | 5678 | if (!zevpn) |
124ead27 | 5679 | return; |
01a6143b | 5680 | |
1a98c087 MK |
5681 | if (IS_ZEBRA_DEBUG_VXLAN) |
5682 | zlog_debug( | |
2853fed6 | 5683 | "EVPN gateway macip Adv %s on VNI %d , currently %s", |
1a98c087 | 5684 | advertise ? "enabled" : "disabled", vni, |
87d76d54 | 5685 | advertise_gw_macip_enabled(zevpn) ? "enabled" |
996c9314 | 5686 | : "disabled"); |
1a98c087 | 5687 | |
87d76d54 | 5688 | if (zevpn->advertise_gw_macip == advertise) |
8068a649 | 5689 | return; |
1a98c087 | 5690 | |
87d76d54 | 5691 | zevpn->advertise_gw_macip = advertise; |
1a98c087 | 5692 | |
87d76d54 | 5693 | ifp = zevpn->vxlan_if; |
b5ebdc9b | 5694 | if (!ifp) |
8068a649 | 5695 | return; |
b5ebdc9b | 5696 | |
5697 | zif = ifp->info; | |
5698 | ||
5699 | /* If down or not mapped to a bridge, we're done. */ | |
b682f6de | 5700 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
8068a649 | 5701 | return; |
b5ebdc9b | 5702 | |
1a98c087 MK |
5703 | zl2_info = zif->l2info.vxl; |
5704 | ||
7cbae20a | 5705 | vlan_if = zvni_map_to_svi(zl2_info.access_vlan, |
1a98c087 MK |
5706 | zif->brslave_info.br_if); |
5707 | if (!vlan_if) | |
8068a649 | 5708 | return; |
1a98c087 | 5709 | |
87d76d54 | 5710 | if (advertise_gw_macip_enabled(zevpn)) { |
1a98c087 | 5711 | /* Add primary SVI MAC-IP */ |
8b5fdf2e | 5712 | zebra_evpn_add_macip_for_intf(vlan_if, zevpn); |
1a98c087 MK |
5713 | |
5714 | /* Add VRR MAC-IP - if any*/ | |
5715 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
5716 | if (vrr_if) | |
8b5fdf2e | 5717 | zebra_evpn_add_macip_for_intf(vrr_if, zevpn); |
1a98c087 MK |
5718 | } else { |
5719 | /* Del primary MAC-IP */ | |
8b5fdf2e | 5720 | zebra_evpn_del_macip_for_intf(vlan_if, zevpn); |
1a98c087 MK |
5721 | |
5722 | /* Del VRR MAC-IP - if any*/ | |
5723 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
5724 | if (vrr_if) | |
8b5fdf2e | 5725 | zebra_evpn_del_macip_for_intf(vrr_if, zevpn); |
1a98c087 MK |
5726 | } |
5727 | } | |
5728 | ||
ec93aa12 | 5729 | stream_failure: |
8068a649 | 5730 | return; |
1a98c087 MK |
5731 | } |
5732 | ||
2961d060 PG |
5733 | static int macfdb_read_ns(struct ns *ns, |
5734 | void *_in_param __attribute__((unused)), | |
5735 | void **out_param __attribute__((unused))) | |
6265fbe5 | 5736 | { |
2961d060 PG |
5737 | struct zebra_ns *zns = ns->info; |
5738 | ||
6265fbe5 | 5739 | macfdb_read(zns); |
2961d060 | 5740 | return NS_WALK_CONTINUE; |
6265fbe5 PG |
5741 | } |
5742 | ||
2961d060 PG |
5743 | static int neigh_read_ns(struct ns *ns, |
5744 | void *_in_param __attribute__((unused)), | |
5745 | void **out_param __attribute__((unused))) | |
6265fbe5 | 5746 | { |
2961d060 PG |
5747 | struct zebra_ns *zns = ns->info; |
5748 | ||
6265fbe5 | 5749 | neigh_read(zns); |
2961d060 | 5750 | return NS_WALK_CONTINUE; |
6265fbe5 | 5751 | } |
1a98c087 | 5752 | |
13d60d35 | 5753 | /* |
5754 | * Handle message from client to learn (or stop learning) about VNIs and MACs. | |
5755 | * When enabled, the VNI hash table will be built and MAC FDB table read; | |
5756 | * when disabled, the entries should be deleted and remote VTEPs and MACs | |
5757 | * uninstalled from the kernel. | |
fbac9605 DS |
5758 | * This also informs the setting for BUM handling at the time this change |
5759 | * occurs; it is relevant only when specifying "learn". | |
13d60d35 | 5760 | */ |
89f4e507 | 5761 | void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS) |
13d60d35 | 5762 | { |
655b04d1 MK |
5763 | struct stream *s = NULL; |
5764 | int advertise = 0; | |
fbac9605 | 5765 | enum vxlan_flood_control flood_ctrl; |
13d60d35 | 5766 | |
77b998fb T |
5767 | /* Mismatch between EVPN VRF and current VRF (should be prevented by |
5768 | * bgpd's cli) */ | |
f920dd6d | 5769 | if (is_evpn_enabled() && !EVPN_ENABLED(zvrf)) |
8068a649 | 5770 | return; |
2853fed6 | 5771 | |
1002497a | 5772 | s = msg; |
ec93aa12 | 5773 | STREAM_GETC(s, advertise); |
fbac9605 | 5774 | STREAM_GETC(s, flood_ctrl); |
13d60d35 | 5775 | |
d62a17ae | 5776 | if (IS_ZEBRA_DEBUG_VXLAN) |
150971b5 T |
5777 | zlog_debug("EVPN VRF %s(%u) VNI Adv %s, currently %s, flood control %u", |
5778 | zvrf_name(zvrf), zvrf_id(zvrf), | |
d62a17ae | 5779 | advertise ? "enabled" : "disabled", |
fbac9605 DS |
5780 | is_evpn_enabled() ? "enabled" : "disabled", |
5781 | flood_ctrl); | |
13d60d35 | 5782 | |
d62a17ae | 5783 | if (zvrf->advertise_all_vni == advertise) |
8068a649 | 5784 | return; |
13d60d35 | 5785 | |
d62a17ae | 5786 | zvrf->advertise_all_vni = advertise; |
f920dd6d | 5787 | if (EVPN_ENABLED(zvrf)) { |
0fb2ad05 | 5788 | zrouter.evpn_vrf = zvrf; |
150971b5 | 5789 | |
fbac9605 DS |
5790 | /* Note BUM handling */ |
5791 | zvrf->vxlan_flood_ctrl = flood_ctrl; | |
5792 | ||
ce5160c0 AK |
5793 | /* Replay all ESs */ |
5794 | zebra_evpn_es_send_all_to_client(true /* add */); | |
5795 | ||
87d76d54 PR |
5796 | /* Build EVPN hash table and inform BGP. */ |
5797 | zevpn_build_hash_table(); | |
2232a77c | 5798 | |
1a98c087 | 5799 | /* Add all SVI (L3 GW) MACs to BGP*/ |
8b5fdf2e PR |
5800 | hash_iterate(zvrf->evpn_table, |
5801 | zebra_evpn_gw_macip_add_for_evpn_hash, NULL); | |
1a98c087 | 5802 | |
d62a17ae | 5803 | /* Read the MAC FDB */ |
2961d060 | 5804 | ns_walk_func(macfdb_read_ns, NULL, NULL); |
2232a77c | 5805 | |
d62a17ae | 5806 | /* Read neighbors */ |
2961d060 | 5807 | ns_walk_func(neigh_read_ns, NULL, NULL); |
d62a17ae | 5808 | } else { |
87d76d54 | 5809 | /* Cleanup VTEPs for all EVPNs - uninstall from |
d62a17ae | 5810 | * kernel and free entries. |
5811 | */ | |
8b5fdf2e PR |
5812 | hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, |
5813 | zvrf); | |
655b04d1 | 5814 | |
ce5160c0 AK |
5815 | /* Delete all ESs in BGP */ |
5816 | zebra_evpn_es_send_all_to_client(false /* add */); | |
5817 | ||
655b04d1 | 5818 | /* cleanup all l3vnis */ |
89272910 | 5819 | hash_iterate(zrouter.l3vni_table, zl3vni_cleanup_all, NULL); |
150971b5 | 5820 | |
0fb2ad05 T |
5821 | /* Mark as "no EVPN VRF" */ |
5822 | zrouter.evpn_vrf = NULL; | |
d62a17ae | 5823 | } |
13d60d35 | 5824 | |
ec93aa12 | 5825 | stream_failure: |
8068a649 | 5826 | return; |
13d60d35 | 5827 | } |
5828 | ||
5829 | /* | |
87d76d54 | 5830 | * Allocate EVPN hash table for this VRF and do other initialization. |
13d60d35 | 5831 | * NOTE: Currently supported only for default VRF. |
5832 | */ | |
d62a17ae | 5833 | void zebra_vxlan_init_tables(struct zebra_vrf *zvrf) |
13d60d35 | 5834 | { |
d62a17ae | 5835 | if (!zvrf) |
5836 | return; | |
8b5fdf2e PR |
5837 | zvrf->evpn_table = |
5838 | hash_create(zebra_evpn_hash_keymake, zebra_evpn_hash_cmp, | |
5839 | "Zebra VRF EVPN Table"); | |
015d264c AK |
5840 | zvrf->vxlan_sg_table = hash_create(zebra_vxlan_sg_hash_key_make, |
5841 | zebra_vxlan_sg_hash_eq, "Zebra VxLAN SG Table"); | |
13d60d35 | 5842 | } |
5843 | ||
87d76d54 | 5844 | /* Cleanup EVPN info, but don't free the table. */ |
84915b0a | 5845 | void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf) |
5846 | { | |
ce5160c0 AK |
5847 | struct zebra_vrf *evpn_zvrf = zebra_vrf_get_evpn(); |
5848 | ||
84915b0a | 5849 | if (!zvrf) |
5850 | return; | |
8b5fdf2e | 5851 | hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf); |
0c16fb72 | 5852 | zebra_vxlan_cleanup_sg_table(zvrf); |
ce5160c0 AK |
5853 | |
5854 | if (zvrf == evpn_zvrf) | |
5855 | zebra_evpn_es_cleanup(); | |
84915b0a | 5856 | } |
5857 | ||
87d76d54 | 5858 | /* Close all EVPN handling */ |
d62a17ae | 5859 | void zebra_vxlan_close_tables(struct zebra_vrf *zvrf) |
13d60d35 | 5860 | { |
2853fed6 | 5861 | if (!zvrf) |
5862 | return; | |
8b5fdf2e | 5863 | hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf); |
87d76d54 | 5864 | hash_free(zvrf->evpn_table); |
0c16fb72 AK |
5865 | if (zvrf->vxlan_sg_table) { |
5866 | zebra_vxlan_cleanup_sg_table(zvrf); | |
5867 | hash_free(zvrf->vxlan_sg_table); | |
5868 | zvrf->vxlan_sg_table = NULL; | |
5869 | } | |
13d60d35 | 5870 | } |
b7cfce93 MK |
5871 | |
5872 | /* init the l3vni table */ | |
6548050a | 5873 | void zebra_vxlan_init(void) |
b7cfce93 | 5874 | { |
89272910 DS |
5875 | zrouter.l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp, |
5876 | "Zebra VRF L3 VNI table"); | |
0fb2ad05 | 5877 | zrouter.evpn_vrf = NULL; |
ce5160c0 | 5878 | zebra_evpn_mh_init(); |
b7cfce93 MK |
5879 | } |
5880 | ||
5881 | /* free l3vni table */ | |
6548050a | 5882 | void zebra_vxlan_disable(void) |
b7cfce93 | 5883 | { |
89272910 | 5884 | hash_free(zrouter.l3vni_table); |
ce5160c0 | 5885 | zebra_evpn_mh_terminate(); |
b7cfce93 | 5886 | } |
d3135ba3 | 5887 | |
5888 | /* get the l3vni svi ifindex */ | |
5889 | ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id) | |
5890 | { | |
5891 | zebra_l3vni_t *zl3vni = NULL; | |
5892 | ||
5893 | zl3vni = zl3vni_from_vrf(vrf_id); | |
5894 | if (!zl3vni || !is_l3vni_oper_up(zl3vni)) | |
5895 | return 0; | |
5896 | ||
5897 | return zl3vni->svi_if->ifindex; | |
5898 | } | |
c80a972c | 5899 | |
015d264c | 5900 | /************************** vxlan SG cache management ************************/ |
4ab3321f | 5901 | /* Inform PIM about the mcast group */ |
ecbbc3a7 AK |
5902 | static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf, |
5903 | struct prefix_sg *sg, | |
5904 | char *sg_str, uint16_t cmd) | |
4ab3321f AK |
5905 | { |
5906 | struct zserv *client = NULL; | |
5907 | struct stream *s = NULL; | |
5908 | ||
5909 | client = zserv_find_client(ZEBRA_ROUTE_PIM, 0); | |
5910 | if (!client) | |
5911 | return 0; | |
5912 | ||
ecbbc3a7 AK |
5913 | if (!CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG)) |
5914 | return 0; | |
5915 | ||
4ab3321f AK |
5916 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
5917 | ||
5918 | zclient_create_header(s, cmd, VRF_DEFAULT); | |
5919 | stream_putl(s, IPV4_MAX_BYTELEN); | |
5920 | stream_put(s, &sg->src.s_addr, IPV4_MAX_BYTELEN); | |
5921 | stream_put(s, &sg->grp.s_addr, IPV4_MAX_BYTELEN); | |
5922 | ||
5923 | /* Write packet size. */ | |
5924 | stream_putw_at(s, 0, stream_get_endp(s)); | |
5925 | ||
5926 | if (IS_ZEBRA_DEBUG_VXLAN) | |
5927 | zlog_debug( | |
5928 | "Send %s %s to %s", | |
5929 | (cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", sg_str, | |
5930 | zebra_route_string(client->proto)); | |
5931 | ||
5932 | if (cmd == ZEBRA_VXLAN_SG_ADD) | |
5933 | client->vxlan_sg_add_cnt++; | |
5934 | else | |
5935 | client->vxlan_sg_del_cnt++; | |
5936 | ||
5937 | return zserv_send_message(client, s); | |
5938 | } | |
5939 | ||
d8b87afe | 5940 | static unsigned int zebra_vxlan_sg_hash_key_make(const void *p) |
015d264c | 5941 | { |
d8b87afe | 5942 | const zebra_vxlan_sg_t *vxlan_sg = p; |
015d264c AK |
5943 | |
5944 | return (jhash_2words(vxlan_sg->sg.src.s_addr, | |
5945 | vxlan_sg->sg.grp.s_addr, 0)); | |
5946 | } | |
5947 | ||
5948 | static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2) | |
5949 | { | |
5950 | const zebra_vxlan_sg_t *sg1 = p1; | |
5951 | const zebra_vxlan_sg_t *sg2 = p2; | |
5952 | ||
5953 | return ((sg1->sg.src.s_addr == sg2->sg.src.s_addr) | |
5954 | && (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr)); | |
5955 | } | |
5956 | ||
5957 | static zebra_vxlan_sg_t *zebra_vxlan_sg_new(struct zebra_vrf *zvrf, | |
5958 | struct prefix_sg *sg) | |
5959 | { | |
5960 | zebra_vxlan_sg_t *vxlan_sg; | |
5961 | ||
5962 | vxlan_sg = XCALLOC(MTYPE_ZVXLAN_SG, sizeof(*vxlan_sg)); | |
5963 | ||
5964 | vxlan_sg->zvrf = zvrf; | |
5965 | vxlan_sg->sg = *sg; | |
5966 | prefix_sg2str(sg, vxlan_sg->sg_str); | |
5967 | ||
5968 | vxlan_sg = hash_get(zvrf->vxlan_sg_table, vxlan_sg, hash_alloc_intern); | |
5969 | ||
5970 | if (IS_ZEBRA_DEBUG_VXLAN) | |
5971 | zlog_debug("vxlan SG %s created", vxlan_sg->sg_str); | |
5972 | ||
5973 | return vxlan_sg; | |
5974 | } | |
5975 | ||
5976 | static zebra_vxlan_sg_t *zebra_vxlan_sg_find(struct zebra_vrf *zvrf, | |
5977 | struct prefix_sg *sg) | |
5978 | { | |
5979 | zebra_vxlan_sg_t lookup; | |
5980 | ||
5981 | lookup.sg = *sg; | |
5982 | return hash_lookup(zvrf->vxlan_sg_table, &lookup); | |
5983 | } | |
5984 | ||
5985 | static zebra_vxlan_sg_t *zebra_vxlan_sg_add(struct zebra_vrf *zvrf, | |
5986 | struct prefix_sg *sg) | |
5987 | { | |
5988 | zebra_vxlan_sg_t *vxlan_sg; | |
5989 | zebra_vxlan_sg_t *parent = NULL; | |
5990 | struct in_addr sip; | |
5991 | ||
5992 | vxlan_sg = zebra_vxlan_sg_find(zvrf, sg); | |
5993 | if (vxlan_sg) | |
5994 | return vxlan_sg; | |
5995 | ||
5996 | /* create a *G entry for every BUM group implicitly - | |
5997 | * 1. The SG entry is used by pimd to setup the vxlan-origination-mroute | |
5998 | * 2. the XG entry is used by pimd to setup the | |
5999 | * vxlan-termination-mroute | |
6000 | */ | |
975a328e | 6001 | if (sg->src.s_addr != INADDR_ANY) { |
015d264c AK |
6002 | memset(&sip, 0, sizeof(sip)); |
6003 | parent = zebra_vxlan_sg_do_ref(zvrf, sip, sg->grp); | |
6004 | if (!parent) | |
6005 | return NULL; | |
6006 | } | |
6007 | ||
6008 | vxlan_sg = zebra_vxlan_sg_new(zvrf, sg); | |
6009 | if (!vxlan_sg) { | |
6010 | if (parent) | |
6011 | zebra_vxlan_sg_do_deref(zvrf, sip, sg->grp); | |
6012 | return vxlan_sg; | |
6013 | } | |
6014 | ||
ecbbc3a7 AK |
6015 | zebra_vxlan_sg_send(zvrf, sg, vxlan_sg->sg_str, |
6016 | ZEBRA_VXLAN_SG_ADD); | |
4ab3321f | 6017 | |
015d264c AK |
6018 | return vxlan_sg; |
6019 | } | |
6020 | ||
6021 | static void zebra_vxlan_sg_del(zebra_vxlan_sg_t *vxlan_sg) | |
6022 | { | |
6023 | struct in_addr sip; | |
6024 | struct zebra_vrf *zvrf; | |
6025 | ||
6026 | zvrf = vrf_info_lookup(VRF_DEFAULT); | |
6027 | if (!zvrf) | |
6028 | return; | |
6029 | ||
6030 | /* On SG entry deletion remove the reference to its parent XG | |
6031 | * entry | |
6032 | */ | |
975a328e | 6033 | if (vxlan_sg->sg.src.s_addr != INADDR_ANY) { |
015d264c AK |
6034 | memset(&sip, 0, sizeof(sip)); |
6035 | zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp); | |
6036 | } | |
6037 | ||
ecbbc3a7 AK |
6038 | zebra_vxlan_sg_send(zvrf, &vxlan_sg->sg, |
6039 | vxlan_sg->sg_str, ZEBRA_VXLAN_SG_DEL); | |
4ab3321f | 6040 | |
015d264c AK |
6041 | hash_release(vxlan_sg->zvrf->vxlan_sg_table, vxlan_sg); |
6042 | ||
6043 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6044 | zlog_debug("VXLAN SG %s deleted", vxlan_sg->sg_str); | |
6045 | ||
6046 | XFREE(MTYPE_ZVXLAN_SG, vxlan_sg); | |
6047 | } | |
6048 | ||
6049 | static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, | |
6050 | struct in_addr sip, struct in_addr mcast_grp) | |
6051 | { | |
6052 | zebra_vxlan_sg_t *vxlan_sg; | |
6053 | struct prefix_sg sg; | |
6054 | ||
6055 | sg.family = AF_INET; | |
6056 | sg.prefixlen = IPV4_MAX_BYTELEN; | |
6057 | sg.src = sip; | |
6058 | sg.grp = mcast_grp; | |
6059 | vxlan_sg = zebra_vxlan_sg_find(zvrf, &sg); | |
6060 | if (!vxlan_sg) | |
6061 | return; | |
6062 | ||
6063 | if (vxlan_sg->ref_cnt) | |
6064 | --vxlan_sg->ref_cnt; | |
6065 | ||
6066 | if (!vxlan_sg->ref_cnt) | |
6067 | zebra_vxlan_sg_del(vxlan_sg); | |
6068 | } | |
6069 | ||
6070 | static zebra_vxlan_sg_t *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf, | |
6071 | struct in_addr sip, struct in_addr mcast_grp) | |
6072 | { | |
6073 | zebra_vxlan_sg_t *vxlan_sg; | |
6074 | struct prefix_sg sg; | |
6075 | ||
6076 | sg.family = AF_INET; | |
6077 | sg.prefixlen = IPV4_MAX_BYTELEN; | |
6078 | sg.src = sip; | |
6079 | sg.grp = mcast_grp; | |
6080 | vxlan_sg = zebra_vxlan_sg_add(zvrf, &sg); | |
6081 | if (vxlan_sg) | |
6082 | ++vxlan_sg->ref_cnt; | |
6083 | ||
6084 | return vxlan_sg; | |
6085 | } | |
abfa0a96 AK |
6086 | |
6087 | static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, | |
6088 | struct in_addr mcast_grp) | |
6089 | { | |
6090 | struct zebra_vrf *zvrf; | |
6091 | ||
975a328e DA |
6092 | if (local_vtep_ip.s_addr == INADDR_ANY |
6093 | || mcast_grp.s_addr == INADDR_ANY) | |
abfa0a96 AK |
6094 | return; |
6095 | ||
6096 | zvrf = vrf_info_lookup(VRF_DEFAULT); | |
6097 | if (!zvrf) | |
6098 | return; | |
6099 | ||
6100 | zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp); | |
6101 | } | |
6102 | ||
6103 | static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, | |
6104 | struct in_addr mcast_grp) | |
6105 | { | |
6106 | struct zebra_vrf *zvrf; | |
6107 | ||
975a328e DA |
6108 | if (local_vtep_ip.s_addr == INADDR_ANY |
6109 | || mcast_grp.s_addr == INADDR_ANY) | |
abfa0a96 AK |
6110 | return; |
6111 | ||
6112 | zvrf = vrf_info_lookup(VRF_DEFAULT); | |
6113 | if (!zvrf) | |
6114 | return; | |
6115 | zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp); | |
6116 | } | |
6117 | ||
0c16fb72 AK |
6118 | static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *backet, void *arg) |
6119 | { | |
6120 | zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data; | |
6121 | ||
6122 | /* increment the ref count against (*,G) to prevent them from being | |
6123 | * deleted | |
6124 | */ | |
6125 | if (vxlan_sg->sg.src.s_addr == INADDR_ANY) | |
6126 | ++vxlan_sg->ref_cnt; | |
6127 | } | |
6128 | ||
6129 | static void zebra_vxlan_xg_post_cleanup(struct hash_bucket *backet, void *arg) | |
6130 | { | |
6131 | zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data; | |
6132 | ||
6133 | /* decrement the dummy ref count against (*,G) to delete them */ | |
6134 | if (vxlan_sg->sg.src.s_addr == INADDR_ANY) { | |
6135 | if (vxlan_sg->ref_cnt) | |
6136 | --vxlan_sg->ref_cnt; | |
6137 | if (!vxlan_sg->ref_cnt) | |
6138 | zebra_vxlan_sg_del(vxlan_sg); | |
6139 | } | |
6140 | } | |
6141 | ||
7f5818fb | 6142 | static void zebra_vxlan_sg_cleanup(struct hash_bucket *backet, void *arg) |
abfa0a96 AK |
6143 | { |
6144 | zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data; | |
6145 | ||
6146 | zebra_vxlan_sg_del(vxlan_sg); | |
6147 | } | |
27627f9a | 6148 | |
0c16fb72 AK |
6149 | static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf) |
6150 | { | |
6151 | /* increment the ref count against (*,G) to prevent them from being | |
6152 | * deleted | |
6153 | */ | |
6154 | hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_xg_pre_cleanup, NULL); | |
6155 | ||
6156 | hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL); | |
6157 | ||
6158 | /* decrement the dummy ref count against the XG entries */ | |
6159 | hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_xg_post_cleanup, NULL); | |
6160 | } | |
6161 | ||
7f5818fb | 6162 | static void zebra_vxlan_sg_replay_send(struct hash_bucket *backet, void *arg) |
ecbbc3a7 AK |
6163 | { |
6164 | zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data; | |
6165 | ||
6166 | zebra_vxlan_sg_send(vxlan_sg->zvrf, &vxlan_sg->sg, | |
6167 | vxlan_sg->sg_str, ZEBRA_VXLAN_SG_ADD); | |
6168 | } | |
6169 | ||
6170 | /* Handle message from client to replay vxlan SG entries */ | |
6171 | void zebra_vxlan_sg_replay(ZAPI_HANDLER_ARGS) | |
6172 | { | |
6173 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6174 | zlog_debug("VxLAN SG updates to PIM, start"); | |
6175 | ||
6176 | SET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG); | |
6177 | ||
6178 | if (!EVPN_ENABLED(zvrf)) { | |
8f86bb06 DS |
6179 | if (IS_ZEBRA_DEBUG_VXLAN) |
6180 | zlog_debug("VxLAN SG replay request on unexpected vrf %d", | |
6181 | zvrf->vrf->vrf_id); | |
ecbbc3a7 AK |
6182 | return; |
6183 | } | |
6184 | ||
6185 | hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_replay_send, NULL); | |
6186 | } | |
6187 | ||
27627f9a KA |
6188 | |
6189 | /* Cleanup EVPN configuration of a specific VRF */ | |
6190 | static void zebra_evpn_vrf_cfg_cleanup(struct zebra_vrf *zvrf) | |
6191 | { | |
b6587fc2 CS |
6192 | zebra_l3vni_t *zl3vni = NULL; |
6193 | ||
27627f9a KA |
6194 | zvrf->advertise_all_vni = 0; |
6195 | zvrf->advertise_gw_macip = 0; | |
6196 | zvrf->advertise_svi_macip = 0; | |
6197 | zvrf->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL; | |
6198 | ||
8b5fdf2e | 6199 | hash_iterate(zvrf->evpn_table, zebra_evpn_cfg_cleanup, NULL); |
b6587fc2 CS |
6200 | |
6201 | if (zvrf->l3vni) | |
6202 | zl3vni = zl3vni_lookup(zvrf->l3vni); | |
6203 | if (zl3vni) { | |
6204 | /* delete and uninstall all rmacs */ | |
6205 | hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry, | |
6206 | zl3vni); | |
6207 | /* delete and uninstall all next-hops */ | |
6208 | hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry, | |
6209 | zl3vni); | |
6210 | } | |
27627f9a KA |
6211 | } |
6212 | ||
6213 | /* Cleanup BGP EVPN configuration upon client disconnect */ | |
ecbbc3a7 | 6214 | static int zebra_evpn_bgp_cfg_clean_up(struct zserv *client) |
27627f9a KA |
6215 | { |
6216 | struct vrf *vrf; | |
6217 | struct zebra_vrf *zvrf; | |
6218 | ||
27627f9a KA |
6219 | RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { |
6220 | zvrf = vrf->info; | |
6221 | if (zvrf) | |
6222 | zebra_evpn_vrf_cfg_cleanup(zvrf); | |
6223 | } | |
6224 | ||
6225 | return 0; | |
6226 | } | |
6227 | ||
ecbbc3a7 AK |
6228 | static int zebra_evpn_pim_cfg_clean_up(struct zserv *client) |
6229 | { | |
6230 | struct zebra_vrf *zvrf = zebra_vrf_get_evpn(); | |
6231 | ||
5e665031 | 6232 | if (zvrf && CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG)) { |
ecbbc3a7 AK |
6233 | if (IS_ZEBRA_DEBUG_VXLAN) |
6234 | zlog_debug("VxLAN SG updates to PIM, stop"); | |
6235 | UNSET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG); | |
6236 | } | |
6237 | ||
6238 | return 0; | |
6239 | } | |
6240 | ||
6241 | static int zebra_evpn_cfg_clean_up(struct zserv *client) | |
6242 | { | |
6243 | if (client->proto == ZEBRA_ROUTE_BGP) | |
6244 | return zebra_evpn_bgp_cfg_clean_up(client); | |
6245 | ||
6246 | if (client->proto == ZEBRA_ROUTE_PIM) | |
6247 | return zebra_evpn_pim_cfg_clean_up(client); | |
6248 | ||
6249 | return 0; | |
6250 | } | |
6251 | ||
036d93c0 MS |
6252 | /* |
6253 | * Handle results for vxlan dataplane operations. | |
6254 | */ | |
6255 | extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx) | |
6256 | { | |
6257 | /* TODO -- anything other than freeing the context? */ | |
6258 | dplane_ctx_fini(&ctx); | |
6259 | } | |
6260 | ||
27627f9a KA |
6261 | /* Cleanup BGP EVPN configuration upon client disconnect */ |
6262 | extern void zebra_evpn_init(void) | |
6263 | { | |
6264 | hook_register(zserv_client_close, zebra_evpn_cfg_clean_up); | |
6265 | } |