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