/src/frr/zebra/zebra_ns.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* zebra NS Routines |
3 | | * Copyright (C) 2016 Cumulus Networks, Inc. |
4 | | * Donald Sharp |
5 | | * Copyright (C) 2017/2018 6WIND |
6 | | */ |
7 | | #include "zebra.h" |
8 | | |
9 | | #include "lib/ns.h" |
10 | | #include "lib/vrf.h" |
11 | | #include "lib/prefix.h" |
12 | | #include "lib/memory.h" |
13 | | |
14 | | #include "zebra_ns.h" |
15 | | #include "zebra_vrf.h" |
16 | | #include "rt.h" |
17 | | #include "zebra_vxlan.h" |
18 | | #include "debug.h" |
19 | | #include "zebra_netns_notify.h" |
20 | | #include "zebra_netns_id.h" |
21 | | #include "zebra_pbr.h" |
22 | | #include "zebra_tc.h" |
23 | | #include "rib.h" |
24 | | #include "table_manager.h" |
25 | | #include "zebra_errors.h" |
26 | | |
27 | | extern struct zebra_privs_t zserv_privs; |
28 | | |
29 | | DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_NS, "Zebra Name Space"); |
30 | | |
31 | | static struct zebra_ns *dzns; |
32 | | |
33 | | static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete); |
34 | | |
35 | | struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id) |
36 | 0 | { |
37 | 0 | if (ns_id == NS_DEFAULT) |
38 | 0 | return dzns; |
39 | 0 | struct zebra_ns *info = (struct zebra_ns *)ns_info_lookup(ns_id); |
40 | |
|
41 | 0 | return (info == NULL) ? dzns : info; |
42 | 0 | } |
43 | | |
44 | | static struct zebra_ns *zebra_ns_alloc(void) |
45 | 0 | { |
46 | 0 | return XCALLOC(MTYPE_ZEBRA_NS, sizeof(struct zebra_ns)); |
47 | 0 | } |
48 | | |
49 | | static int zebra_ns_new(struct ns *ns) |
50 | 0 | { |
51 | 0 | struct zebra_ns *zns; |
52 | |
|
53 | 0 | if (!ns) |
54 | 0 | return -1; |
55 | | |
56 | 0 | if (IS_ZEBRA_DEBUG_EVENT) |
57 | 0 | zlog_info("ZNS %s with id %u (created)", ns->name, ns->ns_id); |
58 | |
|
59 | 0 | zns = zebra_ns_alloc(); |
60 | 0 | ns->info = zns; |
61 | 0 | zns->ns = ns; |
62 | 0 | zns->ns_id = ns->ns_id; |
63 | | |
64 | | /* Do any needed per-NS data structure allocation. */ |
65 | 0 | zns->if_table = route_table_init(); |
66 | |
|
67 | 0 | return 0; |
68 | 0 | } |
69 | | |
70 | | static int zebra_ns_delete(struct ns *ns) |
71 | 0 | { |
72 | 0 | struct zebra_ns *zns = (struct zebra_ns *)ns->info; |
73 | |
|
74 | 0 | if (IS_ZEBRA_DEBUG_EVENT) |
75 | 0 | zlog_info("ZNS %s with id %u (deleted)", ns->name, ns->ns_id); |
76 | 0 | if (!zns) |
77 | 0 | return 0; |
78 | 0 | XFREE(MTYPE_ZEBRA_NS, ns->info); |
79 | 0 | return 0; |
80 | 0 | } |
81 | | |
82 | | static int zebra_ns_enabled(struct ns *ns) |
83 | 0 | { |
84 | 0 | struct zebra_ns *zns = ns->info; |
85 | |
|
86 | 0 | if (IS_ZEBRA_DEBUG_EVENT) |
87 | 0 | zlog_info("ZNS %s with id %u (enabled)", ns->name, ns->ns_id); |
88 | 0 | if (!zns) |
89 | 0 | return 0; |
90 | 0 | return zebra_ns_enable(ns->ns_id, (void **)&zns); |
91 | 0 | } |
92 | | |
93 | | int zebra_ns_disabled(struct ns *ns) |
94 | 0 | { |
95 | 0 | struct zebra_ns *zns = ns->info; |
96 | |
|
97 | 0 | if (IS_ZEBRA_DEBUG_EVENT) |
98 | 0 | zlog_info("ZNS %s with id %u (disabled)", ns->name, ns->ns_id); |
99 | 0 | if (!zns) |
100 | 0 | return 0; |
101 | 0 | return zebra_ns_disable_internal(zns, true); |
102 | 0 | } |
103 | | |
104 | | /* Do global enable actions - open sockets, read kernel config etc. */ |
105 | | int zebra_ns_enable(ns_id_t ns_id, void **info) |
106 | 0 | { |
107 | 0 | struct zebra_ns *zns = (struct zebra_ns *)(*info); |
108 | |
|
109 | 0 | zns->ns_id = ns_id; |
110 | |
|
111 | 0 | kernel_init(zns); |
112 | 0 | zebra_dplane_ns_enable(zns, true); |
113 | 0 | interface_list(zns); |
114 | 0 | route_read(zns); |
115 | |
|
116 | 0 | vlan_read(zns); |
117 | 0 | kernel_read_pbr_rules(zns); |
118 | 0 | kernel_read_tc_qdisc(zns); |
119 | |
|
120 | 0 | return 0; |
121 | 0 | } |
122 | | |
123 | | /* Common handler for ns disable - this can be called during ns config, |
124 | | * or during zebra shutdown. |
125 | | */ |
126 | | static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete) |
127 | 0 | { |
128 | 0 | if (zns->if_table) |
129 | 0 | route_table_finish(zns->if_table); |
130 | 0 | zns->if_table = NULL; |
131 | |
|
132 | 0 | zebra_dplane_ns_enable(zns, false /*Disable*/); |
133 | |
|
134 | 0 | kernel_terminate(zns, complete); |
135 | |
|
136 | 0 | zns->ns_id = NS_DEFAULT; |
137 | |
|
138 | 0 | return 0; |
139 | 0 | } |
140 | | |
141 | | /* During zebra shutdown, do partial cleanup while the async dataplane |
142 | | * is still running. |
143 | | */ |
144 | | int zebra_ns_early_shutdown(struct ns *ns, |
145 | | void *param_in __attribute__((unused)), |
146 | | void **param_out __attribute__((unused))) |
147 | 0 | { |
148 | 0 | struct zebra_ns *zns = ns->info; |
149 | |
|
150 | 0 | if (zns == NULL) |
151 | 0 | return 0; |
152 | | |
153 | 0 | zebra_ns_disable_internal(zns, false); |
154 | 0 | return NS_WALK_CONTINUE; |
155 | 0 | } |
156 | | |
157 | | /* During zebra shutdown, do final cleanup |
158 | | * after all dataplane work is complete. |
159 | | */ |
160 | | int zebra_ns_final_shutdown(struct ns *ns, |
161 | | void *param_in __attribute__((unused)), |
162 | | void **param_out __attribute__((unused))) |
163 | 0 | { |
164 | 0 | struct zebra_ns *zns = ns->info; |
165 | |
|
166 | 0 | if (zns == NULL) |
167 | 0 | return 0; |
168 | | |
169 | 0 | kernel_terminate(zns, true); |
170 | |
|
171 | 0 | return NS_WALK_CONTINUE; |
172 | 0 | } |
173 | | |
174 | | int zebra_ns_init(void) |
175 | 0 | { |
176 | 0 | struct ns *default_ns; |
177 | 0 | ns_id_t ns_id; |
178 | 0 | ns_id_t ns_id_external; |
179 | 0 | struct ns *ns; |
180 | |
|
181 | 0 | frr_with_privs(&zserv_privs) { |
182 | 0 | ns_id = zebra_ns_id_get_default(); |
183 | 0 | } |
184 | 0 | ns_id_external = ns_map_nsid_with_external(ns_id, true); |
185 | 0 | ns_init_management(ns_id_external, ns_id); |
186 | 0 | ns = ns_get_default(); |
187 | 0 | if (ns) |
188 | 0 | ns->relative_default_ns = ns_id; |
189 | |
|
190 | 0 | default_ns = ns_lookup(NS_DEFAULT); |
191 | 0 | if (!default_ns) { |
192 | 0 | flog_err(EC_ZEBRA_NS_NO_DEFAULT, |
193 | 0 | "%s: failed to find default ns", __func__); |
194 | 0 | exit(EXIT_FAILURE); /* This is non-recoverable */ |
195 | 0 | } |
196 | | |
197 | | /* Do any needed per-NS data structure allocation. */ |
198 | 0 | zebra_ns_new(default_ns); |
199 | 0 | dzns = default_ns->info; |
200 | | |
201 | | /* Register zebra VRF callbacks, create and activate default VRF. */ |
202 | 0 | zebra_vrf_init(); |
203 | | |
204 | | /* Default NS is activated */ |
205 | 0 | zebra_ns_enable(ns_id_external, (void **)&dzns); |
206 | |
|
207 | 0 | if (vrf_is_backend_netns()) { |
208 | 0 | ns_add_hook(NS_NEW_HOOK, zebra_ns_new); |
209 | 0 | ns_add_hook(NS_ENABLE_HOOK, zebra_ns_enabled); |
210 | 0 | ns_add_hook(NS_DISABLE_HOOK, zebra_ns_disabled); |
211 | 0 | ns_add_hook(NS_DELETE_HOOK, zebra_ns_delete); |
212 | 0 | zebra_ns_notify_parse(); |
213 | 0 | zebra_ns_notify_init(); |
214 | 0 | } |
215 | |
|
216 | 0 | return 0; |
217 | 0 | } |
218 | | |
219 | | int zebra_ns_config_write(struct vty *vty, struct ns *ns) |
220 | 0 | { |
221 | 0 | if (ns && ns->name != NULL) |
222 | 0 | vty_out(vty, " netns %s\n", ns->name); |
223 | 0 | return 0; |
224 | 0 | } |