Line data Source code
1 : /*
2 : *
3 : * Copyright (c) Juniper Networks, Inc. All rights reserved.
4 : * Copyright Contributors to the OpenSDN project
5 : */
6 :
7 :
8 : #include <stdint.h>
9 : #include <stdio.h>
10 : #include <string.h>
11 :
12 : #include <fcntl.h>
13 : #include <sys/types.h>
14 : #include <sys/stat.h>
15 : #include <sys/mman.h>
16 : #include <sys/sysmacros.h>
17 : #include <sys/socket.h>
18 :
19 : #if defined(__linux__)
20 : #include <linux/netlink.h>
21 : #include <linux/rtnetlink.h>
22 : #include <linux/genetlink.h>
23 : #include <linux/if_ether.h>
24 : #include <linux/sockios.h>
25 : #include <linux/dcbnl.h>
26 : #include <linux/socket.h>
27 : #endif
28 : #include <netinet/tcp.h>
29 : #include <sys/un.h>
30 :
31 : #include <vr_mem.h>
32 : #include <nl_util.h>
33 : #include <ini_parser.h>
34 :
35 : /* This is defined in linux kernel headers (linux/socket.h) */
36 : #if !defined(SOL_NETLINK)
37 : #define SOL_NETLINK 270
38 : #endif
39 :
40 : #define VROUTER_GENETLINK_VROUTER_GROUP_ID 0x4
41 : #define VROUTER_GENETLINK_FAMILY_NAME "vrouter"
42 : #define GENL_ID_VROUTER (NLMSG_MIN_TYPE + 0x10)
43 :
44 : const char *
45 13 : vr_table_map(int major, unsigned int table, const char *table_path, size_t size, void **mem)
46 : {
47 : enum { ERROR_LEN = 1024 };
48 : static char error_msg[ERROR_LEN];
49 :
50 : int fd, ret;
51 : uint16_t dev;
52 :
53 : const char *path;
54 13 : const int platform = get_platform();
55 :
56 13 : if (major < 0) {
57 0 : snprintf(error_msg, ERROR_LEN, "Error: Invalid 'major' value: %d", major);
58 0 : return error_msg;
59 : }
60 :
61 13 : if (table_path) {
62 13 : path = table_path;
63 : } else {
64 0 : switch (table) {
65 0 : case VR_MEM_BRIDGE_TABLE_OBJECT:
66 0 : path = BRIDGE_TABLE_DEV;
67 0 : break;
68 :
69 0 : case VR_MEM_FLOW_TABLE_OBJECT:
70 0 : path = FLOW_TABLE_DEV;
71 0 : break;
72 :
73 0 : default:
74 0 : snprintf(error_msg, ERROR_LEN, "Error: Invalid 'table' value: %u", table);
75 0 : return error_msg;
76 : }
77 :
78 0 : ret = mknod(path, S_IFCHR | O_RDWR, makedev(major, table));
79 0 : if (ret && errno != EEXIST) {
80 0 : goto fail;
81 : }
82 : }
83 :
84 13 : fd = open(path, O_RDONLY | O_SYNC);
85 13 : if (fd < 0) {
86 0 : goto fail;
87 : }
88 :
89 13 : *mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
90 13 : close(fd);
91 :
92 13 : if (*mem == MAP_FAILED) {
93 0 : goto fail;
94 : }
95 :
96 13 : return NULL;
97 :
98 0 : fail:
99 0 : snprintf(error_msg, ERROR_LEN, "%s: %s", path, strerror(errno));
100 0 : return error_msg;
101 : }
102 :
103 : const char *
104 0 : vr_table_unlink(const char *path)
105 : {
106 : enum { ERROR_LEN = 1024 };
107 : static char error_msg[ERROR_LEN];
108 :
109 0 : if (unlink(path) != 0) {
110 0 : if (errno != ENOENT) {
111 0 : snprintf(error_msg, ERROR_LEN,
112 0 : "Error deleting %s. Error <%d>: %s", path, errno, strerror(errno));
113 0 : return error_msg;
114 : }
115 : }
116 :
117 0 : return NULL;
118 : }
119 :
120 : int
121 2951 : nl_socket(struct nl_client *cl, int domain, int type, int protocol)
122 : {
123 2951 : if (cl->cl_sock >= 0)
124 0 : return -EEXIST;
125 :
126 2951 : cl->cl_sock = socket(domain, type, protocol);
127 2951 : if (cl->cl_sock < 0)
128 0 : return cl->cl_sock;
129 :
130 2951 : cl->cl_socket_domain = domain;
131 :
132 2951 : if (type == SOCK_STREAM) {
133 2951 : cl->cl_recvmsg = nl_client_stream_recvmsg;
134 : }
135 : else {
136 0 : cl->cl_recvmsg = nl_client_datagram_recvmsg;
137 : }
138 :
139 2951 : return cl->cl_sock;
140 : }
141 :
142 : int
143 2951 : nl_connect(struct nl_client *cl, uint32_t ip, uint16_t port, int group_id)
144 : {
145 2951 : int group = (group_id == 0) ? VROUTER_GENETLINK_VROUTER_GROUP_ID : group_id;
146 : int ret;
147 :
148 2951 : if (cl->cl_socket_domain == AF_NETLINK) {
149 0 : struct sockaddr_nl *sa = malloc(sizeof(struct sockaddr_nl));
150 :
151 0 : if (!sa)
152 0 : return -1;
153 :
154 0 : memset(sa, 0, sizeof(*sa));
155 0 : sa->nl_family = cl->cl_socket_domain;
156 0 : sa->nl_pid = cl->cl_id;
157 0 : cl->cl_sa = (struct sockaddr *)sa;
158 0 : cl->cl_sa_len = sizeof(*sa);
159 :
160 0 : ret = bind(cl->cl_sock, cl->cl_sa, cl->cl_sa_len);
161 0 : if (ret < 0) {
162 0 : return ret;
163 : }
164 :
165 : /* We join the vrouter netlink broadcast group */
166 0 : ret = setsockopt(cl->cl_sock, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
167 0 : if (ret < 0) {
168 0 : return ret;
169 : }
170 :
171 0 : return 0;
172 : }
173 :
174 2951 : if (cl->cl_socket_domain == AF_INET) {
175 : struct in_addr address;
176 0 : struct sockaddr_in *sa = malloc(sizeof(struct sockaddr_in));
177 0 : if (!sa)
178 0 : return -1;
179 :
180 0 : memset(sa, 0, sizeof(*sa));
181 0 : address.s_addr = htonl(ip);
182 0 : sa->sin_family = cl->cl_socket_domain;
183 0 : sa->sin_addr = address;
184 0 : sa->sin_port = htons(port);
185 0 : cl->cl_sa = (struct sockaddr *)sa;
186 0 : cl->cl_sa_len = sizeof(*sa);
187 :
188 0 : return connect(cl->cl_sock, cl->cl_sa, cl->cl_sa_len);
189 : }
190 2951 : if (cl->cl_socket_domain == AF_UNIX) {
191 2951 : struct sockaddr_un *sa = malloc(sizeof(struct sockaddr_un));
192 2951 : if (!sa)
193 0 : return -1;
194 :
195 2951 : memset(sa, 0, sizeof(*sa));
196 2951 : sa->sun_family = cl->cl_socket_domain;
197 2951 : snprintf(sa->sun_path, sizeof(sa->sun_path), "%s/dpdk_netlink", vr_socket_dir);
198 2951 : cl->cl_sa = (struct sockaddr *)sa;
199 2951 : cl->cl_sa_len = sizeof(*sa);
200 :
201 2951 : return connect(cl->cl_sock, cl->cl_sa, cl->cl_sa_len);
202 : }
203 0 : return 0;
204 : }
205 :
206 : int
207 0 : nl_client_datagram_recvmsg(struct nl_client *cl, bool msg_wait)
208 : {
209 : int ret;
210 : struct msghdr msg;
211 : struct iovec iov;
212 :
213 0 : memset(&msg, 0, sizeof(msg));
214 0 : msg.msg_name = cl->cl_sa;
215 0 : msg.msg_namelen = cl->cl_sa_len;
216 :
217 0 : iov.iov_base = (void *)(cl->cl_buf);
218 0 : iov.iov_len = cl->cl_buf_len;
219 0 : msg.msg_iov = &iov;
220 0 : msg.msg_iovlen = 1;
221 :
222 0 : cl->cl_buf_offset = 0;
223 :
224 0 : if (msg_wait)
225 0 : ret = recvmsg(cl->cl_sock, &msg, MSG_WAITALL);
226 : else
227 0 : ret = recvmsg(cl->cl_sock, &msg, MSG_DONTWAIT);
228 0 : if (ret < 0) {
229 0 : return ret;
230 : }
231 :
232 0 : cl->cl_recv_len = ret;
233 0 : if (cl->cl_recv_len > cl->cl_buf_len)
234 0 : return -EOPNOTSUPP;
235 :
236 0 : return ret;
237 : }
238 :
239 : int
240 2863 : nl_client_stream_recvmsg(struct nl_client *cl, bool msg_wait) {
241 : int ret;
242 : struct msghdr msg;
243 : struct iovec iov;
244 :
245 2863 : memset(&msg, 0, sizeof(msg));
246 :
247 2863 : if (cl->cl_socket_domain != AF_UNIX) {
248 0 : msg.msg_name = cl->cl_sa;
249 0 : msg.msg_namelen = sizeof(cl->cl_sa_len);
250 : }
251 :
252 2863 : iov.iov_base = (void *)(cl->cl_buf);
253 2863 : iov.iov_len = NLMSG_HDRLEN;
254 2863 : msg.msg_iov = &iov;
255 2863 : msg.msg_iovlen = 1;
256 :
257 2863 : cl->cl_buf_offset = 0;
258 :
259 : /* read netlink header and get the lenght of sandesh message */
260 2863 : ret = recvmsg(cl->cl_sock, &msg, 0);
261 2863 : if (ret < 0) {
262 0 : return ret;
263 : }
264 2863 : struct nlmsghdr *nlh = (struct nlmsghdr *)(cl->cl_buf + cl->cl_buf_offset);
265 2863 : uint32_t pending_length = nlh->nlmsg_len - NLMSG_HDRLEN;
266 :
267 : /* read sandesh message */
268 2863 : iov.iov_base = (void *)(cl->cl_buf + NLMSG_HDRLEN);
269 2863 : iov.iov_len = pending_length;
270 2863 : msg.msg_iov = &iov;
271 2863 : msg.msg_iovlen = 1;
272 2863 : ret = recvmsg(cl->cl_sock, &msg, 0);
273 2863 : if (ret < 0) {
274 0 : return ret;
275 : }
276 :
277 2863 : cl->cl_recv_len = nlh->nlmsg_len;
278 2863 : if (cl->cl_recv_len > cl->cl_buf_len)
279 0 : return -EOPNOTSUPP;
280 :
281 2863 : return ret;
282 : }
283 :
284 : int
285 2862 : nl_sendmsg(struct nl_client *cl)
286 : {
287 : struct msghdr msg;
288 : struct iovec iov;
289 :
290 2862 : memset(&msg, 0, sizeof(msg));
291 : #if defined (__linux__)
292 2862 : if (cl->cl_socket_domain != AF_UNIX) {
293 0 : msg.msg_name = cl->cl_sa;
294 0 : msg.msg_namelen = cl->cl_sa_len;
295 : }
296 : #endif
297 :
298 2862 : iov.iov_base = (void *)(cl->cl_buf);
299 2862 : iov.iov_len = cl->cl_buf_offset;
300 :
301 2862 : cl->cl_buf_offset = 0;
302 :
303 2862 : msg.msg_iov = &iov;
304 2862 : msg.msg_iovlen = 1;
305 :
306 2862 : return sendmsg(cl->cl_sock, &msg, 0);
307 : }
308 :
309 : void
310 347705 : nl_free_os_specific(struct nl_client *cl)
311 : {
312 347705 : if (cl->cl_sock >= 0) {
313 2920 : close(cl->cl_sock);
314 2920 : cl->cl_sock = -1;
315 : }
316 :
317 347705 : cl->cl_sa_len = 0;
318 347705 : if (cl->cl_sa) {
319 2920 : free(cl->cl_sa);
320 2920 : cl->cl_sa = NULL;
321 : }
322 347705 : }
323 :
324 : void
325 347908 : nl_reset_cl_sock(struct nl_client *cl)
326 : {
327 347908 : cl->cl_sock = -1;
328 347908 : }
329 :
330 : struct nl_response *
331 0 : nl_parse_reply_os_specific(struct nl_client *cl)
332 : {
333 0 : struct nlmsghdr *nlh = (struct nlmsghdr *)(cl->cl_buf +
334 0 : cl->cl_buf_offset - NLMSG_HDRLEN);
335 0 : struct nl_response *resp = &cl->resp;
336 :
337 0 : if ((nlh->nlmsg_type == RTM_SETDCB) || (nlh->nlmsg_type == RTM_GETDCB)) {
338 0 : resp->nl_type = nlh->nlmsg_type;
339 0 : resp->nl_data = nl_get_buf_ptr(cl);
340 0 : return resp;
341 : }
342 :
343 0 : return NULL;
344 : }
345 :
346 : #if defined(__linux__)
347 : int
348 0 : nl_build_attr_linkinfo(struct nl_client *cl, struct vn_if *ifp)
349 : {
350 : char *link_info_buf;
351 : int len;
352 0 : struct nlattr *nla = (struct nlattr *)
353 0 : ((char *)cl->cl_buf + cl->cl_buf_offset);
354 :
355 0 : len = NLA_HDRLEN + NLA_HDRLEN +
356 0 : NLA_ALIGN(strlen(ifp->if_kind) + 1);
357 :
358 0 : if (cl->cl_buf_offset + len > cl->cl_buf_len)
359 0 : return -ENOMEM;
360 :
361 0 : nla->nla_len = len;
362 0 : nla->nla_type = IFLA_LINKINFO;
363 :
364 0 : link_info_buf = (char *)nla + NLA_HDRLEN;
365 0 : nla = (struct nlattr *)link_info_buf;
366 0 : nla->nla_len = len - NLA_HDRLEN;
367 0 : nla->nla_type = IFLA_INFO_KIND;
368 :
369 0 : link_info_buf += NLA_HDRLEN;
370 0 : strcpy(link_info_buf, ifp->if_kind);
371 :
372 0 : cl->cl_buf_offset += len;
373 :
374 0 : return 0;
375 : }
376 :
377 : int
378 0 : nl_build_attr_ifname(struct nl_client *cl, struct vn_if *ifp)
379 : {
380 : char *if_name_buf;
381 : int len;
382 0 : struct nlattr *nla = (struct nlattr *)
383 0 : ((char *)cl->cl_buf + cl->cl_buf_offset);
384 :
385 0 : len = NLA_HDRLEN + NLA_ALIGN(strlen(ifp->if_name) + 1);
386 0 : if (cl->cl_buf_offset + len > cl->cl_buf_len)
387 0 : return -ENOMEM;
388 :
389 0 : nla->nla_len = len;
390 0 : nla->nla_type = IFLA_IFNAME;
391 :
392 0 : if_name_buf = (char *)nla + NLA_HDRLEN;
393 0 : strcpy(if_name_buf, ifp->if_name);
394 :
395 0 : cl->cl_buf_offset += nla->nla_len;
396 :
397 0 : return 0;
398 : }
399 :
400 : int
401 0 : nl_build_mac_address(struct nl_client *cl, struct vn_if *ifp)
402 : {
403 : int len;
404 : char *mac_buf;
405 0 : struct nlattr *nla = (struct nlattr *)
406 0 : ((char *)cl->cl_buf + cl->cl_buf_offset);
407 :
408 0 : len = NLA_HDRLEN + NLA_ALIGN(6);
409 0 : if (cl->cl_buf_offset + len > cl->cl_buf_len)
410 0 : return -ENOMEM;
411 :
412 0 : nla->nla_len = len;
413 0 : nla->nla_type = IFLA_ADDRESS;
414 :
415 0 : mac_buf = (char *)nla + NLA_HDRLEN;
416 0 : memcpy(mac_buf, ifp->if_mac, sizeof(ifp->if_mac));
417 :
418 0 : cl->cl_buf_offset += nla->nla_len;
419 :
420 0 : return 0;
421 : }
422 :
423 :
424 : int
425 0 : nl_build_ifinfo(struct nl_client *cl, struct vn_if *ifp)
426 : {
427 0 : struct ifinfomsg *ifi_msg = (struct ifinfomsg *)
428 0 : (cl->cl_buf + cl->cl_buf_offset);
429 :
430 0 : if (cl->cl_buf_offset + NLMSG_ALIGN(sizeof(*ifi_msg)) >
431 0 : cl->cl_buf_len)
432 0 : return -ENOMEM;
433 :
434 0 : memset(ifi_msg, 0, sizeof(struct ifinfomsg));
435 0 : cl->cl_buf_offset += NLMSG_ALIGN(sizeof(struct ifinfomsg));
436 :
437 0 : return 0;
438 : }
439 :
440 : int
441 0 : nl_build_if_create_msg(struct nl_client *cl, struct vn_if *ifp, uint8_t ack)
442 : {
443 : int ret;
444 : uint32_t flags;
445 :
446 0 : if (!cl->cl_buf || cl->cl_buf_offset || !ifp)
447 0 : return -EINVAL;
448 :
449 0 : flags = NLM_F_REQUEST | NLM_F_CREATE;
450 0 : if (ack) {
451 0 : flags |= NLM_F_ACK;
452 : }
453 0 : ret = nl_build_nlh(cl, RTM_NEWLINK, flags);
454 0 : if (ret)
455 0 : return ret;
456 :
457 0 : ret = nl_build_ifinfo(cl, ifp);
458 0 : if (ret)
459 0 : return ret;
460 :
461 0 : ret = nl_build_mac_address(cl, ifp);
462 0 : if (ret)
463 0 : return ret;
464 :
465 0 : ret = nl_build_attr_ifname(cl, ifp);
466 0 : if (ret)
467 0 : return ret;
468 :
469 0 : ret = nl_build_attr_linkinfo(cl, ifp);
470 0 : if (ret)
471 0 : return ret;
472 :
473 0 : cl->cl_msg_len = cl->cl_buf_offset;
474 0 : nl_update_nlh(cl);
475 :
476 0 : return 0;
477 : }
478 :
479 : static int
480 0 : nl_build_attr_dcb_set_all(struct nl_client *cl)
481 : {
482 : uint8_t *dst;
483 0 : struct nlattr *nla = (struct nlattr *)nl_get_buf_ptr(cl);
484 :
485 0 : nla->nla_type = DCB_ATTR_SET_ALL;
486 0 : nla->nla_len = NLA_HDRLEN + sizeof(uint8_t);
487 0 : dst = (uint8_t *)nla + NLA_HDRLEN;
488 0 : *dst = 1;
489 :
490 0 : cl->cl_buf_offset += NLA_ALIGN(nla->nla_len);
491 :
492 0 : return 0;
493 : }
494 :
495 : static int
496 0 : nl_build_attr_dcb_state(struct nl_client *cl, uint8_t state)
497 : {
498 : uint8_t *dst;
499 0 : struct nlattr *attr = (struct nlattr *)nl_get_buf_ptr(cl);
500 :
501 0 : attr->nla_len = NLA_HDRLEN + NLA_ALIGN(sizeof(state));
502 0 : attr->nla_type = DCB_ATTR_STATE;
503 :
504 0 : dst = nl_get_buf_ptr(cl) + NLA_HDRLEN;
505 0 : memcpy(dst, &state, sizeof(state));
506 :
507 0 : cl->cl_buf_offset += attr->nla_len;
508 0 : return 0;
509 : }
510 :
511 : static int
512 0 : nl_build_attr_dcb_ifname(struct nl_client *cl, uint8_t *ifname)
513 : {
514 : uint8_t *dst;
515 0 : struct nlattr *attr = (struct nlattr *)nl_get_buf_ptr(cl);
516 :
517 0 : attr->nla_len = NLA_HDRLEN + strlen(ifname) + 1;
518 0 : attr->nla_type = DCB_ATTR_IFNAME;
519 :
520 0 : dst = nl_get_buf_ptr(cl) + NLA_HDRLEN;
521 0 : memcpy(dst, ifname, strlen(ifname));
522 0 : *(dst + strlen(ifname)) = '\0';
523 :
524 0 : cl->cl_buf_offset += NLA_ALIGN(attr->nla_len);
525 0 : return 0;
526 : }
527 :
528 : static int
529 0 : nl_build_attr_set_dcbx(struct nl_client *cl, uint8_t dcbx)
530 : {
531 : uint8_t *dst;
532 0 : struct nlattr *nla = (struct nlattr *)nl_get_buf_ptr(cl);
533 :
534 0 : nla->nla_len = NLA_HDRLEN + NLA_ALIGN(sizeof(uint8_t));
535 0 : nla->nla_type = DCB_ATTR_DCBX;
536 :
537 0 : dst = nl_get_buf_ptr(cl) + NLA_HDRLEN;
538 0 : *dst = dcbx;
539 :
540 0 : cl->cl_buf_offset += nla->nla_len;
541 0 : return 0;
542 : }
543 :
544 : static int
545 0 : nl_build_attr_dcb_get_pgtx(struct nl_client *cl)
546 : {
547 0 : unsigned int len = 0;
548 0 : struct nlattr *nla_p, *nla = (struct nlattr *)nl_get_buf_ptr(cl);
549 :
550 0 : nla_p = nla;
551 0 : nla->nla_len = len = NLA_HDRLEN;
552 0 : nla->nla_type = DCB_ATTR_PG_CFG;
553 0 : len += nla_p->nla_len;
554 :
555 0 : nla_p = (struct nlattr *)((uint8_t *)nla_p + nla_p->nla_len);
556 0 : nla_p->nla_type = DCB_PG_ATTR_TC_ALL;
557 0 : nla_p->nla_len = 2 * NLA_HDRLEN;
558 0 : len += nla_p->nla_len;
559 :
560 0 : nla_p = (struct nlattr *)((uint8_t *)nla_p + NLA_HDRLEN);
561 0 : nla_p->nla_type = DCB_TC_ATTR_PARAM_ALL;
562 0 : nla_p->nla_len = NLA_HDRLEN;
563 0 : len += nla_p->nla_len;
564 :
565 0 : nla_p = (struct nlattr *)((uint8_t *)nla_p + nla_p->nla_len);
566 0 : nla_p->nla_type = DCB_PG_ATTR_BW_ID_ALL;
567 0 : nla_p->nla_len = NLA_HDRLEN;
568 0 : len += nla_p->nla_len;
569 :
570 0 : nla->nla_len = len;
571 0 : cl->cl_buf_offset += len;
572 :
573 0 : return 0;
574 : }
575 :
576 : static int
577 0 : nl_build_attr_dcb_pgtx(struct nl_client *cl, struct priority *p)
578 : {
579 : uint8_t i, j, map, *dst;
580 0 : unsigned int len = 0, tc_attr_len;
581 0 : struct nlattr *nla_p, *tcattr, *nla = (struct nlattr *)nl_get_buf_ptr(cl);
582 :
583 0 : nla_p = nla;
584 0 : nla->nla_len = len = NLA_HDRLEN;
585 0 : nla->nla_type = DCB_ATTR_PG_CFG;
586 :
587 0 : nla_p += 1;
588 0 : for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
589 0 : tcattr = nla_p;
590 0 : tcattr->nla_type = i;
591 0 : tcattr->nla_len = NLA_HDRLEN;
592 :
593 0 : tc_attr_len = 0;
594 :
595 0 : nla_p += 1;
596 0 : nla_p->nla_type = DCB_TC_ATTR_PARAM_STRICT_PRIO;
597 0 : nla_p->nla_len = NLA_HDRLEN + sizeof(uint8_t);
598 0 : dst = (uint8_t *)nla_p + NLA_HDRLEN;
599 0 : *dst = (p->tc_strictness & (1 << (i - DCB_PG_ATTR_TC_0)) ? 1 : 0);
600 0 : tc_attr_len += NLA_ALIGN(nla_p->nla_len);
601 :
602 0 : nla_p = (struct nlattr *)((uint8_t *)nla_p + NLA_ALIGN(nla_p->nla_len));
603 0 : nla_p->nla_len = NLA_HDRLEN + sizeof(uint8_t);
604 0 : nla_p->nla_type = DCB_TC_ATTR_PARAM_PGID;
605 0 : dst = (uint8_t *)nla_p + NLA_HDRLEN;
606 0 : *dst = p->tc_to_group[i - DCB_PG_ATTR_TC_0];
607 0 : tc_attr_len += NLA_ALIGN(nla_p->nla_len);
608 :
609 0 : if (p->tc_bw_pct[i - DCB_PG_ATTR_TC_0]) {
610 0 : nla_p = (struct nlattr *)((uint8_t *)nla_p +
611 0 : NLA_ALIGN(nla_p->nla_len));
612 0 : nla_p->nla_len = NLA_HDRLEN + sizeof(uint8_t);
613 0 : nla_p->nla_type = DCB_TC_ATTR_PARAM_BW_PCT;
614 0 : dst = (uint8_t *)nla_p + NLA_HDRLEN;
615 0 : *dst = p->tc_bw_pct[i - DCB_PG_ATTR_TC_0];
616 0 : tc_attr_len += NLA_ALIGN(nla_p->nla_len);
617 : }
618 :
619 0 : map = 0;
620 0 : for (j = 0; j < sizeof(p->prio_to_tc); j++) {
621 0 : if (p->prio_to_tc[j] == (i - DCB_PG_ATTR_TC_0))
622 0 : map |= (1 << j);
623 : }
624 :
625 0 : nla_p = (struct nlattr *)((uint8_t *)nla_p +
626 0 : NLA_ALIGN(nla_p->nla_len));
627 0 : nla_p->nla_len = NLA_HDRLEN + sizeof(uint8_t);
628 0 : nla_p->nla_type = DCB_TC_ATTR_PARAM_UP_MAPPING;
629 0 : dst = (uint8_t *)nla_p + NLA_HDRLEN;
630 0 : *dst = map;
631 0 : tc_attr_len += NLA_ALIGN(nla_p->nla_len);
632 :
633 0 : tcattr->nla_len += tc_attr_len;
634 0 : len += tcattr->nla_len;
635 0 : nla_p = (struct nlattr *)((uint8_t *)nla_p + NLA_ALIGN(nla_p->nla_len));
636 : }
637 :
638 0 : for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
639 0 : nla_p->nla_type = i;
640 0 : nla_p->nla_len = NLA_HDRLEN + sizeof(uint8_t);
641 0 : dst = (uint8_t *)nla_p + NLA_HDRLEN;
642 0 : *dst = p->prio_group_bw[i - DCB_PG_ATTR_BW_ID_0];
643 0 : len += NLA_ALIGN(nla_p->nla_len);
644 :
645 0 : nla_p = (struct nlattr *)((uint8_t *)nla_p + NLA_ALIGN(nla_p->nla_len));
646 : }
647 :
648 0 : nla->nla_len = len;
649 0 : cl->cl_buf_offset += len;
650 :
651 0 : return 0;
652 : }
653 :
654 : static int
655 0 : nl_build_dcb_msg(struct nl_client *cl, uint8_t cmd)
656 : {
657 0 : struct dcbmsg *dcb = (struct dcbmsg *)nl_get_buf_ptr(cl);
658 :
659 0 : dcb->cmd = cmd;
660 0 : dcb->dcb_family = AF_UNSPEC;
661 0 : dcb->dcb_pad = 0;
662 :
663 0 : cl->cl_buf_offset += sizeof(*dcb);
664 :
665 0 : return 0;
666 : }
667 :
668 : static bool
669 0 : nl_dcb_set_cmd(uint8_t cmd)
670 : {
671 0 : switch (cmd) {
672 0 : case DCB_CMD_SSTATE:
673 : case DCB_CMD_PGTX_SCFG:
674 : case DCB_CMD_SET_ALL:
675 : case DCB_CMD_SDCBX:
676 : case DCB_CMD_IEEE_SET:
677 0 : return true;
678 :
679 0 : default:
680 0 : break;
681 : }
682 :
683 0 : return false;
684 : }
685 :
686 : static int
687 0 : nl_build_dcb_nl_msg(struct nl_client *cl, uint8_t *ifname,
688 : uint8_t cmd, uint8_t ack)
689 : {
690 : int ret, msgtype;
691 : uint32_t flags;
692 :
693 0 : if (!cl->cl_buf || cl->cl_buf_offset)
694 0 : return -EINVAL;
695 :
696 0 : flags = NLM_F_REQUEST | NLM_F_CREATE;
697 0 : if (ack) {
698 0 : flags |= NLM_F_ACK;
699 : }
700 :
701 0 : if (nl_dcb_set_cmd(cmd)) {
702 0 : msgtype = RTM_SETDCB;
703 : } else {
704 0 : msgtype = RTM_GETDCB;
705 : }
706 :
707 0 : ret = nl_build_nlh(cl, msgtype, flags);
708 0 : if (ret)
709 0 : return ret;
710 :
711 0 : ret = nl_build_dcb_msg(cl, cmd);
712 0 : if (ret)
713 0 : return ret;
714 :
715 0 : ret = nl_build_attr_dcb_ifname(cl, ifname);
716 0 : if (ret)
717 0 : return ret;
718 :
719 0 : return ret;
720 : }
721 :
722 : static int
723 0 : nl_parse_dcb_tc_attr(struct nlattr *nla, void *buf, uint8_t parent_attr_type)
724 : {
725 : int ret;
726 : uint8_t byte, j;
727 0 : unsigned int processed = 0, nla_len;
728 :
729 : struct nlattr *nla_p;
730 0 : struct priority *p = (struct priority *)buf;
731 :
732 0 : switch (nla->nla_type) {
733 0 : case DCB_TC_ATTR_PARAM_PGID:
734 0 : byte = *(uint8_t *)(nla + 1);
735 0 : p->tc_to_group[parent_attr_type - DCB_PG_ATTR_TC_0] = byte;
736 0 : processed = NLA_ALIGN(NLA_HDRLEN + sizeof(uint8_t));
737 0 : break;
738 :
739 0 : case DCB_TC_ATTR_PARAM_UP_MAPPING:
740 0 : byte = *(uint8_t *)(nla + 1);
741 0 : if (byte) {
742 0 : for (j = 0; j < 8; j++) {
743 0 : if (byte & (1 << j)) {
744 0 : p->prio_to_tc[j] = parent_attr_type - DCB_PG_ATTR_TC_0;
745 : }
746 : }
747 : }
748 0 : processed = NLA_ALIGN(NLA_HDRLEN + sizeof(uint8_t));
749 0 : break;
750 :
751 0 : case DCB_TC_ATTR_PARAM_STRICT_PRIO:
752 0 : byte = *(uint8_t *)(nla + 1);
753 0 : if (byte)
754 0 : p->tc_strictness |= (1 << (parent_attr_type - DCB_PG_ATTR_TC_0));
755 0 : processed = NLA_ALIGN(NLA_HDRLEN + sizeof(uint8_t));
756 0 : break;
757 :
758 0 : case DCB_TC_ATTR_PARAM_BW_PCT:
759 0 : processed = NLA_ALIGN(NLA_HDRLEN + sizeof(uint8_t));
760 0 : break;
761 :
762 0 : default:
763 0 : return -EINVAL;
764 : }
765 :
766 0 : return processed;
767 : }
768 :
769 :
770 : static int
771 0 : nl_parse_dcb_pg_attr(struct nlattr *nla, void *buf)
772 : {
773 : int ret;
774 : uint8_t byte;
775 0 : unsigned int processed = 0, nla_len;
776 :
777 : struct nlattr *nla_p;
778 0 : struct priority *p = (struct priority *)buf;
779 :
780 0 : nla_len = NLA_ALIGN(nla->nla_len);
781 :
782 0 : switch (nla->nla_type) {
783 0 : case DCB_PG_ATTR_TC_0:
784 : case DCB_PG_ATTR_TC_1:
785 : case DCB_PG_ATTR_TC_2:
786 : case DCB_PG_ATTR_TC_3:
787 : case DCB_PG_ATTR_TC_4:
788 : case DCB_PG_ATTR_TC_5:
789 : case DCB_PG_ATTR_TC_6:
790 : case DCB_PG_ATTR_TC_7:
791 0 : processed = NLA_HDRLEN;
792 0 : break;
793 :
794 0 : case DCB_PG_ATTR_BW_ID_0:
795 : case DCB_PG_ATTR_BW_ID_1:
796 : case DCB_PG_ATTR_BW_ID_2:
797 : case DCB_PG_ATTR_BW_ID_3:
798 : case DCB_PG_ATTR_BW_ID_4:
799 : case DCB_PG_ATTR_BW_ID_5:
800 : case DCB_PG_ATTR_BW_ID_6:
801 : case DCB_PG_ATTR_BW_ID_7:
802 0 : byte = *(uint8_t *)(nla + 1);
803 0 : p->prio_group_bw[nla->nla_type - DCB_PG_ATTR_BW_ID_0] = byte;
804 0 : processed = NLA_ALIGN(NLA_HDRLEN + sizeof(uint8_t));
805 0 : break;
806 :
807 0 : default:
808 0 : return -EINVAL;
809 : }
810 :
811 0 : nla_len -= NLA_ALIGN(processed);
812 0 : while (nla_len) {
813 0 : nla_p = (struct nlattr *)((uint8_t *)nla + NLA_ALIGN(processed));
814 0 : ret = nl_parse_dcb_tc_attr(nla_p, buf, nla->nla_type);
815 0 : if (ret < 0)
816 0 : return ret;
817 :
818 0 : processed += ret;
819 0 : nla_len -= NLA_ALIGN(ret);
820 : }
821 :
822 0 : return processed;
823 : }
824 :
825 : static int
826 0 : nl_parse_dcb_ieee_attr_ets(struct nlattr *nla, void *buf)
827 : {
828 : uint8_t i;
829 :
830 0 : struct priority *p = (struct priority *)buf;
831 : struct ieee_ets *ets;
832 :
833 0 : ets = (struct ieee_ets *)(nla + 1);
834 0 : memcpy(p->prio_group_bw, ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
835 0 : p->tc_strictness = 0;
836 0 : for (i = 0; i < 8; i++) {
837 0 : if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_STRICT) {
838 0 : p->tc_strictness |= (1 << i);
839 : }
840 : }
841 :
842 0 : memcpy(p->prio_to_tc, ets->prio_tc, sizeof(ets->tc_tx_bw));
843 0 : for (i = 0; i < 8; i++) {
844 0 : p->tc_to_group[i] = i;
845 : }
846 :
847 0 : return nla->nla_len;
848 : }
849 :
850 : static int
851 0 : nl_parse_dcb_ieee_attr(struct nlattr *nla, void *buf)
852 : {
853 : int ret;
854 :
855 0 : switch (nla->nla_type) {
856 0 : case DCB_ATTR_IEEE_ETS:
857 0 : ret = nl_parse_dcb_ieee_attr_ets(nla, buf);
858 0 : break;
859 :
860 0 : default:
861 0 : ret = nla->nla_len;
862 0 : break;
863 : }
864 :
865 0 : return ret;
866 : }
867 :
868 : static int
869 0 : nla_parse_dcb_ieee_response(struct nlattr *nla, void *buf)
870 : {
871 : int ret;
872 0 : unsigned int processed = 0, nla_len;
873 : struct nlattr *nla_p;
874 :
875 0 : if (nla->nla_type != DCB_ATTR_IFNAME)
876 0 : return -EINVAL;
877 0 : nla_len = NLA_ALIGN(nla->nla_len);
878 :
879 0 : nla = (struct nlattr *)((uint8_t *)nla + nla_len);
880 0 : if (nla->nla_type != DCB_ATTR_IEEE)
881 0 : return -EINVAL;
882 0 : nla_len = NLA_ALIGN(nla->nla_len);
883 0 : processed += NLA_HDRLEN;
884 0 : nla_len -= NLA_HDRLEN;
885 :
886 0 : while (nla_len) {
887 0 : nla_p = (struct nlattr *)((uint8_t *)nla + NLA_ALIGN(processed));
888 0 : ret = nl_parse_dcb_ieee_attr(nla_p, buf);
889 0 : if (ret < 0)
890 0 : return ret;
891 :
892 0 : processed += NLA_ALIGN(ret);
893 0 : nla_len -= NLA_ALIGN(ret);
894 : }
895 :
896 0 : return processed;
897 : }
898 :
899 : static int
900 0 : nla_parse_dcb_pg_response(struct nlattr *nla, void *buf)
901 : {
902 : int ret;
903 0 : unsigned int processed = 0, nla_len;
904 : struct nlattr *nla_p;
905 :
906 0 : nla_len = NLA_ALIGN(nla->nla_len);
907 0 : if (!nla_len || (nla->nla_type != DCB_ATTR_PG_CFG))
908 0 : return -EINVAL;
909 :
910 0 : processed = NLA_HDRLEN;
911 0 : nla_len -= NLA_ALIGN(processed);
912 :
913 0 : while (nla_len) {
914 0 : nla_p = (struct nlattr *)((uint8_t *)nla + NLA_ALIGN(processed));
915 0 : ret = nl_parse_dcb_pg_attr(nla_p, buf);
916 0 : if (ret < 0)
917 0 : return ret;
918 :
919 0 : processed += ret;
920 0 : nla_len -= NLA_ALIGN(ret);
921 : }
922 :
923 0 : return processed;
924 : }
925 :
926 : static int
927 0 : nl_parse_dcb_response(uint8_t *dcbm, uint8_t cmd, uint8_t attr, void *buf)
928 : {
929 : int ret;
930 : struct nlattr *nla;
931 0 : struct dcbmsg *dcb = (struct dcbmsg *)dcbm;
932 :
933 0 : if (dcb->cmd != cmd) {
934 0 : return -EINVAL;
935 : }
936 :
937 0 : nla = (struct nlattr *)(dcb + 1);
938 0 : if (nla->nla_type != attr)
939 0 : return -EINVAL;
940 :
941 0 : if ((nla->nla_type == DCB_ATTR_PG_CFG) &&
942 : (cmd == DCB_CMD_PGTX_GCFG)) {
943 0 : return nla_parse_dcb_pg_response(nla, buf);
944 0 : } else if (cmd == DCB_CMD_IEEE_GET) {
945 0 : return nla_parse_dcb_ieee_response(nla, buf);
946 : }
947 :
948 0 : return *((uint8_t *)((uint8_t *)nla + NLA_HDRLEN));
949 : }
950 :
951 : int
952 0 : nl_build_set_dcb_state_msg(struct nl_client *cl,
953 : uint8_t *ifname, uint8_t state)
954 : {
955 : int ret;
956 :
957 0 : ret = nl_build_dcb_nl_msg(cl, ifname, DCB_CMD_SSTATE, 0);
958 0 : if (ret)
959 0 : return ret;
960 :
961 0 : ret = nl_build_attr_dcb_state(cl, state);
962 0 : if (ret)
963 0 : return ret;
964 :
965 0 : cl->cl_msg_len = cl->cl_buf_offset;
966 0 : nl_update_nlh(cl);
967 :
968 0 : return ret;
969 : }
970 :
971 : int
972 0 : nl_build_get_dcb_state_msg(struct nl_client *cl, uint8_t *ifname)
973 : {
974 : int ret;
975 :
976 0 : ret = nl_build_dcb_nl_msg(cl, ifname, DCB_CMD_GSTATE, 0);
977 0 : if (ret)
978 0 : return ret;
979 :
980 0 : cl->cl_msg_len = cl->cl_buf_offset;
981 0 : nl_update_nlh(cl);
982 :
983 0 : return 0;
984 : }
985 :
986 : int
987 0 : nl_build_set_priority_config_msg(struct nl_client *cl, uint8_t *ifname,
988 : struct priority *p)
989 : {
990 : int ret;
991 :
992 0 : ret = nl_build_dcb_nl_msg(cl, ifname, DCB_CMD_PGTX_SCFG, 0);
993 0 : if (ret)
994 0 : return ret;
995 :
996 0 : ret = nl_build_attr_dcb_pgtx(cl, p);
997 0 : if (ret)
998 0 : return ret;
999 :
1000 0 : cl->cl_msg_len = cl->cl_buf_offset;
1001 0 : nl_update_nlh(cl);
1002 :
1003 0 : return 0;
1004 : }
1005 :
1006 : int
1007 0 : nl_build_get_priority_config_msg(struct nl_client *cl, uint8_t *ifname)
1008 : {
1009 : int ret;
1010 :
1011 0 : ret = nl_build_dcb_nl_msg(cl, ifname, DCB_CMD_PGTX_GCFG, 0);
1012 0 : if (ret)
1013 0 : return ret;
1014 :
1015 0 : ret = nl_build_attr_dcb_get_pgtx(cl);
1016 0 : if (ret)
1017 0 : return ret;
1018 :
1019 0 : cl->cl_msg_len = cl->cl_buf_offset;
1020 0 : nl_update_nlh(cl);
1021 :
1022 0 : return 0;
1023 : }
1024 :
1025 : int
1026 0 : nl_build_set_dcb_all(struct nl_client *cl, uint8_t *ifname)
1027 : {
1028 : int ret;
1029 :
1030 0 : ret = nl_build_dcb_nl_msg(cl, ifname, DCB_CMD_SET_ALL, 0);
1031 0 : if (ret)
1032 0 : return ret;
1033 :
1034 0 : ret = nl_build_attr_dcb_set_all(cl);
1035 0 : if (ret)
1036 0 : return ret;
1037 :
1038 0 : cl->cl_msg_len = cl->cl_buf_offset;
1039 0 : nl_update_nlh(cl);
1040 :
1041 0 : return 0;
1042 : }
1043 :
1044 : int
1045 0 : nl_build_set_dcbx(struct nl_client *cl, uint8_t *ifname, uint8_t dcbx)
1046 : {
1047 : int ret;
1048 :
1049 0 : ret = nl_build_dcb_nl_msg(cl, ifname, DCB_CMD_SDCBX, 0);
1050 0 : if (ret)
1051 0 : return ret;
1052 :
1053 0 : ret = nl_build_attr_set_dcbx(cl, dcbx);
1054 0 : if (ret)
1055 0 : return ret;
1056 :
1057 0 : cl->cl_msg_len = cl->cl_buf_offset;
1058 0 : nl_update_nlh(cl);
1059 :
1060 0 : return 0;
1061 : }
1062 :
1063 : int
1064 0 : nl_build_get_dcbx(struct nl_client *cl, uint8_t *ifname)
1065 : {
1066 : int ret;
1067 :
1068 0 : ret = nl_build_dcb_nl_msg(cl, ifname, DCB_CMD_GDCBX, 0);
1069 0 : if (ret)
1070 0 : return ret;
1071 :
1072 0 : cl->cl_msg_len = cl->cl_buf_offset;
1073 0 : nl_update_nlh(cl);
1074 :
1075 0 : return 0;
1076 : }
1077 :
1078 : int
1079 0 : nl_dcb_parse_reply(struct nl_client *cl, uint8_t cmd, void *resp_buf)
1080 : {
1081 0 : int ret = 0;
1082 0 : uint8_t attr = DCB_ATTR_UNDEFINED;
1083 : struct nl_response *resp;
1084 :
1085 0 : resp = nl_parse_reply(cl);
1086 0 : if (resp) {
1087 0 : if (resp->nl_type == NL_MSG_TYPE_ERROR) {
1088 0 : printf("vRouter: DCB %d failed with error %d\n",
1089 : cmd, resp->nl_op);
1090 0 : return resp->nl_op;
1091 : }
1092 :
1093 0 : switch (cmd) {
1094 0 : case DCB_CMD_SSTATE:
1095 : case DCB_CMD_GSTATE:
1096 0 : attr = DCB_ATTR_STATE;
1097 0 : break;
1098 :
1099 0 : case DCB_CMD_SDCBX:
1100 : case DCB_CMD_GDCBX:
1101 0 : attr = DCB_ATTR_DCBX;
1102 0 : break;
1103 :
1104 0 : case DCB_CMD_PGTX_SCFG:
1105 : case DCB_CMD_PGTX_GCFG:
1106 0 : attr = DCB_ATTR_PG_CFG;
1107 0 : break;
1108 :
1109 0 : case DCB_CMD_IEEE_SET:
1110 0 : attr = DCB_ATTR_IEEE;
1111 0 : break;
1112 :
1113 0 : case DCB_CMD_IEEE_GET:
1114 0 : attr = DCB_ATTR_IFNAME;
1115 0 : break;
1116 :
1117 0 : default:
1118 0 : break;
1119 : }
1120 :
1121 0 : ret = nl_parse_dcb_response((uint8_t *)resp->nl_data, cmd,
1122 : attr, resp_buf);
1123 : }
1124 :
1125 0 : cl->cl_buf_offset = 0;
1126 0 : return ret;
1127 : }
1128 :
1129 : static int
1130 0 : nl_build_attr_ieee_ets(struct nl_client *cl, struct priority *p)
1131 : {
1132 : unsigned int i;
1133 :
1134 : struct ieee_ets *ets;
1135 0 : struct nlattr *nla_p, *nla = (struct nlattr *)nl_get_buf_ptr(cl);
1136 :
1137 0 : nla->nla_type = DCB_ATTR_IEEE;
1138 0 : nla->nla_len = NLA_HDRLEN;
1139 :
1140 0 : nla_p = (struct nlattr *)(nla + 1);
1141 0 : nla_p->nla_type = DCB_ATTR_IEEE_ETS;
1142 0 : nla_p->nla_len = NLA_HDRLEN + sizeof(*ets);
1143 :
1144 0 : ets = (struct ieee_ets *)(nla_p + 1);
1145 0 : memset(ets, 0, sizeof(*ets));
1146 :
1147 0 : ets->willing = 0;
1148 0 : ets->ets_cap = 8;
1149 0 : ets->cbs = 0;
1150 :
1151 0 : memcpy(&ets->tc_tx_bw, &p->prio_group_bw, sizeof(p->prio_group_bw));
1152 0 : memcpy(&ets->prio_tc, &p->prio_to_tc, sizeof(p->prio_to_tc));
1153 :
1154 0 : for (i = 0; i < 8; i++) {
1155 0 : if (p->tc_strictness & (1 << i)) {
1156 0 : ets->tc_tsa[i] = IEEE_8021QAZ_TSA_STRICT;
1157 : } else {
1158 0 : ets->tc_tsa[i] = IEEE_8021QAZ_TSA_ETS;
1159 : }
1160 : }
1161 :
1162 0 : nla->nla_len += NLA_ALIGN(nla_p->nla_len);
1163 0 : cl->cl_buf_offset += NLA_ALIGN(nla->nla_len);
1164 :
1165 0 : return 0;
1166 : }
1167 :
1168 : int
1169 0 : nl_build_get_ieee_ets(struct nl_client *cl, uint8_t *ifname,
1170 : struct priority *p)
1171 : {
1172 : int ret;
1173 :
1174 0 : ret = nl_build_dcb_nl_msg(cl, ifname, DCB_CMD_IEEE_GET, 0);
1175 0 : if (ret)
1176 0 : return ret;
1177 :
1178 0 : cl->cl_msg_len = cl->cl_buf_offset;
1179 0 : nl_update_nlh(cl);
1180 :
1181 0 : return 0;
1182 : }
1183 :
1184 : int
1185 0 : nl_build_set_ieee_ets(struct nl_client *cl, uint8_t *ifname,
1186 : struct priority *p)
1187 : {
1188 : int ret;
1189 :
1190 0 : ret = nl_build_dcb_nl_msg(cl, ifname, DCB_CMD_IEEE_SET, 0);
1191 0 : if (ret)
1192 0 : return ret;
1193 :
1194 0 : ret = nl_build_attr_ieee_ets(cl, p);
1195 0 : if (ret < 0)
1196 0 : return ret;
1197 :
1198 0 : cl->cl_msg_len = cl->cl_buf_offset;
1199 0 : nl_update_nlh(cl);
1200 :
1201 0 : return 0;
1202 : }
1203 :
1204 :
1205 : int
1206 0 : nl_dcb_sendmsg(struct nl_client *cl, uint8_t cmd, void *resp_buf)
1207 : {
1208 : int ret;
1209 :
1210 0 : ret = nl_sendmsg(cl);
1211 0 : if (ret <= 0)
1212 0 : return -1;
1213 :
1214 0 : if ((ret = nl_recvmsg(cl)) > 0) {
1215 0 : return nl_dcb_parse_reply(cl, cmd, resp_buf);
1216 : }
1217 :
1218 0 : return ret;
1219 : }
1220 :
1221 : int
1222 0 : vrouter_obtain_family_id(struct nl_client *cl)
1223 : {
1224 : int ret;
1225 : struct nl_response *resp;
1226 : struct genl_ctrl_message *msg;
1227 :
1228 0 : if (cl->cl_socket_domain != AF_NETLINK) {
1229 0 : nl_set_genl_family_id(cl, GENL_ID_VROUTER);
1230 0 : return GENL_ID_VROUTER;
1231 : }
1232 :
1233 0 : if ((ret = nl_build_get_family_id(cl, VROUTER_GENETLINK_FAMILY_NAME)))
1234 0 : return ret;
1235 :
1236 0 : if (nl_sendmsg(cl) <= 0)
1237 0 : return -errno;
1238 :
1239 : while (1) {
1240 0 : ret = nl_recvmsg(cl);
1241 0 : if (ret == EAGAIN)
1242 0 : continue;
1243 0 : else if (ret > 0)
1244 0 : break;
1245 :
1246 0 : return -errno;
1247 : }
1248 :
1249 0 : resp = nl_parse_reply(cl);
1250 0 : if (!resp || resp->nl_type != NL_MSG_TYPE_GEN_CTRL ||
1251 0 : resp->nl_op != CTRL_CMD_NEWFAMILY)
1252 0 : return -EINVAL;
1253 :
1254 0 : msg = (struct genl_ctrl_message *)resp->nl_data;
1255 0 : nl_set_genl_family_id(cl, msg->family_id);
1256 :
1257 0 : return cl->cl_genl_family_id;
1258 : }
1259 : #endif /* __linux__ */
|