Line data Source code
1 : /*
2 : * nl_util.c -- netlink utility functions common for all the utilities
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : */
6 : #include <stdio.h>
7 : #include <stdlib.h>
8 : #include <unistd.h>
9 : #include <string.h>
10 : #include <stdbool.h>
11 : #include <errno.h>
12 : #include <stdlib.h>
13 : #include <assert.h>
14 : #include <errno.h>
15 :
16 : #if defined(__linux__)
17 : #include <asm/types.h>
18 : #include <sys/socket.h>
19 : #include <linux/netlink.h>
20 : #include <linux/rtnetlink.h>
21 : #include <linux/genetlink.h>
22 : #include <linux/sockios.h>
23 : #include <linux/dcbnl.h>
24 : #include <linux/socket.h>
25 : #endif
26 :
27 : #include <stdint.h>
28 : #include <net/if.h>
29 : #include <netinet/in.h>
30 : #include "vr_types.h"
31 : #include "nl_util.h"
32 : #include "vr_genetlink.h"
33 : #include "vr_os.h"
34 :
35 : extern struct nl_response *nl_parse_gen(struct nl_client *);
36 :
37 : uint16_t vr_netlink_port = VR_DEF_NETLINK_PORT;
38 : char *vr_socket_dir = VR_DEF_SOCKET_DIR;
39 : struct nl_sandesh_callbacks nl_cb;
40 :
41 : void
42 0 : vrouter_ops_process(void *s_req)
43 : {
44 0 : if (nl_cb.vrouter_ops_process) {
45 0 : nl_cb.vrouter_ops_process(s_req);
46 : }
47 0 : }
48 :
49 : void
50 25 : vr_nexthop_req_process(void *s_req)
51 : {
52 25 : if (nl_cb.vr_nexthop_req_process) {
53 25 : nl_cb.vr_nexthop_req_process(s_req);
54 : }
55 25 : }
56 :
57 :
58 : void
59 0 : vr_flow_req_process(void *s_req)
60 : {
61 0 : if (nl_cb.vr_flow_req_process) {
62 0 : nl_cb.vr_flow_req_process(s_req);
63 : }
64 0 : }
65 :
66 : void
67 322 : vr_flow_response_process(void *s_req)
68 : {
69 322 : if (nl_cb.vr_flow_response_process) {
70 322 : nl_cb.vr_flow_response_process(s_req);
71 : }
72 322 : }
73 :
74 : void
75 13 : vr_flow_table_data_process(void *s_req)
76 : {
77 13 : if (nl_cb.vr_flow_table_data_process) {
78 13 : nl_cb.vr_flow_table_data_process(s_req);
79 : }
80 13 : }
81 :
82 : void
83 331 : vr_route_req_process(void *s_req)
84 : {
85 331 : if (nl_cb.vr_route_req_process) {
86 331 : nl_cb.vr_route_req_process(s_req);
87 : }
88 331 : }
89 :
90 : void
91 163 : vr_interface_req_process(void *s_req)
92 : {
93 163 : if (nl_cb.vr_interface_req_process) {
94 163 : nl_cb.vr_interface_req_process(s_req);
95 : }
96 163 : }
97 :
98 : void
99 1 : vr_mpls_req_process(void *s_req)
100 : {
101 1 : if (nl_cb.vr_mpls_req_process) {
102 1 : nl_cb.vr_mpls_req_process(s_req);
103 : }
104 1 : }
105 :
106 : void
107 1 : vr_mirror_req_process(void *s_req)
108 : {
109 1 : if (nl_cb.vr_mirror_req_process) {
110 1 : nl_cb.vr_mirror_req_process(s_req);
111 : }
112 1 : }
113 :
114 : void
115 0 : vr_vrf_req_process(void *s_req)
116 : {
117 0 : if (nl_cb.vr_vrf_req_process) {
118 0 : nl_cb.vr_vrf_req_process(s_req);
119 : }
120 0 : }
121 :
122 : void
123 2862 : vr_response_process(void *s_req)
124 : {
125 2862 : if (nl_cb.vr_response_process) {
126 2861 : nl_cb.vr_response_process(s_req);
127 : }
128 2862 : }
129 :
130 :
131 : void
132 0 : vr_vrf_assign_req_process(void *s_req)
133 : {
134 0 : if (nl_cb.vr_vrf_assign_req_process) {
135 0 : nl_cb.vr_vrf_assign_req_process(s_req);
136 : }
137 0 : }
138 :
139 : void
140 0 : vr_vrf_stats_req_process(void *s_req)
141 : {
142 0 : if (nl_cb.vr_vrf_stats_req_process) {
143 0 : nl_cb.vr_vrf_stats_req_process(s_req);
144 : }
145 0 : }
146 :
147 : void
148 0 : vr_pkt_drop_log_req_process(void *s_req)
149 : {
150 0 : if (nl_cb.vr_pkt_drop_log_req_process) {
151 0 : nl_cb.vr_pkt_drop_log_req_process(s_req);
152 : }
153 0 : }
154 :
155 : void
156 1 : vr_info_req_process(void *s_req)
157 : {
158 1 : if (nl_cb.vr_info_req_process) {
159 1 : nl_cb.vr_info_req_process(s_req);
160 : }
161 1 : }
162 : void
163 11 : vr_drop_stats_req_process(void *s_req)
164 : {
165 11 : if (nl_cb.vr_drop_stats_req_process) {
166 11 : nl_cb.vr_drop_stats_req_process(s_req);
167 : }
168 11 : }
169 :
170 : void
171 1 : vr_vxlan_req_process(void *s_req)
172 : {
173 1 : if (nl_cb.vr_vxlan_req_process) {
174 1 : nl_cb.vr_vxlan_req_process(s_req);
175 : }
176 1 : }
177 :
178 : void
179 0 : vr_mem_stats_req_process(void *s_req)
180 : {
181 0 : if (nl_cb.vr_mem_stats_req_process) {
182 0 : nl_cb.vr_mem_stats_req_process(s_req);
183 : }
184 0 : }
185 :
186 : void
187 0 : vr_qos_map_req_process(void *s_req)
188 : {
189 0 : if (nl_cb.vr_qos_map_req_process) {
190 0 : nl_cb.vr_qos_map_req_process(s_req);
191 : }
192 0 : }
193 :
194 : void
195 0 : vr_fc_map_req_process(void *s_req)
196 : {
197 0 : if (nl_cb.vr_fc_map_req_process) {
198 0 : nl_cb.vr_fc_map_req_process(s_req);
199 : }
200 0 : }
201 :
202 : void
203 0 : vr_bridge_table_data_process(void *s_req)
204 : {
205 0 : if (nl_cb.vr_bridge_table_data_process) {
206 0 : nl_cb.vr_bridge_table_data_process(s_req);
207 : }
208 0 : }
209 :
210 : void
211 0 : vr_hugepage_config_process(void *s_req)
212 : {
213 0 : if (nl_cb.vr_hugepage_config_process) {
214 0 : nl_cb.vr_hugepage_config_process(s_req);
215 : }
216 0 : }
217 :
218 : struct nl_response *
219 0 : nl_parse_gen_ctrl(struct nl_client *cl)
220 : {
221 : int len;
222 : struct nlattr *nla;
223 : struct genl_ctrl_message *msg;
224 0 : char *buf = cl->cl_buf + cl->cl_buf_offset;
225 0 : struct nl_response *resp = &cl->resp;
226 :
227 0 : msg = (struct genl_ctrl_message *)cl->cl_resp_buf;
228 0 : resp->nl_data = (uint8_t *)(msg);
229 0 : memset(msg, 0, sizeof(*msg));
230 0 : msg->family_id = -1;
231 :
232 0 : len = cl->cl_msg_len - (cl->cl_buf_offset - cl->cl_msg_start);
233 0 : nla = (struct nlattr *)buf;
234 :
235 0 : while (len > 0 && len > NLA_HDRLEN) {
236 0 : if (len < NLA_ALIGN(nla->nla_len))
237 0 : return nl_set_resp_err(cl, -EINVAL);
238 :
239 0 : switch (nla->nla_type) {
240 0 : case CTRL_ATTR_FAMILY_NAME:
241 0 : strncpy(msg->family_name, NLA_DATA(nla), sizeof(msg->family_name) - 1);
242 0 : break;
243 :
244 0 : case CTRL_ATTR_FAMILY_ID:
245 0 : msg->family_id = *(unsigned short *)NLA_DATA(nla);
246 0 : break;
247 :
248 0 : default:
249 0 : break;
250 : }
251 :
252 0 : cl->cl_buf_offset += NLA_ALIGN(nla->nla_len);
253 0 : len -= NLA_ALIGN(nla->nla_len);
254 0 : nla = (struct nlattr *)((char *)nla + NLA_ALIGN(nla->nla_len));
255 : }
256 :
257 0 : return resp;
258 : }
259 :
260 :
261 : struct nl_response *
262 2863 : nl_parse_gen(struct nl_client *cl)
263 : {
264 2863 : char *buf = cl->cl_buf + cl->cl_buf_offset;
265 : struct genlmsghdr *ghdr;
266 2863 : struct nl_response *resp = &cl->resp;
267 : struct nlattr *nla;
268 :
269 2863 : if (cl->cl_buf_len < cl->cl_buf_offset + GENL_HDRLEN)
270 0 : return nl_set_resp_err(cl, -EINVAL);
271 :
272 2863 : ghdr = (struct genlmsghdr *)buf;
273 2863 : cl->cl_buf_offset += GENL_HDRLEN;
274 :
275 2863 : resp->nl_op = ghdr->cmd;
276 2863 : if (resp->nl_type == NL_MSG_TYPE_GEN_CTRL) {
277 0 : return nl_parse_gen_ctrl(cl);
278 : } else {
279 2863 : nla = (struct nlattr *)(cl->cl_buf + cl->cl_buf_offset);
280 2863 : resp->nl_len = nla->nla_len;
281 2863 : cl->cl_buf_offset += NLA_HDRLEN;
282 2863 : resp->nl_data = (uint8_t *)(cl->cl_buf + cl->cl_buf_offset);
283 2863 : return resp;
284 : }
285 : }
286 :
287 : static int
288 300381 : nl_build_sandesh_attr_without_attr_len(struct nl_client *cl)
289 : {
290 300381 : struct nlattr *nla = (struct nlattr *)
291 300381 : ((char *)cl->cl_buf + cl->cl_buf_offset);
292 :
293 300381 : if (cl->cl_buf_offset + NLA_HDRLEN > cl->cl_buf_len)
294 0 : return -ENOMEM;
295 :
296 300381 : nla->nla_len = NLA_HDRLEN;
297 300381 : nla->nla_type = NL_ATTR_VR_MESSAGE_PROTOCOL;
298 300381 : cl->cl_buf_offset += NLA_HDRLEN;
299 :
300 300381 : return 0;
301 : }
302 :
303 : int
304 300381 : nl_build_header(struct nl_client *cl, unsigned char **buf, uint32_t *buf_len)
305 : {
306 : int ret;
307 :
308 300381 : if (!cl->cl_buf)
309 0 : return -EINVAL;
310 :
311 300381 : if (!cl->cl_genl_family_id)
312 0 : return -EINVAL;
313 :
314 300381 : ret = nl_build_nlh(cl, cl->cl_genl_family_id, NLM_F_REQUEST);
315 300381 : if (ret)
316 0 : return ret;
317 :
318 300381 : ret = nl_build_genlh(cl, SANDESH_REQUEST, 0);
319 300381 : if (ret)
320 0 : return ret;
321 :
322 300381 : ret = nl_build_sandesh_attr_without_attr_len(cl);
323 300381 : if (ret)
324 0 : return ret;
325 :
326 300381 : *buf = (unsigned char *)(cl->cl_buf) + cl->cl_buf_offset;
327 300381 : *buf_len = cl->cl_buf_len - cl->cl_buf_offset;
328 :
329 300381 : return 0;
330 : }
331 :
332 : void
333 300213 : nl_update_header(struct nl_client *cl, int data_len)
334 : {
335 : /* First update attribute header len for NLA_SANDESH_ATTR */
336 300213 : struct nlattr *nla = (struct nlattr *)
337 300213 : ((char *)cl->cl_buf + cl->cl_buf_offset - NLA_HDRLEN);
338 :
339 300213 : assert(nla->nla_type == NL_ATTR_VR_MESSAGE_PROTOCOL);
340 300213 : nla->nla_len += data_len;
341 :
342 300213 : cl->cl_buf_offset += data_len;
343 300213 : nl_update_nlh(cl);
344 300213 : }
345 :
346 : int
347 0 : nl_family_name_attr_length(char *family)
348 : {
349 0 : return NLA_HDRLEN + NLA_ALIGN(strlen(family) + 1);
350 : }
351 :
352 : int
353 0 : nl_build_family_name_attr(struct nl_client *cl, char *family)
354 : {
355 : char *buf;
356 : int len;
357 0 : struct nlattr *nla = (struct nlattr *)
358 0 : ((char *)cl->cl_buf + cl->cl_buf_offset);
359 :
360 0 : len = nl_family_name_attr_length(family);
361 0 : if (cl->cl_buf_offset + len > cl->cl_buf_len)
362 0 : return -ENOMEM;
363 :
364 0 : nla->nla_len = len;
365 0 : nla->nla_type = CTRL_ATTR_FAMILY_NAME;
366 0 : cl->cl_buf_offset += NLA_HDRLEN;
367 :
368 0 : buf = (char *)cl->cl_buf + cl->cl_buf_offset;
369 0 : strcpy(buf, family);
370 0 : cl->cl_buf_offset += NLA_ALIGN(strlen(family) + 1);
371 :
372 0 : return 0;
373 : }
374 :
375 :
376 : int
377 0 : nl_build_get_family_id(struct nl_client *cl, char *family)
378 : {
379 : int ret;
380 :
381 0 : if (!cl->cl_buf)
382 0 : return -ENOMEM;
383 :
384 0 : ret = nl_build_nlh(cl, GENL_ID_CTRL, NLM_F_REQUEST);
385 0 : if (ret)
386 0 : return ret;
387 :
388 0 : ret = nl_build_genlh(cl, CTRL_CMD_GETFAMILY, 0);
389 0 : if (ret)
390 0 : return ret;
391 :
392 0 : ret = nl_build_family_name_attr(cl, family);
393 0 : if (ret)
394 0 : return ret;
395 :
396 0 : nl_update_nlh(cl);
397 :
398 0 : return 0;
399 : }
400 :
401 : int
402 303243 : nl_build_genlh(struct nl_client *cl, uint8_t cmd, uint8_t version)
403 : {
404 303243 : struct genlmsghdr *genlh = (struct genlmsghdr *)
405 303243 : ((char *)cl->cl_buf + cl->cl_buf_offset);
406 :
407 303243 : if (cl->cl_buf_offset + GENL_HDRLEN > cl->cl_buf_len)
408 0 : return -ENOMEM;
409 :
410 303243 : genlh->cmd = cmd;
411 303243 : genlh->version = version;
412 303243 : genlh->reserved = 0;
413 :
414 303243 : cl->cl_buf_offset += GENL_HDRLEN;
415 :
416 303243 : return 0;
417 : }
418 :
419 :
420 : struct nl_response *
421 0 : nl_set_resp_err(struct nl_client *cl, int error)
422 : {
423 0 : struct nl_response *resp = (struct nl_response *)cl->cl_resp_buf;
424 :
425 0 : resp->nl_type = NL_MSG_TYPE_ERROR;
426 0 : resp->nl_op = error;
427 0 : return resp;
428 : }
429 :
430 :
431 : void
432 303075 : nl_update_nlh(struct nl_client *cl)
433 : {
434 303075 : struct nlmsghdr *nlh = (struct nlmsghdr *)cl->cl_buf;
435 303075 : nlh->nlmsg_len = cl->cl_msg_len = cl->cl_buf_offset;
436 303075 : }
437 :
438 : int
439 2862 : nl_get_attr_hdr_size()
440 : {
441 2862 : return NLA_HDRLEN;
442 : }
443 :
444 : uint8_t *
445 2862 : nl_get_buf_ptr(struct nl_client *cl)
446 : {
447 2862 : return (uint8_t *)(cl->cl_buf + cl->cl_buf_offset);
448 : }
449 :
450 : uint32_t
451 2862 : nl_get_buf_len(struct nl_client *cl)
452 : {
453 2862 : return cl->cl_buf_len - cl->cl_buf_offset;
454 : }
455 :
456 : void
457 0 : nl_update_attr_len(struct nl_client *cl, int len)
458 : {
459 : struct nlattr *nla;
460 :
461 0 : nla = (struct nlattr *)cl->cl_attr;
462 0 : nla->nla_len += len;
463 0 : cl->cl_buf_offset += len;
464 0 : }
465 :
466 : void
467 2862 : nl_build_attr(struct nl_client *cl, int len, int attr)
468 : {
469 : struct nlattr *nla;
470 :
471 2862 : nla = (struct nlattr *)(cl->cl_buf + cl->cl_buf_offset);
472 2862 : cl->cl_attr = (uint8_t *)nla;
473 2862 : nla->nla_len = NLA_HDRLEN + (len);
474 2862 : nla->nla_type = attr;
475 :
476 : /* Adjust by attribute length */
477 2862 : cl->cl_buf_offset += NLA_HDRLEN + (len);
478 2862 : }
479 :
480 :
481 : int
482 303243 : nl_build_nlh(struct nl_client *cl, uint32_t type, uint32_t flags)
483 : {
484 303243 : struct nlmsghdr *nlh = (struct nlmsghdr *)(cl->cl_buf);
485 :
486 303243 : if (cl->cl_buf_offset + NLMSG_HDRLEN > cl->cl_buf_len)
487 0 : return -ENOMEM;
488 :
489 303243 : nlh->nlmsg_len = cl->cl_buf_len;
490 303243 : nlh->nlmsg_type = type;
491 303243 : nlh->nlmsg_flags = flags;
492 303243 : nlh->nlmsg_seq = cl->cl_seq++;
493 303243 : nlh->nlmsg_pid = cl->cl_id;
494 :
495 303243 : cl->cl_buf_offset = NLMSG_HDRLEN;
496 :
497 303243 : return 0;
498 : }
499 :
500 : void
501 303133 : nl_free(struct nl_client *cl)
502 : {
503 303133 : nl_free_os_specific(cl);
504 :
505 303133 : cl->cl_buf_offset = 0;
506 303133 : cl->cl_buf_len = 0;
507 303133 : if (cl->cl_buf) {
508 303133 : free(cl->cl_buf);
509 303133 : cl->cl_buf = NULL;
510 : }
511 :
512 303133 : cl->cl_resp_buf_len = 0;
513 303133 : if (cl->cl_resp_buf) {
514 2920 : free(cl->cl_resp_buf);
515 2920 : cl->cl_resp_buf = NULL;
516 : }
517 :
518 303133 : cl->cl_recvmsg = NULL;
519 303133 : }
520 :
521 : int
522 2863 : nl_recvmsg(struct nl_client *cl)
523 : {
524 2863 : return cl->cl_recvmsg(cl, false);
525 : }
526 :
527 : int
528 0 : nl_recvmsg_waitall(struct nl_client *cl)
529 : {
530 0 : return cl->cl_recvmsg(cl, true);
531 : }
532 :
533 : void
534 0 : nl_set_buf(struct nl_client *cl, char *buf, unsigned int len)
535 : {
536 0 : if (cl->cl_buf)
537 0 : free(cl->cl_buf);
538 :
539 0 : cl->cl_buf = buf;
540 0 : cl->cl_buf_offset = 0;
541 0 : cl->cl_buf_len = len;
542 0 : cl->cl_msg_len = 0;
543 0 : }
544 :
545 : void
546 0 : nl_set_rcv_len(struct nl_client *cl, unsigned int rcv_len)
547 : {
548 0 : cl->cl_recv_len = rcv_len;
549 0 : cl->cl_buf_offset = 0;
550 0 : cl->cl_msg_len = 0;
551 0 : }
552 :
553 : void
554 0 : nl_set_genl_family_id(struct nl_client *cl, unsigned int family_id)
555 : {
556 0 : cl->cl_genl_family_id = family_id;
557 0 : }
558 :
559 : struct nl_client *
560 2951 : nl_register_client(void)
561 : {
562 : struct nl_client *cl;
563 :
564 2951 : cl = calloc(sizeof(*cl), 1);
565 2951 : if (!cl)
566 0 : return cl;
567 :
568 2951 : cl->cl_buf = calloc(NL_MSG_DEFAULT_SIZE, 1);
569 2951 : if (!cl->cl_buf)
570 0 : goto exit_register;
571 2951 : cl->cl_buf_len = NL_MSG_DEFAULT_SIZE;
572 2951 : cl->cl_resp_buf = malloc(NL_RESP_DEFAULT_SIZE);
573 2951 : if (!cl->cl_resp_buf)
574 0 : goto exit_register;
575 2951 : cl->cl_resp_buf_len = NL_RESP_DEFAULT_SIZE;
576 :
577 2951 : cl->cl_id = 0;
578 2951 : nl_reset_cl_sock(cl);
579 :
580 2951 : return cl;
581 :
582 0 : exit_register:
583 0 : if (cl)
584 0 : nl_free_client(cl);
585 :
586 0 : return NULL;
587 : }
588 :
589 : void
590 2920 : nl_free_client(struct nl_client *cl)
591 : {
592 2920 : nl_free(cl);
593 2920 : free(cl);
594 2920 : }
595 :
596 : int
597 300381 : nl_init_generic_client_req(struct nl_client *cl, int family)
598 : {
599 300381 : memset(cl, 0, sizeof(*cl));
600 300381 : cl->cl_buf = malloc(NL_MSG_DEFAULT_SIZE);
601 300381 : if (!cl->cl_buf)
602 0 : goto exit_register;
603 300381 : cl->cl_buf_len = NL_MSG_DEFAULT_SIZE;
604 300381 : cl->cl_genl_family_id = family;
605 300381 : nl_reset_cl_sock(cl);
606 :
607 300381 : return 1;
608 :
609 0 : exit_register:
610 0 : return 0;
611 : }
612 :
613 : struct nl_response *
614 2863 : nl_parse_reply(struct nl_client *cl)
615 : {
616 2863 : struct nlmsghdr *nlh = (struct nlmsghdr *)(cl->cl_buf + cl->cl_buf_offset);
617 : struct nlmsgerr *err;
618 2863 : struct nl_response *resp = &cl->resp;
619 :
620 2863 : memset(resp, 0, sizeof(*resp));
621 2863 : resp->nl_type = NL_MSG_TYPE_ERROR;
622 2863 : if (cl->cl_buf_offset + NLMSG_HDRLEN > cl->cl_recv_len)
623 0 : return NULL;
624 :
625 2863 : cl->cl_msg_len = nlh->nlmsg_len;
626 2863 : cl->cl_msg_start = cl->cl_buf_offset;
627 2863 : if (cl->cl_msg_len + cl->cl_buf_offset > cl->cl_recv_len)
628 0 : return nl_set_resp_err(cl, -ENOMEM);
629 :
630 2863 : cl->cl_buf_offset += NLMSG_HDRLEN;
631 :
632 2863 : if (nlh->nlmsg_type == NLMSG_DONE) {
633 0 : resp->nl_type = NL_MSG_TYPE_DONE;
634 0 : return resp;
635 : }
636 :
637 2863 : if (nlh->nlmsg_type == NETLINK_GENERIC) {
638 0 : resp->nl_type = NL_MSG_TYPE_GEN_CTRL;
639 0 : resp = nl_parse_gen(cl);
640 0 : return resp;
641 : }
642 :
643 2863 : if (nlh->nlmsg_type == cl->cl_genl_family_id) {
644 2863 : resp->nl_type = NL_MSG_TYPE_FMLY;
645 2863 : resp = nl_parse_gen(cl);
646 2863 : return resp;
647 : }
648 :
649 0 : resp = nl_parse_reply_os_specific(cl);
650 0 : if (resp)
651 0 : return resp;
652 :
653 0 : err = (struct nlmsgerr *)nl_get_buf_ptr(cl);
654 0 : return nl_set_resp_err(cl, err->error);
655 : }
|