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