]>
Commit | Line | Data |
---|---|---|
7c551956 DS |
1 | /* |
2 | * Copyright (C) 2016 CumulusNetworks | |
3 | * Donald Sharp | |
4 | * | |
5 | * This file is part of Quagga | |
6 | * | |
7 | * Quagga 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 | * Quagga 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 | * | |
896014f4 DL |
17 | * You should have received a copy of the GNU General Public License along |
18 | * with this program; see the file COPYING; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
7c551956 DS |
20 | */ |
21 | #include <zebra.h> | |
22 | ||
62d89c64 IR |
23 | /* for basename */ |
24 | #include <libgen.h> | |
25 | ||
7c551956 DS |
26 | #include "log.h" |
27 | #include "linklist.h" | |
f30c50b9 | 28 | #include "command.h" |
4a1ab8e4 | 29 | #include "memory.h" |
05737783 | 30 | #include "srcdest_table.h" |
78dd30b2 | 31 | #include "vrf.h" |
82f97584 | 32 | #include "vty.h" |
78dd30b2 | 33 | |
89272910 | 34 | #include "zebra/zebra_router.h" |
df9c8c57 | 35 | #include "zebra/rtadv.h" |
7c551956 | 36 | #include "zebra/debug.h" |
bf094f69 | 37 | #include "zebra/zapi_msg.h" |
7c551956 DS |
38 | #include "zebra/rib.h" |
39 | #include "zebra/zebra_vrf.h" | |
5a8dfcd8 | 40 | #include "zebra/zebra_rnh.h" |
7c551956 | 41 | #include "zebra/router-id.h" |
5a8dfcd8 | 42 | #include "zebra/interface.h" |
7758e3f3 | 43 | #include "zebra/zebra_mpls.h" |
13d60d35 | 44 | #include "zebra/zebra_vxlan.h" |
3bc34908 | 45 | #include "zebra/zebra_netns_notify.h" |
7cf16e19 | 46 | #include "zebra/zebra_routemap.h" |
37cb0475 IR |
47 | #ifndef VTYSH_EXTRACT_PL |
48 | #include "zebra/zebra_vrf_clippy.c" | |
49 | #endif | |
42d4b30e | 50 | #include "zebra/table_manager.h" |
7c551956 | 51 | |
9d97533e | 52 | static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, |
53 | safi_t safi); | |
54 | static void zebra_rnhtable_node_cleanup(struct route_table *table, | |
55 | struct route_node *node); | |
56 | ||
bf8d3d6a DL |
57 | DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF"); |
58 | DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table"); | |
d8612e65 | 59 | |
7c551956 | 60 | /* VRF information update. */ |
d62a17ae | 61 | static void zebra_vrf_add_update(struct zebra_vrf *zvrf) |
7c551956 | 62 | { |
d62a17ae | 63 | struct listnode *node, *nnode; |
64 | struct zserv *client; | |
7c551956 | 65 | |
d62a17ae | 66 | if (IS_ZEBRA_DEBUG_EVENT) |
67 | zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf)); | |
7c551956 | 68 | |
17da84a4 KS |
69 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
70 | /* Do not send unsolicited messages to synchronous clients. */ | |
71 | if (client->synchronous) | |
72 | continue; | |
73 | ||
d62a17ae | 74 | zsend_vrf_add(client, zvrf); |
17da84a4 | 75 | } |
7c551956 DS |
76 | } |
77 | ||
d62a17ae | 78 | static void zebra_vrf_delete_update(struct zebra_vrf *zvrf) |
7c551956 | 79 | { |
d62a17ae | 80 | struct listnode *node, *nnode; |
81 | struct zserv *client; | |
7c551956 | 82 | |
d62a17ae | 83 | if (IS_ZEBRA_DEBUG_EVENT) |
84 | zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf)); | |
7c551956 | 85 | |
17da84a4 KS |
86 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
87 | /* Do not send unsolicited messages to synchronous clients. */ | |
88 | if (client->synchronous) | |
89 | continue; | |
90 | ||
d62a17ae | 91 | zsend_vrf_delete(client, zvrf); |
17da84a4 | 92 | } |
7c551956 DS |
93 | } |
94 | ||
d62a17ae | 95 | void zebra_vrf_update_all(struct zserv *client) |
7c551956 | 96 | { |
d62a17ae | 97 | struct vrf *vrf; |
7c551956 | 98 | |
a2addae8 | 99 | RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { |
4691b65a | 100 | if (vrf->vrf_id != VRF_UNKNOWN) |
d62a17ae | 101 | zsend_vrf_add(client, vrf_info_lookup(vrf->vrf_id)); |
102 | } | |
7c551956 DS |
103 | } |
104 | ||
105 | /* Callback upon creating a new VRF. */ | |
d62a17ae | 106 | static int zebra_vrf_new(struct vrf *vrf) |
7c551956 | 107 | { |
d62a17ae | 108 | struct zebra_vrf *zvrf; |
7c551956 | 109 | |
d62a17ae | 110 | if (IS_ZEBRA_DEBUG_EVENT) |
14a4d9d0 | 111 | zlog_debug("VRF %s created, id %u", vrf->name, vrf->vrf_id); |
7c551956 | 112 | |
ec64a634 | 113 | zvrf = zebra_vrf_alloc(vrf); |
91b1421e PG |
114 | if (!vrf_is_backend_netns()) |
115 | zvrf->zns = zebra_ns_lookup(NS_DEFAULT); | |
d8612e65 DS |
116 | |
117 | otable_init(&zvrf->other_tables); | |
118 | ||
fbb65ff5 | 119 | router_id_init(zvrf); |
42d4b30e PG |
120 | |
121 | /* Initiate Table Manager per ZNS */ | |
122 | table_manager_enable(zvrf); | |
123 | ||
d62a17ae | 124 | return 0; |
7c551956 DS |
125 | } |
126 | ||
127 | /* Callback upon enabling a VRF. */ | |
d62a17ae | 128 | static int zebra_vrf_enable(struct vrf *vrf) |
7c551956 | 129 | { |
d62a17ae | 130 | struct zebra_vrf *zvrf = vrf->info; |
9d97533e | 131 | struct route_table *table; |
d62a17ae | 132 | afi_t afi; |
133 | safi_t safi; | |
134 | ||
135 | assert(zvrf); | |
84915b0a | 136 | if (IS_ZEBRA_DEBUG_EVENT) |
996c9314 LB |
137 | zlog_debug("VRF %s id %u is now active", zvrf_name(zvrf), |
138 | zvrf_id(zvrf)); | |
d62a17ae | 139 | |
fbb65ff5 PG |
140 | if (vrf_is_backend_netns()) |
141 | zvrf->zns = zebra_ns_lookup((ns_id_t)vrf->vrf_id); | |
142 | else | |
143 | zvrf->zns = zebra_ns_lookup(NS_DEFAULT); | |
df9c8c57 | 144 | #if defined(HAVE_RTADV) |
7c2ddfb9 | 145 | rtadv_vrf_init(zvrf); |
df9c8c57 PG |
146 | #endif |
147 | ||
84915b0a | 148 | /* Inform clients that the VRF is now active. This is an |
149 | * add for the clients. | |
150 | */ | |
d62a17ae | 151 | |
8288a24f | 152 | zebra_vrf_add_update(zvrf); |
9d97533e | 153 | /* Allocate tables */ |
154 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
155 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) | |
156 | zebra_vrf_table_create(zvrf, afi, safi); | |
157 | ||
158 | table = route_table_init(); | |
159 | table->cleanup = zebra_rnhtable_node_cleanup; | |
160 | zvrf->rnh_table[afi] = table; | |
161 | ||
162 | table = route_table_init(); | |
163 | table->cleanup = zebra_rnhtable_node_cleanup; | |
a4598b97 | 164 | zvrf->rnh_table_multicast[afi] = table; |
9d97533e | 165 | } |
166 | ||
84915b0a | 167 | /* Kick off any VxLAN-EVPN processing. */ |
168 | zebra_vxlan_vrf_enable(zvrf); | |
169 | ||
d62a17ae | 170 | return 0; |
7c551956 DS |
171 | } |
172 | ||
173 | /* Callback upon disabling a VRF. */ | |
d62a17ae | 174 | static int zebra_vrf_disable(struct vrf *vrf) |
7c551956 | 175 | { |
d62a17ae | 176 | struct zebra_vrf *zvrf = vrf->info; |
9d97533e | 177 | struct interface *ifp; |
d62a17ae | 178 | afi_t afi; |
179 | safi_t safi; | |
9d97533e | 180 | unsigned i; |
d62a17ae | 181 | |
84915b0a | 182 | assert(zvrf); |
183 | if (IS_ZEBRA_DEBUG_EVENT) | |
996c9314 LB |
184 | zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf), |
185 | zvrf_id(zvrf)); | |
d62a17ae | 186 | |
42d4b30e PG |
187 | table_manager_disable(zvrf); |
188 | ||
84915b0a | 189 | /* Stop any VxLAN-EVPN processing. */ |
190 | zebra_vxlan_vrf_disable(zvrf); | |
d62a17ae | 191 | |
df9c8c57 | 192 | #if defined(HAVE_RTADV) |
aab5893a | 193 | rtadv_vrf_terminate(zvrf); |
df9c8c57 PG |
194 | #endif |
195 | ||
84915b0a | 196 | /* Inform clients that the VRF is now inactive. This is a |
197 | * delete for the clients. | |
198 | */ | |
d62a17ae | 199 | zebra_vrf_delete_update(zvrf); |
200 | ||
9d97533e | 201 | /* If asked to retain routes, there's nothing more to do. */ |
202 | if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) | |
203 | return 0; | |
204 | ||
205 | /* Remove all routes. */ | |
206 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
41dc8c14 DS |
207 | route_table_finish(zvrf->rnh_table[afi]); |
208 | zvrf->rnh_table[afi] = NULL; | |
a4598b97 DS |
209 | route_table_finish(zvrf->rnh_table_multicast[afi]); |
210 | zvrf->rnh_table_multicast[afi] = NULL; | |
41dc8c14 | 211 | |
9d97533e | 212 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) |
213 | rib_close_table(zvrf->table[afi][safi]); | |
9d97533e | 214 | } |
215 | ||
216 | /* Cleanup Vxlan, MPLS and PW tables. */ | |
217 | zebra_vxlan_cleanup_tables(zvrf); | |
218 | zebra_mpls_cleanup_tables(zvrf); | |
219 | zebra_pw_exit(zvrf); | |
220 | ||
996c9314 LB |
221 | /* Remove link-local IPv4 addresses created for BGP unnumbered peering. |
222 | */ | |
9d97533e | 223 | FOR_ALL_INTERFACES (vrf, ifp) |
224 | if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); | |
225 | ||
226 | /* clean-up work queues */ | |
227 | for (i = 0; i < MQ_SIZE; i++) { | |
228 | struct listnode *lnode, *nnode; | |
229 | struct route_node *rnode; | |
230 | rib_dest_t *dest; | |
231 | ||
ea45a4e7 | 232 | for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode, |
996c9314 | 233 | rnode)) { |
9d97533e | 234 | dest = rib_dest_from_rnode(rnode); |
235 | if (dest && rib_dest_vrf(dest) == zvrf) { | |
236 | route_unlock_node(rnode); | |
ea45a4e7 DS |
237 | list_delete_node(zrouter.mq->subq[i], lnode); |
238 | zrouter.mq->size--; | |
9d97533e | 239 | } |
d62a17ae | 240 | } |
9d97533e | 241 | } |
7c551956 | 242 | |
9d97533e | 243 | /* Cleanup (free) routing tables and NHT tables. */ |
244 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
89272910 DS |
245 | /* |
246 | * Set the table pointer to NULL as that | |
247 | * we no-longer need a copy of it, nor do we | |
248 | * own this data, the zebra_router structure | |
249 | * owns these tables. Once we've cleaned up the | |
250 | * table, see rib_close_table above | |
251 | * we no-longer need this pointer. | |
252 | */ | |
bd4fb615 DS |
253 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { |
254 | zebra_router_release_table(zvrf, zvrf->table_id, afi, | |
255 | safi); | |
9d97533e | 256 | zvrf->table[afi][safi] = NULL; |
bd4fb615 | 257 | } |
5a8dfcd8 RW |
258 | } |
259 | ||
d62a17ae | 260 | return 0; |
7c551956 DS |
261 | } |
262 | ||
d62a17ae | 263 | static int zebra_vrf_delete(struct vrf *vrf) |
7c551956 | 264 | { |
d62a17ae | 265 | struct zebra_vrf *zvrf = vrf->info; |
d8612e65 | 266 | struct other_route_table *otable; |
d62a17ae | 267 | struct route_table *table; |
d62a17ae | 268 | afi_t afi; |
269 | safi_t safi; | |
270 | unsigned i; | |
271 | ||
272 | assert(zvrf); | |
84915b0a | 273 | if (IS_ZEBRA_DEBUG_EVENT) |
996c9314 LB |
274 | zlog_debug("VRF %s id %u deleted", zvrf_name(zvrf), |
275 | zvrf_id(zvrf)); | |
5a8dfcd8 | 276 | |
d62a17ae | 277 | /* clean-up work queues */ |
278 | for (i = 0; i < MQ_SIZE; i++) { | |
279 | struct listnode *lnode, *nnode; | |
280 | struct route_node *rnode; | |
281 | rib_dest_t *dest; | |
282 | ||
ea45a4e7 | 283 | for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode, |
996c9314 | 284 | rnode)) { |
d62a17ae | 285 | dest = rib_dest_from_rnode(rnode); |
286 | if (dest && rib_dest_vrf(dest) == zvrf) { | |
287 | route_unlock_node(rnode); | |
ea45a4e7 DS |
288 | list_delete_node(zrouter.mq->subq[i], lnode); |
289 | zrouter.mq->size--; | |
d62a17ae | 290 | } |
291 | } | |
5a8dfcd8 | 292 | } |
5a8dfcd8 | 293 | |
84915b0a | 294 | /* Free Vxlan and MPLS. */ |
295 | zebra_vxlan_close_tables(zvrf); | |
296 | zebra_mpls_close_tables(zvrf); | |
297 | ||
d62a17ae | 298 | /* release allocated memory */ |
299 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
d62a17ae | 300 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { |
301 | table = zvrf->table[afi][safi]; | |
9d97533e | 302 | if (table) { |
bd4fb615 DS |
303 | zebra_router_release_table(zvrf, zvrf->table_id, |
304 | afi, safi); | |
305 | zvrf->table[afi][safi] = NULL; | |
9d97533e | 306 | } |
d62a17ae | 307 | } |
5a8dfcd8 | 308 | |
41dc8c14 DS |
309 | if (zvrf->rnh_table[afi]) |
310 | route_table_finish(zvrf->rnh_table[afi]); | |
a4598b97 DS |
311 | if (zvrf->rnh_table_multicast[afi]) |
312 | route_table_finish(zvrf->rnh_table[afi]); | |
5a8dfcd8 | 313 | } |
b7cfce93 | 314 | |
d8612e65 DS |
315 | otable = otable_pop(&zvrf->other_tables); |
316 | while (otable) { | |
317 | zebra_router_release_table(zvrf, otable->table_id, | |
318 | otable->afi, otable->safi); | |
319 | XFREE(MTYPE_OTHER_TABLE, otable); | |
320 | ||
321 | otable = otable_pop(&zvrf->other_tables); | |
322 | } | |
323 | ||
84915b0a | 324 | /* Cleanup EVPN states for vrf */ |
b7cfce93 MK |
325 | zebra_vxlan_vrf_delete(zvrf); |
326 | ||
d62a17ae | 327 | list_delete_all_node(zvrf->rid_all_sorted_list); |
328 | list_delete_all_node(zvrf->rid_lo_sorted_list); | |
d8612e65 | 329 | |
cdc09a4b MS |
330 | list_delete_all_node(zvrf->rid6_all_sorted_list); |
331 | list_delete_all_node(zvrf->rid6_lo_sorted_list); | |
332 | ||
d8612e65 | 333 | otable_fini(&zvrf->other_tables); |
d62a17ae | 334 | XFREE(MTYPE_ZEBRA_VRF, zvrf); |
335 | vrf->info = NULL; | |
5a8dfcd8 | 336 | |
d62a17ae | 337 | return 0; |
7c551956 DS |
338 | } |
339 | ||
ecbc5a37 PG |
340 | static int zebra_vrf_update(struct vrf *vrf) |
341 | { | |
342 | struct zebra_vrf *zvrf = vrf->info; | |
343 | ||
344 | assert(zvrf); | |
345 | if (IS_ZEBRA_DEBUG_EVENT) | |
346 | zlog_debug("VRF %s id %u, name updated", vrf->name, | |
347 | zvrf_id(zvrf)); | |
348 | zebra_vrf_add_update(zvrf); | |
349 | return 0; | |
350 | } | |
351 | ||
7c551956 | 352 | /* Lookup the routing table in a VRF based on both VRF-Id and table-id. |
e9748a89 PG |
353 | * NOTE: Table-id is relevant on two modes: |
354 | * - case VRF backend is default : on default VRF only | |
355 | * - case VRF backend is netns : on all VRFs | |
7c551956 | 356 | */ |
c7c0b007 SW |
357 | struct route_table *zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi, |
358 | vrf_id_t vrf_id, | |
359 | uint32_t table_id) | |
7c551956 | 360 | { |
8ab39b7f | 361 | struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id); |
d8612e65 | 362 | struct other_route_table ort, *otable; |
8ab39b7f DS |
363 | |
364 | if (!zvrf) | |
365 | return NULL; | |
d62a17ae | 366 | |
367 | if (afi >= AFI_MAX || safi >= SAFI_MAX) | |
368 | return NULL; | |
369 | ||
8ab39b7f DS |
370 | if (table_id == zvrf->table_id) |
371 | return zebra_vrf_table(afi, safi, vrf_id); | |
d62a17ae | 372 | |
d8612e65 DS |
373 | ort.afi = afi; |
374 | ort.safi = safi; | |
375 | ort.table_id = table_id; | |
376 | otable = otable_find(&zvrf->other_tables, &ort); | |
c7c0b007 | 377 | |
d8612e65 DS |
378 | if (otable) |
379 | return otable->table; | |
380 | ||
c7c0b007 SW |
381 | return NULL; |
382 | } | |
383 | ||
384 | struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi, safi_t safi, | |
385 | vrf_id_t vrf_id, | |
386 | uint32_t table_id) | |
387 | { | |
388 | struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id); | |
389 | struct other_route_table *otable; | |
390 | struct route_table *table; | |
391 | ||
392 | table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id, | |
393 | table_id); | |
394 | ||
395 | if (table) | |
396 | goto done; | |
397 | ||
398 | /* Create it as an `other` table */ | |
d8612e65 DS |
399 | table = zebra_router_get_table(zvrf, table_id, afi, safi); |
400 | ||
401 | otable = XCALLOC(MTYPE_OTHER_TABLE, sizeof(*otable)); | |
402 | otable->afi = afi; | |
403 | otable->safi = safi; | |
404 | otable->table_id = table_id; | |
405 | otable->table = table; | |
406 | otable_add(&zvrf->other_tables, otable); | |
d62a17ae | 407 | |
c7c0b007 | 408 | done: |
d62a17ae | 409 | return table; |
7c551956 DS |
410 | } |
411 | ||
d62a17ae | 412 | static void zebra_rnhtable_node_cleanup(struct route_table *table, |
413 | struct route_node *node) | |
5a8dfcd8 | 414 | { |
d62a17ae | 415 | if (node->info) |
416 | zebra_free_rnh(node->info); | |
5a8dfcd8 RW |
417 | } |
418 | ||
7c551956 DS |
419 | /* |
420 | * Create a routing table for the specific AFI/SAFI in the given VRF. | |
421 | */ | |
d62a17ae | 422 | static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, |
423 | safi_t safi) | |
7c551956 | 424 | { |
c86ba6c2 DS |
425 | struct route_node *rn; |
426 | struct prefix p; | |
427 | ||
d62a17ae | 428 | assert(!zvrf->table[afi][safi]); |
429 | ||
ea66cec4 DS |
430 | zvrf->table[afi][safi] = |
431 | zebra_router_get_table(zvrf, zvrf->table_id, afi, safi); | |
c86ba6c2 DS |
432 | |
433 | memset(&p, 0, sizeof(p)); | |
434 | p.family = afi2family(afi); | |
435 | ||
436 | rn = srcdest_rnode_get(zvrf->table[afi][safi], &p, NULL); | |
437 | zebra_rib_create_dest(rn); | |
7c551956 DS |
438 | } |
439 | ||
440 | /* Allocate new zebra VRF. */ | |
ec64a634 | 441 | struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf) |
7c551956 | 442 | { |
d62a17ae | 443 | struct zebra_vrf *zvrf; |
d62a17ae | 444 | |
445 | zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf)); | |
446 | ||
ec64a634 DS |
447 | zvrf->vrf = vrf; |
448 | vrf->info = zvrf; | |
449 | ||
d62a17ae | 450 | zebra_vxlan_init_tables(zvrf); |
451 | zebra_mpls_init_tables(zvrf); | |
6833ae01 | 452 | zebra_pw_init(zvrf); |
e9748a89 PG |
453 | zvrf->table_id = RT_TABLE_MAIN; |
454 | /* by default table ID is default one */ | |
d62a17ae | 455 | return zvrf; |
7c551956 DS |
456 | } |
457 | ||
458 | /* Lookup VRF by identifier. */ | |
d62a17ae | 459 | struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id) |
7c551956 | 460 | { |
d62a17ae | 461 | return vrf_info_lookup(vrf_id); |
7c551956 DS |
462 | } |
463 | ||
51bdc5f8 | 464 | /* Lookup VRF by name. */ |
d62a17ae | 465 | struct zebra_vrf *zebra_vrf_lookup_by_name(const char *name) |
871d39b3 | 466 | { |
d62a17ae | 467 | struct vrf *vrf; |
871d39b3 | 468 | |
d62a17ae | 469 | if (!name) |
470 | name = VRF_DEFAULT_NAME; | |
a3d21ef3 | 471 | |
d62a17ae | 472 | vrf = vrf_lookup_by_name(name); |
473 | if (vrf) | |
474 | return ((struct zebra_vrf *)vrf->info); | |
51bdc5f8 | 475 | |
d62a17ae | 476 | return NULL; |
871d39b3 DS |
477 | } |
478 | ||
7c551956 | 479 | /* Lookup the routing table in an enabled VRF. */ |
d62a17ae | 480 | struct route_table *zebra_vrf_table(afi_t afi, safi_t safi, vrf_id_t vrf_id) |
7c551956 | 481 | { |
d62a17ae | 482 | struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id); |
7c551956 | 483 | |
d62a17ae | 484 | if (!zvrf) |
485 | return NULL; | |
7c551956 | 486 | |
d62a17ae | 487 | if (afi >= AFI_MAX || safi >= SAFI_MAX) |
488 | return NULL; | |
7c551956 | 489 | |
d62a17ae | 490 | return zvrf->table[afi][safi]; |
7c551956 DS |
491 | } |
492 | ||
d62a17ae | 493 | static int vrf_config_write(struct vty *vty) |
f30c50b9 | 494 | { |
d62a17ae | 495 | struct vrf *vrf; |
496 | struct zebra_vrf *zvrf; | |
497 | ||
a2addae8 | 498 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { |
d62a17ae | 499 | zvrf = vrf->info; |
1e9f448f DS |
500 | |
501 | if (!zvrf) | |
502 | continue; | |
503 | ||
a5654735 MK |
504 | if (zvrf_id(zvrf) == VRF_DEFAULT) { |
505 | if (zvrf->l3vni) | |
8d0f01f1 CS |
506 | vty_out(vty, "vni %u%s\n", zvrf->l3vni, |
507 | is_l3vni_for_prefix_routes_only( | |
508 | zvrf->l3vni) | |
509 | ? " prefix-routes-only" | |
510 | : ""); | |
5a0bdc78 PG |
511 | if (zvrf->zebra_rnh_ip_default_route) |
512 | vty_out(vty, "ip nht resolve-via-default\n"); | |
513 | ||
514 | if (zvrf->zebra_rnh_ipv6_default_route) | |
515 | vty_out(vty, "ipv6 nht resolve-via-default\n"); | |
42d4b30e PG |
516 | |
517 | if (zvrf->tbl_mgr | |
518 | && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)) | |
519 | vty_out(vty, "ip table range %u %u\n", | |
520 | zvrf->tbl_mgr->start, | |
521 | zvrf->tbl_mgr->end); | |
c319e19d QY |
522 | } else { |
523 | vty_frame(vty, "vrf %s\n", zvrf_name(zvrf)); | |
22bd3e94 | 524 | if (zvrf->l3vni) |
996c9314 LB |
525 | vty_out(vty, " vni %u%s\n", zvrf->l3vni, |
526 | is_l3vni_for_prefix_routes_only( | |
527 | zvrf->l3vni) | |
528 | ? " prefix-routes-only" | |
529 | : ""); | |
b95c1883 | 530 | zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt); |
5a0bdc78 PG |
531 | if (zvrf->zebra_rnh_ip_default_route) |
532 | vty_out(vty, " ip nht resolve-via-default\n"); | |
533 | ||
534 | if (zvrf->zebra_rnh_ipv6_default_route) | |
535 | vty_out(vty, " ipv6 nht resolve-via-default\n"); | |
42d4b30e PG |
536 | |
537 | if (zvrf->tbl_mgr && vrf_is_backend_netns() | |
538 | && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)) | |
539 | vty_out(vty, " ip table range %u %u\n", | |
540 | zvrf->tbl_mgr->start, | |
541 | zvrf->tbl_mgr->end); | |
22bd3e94 | 542 | } |
37728041 | 543 | |
5a0bdc78 | 544 | |
7cf16e19 | 545 | zebra_routemap_config_write_protocol(vty, zvrf); |
03fba42e | 546 | router_id_write(vty, zvrf); |
7cf16e19 | 547 | |
c319e19d | 548 | if (zvrf_id(zvrf) != VRF_DEFAULT) |
07679ad9 | 549 | vty_endframe(vty, "exit-vrf\n!\n"); |
7cf16e19 | 550 | else |
551 | vty_out(vty, "!\n"); | |
d62a17ae | 552 | } |
553 | return 0; | |
f30c50b9 RW |
554 | } |
555 | ||
37cb0475 IR |
556 | DEFPY (vrf_netns, |
557 | vrf_netns_cmd, | |
558 | "netns NAME$netns_name", | |
559 | "Attach VRF to a Namespace\n" | |
560 | "The file name in " NS_RUN_DIR ", or a full pathname\n") | |
561 | { | |
562 | char *pathname = ns_netns_pathname(vty, netns_name); | |
563 | int ret; | |
564 | ||
565 | VTY_DECLVAR_CONTEXT(vrf, vrf); | |
566 | ||
567 | if (!pathname) | |
568 | return CMD_WARNING_CONFIG_FAILED; | |
569 | ||
570 | frr_with_privs(&zserv_privs) { | |
62d89c64 IR |
571 | ret = zebra_vrf_netns_handler_create( |
572 | vty, vrf, pathname, NS_UNKNOWN, NS_UNKNOWN, NS_UNKNOWN); | |
37cb0475 IR |
573 | } |
574 | ||
575 | return ret; | |
576 | } | |
577 | ||
578 | DEFUN (no_vrf_netns, | |
579 | no_vrf_netns_cmd, | |
580 | "no netns [NAME]", | |
581 | NO_STR | |
582 | "Detach VRF from a Namespace\n" | |
583 | "The file name in " NS_RUN_DIR ", or a full pathname\n") | |
584 | { | |
585 | struct ns *ns = NULL; | |
586 | ||
587 | VTY_DECLVAR_CONTEXT(vrf, vrf); | |
588 | ||
589 | if (!vrf_is_backend_netns()) { | |
590 | vty_out(vty, "VRF backend is not Netns. Aborting\n"); | |
591 | return CMD_WARNING_CONFIG_FAILED; | |
592 | } | |
593 | if (!vrf->ns_ctxt) { | |
594 | vty_out(vty, "VRF %s(%u) is not configured with NetNS\n", | |
595 | vrf->name, vrf->vrf_id); | |
596 | return CMD_WARNING_CONFIG_FAILED; | |
597 | } | |
598 | ||
599 | ns = (struct ns *)vrf->ns_ctxt; | |
600 | ||
601 | ns->vrf_ctxt = NULL; | |
602 | vrf_disable(vrf); | |
603 | /* vrf ID from VRF is necessary for Zebra | |
604 | * so that propagate to other clients is done | |
605 | */ | |
606 | ns_delete(ns); | |
607 | vrf->ns_ctxt = NULL; | |
608 | return CMD_SUCCESS; | |
609 | } | |
610 | ||
62d89c64 IR |
611 | /* if ns_id is different and not VRF_UNKNOWN, |
612 | * then update vrf identifier, and enable VRF | |
613 | */ | |
614 | static void vrf_update_vrf_id(ns_id_t ns_id, void *opaqueptr) | |
615 | { | |
616 | ns_id_t vrf_id = (vrf_id_t)ns_id; | |
617 | vrf_id_t old_vrf_id; | |
618 | struct vrf *vrf = (struct vrf *)opaqueptr; | |
619 | ||
620 | if (!vrf) | |
621 | return; | |
622 | old_vrf_id = vrf->vrf_id; | |
623 | if (vrf_id == vrf->vrf_id) | |
624 | return; | |
625 | if (vrf->vrf_id != VRF_UNKNOWN) | |
626 | RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); | |
627 | vrf->vrf_id = vrf_id; | |
628 | RB_INSERT(vrf_id_head, &vrfs_by_id, vrf); | |
629 | if (old_vrf_id == VRF_UNKNOWN) | |
630 | vrf_enable(vrf); | |
631 | } | |
632 | ||
633 | int zebra_vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, | |
634 | char *pathname, ns_id_t ns_id, | |
635 | ns_id_t internal_ns_id, | |
636 | ns_id_t rel_def_ns_id) | |
637 | { | |
638 | struct ns *ns = NULL; | |
639 | ||
640 | if (!vrf) | |
641 | return CMD_WARNING_CONFIG_FAILED; | |
642 | if (vrf->vrf_id != VRF_UNKNOWN && vrf->ns_ctxt == NULL) { | |
643 | if (vty) | |
644 | vty_out(vty, | |
645 | "VRF %u is already configured with VRF %s\n", | |
646 | vrf->vrf_id, vrf->name); | |
647 | else | |
648 | zlog_info("VRF %u is already configured with VRF %s", | |
649 | vrf->vrf_id, vrf->name); | |
650 | return CMD_WARNING_CONFIG_FAILED; | |
651 | } | |
652 | if (vrf->ns_ctxt != NULL) { | |
653 | ns = (struct ns *)vrf->ns_ctxt; | |
654 | if (!strcmp(ns->name, pathname)) { | |
655 | if (vty) | |
656 | vty_out(vty, | |
657 | "VRF %u already configured with NETNS %s\n", | |
658 | vrf->vrf_id, ns->name); | |
659 | else | |
660 | zlog_info( | |
661 | "VRF %u already configured with NETNS %s", | |
662 | vrf->vrf_id, ns->name); | |
663 | return CMD_WARNING_CONFIG_FAILED; | |
664 | } | |
665 | } | |
666 | ns = ns_lookup_name(pathname); | |
667 | if (ns && ns->vrf_ctxt) { | |
668 | struct vrf *vrf2 = (struct vrf *)ns->vrf_ctxt; | |
669 | ||
670 | if (vrf2 == vrf) | |
671 | return CMD_SUCCESS; | |
672 | if (vty) | |
673 | vty_out(vty, | |
674 | "NS %s is already configured with VRF %u(%s)\n", | |
675 | ns->name, vrf2->vrf_id, vrf2->name); | |
676 | else | |
677 | zlog_info("NS %s is already configured with VRF %u(%s)", | |
678 | ns->name, vrf2->vrf_id, vrf2->name); | |
679 | return CMD_WARNING_CONFIG_FAILED; | |
680 | } | |
681 | ns = ns_get_created(ns, pathname, ns_id); | |
682 | ns->internal_ns_id = internal_ns_id; | |
683 | ns->relative_default_ns = rel_def_ns_id; | |
684 | ns->vrf_ctxt = (void *)vrf; | |
685 | vrf->ns_ctxt = (void *)ns; | |
686 | /* update VRF netns NAME */ | |
687 | strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ); | |
688 | ||
689 | if (!ns_enable(ns, vrf_update_vrf_id)) { | |
690 | if (vty) | |
691 | vty_out(vty, "Can not associate NS %u with NETNS %s\n", | |
692 | ns->ns_id, ns->name); | |
693 | else | |
694 | zlog_info("Can not associate NS %u with NETNS %s", | |
695 | ns->ns_id, ns->name); | |
696 | return CMD_WARNING_CONFIG_FAILED; | |
697 | } | |
698 | ||
699 | return CMD_SUCCESS; | |
700 | } | |
701 | ||
7c551956 | 702 | /* Zebra VRF initialization. */ |
d62a17ae | 703 | void zebra_vrf_init(void) |
7c551956 | 704 | { |
996c9314 | 705 | vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable, |
ecbc5a37 | 706 | zebra_vrf_delete, zebra_vrf_update); |
7c551956 | 707 | |
903c6fa2 IR |
708 | hook_register(zserv_client_close, release_daemon_table_chunks); |
709 | ||
cfc369c4 | 710 | vrf_cmd_init(vrf_config_write); |
37cb0475 IR |
711 | |
712 | if (vrf_is_backend_netns() && ns_have_netns()) { | |
713 | /* Install NS commands. */ | |
714 | install_element(VRF_NODE, &vrf_netns_cmd); | |
715 | install_element(VRF_NODE, &no_vrf_netns_cmd); | |
716 | } | |
7c551956 | 717 | } |