]>
Commit | Line | Data |
---|---|---|
fe18ee2d DS |
1 | /* zebra NS Routines |
2 | * Copyright (C) 2016 Cumulus Networks, Inc. | |
3 | * Donald Sharp | |
b95c1883 | 4 | * Copyright (C) 2017/2018 6WIND |
fe18ee2d DS |
5 | * |
6 | * This file is part of Quagga. | |
7 | * | |
8 | * Quagga is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2, or (at your option) any | |
11 | * later version. | |
12 | * | |
13 | * Quagga is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
896014f4 DL |
18 | * You should have received a copy of the GNU General Public License along |
19 | * with this program; see the file COPYING; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
fe18ee2d DS |
21 | */ |
22 | #include "zebra.h" | |
23 | ||
13460c44 | 24 | #include "lib/ns.h" |
fe18ee2d | 25 | #include "lib/vrf.h" |
736d41ad | 26 | #include "lib/logicalrouter.h" |
fe18ee2d DS |
27 | #include "lib/prefix.h" |
28 | #include "lib/memory.h" | |
29 | ||
30 | #include "rtadv.h" | |
31 | #include "zebra_ns.h" | |
7c551956 | 32 | #include "zebra_vrf.h" |
4a1ab8e4 | 33 | #include "zebra_memory.h" |
05f7f5db | 34 | #include "rt.h" |
b7cfce93 | 35 | #include "zebra_vxlan.h" |
3347430b | 36 | #include "debug.h" |
e27dec3c | 37 | #include "zebra_netns_notify.h" |
ec31f30d | 38 | #include "zebra_netns_id.h" |
43fe6a2a | 39 | #include "zebra_pbr.h" |
47a08aa9 | 40 | #include "rib.h" |
8288a24f | 41 | #include "table_manager.h" |
ec31f30d PG |
42 | |
43 | extern struct zebra_privs_t zserv_privs; | |
4a1ab8e4 | 44 | |
d62a17ae | 45 | DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space") |
fe18ee2d | 46 | |
996c9314 LB |
47 | static inline int zebra_ns_table_entry_compare(const struct zebra_ns_table *e1, |
48 | const struct zebra_ns_table *e2); | |
5335613b DS |
49 | |
50 | RB_GENERATE(zebra_ns_table_head, zebra_ns_table, zebra_ns_table_entry, | |
51 | zebra_ns_table_entry_compare); | |
52 | ||
337960dd | 53 | static struct zebra_ns *dzns; |
fe18ee2d | 54 | |
996c9314 LB |
55 | static inline int zebra_ns_table_entry_compare(const struct zebra_ns_table *e1, |
56 | const struct zebra_ns_table *e2) | |
5335613b DS |
57 | { |
58 | if (e1->tableid == e2->tableid) | |
59 | return (e1->afi - e2->afi); | |
60 | ||
61 | return e1->tableid - e2->tableid; | |
62 | } | |
63 | ||
736d41ad PG |
64 | static int logicalrouter_config_write(struct vty *vty); |
65 | ||
d62a17ae | 66 | struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id) |
fe18ee2d | 67 | { |
ff705b15 PG |
68 | if (ns_id == NS_DEFAULT) |
69 | return dzns; | |
70 | struct zebra_ns *info = (struct zebra_ns *)ns_info_lookup(ns_id); | |
71 | ||
72 | return (info == NULL) ? dzns : info; | |
fe18ee2d DS |
73 | } |
74 | ||
3347430b PG |
75 | static struct zebra_ns *zebra_ns_alloc(void) |
76 | { | |
77 | return XCALLOC(MTYPE_ZEBRA_NS, sizeof(struct zebra_ns)); | |
78 | } | |
79 | ||
80 | static int zebra_ns_new(struct ns *ns) | |
81 | { | |
82 | struct zebra_ns *zns; | |
83 | ||
84 | if (IS_ZEBRA_DEBUG_EVENT) | |
85 | zlog_info("ZNS %s with id %u (created)", ns->name, ns->ns_id); | |
86 | ||
87 | zns = zebra_ns_alloc(); | |
88 | ns->info = zns; | |
89 | zns->ns = ns; | |
ff705b15 PG |
90 | |
91 | /* Do any needed per-NS data structure allocation. */ | |
92 | zns->if_table = route_table_init(); | |
93 | zebra_vxlan_ns_init(zns); | |
94 | ||
3347430b PG |
95 | return 0; |
96 | } | |
97 | ||
98 | static int zebra_ns_delete(struct ns *ns) | |
99 | { | |
996c9314 | 100 | struct zebra_ns *zns = (struct zebra_ns *)ns->info; |
3347430b PG |
101 | |
102 | if (IS_ZEBRA_DEBUG_EVENT) | |
103 | zlog_info("ZNS %s with id %u (deleted)", ns->name, ns->ns_id); | |
104 | if (!zns) | |
105 | return 0; | |
106 | XFREE(MTYPE_ZEBRA_NS, zns); | |
107 | return 0; | |
108 | } | |
109 | ||
110 | static int zebra_ns_enabled(struct ns *ns) | |
111 | { | |
112 | struct zebra_ns *zns = ns->info; | |
113 | ||
114 | if (IS_ZEBRA_DEBUG_EVENT) | |
115 | zlog_info("ZNS %s with id %u (enabled)", ns->name, ns->ns_id); | |
116 | if (!zns) | |
117 | return 0; | |
118 | return zebra_ns_enable(ns->ns_id, (void **)&zns); | |
119 | } | |
120 | ||
ff705b15 | 121 | int zebra_ns_disabled(struct ns *ns) |
3347430b PG |
122 | { |
123 | struct zebra_ns *zns = ns->info; | |
124 | ||
125 | if (IS_ZEBRA_DEBUG_EVENT) | |
126 | zlog_info("ZNS %s with id %u (disabled)", ns->name, ns->ns_id); | |
127 | if (!zns) | |
128 | return 0; | |
129 | return zebra_ns_disable(ns->ns_id, (void **)&zns); | |
130 | } | |
131 | ||
84915b0a | 132 | /* Do global enable actions - open sockets, read kernel config etc. */ |
d62a17ae | 133 | int zebra_ns_enable(ns_id_t ns_id, void **info) |
fe18ee2d | 134 | { |
d62a17ae | 135 | struct zebra_ns *zns = (struct zebra_ns *)(*info); |
fe18ee2d | 136 | |
ff705b15 PG |
137 | zns->ns_id = ns_id; |
138 | ||
5e280e56 PG |
139 | zns->rules_hash = |
140 | hash_create_size(8, zebra_pbr_rules_hash_key, | |
141 | zebra_pbr_rules_hash_equal, "Rules Hash"); | |
142 | ||
7661461a PG |
143 | zns->ipset_hash = |
144 | hash_create_size(8, zebra_pbr_ipset_hash_key, | |
145 | zebra_pbr_ipset_hash_equal, "IPset Hash"); | |
146 | ||
147 | zns->ipset_entry_hash = | |
148 | hash_create_size(8, zebra_pbr_ipset_entry_hash_key, | |
149 | zebra_pbr_ipset_entry_hash_equal, | |
150 | "IPset Hash Entry"); | |
d62a17ae | 151 | #if defined(HAVE_RTADV) |
152 | rtadv_init(zns); | |
fe18ee2d DS |
153 | #endif |
154 | ||
d62a17ae | 155 | kernel_init(zns); |
156 | interface_list(zns); | |
157 | route_read(zns); | |
fe18ee2d | 158 | |
8288a24f PG |
159 | /* Initiate Table Manager per ZNS */ |
160 | table_manager_enable(ns_id); | |
161 | ||
d62a17ae | 162 | return 0; |
fe18ee2d DS |
163 | } |
164 | ||
996c9314 LB |
165 | struct route_table *zebra_ns_find_table(struct zebra_ns *zns, uint32_t tableid, |
166 | afi_t afi) | |
ae825b8b | 167 | { |
55cd0f61 DS |
168 | struct zebra_ns_table finder; |
169 | struct zebra_ns_table *znst; | |
ae825b8b DS |
170 | |
171 | memset(&finder, 0, sizeof(finder)); | |
172 | finder.afi = afi; | |
173 | finder.tableid = tableid; | |
55cd0f61 | 174 | znst = RB_FIND(zebra_ns_table_head, &zns->ns_tables, &finder); |
ae825b8b DS |
175 | |
176 | if (znst) | |
177 | return znst->table; | |
178 | else | |
179 | return NULL; | |
180 | } | |
181 | ||
d7c0a89a | 182 | unsigned long zebra_ns_score_proto(uint8_t proto, unsigned short instance) |
47a08aa9 DS |
183 | { |
184 | struct zebra_ns *zns; | |
185 | struct zebra_ns_table *znst; | |
186 | unsigned long cnt = 0; | |
187 | ||
188 | zns = zebra_ns_lookup(NS_DEFAULT); | |
189 | ||
190 | RB_FOREACH (znst, zebra_ns_table_head, &zns->ns_tables) | |
191 | cnt += rib_score_proto_table(proto, instance, znst->table); | |
192 | ||
193 | return cnt; | |
194 | } | |
195 | ||
95a29032 DS |
196 | void zebra_ns_sweep_route(void) |
197 | { | |
198 | struct zebra_ns_table *znst; | |
199 | struct zebra_ns *zns; | |
200 | ||
201 | zns = zebra_ns_lookup(NS_DEFAULT); | |
202 | ||
203 | RB_FOREACH (znst, zebra_ns_table_head, &zns->ns_tables) | |
204 | rib_sweep_table(znst->table); | |
205 | } | |
206 | ||
5335613b DS |
207 | struct route_table *zebra_ns_get_table(struct zebra_ns *zns, |
208 | struct zebra_vrf *zvrf, uint32_t tableid, | |
209 | afi_t afi) | |
210 | { | |
211 | struct zebra_ns_table finder; | |
212 | struct zebra_ns_table *znst; | |
213 | rib_table_info_t *info; | |
214 | ||
215 | memset(&finder, 0, sizeof(finder)); | |
216 | finder.afi = afi; | |
217 | finder.tableid = tableid; | |
218 | znst = RB_FIND(zebra_ns_table_head, &zns->ns_tables, &finder); | |
219 | ||
220 | if (znst) | |
221 | return znst->table; | |
222 | ||
223 | znst = XCALLOC(MTYPE_ZEBRA_NS, sizeof(*znst)); | |
224 | znst->tableid = tableid; | |
225 | znst->afi = afi; | |
226 | znst->table = | |
227 | (afi == AFI_IP6) ? srcdest_table_init() : route_table_init(); | |
228 | ||
229 | info = XCALLOC(MTYPE_RIB_TABLE_INFO, sizeof(*info)); | |
230 | info->zvrf = zvrf; | |
231 | info->afi = afi; | |
232 | info->safi = SAFI_UNICAST; | |
233 | znst->table->info = info; | |
234 | znst->table->cleanup = zebra_rtable_node_cleanup; | |
235 | ||
236 | RB_INSERT(zebra_ns_table_head, &zns->ns_tables, znst); | |
237 | return znst->table; | |
238 | } | |
239 | ||
783fc3cd | 240 | static void zebra_ns_free_table(struct zebra_ns_table *znst) |
5335613b DS |
241 | { |
242 | void *table_info; | |
27b136bd | 243 | |
5335613b DS |
244 | rib_close_table(znst->table); |
245 | ||
246 | table_info = znst->table->info; | |
247 | route_table_finish(znst->table); | |
248 | XFREE(MTYPE_RIB_TABLE_INFO, table_info); | |
249 | XFREE(MTYPE_ZEBRA_NS, znst); | |
5335613b DS |
250 | } |
251 | ||
d62a17ae | 252 | int zebra_ns_disable(ns_id_t ns_id, void **info) |
fe18ee2d | 253 | { |
5335613b | 254 | struct zebra_ns_table *znst; |
d62a17ae | 255 | struct zebra_ns *zns = (struct zebra_ns *)(*info); |
fe18ee2d | 256 | |
43fe6a2a DS |
257 | hash_clean(zns->rules_hash, zebra_pbr_rules_free); |
258 | hash_free(zns->rules_hash); | |
7661461a PG |
259 | hash_clean(zns->ipset_hash, zebra_pbr_ipset_free); |
260 | hash_free(zns->ipset_hash); | |
261 | hash_clean(zns->ipset_entry_hash, | |
262 | zebra_pbr_ipset_entry_free), | |
263 | hash_free(zns->ipset_entry_hash); | |
264 | ||
55cd0f61 DS |
265 | while (!RB_EMPTY(zebra_ns_table_head, &zns->ns_tables)) { |
266 | znst = RB_ROOT(zebra_ns_table_head, &zns->ns_tables); | |
267 | ||
5335613b | 268 | RB_REMOVE(zebra_ns_table_head, &zns->ns_tables, znst); |
783fc3cd | 269 | zebra_ns_free_table(znst); |
5335613b | 270 | } |
43fe6a2a | 271 | |
d62a17ae | 272 | route_table_finish(zns->if_table); |
b7cfce93 | 273 | zebra_vxlan_ns_disable(zns); |
d62a17ae | 274 | #if defined(HAVE_RTADV) |
275 | rtadv_terminate(zns); | |
fe18ee2d DS |
276 | #endif |
277 | ||
d62a17ae | 278 | kernel_terminate(zns); |
fe18ee2d | 279 | |
8288a24f PG |
280 | table_manager_disable(zns->ns_id); |
281 | ||
ff705b15 PG |
282 | zns->ns_id = NS_DEFAULT; |
283 | ||
d62a17ae | 284 | return 0; |
fe18ee2d DS |
285 | } |
286 | ||
5335613b | 287 | |
d62a17ae | 288 | int zebra_ns_init(void) |
fe18ee2d | 289 | { |
ec31f30d | 290 | ns_id_t ns_id; |
03aff2d8 | 291 | ns_id_t ns_id_external; |
ec31f30d | 292 | |
3347430b PG |
293 | dzns = zebra_ns_alloc(); |
294 | ||
ec31f30d PG |
295 | if (zserv_privs.change(ZPRIVS_RAISE)) |
296 | zlog_err("Can't raise privileges"); | |
297 | ns_id = zebra_ns_id_get_default(); | |
298 | if (zserv_privs.change(ZPRIVS_LOWER)) | |
299 | zlog_err("Can't lower privileges"); | |
03aff2d8 PG |
300 | ns_id_external = ns_map_nsid_with_external(ns_id, true); |
301 | ns_init_management(ns_id_external, ns_id); | |
736d41ad PG |
302 | |
303 | logicalrouter_init(logicalrouter_config_write); | |
13460c44 | 304 | |
84915b0a | 305 | /* Do any needed per-NS data structure allocation. */ |
306 | dzns->if_table = route_table_init(); | |
307 | zebra_vxlan_ns_init(dzns); | |
308 | ||
309 | /* Register zebra VRF callbacks, create and activate default VRF. */ | |
d62a17ae | 310 | zebra_vrf_init(); |
fe18ee2d | 311 | |
84915b0a | 312 | /* Default NS is activated */ |
03aff2d8 | 313 | zebra_ns_enable(ns_id_external, (void **)&dzns); |
fe18ee2d | 314 | |
3347430b PG |
315 | if (vrf_is_backend_netns()) { |
316 | ns_add_hook(NS_NEW_HOOK, zebra_ns_new); | |
317 | ns_add_hook(NS_ENABLE_HOOK, zebra_ns_enabled); | |
318 | ns_add_hook(NS_DISABLE_HOOK, zebra_ns_disabled); | |
319 | ns_add_hook(NS_DELETE_HOOK, zebra_ns_delete); | |
e27dec3c PG |
320 | zebra_ns_notify_parse(); |
321 | zebra_ns_notify_init(); | |
3347430b | 322 | } |
d62a17ae | 323 | return 0; |
fe18ee2d | 324 | } |
b95c1883 | 325 | |
736d41ad PG |
326 | static int logicalrouter_config_write(struct vty *vty) |
327 | { | |
328 | struct ns *ns; | |
329 | int write = 0; | |
330 | ||
996c9314 | 331 | RB_FOREACH (ns, ns_head, &ns_tree) { |
736d41ad PG |
332 | if (ns->ns_id == NS_DEFAULT || ns->name == NULL) |
333 | continue; | |
334 | vty_out(vty, "logical-router %u netns %s\n", ns->ns_id, | |
335 | ns->name); | |
336 | write = 1; | |
337 | } | |
338 | return write; | |
339 | } | |
340 | ||
b95c1883 PG |
341 | int zebra_ns_config_write(struct vty *vty, struct ns *ns) |
342 | { | |
343 | if (ns && ns->name != NULL) | |
344 | vty_out(vty, " netns %s\n", ns->name); | |
345 | return 0; | |
346 | } |