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