Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * VRF functions. |
4 | | * Copyright (C) 2014 6WIND S.A. |
5 | | */ |
6 | | |
7 | | #include <zebra.h> |
8 | | |
9 | | #include "if.h" |
10 | | #include "vrf.h" |
11 | | #include "vrf_int.h" |
12 | | #include "prefix.h" |
13 | | #include "table.h" |
14 | | #include "log.h" |
15 | | #include "memory.h" |
16 | | #include "command.h" |
17 | | #include "ns.h" |
18 | | #include "privs.h" |
19 | | #include "nexthop_group.h" |
20 | | #include "lib_errors.h" |
21 | | #include "northbound.h" |
22 | | #include "northbound_cli.h" |
23 | | |
24 | | /* default VRF name value used when VRF backend is not NETNS */ |
25 | | #define VRF_DEFAULT_NAME_INTERNAL "default" |
26 | | |
27 | | DEFINE_MTYPE_STATIC(LIB, VRF, "VRF"); |
28 | | DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map"); |
29 | | |
30 | | DEFINE_QOBJ_TYPE(vrf); |
31 | | |
32 | | static __inline int vrf_id_compare(const struct vrf *, const struct vrf *); |
33 | | static __inline int vrf_name_compare(const struct vrf *, const struct vrf *); |
34 | | |
35 | | RB_GENERATE(vrf_id_head, vrf, id_entry, vrf_id_compare); |
36 | | RB_GENERATE(vrf_name_head, vrf, name_entry, vrf_name_compare); |
37 | | |
38 | | struct vrf_id_head vrfs_by_id = RB_INITIALIZER(&vrfs_by_id); |
39 | | struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name); |
40 | | |
41 | | static int vrf_backend; |
42 | | static int vrf_backend_configured; |
43 | | static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL; |
44 | | |
45 | | /* |
46 | | * Turn on/off debug code |
47 | | * for vrf. |
48 | | */ |
49 | | static int debug_vrf = 0; |
50 | | |
51 | | /* Holding VRF hooks */ |
52 | | static struct vrf_master { |
53 | | int (*vrf_new_hook)(struct vrf *); |
54 | | int (*vrf_delete_hook)(struct vrf *); |
55 | | int (*vrf_enable_hook)(struct vrf *); |
56 | | int (*vrf_disable_hook)(struct vrf *); |
57 | | } vrf_master = { |
58 | | 0, |
59 | | }; |
60 | | |
61 | | static int vrf_is_enabled(struct vrf *vrf); |
62 | | |
63 | | /* VRF list existance check by name. */ |
64 | | struct vrf *vrf_lookup_by_name(const char *name) |
65 | 7 | { |
66 | 7 | struct vrf vrf; |
67 | 7 | strlcpy(vrf.name, name, sizeof(vrf.name)); |
68 | 7 | return (RB_FIND(vrf_name_head, &vrfs_by_name, &vrf)); |
69 | 7 | } |
70 | | |
71 | | static __inline int vrf_id_compare(const struct vrf *a, const struct vrf *b) |
72 | 1.23k | { |
73 | 1.23k | return (a->vrf_id - b->vrf_id); |
74 | 1.23k | } |
75 | | |
76 | | static int vrf_name_compare(const struct vrf *a, const struct vrf *b) |
77 | 5 | { |
78 | 5 | return strcmp(a->name, b->name); |
79 | 5 | } |
80 | | |
81 | | int vrf_switch_to_netns(vrf_id_t vrf_id) |
82 | 0 | { |
83 | 0 | char *name; |
84 | 0 | struct vrf *vrf = vrf_lookup_by_id(vrf_id); |
85 | | |
86 | | /* VRF is default VRF. silently ignore */ |
87 | 0 | if (!vrf || vrf->vrf_id == VRF_DEFAULT) |
88 | 0 | return 1; /* 1 = default */ |
89 | | /* VRF has no NETNS backend. silently ignore */ |
90 | 0 | if (vrf->data.l.netns_name[0] == '\0') |
91 | 0 | return 2; /* 2 = no netns */ |
92 | 0 | name = ns_netns_pathname(NULL, vrf->data.l.netns_name); |
93 | 0 | if (debug_vrf) |
94 | 0 | zlog_debug("VRF_SWITCH: %s(%u)", name, vrf->vrf_id); |
95 | 0 | return ns_switch_to_netns(name); |
96 | 0 | } |
97 | | |
98 | | int vrf_switchback_to_initial(void) |
99 | 0 | { |
100 | 0 | int ret = ns_switchback_to_initial(); |
101 | |
|
102 | 0 | if (ret == 0 && debug_vrf) |
103 | 0 | zlog_debug("VRF_SWITCHBACK"); |
104 | 0 | return ret; |
105 | 0 | } |
106 | | |
107 | | /* Get a VRF. If not found, create one. |
108 | | * Arg: |
109 | | * name - The name of the vrf. May be NULL if unknown. |
110 | | * vrf_id - The vrf_id of the vrf. May be VRF_UNKNOWN if unknown |
111 | | * Description: Please note that this routine can be called with just the name |
112 | | * and 0 vrf-id |
113 | | */ |
114 | | struct vrf *vrf_get(vrf_id_t vrf_id, const char *name) |
115 | 6 | { |
116 | 6 | struct vrf *vrf = NULL; |
117 | 6 | int new = 0; |
118 | | |
119 | | /* Nothing to see, move along here */ |
120 | 6 | if (!name && vrf_id == VRF_UNKNOWN) |
121 | 0 | return NULL; |
122 | | |
123 | | /* attempt to find already available VRF |
124 | | */ |
125 | 6 | if (name) |
126 | 6 | vrf = vrf_lookup_by_name(name); |
127 | 6 | if (vrf && vrf_id != VRF_UNKNOWN |
128 | 6 | && vrf->vrf_id != VRF_UNKNOWN |
129 | 6 | && vrf->vrf_id != vrf_id) { |
130 | 0 | zlog_debug("VRF_GET: avoid %s creation(%u), same name exists (%u)", |
131 | 0 | name, vrf_id, vrf->vrf_id); |
132 | 0 | return NULL; |
133 | 0 | } |
134 | | /* Try to find VRF both by ID and name */ |
135 | 6 | if (!vrf && vrf_id != VRF_UNKNOWN) |
136 | 2 | vrf = vrf_lookup_by_id(vrf_id); |
137 | | |
138 | 6 | if (vrf == NULL) { |
139 | 2 | vrf = XCALLOC(MTYPE_VRF, sizeof(struct vrf)); |
140 | 2 | vrf->vrf_id = VRF_UNKNOWN; |
141 | 2 | QOBJ_REG(vrf, vrf); |
142 | 2 | new = 1; |
143 | | |
144 | 2 | if (debug_vrf) |
145 | 0 | zlog_debug("VRF(%u) %s is created.", vrf_id, |
146 | 2 | (name) ? name : "(NULL)"); |
147 | 2 | } |
148 | | |
149 | | /* Set identifier */ |
150 | 6 | if (vrf_id != VRF_UNKNOWN && vrf->vrf_id == VRF_UNKNOWN) { |
151 | 2 | vrf->vrf_id = vrf_id; |
152 | 2 | RB_INSERT(vrf_id_head, &vrfs_by_id, vrf); |
153 | 2 | } |
154 | | |
155 | | /* Set name */ |
156 | 6 | if (name && vrf->name[0] != '\0' && strcmp(name, vrf->name)) { |
157 | | /* update the vrf name */ |
158 | 0 | RB_REMOVE(vrf_name_head, &vrfs_by_name, vrf); |
159 | 0 | strlcpy(vrf->data.l.netns_name, |
160 | 0 | name, NS_NAMSIZ); |
161 | 0 | strlcpy(vrf->name, name, sizeof(vrf->name)); |
162 | 0 | RB_INSERT(vrf_name_head, &vrfs_by_name, vrf); |
163 | 6 | } else if (name && vrf->name[0] == '\0') { |
164 | 2 | strlcpy(vrf->name, name, sizeof(vrf->name)); |
165 | 2 | RB_INSERT(vrf_name_head, &vrfs_by_name, vrf); |
166 | 2 | } |
167 | 6 | if (new &&vrf_master.vrf_new_hook) |
168 | 2 | (*vrf_master.vrf_new_hook)(vrf); |
169 | | |
170 | 6 | return vrf; |
171 | 6 | } |
172 | | |
173 | | /* Update a VRF. If not found, create one. |
174 | | * Arg: |
175 | | * name - The name of the vrf. |
176 | | * vrf_id - The vrf_id of the vrf. |
177 | | * Description: This function first finds the vrf using its name. If the vrf is |
178 | | * found and the vrf-id of the existing vrf does not match the new vrf id, it |
179 | | * will disable the existing vrf and update it with new vrf-id. If the vrf is |
180 | | * not found, it will create the vrf with given name and the new vrf id. |
181 | | */ |
182 | | struct vrf *vrf_update(vrf_id_t new_vrf_id, const char *name) |
183 | 0 | { |
184 | 0 | struct vrf *vrf = NULL; |
185 | | |
186 | | /*Treat VRF add for existing vrf as update |
187 | | * Update VRF ID and also update in VRF ID table |
188 | | */ |
189 | 0 | if (name) |
190 | 0 | vrf = vrf_lookup_by_name(name); |
191 | 0 | if (vrf && new_vrf_id != VRF_UNKNOWN && vrf->vrf_id != VRF_UNKNOWN |
192 | 0 | && vrf->vrf_id != new_vrf_id) { |
193 | 0 | if (debug_vrf) { |
194 | 0 | zlog_debug( |
195 | 0 | "Vrf Update event: %s old id: %u, new id: %u", |
196 | 0 | name, vrf->vrf_id, new_vrf_id); |
197 | 0 | } |
198 | | |
199 | | /*Disable the vrf to simulate implicit delete |
200 | | * so that all stale routes are deleted |
201 | | * This vrf will be enabled down the line |
202 | | */ |
203 | 0 | vrf_disable(vrf); |
204 | | |
205 | |
|
206 | 0 | RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); |
207 | 0 | vrf->vrf_id = new_vrf_id; |
208 | 0 | RB_INSERT(vrf_id_head, &vrfs_by_id, vrf); |
209 | |
|
210 | 0 | } else { |
211 | | |
212 | | /* |
213 | | * vrf_get is implied creation if it does not exist |
214 | | */ |
215 | 0 | vrf = vrf_get(new_vrf_id, name); |
216 | 0 | } |
217 | 0 | return vrf; |
218 | 0 | } |
219 | | |
220 | | /* Delete a VRF. This is called when the underlying VRF goes away, a |
221 | | * pre-configured VRF is deleted or when shutting down (vrf_terminate()). |
222 | | */ |
223 | | void vrf_delete(struct vrf *vrf) |
224 | 0 | { |
225 | 0 | if (debug_vrf) |
226 | 0 | zlog_debug("VRF %s(%u) is to be deleted.", vrf->name, |
227 | 0 | vrf->vrf_id); |
228 | |
|
229 | 0 | if (vrf_is_enabled(vrf)) |
230 | 0 | vrf_disable(vrf); |
231 | |
|
232 | 0 | if (vrf->vrf_id != VRF_UNKNOWN) { |
233 | 0 | RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); |
234 | 0 | vrf->vrf_id = VRF_UNKNOWN; |
235 | 0 | } |
236 | | |
237 | | /* If the VRF is user configured, it'll stick around, just remove |
238 | | * the ID mapping. Interfaces assigned to this VRF should've been |
239 | | * removed already as part of the VRF going down. |
240 | | */ |
241 | 0 | if (vrf_is_user_cfged(vrf)) |
242 | 0 | return; |
243 | | |
244 | | /* Do not delete the VRF if it has interfaces configured in it. */ |
245 | 0 | if (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) |
246 | 0 | return; |
247 | | |
248 | 0 | if (vrf_master.vrf_delete_hook) |
249 | 0 | (*vrf_master.vrf_delete_hook)(vrf); |
250 | |
|
251 | 0 | QOBJ_UNREG(vrf); |
252 | |
|
253 | 0 | if (vrf->name[0] != '\0') |
254 | 0 | RB_REMOVE(vrf_name_head, &vrfs_by_name, vrf); |
255 | |
|
256 | 0 | XFREE(MTYPE_VRF, vrf); |
257 | 0 | } |
258 | | |
259 | | /* Look up a VRF by identifier. */ |
260 | | struct vrf *vrf_lookup_by_id(vrf_id_t vrf_id) |
261 | 1.23k | { |
262 | 1.23k | struct vrf vrf; |
263 | 1.23k | vrf.vrf_id = vrf_id; |
264 | 1.23k | return (RB_FIND(vrf_id_head, &vrfs_by_id, &vrf)); |
265 | 1.23k | } |
266 | | |
267 | | /* |
268 | | * Enable a VRF - that is, let the VRF be ready to use. |
269 | | * The VRF_ENABLE_HOOK callback will be called to inform |
270 | | * that they can allocate resources in this VRF. |
271 | | * |
272 | | * RETURN: 1 - enabled successfully; otherwise, 0. |
273 | | */ |
274 | | int vrf_enable(struct vrf *vrf) |
275 | 2 | { |
276 | 2 | if (vrf_is_enabled(vrf)) |
277 | 0 | return 1; |
278 | | |
279 | 2 | if (debug_vrf) |
280 | 0 | zlog_debug("VRF %s(%u) is enabled.", vrf->name, vrf->vrf_id); |
281 | | |
282 | 2 | SET_FLAG(vrf->status, VRF_ACTIVE); |
283 | | |
284 | 2 | if (vrf_master.vrf_enable_hook) |
285 | 2 | (*vrf_master.vrf_enable_hook)(vrf); |
286 | | |
287 | | /* |
288 | | * If we have any nexthop group entries that |
289 | | * are awaiting vrf initialization then |
290 | | * let's let people know about it |
291 | | */ |
292 | 2 | nexthop_group_enable_vrf(vrf); |
293 | | |
294 | 2 | return 1; |
295 | 2 | } |
296 | | |
297 | | /* |
298 | | * Disable a VRF - that is, let the VRF be unusable. |
299 | | * The VRF_DELETE_HOOK callback will be called to inform |
300 | | * that they must release the resources in the VRF. |
301 | | */ |
302 | | void vrf_disable(struct vrf *vrf) |
303 | 0 | { |
304 | 0 | if (!vrf_is_enabled(vrf)) |
305 | 0 | return; |
306 | | |
307 | 0 | UNSET_FLAG(vrf->status, VRF_ACTIVE); |
308 | |
|
309 | 0 | if (debug_vrf) |
310 | 0 | zlog_debug("VRF %s(%u) is to be disabled.", vrf->name, |
311 | 0 | vrf->vrf_id); |
312 | | |
313 | | /* Till now, nothing to be done for the default VRF. */ |
314 | | // Pending: see why this statement. |
315 | | |
316 | | |
317 | | /* |
318 | | * When the vrf is disabled let's |
319 | | * handle all nexthop-groups associated |
320 | | * with this vrf |
321 | | */ |
322 | 0 | nexthop_group_disable_vrf(vrf); |
323 | |
|
324 | 0 | if (vrf_master.vrf_disable_hook) |
325 | 0 | (*vrf_master.vrf_disable_hook)(vrf); |
326 | 0 | } |
327 | | |
328 | | const char *vrf_id_to_name(vrf_id_t vrf_id) |
329 | 0 | { |
330 | 0 | struct vrf *vrf; |
331 | |
|
332 | 0 | if (vrf_id == VRF_DEFAULT) |
333 | 0 | return VRF_DEFAULT_NAME; |
334 | | |
335 | 0 | vrf = vrf_lookup_by_id(vrf_id); |
336 | 0 | return VRF_LOGNAME(vrf); |
337 | 0 | } |
338 | | |
339 | | /* Look up the data pointer of the specified VRF. */ |
340 | | void *vrf_info_lookup(vrf_id_t vrf_id) |
341 | 0 | { |
342 | 0 | struct vrf *vrf = vrf_lookup_by_id(vrf_id); |
343 | 0 | return vrf ? vrf->info : NULL; |
344 | 0 | } |
345 | | |
346 | | /* |
347 | | * VRF hash for storing set or not. |
348 | | */ |
349 | | struct vrf_bit_set { |
350 | | vrf_id_t vrf_id; |
351 | | bool set; |
352 | | }; |
353 | | |
354 | | static unsigned int vrf_hash_bitmap_key(const void *data) |
355 | 0 | { |
356 | 0 | const struct vrf_bit_set *bit = data; |
357 | |
|
358 | 0 | return bit->vrf_id; |
359 | 0 | } |
360 | | |
361 | | static bool vrf_hash_bitmap_cmp(const void *a, const void *b) |
362 | 0 | { |
363 | 0 | const struct vrf_bit_set *bit1 = a; |
364 | 0 | const struct vrf_bit_set *bit2 = b; |
365 | |
|
366 | 0 | return bit1->vrf_id == bit2->vrf_id; |
367 | 0 | } |
368 | | |
369 | | static void *vrf_hash_bitmap_alloc(void *data) |
370 | 0 | { |
371 | 0 | struct vrf_bit_set *copy = data; |
372 | 0 | struct vrf_bit_set *bit; |
373 | |
|
374 | 0 | bit = XMALLOC(MTYPE_VRF_BITMAP, sizeof(*bit)); |
375 | 0 | bit->vrf_id = copy->vrf_id; |
376 | |
|
377 | 0 | return bit; |
378 | 0 | } |
379 | | |
380 | | static void vrf_hash_bitmap_free(void *data) |
381 | 0 | { |
382 | 0 | struct vrf_bit_set *bit = data; |
383 | |
|
384 | 0 | XFREE(MTYPE_VRF_BITMAP, bit); |
385 | 0 | } |
386 | | |
387 | | vrf_bitmap_t vrf_bitmap_init(void) |
388 | 192 | { |
389 | 192 | return hash_create_size(32, vrf_hash_bitmap_key, vrf_hash_bitmap_cmp, |
390 | 192 | "VRF BIT HASH"); |
391 | 192 | } |
392 | | |
393 | | void vrf_bitmap_free(vrf_bitmap_t bmap) |
394 | 0 | { |
395 | 0 | struct hash *vrf_hash = bmap; |
396 | |
|
397 | 0 | hash_clean_and_free(&vrf_hash, vrf_hash_bitmap_free); |
398 | 0 | } |
399 | | |
400 | | void vrf_bitmap_set(vrf_bitmap_t bmap, vrf_id_t vrf_id) |
401 | 0 | { |
402 | 0 | struct vrf_bit_set lookup = { .vrf_id = vrf_id }; |
403 | 0 | struct hash *vrf_hash = bmap; |
404 | 0 | struct vrf_bit_set *bit; |
405 | |
|
406 | 0 | if (vrf_hash == NULL || vrf_id == VRF_UNKNOWN) |
407 | 0 | return; |
408 | | |
409 | 0 | bit = hash_get(vrf_hash, &lookup, vrf_hash_bitmap_alloc); |
410 | 0 | bit->set = true; |
411 | 0 | } |
412 | | |
413 | | void vrf_bitmap_unset(vrf_bitmap_t bmap, vrf_id_t vrf_id) |
414 | 0 | { |
415 | 0 | struct vrf_bit_set lookup = { .vrf_id = vrf_id }; |
416 | 0 | struct hash *vrf_hash = bmap; |
417 | 0 | struct vrf_bit_set *bit; |
418 | |
|
419 | 0 | if (vrf_hash == NULL || vrf_id == VRF_UNKNOWN) |
420 | 0 | return; |
421 | | |
422 | 0 | bit = hash_get(vrf_hash, &lookup, vrf_hash_bitmap_alloc); |
423 | 0 | bit->set = false; |
424 | 0 | } |
425 | | |
426 | | int vrf_bitmap_check(vrf_bitmap_t bmap, vrf_id_t vrf_id) |
427 | 3.27k | { |
428 | 3.27k | struct vrf_bit_set lookup = { .vrf_id = vrf_id }; |
429 | 3.27k | struct hash *vrf_hash = bmap; |
430 | 3.27k | struct vrf_bit_set *bit; |
431 | | |
432 | 3.27k | if (vrf_hash == NULL || vrf_id == VRF_UNKNOWN) |
433 | 0 | return 0; |
434 | | |
435 | 3.27k | bit = hash_lookup(vrf_hash, &lookup); |
436 | 3.27k | if (bit) |
437 | 0 | return bit->set; |
438 | | |
439 | 3.27k | return 0; |
440 | 3.27k | } |
441 | | |
442 | | static void vrf_autocomplete(vector comps, struct cmd_token *token) |
443 | 0 | { |
444 | 0 | struct vrf *vrf = NULL; |
445 | |
|
446 | 0 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) |
447 | 0 | vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name)); |
448 | 0 | } |
449 | | |
450 | | static const struct cmd_variable_handler vrf_var_handlers[] = { |
451 | | { |
452 | | .varname = "vrf", |
453 | | .completions = vrf_autocomplete, |
454 | | }, |
455 | | { |
456 | | .varname = "vrf_name", |
457 | | .completions = vrf_autocomplete, |
458 | | }, |
459 | | { |
460 | | .varname = "nexthop_vrf", |
461 | | .completions = vrf_autocomplete, |
462 | | }, |
463 | | {.completions = NULL}, |
464 | | }; |
465 | | |
466 | | /* Initialize VRF module. */ |
467 | | void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), |
468 | | int (*disable)(struct vrf *), int (*destroy)(struct vrf *)) |
469 | 2 | { |
470 | 2 | struct vrf *default_vrf; |
471 | | |
472 | | /* initialise NS, in case VRF backend if NETNS */ |
473 | 2 | ns_init(); |
474 | 2 | if (debug_vrf) |
475 | 0 | zlog_debug("%s: Initializing VRF subsystem", __func__); |
476 | | |
477 | 2 | vrf_master.vrf_new_hook = create; |
478 | 2 | vrf_master.vrf_enable_hook = enable; |
479 | 2 | vrf_master.vrf_disable_hook = disable; |
480 | 2 | vrf_master.vrf_delete_hook = destroy; |
481 | | |
482 | | /* The default VRF always exists. */ |
483 | 2 | default_vrf = vrf_get(VRF_DEFAULT, VRF_DEFAULT_NAME); |
484 | 2 | if (!default_vrf) { |
485 | 0 | flog_err(EC_LIB_VRF_START, |
486 | 0 | "vrf_init: failed to create the default VRF!"); |
487 | 0 | exit(1); |
488 | 0 | } |
489 | 2 | if (vrf_is_backend_netns()) { |
490 | 0 | struct ns *ns; |
491 | |
|
492 | 0 | strlcpy(default_vrf->data.l.netns_name, |
493 | 0 | VRF_DEFAULT_NAME, NS_NAMSIZ); |
494 | 0 | ns = ns_lookup(NS_DEFAULT); |
495 | 0 | ns->vrf_ctxt = default_vrf; |
496 | 0 | default_vrf->ns_ctxt = ns; |
497 | 0 | } |
498 | | |
499 | | /* Enable the default VRF. */ |
500 | 2 | if (!vrf_enable(default_vrf)) { |
501 | 0 | flog_err(EC_LIB_VRF_START, |
502 | 0 | "vrf_init: failed to enable the default VRF!"); |
503 | 0 | exit(1); |
504 | 0 | } |
505 | | |
506 | 2 | cmd_variable_handler_register(vrf_var_handlers); |
507 | 2 | } |
508 | | |
509 | | static void vrf_terminate_single(struct vrf *vrf) |
510 | 0 | { |
511 | | /* Clear configured flag and invoke delete. */ |
512 | 0 | vrf_disable(vrf); |
513 | 0 | UNSET_FLAG(vrf->status, VRF_CONFIGURED); |
514 | 0 | if_terminate(vrf); |
515 | 0 | vrf_delete(vrf); |
516 | 0 | } |
517 | | |
518 | | /* Terminate VRF module. */ |
519 | | void vrf_terminate(void) |
520 | 0 | { |
521 | 0 | struct vrf *vrf, *tmp; |
522 | |
|
523 | 0 | if (debug_vrf) |
524 | 0 | zlog_debug("%s: Shutting down vrf subsystem", __func__); |
525 | |
|
526 | 0 | RB_FOREACH_SAFE (vrf, vrf_id_head, &vrfs_by_id, tmp) { |
527 | 0 | if (vrf->vrf_id == VRF_DEFAULT) |
528 | 0 | continue; |
529 | | |
530 | 0 | vrf_terminate_single(vrf); |
531 | 0 | } |
532 | |
|
533 | 0 | RB_FOREACH_SAFE (vrf, vrf_name_head, &vrfs_by_name, tmp) { |
534 | 0 | if (vrf->vrf_id == VRF_DEFAULT) |
535 | 0 | continue; |
536 | | |
537 | 0 | vrf_terminate_single(vrf); |
538 | 0 | } |
539 | | |
540 | | /* Finally terminate default VRF */ |
541 | 0 | vrf = vrf_lookup_by_id(VRF_DEFAULT); |
542 | 0 | if (vrf) |
543 | 0 | vrf_terminate_single(vrf); |
544 | 0 | } |
545 | | |
546 | | int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id, |
547 | | const char *interfacename) |
548 | 0 | { |
549 | 0 | int ret, save_errno, ret2; |
550 | |
|
551 | 0 | ret = vrf_switch_to_netns(vrf_id); |
552 | 0 | if (ret < 0) |
553 | 0 | flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)", |
554 | 0 | __func__, vrf_id, safe_strerror(errno)); |
555 | |
|
556 | 0 | ret = socket(domain, type, protocol); |
557 | 0 | save_errno = errno; |
558 | 0 | ret2 = vrf_switchback_to_initial(); |
559 | 0 | if (ret2 < 0) |
560 | 0 | flog_err_sys(EC_LIB_SOCKET, |
561 | 0 | "%s: Can't switchback from VRF %u (%s)", __func__, |
562 | 0 | vrf_id, safe_strerror(errno)); |
563 | 0 | errno = save_errno; |
564 | 0 | if (ret <= 0) |
565 | 0 | return ret; |
566 | 0 | ret2 = vrf_bind(vrf_id, ret, interfacename); |
567 | 0 | if (ret2 < 0) { |
568 | 0 | close(ret); |
569 | 0 | ret = ret2; |
570 | 0 | } |
571 | 0 | return ret; |
572 | 0 | } |
573 | | |
574 | | int vrf_is_backend_netns(void) |
575 | 2 | { |
576 | 2 | return (vrf_backend == VRF_BACKEND_NETNS); |
577 | 2 | } |
578 | | |
579 | | int vrf_get_backend(void) |
580 | 3 | { |
581 | 3 | if (!vrf_backend_configured) |
582 | 1 | return VRF_BACKEND_UNKNOWN; |
583 | 2 | return vrf_backend; |
584 | 3 | } |
585 | | |
586 | | int vrf_configure_backend(enum vrf_backend_type backend) |
587 | 1 | { |
588 | | /* Work around issue in old gcc */ |
589 | 1 | switch (backend) { |
590 | 0 | case VRF_BACKEND_UNKNOWN: |
591 | 0 | case VRF_BACKEND_NETNS: |
592 | 1 | case VRF_BACKEND_VRF_LITE: |
593 | 1 | break; |
594 | 0 | case VRF_BACKEND_MAX: |
595 | 0 | return -1; |
596 | 1 | } |
597 | | |
598 | 1 | vrf_backend = backend; |
599 | 1 | vrf_backend_configured = 1; |
600 | | |
601 | 1 | return 0; |
602 | 1 | } |
603 | | |
604 | | /* vrf CLI commands */ |
605 | | DEFUN_NOSH(vrf_exit, |
606 | | vrf_exit_cmd, |
607 | | "exit-vrf", |
608 | | "Exit current mode and down to previous mode\n") |
609 | 0 | { |
610 | 0 | cmd_exit(vty); |
611 | 0 | return CMD_SUCCESS; |
612 | 0 | } |
613 | | |
614 | | DEFUN_YANG_NOSH (vrf, |
615 | | vrf_cmd, |
616 | | "vrf NAME", |
617 | | "Select a VRF to configure\n" |
618 | | "VRF's name\n") |
619 | 0 | { |
620 | 0 | int idx_name = 1; |
621 | 0 | const char *vrfname = argv[idx_name]->arg; |
622 | 0 | char xpath_list[XPATH_MAXLEN]; |
623 | 0 | struct vrf *vrf; |
624 | 0 | int ret; |
625 | |
|
626 | 0 | if (strlen(vrfname) > VRF_NAMSIZ) { |
627 | 0 | vty_out(vty, |
628 | 0 | "%% VRF name %s invalid: length exceeds %d bytes\n", |
629 | 0 | vrfname, VRF_NAMSIZ); |
630 | 0 | return CMD_WARNING_CONFIG_FAILED; |
631 | 0 | } |
632 | | |
633 | 0 | snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH, vrfname); |
634 | |
|
635 | 0 | nb_cli_enqueue_change(vty, xpath_list, NB_OP_CREATE, NULL); |
636 | 0 | ret = nb_cli_apply_changes_clear_pending(vty, "%s", xpath_list); |
637 | 0 | if (ret == CMD_SUCCESS) { |
638 | 0 | VTY_PUSH_XPATH(VRF_NODE, xpath_list); |
639 | 0 | vrf = vrf_lookup_by_name(vrfname); |
640 | 0 | if (vrf) |
641 | 0 | VTY_PUSH_CONTEXT(VRF_NODE, vrf); |
642 | 0 | } |
643 | | |
644 | 0 | return ret; |
645 | 0 | } |
646 | | |
647 | | DEFUN_YANG (no_vrf, |
648 | | no_vrf_cmd, |
649 | | "no vrf NAME", |
650 | | NO_STR |
651 | | "Delete a pseudo VRF's configuration\n" |
652 | | "VRF's name\n") |
653 | 0 | { |
654 | 0 | const char *vrfname = argv[2]->arg; |
655 | 0 | char xpath_list[XPATH_MAXLEN]; |
656 | |
|
657 | 0 | struct vrf *vrfp; |
658 | |
|
659 | 0 | vrfp = vrf_lookup_by_name(vrfname); |
660 | |
|
661 | 0 | if (vrfp == NULL) |
662 | 0 | return CMD_SUCCESS; |
663 | | |
664 | 0 | if (CHECK_FLAG(vrfp->status, VRF_ACTIVE)) { |
665 | 0 | vty_out(vty, "%% Only inactive VRFs can be deleted\n"); |
666 | 0 | return CMD_WARNING_CONFIG_FAILED; |
667 | 0 | } |
668 | | |
669 | 0 | if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) { |
670 | | /* |
671 | | * Remove the VRF interface config when removing the VRF. |
672 | | */ |
673 | 0 | snprintf(xpath_list, sizeof(xpath_list), |
674 | 0 | "/frr-interface:lib/interface[name='%s']", vrfname); |
675 | 0 | nb_cli_enqueue_change(vty, xpath_list, NB_OP_DESTROY, NULL); |
676 | 0 | } |
677 | |
|
678 | 0 | snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH, vrfname); |
679 | |
|
680 | 0 | nb_cli_enqueue_change(vty, xpath_list, NB_OP_DESTROY, NULL); |
681 | 0 | return nb_cli_apply_changes(vty, NULL); |
682 | 0 | } |
683 | | |
684 | | |
685 | | static struct cmd_node vrf_node = { |
686 | | .name = "vrf", |
687 | | .node = VRF_NODE, |
688 | | .parent_node = CONFIG_NODE, |
689 | | .prompt = "%s(config-vrf)# ", |
690 | | }; |
691 | | |
692 | | /* |
693 | | * Debug CLI for vrf's |
694 | | */ |
695 | | DEFUN (vrf_debug, |
696 | | vrf_debug_cmd, |
697 | | "debug vrf", |
698 | | DEBUG_STR |
699 | | "VRF Debugging\n") |
700 | 0 | { |
701 | 0 | debug_vrf = 1; |
702 | |
|
703 | 0 | return CMD_SUCCESS; |
704 | 0 | } |
705 | | |
706 | | DEFUN (no_vrf_debug, |
707 | | no_vrf_debug_cmd, |
708 | | "no debug vrf", |
709 | | NO_STR |
710 | | DEBUG_STR |
711 | | "VRF Debugging\n") |
712 | 0 | { |
713 | 0 | debug_vrf = 0; |
714 | |
|
715 | 0 | return CMD_SUCCESS; |
716 | 0 | } |
717 | | |
718 | | static int vrf_write_host(struct vty *vty) |
719 | 0 | { |
720 | 0 | if (debug_vrf) |
721 | 0 | vty_out(vty, "debug vrf\n"); |
722 | |
|
723 | 0 | return 1; |
724 | 0 | } |
725 | | |
726 | | static int vrf_write_host(struct vty *vty); |
727 | | static struct cmd_node vrf_debug_node = { |
728 | | .name = "vrf debug", |
729 | | .node = VRF_DEBUG_NODE, |
730 | | .prompt = "", |
731 | | .config_write = vrf_write_host, |
732 | | }; |
733 | | |
734 | | void vrf_install_commands(void) |
735 | 2 | { |
736 | 2 | install_node(&vrf_debug_node); |
737 | | |
738 | 2 | install_element(CONFIG_NODE, &vrf_debug_cmd); |
739 | 2 | install_element(ENABLE_NODE, &vrf_debug_cmd); |
740 | 2 | install_element(CONFIG_NODE, &no_vrf_debug_cmd); |
741 | 2 | install_element(ENABLE_NODE, &no_vrf_debug_cmd); |
742 | 2 | } |
743 | | |
744 | | void vrf_cmd_init(int (*writefunc)(struct vty *vty)) |
745 | 0 | { |
746 | 0 | install_element(CONFIG_NODE, &vrf_cmd); |
747 | 0 | install_element(CONFIG_NODE, &no_vrf_cmd); |
748 | 0 | vrf_node.config_write = writefunc; |
749 | 0 | install_node(&vrf_node); |
750 | 0 | install_default(VRF_NODE); |
751 | 0 | install_element(VRF_NODE, &vrf_exit_cmd); |
752 | 0 | } |
753 | | |
754 | | void vrf_set_default_name(const char *default_name) |
755 | 0 | { |
756 | 0 | snprintf(vrf_default_name, VRF_NAMSIZ, "%s", default_name); |
757 | 0 | } |
758 | | |
759 | | const char *vrf_get_default_name(void) |
760 | 4 | { |
761 | 4 | return vrf_default_name; |
762 | 4 | } |
763 | | |
764 | | int vrf_bind(vrf_id_t vrf_id, int fd, const char *ifname) |
765 | 0 | { |
766 | 0 | int ret = 0; |
767 | 0 | struct interface *ifp; |
768 | 0 | struct vrf *vrf; |
769 | |
|
770 | 0 | if (fd < 0) |
771 | 0 | return -1; |
772 | | |
773 | 0 | if (vrf_id == VRF_UNKNOWN) |
774 | 0 | return -1; |
775 | | |
776 | | /* can't bind to a VRF that doesn't exist */ |
777 | 0 | vrf = vrf_lookup_by_id(vrf_id); |
778 | 0 | if (!vrf_is_enabled(vrf)) |
779 | 0 | return -1; |
780 | | |
781 | 0 | if (ifname && strcmp(ifname, vrf->name)) { |
782 | | /* binding to a regular interface */ |
783 | | |
784 | | /* can't bind to an interface that doesn't exist */ |
785 | 0 | ifp = if_lookup_by_name(ifname, vrf_id); |
786 | 0 | if (!ifp) |
787 | 0 | return -1; |
788 | 0 | } else { |
789 | | /* binding to a VRF device */ |
790 | | |
791 | | /* nothing to do for netns */ |
792 | 0 | if (vrf_is_backend_netns()) |
793 | 0 | return 0; |
794 | | |
795 | | /* nothing to do for default vrf */ |
796 | 0 | if (vrf_id == VRF_DEFAULT) |
797 | 0 | return 0; |
798 | | |
799 | 0 | ifname = vrf->name; |
800 | 0 | } |
801 | | |
802 | 0 | #ifdef SO_BINDTODEVICE |
803 | 0 | ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, |
804 | 0 | strlen(ifname) + 1); |
805 | 0 | if (ret < 0) |
806 | 0 | zlog_err("bind to interface %s failed, errno=%d", ifname, |
807 | 0 | errno); |
808 | 0 | #endif /* SO_BINDTODEVICE */ |
809 | 0 | return ret; |
810 | 0 | } |
811 | | int vrf_getaddrinfo(const char *node, const char *service, |
812 | | const struct addrinfo *hints, struct addrinfo **res, |
813 | | vrf_id_t vrf_id) |
814 | 0 | { |
815 | 0 | int ret, ret2, save_errno; |
816 | |
|
817 | 0 | ret = vrf_switch_to_netns(vrf_id); |
818 | 0 | if (ret < 0) |
819 | 0 | flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)", |
820 | 0 | __func__, vrf_id, safe_strerror(errno)); |
821 | 0 | ret = getaddrinfo(node, service, hints, res); |
822 | 0 | save_errno = errno; |
823 | 0 | ret2 = vrf_switchback_to_initial(); |
824 | 0 | if (ret2 < 0) |
825 | 0 | flog_err_sys(EC_LIB_SOCKET, |
826 | 0 | "%s: Can't switchback from VRF %u (%s)", __func__, |
827 | 0 | vrf_id, safe_strerror(errno)); |
828 | 0 | errno = save_errno; |
829 | 0 | return ret; |
830 | 0 | } |
831 | | |
832 | | int vrf_ioctl(vrf_id_t vrf_id, int d, unsigned long request, char *params) |
833 | 0 | { |
834 | 0 | int ret, saved_errno, rc; |
835 | |
|
836 | 0 | ret = vrf_switch_to_netns(vrf_id); |
837 | 0 | if (ret < 0) { |
838 | 0 | flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)", |
839 | 0 | __func__, vrf_id, safe_strerror(errno)); |
840 | 0 | return 0; |
841 | 0 | } |
842 | 0 | rc = ioctl(d, request, params); |
843 | 0 | saved_errno = errno; |
844 | 0 | ret = vrf_switchback_to_initial(); |
845 | 0 | if (ret < 0) |
846 | 0 | flog_err_sys(EC_LIB_SOCKET, |
847 | 0 | "%s: Can't switchback from VRF %u (%s)", __func__, |
848 | 0 | vrf_id, safe_strerror(errno)); |
849 | 0 | errno = saved_errno; |
850 | 0 | return rc; |
851 | 0 | } |
852 | | |
853 | | int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id, |
854 | | const char *interfacename) |
855 | 0 | { |
856 | 0 | int ret, save_errno, ret2; |
857 | |
|
858 | 0 | ret = vrf_switch_to_netns(vrf_id); |
859 | 0 | if (ret < 0) |
860 | 0 | flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)", |
861 | 0 | __func__, vrf_id, safe_strerror(errno)); |
862 | 0 | ret = sockunion_socket(su); |
863 | 0 | save_errno = errno; |
864 | 0 | ret2 = vrf_switchback_to_initial(); |
865 | 0 | if (ret2 < 0) |
866 | 0 | flog_err_sys(EC_LIB_SOCKET, |
867 | 0 | "%s: Can't switchback from VRF %u (%s)", __func__, |
868 | 0 | vrf_id, safe_strerror(errno)); |
869 | 0 | errno = save_errno; |
870 | |
|
871 | 0 | if (ret <= 0) |
872 | 0 | return ret; |
873 | 0 | ret2 = vrf_bind(vrf_id, ret, interfacename); |
874 | 0 | if (ret2 < 0) { |
875 | 0 | close(ret); |
876 | 0 | ret = ret2; |
877 | 0 | } |
878 | 0 | return ret; |
879 | 0 | } |
880 | | |
881 | | /* ------- Northbound callbacks ------- */ |
882 | | |
883 | | /* |
884 | | * XPath: /frr-vrf:lib/vrf |
885 | | */ |
886 | | static int lib_vrf_create(struct nb_cb_create_args *args) |
887 | 0 | { |
888 | 0 | const char *vrfname; |
889 | 0 | struct vrf *vrfp; |
890 | |
|
891 | 0 | vrfname = yang_dnode_get_string(args->dnode, "./name"); |
892 | |
|
893 | 0 | if (args->event != NB_EV_APPLY) |
894 | 0 | return NB_OK; |
895 | | |
896 | 0 | vrfp = vrf_get(VRF_UNKNOWN, vrfname); |
897 | |
|
898 | 0 | SET_FLAG(vrfp->status, VRF_CONFIGURED); |
899 | 0 | nb_running_set_entry(args->dnode, vrfp); |
900 | |
|
901 | 0 | return NB_OK; |
902 | 0 | } |
903 | | |
904 | | static int lib_vrf_destroy(struct nb_cb_destroy_args *args) |
905 | 0 | { |
906 | 0 | struct vrf *vrfp; |
907 | |
|
908 | 0 | switch (args->event) { |
909 | 0 | case NB_EV_VALIDATE: |
910 | 0 | vrfp = nb_running_get_entry(args->dnode, NULL, true); |
911 | 0 | if (CHECK_FLAG(vrfp->status, VRF_ACTIVE)) { |
912 | 0 | snprintf(args->errmsg, args->errmsg_len, |
913 | 0 | "Only inactive VRFs can be deleted"); |
914 | 0 | return NB_ERR_VALIDATION; |
915 | 0 | } |
916 | 0 | break; |
917 | 0 | case NB_EV_PREPARE: |
918 | 0 | case NB_EV_ABORT: |
919 | 0 | break; |
920 | 0 | case NB_EV_APPLY: |
921 | 0 | vrfp = nb_running_unset_entry(args->dnode); |
922 | | |
923 | | /* Clear configured flag and invoke delete. */ |
924 | 0 | UNSET_FLAG(vrfp->status, VRF_CONFIGURED); |
925 | 0 | vrf_delete(vrfp); |
926 | 0 | break; |
927 | 0 | } |
928 | | |
929 | 0 | return NB_OK; |
930 | 0 | } |
931 | | |
932 | | static const void *lib_vrf_get_next(struct nb_cb_get_next_args *args) |
933 | 0 | { |
934 | 0 | struct vrf *vrfp = (struct vrf *)args->list_entry; |
935 | |
|
936 | 0 | if (args->list_entry == NULL) { |
937 | 0 | vrfp = RB_MIN(vrf_name_head, &vrfs_by_name); |
938 | 0 | } else { |
939 | 0 | vrfp = RB_NEXT(vrf_name_head, vrfp); |
940 | 0 | } |
941 | |
|
942 | 0 | return vrfp; |
943 | 0 | } |
944 | | |
945 | | static int lib_vrf_get_keys(struct nb_cb_get_keys_args *args) |
946 | 0 | { |
947 | 0 | struct vrf *vrfp = (struct vrf *)args->list_entry; |
948 | |
|
949 | 0 | args->keys->num = 1; |
950 | 0 | strlcpy(args->keys->key[0], vrfp->name, sizeof(args->keys->key[0])); |
951 | |
|
952 | 0 | return NB_OK; |
953 | 0 | } |
954 | | |
955 | | static const void *lib_vrf_lookup_entry(struct nb_cb_lookup_entry_args *args) |
956 | 0 | { |
957 | 0 | const char *vrfname = args->keys->key[0]; |
958 | |
|
959 | 0 | struct vrf *vrf = vrf_lookup_by_name(vrfname); |
960 | |
|
961 | 0 | return vrf; |
962 | 0 | } |
963 | | |
964 | | /* |
965 | | * XPath: /frr-vrf:lib/vrf/id |
966 | | */ |
967 | | static struct yang_data * |
968 | | lib_vrf_state_id_get_elem(struct nb_cb_get_elem_args *args) |
969 | 0 | { |
970 | 0 | struct vrf *vrfp = (struct vrf *)args->list_entry; |
971 | |
|
972 | 0 | return yang_data_new_uint32(args->xpath, vrfp->vrf_id); |
973 | 0 | } |
974 | | |
975 | | /* |
976 | | * XPath: /frr-vrf:lib/vrf/active |
977 | | */ |
978 | | static struct yang_data * |
979 | | lib_vrf_state_active_get_elem(struct nb_cb_get_elem_args *args) |
980 | 0 | { |
981 | 0 | struct vrf *vrfp = (struct vrf *)args->list_entry; |
982 | |
|
983 | 0 | if (vrfp->status == VRF_ACTIVE) |
984 | 0 | return yang_data_new_bool(args->xpath, true); |
985 | | |
986 | 0 | return NULL; |
987 | 0 | } |
988 | | |
989 | | /* clang-format off */ |
990 | | const struct frr_yang_module_info frr_vrf_info = { |
991 | | .name = "frr-vrf", |
992 | | .nodes = { |
993 | | { |
994 | | .xpath = "/frr-vrf:lib/vrf", |
995 | | .cbs = { |
996 | | .create = lib_vrf_create, |
997 | | .destroy = lib_vrf_destroy, |
998 | | .get_next = lib_vrf_get_next, |
999 | | .get_keys = lib_vrf_get_keys, |
1000 | | .lookup_entry = lib_vrf_lookup_entry, |
1001 | | }, |
1002 | | .priority = NB_DFLT_PRIORITY - 2, |
1003 | | }, |
1004 | | { |
1005 | | .xpath = "/frr-vrf:lib/vrf/state/id", |
1006 | | .cbs = { |
1007 | | .get_elem = lib_vrf_state_id_get_elem, |
1008 | | } |
1009 | | }, |
1010 | | { |
1011 | | .xpath = "/frr-vrf:lib/vrf/state/active", |
1012 | | .cbs = { |
1013 | | .get_elem = lib_vrf_state_active_get_elem, |
1014 | | } |
1015 | | }, |
1016 | | { |
1017 | | .xpath = NULL, |
1018 | | }, |
1019 | | } |
1020 | | }; |
1021 | | |