1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/rtnetlink.h>
23 #include <netinet/in.h>
24 #include <netinet/ether.h>
32 #include "rtnl-internal.h"
34 struct sd_rtnl_message {
38 size_t container_offsets[RTNL_CONTAINER_DEPTH]; /* offset from hdr to each container's start */
39 unsigned n_containers; /* number of containers */
40 size_t next_rta_offset; /* offset from hdr to next rta */
45 #define GET_CONTAINER(m, i) (i < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
46 #define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
47 #define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
49 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
52 assert_return(ret, -EINVAL);
53 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
55 m = new0(sd_rtnl_message, 1);
59 m->hdr = malloc0(initial_size);
65 m->n_ref = REFCNT_INIT;
67 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
75 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
81 r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
85 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
86 (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
87 (*ret)->hdr->nlmsg_seq = serial;
89 err = NLMSG_DATA((*ret)->hdr);
96 bool message_type_is_route(uint16_t type) {
107 bool message_type_is_link(uint16_t type) {
119 bool message_type_is_addr(uint16_t type) {
130 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
133 assert_return(m, -EINVAL);
134 assert_return(m->hdr, -EINVAL);
135 assert_return(message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
137 rtm = NLMSG_DATA(m->hdr);
139 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
140 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
143 rtm->rtm_dst_len = prefixlen;
148 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
149 sd_rtnl_message **ret) {
153 assert_return(message_type_is_route(nlmsg_type), -EINVAL);
154 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
155 assert_return(ret, -EINVAL);
157 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
161 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
162 (*ret)->hdr->nlmsg_type = nlmsg_type;
163 if (nlmsg_type == RTM_NEWROUTE)
164 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
166 rtm = NLMSG_DATA((*ret)->hdr);
168 UPDATE_RTA(*ret, RTM_RTA(rtm));
170 rtm->rtm_family = rtm_family;
171 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
172 rtm->rtm_type = RTN_UNICAST;
173 rtm->rtm_table = RT_TABLE_MAIN;
174 rtm->rtm_protocol = RTPROT_BOOT;
179 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
180 struct ifinfomsg *ifi;
182 assert_return(m, -EINVAL);
183 assert_return(m->hdr, -EINVAL);
184 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
186 ifi = NLMSG_DATA(m->hdr);
188 ifi->ifi_flags = flags;
190 ifi->ifi_change = change;
192 ifi->ifi_change = 0xffffffff;
197 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
198 struct ifinfomsg *ifi;
200 assert_return(m, -EINVAL);
201 assert_return(m->hdr, -EINVAL);
202 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
204 ifi = NLMSG_DATA(m->hdr);
206 ifi->ifi_type = type;
211 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
212 struct ifinfomsg *ifi;
215 assert_return(message_type_is_link(nlmsg_type), -EINVAL);
216 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
217 assert_return(ret, -EINVAL);
219 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
223 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
224 (*ret)->hdr->nlmsg_type = nlmsg_type;
225 if (nlmsg_type == RTM_NEWLINK)
226 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
228 ifi = NLMSG_DATA((*ret)->hdr);
230 ifi->ifi_family = AF_UNSPEC;
231 ifi->ifi_index = index;
233 UPDATE_RTA(*ret, IFLA_RTA(ifi));
238 int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
239 struct ifaddrmsg *ifa;
241 assert_return(m, -EINVAL);
242 assert_return(m->hdr, -EINVAL);
243 assert_return(message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
245 ifa = NLMSG_DATA(m->hdr);
247 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
248 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
251 ifa->ifa_prefixlen = prefixlen;
256 int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
257 struct ifaddrmsg *ifa;
259 assert_return(m, -EINVAL);
260 assert_return(m->hdr, -EINVAL);
261 assert_return(message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
263 ifa = NLMSG_DATA(m->hdr);
265 ifa->ifa_flags = flags;
270 int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
271 struct ifaddrmsg *ifa;
273 assert_return(m, -EINVAL);
274 assert_return(m->hdr, -EINVAL);
275 assert_return(message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
277 ifa = NLMSG_DATA(m->hdr);
279 ifa->ifa_scope = scope;
284 int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family,
285 sd_rtnl_message **ret) {
286 struct ifaddrmsg *ifa;
289 assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
290 assert_return(index > 0, -EINVAL);
291 assert_return(family == AF_INET || family == AF_INET6, -EINVAL);
292 assert_return(ret, -EINVAL);
294 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
298 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
299 (*ret)->hdr->nlmsg_type = nlmsg_type;
301 ifa = NLMSG_DATA((*ret)->hdr);
303 ifa->ifa_index = index;
304 ifa->ifa_family = family;
305 if (family == AF_INET)
306 ifa->ifa_prefixlen = 32;
307 else if (family == AF_INET6)
308 ifa->ifa_prefixlen = 128;
310 UPDATE_RTA(*ret, IFA_RTA(ifa));
315 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
317 assert_se(REFCNT_INC(m->n_ref) >= 2);
322 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
323 if (m && REFCNT_DEC(m->n_ref) <= 0) {
331 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
332 assert_return(m, -EINVAL);
333 assert_return(type, -EINVAL);
335 *type = m->hdr->nlmsg_type;
340 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
341 struct ifinfomsg *ifi;
343 assert_return(m, -EINVAL);
344 assert_return(m->hdr, -EINVAL);
345 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
346 assert_return(ifindex, -EINVAL);
348 ifi = NLMSG_DATA(m->hdr);
350 *ifindex = ifi->ifi_index;
355 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
356 struct ifinfomsg *ifi;
358 assert_return(m, -EINVAL);
359 assert_return(m->hdr, -EINVAL);
360 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
361 assert_return(flags, -EINVAL);
363 ifi = NLMSG_DATA(m->hdr);
365 *flags = ifi->ifi_flags;
370 /* If successful the updated message will be correctly aligned, if
371 unsuccessful the old message is untouched. */
372 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
373 uint32_t rta_length, message_length;
374 struct nlmsghdr *new_hdr;
381 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
382 assert(!data || data_length > 0);
383 assert(data || m->n_containers < RTNL_CONTAINER_DEPTH);
385 /* get the size of the new rta attribute (with padding at the end) */
386 rta_length = RTA_LENGTH(data_length);
388 /* get the new message size (with padding at the end) */
389 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
391 /* realloc to fit the new attribute */
392 new_hdr = realloc(m->hdr, message_length);
397 /* get pointer to the attribute we are about to add */
398 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
400 /* if we are inside containers, extend them */
401 for (i = 0; i < m->n_containers; i++)
402 GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len;
404 /* fill in the attribute */
405 rta->rta_type = type;
406 rta->rta_len = rta_length;
408 /* this is the start of a new container */
409 m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len;
411 /* we don't deal with the case where the user lies about the type
412 * and gives us too little data (so don't do that)
414 padding = mempcpy(RTA_DATA(rta), data, data_length);
415 /* make sure also the padding at the end of the message is initialized */
417 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
420 /* update message size */
421 m->hdr->nlmsg_len = message_length;
426 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
430 assert_return(m, -EINVAL);
431 assert_return(data, -EINVAL);
433 r = sd_rtnl_message_get_type(m, &rtm_type);
437 /* check that the type is correct */
443 if (m->n_containers == 1) {
444 if (GET_CONTAINER(m, 0)->rta_type != IFLA_LINKINFO ||
445 type != IFLA_INFO_KIND)
461 if (type != IFA_LABEL)
468 r = add_rtattr(m, type, data, strlen(data) + 1);
475 int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
479 assert_return(m, -EINVAL);
481 r = sd_rtnl_message_get_type(m, &rtm_type);
485 /* check that the type is correct */
491 if (m->n_containers == 2 &&
492 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
493 GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA &&
494 type == IFLA_VLAN_ID)
503 r = add_rtattr(m, type, &data, sizeof(uint16_t));
510 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
514 assert_return(m, -EINVAL);
516 r = sd_rtnl_message_get_type(m, &rtm_type);
520 /* check that the type is correct */
552 r = add_rtattr(m, type, &data, sizeof(uint32_t));
559 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
560 struct ifaddrmsg *ifa;
565 assert_return(m, -EINVAL);
566 assert_return(data, -EINVAL);
568 r = sd_rtnl_message_get_type(m, &rtm_type);
572 /* check that the type is correct */
582 ifa = NLMSG_DATA(m->hdr);
584 if (ifa->ifa_family != AF_INET)
599 rtm = NLMSG_DATA(m->hdr);
601 if (rtm->rtm_family != AF_INET)
613 r = add_rtattr(m, type, data, sizeof(struct in_addr));
620 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
621 struct ifaddrmsg *ifa;
626 assert_return(m, -EINVAL);
627 assert_return(data, -EINVAL);
629 r = sd_rtnl_message_get_type(m, &rtm_type);
633 /* check that the type is correct */
643 ifa = NLMSG_DATA(m->hdr);
645 if (ifa->ifa_family != AF_INET6)
660 rtm = NLMSG_DATA(m->hdr);
662 if (rtm->rtm_family != AF_INET6)
673 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
680 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
684 assert_return(m, -EINVAL);
685 assert_return(data, -EINVAL);
687 sd_rtnl_message_get_type(m, &rtm_type);
706 r = add_rtattr(m, type, data, ETH_ALEN);
713 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
716 assert_return(m, -EINVAL);
718 sd_rtnl_message_get_type(m, &rtm_type);
720 if (message_type_is_link(rtm_type)) {
721 if ((type == IFLA_LINKINFO && m->n_containers == 0) ||
722 (type == IFLA_INFO_DATA && m->n_containers == 1 &&
723 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO))
724 return add_rtattr(m, type, NULL, 0);
733 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
734 assert_return(m, -EINVAL);
735 assert_return(m->n_containers > 0, -EINVAL);
742 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
743 size_t remaining_size;
748 assert(m->next_rta_offset);
752 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
754 if (!RTA_OK(NEXT_RTA(m), remaining_size))
757 /* make sure we don't try to read a container
758 * TODO: add support for entering containers for reading */
759 r = sd_rtnl_message_get_type(m, &rtm_type);
763 if (message_type_is_link(rtm_type) &&
764 NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
767 *data = RTA_DATA(NEXT_RTA(m));
768 *type = NEXT_RTA(m)->rta_type;
770 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
775 uint32_t message_get_serial(sd_rtnl_message *m) {
779 return m->hdr->nlmsg_seq;
782 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
783 struct nlmsgerr *err;
785 assert_return(m, -EINVAL);
786 assert_return(m->hdr, -EINVAL);
788 if (m->hdr->nlmsg_type != NLMSG_ERROR)
791 err = NLMSG_DATA(m->hdr);
796 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
804 m->hdr->nlmsg_seq = nl->serial++;
810 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
814 /* ioctl(rtnl->fd, FIONREAD, &need)
815 Does not appear to work on netlink sockets. libnl uses
816 MSG_PEEK instead. I don't know if that is worth the
819 For now we simply use the maximum message size the kernel
820 may use (NLMSG_GOODSIZE), and then realloc to the actual
821 size after reading the message (hence avoiding huge memory
822 usage in case many small messages are kept around) */
830 /* returns the number of bytes sent, or a negative error code */
831 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
834 struct sockaddr_nl nl;
836 .nl.nl_family = AF_NETLINK,
844 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
845 0, &addr.sa, sizeof(addr));
847 return (errno == EAGAIN) ? 0 : -errno;
852 /* On success, the number of bytes received is returned and *ret points to the received message
853 * which has a valid header and the correct size.
854 * If nothing useful was received 0 is returned.
855 * On failure, a negative error code is returned.
857 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
861 struct sockaddr_nl nl;
871 r = message_receive_need(nl, &need);
875 r = message_new(&m, need);
879 addr_len = sizeof(addr);
881 k = recvfrom(nl->fd, m->hdr, need,
882 0, &addr.sa, &addr_len);
884 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
886 k = -ECONNRESET; /* connection was closed by the kernel */
887 else if (addr_len != sizeof(addr.nl) ||
888 addr.nl.nl_family != AF_NETLINK)
889 k = -EIO; /* not a netlink message */
890 else if (addr.nl.nl_pid != 0)
891 k = 0; /* not from the kernel */
892 else if ((size_t) k < sizeof(struct nlmsghdr) ||
893 (size_t) k < m->hdr->nlmsg_len)
894 k = -EIO; /* too small (we do accept too big though) */
895 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
896 k = 0; /* not broadcast and not for us */
899 switch (m->hdr->nlmsg_type) {
900 struct ifinfomsg *ifi;
901 struct ifaddrmsg *ifa;
904 /* check that the size matches the message type */
906 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
913 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
916 ifi = NLMSG_DATA(m->hdr);
917 UPDATE_RTA(m, IFLA_RTA(ifi));
923 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
926 ifa = NLMSG_DATA(m->hdr);
927 UPDATE_RTA(m, IFA_RTA(ifa));
933 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
936 rtm = NLMSG_DATA(m->hdr);
937 UPDATE_RTA(m, RTM_RTA(rtm));
944 k = 0; /* ignoring message of unknown type */
948 sd_rtnl_message_unref(m);
950 /* we probably allocated way too much memory, give it back */
951 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
958 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
959 struct ifinfomsg *ifi;
960 struct ifaddrmsg *ifa;
963 assert_return(m, -EINVAL);
964 assert_return(m->hdr, -EINVAL);
966 switch(m->hdr->nlmsg_type) {
971 ifi = NLMSG_DATA(m->hdr);
972 UPDATE_RTA(m, IFLA_RTA(ifi));
978 ifa = NLMSG_DATA(m->hdr);
979 UPDATE_RTA(m, IFA_RTA(ifa));
985 rtm = NLMSG_DATA(m->hdr);
986 UPDATE_RTA(m, RTM_RTA(rtm));