[systemd-commits] 6 commits - src/libsystemd src/network src/systemd

Tom Gundersen tomegun at kemper.freedesktop.org
Mon Apr 14 08:57:02 PDT 2014


 src/libsystemd/sd-rtnl/rtnl-internal.h |    5 +
 src/libsystemd/sd-rtnl/rtnl-message.c  |  164 ++++++++++++++++++++++++---------
 src/libsystemd/sd-rtnl/sd-rtnl.c       |    8 +
 src/network/networkd-link.c            |   14 +-
 src/systemd/sd-rtnl.h                  |    6 +
 5 files changed, 149 insertions(+), 48 deletions(-)

New commits:
commit 3379e257ee06f997ec756cd70008353796457b43
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Apr 14 17:55:47 2014 +0200

    networkd: link - make state changing logging a bit less verbose

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 927dbb1..f179af3 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1074,14 +1074,14 @@ static int link_update_flags(Link *link, unsigned flags) {
                 log_info_link(link, "link is down");
 
         if (flags_added & IFF_LOWER_UP)
-                log_info_link(link, "link is lower up");
+                log_debug_link(link, "link is lower up");
         else if (flags_removed & IFF_LOWER_UP)
-                log_info_link(link, "link is lower down");
+                log_debug_link(link, "link is lower down");
 
         if (flags_added & IFF_RUNNING)
-                log_info_link(link, "link is running");
+                log_debug_link(link, "link is running");
         else if (flags_removed & IFF_RUNNING)
-                log_info_link(link, "link is not running");
+                log_debug_link(link, "link is not running");
 
         if (carrier_gained) {
                 log_info_link(link, "gained carrier");

commit b9ef681b04644493fca7c1d5611db7169697d26a
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Apr 14 12:42:11 2014 +0200

    sd-rtnl: message_addr - allow dumping of messages

diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index a93cb0c..1afba8f 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -326,15 +326,17 @@ int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
         int r;
 
         assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
-        assert_return(index > 0, -EINVAL);
-        assert_return(family == AF_INET || family == AF_INET6, -EINVAL);
+        assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
+                      index > 0, -EINVAL);
+        assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
+                      family == AF_INET || family == AF_INET6, -EINVAL);
         assert_return(ret, -EINVAL);
 
         r = message_new(rtnl, ret, nlmsg_type);
         if (r < 0)
                 return r;
 
-        if (nlmsg_type == RTM_GETADDR && family == AF_INET)
+        if (nlmsg_type == RTM_GETADDR)
                 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
 
         ifa = NLMSG_DATA((*ret)->hdr);

commit a88f77c406ea56160c1e5a4b39eab1de134abe40
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Apr 14 17:20:51 2014 +0200

    sd-rtnl: socket_read - use a read buffer
    
    Rather than allocating/freeing memory for each message read, keep a global read buffer
    in the rtnl object. Also, rather than using a fixed size, peek at the pending message
    header to get the message size and reallocate as necessary.

diff --git a/src/libsystemd/sd-rtnl/rtnl-internal.h b/src/libsystemd/sd-rtnl/rtnl-internal.h
index 2f788d0..6dd65b2 100644
--- a/src/libsystemd/sd-rtnl/rtnl-internal.h
+++ b/src/libsystemd/sd-rtnl/rtnl-internal.h
@@ -72,6 +72,9 @@ struct sd_rtnl {
         unsigned wqueue_size;
         size_t wqueue_allocated;
 
+        struct nlmsghdr *rbuffer;
+        size_t rbuffer_allocated;
+
         bool processing:1;
 
         uint32_t serial;
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index 3a24cb8..a93cb0c 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -997,26 +997,6 @@ int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
         return err->error;
 }
 
