Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2017 6WIND S.A.
3 : : * Copyright 2017 Mellanox Technologies, Ltd
4 : : */
5 : :
6 : : #include <errno.h>
7 : : #include <inttypes.h>
8 : : #include <linux/netlink.h>
9 : : #include <net/if.h>
10 : : #include <string.h>
11 : : #include <sys/socket.h>
12 : : #include <unistd.h>
13 : : #include <stdbool.h>
14 : :
15 : : #include <rte_malloc.h>
16 : : #include <tap_netlink.h>
17 : : #include <rte_random.h>
18 : :
19 : : #include "tap_log.h"
20 : :
21 : : /* Compatibility with glibc < 2.24 */
22 : : #ifndef SOL_NETLINK
23 : : #define SOL_NETLINK 270
24 : : #endif
25 : :
26 : : /* Must be quite large to support dumping a huge list of QDISC or filters. */
27 : : #define BUF_SIZE (32 * 1024) /* Size of the buffer to receive kernel messages */
28 : : #define SNDBUF_SIZE 32768 /* Send buffer size for the netlink socket */
29 : : #define RCVBUF_SIZE 32768 /* Receive buffer size for the netlink socket */
30 : :
31 : : struct nested_tail {
32 : : struct rtattr *tail;
33 : : struct nested_tail *prev;
34 : : };
35 : :
36 : : /**
37 : : * Initialize a netlink socket for communicating with the kernel.
38 : : *
39 : : * @param nl_groups
40 : : * Set it to a netlink group value (e.g. RTMGRP_LINK) to receive messages for
41 : : * specific netlink multicast groups. Otherwise, no subscription will be made.
42 : : *
43 : : * @return
44 : : * netlink socket file descriptor on success, -1 otherwise.
45 : : */
46 : : int
47 : 0 : tap_nl_init(uint32_t nl_groups)
48 : : {
49 : 0 : int fd, sndbuf_size = SNDBUF_SIZE, rcvbuf_size = RCVBUF_SIZE;
50 : 0 : struct sockaddr_nl local = {
51 : : .nl_family = AF_NETLINK,
52 : : .nl_groups = nl_groups,
53 : : };
54 : : #ifdef NETLINK_EXT_ACK
55 : 0 : int one = 1;
56 : : #endif
57 : :
58 : 0 : fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
59 [ # # ]: 0 : if (fd < 0) {
60 : 0 : TAP_LOG(ERR, "Unable to create a netlink socket");
61 : 0 : return -1;
62 : : }
63 [ # # ]: 0 : if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(int))) {
64 : 0 : TAP_LOG(ERR, "Unable to set socket buffer send size");
65 : 0 : close(fd);
66 : 0 : return -1;
67 : : }
68 [ # # ]: 0 : if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, sizeof(int))) {
69 : 0 : TAP_LOG(ERR, "Unable to set socket buffer receive size");
70 : 0 : close(fd);
71 : 0 : return -1;
72 : : }
73 : :
74 : : #ifdef NETLINK_EXT_ACK
75 : : /* Ask for extended ACK response. on older kernel will ignore request. */
76 [ # # ]: 0 : if (setsockopt(fd, SOL_NETLINK, NETLINK_EXT_ACK, &one, sizeof(one)) < 0)
77 : 0 : TAP_LOG(NOTICE, "Unable to request netlink error information");
78 : : #endif
79 : :
80 [ # # ]: 0 : if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
81 : 0 : TAP_LOG(ERR, "Unable to bind to the netlink socket");
82 : 0 : close(fd);
83 : 0 : return -1;
84 : : }
85 : : return fd;
86 : : }
87 : :
88 : : /**
89 : : * Clean up a netlink socket once all communicating with the kernel is finished.
90 : : *
91 : : * @param[in] nlsk_fd
92 : : * The netlink socket file descriptor used for communication.
93 : : *
94 : : * @return
95 : : * 0 on success, -1 otherwise.
96 : : */
97 : : int
98 : 0 : tap_nl_final(int nlsk_fd)
99 : : {
100 [ # # ]: 0 : if (close(nlsk_fd)) {
101 : 0 : TAP_LOG(ERR, "Failed to close netlink socket: %s (%d)",
102 : : strerror(errno), errno);
103 : 0 : return -1;
104 : : }
105 : : return 0;
106 : : }
107 : :
108 : : /**
109 : : * Send a message to the kernel on the netlink socket.
110 : : *
111 : : * @param[in] nlsk_fd
112 : : * The netlink socket file descriptor used for communication.
113 : : * @param[in] nh
114 : : * The netlink message send to the kernel.
115 : : *
116 : : * @return
117 : : * the number of sent bytes on success, -1 otherwise.
118 : : */
119 : : int
120 : 0 : tap_nl_send(int nlsk_fd, struct nlmsghdr *nh)
121 : : {
122 : : int send_bytes;
123 : :
124 : 0 : nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
125 : 0 : nh->nlmsg_seq = (uint32_t)rte_rand();
126 : :
127 : 0 : retry:
128 : 0 : send_bytes = send(nlsk_fd, nh, nh->nlmsg_len, 0);
129 [ # # ]: 0 : if (send_bytes < 0) {
130 [ # # ]: 0 : if (errno == EINTR)
131 : 0 : goto retry;
132 : :
133 : 0 : TAP_LOG(ERR, "Failed to send netlink message: %s (%d)",
134 : : strerror(errno), errno);
135 : 0 : return -1;
136 : : }
137 : : return send_bytes;
138 : : }
139 : :
140 : : #ifdef NETLINK_EXT_ACK
141 : : static const struct nlattr *
142 : : tap_nl_attr_first(const struct nlmsghdr *nh, size_t offset)
143 : : {
144 : 0 : return (const struct nlattr *)((const char *)nh + NLMSG_SPACE(offset));
145 : : }
146 : :
147 : : static const struct nlattr *
148 : : tap_nl_attr_next(const struct nlattr *attr)
149 : : {
150 : 0 : return (const struct nlattr *)((const char *)attr
151 : 0 : + NLMSG_ALIGN(attr->nla_len));
152 : : }
153 : :
154 : : static bool
155 : : tap_nl_attr_ok(const struct nlattr *attr, int len)
156 : : {
157 : 0 : if (len < (int)sizeof(struct nlattr))
158 : : return false; /* missing header */
159 [ # # ]: 0 : if (attr->nla_len < sizeof(struct nlattr))
160 : : return false; /* attribute length should include itself */
161 [ # # ]: 0 : if ((int)attr->nla_len > len)
162 : : return false; /* attribute is truncated */
163 : : return true;
164 : : }
165 : :
166 : :
167 : : /* Decode extended errors from kernel */
168 : : static void
169 : 0 : tap_nl_dump_ext_ack(const struct nlmsghdr *nh, const struct nlmsgerr *err)
170 : : {
171 : : const struct nlattr *attr;
172 : 0 : const char *tail = (const char *)nh + NLMSG_ALIGN(nh->nlmsg_len);
173 : : size_t hlen = sizeof(*err);
174 : :
175 : : /* no TLVs, no extended response */
176 [ # # ]: 0 : if (!(nh->nlmsg_flags & NLM_F_ACK_TLVS))
177 : : return;
178 : :
179 [ # # ]: 0 : if (!(nh->nlmsg_flags & NLM_F_CAPPED))
180 : 0 : hlen += err->msg.nlmsg_len - NLMSG_HDRLEN;
181 : :
182 : 0 : for (attr = tap_nl_attr_first(nh, hlen);
183 [ # # ]: 0 : tap_nl_attr_ok(attr, tail - (const char *)attr);
184 : : attr = tap_nl_attr_next(attr)) {
185 : 0 : uint16_t type = attr->nla_type & NLA_TYPE_MASK;
186 : :
187 [ # # ]: 0 : if (type == NLMSGERR_ATTR_MSG) {
188 : 0 : const char *msg = (const char *)attr
189 : : + NLMSG_ALIGN(sizeof(*attr));
190 : :
191 [ # # ]: 0 : if (err->error)
192 : 0 : TAP_LOG(ERR, "%s", msg);
193 : : else
194 : :
195 : 0 : TAP_LOG(WARNING, "%s", msg);
196 : : break;
197 : : }
198 : : }
199 : : }
200 : : #else
201 : : /*
202 : : * External ACK support was added in Linux kernel 4.17
203 : : * on older kernels, just ignore that part of message
204 : : */
205 : : #define tap_nl_dump_ext_ack(nh, err) do { } while (0)
206 : : #endif
207 : :
208 : : /**
209 : : * Check that the kernel sends an appropriate ACK in response
210 : : * to an tap_nl_send().
211 : : *
212 : : * @param[in] nlsk_fd
213 : : * The netlink socket file descriptor used for communication.
214 : : *
215 : : * @return
216 : : * 0 on success, -1 otherwise with errno set.
217 : : */
218 : : int
219 : 0 : tap_nl_recv_ack(int nlsk_fd)
220 : : {
221 : 0 : return tap_nl_recv(nlsk_fd, NULL, NULL);
222 : : }
223 : :
224 : : /**
225 : : * Receive a message from the kernel on the netlink socket, following an
226 : : * tap_nl_send().
227 : : *
228 : : * @param[in] nlsk_fd
229 : : * The netlink socket file descriptor used for communication.
230 : : * @param[in] cb
231 : : * The callback function to call for each netlink message received.
232 : : * @param[in, out] arg
233 : : * Custom arguments for the callback.
234 : : *
235 : : * @return
236 : : * 0 on success, -1 otherwise with errno set.
237 : : */
238 : : int
239 : 0 : tap_nl_recv(int nlsk_fd, int (*cb)(struct nlmsghdr *, void *arg), void *arg)
240 : : {
241 : : char buf[BUF_SIZE];
242 : : int multipart = 0;
243 : : int ret = 0;
244 : :
245 : : do {
246 : : struct nlmsghdr *nh;
247 : : int recv_bytes;
248 : :
249 : 0 : retry:
250 : 0 : recv_bytes = recv(nlsk_fd, buf, sizeof(buf), 0);
251 [ # # ]: 0 : if (recv_bytes < 0) {
252 [ # # ]: 0 : if (errno == EINTR)
253 : 0 : goto retry;
254 : : return -1;
255 : : }
256 : :
257 : : for (nh = (struct nlmsghdr *)buf;
258 [ # # # # : 0 : NLMSG_OK(nh, (unsigned int)recv_bytes);
# # ]
259 : 0 : nh = NLMSG_NEXT(nh, recv_bytes)) {
260 [ # # ]: 0 : if (nh->nlmsg_type == NLMSG_ERROR) {
261 : 0 : struct nlmsgerr *err_data = NLMSG_DATA(nh);
262 : :
263 : 0 : tap_nl_dump_ext_ack(nh, err_data);
264 [ # # ]: 0 : if (err_data->error < 0) {
265 : 0 : errno = -err_data->error;
266 : 0 : return -1;
267 : : }
268 : : /* Ack message. */
269 : : return 0;
270 : : }
271 : : /* Multi-part msgs and their trailing DONE message. */
272 [ # # ]: 0 : if (nh->nlmsg_flags & NLM_F_MULTI) {
273 [ # # ]: 0 : if (nh->nlmsg_type == NLMSG_DONE)
274 : : return 0;
275 : : multipart = 1;
276 : : }
277 [ # # ]: 0 : if (cb)
278 : 0 : ret = cb(nh, arg);
279 : : }
280 [ # # ]: 0 : } while (multipart);
281 : : return ret;
282 : : }
283 : :
284 : : /**
285 : : * Append a netlink attribute to a message.
286 : : *
287 : : * @param[in, out] nh
288 : : * The netlink message to parse, received from the kernel.
289 : : * @param[in] type
290 : : * The type of attribute to append.
291 : : * @param[in] data_len
292 : : * The length of the data to append.
293 : : * @param[in] data
294 : : * The data to append.
295 : : */
296 : : void
297 : 0 : tap_nlattr_add(struct tap_nlmsg *msg, unsigned short type,
298 : : unsigned int data_len, const void *data)
299 : : {
300 : : /* see man 3 rtnetlink */
301 : : struct rtattr *rta;
302 : :
303 : 0 : rta = (struct rtattr *)NLMSG_TAIL(msg);
304 : 0 : rta->rta_len = RTA_LENGTH(data_len);
305 : 0 : rta->rta_type = type;
306 [ # # ]: 0 : if (data_len > 0)
307 : 0 : memcpy(RTA_DATA(rta), data, data_len);
308 : 0 : msg->nh.nlmsg_len = NLMSG_ALIGN(msg->nh.nlmsg_len) + RTA_ALIGN(rta->rta_len);
309 : 0 : }
310 : :
311 : : /**
312 : : * Append a uint8_t netlink attribute to a message.
313 : : *
314 : : * @param[in, out] nh
315 : : * The netlink message to parse, received from the kernel.
316 : : * @param[in] type
317 : : * The type of attribute to append.
318 : : * @param[in] data
319 : : * The data to append.
320 : : */
321 : : void
322 : 0 : tap_nlattr_add8(struct tap_nlmsg *msg, unsigned short type, uint8_t data)
323 : : {
324 : 0 : tap_nlattr_add(msg, type, sizeof(uint8_t), &data);
325 : 0 : }
326 : :
327 : : /**
328 : : * Append a uint16_t netlink attribute to a message.
329 : : *
330 : : * @param[in, out] nh
331 : : * The netlink message to parse, received from the kernel.
332 : : * @param[in] type
333 : : * The type of attribute to append.
334 : : * @param[in] data
335 : : * The data to append.
336 : : */
337 : : void
338 : 0 : tap_nlattr_add16(struct tap_nlmsg *msg, unsigned short type, uint16_t data)
339 : : {
340 : 0 : tap_nlattr_add(msg, type, sizeof(uint16_t), &data);
341 : 0 : }
342 : :
343 : : /**
344 : : * Append a uint16_t netlink attribute to a message.
345 : : *
346 : : * @param[in, out] nh
347 : : * The netlink message to parse, received from the kernel.
348 : : * @param[in] type
349 : : * The type of attribute to append.
350 : : * @param[in] data
351 : : * The data to append.
352 : : */
353 : : void
354 : 0 : tap_nlattr_add32(struct tap_nlmsg *msg, unsigned short type, uint32_t data)
355 : : {
356 : 0 : tap_nlattr_add(msg, type, sizeof(uint32_t), &data);
357 : 0 : }
358 : :
359 : : /**
360 : : * Start a nested netlink attribute.
361 : : * It must be followed later by a call to tap_nlattr_nested_finish().
362 : : *
363 : : * @param[in, out] msg
364 : : * The netlink message where to edit the nested_tails metadata.
365 : : * @param[in] type
366 : : * The nested attribute type to append.
367 : : *
368 : : * @return
369 : : * -1 if adding a nested netlink attribute failed, 0 otherwise.
370 : : */
371 : : int
372 : 0 : tap_nlattr_nested_start(struct tap_nlmsg *msg, uint16_t type)
373 : : {
374 : : struct nested_tail *tail;
375 : :
376 : 0 : tail = rte_zmalloc(NULL, sizeof(struct nested_tail), 0);
377 [ # # ]: 0 : if (!tail) {
378 : 0 : TAP_LOG(ERR,
379 : : "Couldn't allocate memory for nested netlink attribute");
380 : 0 : return -1;
381 : : }
382 : :
383 : 0 : tail->tail = (struct rtattr *)NLMSG_TAIL(msg);
384 : :
385 : 0 : tap_nlattr_add(msg, type, 0, NULL);
386 : :
387 : 0 : tail->prev = msg->nested_tails;
388 : :
389 : 0 : msg->nested_tails = tail;
390 : :
391 : 0 : return 0;
392 : : }
393 : :
394 : : /**
395 : : * End a nested netlink attribute.
396 : : * It follows a call to tap_nlattr_nested_start().
397 : : * In effect, it will modify the nested attribute length to include every bytes
398 : : * from the nested attribute start, up to here.
399 : : *
400 : : * @param[in, out] msg
401 : : * The netlink message where to edit the nested_tails metadata.
402 : : */
403 : : void
404 : 0 : tap_nlattr_nested_finish(struct tap_nlmsg *msg)
405 : : {
406 : 0 : struct nested_tail *tail = msg->nested_tails;
407 : :
408 : 0 : tail->tail->rta_len = (char *)NLMSG_TAIL(msg) - (char *)tail->tail;
409 : :
410 [ # # ]: 0 : if (tail->prev)
411 : 0 : msg->nested_tails = tail->prev;
412 : :
413 : 0 : rte_free(tail);
414 : 0 : }
415 : :
416 : : /**
417 : : * Helper structure to pass data between netlink request and callback
418 : : */
419 : : struct link_info_ctx {
420 : : struct ifinfomsg *info;
421 : : struct rte_ether_addr *mac;
422 : : unsigned int *flags;
423 : : unsigned int ifindex;
424 : : int found;
425 : : };
426 : :
427 : : /**
428 : : * Callback to extract link information from RTM_GETLINK response
429 : : */
430 : : static int
431 : 0 : tap_nl_link_cb(struct nlmsghdr *nh, void *arg)
432 : : {
433 : : struct link_info_ctx *ctx = arg;
434 : : struct ifinfomsg *ifi = NLMSG_DATA(nh);
435 : : struct rtattr *rta;
436 : : int rta_len;
437 : :
438 [ # # ]: 0 : if (nh->nlmsg_type != RTM_NEWLINK)
439 : : return 0;
440 : :
441 : : /* Check if this is the interface we're looking for */
442 [ # # ]: 0 : if (ifi->ifi_index != (int)ctx->ifindex)
443 : : return 0;
444 : :
445 : 0 : ctx->found = 1;
446 : :
447 : : /* Copy basic info if requested */
448 [ # # ]: 0 : if (ctx->info)
449 : 0 : *ctx->info = *ifi;
450 : :
451 : : /* Extract flags if requested */
452 [ # # ]: 0 : if (ctx->flags)
453 : 0 : *ctx->flags = ifi->ifi_flags;
454 : :
455 : : /* Parse attributes for MAC address if requested */
456 [ # # ]: 0 : if (ctx->mac) {
457 : 0 : rta = IFLA_RTA(ifi);
458 : 0 : rta_len = IFLA_PAYLOAD(nh);
459 : :
460 [ # # # # : 0 : for (; RTA_OK(rta, rta_len); rta = RTA_NEXT(rta, rta_len)) {
# # ]
461 [ # # ]: 0 : if (rta->rta_type == IFLA_ADDRESS) {
462 [ # # ]: 0 : if (RTA_PAYLOAD(rta) >= RTE_ETHER_ADDR_LEN)
463 : 0 : memcpy(ctx->mac, RTA_DATA(rta),
464 : : RTE_ETHER_ADDR_LEN);
465 : : break;
466 : : }
467 : : }
468 : : }
469 : :
470 : : return 0;
471 : : }
472 : :
473 : : /**
474 : : * Get interface flags by ifindex
475 : : *
476 : : * @param nlsk_fd
477 : : * Netlink socket file descriptor
478 : : * @param ifindex
479 : : * Interface index
480 : : * @param flags
481 : : * Pointer to store interface flags
482 : : *
483 : : * @return
484 : : * 0 on success, -1 on error
485 : : */
486 : : int
487 : 0 : tap_nl_get_flags(int nlsk_fd, unsigned int ifindex, unsigned int *flags)
488 : : {
489 : : struct {
490 : : struct nlmsghdr nh;
491 : : struct ifinfomsg ifi;
492 : 0 : } req = {
493 : : .nh = {
494 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
495 : : .nlmsg_type = RTM_GETLINK,
496 : : .nlmsg_flags = NLM_F_REQUEST,
497 : : },
498 : : .ifi = {
499 : : .ifi_family = AF_UNSPEC,
500 : : .ifi_index = ifindex,
501 : : },
502 : : };
503 : 0 : struct link_info_ctx ctx = {
504 : : .flags = flags,
505 : : .ifindex = ifindex,
506 : : .found = 0,
507 : : };
508 : :
509 [ # # ]: 0 : if (tap_nl_send(nlsk_fd, &req.nh) < 0)
510 : : return -1;
511 : :
512 [ # # ]: 0 : if (tap_nl_recv(nlsk_fd, tap_nl_link_cb, &ctx) < 0)
513 : : return -1;
514 : :
515 [ # # ]: 0 : if (!ctx.found) {
516 : 0 : errno = ENODEV;
517 : 0 : return -1;
518 : : }
519 : :
520 : : return 0;
521 : : }
522 : :
523 : : /**
524 : : * Set interface flags by ifindex
525 : : *
526 : : * @param nlsk_fd
527 : : * Netlink socket file descriptor
528 : : * @param ifindex
529 : : * Interface index
530 : : * @param flags
531 : : * Flags to set/unset
532 : : * @param set
533 : : * 1 to set flags, 0 to unset them
534 : : *
535 : : * @return
536 : : * 0 on success, -1 on error
537 : : */
538 : : int
539 : 0 : tap_nl_set_flags(int nlsk_fd, unsigned int ifindex, unsigned int flags, int set)
540 : : {
541 : : struct {
542 : : struct nlmsghdr nh;
543 : : struct ifinfomsg ifi;
544 : 0 : } req = {
545 : : .nh = {
546 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
547 : : .nlmsg_type = RTM_SETLINK,
548 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
549 : : },
550 : : .ifi = {
551 : : .ifi_family = AF_UNSPEC,
552 : : .ifi_index = ifindex,
553 [ # # ]: 0 : .ifi_flags = set ? flags : 0,
554 : : .ifi_change = flags, /* mask of flags to change */
555 : : },
556 : : };
557 : :
558 [ # # ]: 0 : if (tap_nl_send(nlsk_fd, &req.nh) < 0)
559 : : return -1;
560 : :
561 : 0 : return tap_nl_recv_ack(nlsk_fd);
562 : : }
563 : :
564 : : /**
565 : : * Set interface MTU by ifindex
566 : : *
567 : : * @param nlsk_fd
568 : : * Netlink socket file descriptor
569 : : * @param ifindex
570 : : * Interface index
571 : : * @param mtu
572 : : * New MTU value
573 : : *
574 : : * @return
575 : : * 0 on success, -1 on error
576 : : */
577 : : int
578 : 0 : tap_nl_set_mtu(int nlsk_fd, unsigned int ifindex, unsigned int mtu)
579 : : {
580 : : struct {
581 : : struct nlmsghdr nh;
582 : : struct ifinfomsg ifi;
583 : : char buf[64];
584 : 0 : } req = {
585 : : .nh = {
586 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
587 : : .nlmsg_type = RTM_SETLINK,
588 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
589 : : },
590 : : .ifi = {
591 : : .ifi_family = AF_UNSPEC,
592 : : .ifi_index = ifindex,
593 : : },
594 : : };
595 : : struct rtattr *rta;
596 : :
597 : : /* Add MTU attribute */
598 : : rta = (struct rtattr *)((char *)&req + NLMSG_ALIGN(req.nh.nlmsg_len));
599 : 0 : rta->rta_type = IFLA_MTU;
600 : 0 : rta->rta_len = RTA_LENGTH(sizeof(mtu));
601 : : memcpy(RTA_DATA(rta), &mtu, sizeof(mtu));
602 : 0 : req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_ALIGN(rta->rta_len);
603 : :
604 [ # # ]: 0 : if (tap_nl_send(nlsk_fd, &req.nh) < 0)
605 : : return -1;
606 : :
607 : 0 : return tap_nl_recv_ack(nlsk_fd);
608 : : }
609 : :
610 : : /**
611 : : * Get interface MAC address by ifindex
612 : : *
613 : : * @param nlsk_fd
614 : : * Netlink socket file descriptor
615 : : * @param ifindex
616 : : * Interface index
617 : : * @param mac
618 : : * Pointer to store MAC address
619 : : *
620 : : * @return
621 : : * 0 on success, -1 on error
622 : : */
623 : : int
624 : 0 : tap_nl_get_mac(int nlsk_fd, unsigned int ifindex, struct rte_ether_addr *mac)
625 : : {
626 : : struct {
627 : : struct nlmsghdr nh;
628 : : struct ifinfomsg ifi;
629 : 0 : } req = {
630 : : .nh = {
631 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
632 : : .nlmsg_type = RTM_GETLINK,
633 : : .nlmsg_flags = NLM_F_REQUEST,
634 : : },
635 : : .ifi = {
636 : : .ifi_family = AF_UNSPEC,
637 : : .ifi_index = ifindex,
638 : : },
639 : : };
640 : 0 : struct link_info_ctx ctx = {
641 : : .mac = mac,
642 : : .ifindex = ifindex,
643 : : .found = 0,
644 : : };
645 : :
646 [ # # ]: 0 : if (tap_nl_send(nlsk_fd, &req.nh) < 0)
647 : : return -1;
648 : :
649 [ # # ]: 0 : if (tap_nl_recv(nlsk_fd, tap_nl_link_cb, &ctx) < 0)
650 : : return -1;
651 : :
652 [ # # ]: 0 : if (!ctx.found) {
653 : 0 : errno = ENODEV;
654 : 0 : return -1;
655 : : }
656 : :
657 : : return 0;
658 : : }
659 : :
660 : : /**
661 : : * Set interface MAC address by ifindex
662 : : *
663 : : * @param nlsk_fd
664 : : * Netlink socket file descriptor
665 : : * @param ifindex
666 : : * Interface index
667 : : * @param mac
668 : : * New MAC address
669 : : *
670 : : * @return
671 : : * 0 on success, -1 on error
672 : : */
673 : : int
674 : 0 : tap_nl_set_mac(int nlsk_fd, unsigned int ifindex, const struct rte_ether_addr *mac)
675 : : {
676 : : struct {
677 : : struct nlmsghdr nh;
678 : : struct ifinfomsg ifi;
679 : : char buf[64];
680 : 0 : } req = {
681 : : .nh = {
682 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
683 : : .nlmsg_type = RTM_SETLINK,
684 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
685 : : },
686 : : .ifi = {
687 : : .ifi_family = AF_UNSPEC,
688 : : .ifi_index = ifindex,
689 : : },
690 : : };
691 : : struct rtattr *rta;
692 : :
693 : : /* Add MAC address attribute */
694 : : rta = (struct rtattr *)((char *)&req + NLMSG_ALIGN(req.nh.nlmsg_len));
695 : 0 : rta->rta_type = IFLA_ADDRESS;
696 : 0 : rta->rta_len = RTA_LENGTH(RTE_ETHER_ADDR_LEN);
697 : : memcpy(RTA_DATA(rta), mac, RTE_ETHER_ADDR_LEN);
698 : 0 : req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_ALIGN(rta->rta_len);
699 : :
700 [ # # ]: 0 : if (tap_nl_send(nlsk_fd, &req.nh) < 0)
701 : : return -1;
702 : :
703 : 0 : return tap_nl_recv_ack(nlsk_fd);
704 : : }
|