Line data Source code
1 : /*
2 : * vr_route.c -- route management
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : * Copyright Contributors to the OpenSDN project
6 : */
7 : #include <vr_os.h>
8 : #include <vr_types.h>
9 : #include <vr_packet.h>
10 : #include <vr_route.h>
11 : #include "vr_message.h"
12 : #include "vr_sandesh.h"
13 : #include "vr_offloads_dp.h"
14 :
15 : unsigned int vr_vrfs = VR_DEF_VRFS;
16 :
17 : extern int mtrie_algo_init(struct vr_rtable *, struct rtable_fspec *);
18 : extern void mtrie_algo_deinit(struct vr_rtable *, struct rtable_fspec *, bool);
19 : extern int bridge_table_init(struct vr_rtable *, struct rtable_fspec *);
20 : extern void bridge_table_deinit(struct vr_rtable *, struct rtable_fspec *, bool);
21 :
22 : static int inet_rtb_family_init(struct rtable_fspec *fs, struct vrouter *router);
23 : static void inet_rtb_family_deinit(struct rtable_fspec *fs, struct vrouter *router, bool soft_reset);
24 : static int bridge_rtb_family_init(struct rtable_fspec *fs, struct vrouter *router);
25 : static void bridge_rtb_family_deinit(struct rtable_fspec *fs, struct vrouter *router, bool soft_reset);
26 :
27 : int vr_route_delete(vr_route_req *);
28 : int vr_route_get(vr_route_req *);
29 : int vr_route_dump(vr_route_req *);
30 :
31 : int inet_route_add(struct rtable_fspec *, struct vr_route_req *);
32 : int inet_route_del(struct rtable_fspec *, struct vr_route_req *);
33 :
34 : int bridge_entry_add(struct rtable_fspec *, struct vr_route_req *);
35 : int bridge_entry_del(struct rtable_fspec *, struct vr_route_req *);
36 :
37 : /* hopefully we can afford a bit of bloat while loading ? */
38 : static struct rtable_fspec rtable_families[] = {
39 : {
40 : .rtb_family = AF_INET,
41 : .rtb_family_init = inet_rtb_family_init,
42 : .rtb_family_deinit = inet_rtb_family_deinit,
43 : .route_add = inet_route_add,
44 : .route_del = inet_route_del,
45 : .algo_init = mtrie_algo_init,
46 : .algo_deinit = mtrie_algo_deinit,
47 : },
48 : {
49 : .rtb_family = AF_BRIDGE,
50 : .rtb_family_init = bridge_rtb_family_init,
51 : .rtb_family_deinit = bridge_rtb_family_deinit,
52 : .route_add = bridge_entry_add,
53 : .route_del = bridge_entry_del,
54 : .algo_init = bridge_table_init,
55 : .algo_deinit = bridge_table_deinit,
56 : },
57 : {
58 : .rtb_family = AF_INET6,
59 : .rtb_family_init = inet_rtb_family_init,
60 : .rtb_family_deinit = inet_rtb_family_deinit,
61 : .route_add = inet_route_add,
62 : .route_del = inet_route_del,
63 : .algo_init = mtrie_algo_init,
64 : .algo_deinit = mtrie_algo_deinit,
65 : }
66 : };
67 :
68 : static struct rtable_fspec *
69 709 : vr_get_family(unsigned int family)
70 : {
71 709 : switch (family) {
72 473 : case AF_INET:
73 473 : return &rtable_families[0];
74 179 : case AF_BRIDGE:
75 179 : return &rtable_families[1];
76 57 : case AF_INET6:
77 57 : return &rtable_families[2];
78 :
79 0 : default:
80 0 : return NULL;
81 : }
82 :
83 : return NULL;
84 : }
85 :
86 : int
87 490 : vr_route_delete(vr_route_req *req)
88 : {
89 : struct rtable_fspec *fs;
90 : struct vr_route_req vr_req;
91 : int ret;
92 : uint32_t rt_prefix[4];
93 :
94 490 : fs = vr_get_family(req->rtr_family);
95 490 : if (!fs)
96 0 : ret = -ENOENT;
97 : else {
98 490 : vr_req.rtr_req = *req;
99 :
100 490 : if (req->rtr_family != AF_BRIDGE && !req->rtr_prefix_size) {
101 0 : ret = -EINVAL;
102 0 : goto error;
103 : }
104 :
105 490 : if (req ->rtr_family == AF_BRIDGE &&
106 87 : (!req->rtr_mac_size || !req->rtr_mac)) {
107 0 : ret = -EINVAL;
108 0 : goto error;
109 : }
110 :
111 490 : if (req ->rtr_family != AF_BRIDGE) {
112 403 : vr_req.rtr_req.rtr_prefix = (uint8_t*)&rt_prefix;
113 403 : memcpy(vr_req.rtr_req.rtr_prefix, req->rtr_prefix, RT_IP_ADDR_SIZE(req->rtr_family));
114 : }
115 490 : vr_req.rtr_req.rtr_marker_size = 0;
116 490 : ret = fs->route_del(fs, &vr_req);
117 : }
118 :
119 : /* notify hw offload of change, if enabled */
120 490 : if (!ret)
121 109 : vr_offload_route_del(req);
122 :
123 381 : error:
124 490 : vr_send_response(ret);
125 490 : vr_send_broadcast(VR_ROUTE_OBJECT_ID, &vr_req, SANDESH_OP_DEL, ret);
126 :
127 490 : return ret;
128 : }
129 :
130 : int
131 219 : vr_route_add(vr_route_req *req)
132 : {
133 : struct rtable_fspec *fs;
134 : struct vr_route_req vr_req;
135 : int ret;
136 : uint32_t rt_prefix[4];
137 :
138 219 : fs = vr_get_family(req->rtr_family);
139 219 : if (!fs) {
140 0 : ret = -ENOENT;
141 : } else {
142 219 : vr_req.rtr_req = *req;
143 219 : if (req->rtr_prefix_size) {
144 127 : vr_req.rtr_req.rtr_prefix = (uint8_t*)&rt_prefix;
145 127 : memcpy(vr_req.rtr_req.rtr_prefix, req->rtr_prefix, RT_IP_ADDR_SIZE(req->rtr_family));
146 127 : vr_req.rtr_req.rtr_marker_size = 0;
147 127 : vr_req.rtr_req.rtr_prefix_size = req->rtr_prefix_size;
148 : } else {
149 92 : vr_req.rtr_req.rtr_prefix = NULL;
150 : }
151 :
152 219 : ret = fs->route_add(fs, &vr_req);
153 : }
154 :
155 : /* notify hw offload of change, if enabled */
156 219 : if (!ret) {
157 218 : ret = vr_offload_route_add(req);
158 218 : if (ret)
159 0 : fs->route_del(fs, &vr_req);
160 : }
161 :
162 219 : vr_send_response(ret);
163 219 : vr_send_broadcast(VR_ROUTE_OBJECT_ID, &vr_req, SANDESH_OP_ADD, ret);
164 :
165 219 : return ret;
166 : }
167 :
168 : int
169 331 : vr_route_get(vr_route_req *req)
170 : {
171 331 : int ret = 0;
172 : uint32_t rt_prefix[4];
173 331 : bool mac_mem_free = false;
174 :
175 : struct vr_route_req vr_req;
176 : struct vrouter *router;
177 331 : struct vr_rtable *rtable = NULL;
178 :
179 331 : if (!req->rtr_mac)
180 0 : mac_mem_free = true;
181 :
182 331 : if ((req->rtr_family != AF_INET) && (req->rtr_family != AF_INET6) &&
183 0 : (req->rtr_family != AF_BRIDGE)) {
184 0 : ret = -EINVAL;
185 0 : goto generate_response;
186 : }
187 :
188 331 : vr_req.rtr_req = *req;
189 :
190 331 : vr_req.rtr_req.rtr_marker_size = 0;
191 331 : vr_req.rtr_req.rtr_prefix_size = req->rtr_prefix_size;
192 331 : if (req->rtr_prefix_size) {
193 331 : vr_req.rtr_req.rtr_prefix = (uint8_t*)&rt_prefix;
194 331 : memcpy(vr_req.rtr_req.rtr_prefix, req->rtr_prefix, RT_IP_ADDR_SIZE(req->rtr_family));
195 : } else
196 0 : vr_req.rtr_req.rtr_prefix = NULL;
197 :
198 331 : router = vrouter_get(req->rtr_rid);
199 331 : if (!router) {
200 0 : ret = -ENOENT;
201 0 : goto generate_response;
202 : } else {
203 331 : if ((req->rtr_family == AF_INET) || (req->rtr_family == AF_INET6)) {
204 331 : rtable = router->vr_inet_rtable;
205 0 : } else if (req->rtr_family == AF_BRIDGE) {
206 0 : rtable = router->vr_bridge_table;
207 : }
208 :
209 331 : if (!rtable) {
210 0 : ret = -ENOENT;
211 0 : goto generate_response;
212 : }
213 :
214 331 : ret = rtable->algo_get(vr_req.rtr_req.rtr_vrf_id, &vr_req);
215 : }
216 : /* Allow for debug comparison to check if matching entry is programmed on NIC */
217 331 : if (!ret)
218 331 : vr_offload_route_get(req);
219 0 : generate_response:
220 331 : vr_message_response(VR_ROUTE_OBJECT_ID, ret ? NULL : &vr_req, ret, false);
221 331 : if (mac_mem_free && vr_req.rtr_req.rtr_mac) {
222 0 : vr_free(vr_req.rtr_req.rtr_mac, VR_ROUTE_REQ_MAC_OBJECT);
223 0 : vr_req.rtr_req.rtr_mac = NULL;
224 : }
225 :
226 331 : return ret;
227 : }
228 :
229 : int
230 0 : vr_route_dump(vr_route_req *req)
231 : {
232 : struct vr_route_req vr_req;
233 : struct vrouter *router;
234 0 : struct vr_rtable *rtable = NULL;
235 : int ret;
236 : uint32_t rt_prefix[4], rt_marker[4];
237 :
238 0 : vr_req.rtr_req = *req;
239 0 : vr_req.rtr_req.rtr_prefix_size = req->rtr_prefix_size;
240 0 : if (req->rtr_prefix_size) {
241 0 : vr_req.rtr_req.rtr_prefix = (uint8_t*)&rt_prefix;
242 0 : memcpy(vr_req.rtr_req.rtr_prefix, req->rtr_prefix, RT_IP_ADDR_SIZE(req->rtr_family));
243 : } else {
244 0 : vr_req.rtr_req.rtr_prefix = NULL;
245 : }
246 :
247 0 : vr_req.rtr_req.rtr_marker_size = req->rtr_marker_size;
248 0 : if (req->rtr_marker_size) {
249 0 : vr_req.rtr_req.rtr_marker = (uint8_t*)&rt_marker;
250 0 : memcpy(vr_req.rtr_req.rtr_marker, req->rtr_marker, RT_IP_ADDR_SIZE(req->rtr_family));
251 : } else {
252 0 : vr_req.rtr_req.rtr_marker = NULL;
253 : }
254 :
255 0 : router = vrouter_get(req->rtr_rid);
256 0 : if (!router) {
257 0 : ret = -ENOENT;
258 0 : goto generate_error;
259 : } else {
260 :
261 0 : if (req->rtr_family == AF_BRIDGE) {
262 0 : rtable = router->vr_bridge_table;
263 : } else {
264 0 : rtable = router->vr_inet_rtable;
265 : }
266 :
267 0 : if (!rtable) {
268 0 : ret = -ENOENT;
269 0 : goto generate_error;
270 : }
271 :
272 0 : ret = rtable->algo_dump(NULL, &vr_req);
273 : }
274 : /* Allow for debug comparison to check if matching entry is programmed on NIC */
275 0 : if (!ret)
276 0 : vr_offload_route_dump(&vr_req);
277 :
278 0 : return ret;
279 :
280 0 : generate_error:
281 0 : vr_send_response(ret);
282 :
283 0 : return ret;
284 : }
285 :
286 : void
287 1040 : vr_route_req_process(void *s_req)
288 : {
289 1040 : vr_route_req *req = (vr_route_req *)s_req;
290 :
291 1040 : switch (req->h_op) {
292 219 : case SANDESH_OP_ADD:
293 219 : vr_route_add(req);
294 219 : break;
295 :
296 490 : case SANDESH_OP_DEL:
297 490 : vr_route_delete(req);
298 490 : break;
299 :
300 331 : case SANDESH_OP_GET:
301 331 : vr_route_get(req);
302 331 : break;
303 :
304 0 : case SANDESH_OP_DUMP:
305 0 : vr_route_dump(req);
306 0 : break;
307 :
308 0 : default:
309 0 : break;
310 : }
311 :
312 1040 : return;
313 : }
314 :
315 : static void
316 0 : vr_inet_vrf_stats_dump(struct vrouter *router, vr_vrf_stats_req *req)
317 : {
318 0 : int ret = 0;
319 : struct vr_rtable *rtable;
320 :
321 0 : rtable = router->vr_inet_rtable;
322 0 : if (!rtable) {
323 0 : ret = -ENOENT;
324 0 : goto generate_error;
325 : }
326 :
327 0 : ret = rtable->algo_stats_dump(rtable, req);
328 0 : return;
329 :
330 0 : generate_error:
331 0 : vr_send_response(ret);
332 0 : return;
333 : }
334 :
335 : static void
336 0 : vr_inet_vrf_stats_get(struct vrouter *router, vr_vrf_stats_req *req)
337 : {
338 0 : int ret = 0;
339 : struct vr_rtable *rtable;
340 : vr_vrf_stats_req response;
341 :
342 0 : rtable = router->vr_inet_rtable;
343 0 : if (!rtable) {
344 0 : ret = -ENOENT;
345 0 : goto generate_error;
346 : }
347 :
348 0 : if (req->vsr_vrf >= 0 &&
349 0 : (unsigned int)req->vsr_vrf >= rtable->algo_max_vrfs) {
350 0 : ret = -EINVAL;
351 0 : goto generate_error;
352 : }
353 :
354 0 : ret = rtable->algo_stats_get(req, &response);
355 0 : generate_error:
356 0 : vr_message_response(VR_VRF_STATS_OBJECT_ID, ret ? NULL : &response, ret, false);
357 0 : return;
358 : }
359 :
360 : static void
361 0 : vr_inet_vrf_stats_op(struct vrouter *router, vr_vrf_stats_req *req)
362 : {
363 0 : if (req->h_op == SANDESH_OP_GET)
364 0 : vr_inet_vrf_stats_get(router, req);
365 0 : else if (req->h_op == SANDESH_OP_DUMP)
366 0 : vr_inet_vrf_stats_dump(router, req);
367 :
368 0 : return;
369 : }
370 :
371 : static void
372 0 : vr_vrf_stats_op(vr_vrf_stats_req *req)
373 : {
374 0 : int ret = 0;
375 : struct vrouter *router;
376 :
377 0 : router = vrouter_get(req->vsr_rid);
378 0 : if (!router) {
379 0 : ret = -EINVAL;
380 0 : goto generate_error;
381 : }
382 :
383 0 : switch (req->vsr_family) {
384 0 : case AF_INET:
385 0 : vr_inet_vrf_stats_op(router, req);
386 0 : break;
387 :
388 0 : default:
389 0 : ret = -EINVAL;
390 0 : goto generate_error;
391 : }
392 :
393 0 : return;
394 :
395 0 : generate_error:
396 0 : vr_send_response(ret);
397 0 : return;
398 : }
399 :
400 : void
401 0 : vr_vrf_stats_req_process(void *s_req)
402 : {
403 0 : vr_vrf_stats_req *req = (vr_vrf_stats_req *)s_req;
404 :
405 0 : switch (req->h_op) {
406 0 : case SANDESH_OP_GET:
407 : case SANDESH_OP_DUMP:
408 0 : vr_vrf_stats_op(req);
409 0 : break;
410 :
411 0 : default:
412 0 : break;
413 : }
414 :
415 0 : return;
416 : }
417 :
418 : int
419 127 : inet_route_add(struct rtable_fspec *fs, struct vr_route_req *req)
420 : {
421 : unsigned char pmask, pmask_byte;
422 : struct vr_rtable *rtable;
423 : struct vrouter *router;
424 :
425 127 : router = vrouter_get(req->rtr_req.rtr_rid);
426 127 : if (!router)
427 0 : return -EINVAL;
428 :
429 : /* V4 and V6 only */
430 127 : if (req->rtr_req.rtr_family != AF_INET &&
431 24 : req->rtr_req.rtr_family != AF_INET6)
432 0 : return -EINVAL;
433 :
434 : /* There has to be some prefix to add */
435 127 : if (!req->rtr_req.rtr_prefix_size)
436 0 : return -EINVAL;
437 :
438 :
439 127 : rtable = router->vr_inet_rtable;
440 127 : if (!rtable ||
441 254 : ((unsigned int)req->rtr_req.rtr_vrf_id >= fs->rtb_max_vrfs) ||
442 127 : ((unsigned int)(req->rtr_req.rtr_prefix_len) >
443 127 : (RT_IP_ADDR_SIZE(req->rtr_req.rtr_family)*8)))
444 0 : return -EINVAL;
445 :
446 : /* Zero the bits in prefix, which are set beyond the mask len */
447 127 : if (req->rtr_req.rtr_prefix) {
448 :
449 127 : pmask = req->rtr_req.rtr_prefix_len % 8;
450 127 : pmask_byte = req->rtr_req.rtr_prefix_len / 8;
451 : /*
452 : * pmask_byte identifies the byte bumber from which we need to
453 : * reset prefix till the end of prefix. If mask len is not 8 bit
454 : * boundary, we calculate that in pmask
455 : */
456 127 : if (pmask) {
457 8 : pmask = ~((1 << (8 - pmask)) - 1);
458 8 : req->rtr_req.rtr_prefix[pmask_byte] =
459 8 : req->rtr_req.rtr_prefix[pmask_byte] & pmask;
460 8 : pmask_byte++;
461 : }
462 362 : for (; pmask_byte < RT_IP_ADDR_SIZE(req->rtr_req.rtr_family);
463 235 : pmask_byte++) {
464 235 : req->rtr_req.rtr_prefix[pmask_byte] = 0;
465 : }
466 : }
467 :
468 127 : if (rtable) {
469 127 : if (rtable->algo_add)
470 127 : return rtable->algo_add(rtable, req);
471 : else
472 0 : return -1;
473 : } else {
474 0 : return -1;
475 : }
476 : }
477 :
478 : int
479 403 : inet_route_del(struct rtable_fspec *fs, struct vr_route_req *req)
480 : {
481 : struct vr_rtable *rtable;
482 : struct vrouter *router;
483 :
484 403 : if (((unsigned int)(req->rtr_req.rtr_prefix_len) >
485 403 : (RT_IP_ADDR_SIZE(req->rtr_req.rtr_family)*8)) ||
486 403 : (unsigned int)(req->rtr_req.rtr_vrf_id) >= fs->rtb_max_vrfs)
487 0 : return -EINVAL;
488 :
489 403 : router = vrouter_get(req->rtr_req.rtr_rid);
490 403 : if (!router)
491 0 : return -EINVAL;
492 :
493 403 : rtable = router->vr_inet_rtable;
494 403 : if (!rtable ||
495 403 : (unsigned int)req->rtr_req.rtr_vrf_id >= fs->rtb_max_vrfs)
496 0 : return -EINVAL;
497 :
498 403 : return rtable->algo_del(rtable, req);
499 : }
500 :
501 : static void
502 106 : inet_rtb_family_deinit(struct rtable_fspec *fs, struct vrouter *router,
503 : bool soft_reset)
504 : {
505 106 : if (router->vr_inet_rtable) {
506 53 : fs->algo_deinit(router->vr_inet_rtable, fs, soft_reset);
507 53 : if (!soft_reset) {
508 53 : vr_free(router->vr_inet_rtable, VR_ROUTE_TABLE_OBJECT);
509 53 : router->vr_inet_rtable = NULL;
510 : }
511 : }
512 :
513 106 : return;
514 : }
515 :
516 : static int
517 106 : inet_rtb_family_init(struct rtable_fspec *fs, struct vrouter *router)
518 : {
519 : int ret;
520 :
521 106 : if (!fs->algo_init)
522 0 : return 1;
523 :
524 106 : if (!router->vr_inet_rtable) {
525 53 : router->vr_inet_rtable = vr_zalloc(sizeof(struct vr_rtable),
526 : VR_ROUTE_TABLE_OBJECT);
527 53 : if (!router->vr_inet_rtable)
528 0 : return vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, 0);
529 : }
530 :
531 106 : ret = fs->algo_init(router->vr_inet_rtable, fs);
532 106 : if (ret)
533 0 : return vr_module_error(ret, __FUNCTION__, __LINE__, 0);
534 :
535 106 : return 0;
536 : }
537 :
538 : int
539 92 : bridge_entry_add(struct rtable_fspec *fs, struct vr_route_req *req)
540 : {
541 : struct vrouter *router;
542 :
543 92 : if (!fs) {
544 0 : fs = vr_get_family(AF_BRIDGE);
545 0 : if (!fs)
546 0 : return -EINVAL;
547 : }
548 :
549 92 : router = vrouter_get(req->rtr_req.rtr_rid);
550 92 : if (!router)
551 0 : return -EINVAL;
552 :
553 92 : if (!router->vr_bridge_table ||
554 92 : ((unsigned int)req->rtr_req.rtr_vrf_id >= fs->rtb_max_vrfs) ||
555 92 : ((unsigned int)(req->rtr_req.rtr_mac_size) != VR_ETHER_ALEN))
556 0 : return -EINVAL;
557 :
558 92 : return router->vr_bridge_table->algo_add(router->vr_bridge_table, req);
559 : }
560 :
561 : int
562 87 : bridge_entry_del(struct rtable_fspec *fs, struct vr_route_req *req)
563 : {
564 : struct vrouter *router;
565 :
566 87 : if ((unsigned int)(req->rtr_req.rtr_mac_size) > 6 ||
567 87 : (unsigned int)(req->rtr_req.rtr_vrf_id) >= fs->rtb_max_vrfs)
568 0 : return -EINVAL;
569 :
570 87 : router = vrouter_get(req->rtr_req.rtr_rid);
571 87 : if (!router)
572 0 : return -EINVAL;
573 :
574 87 : if (!router->vr_bridge_table ||
575 87 : (unsigned int)req->rtr_req.rtr_vrf_id >= fs->rtb_max_vrfs)
576 0 : return -EINVAL;
577 :
578 87 : return router->vr_bridge_table->algo_del(router->vr_bridge_table, req);
579 : }
580 :
581 : static int
582 53 : bridge_rtb_family_init(struct rtable_fspec *fs, struct vrouter *router)
583 : {
584 : int ret;
585 53 : struct vr_rtable *table = NULL;
586 :
587 53 : if (router->vr_bridge_table)
588 0 : return 0;
589 :
590 53 : if (fs->algo_init) {
591 53 : table = vr_zalloc(sizeof(struct vr_rtable), VR_ROUTE_TABLE_OBJECT);
592 53 : if (!table)
593 0 : return vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, 0);
594 :
595 53 : ret = fs->algo_init(table, fs);
596 53 : if (ret) {
597 0 : vr_free(table, VR_ROUTE_TABLE_OBJECT);
598 0 : return vr_module_error(ret, __FUNCTION__, __LINE__, 0);
599 : }
600 : }
601 :
602 53 : router->vr_bridge_table = table;
603 53 : return 0;
604 : }
605 :
606 : static void
607 53 : bridge_rtb_family_deinit(struct rtable_fspec *fs, struct vrouter *router,
608 : bool soft_reset)
609 : {
610 53 : if (!router->vr_bridge_table) {
611 0 : return;
612 : }
613 :
614 53 : fs->algo_deinit(router->vr_bridge_table, fs, soft_reset);
615 :
616 53 : if (!soft_reset) {
617 53 : vr_free(router->vr_bridge_table, VR_ROUTE_TABLE_OBJECT);
618 53 : router->vr_bridge_table = NULL;
619 : }
620 : }
621 :
622 : void
623 53 : vr_fib_exit(struct vrouter *router, bool soft_reset)
624 : {
625 : unsigned int i;
626 : struct rtable_fspec *fs;
627 :
628 212 : for (i = 0; i < ARRAYSIZE(rtable_families); i++) {
629 159 : fs = &rtable_families[i];
630 159 : fs->rtb_family_deinit(fs, router, soft_reset);
631 : }
632 :
633 53 : return;
634 : }
635 :
636 : int
637 53 : vr_fib_mem(struct vrouter *router)
638 : {
639 53 : int i = 0, ret, size;
640 : struct rtable_fspec *fs;
641 :
642 53 : if (vr_vrfs > VR_MAX_VRFS) {
643 0 : return vr_module_error(-EINVAL, __FUNCTION__, __LINE__, vr_vrfs);
644 : }
645 :
646 53 : router->vr_max_vrfs = vr_vrfs;
647 :
648 53 : size = (int)ARRAYSIZE(rtable_families);
649 212 : for (i = 0; i < size; i++) {
650 159 : fs = &rtable_families[i];
651 159 : fs->rtb_max_vrfs = router->vr_max_vrfs;
652 159 : ret = fs->rtb_family_init(fs, router);
653 159 : if (ret) {
654 0 : vr_module_error(ret, __FUNCTION__, __LINE__, 0);
655 0 : goto exit_init;
656 : }
657 : }
658 :
659 53 : return 0;
660 :
661 0 : exit_init:
662 0 : if (!i)
663 0 : return ret;
664 :
665 0 : for (--i, --fs; i >= 0; i--) {
666 0 : fs->rtb_family_deinit(fs, router, false);
667 : }
668 :
669 0 : return ret;
670 : }
671 :
672 : int
673 53 : vr_fib_init(struct vrouter *router)
674 : {
675 53 : return 0;
676 : }
|