-static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
-        assert(rtnl);
-        assert(need);
-
-        /* ioctl(rtnl->fd, FIONREAD, &need)
-           Does not appear to work on netlink sockets. libnl uses
-           MSG_PEEK instead. I don't know if that is worth the
-           extra roundtrip.
-
-           For now we simply use the maximum message size the kernel
-           may use (NLMSG_GOODSIZE), and then realloc to the actual
-           size after reading the message (hence avoiding huge memory
-           usage in case many small messages are kept around) */
-        *need = page_size();
-        if (*need > 8192UL)
-                *need = 8192UL;
-
-        return 0;
-}
-
 int rtnl_message_parse(sd_rtnl_message *m,
                        size_t **rta_offset_tb,
                        unsigned short *rta_tb_size,
@@ -1082,7 +1062,6 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
 int socket_read_message(sd_rtnl *rtnl) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
         sd_rtnl_message *previous = NULL;
-        _cleanup_free_ void *buffer = NULL;
         uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
         struct iovec iov = {};
         struct msghdr msg = {
@@ -1094,23 +1073,37 @@ int socket_read_message(sd_rtnl *rtnl) {
         struct cmsghdr *cmsg;
         bool auth = false;
         struct nlmsghdr *new_msg;
-        size_t need, len;
+        size_t len;
         int r, ret = 0;
 
         assert(rtnl);
+        assert(rtnl->rbuffer);
 
-        r = message_receive_need(rtnl, &need);
+        iov.iov_base = rtnl->rbuffer;
+        iov.iov_len = rtnl->rbuffer_allocated;
+
+        /* peek at the pending message header to get the message size */
+        r = recvmsg(rtnl->fd, &msg, MSG_PEEK);
         if (r < 0)
-                return r;
+                /* no data */
+                return (errno == EAGAIN) ? 0 : -errno;
+        else if (r == 0)
+                /* connection was closed by the kernel */
+                return -ECONNRESET;
+        else if ((size_t)r < sizeof(struct nlmsghdr))
+                return -EIO;
 
-        buffer = malloc0(need);
-        if (!buffer)
+        /* make room for the pending message */
+        if (!greedy_realloc((void **)&rtnl->rbuffer,
+                            &rtnl->rbuffer_allocated,
+                            rtnl->rbuffer->nlmsg_len,
+                            sizeof(uint8_t)))
                 return -ENOMEM;
 
-        iov.iov_base = buffer;
-        iov.iov_len = need;
+        iov.iov_base = rtnl->rbuffer;
+        iov.iov_len = rtnl->rbuffer_allocated;
 
-        r = recvmsg(rtnl->fd, &msg, 0);
+        r = recvmsg(rtnl->fd, &msg, MSG_TRUNC);
         if (r < 0)
                 /* no data */
                 return (errno == EAGAIN) ? 0 : -errno;
@@ -1120,6 +1113,10 @@ int socket_read_message(sd_rtnl *rtnl) {
         else
                 len = (size_t)r;
 
+        if (len > rtnl->rbuffer_allocated)
+                /* message did not fit in read buffer */
+                return -EIO;
+
         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
                 if (cmsg->cmsg_level == SOL_SOCKET &&
                     cmsg->cmsg_type == SCM_CREDENTIALS &&
@@ -1138,7 +1135,7 @@ int socket_read_message(sd_rtnl *rtnl) {
                 /* not from the kernel, ignore */
                 return 0;
 
-        for (new_msg = buffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
+        for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
                 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
                 const NLType *nl_type;
 
diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c
index 367f165..e4d436b 100644
--- a/src/libsystemd/sd-rtnl/sd-rtnl.c
+++ b/src/libsystemd/sd-rtnl/sd-rtnl.c
@@ -54,6 +54,12 @@ static int sd_rtnl_new(sd_rtnl **ret) {
         if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
                 return -ENOMEM;
 
+        /* We guarantee that the read buffer has at least space for
+         * a message header */
+        if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
+                            sizeof(struct nlmsghdr), sizeof(uint8_t)))
+                return -ENOMEM;
+
         *ret = rtnl;
         rtnl = NULL;
 
@@ -133,6 +139,8 @@ sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
                         sd_rtnl_message_unref(rtnl->wqueue[i]);
                 free(rtnl->wqueue);
 
+                free(rtnl->rbuffer);
+
                 hashmap_free_free(rtnl->reply_callbacks);
                 prioq_free(rtnl->reply_callbacks_prioq);
 

commit 1403f45ab61d6f2026a3a7a06b52a536c1b7a3b3
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun Apr 13 21:37:53 2014 +0200

    sd-rtnl: multi-part message - store as linked-list rather than independent messages
    
    This means the API can stay the same as for single-part messages by simply passing the head message around. Unrefing
    the head of the linked list unrefs the whole list.

diff --git a/src/libsystemd/sd-rtnl/rtnl-internal.h b/src/libsystemd/sd-rtnl/rtnl-internal.h
index 9d857ed..2f788d0 100644
--- a/src/libsystemd/sd-rtnl/rtnl-internal.h
+++ b/src/libsystemd/sd-rtnl/rtnl-internal.h
@@ -102,6 +102,8 @@ struct sd_rtnl_message {
         size_t *rta_offset_tb[RTNL_CONTAINER_DEPTH];
         unsigned short rta_tb_size[RTNL_CONTAINER_DEPTH];
         bool sealed:1;
+
+        sd_rtnl_message *next; /* next in a chain of multi-part messages */
 };
 
 int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type);
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index fc71ed9..3a24cb8 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -378,6 +378,8 @@ sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
                 for (i = 0; i <= m->n_containers; i++)
                         free(m->rta_offset_tb[i]);
 
+                sd_rtnl_message_unref(m->next);
+
                 free(m);
         }
 
@@ -1078,6 +1080,8 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
  * On failure, a negative error code is returned.
  */
 int socket_read_message(sd_rtnl *rtnl) {
+        _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
+        sd_rtnl_message *previous = NULL;
         _cleanup_free_ void *buffer = NULL;
         uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
         struct iovec iov = {};
@@ -1146,6 +1150,10 @@ int socket_read_message(sd_rtnl *rtnl) {
                 if (new_msg->nlmsg_type == NLMSG_NOOP)
                         continue;
 
+                /* finished reading multi-part message */
+                if (new_msg->nlmsg_type == NLMSG_DONE)
+                        break;
+
                 /* check that we support this message type */
                 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
                 if (r < 0) {
@@ -1173,21 +1181,30 @@ int socket_read_message(sd_rtnl *rtnl) {
                 if (r < 0)
                         return r;
 
-                r = rtnl_rqueue_make_room(rtnl);
-                if (r < 0)
-                        return r;
+                if (!first)
+                        first = m;
+                else {
+                        assert(previous);
 
-                rtnl->rqueue[rtnl->rqueue_size ++] = m;
+                        previous->next = m;
+                }
+                previous = m;
                 m = NULL;
+
                 ret += new_msg->nlmsg_len;
 
-                /* reached end of multi-part message, or not a multi-part
-                   message at all */
-                if (new_msg->nlmsg_type == NLMSG_DONE ||
-                    !(new_msg->nlmsg_flags & NLM_F_MULTI))
+                /* not a multi-part message, so stop reading*/
+                if (!(new_msg->nlmsg_flags & NLM_F_MULTI))
                         break;
         }
 
+        r = rtnl_rqueue_make_room(rtnl);
+        if (r < 0)
+                return r;
+
+        rtnl->rqueue[rtnl->rqueue_size ++] = first;
+        first = NULL;
+
         return ret;
 }
 
@@ -1249,3 +1266,9 @@ void rtnl_message_seal(sd_rtnl_message *m) {
 
         m->sealed = true;
 }
+
+sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
+        assert_return(m, NULL);
+
+        return m->next;
+}
diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h
index c32c5e2..6fbaee0 100644
--- a/src/systemd/sd-rtnl.h
+++ b/src/systemd/sd-rtnl.h
@@ -123,6 +123,8 @@ int sd_rtnl_message_exit_container(sd_rtnl_message *m);
 
 int sd_rtnl_message_rewind(sd_rtnl_message *m);
 
+sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m);
+
 _SD_END_DECLARATIONS;
 
 #endif

commit e00d77ddd598ea6cbc2d512d143e9e4d98e62256
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Apr 14 12:41:13 2014 +0200

    sd-rtnl: message_addr - expose a few more getters

diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index c9f3487..fc71ed9 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -259,6 +259,66 @@ int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
         return 0;
 }
 
+int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, unsigned char *family) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(family, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *family = ifa->ifa_family;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(scope, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *scope = ifa->ifa_scope;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(flags, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *flags = ifa->ifa_flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(ifindex, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *ifindex = ifa->ifa_index;
+
+        return 0;
+}
+
 int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
                              uint16_t nlmsg_type, int index,
                              unsigned char family) {
diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h
index f7f7074..c32c5e2 100644
--- a/src/systemd/sd-rtnl.h
+++ b/src/systemd/sd-rtnl.h
@@ -84,6 +84,10 @@ int sd_rtnl_message_is_broadcast(sd_rtnl_message *m);
 int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen);
 int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope);
 int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags);
+int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, unsigned char *family);
+int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope);
+int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags);
+int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex);
 
 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change);
 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type);

commit e9189a1f56e5dd418d13dfcf3a7f5a701884858e
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun Apr 13 22:10:34 2014 +0200

    networkd: link - ignore missing MAC address from NEWLINK message
    
    The kernel may broadcast such messages, simply discard them.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 7f81538..927dbb1 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1490,10 +1490,10 @@ int link_update(Link *link, sd_rtnl_message *m) {
                                        PRIu16, link->original_mtu);
         }
 
+        /* The kernel may broadcast NEWLINK messages without the MAC address
+           set, simply ignore them. */
         r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
-        if (r < 0)
-                log_debug_link(link, "Could not get MAC address: %s", strerror(-r));
-        else {
+        if (r >= 0) {
                 if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN)) {
 
                         memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN);



More information about the systemd-commits mailing list