]>
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" | |
174482ef | 29 | #include "lib/lib_errors.h" |
fe18ee2d DS |
30 | |
31 | #include "rtadv.h" | |
32 | #include "zebra_ns.h" | |
7c551956 | 33 | #include "zebra_vrf.h" |
4a1ab8e4 | 34 | #include "zebra_memory.h" |
05f7f5db | 35 | #include "rt.h" |
b7cfce93 | 36 | #include "zebra_vxlan.h" |
3347430b | 37 | #include "debug.h" |
e27dec3c | 38 | #include "zebra_netns_notify.h" |
ec31f30d | 39 | #include "zebra_netns_id.h" |
43fe6a2a | 40 | #include "zebra_pbr.h" |
47a08aa9 | 41 | #include "rib.h" |
8288a24f | 42 | #include "table_manager.h" |
ec31f30d PG |
43 | |
44 | extern struct zebra_privs_t zserv_privs; | |
4a1ab8e4 | 45 | |
d62a17ae | 46 | DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space") |
fe18ee2d | 47 | |
996c9314 LB |
48 | static inline int zebra_ns_table_entry_compare(const struct zebra_ns_table *e1, |
49 | const struct zebra_ns_table *e2); | |
5335613b DS |
50 | |
51 | RB_GENERATE(zebra_ns_table_head, zebra_ns_table, zebra_ns_table_entry, | |
52 | zebra_ns_table_entry_compare); | |
53 | ||
337960dd | 54 | static struct zebra_ns *dzns; |
fe18ee2d | 55 | |
996c9314 LB |
56 | static inline int zebra_ns_table_entry_compare(const struct zebra_ns_table *e1, |
57 | const struct zebra_ns_table *e2) | |
5335613b | 58 | { |
b3441a6a PG |
59 | if (e1->tableid < e2->tableid) |
60 | return -1; | |
61 | if (e1->tableid > e2->tableid) | |
62 | return 1; | |
63 | if (e1->ns_id < e2->ns_id) | |
64 | return -1; | |
65 | if (e1->ns_id > e2->ns_id) | |
66 | return 1; | |
67 | return (e1->afi - e2->afi); | |
5335613b DS |
68 | } |
69 | ||
736d41ad PG |
70 | static int logicalrouter_config_write(struct vty *vty); |
71 | ||
d62a17ae | 72 | struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id) |
fe18ee2d | 73 | { |
ff705b15 PG |
74 | if (ns_id == NS_DEFAULT) |
75 | return dzns; | |
76 | struct zebra_ns *info = (struct zebra_ns *)ns_info_lookup(ns_id); | |
77 | ||
78 | return (info == NULL) ? dzns : info; | |
fe18ee2d DS |
79 | } |
80 | ||
3347430b PG |
81 | static struct zebra_ns *zebra_ns_alloc(void) |
82 | { | |
83 | return XCALLOC(MTYPE_ZEBRA_NS, sizeof(struct zebra_ns)); | |
84 | } | |
85 | ||
86 | static int zebra_ns_new(struct ns *ns) | |
87 | { | |
88 | struct zebra_ns *zns; | |
89 | ||
90 | if (IS_ZEBRA_DEBUG_EVENT) | |
91 | zlog_info("ZNS %s with id %u (created)", ns->name, ns->ns_id); | |
92 | ||
93 | zns = zebra_ns_alloc(); | |
94 | ns->info = zns; | |
95 | zns->ns = ns; | |
ff705b15 PG |
96 | |
97 | /* Do any needed per-NS data structure allocation. */ | |
98 | zns->if_table = route_table_init(); | |
99 | zebra_vxlan_ns_init(zns); | |
100 | ||
3347430b PG |
101 | return 0; |
102 | } | |
103 | ||
104 | static int zebra_ns_delete(struct ns *ns) | |
105 | { | |
996c9314 | 106 | struct zebra_ns *zns = (struct zebra_ns *)ns->info; |
3347430b PG |
107 | |
108 | if (IS_ZEBRA_DEBUG_EVENT) | |
109 | zlog_info("ZNS %s with id %u (deleted)", ns->name, ns->ns_id); | |
110 | if (!zns) | |
111 | return 0; | |
112 | XFREE(MTYPE_ZEBRA_NS, zns); | |
113 | return 0; | |
114 | } | |
115 | ||
116 | static int zebra_ns_enabled(struct ns *ns) | |
117 | { | |
118 | struct zebra_ns *zns = ns->info; | |
119 | ||
120 | if (IS_ZEBRA_DEBUG_EVENT) | |
121 | zlog_info("ZNS %s with id %u (enabled)", ns->name, ns->ns_id); | |
122 | if (!zns) | |
123 | return 0; | |
124 | return zebra_ns_enable(ns->ns_id, (void **)&zns); | |
125 | } | |
126 | ||
ff705b15 | 127 | int zebra_ns_disabled(struct ns *ns) |
3347430b PG |
128 | { |
129 | struct zebra_ns *zns = ns->info; | |
130 | ||
131 | if (IS_ZEBRA_DEBUG_EVENT) | |
132 | zlog_info("ZNS %s with id %u (disabled)", ns->name, ns->ns_id); | |
133 | if (!zns) | |
134 | return 0; | |
135 | return zebra_ns_disable(ns->ns_id, (void **)&zns); | |
136 | } | |
137 | ||
84915b0a | 138 | /* Do global enable actions - open sockets, read kernel config etc. */ |
d62a17ae | 139 | int zebra_ns_enable(ns_id_t ns_id, void **info) |
fe18ee2d | 140 | { |
d62a17ae | 141 | struct zebra_ns *zns = (struct zebra_ns *)(*info); |
fe18ee2d | 142 | |
ff705b15 PG |
143 | zns->ns_id = ns_id; |
144 | ||
5e280e56 PG |
145 | zns->rules_hash = |
146 | hash_create_size(8, zebra_pbr_rules_hash_key, | |
147 | zebra_pbr_rules_hash_equal, "Rules Hash"); | |
148 | ||
7661461a PG |
149 | zns->ipset_hash = |
150 | hash_create_size(8, zebra_pbr_ipset_hash_key, | |
151 | zebra_pbr_ipset_hash_equal, "IPset Hash"); | |
152 | ||
153 | zns->ipset_entry_hash = | |
154 | hash_create_size(8, zebra_pbr_ipset_entry_hash_key, | |
155 | zebra_pbr_ipset_entry_hash_equal, | |
156 | "IPset Hash Entry"); | |
7abd6c4f PG |
157 | |
158 | zns->iptable_hash = | |
159 | hash_create_size(8, zebra_pbr_iptable_hash_key, | |
160 | zebra_pbr_iptable_hash_equal, | |
161 | "IPtable Hash Entry"); | |
162 | ||
d62a17ae | 163 | #if defined(HAVE_RTADV) |
164 | rtadv_init(zns); | |
fe18ee2d DS |
165 | #endif |
166 | ||
d62a17ae | 167 | kernel_init(zns); |
168 | interface_list(zns); | |
169 | route_read(zns); | |
fe18ee2d | 170 | |
8288a24f PG |
171 | /* Initiate Table Manager per ZNS */ |
172 | table_manager_enable(ns_id); | |
173 | ||
d62a17ae | 174 | return 0; |
fe18ee2d DS |
175 | } |
176 | ||
996c9314 LB |
177 | struct route_table *zebra_ns_find_table(struct zebra_ns *zns, uint32_t tableid, |
178 | afi_t afi) | |
ae825b8b | 179 | { |
55cd0f61 DS |
180 | struct zebra_ns_table finder; |
181 | struct zebra_ns_table *znst; | |
ae825b8b DS |
182 | |
183 | memset(&finder, 0, sizeof(finder)); | |
184 | finder.afi = afi; | |
185 | finder.tableid = tableid; | |
b3441a6a | 186 | finder.ns_id = zns->ns_id; |
55cd0f61 | 187 | znst = RB_FIND(zebra_ns_table_head, &zns->ns_tables, &finder); |
ae825b8b DS |
188 | |
189 | if (znst) | |
190 | return znst->table; | |
191 | else | |
192 | return NULL; | |
193 | } | |
194 | ||
d7c0a89a | 195 | unsigned long zebra_ns_score_proto(uint8_t proto, unsigned short instance) |
47a08aa9 DS |
196 | { |
197 | struct zebra_ns *zns; | |
198 | struct zebra_ns_table *znst; | |
199 | unsigned long cnt = 0; | |
200 | ||
201 | zns = zebra_ns_lookup(NS_DEFAULT); | |
202 | ||
b3441a6a PG |
203 | RB_FOREACH (znst, zebra_ns_table_head, &zns->ns_tables) { |
204 | if (znst->ns_id != NS_DEFAULT) | |
205 | continue; | |
47a08aa9 | 206 | cnt += rib_score_proto_table(proto, instance, znst->table); |
b3441a6a | 207 | } |
47a08aa9 DS |
208 | return cnt; |
209 | } | |
210 | ||
95a29032 DS |
211 | void zebra_ns_sweep_route(void) |
212 | { | |
213 | struct zebra_ns_table *znst; | |
214 | struct zebra_ns *zns; | |
215 | ||
216 | zns = zebra_ns_lookup(NS_DEFAULT); | |
217 | ||
b3441a6a PG |
218 | RB_FOREACH (znst, zebra_ns_table_head, &zns->ns_tables) { |
219 | if (znst->ns_id != NS_DEFAULT) | |
220 | continue; | |
95a29032 | 221 | rib_sweep_table(znst->table); |
b3441a6a | 222 | } |
95a29032 DS |
223 | } |
224 | ||
5335613b DS |
225 | struct route_table *zebra_ns_get_table(struct zebra_ns *zns, |
226 | struct zebra_vrf *zvrf, uint32_t tableid, | |
227 | afi_t afi) | |
228 | { | |
229 | struct zebra_ns_table finder; | |
230 | struct zebra_ns_table *znst; | |
231 | rib_table_info_t *info; | |
232 | ||
233 | memset(&finder, 0, sizeof(finder)); | |
234 | finder.afi = afi; | |
235 | finder.tableid = tableid; | |
b3441a6a | 236 | finder.ns_id = zns->ns_id; |
5335613b DS |
237 | znst = RB_FIND(zebra_ns_table_head, &zns->ns_tables, &finder); |
238 | ||
239 | if (znst) | |
240 | return znst->table; | |
241 | ||
242 | znst = XCALLOC(MTYPE_ZEBRA_NS, sizeof(*znst)); | |
243 | znst->tableid = tableid; | |
244 | znst->afi = afi; | |
b3441a6a | 245 | znst->ns_id = zns->ns_id; |
5335613b DS |
246 | znst->table = |
247 | (afi == AFI_IP6) ? srcdest_table_init() : route_table_init(); | |
248 | ||
249 | info = XCALLOC(MTYPE_RIB_TABLE_INFO, sizeof(*info)); | |
250 | info->zvrf = zvrf; | |
251 | info->afi = afi; | |
252 | info->safi = SAFI_UNICAST; | |
253 | znst->table->info = info; | |
254 | znst->table->cleanup = zebra_rtable_node_cleanup; | |
255 | ||
256 | RB_INSERT(zebra_ns_table_head, &zns->ns_tables, znst); | |
257 | return znst->table; | |
258 | } | |
259 | ||
783fc3cd | 260 | static void zebra_ns_free_table(struct zebra_ns_table *znst) |
5335613b DS |
261 | { |
262 | void *table_info; | |
27b136bd | 263 | |
5335613b DS |
264 | rib_close_table(znst->table); |
265 | ||
266 | table_info = znst->table->info; | |
267 | route_table_finish(znst->table); | |
268 | XFREE(MTYPE_RIB_TABLE_INFO, table_info); | |
269 | XFREE(MTYPE_ZEBRA_NS, znst); | |
5335613b DS |
270 | } |
271 | ||
d62a17ae | 272 | int zebra_ns_disable(ns_id_t ns_id, void **info) |
fe18ee2d | 273 | { |
b3441a6a | 274 | struct zebra_ns_table *znst, *tmp; |
d62a17ae | 275 | struct zebra_ns *zns = (struct zebra_ns *)(*info); |
fe18ee2d | 276 | |
43fe6a2a DS |
277 | hash_clean(zns->rules_hash, zebra_pbr_rules_free); |
278 | hash_free(zns->rules_hash); | |
7661461a PG |
279 | hash_clean(zns->ipset_entry_hash, |
280 | zebra_pbr_ipset_entry_free), | |
be2028d1 PG |
281 | hash_clean(zns->ipset_hash, zebra_pbr_ipset_free); |
282 | hash_free(zns->ipset_hash); | |
7661461a | 283 | hash_free(zns->ipset_entry_hash); |
7abd6c4f PG |
284 | hash_clean(zns->iptable_hash, |
285 | zebra_pbr_iptable_free); | |
286 | hash_free(zns->iptable_hash); | |
7661461a | 287 | |
b3441a6a PG |
288 | RB_FOREACH_SAFE (znst, zebra_ns_table_head, &zns->ns_tables, tmp) { |
289 | if (znst->ns_id != ns_id) | |
290 | continue; | |
5335613b | 291 | RB_REMOVE(zebra_ns_table_head, &zns->ns_tables, znst); |
783fc3cd | 292 | zebra_ns_free_table(znst); |
5335613b | 293 | } |
43fe6a2a | 294 | |
d62a17ae | 295 | route_table_finish(zns->if_table); |
b7cfce93 | 296 | zebra_vxlan_ns_disable(zns); |
d62a17ae | 297 | #if defined(HAVE_RTADV) |
298 | rtadv_terminate(zns); | |
fe18ee2d DS |
299 | #endif |
300 | ||
d62a17ae | 301 | kernel_terminate(zns); |
fe18ee2d | 302 | |
8288a24f PG |
303 | table_manager_disable(zns->ns_id); |
304 | ||
ff705b15 PG |
305 | zns->ns_id = NS_DEFAULT; |
306 | ||
d62a17ae | 307 | return 0; |
fe18ee2d DS |
308 | } |
309 | ||
5335613b | 310 | |
d62a17ae | 311 | int zebra_ns_init(void) |
fe18ee2d | 312 | { |
ec31f30d | 313 | ns_id_t ns_id; |
03aff2d8 | 314 | ns_id_t ns_id_external; |
ec31f30d | 315 | |
3347430b PG |
316 | dzns = zebra_ns_alloc(); |
317 | ||
01b9e3fd DL |
318 | frr_elevate_privs(&zserv_privs) { |
319 | ns_id = zebra_ns_id_get_default(); | |
320 | } | |
03aff2d8 PG |
321 | ns_id_external = ns_map_nsid_with_external(ns_id, true); |
322 | ns_init_management(ns_id_external, ns_id); | |
736d41ad PG |
323 | |
324 | logicalrouter_init(logicalrouter_config_write); | |
13460c44 | 325 | |
84915b0a | 326 | /* Do any needed per-NS data structure allocation. */ |
327 | dzns->if_table = route_table_init(); | |
328 | zebra_vxlan_ns_init(dzns); | |
329 | ||
330 | /* Register zebra VRF callbacks, create and activate default VRF. */ | |
d62a17ae | 331 | zebra_vrf_init(); |
fe18ee2d | 332 | |
84915b0a | 333 | /* Default NS is activated */ |
03aff2d8 | 334 | zebra_ns_enable(ns_id_external, (void **)&dzns); |
fe18ee2d | 335 | |
3347430b PG |
336 | if (vrf_is_backend_netns()) { |
337 | ns_add_hook(NS_NEW_HOOK, zebra_ns_new); | |
338 | ns_add_hook(NS_ENABLE_HOOK, zebra_ns_enabled); | |
339 | ns_add_hook(NS_DISABLE_HOOK, zebra_ns_disabled); | |
340 | ns_add_hook(NS_DELETE_HOOK, zebra_ns_delete); | |
e27dec3c PG |
341 | zebra_ns_notify_parse(); |
342 | zebra_ns_notify_init(); | |
3347430b | 343 | } |
d62a17ae | 344 | return 0; |
fe18ee2d | 345 | } |
b95c1883 | 346 | |
736d41ad PG |
347 | static int logicalrouter_config_write(struct vty *vty) |
348 | { | |
349 | struct ns *ns; | |
350 | int write = 0; | |
351 | ||
996c9314 | 352 | RB_FOREACH (ns, ns_head, &ns_tree) { |
736d41ad PG |
353 | if (ns->ns_id == NS_DEFAULT || ns->name == NULL) |
354 | continue; | |
355 | vty_out(vty, "logical-router %u netns %s\n", ns->ns_id, | |
356 | ns->name); | |
357 | write = 1; | |
358 | } | |
359 | return write; | |
360 | } | |
361 | ||
b95c1883 PG |
362 | int zebra_ns_config_write(struct vty *vty, struct ns *ns) |
363 | { | |
364 | if (ns && ns->name != NULL) | |
365 | vty_out(vty, " netns %s\n", ns->name); | |
366 | return 0; | |
367 | } |