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