chiark / gitweb /
rtnl: add preliminary support for containers
[elogind.git] / src / libsystemd-rtnl / rtnl-message.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <linux/rtnetlink.h>
23 #include <netinet/in.h>
24 #include <netinet/ether.h>
25 #include <stdbool.h>
26 #include <unistd.h>
27
28 #include "util.h"
29 #include "refcnt.h"
30
31 #include "sd-rtnl.h"
32 #include "rtnl-internal.h"
33
34 struct sd_rtnl_message {
35         RefCount n_ref;
36
37         struct nlmsghdr *hdr;
38
39         struct rtattr *current_container;
40
41         struct rtattr *next_rta;
42         size_t remaining_size;
43
44         bool sealed:1;
45 };
46
47 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
48         sd_rtnl_message *m;
49
50         assert_return(ret, -EINVAL);
51         assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
52
53         m = new0(sd_rtnl_message, 1);
54         if (!m)
55                 return -ENOMEM;
56
57         m->hdr = malloc0(initial_size);
58         if (!m->hdr) {
59                 free(m);
60                 return -ENOMEM;
61         }
62
63         m->n_ref = REFCNT_INIT;
64
65         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
66         m->sealed = false;
67
68         *ret = m;
69
70         return 0;
71 }
72
73 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
74         struct nlmsgerr *err;
75         int r;
76
77         assert(error <= 0);
78
79         r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
80         if (r < 0)
81                 return r;
82
83         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
84         (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
85         (*ret)->hdr->nlmsg_seq = serial;
86
87         err = NLMSG_DATA((*ret)->hdr);
88
89         err->error = error;
90
91         return 0;
92 }
93
94 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
95                               unsigned char rtm_dst_len, unsigned char rtm_src_len,
96                               unsigned char rtm_tos, unsigned char rtm_table,
97                               unsigned char rtm_scope, unsigned char rtm_protocol,
98                               unsigned char rtm_type, unsigned rtm_flags, sd_rtnl_message **ret) {
99         struct rtmsg *rtm;
100         int r;
101
102         assert_return(nlmsg_type == RTM_NEWROUTE || nlmsg_type == RTM_DELROUTE ||
103                       nlmsg_type == RTM_GETROUTE, -EINVAL);
104         assert_return(ret, -EINVAL);
105
106         r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
107         if (r < 0)
108                 return r;
109
110         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
111         (*ret)->hdr->nlmsg_type = nlmsg_type;
112         if (nlmsg_type == RTM_NEWROUTE)
113                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
114
115         rtm = NLMSG_DATA((*ret)->hdr);
116
117         rtm->rtm_family = rtm_family;
118         rtm->rtm_dst_len = rtm_dst_len;
119         rtm->rtm_src_len = rtm_src_len;
120         rtm->rtm_tos = rtm_tos;
121         rtm->rtm_table = rtm_table;
122         rtm->rtm_protocol = rtm_protocol;
123         rtm->rtm_scope = rtm_scope;
124         rtm->rtm_type = rtm_type;
125         rtm->rtm_flags = rtm_flags;
126
127         return 0;
128 }
129
130 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, unsigned int type, unsigned int flags, sd_rtnl_message **ret) {
131         struct ifinfomsg *ifi;
132         int r;
133
134         assert_return(nlmsg_type == RTM_NEWLINK || nlmsg_type == RTM_DELLINK ||
135                       nlmsg_type == RTM_SETLINK || nlmsg_type == RTM_GETLINK, -EINVAL);
136         assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
137         assert_return(ret, -EINVAL);
138
139         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
140         if (r < 0)
141                 return r;
142
143         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
144         (*ret)->hdr->nlmsg_type = nlmsg_type;
145         if (nlmsg_type == RTM_NEWLINK)
146                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
147
148         ifi = NLMSG_DATA((*ret)->hdr);
149
150         ifi->ifi_family = AF_UNSPEC;
151         ifi->ifi_index = index;
152         ifi->ifi_type = type;
153         ifi->ifi_flags = flags;
154         ifi->ifi_change = 0xffffffff;
155
156         return 0;
157 }
158
159 int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family, unsigned char prefixlen, unsigned char flags, unsigned char scope, sd_rtnl_message **ret) {
160         struct ifaddrmsg *ifa;
161         int r;
162
163         assert_return(nlmsg_type == RTM_NEWADDR || nlmsg_type == RTM_DELADDR || nlmsg_type == RTM_GETADDR, -EINVAL);
164         assert_return(index > 0, -EINVAL);
165         assert_return(ret, -EINVAL);
166
167         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
168         if (r < 0)
169                 return r;
170
171         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
172         (*ret)->hdr->nlmsg_type = nlmsg_type;
173
174         ifa = NLMSG_DATA((*ret)->hdr);
175
176         ifa->ifa_family = family;
177         ifa->ifa_prefixlen = prefixlen;
178         ifa->ifa_flags = flags;
179         ifa->ifa_scope = scope;
180         ifa->ifa_index = index;
181
182         return 0;
183 }
184
185 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
186         if (m)
187                 assert_se(REFCNT_INC(m->n_ref) >= 2);
188
189         return m;
190 }
191
192 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
193         if (m && REFCNT_DEC(m->n_ref) <= 0) {
194                 free(m->hdr);
195                 free(m);
196         }
197
198         return NULL;
199 }
200
201 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
202         assert_return(m, -EINVAL);
203         assert_return(type, -EINVAL);
204
205         *type = m->hdr->nlmsg_type;
206
207         return 0;
208 }
209
210 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
211         struct ifinfomsg *ifi;
212
213         assert_return(m, -EINVAL);
214         assert_return(ifindex, -EINVAL);
215         assert_return(m->hdr->nlmsg_type == RTM_NEWLINK || m->hdr->nlmsg_type == RTM_DELLINK ||
216                       m->hdr->nlmsg_type == RTM_GETLINK || m->hdr->nlmsg_type == RTM_SETLINK, -EINVAL);
217
218         ifi = NLMSG_DATA(m->hdr);
219
220         *ifindex = ifi->ifi_index;
221
222         return 0;
223 }
224
225 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
226    untouched */
227 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
228         uint32_t rta_length, message_length;
229         struct nlmsghdr *new_hdr;
230         struct rtattr *rta;
231         char *padding;
232
233         assert(m);
234         assert(m->hdr);
235         assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
236         assert(!data || data_length > 0);
237
238         /* get the size of the new rta attribute (with padding at the end) */
239         rta_length = RTA_LENGTH(data_length);
240         /* get the new message size (with padding at the end)
241          */
242         message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
243
244         /* realloc to fit the new attribute */
245         new_hdr = realloc(m->hdr, message_length);
246         if (!new_hdr)
247                 return -ENOMEM;
248         m->hdr = new_hdr;
249
250         /* get pointer to the attribute we are about to add */
251         rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
252         /* update message size */
253         m->hdr->nlmsg_len = message_length;
254
255         /* we are inside a container, extend it */
256         if (m->current_container)
257                 m->current_container->rta_len = (unsigned char *) m->hdr +
258                                                 m->hdr->nlmsg_len -
259                                                 (unsigned char *) m->current_container;
260
261         /* fill in the attribute */
262         rta->rta_type = type;
263         rta->rta_len = rta_length;
264         if (!data) {
265                 /* this is a container, set pointer */
266                 m->current_container = rta;
267         } else {
268                 /* we don't deal with the case where the user lies about the type
269                  * and gives us too little data (so don't do that)
270                 */
271                 padding = mempcpy(RTA_DATA(rta), data, data_length);
272                 /* make sure also the padding at the end of the message is initialized */
273                 memset(padding, '\0', (unsigned char *) m->hdr +
274                                       m->hdr->nlmsg_len -
275                                       (unsigned char *) padding);
276         }
277
278         return 0;
279 }
280
281 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
282         uint16_t rtm_type;
283         struct ifaddrmsg *ifa;
284         struct rtmsg *rtm;
285
286         assert_return(m, -EINVAL);
287         assert_return(data, -EINVAL);
288
289         sd_rtnl_message_get_type(m, &rtm_type);
290
291         if (m->current_container) {
292                 switch (rtm_type) {
293                         case RTM_NEWLINK:
294                         case RTM_SETLINK:
295                         case RTM_GETLINK:
296                         case RTM_DELLINK:
297                                 switch (m->current_container->rta_type) {
298                                         case IFLA_LINKINFO:
299                                                 switch (type) {
300                                                         case IFLA_INFO_KIND:
301                                                                 return add_rtattr(m, type, data, strlen(data) + 1);
302                                                         default:
303                                                                 return -ENOTSUP;
304                                                 }
305                                         default:
306                                                 return -ENOTSUP;
307                                 }
308                         default:
309                                 return -ENOTSUP;
310                 }
311         }
312
313         switch (rtm_type) {
314                 case RTM_NEWLINK:
315                 case RTM_SETLINK:
316                 case RTM_DELLINK:
317                 case RTM_GETLINK:
318                         switch (type) {
319                                 case IFLA_IFNAME:
320                                 case IFLA_IFALIAS:
321                                 case IFLA_QDISC:
322                                         return add_rtattr(m, type, data, strlen(data) + 1);
323                                 case IFLA_MTU:
324                                 case IFLA_LINK:
325                                         return add_rtattr(m, type, data, sizeof(uint32_t));
326                                 case IFLA_STATS:
327                                         return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
328                                 case IFLA_ADDRESS:
329                                 case IFLA_BROADCAST:
330                                         return add_rtattr(m, type, data, ETH_ALEN);
331                                 default:
332                                         return -ENOTSUP;
333                         }
334                 case RTM_NEWADDR:
335                 case RTM_DELADDR:
336                 case RTM_GETADDR:
337                         switch (type) {
338                                 case IFA_LABEL:
339                                         return add_rtattr(m, type, data, strlen(data) + 1);
340                                 case IFA_ADDRESS:
341                                 case IFA_LOCAL:
342                                 case IFA_BROADCAST:
343                                 case IFA_ANYCAST:
344                                         ifa = NLMSG_DATA(m->hdr);
345                                         switch (ifa->ifa_family) {
346                                                 case AF_INET:
347                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
348                                                 case AF_INET6:
349                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
350                                                 default:
351                                                         return -EINVAL;
352                                         }
353                                 default:
354                                         return -ENOTSUP;
355                         }
356                 case RTM_NEWROUTE:
357                 case RTM_DELROUTE:
358                 case RTM_GETROUTE:
359                         switch (type) {
360                                 case RTA_DST:
361                                 case RTA_SRC:
362                                 case RTA_GATEWAY:
363                                         rtm = NLMSG_DATA(m->hdr);
364                                         switch (rtm->rtm_family) {
365                                                 case AF_INET:
366                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
367                                                 case AF_INET6:
368                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
369                                                 default:
370                                                         return -EINVAL;
371                                         }
372                                 case RTA_TABLE:
373                                 case RTA_PRIORITY:
374                                 case RTA_IIF:
375                                 case RTA_OIF:
376                                         return add_rtattr(m, type, data, sizeof(uint32_t));
377                                 default:
378                                         return -ENOTSUP;
379                         }
380                 default:
381                         return -ENOTSUP;
382         }
383 }
384
385 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
386         uint16_t rtm_type;
387
388         assert_return(m, -EINVAL);
389         assert_return(!m->current_container, -EINVAL);
390
391         sd_rtnl_message_get_type(m, &rtm_type);
392
393         switch (rtm_type) {
394                 case RTM_NEWLINK:
395                 case RTM_SETLINK:
396                 case RTM_GETLINK:
397                 case RTM_DELLINK:
398                         if (type == IFLA_LINKINFO)
399                                 return add_rtattr(m, type, NULL, 0);
400                         else
401                                 return -ENOTSUP;
402                 default:
403                         return -ENOTSUP;
404         }
405
406         return 0;
407 }
408
409 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
410         assert_return(m, -EINVAL);
411         assert_return(m->current_container, -EINVAL);
412
413         m->current_container = NULL;
414
415         return 0;
416 }
417
418 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
419         uint16_t rtm_type;
420         int r;
421
422         assert(m);
423         assert(m->next_rta);
424         assert(type);
425         assert(data);
426
427         if (!RTA_OK(m->next_rta, m->remaining_size))
428                 return 0;
429
430         /* make sure we don't try to read a container
431          * TODO: add support for entering containers for reading */
432         r = sd_rtnl_message_get_type(m, &rtm_type);
433         if (r < 0)
434                 return r;
435
436         switch (rtm_type) {
437                 case RTM_NEWLINK:
438                 case RTM_GETLINK:
439                 case RTM_SETLINK:
440                 case RTM_DELLINK:
441                         if (m->next_rta->rta_type == IFLA_LINKINFO) {
442                                 return -EINVAL;
443                         }
444         }
445
446         *data = RTA_DATA(m->next_rta);
447         *type = m->next_rta->rta_type;
448
449         m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
450
451         return 1;
452 }
453
454 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
455         uint16_t rtm_type;
456         int r;
457
458         assert_return(m, -EINVAL);
459         assert_return(data, -EINVAL);
460
461         r = sd_rtnl_message_get_type(m, &rtm_type);
462         if (r < 0)
463                 return r;
464
465         switch (rtm_type) {
466                 case RTM_NEWLINK:
467                 case RTM_SETLINK:
468                 case RTM_DELLINK:
469                 case RTM_GETLINK:
470                         if (!m->next_rta) {
471                                 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
472
473                                 m->next_rta = IFLA_RTA(ifi);
474                                 m->remaining_size = IFLA_PAYLOAD(m->hdr);
475                         }
476                         break;
477                 case RTM_NEWADDR:
478                 case RTM_DELADDR:
479                 case RTM_GETADDR:
480                         if (!m->next_rta) {
481                                 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
482
483                                 m->next_rta = IFA_RTA(ifa);
484                                 m->remaining_size = IFA_PAYLOAD(m->hdr);
485                         }
486                         break;
487                 case RTM_NEWROUTE:
488                 case RTM_DELROUTE:
489                 case RTM_GETROUTE:
490                         if (!m->next_rta) {
491                                 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
492
493                                 m->next_rta = RTM_RTA(rtm);
494                                 m->remaining_size = RTM_PAYLOAD(m->hdr);
495                         }
496                         break;
497                 default:
498                         return -ENOTSUP;
499         }
500
501         return message_read(m, type, data);
502 }
503
504 uint32_t message_get_serial(sd_rtnl_message *m) {
505         assert(m);
506
507         return m->hdr->nlmsg_seq;
508 }
509
510 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
511         struct nlmsgerr *err;
512
513         assert_return(m, -EINVAL);
514
515         if (m->hdr->nlmsg_type != NLMSG_ERROR)
516                 return 0;
517
518         err = NLMSG_DATA(m->hdr);
519
520         return err->error;
521 }
522
523 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
524         if (m->sealed)
525                 return -EPERM;
526
527         m->hdr->nlmsg_seq = nl->serial++;
528         m->sealed = true;
529
530         return 0;
531 }
532
533 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
534         assert_return(rtnl, -EINVAL);
535         assert_return(need, -EINVAL);
536
537         /* ioctl(rtnl->fd, FIONREAD, &need)
538            Does not appear to work on netlink sockets. libnl uses
539            MSG_PEEK instead. I don't know if that is worth the
540            extra roundtrip.
541
542            For now we simply use the maximum message size the kernel
543            may use (NLMSG_GOODSIZE), and then realloc to the actual
544            size after reading the message (hence avoiding huge memory
545            usage in case many small messages are kept around) */
546         *need = page_size();
547         if (*need > 8192UL)
548                 *need = 8192UL;
549
550         return 0;
551 }
552
553 /* returns the number of bytes sent, or a negative error code */
554 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
555         union {
556                 struct sockaddr sa;
557                 struct sockaddr_nl nl;
558         } addr = {
559                 .nl.nl_family = AF_NETLINK,
560         };
561         ssize_t k;
562
563         assert_return(nl, -EINVAL);
564         assert_return(m, -EINVAL);
565
566         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
567                         0, &addr.sa, sizeof(addr));
568         if (k < 0)
569                 return (errno == EAGAIN) ? 0 : -errno;
570
571         return k;
572 }
573
574 /* On success, the number of bytes received is returned and *ret points to the received message
575  * which has a valid header and the correct size.
576  * If nothing useful was received 0 is returned.
577  * On failure, a negative error code is returned.
578  */
579 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
580         sd_rtnl_message *m;
581         union {
582                 struct sockaddr sa;
583                 struct sockaddr_nl nl;
584         } addr;
585         socklen_t addr_len;
586         int r;
587         ssize_t k;
588         size_t need;
589
590         assert_return(nl, -EINVAL);
591         assert_return(ret, -EINVAL);
592
593         r = message_receive_need(nl, &need);
594         if (r < 0)
595                 return r;
596
597         r = message_new(&m, need);
598         if (r < 0)
599                 return r;
600
601         addr_len = sizeof(addr);
602
603         k = recvfrom(nl->fd, m->hdr, need,
604                         0, &addr.sa, &addr_len);
605         if (k < 0)
606                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
607         else if (k == 0)
608                 k = -ECONNRESET; /* connection was closed by the kernel */
609         else if (addr_len != sizeof(addr.nl) ||
610                         addr.nl.nl_family != AF_NETLINK)
611                 k = -EIO; /* not a netlink message */
612         else if (addr.nl.nl_pid != 0)
613                 k = 0; /* not from the kernel */
614         else if ((size_t) k < sizeof(struct nlmsghdr) ||
615                         (size_t) k < m->hdr->nlmsg_len)
616                 k = -EIO; /* too small (we do accept too big though) */
617         else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
618                 k = 0; /* not for us */
619
620         if (k > 0)
621                 switch (m->hdr->nlmsg_type) {
622                         /* check that the size matches the message type */
623                         case NLMSG_ERROR:
624                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
625                                         k = -EIO;
626                                 break;
627                         case RTM_NEWLINK:
628                         case RTM_SETLINK:
629                         case RTM_DELLINK:
630                         case RTM_GETLINK:
631                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
632                                         k = -EIO;
633                                 break;
634                         case RTM_NEWADDR:
635                         case RTM_DELADDR:
636                         case RTM_GETADDR:
637                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
638                                         k = -EIO;
639                                 break;
640                         case NLMSG_NOOP:
641                                 k = 0;
642                                 break;
643                         default:
644                                 k = 0; /* ignoring message of unknown type */
645                 }
646
647         if (k <= 0)
648                 sd_rtnl_message_unref(m);
649         else {
650                 /* we probably allocated way too much memory, give it back */
651                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
652                 *ret = m;
653         }
654
655         return k;
656 }