Line data Source code
1 : /*
2 : * se ts=4;se expandtab
3 : *
4 : * vrouter.c -- virtual router
5 : *
6 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
7 : * Copyright Contributors to the OpenSDN project
8 : */
9 : #include <vr_os.h>
10 : #if defined(__linux__)
11 : #include <linux/version.h>
12 : #endif
13 : #include "vr_types.h"
14 : #include "vr_sandesh.h"
15 : #include "vr_message.h"
16 : #include "vr_cpuid.h"
17 : #include <vr_packet.h>
18 : #include <vr_interface.h>
19 : #include <vr_nexthop.h>
20 : #include <vr_route.h>
21 : #include <vr_mpls.h>
22 : #include <vr_flow.h>
23 : #include <vr_bridge.h>
24 : #include <vr_packet.h>
25 : #include <vr_mirror.h>
26 : #include <vr_vrf_table.h>
27 : #include <vr_vxlan.h>
28 : #include <vr_qos.h>
29 : #include <vr_offloads_dp.h>
30 :
31 : static struct vrouter router;
32 : struct host_os *vrouter_host;
33 : struct vr_offload_ops *offload_ops;
34 : void (*vr_init_cpuid)(struct vr_cpu_type_t *vr_cpu_type) = NULL;
35 : struct vr_cpu_type_t vr_cpu_type = {0};
36 : static bool vr_ipv6_underlay_enabled = false;
37 : bool vr_force_ipv6_underlay_enabled = false;
38 :
39 : extern struct host_os *vrouter_get_host(void);
40 : extern int vr_stats_init(struct vrouter *);
41 : extern void vr_stats_exit(struct vrouter *, bool);
42 : #if defined (__linux__) && defined(__KERNEL__)
43 : extern int vr_shmem_init(void);
44 : #endif
45 :
46 : extern unsigned int vr_flow_entries;
47 : extern unsigned int vr_oflow_entries;
48 : extern unsigned int vr_bridge_entries;
49 : extern unsigned int vr_bridge_oentries;
50 : extern unsigned int vif_bridge_entries;
51 : extern unsigned int vif_bridge_oentries;
52 : extern unsigned int vr_pkt_droplog_bufsz;
53 : extern unsigned int vr_pkt_droplog_buf_en;
54 : extern unsigned int vr_pkt_droplog_sysctl_en;
55 : extern const char *ContrailBuildInfo;
56 : extern unsigned int vr_uncond_close_flow_on_tcp_rst;
57 : extern void *vr_flow_table;
58 : extern void *vr_oflow_table;
59 : extern void *vr_bridge_table;
60 : extern void *vr_obridge_table;
61 : void vrouter_exit(bool);
62 :
63 : volatile bool vr_not_ready = true;
64 :
65 : /* Below hugepage req recv and resp variables are added for debug purpose */
66 : int vr_hpage_req_recv = 0;
67 : int vr_hpage_req_resp = 0;
68 : int vr_hpage_mem_fail = 0;
69 : int vr_genetlink_group_id = 0;
70 :
71 : unsigned int vr_memory_alloc_checks = 0;
72 : unsigned int vr_priority_tagging = 0;
73 :
74 : struct vr_module {
75 : char *mod_name;
76 : int error;
77 : const char *error_func;
78 : int error_line;
79 : int error_data;
80 : int (*init)(struct vrouter *);
81 : void (*exit)(struct vrouter *, bool);
82 : void (*shut)(struct vrouter *);
83 : int (*mem)(struct vrouter *);
84 : };
85 :
86 : struct vr_module *module_under_init;
87 :
88 : static struct vr_module modules[] = {
89 : {
90 : .mod_name = "Stats",
91 : .init = vr_stats_init,
92 : .exit = vr_stats_exit,
93 : },
94 : {
95 : .mod_name = "Nexthop",
96 : .init = vr_nexthop_init,
97 : .exit = vr_nexthop_exit,
98 : },
99 : {
100 : .mod_name = "Fib",
101 : .init = vr_fib_init,
102 : .mem = vr_fib_mem,
103 : .exit = vr_fib_exit,
104 : },
105 : {
106 : .mod_name = "Mpls",
107 : .init = vr_mpls_init,
108 : .exit = vr_mpls_exit,
109 : },
110 : {
111 : .mod_name = "Flow",
112 : .init = vr_flow_init,
113 : .mem = vr_flow_mem,
114 : .exit = vr_flow_exit,
115 : },
116 : {
117 : .mod_name = "Mirror",
118 : .init = vr_mirror_init,
119 : .exit = vr_mirror_exit,
120 : },
121 : {
122 : .mod_name = "Vxlan",
123 : .init = vr_vxlan_init,
124 : .exit = vr_vxlan_exit,
125 : },
126 : {
127 : .mod_name = "QOS",
128 : .init = vr_qos_init,
129 : .exit = vr_qos_exit,
130 : },
131 : {
132 : .mod_name = "Offloads",
133 : .init = vr_offloads_init,
134 : .exit = vr_offloads_exit,
135 : },
136 : {
137 : .mod_name = "Vrf",
138 : .init = vr_vrf_table_init,
139 : .exit = vr_vrf_table_exit,
140 : },
141 : {
142 : .mod_name = "Interface",
143 : .init = vr_interface_init,
144 : .exit = vr_interface_exit,
145 : .shut = vr_interface_shut,
146 : },
147 : };
148 :
149 :
150 : #define VR_NUM_MODULES (sizeof(modules) / sizeof(modules[0]))
151 : /*
152 : * TODO For BSD we turn off all performance tweaks for now, it will
153 : * be implemented later.
154 : */
155 : /*
156 : * Enable changes for better performance
157 : */
158 : #if defined(__linux__)
159 : int vr_perfr = 1; /* GRO */
160 : int vr_perfs = 1; /* segmentation in software */
161 : #endif
162 :
163 : /*
164 : * Enable MPLS over UDP globally
165 : */
166 : int vr_mudp = 0;
167 :
168 : /*
169 : * TCP MSS adjust settings
170 : */
171 : #if defined(__linux__)
172 : int vr_from_vm_mss_adj = 1; /* adjust TCP MSS on packets from VM */
173 : int vr_to_vm_mss_adj = 1; /* adjust TCP MSS on packet sent to VM */
174 : #endif
175 : /*
176 : * Following sysctls are to enable RPS. Based on empirical results,
177 : * performing RPS immediately after packets arrive on a physical interface
178 : * gives the best bidirectional throughput (as opposed to performing
179 : * RPS after pulling inner headers on the CPU core which received the
180 : * interrupt from the physical interface). This is probably because
181 : * more work can happen in parallel on multiple cores in the former case.
182 : * So, vr_perfr1 is set to 0 and vr_perfr3 is set to 1. vr_perfr2 is always
183 : * set as the vhost thread is usually scheduled on the CPU which received
184 : * the packet after GRO. Setting vr_perfr2 allows us to influence the
185 : * scheduling of the vhost thread to some extent (otherwise the scheduler
186 : * can sometimes make sub-optimal choices such as scheduling it on the CPU
187 : * which receives interrupts from the physical interface). vrouter ensures
188 : * that the receive processing happens on multiple cores which are in the
189 : * same NUMA node as the physical interface i.e. the CPU core which receives
190 : * packets from the physical interface is different from the CPU core which
191 : * does vrouter RX processing. A third CPU core does GRO processing (assuming
192 : * that enough cores are available). Also, hyper-thread siblings of the
193 : * above 3 cores are not used by vrouter for RX processing.
194 : */
195 : #if defined(__linux__)
196 :
197 : int vr_perfr1 = 0; /* RPS after pulling inner headers */
198 : int vr_perfr2 = 1; /* RPS after GRO on pkt1 interface */
199 : int vr_perfr3 = 1; /* RPS from physical interface rx handler */
200 : int vr_perfp = 1; /* pull inner headers, faster version */
201 :
202 : int vr_use_linux_br = 0; /* nop if netdev_rx_handler_register() is used */
203 :
204 : #endif
205 : /*
206 : * Following sysctls can be set if vrouter shouldn't pick a CPU for RPS
207 : * core based on a hash of the received packet. Turned off by default.
208 : */
209 : int vr_perfq1 = 0; /* CPU to send packets to if vr_perfr1 is 1 */
210 : int vr_perfq2 = 0; /* CPU to send packets to if vr_perfr2 is 1 */
211 : int vr_perfq3 = 0; /* CPU to send packets to if vr_perfr3 is 1 */
212 :
213 : /* Should NIC perform checksum offload for outer UDP header? */
214 : int vr_udp_coff = 0;
215 :
216 : int
217 0 : vr_module_error(int error, const char *func,
218 : int line, int mod_specific)
219 : {
220 0 : struct vr_module *module = module_under_init;
221 :
222 : /*
223 : * set the error only if it was not set earlier. sometimes, the module
224 : * init can call functions which fail and set the error. In those cases,
225 : * for the sake of consistency, the module init should also be able to
226 : * call this function without overwriting the set error data
227 : */
228 0 : if (module && !module->error) {
229 0 : module->error = error;
230 0 : module->error_func = func;
231 0 : module->error_line = line;
232 0 : module->error_data = mod_specific;
233 : }
234 :
235 0 : return error;
236 : }
237 :
238 : static void
239 0 : vr_module_debug_dump(void)
240 : {
241 0 : struct vr_module *module = module_under_init;
242 :
243 0 : if (!module)
244 0 : return;
245 :
246 0 : vr_printf("vrouter (%s): Init failed at %s:%d with return %d (data %d)\n",
247 : module->mod_name, module->error_func, module->error_line,
248 : module->error, module->error_data);
249 :
250 : /* reset error data */
251 0 : module->error = 0;
252 0 : module->error_func = NULL;
253 0 : module->error_line = -1;
254 0 : module->error_data = 0;
255 :
256 0 : return;
257 : }
258 :
259 : struct vrouter *
260 1969749792 : vrouter_get(unsigned int vr_id)
261 : {
262 1969749792 : return &router;
263 : }
264 :
265 : unsigned int
266 332 : vrouter_generation_num_get(struct vrouter *router)
267 : {
268 332 : return ++router->vr_generation_num;
269 : }
270 :
271 : static void
272 0 : vrouter_ops_destroy(vrouter_ops *req)
273 : {
274 0 : if (!req)
275 0 : return;
276 :
277 0 : if (req->vo_build_info) {
278 0 : vr_free(req->vo_build_info, VR_BUILD_INFO_OBJECT);
279 0 : req->vo_build_info = NULL;
280 : }
281 :
282 0 : if (req->vo_log_type_enable) {
283 0 : vr_free(req->vo_log_type_enable, VR_LOG_TYPES_OBJECT);
284 0 : req->vo_log_type_enable = NULL;
285 : }
286 :
287 0 : vr_free(req, VR_VROUTER_REQ_OBJECT);
288 :
289 0 : return;
290 : }
291 :
292 : static vrouter_ops *
293 0 : vrouter_ops_get(void)
294 : {
295 : vrouter_ops *req;
296 :
297 0 : req = vr_zalloc(sizeof(*req), VR_VROUTER_REQ_OBJECT);
298 0 : if (!req)
299 0 : return NULL;
300 :
301 0 : req->vo_build_info = vr_zalloc(strlen(ContrailBuildInfo) + 1,
302 : VR_BUILD_INFO_OBJECT);
303 0 : if (!req->vo_build_info) {
304 0 : vr_free(req, VR_VROUTER_REQ_OBJECT);
305 0 : return NULL;
306 : }
307 :
308 0 : return req;
309 : }
310 :
311 : static void
312 0 : vrouter_ops_get_process(void *s_req)
313 : {
314 0 : int ret = 0;
315 : struct vrouter *router;
316 0 : vrouter_ops *req = (vrouter_ops *)s_req;
317 0 : vrouter_ops *resp = NULL;
318 :
319 0 : if (req->h_op != SANDESH_OP_GET) {
320 0 : ret = -EOPNOTSUPP;
321 0 : goto generate_response;
322 : }
323 :
324 0 : router = vrouter_get(req->vo_rid);
325 0 : if (!router) {
326 0 : ret = -EINVAL;
327 0 : goto generate_response;
328 : }
329 :
330 0 : resp = vrouter_ops_get();
331 0 : if (!resp) {
332 0 : ret = -ENOMEM;
333 0 : goto generate_response;
334 : }
335 :
336 : /* Startup command line parameters */
337 0 : resp->vo_interfaces = router->vr_max_interfaces;
338 0 : resp->vo_vrfs = router->vr_max_vrfs;
339 0 : resp->vo_mpls_labels = router->vr_max_labels;
340 0 : resp->vo_nexthops = router->vr_max_nexthops;
341 0 : resp->vo_bridge_entries = vr_bridge_entries;
342 0 : resp->vo_oflow_bridge_entries = vr_bridge_oentries;
343 0 : resp->vo_flow_entries = vr_flow_entries;
344 0 : resp->vo_oflow_entries = vr_oflow_entries;
345 0 : resp->vo_mirror_entries = router->vr_max_mirror_indices;
346 0 : resp->vo_vif_bridge_entries = vif_bridge_entries;
347 0 : resp->vo_vif_oflow_bridge_entries = vif_bridge_oentries;
348 0 : resp->vo_pkt_droplog_bufsz = vr_pkt_droplog_bufsz;
349 0 : resp->vo_pkt_droplog_buf_en = vr_pkt_droplog_buf_en;
350 :
351 : /* Runtime parameters adjustable via sysctl or the vrouter utility */
352 0 : resp->vo_perfr = vr_perfr;
353 0 : resp->vo_perfs = vr_perfs;
354 0 : resp->vo_from_vm_mss_adj = vr_from_vm_mss_adj;
355 0 : resp->vo_to_vm_mss_adj = vr_to_vm_mss_adj;
356 0 : resp->vo_perfr1 = vr_perfr1;
357 0 : resp->vo_perfr2 = vr_perfr2;
358 0 : resp->vo_perfr3 = vr_perfr3;
359 0 : resp->vo_perfp = vr_perfp;
360 0 : resp->vo_perfq1 = vr_perfq1;
361 0 : resp->vo_perfq2 = vr_perfq2;
362 0 : resp->vo_perfq3 = vr_perfq3;
363 0 : resp->vo_udp_coff = vr_udp_coff;
364 0 : resp->vo_flow_hold_limit = vr_flow_hold_limit;
365 0 : resp->vo_mudp = vr_mudp;
366 0 : resp->vo_packet_dump = 0;
367 0 : resp->vo_pkt_droplog_en = vr_pkt_droplog_sysctl_en;
368 0 : resp->vo_pkt_droplog_min_en = vr_pkt_droplog_min_sysctl_en;
369 0 : resp->vo_uncond_close_flow_on_tcp_rst = vr_uncond_close_flow_on_tcp_rst;
370 0 : resp->vo_genetlink_group_id = vr_genetlink_group_id;
371 :
372 0 : if(vr_get_dump_packets != NULL) {
373 0 : resp->vo_packet_dump = vr_get_dump_packets();
374 : }
375 :
376 : /* Build info */
377 0 : memcpy(resp->vo_build_info, ContrailBuildInfo,
378 0 : strlen(ContrailBuildInfo)+1);
379 :
380 : /* Logging entries */
381 0 : resp->vo_log_level = vr_get_log_level();
382 0 : resp->vo_log_type_enable =
383 0 : vr_get_enabled_log_types(&resp->vo_log_type_enable_size);
384 :
385 :
386 : /* Used entries */
387 0 : resp->vo_flow_used_entries =
388 0 : vr_flow_table_used_total_entries(router);
389 0 : resp->vo_flow_used_oentries =
390 0 : vr_flow_table_used_oflow_entries(router);
391 :
392 0 : resp->vo_bridge_used_entries =
393 0 : vr_bridge_table_used_total_entries(router);
394 0 : resp->vo_bridge_used_oentries =
395 0 : vr_bridge_table_used_oflow_entries(router);
396 :
397 0 : vr_flow_get_burst_params(router, &resp->vo_burst_tokens,
398 0 : &resp->vo_burst_interval, &resp->vo_burst_step);
399 :
400 0 : resp->vo_memory_alloc_checks = vr_memory_alloc_checks;
401 0 : resp->vo_priority_tagging = vr_priority_tagging;
402 :
403 0 : req = resp;
404 0 : generate_response:
405 0 : if (ret)
406 0 : req = NULL;
407 :
408 0 : vr_message_response(VR_VROUTER_OPS_OBJECT_ID, req, ret, false);
409 0 : if (resp)
410 0 : vrouter_ops_destroy(resp);
411 :
412 0 : return;
413 : }
414 :
415 : /**
416 : * A handler for control messages.
417 : *
418 : * Currently logging control and runtime parameters are supported.
419 : * Setting runtime parameters is also possible via sysctl.
420 : *
421 : * @param s_req Received request to be processed.
422 : */
423 : static void
424 0 : vrouter_ops_add_process(void *s_req)
425 : {
426 : int i;
427 :
428 0 : vrouter_ops *req = (vrouter_ops *)s_req;
429 :
430 : /* Log levels */
431 0 : if (req->vo_log_level)
432 0 : vr_set_log_level(req->vo_log_level);
433 :
434 0 : if (req->vo_log_type_enable_size)
435 0 : for (i = 0; i < req->vo_log_type_enable_size; ++i)
436 0 : vr_set_log_type(req->vo_log_type_enable[i], 1);
437 :
438 0 : if (req->vo_log_type_disable_size)
439 0 : for (i = 0; i < req->vo_log_type_disable_size; ++i)
440 0 : vr_set_log_type(req->vo_log_type_disable[i], 0);
441 :
442 : /* Runtime parameters */
443 0 : if (req->vo_packet_dump != -1 && vr_set_dump_packets != NULL)
444 0 : vr_set_dump_packets(req->vo_packet_dump);
445 0 : if (req->vo_perfr != -1)
446 0 : vr_perfr = req->vo_perfr;
447 0 : if (req->vo_perfs != -1)
448 0 : vr_perfs = req->vo_perfs;
449 0 : if (req->vo_from_vm_mss_adj != -1)
450 0 : vr_from_vm_mss_adj = req->vo_from_vm_mss_adj;
451 0 : if (req->vo_to_vm_mss_adj != -1)
452 0 : vr_to_vm_mss_adj = req->vo_to_vm_mss_adj;
453 0 : if (req->vo_perfr1 != -1)
454 0 : vr_perfr1 = req->vo_perfr1;
455 0 : if (req->vo_perfr2 != -1)
456 0 : vr_perfr2 = req->vo_perfr2;
457 0 : if (req->vo_perfr3 != -1)
458 0 : vr_perfr3 = req->vo_perfr3;
459 0 : if (req->vo_perfp != -1)
460 0 : vr_perfp = req->vo_perfp;
461 0 : if (req->vo_perfq1 != -1)
462 0 : vr_perfq1 = req->vo_perfq1;
463 0 : if (req->vo_perfq2 != -1)
464 0 : vr_perfq2 = req->vo_perfq2;
465 0 : if (req->vo_perfq3 != -1)
466 0 : vr_perfq3 = req->vo_perfq3;
467 0 : if (req->vo_udp_coff != -1)
468 0 : vr_udp_coff = req->vo_udp_coff;
469 0 : if (req->vo_flow_hold_limit != -1)
470 0 : vr_flow_hold_limit = (unsigned int)req->vo_flow_hold_limit;
471 0 : if (req->vo_mudp != -1)
472 0 : vr_mudp = req->vo_mudp;
473 0 : vr_flow_set_burst_params(vrouter_get(req->vo_rid), req->vo_burst_tokens,
474 : req->vo_burst_interval, req->vo_burst_step);
475 :
476 0 : vr_priority_tagging = req->vo_priority_tagging;
477 :
478 : /* Neither of currently called functions signals an error. Just send OK
479 : * response here for now. */
480 0 : vr_send_response(0);
481 0 : }
482 :
483 : void
484 53 : vrouter_exit(bool soft_reset)
485 : {
486 : int i;
487 :
488 636 : for (i = 0; i < (int)VR_NUM_MODULES; i++)
489 583 : if (modules[i].shut)
490 53 : modules[i].shut(&router);
491 :
492 : /* Mark that vrouter is no more ready as shut is already done */
493 53 : vr_not_ready = true;
494 :
495 : /* Flush the previous ashynchronous events, before init */
496 53 : if (vr_soft_reset)
497 53 : vr_soft_reset(&router);
498 :
499 636 : for (i = VR_NUM_MODULES - 1; i >= 0; --i) {
500 583 : modules[i].exit(&router, soft_reset);
501 : }
502 :
503 : /*
504 : * This is necessary on operating systems that don't
505 : * unload the binary on exit.
506 : * When soft reset is happening we must not reinitialize
507 : * vrouter struct.
508 : */
509 53 : if (!soft_reset) {
510 53 : memset(&router, 0, sizeof(router));
511 : }
512 :
513 53 : return;
514 : }
515 :
516 : int
517 53 : vrouter_init(void)
518 : {
519 : unsigned int i;
520 : int ret;
521 :
522 : /* init CPU id struct*/
523 53 : if (vr_init_cpuid != NULL)
524 53 : vr_init_cpuid(&vr_cpu_type);
525 :
526 53 : vrouter_host = vrouter_get_host();
527 53 : if (!vrouter_host && (ret = -ENOMEM))
528 0 : goto init_fail;
529 :
530 636 : for (i = 0; i < VR_NUM_MODULES; i++) {
531 583 : module_under_init = &modules[i];
532 583 : ret = modules[i].init(&router);
533 583 : if (ret) {
534 0 : vr_printf("vrouter module %u init error (%d)\n", i, ret);
535 0 : goto init_fail;
536 : }
537 : // actually, this is not executed in the linux kernel mode
538 : // in most cases
539 583 : if (vr_hpage_mem_fail || !vr_huge_page_config) {
540 583 : if (modules[i].mem) {
541 106 : ret = modules[i].mem(&router);
542 106 : if (ret) {
543 0 : vr_printf("vrouter module %u mem error (%d)\n", i, ret);
544 0 : goto init_fail;
545 : }
546 : }
547 : }
548 : }
549 53 : vr_hpage_mem_fail = 0;
550 53 : module_under_init = NULL;
551 53 : vr_not_ready = false;
552 53 : return 0;
553 :
554 0 : init_fail:
555 0 : vrouter_exit(false);
556 0 : vr_module_debug_dump();
557 0 : module_under_init = NULL;
558 :
559 0 : return ret;
560 : }
561 :
562 : static int
563 0 : vrouter_soft_reset(void)
564 : {
565 0 : int ret = 0;
566 0 : vrouter_exit(true);
567 0 : ret = vrouter_init();
568 0 : if (!ret)
569 0 : ret = vr_offload_soft_reset();
570 0 : return ret;
571 : }
572 :
573 : void
574 0 : vrouter_ops_process(void *s_req)
575 : {
576 : int ret;
577 :
578 0 : vrouter_ops *ops = (vrouter_ops *)s_req;
579 :
580 0 : switch (ops->h_op) {
581 0 : case SANDESH_OP_RESET:
582 0 : vr_printf("vrouter soft reset start\n");
583 0 : ret = vrouter_soft_reset();
584 0 : vr_printf("vrouter soft reset done (%d)\n", ret);
585 0 : break;
586 :
587 0 : case SANDESH_OP_GET:
588 0 : vrouter_ops_get_process(s_req);
589 0 : return;
590 :
591 0 : case SANDESH_OP_ADD:
592 0 : vrouter_ops_add_process(s_req);
593 0 : return;
594 :
595 0 : default:
596 0 : ret = -EOPNOTSUPP;
597 : }
598 :
599 0 : vr_send_response(ret);
600 :
601 0 : return;
602 : }
603 :
604 0 : static int vr_shmem_open(const struct vrouter *router) {
605 : #if defined (__linux__) && defined(__KERNEL__)
606 : if (router->vr_flow_table != NULL &&
607 : router->vr_bridge_table != NULL) {
608 : printk ("tables are in memory\n");
609 : return vr_shmem_init();
610 : }
611 : return -1;
612 : #endif
613 0 : return 0;
614 : }
615 :
616 : void
617 0 : vr_hugepage_config_process(void *s_req)
618 : {
619 0 : int i, ret = -EEXIST, mret = 0;
620 : vr_hugepage_config hcfg_resp;
621 0 : vr_hugepage_config *req= (vr_hugepage_config *)s_req;
622 0 : struct vrouter *router = vrouter_get(0);
623 :
624 : /* Debug purpose: Increment below variable when we get hugepage req from agent */
625 0 : vr_hpage_req_recv++;
626 :
627 : /* Only addition of huge pages is supported */
628 0 : if (req->vhp_op != SANDESH_OP_ADD) {
629 0 : vr_send_response(-EOPNOTSUPP);
630 0 : return;
631 : }
632 :
633 : /* Invoke huge page configuration only if a segment exists */
634 0 : if (vr_huge_page_config) {
635 0 : ret = vr_huge_page_config(req->vhp_mem, req->vhp_mem_size,
636 0 : req->vhp_psize, req->vhp_psize_size,
637 0 : req->vhp_mem_sz, req->vhp_mem_sz_size,
638 : req->vhp_file_paths, req->vhp_file_path_sz);
639 : }
640 :
641 0 : if (ret != -EEXIST) {
642 0 : for (i = 0; i < (int)VR_NUM_MODULES; i++) {
643 0 : if (modules[i].mem) {
644 0 : mret = modules[i].mem(router);
645 0 : if (mret)
646 0 : break;
647 : }
648 : }
649 : }
650 :
651 0 : memset(&hcfg_resp, 0, sizeof(hcfg_resp));
652 0 : hcfg_resp.vhp_op = req->vhp_op;
653 :
654 : /*
655 : * If we fail to allocate memory both in huge pages and as well
656 : * regular respond with VR_HPAGE_CFG_RESP_MEM_FAILURE. Return status
657 : * in vrouter_response would be an error value. If memory allocation
658 : * succeds in either the huge pages or regular, return status is
659 : * going to be "0" and response code gives the details of the
660 : * allocation
661 : */
662 :
663 0 : switch (ret) {
664 0 : case 0:
665 0 : if (!mret)
666 0 : hcfg_resp.vhp_resp = VR_HPAGE_CFG_RESP_HPAGE_SUCCESS;
667 0 : break;
668 :
669 0 : case -EINVAL:
670 0 : if (!mret) {
671 0 : hcfg_resp.vhp_resp = VR_HPAGE_CFG_RESP_INVALID_ARG_MEM_INITED;
672 0 : ret = 0;
673 : }
674 0 : break;
675 :
676 0 : case -EEXIST:
677 0 : hcfg_resp.vhp_resp = VR_HPAGE_CFG_RESP_MEM_ALREADY_INITED;
678 0 : break;
679 :
680 0 : case -ENOMEM:
681 0 : if (!mret) {
682 0 : hcfg_resp.vhp_resp = VR_HPAGE_CFG_RESP_HPAGE_FAILURE_MEM_INITED;
683 0 : ret = 0;
684 : }
685 0 : break;
686 :
687 0 : case -E2BIG:
688 0 : if (!mret) {
689 0 : hcfg_resp.vhp_resp = VR_HPAGE_CFG_RESP_HPAGE_PARTIAL_SUCCESS;
690 0 : ret = 0;
691 : }
692 0 : break;
693 :
694 0 : default:
695 0 : ret = -EINVAL;
696 0 : break;
697 : }
698 :
699 0 : if (mret) {
700 0 : hcfg_resp.vhp_resp = VR_HPAGE_CFG_RESP_MEM_FAILURE;
701 0 : ret = mret;
702 : /* cleaning up partially allocated memory. */
703 0 : for (i = 0; i < (int)VR_NUM_MODULES; i++) {
704 0 : if (modules[i].mem) {
705 0 : modules[i].exit(router, false);
706 : }
707 : }
708 0 : vr_hpage_mem_fail = mret;
709 : }
710 :
711 0 : if (ret == 0) {
712 0 : ret = vr_shmem_open(router);
713 0 : if (ret != 0) {
714 0 : hcfg_resp.vhp_resp = VR_HPAGE_CFG_RESP_SHMEM_FAILURE;
715 : }
716 : }
717 :
718 : /* Debug purpose: Increment below variable before sending response */
719 0 : vr_hpage_req_resp++;
720 0 : vr_printf("Huge page req_recv_cntr:%d resp_cntr:%d resp: %d ret: %d\n", vr_hpage_req_recv,
721 : vr_hpage_req_resp, hcfg_resp.vhp_resp, ret);
722 :
723 0 : vr_message_response(VR_HPAGE_CFG_OBJECT_ID, &hcfg_resp, ret,
724 : false);
725 :
726 0 : return;
727 : }
728 :
729 : bool
730 13 : vr_is_ipv6_underlay_enabled(void)
731 : {
732 13 : return vr_ipv6_underlay_enabled ||
733 : vr_force_ipv6_underlay_enabled;
734 : }
735 :
736 : void
737 9 : vr_set_ipv6_underlay_enabled(void)
738 : {
739 9 : vr_ipv6_underlay_enabled = true;
740 9 : }
|