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