]> code.ossystems Code Review - openembedded-core.git/commitdiff
systemd: Add fix for systemd-networkd crash during free
authorRanjitsinh Rathod <ranjitsinh.rathod@kpit.com>
Wed, 22 Sep 2021 15:38:08 +0000 (21:08 +0530)
committerSteve Sakoman <steve@sakoman.com>
Thu, 30 Sep 2021 14:20:38 +0000 (04:20 -1000)
We are observing systemd-network service crash during link down
while freeing link->ifname pointer

Backtrace:
(gdb) bt
0  __GI_abort () at abort.c:107
1  0x0000007f861d32b4 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7f8628d500 "%s\n") at ../sysdeps/posix/libc_fatal.c:155
2  0x0000007f861da51c in malloc_printerr (str=str@entry=0x7f86289070 "free(): invalid next size (fast)") at malloc.c:5347
3  0x0000007f861dbd58 in _int_free (av=0x7f862c9a28 <main_arena>, p=0x558aa28eb0, have_lock=0) at malloc.c:4249
4  0x0000005569249cf0 in link_free (link=0x558aa1c0d0) at ../git/src/network/networkd-link.c:715
5  link_unref (p=0x558aa1c0d0) at ../git/src/network/networkd-link.c:734
6  0x000000556920f34c in manager_rtnl_process_link (rtnl=<optimized out>, message=0x558aa2a430, userdata=0x558a9fc630)

While checking upstream code change with regards to link->ifname
memory allocation and free, we found below PR which also fixes
random systemd-networkd crash:

https://github.com/systemd/systemd/pull/19631
https://github.com/systemd/systemd/issues/19629

Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com>
Signed-off-by: Ranjitsinh Rathod <ranjitsinhrathod1991@gmail.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
meta/recipes-core/systemd/systemd/basic-pass-allocation-info-for-ordered-set-new-and-introd.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/introduce-ordered_set_clear-free-with-destructor.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/network-add-skeleton-of-request-queue.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/network-also-drop-requests-when-link-enters-linger-state.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/network-fix-Link-reference-counter-issue.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/network-merge-link_drop-and-link_detach_from_manager.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd_244.5.bb

diff --git a/meta/recipes-core/systemd/systemd/basic-pass-allocation-info-for-ordered-set-new-and-introd.patch b/meta/recipes-core/systemd/systemd/basic-pass-allocation-info-for-ordered-set-new-and-introd.patch
new file mode 100644 (file)
index 0000000..86d9b04
--- /dev/null
@@ -0,0 +1,78 @@
+From 1f25c71d9d0b5fe6cf383c347dcebc2443a99fe1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Tue, 1 Sep 2020 12:42:35 +0200
+Subject: [PATCH] basic: pass allocation info for ordered_set_new() and
+ introduce ordered_set_ensure_put()
+
+Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/1f25c71d9d0b5fe6cf383c347dcebc2443a99fe1]
+Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com>
+
+---
+ src/basic/ordered-set.c | 21 +++++++++++++++++++++
+ src/basic/ordered-set.h | 18 +++++++-----------
+ 2 files changed, 28 insertions(+), 11 deletions(-)
+
+diff --git a/src/basic/ordered-set.c b/src/basic/ordered-set.c
+index 7fdb47e064..fb82c17b5a 100644
+--- a/src/basic/ordered-set.c
++++ b/src/basic/ordered-set.c
+@@ -4,6 +4,27 @@
+ #include "ordered-set.h"
+ #include "strv.h"
++int _ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops  HASHMAP_DEBUG_PARAMS) {
++        if (*s)
++                return 0;
++
++        *s = _ordered_set_new(ops  HASHMAP_DEBUG_PASS_ARGS);
++        if (!*s)
++                return -ENOMEM;
++
++        return 0;
++}
++
++int _ordered_set_ensure_put(OrderedSet **s, const struct hash_ops *ops, void *p  HASHMAP_DEBUG_PARAMS) {
++        int r;
++
++        r = _ordered_set_ensure_allocated(s, ops  HASHMAP_DEBUG_PASS_ARGS);
++        if (r < 0)
++                return r;
++
++        return ordered_set_put(*s, p);
++}
++
+ int ordered_set_consume(OrderedSet *s, void *p) {
+         int r;
+diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h
+index a42a57eb49..2c241a808b 100644
+--- a/src/basic/ordered-set.h
++++ b/src/basic/ordered-set.h
+@@ -7,20 +7,16 @@
+ typedef struct OrderedSet OrderedSet;
+-static inline OrderedSet* ordered_set_new(const struct hash_ops *ops) {
+-        return (OrderedSet*) ordered_hashmap_new(ops);
++static inline OrderedSet* _ordered_set_new(const struct hash_ops *ops  HASHMAP_DEBUG_PARAMS) {
++        return (OrderedSet*) internal_ordered_hashmap_new(ops  HASHMAP_DEBUG_PASS_ARGS);
+ }
++#define ordered_set_new(ops) _ordered_set_new(ops  HASHMAP_DEBUG_SRC_ARGS)
+-static inline int ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops) {
+-        if (*s)
+-                return 0;
++int _ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops  HASHMAP_DEBUG_PARAMS);
++#define ordered_set_ensure_allocated(s, ops) _ordered_set_ensure_allocated(s, ops  HASHMAP_DEBUG_SRC_ARGS)
+-        *s = ordered_set_new(ops);
+-        if (!*s)
+-                return -ENOMEM;
+-
+-        return 0;
+-}
++int _ordered_set_ensure_put(OrderedSet **s, const struct hash_ops *ops, void *p  HASHMAP_DEBUG_PARAMS);
++#define ordered_set_ensure_put(s, hash_ops, key) _ordered_set_ensure_put(s, hash_ops, key  HASHMAP_DEBUG_SRC_ARGS)
+ static inline OrderedSet* ordered_set_free(OrderedSet *s) {
+         return (OrderedSet*) ordered_hashmap_free((OrderedHashmap*) s);
diff --git a/meta/recipes-core/systemd/systemd/introduce-ordered_set_clear-free-with-destructor.patch b/meta/recipes-core/systemd/systemd/introduce-ordered_set_clear-free-with-destructor.patch
new file mode 100644 (file)
index 0000000..42b6e05
--- /dev/null
@@ -0,0 +1,35 @@
+From d38a6476aad3f2cc80a2a4bc11f3898cc06a70f5 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Mon, 26 Apr 2021 23:52:40 +0900
+Subject: [PATCH] ordered-set: introduce
+ ordered_set_clear/free_with_destructor()
+
+Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/d38a6476aad3f2cc80a2a4bc11f3898cc06a70f5]
+Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com>
+
+---
+ src/basic/ordered-set.h | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h
+index a377f20b1f..64df41766f 100644
+--- a/src/basic/ordered-set.h
++++ b/src/basic/ordered-set.h
+@@ -63,6 +63,17 @@ void ordered_set_print(FILE *f, const char *field, OrderedSet *s);
+ #define ORDERED_SET_FOREACH(e, s, i)                                    \
+         for ((i) = ITERATOR_FIRST; ordered_set_iterate((s), &(i), (void**)&(e)); )
++#define ordered_set_clear_with_destructor(s, f)                 \
++        ({                                                      \
++                OrderedSet *_s = (s);                           \
++                void *_item;                                    \
++                while ((_item = ordered_set_steal_first(_s)))   \
++                        f(_item);                               \
++                _s;                                             \
++        })
++#define ordered_set_free_with_destructor(s, f)                  \
++        ordered_set_free(ordered_set_clear_with_destructor(s, f))
++
+ DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free);
+ DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free_free);
diff --git a/meta/recipes-core/systemd/systemd/network-add-skeleton-of-request-queue.patch b/meta/recipes-core/systemd/systemd/network-add-skeleton-of-request-queue.patch
new file mode 100644 (file)
index 0000000..06c5238
--- /dev/null
@@ -0,0 +1,285 @@
+From 19d9a5adf0c1a6b5a243eea0390f6f6526d569de Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Fri, 7 May 2021 15:39:16 +0900
+Subject: [PATCH] network: add skeleton of request queue
+
+This will be used in later commits.
+
+Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/19d9a5adf0c1a6b5a243eea0390f6f6526d569de]
+Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com>
+
+---
+ src/network/meson.build        |   2 +
+ src/network/networkd-link.c    |  20 +++++-
+ src/network/networkd-manager.c |   7 ++
+ src/network/networkd-manager.h |   2 +
+ src/network/networkd-queue.c   | 121 +++++++++++++++++++++++++++++++++
+ src/network/networkd-queue.h   |  42 ++++++++++++
+ 6 files changed, 192 insertions(+), 2 deletions(-)
+ create mode 100644 src/network/networkd-queue.c
+ create mode 100644 src/network/networkd-queue.h
+
+diff --git a/src/network/meson.build b/src/network/meson.build
+index 4fca3106dc..a8b9232e64 100644
+--- a/src/network/meson.build
++++ b/src/network/meson.build
+@@ -105,6 +105,8 @@ sources = files('''
+         networkd-network.h
+         networkd-nexthop.c
+         networkd-nexthop.h
++        networkd-queue.c
++        networkd-queue.h
+         networkd-route.c
+         networkd-route.h
+         networkd-routing-policy-rule.c
+diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
+index 34359b2541..2f33305a27 100644
+--- a/src/network/networkd-link.c
++++ b/src/network/networkd-link.c
+@@ -30,6 +30,7 @@
+ #include "networkd-manager.h"
+ #include "networkd-ndisc.h"
+ #include "networkd-neighbor.h"
++#include "networkd-queue.h"
+ #include "networkd-radv.h"
+ #include "networkd-routing-policy-rule.h"
+ #include "networkd-wifi.h"
+
+@@ -2232,6 +2244,8 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for
+         if (r < 0)
+                 return r;
++        link_drop_requests(link);
++
+         r = link_drop_config(link);
+         if (r < 0)
+                 return r;
+@@ -2664,6 +2678,8 @@ static int link_carrier_lost(Link *link) {
+                 return r;
+         }
++        link_drop_requests(link);
++
+         r = link_drop_config(link);
+         if (r < 0)
+                 return r;
+diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
+index 562ce5ca54..fd576169a9 100644
+--- a/src/network/networkd-manager.c
++++ b/src/network/networkd-manager.c
+@@ -34,6 +34,7 @@
+ #include "networkd-manager-bus.h"
+ #include "networkd-manager.h"
+ #include "networkd-network-bus.h"
++#include "networkd-queue.h"
+ #include "networkd-speed-meter.h"
+ #include "ordered-set.h"
+ #include "path-util.h"
+@@ -406,6 +407,10 @@ int manager_new(Manager **ret) {
+         if (r < 0)
+                 return r;
++        r = sd_event_add_post(m->event, NULL, manager_process_requests, m);
++        if (r < 0)
++                return r;
++
+         r = manager_connect_rtnl(m);
+         if (r < 0)
+                 return r;
+@@ -446,6 +451,8 @@ Manager* manager_free(Manager *m) {
+         free(m->state_file);
++        m->request_queue = ordered_set_free_with_destructor(m->request_queue, request_free);
++
+         while ((a = hashmap_first_key(m->dhcp6_prefixes)))
+                 (void) dhcp6_prefix_remove(m, a);
+         m->dhcp6_prefixes = hashmap_free(m->dhcp6_prefixes);
+diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
+index 301b97c1a1..26e8802871 100644
+--- a/src/network/networkd-manager.h
++++ b/src/network/networkd-manager.h
+@@ -91,6 +91,8 @@ struct Manager {
+         usec_t speed_meter_usec_old;
+         bool dhcp4_prefix_root_cannot_set_table;
++
++        OrderedSet *request_queue;
+ };
+ int manager_new(Manager **ret);
+diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c
+new file mode 100644
+index 0000000000..24bb2c845d
+--- /dev/null
++++ b/src/network/networkd-queue.c
+@@ -0,0 +1,121 @@
++/* SPDX-License-Identifier: LGPL-2.1-or-later */
++
++#include "networkd-address.h"
++#include "networkd-manager.h"
++#include "networkd-neighbor.h"
++#include "networkd-nexthop.h"
++#include "networkd-route.h"
++#include "networkd-routing-policy-rule.h"
++#include "networkd-queue.h"
++
++static void request_free_object(RequestType type, void *object) {
++        switch(type) {
++        default:
++                assert_not_reached("invalid request type.");
++        }
++}
++
++Request *request_free(Request *req) {
++        if (!req)
++                return NULL;
++
++        if (req->on_free)
++                req->on_free(req);
++        if (req->consume_object)
++                request_free_object(req->type, req->object);
++        if (req->link && req->link->manager)
++                ordered_set_remove(req->link->manager->request_queue, req);
++        link_unref(req->link);
++
++        return mfree(req);
++}
++
++DEFINE_TRIVIAL_CLEANUP_FUNC(Request*, request_free);
++
++void request_drop(Request *req) {
++        if (req->message_counter)
++                (*req->message_counter)--;
++
++        request_free(req);
++}
++
++int link_queue_request(
++                Link *link,
++                RequestType type,
++                void *object,
++                bool consume_object,
++                unsigned *message_counter,
++                link_netlink_message_handler_t netlink_handler,
++                Request **ret) {
++
++        _cleanup_(request_freep) Request *req = NULL;
++        int r;
++
++        assert(link);
++        assert(link->manager);
++        assert(type >= 0 && type < _REQUEST_TYPE_MAX);
++        assert(object);
++        assert(netlink_handler);
++
++        req = new(Request, 1);
++        if (!req) {
++                if (consume_object)
++                        request_free_object(type, object);
++                return -ENOMEM;
++        }
++
++        *req = (Request) {
++                .link = link,
++                .type = type,
++                .object = object,
++                .consume_object = consume_object,
++                .message_counter = message_counter,
++                .netlink_handler = netlink_handler,
++        };
++
++        link_ref(link);
++
++        r = ordered_set_ensure_put(&link->manager->request_queue, NULL, req);
++        if (r < 0)
++                return r;
++
++        if (req->message_counter)
++                (*req->message_counter)++;
++
++        if (ret)
++                *ret = req;
++
++        TAKE_PTR(req);
++        return 0;
++}
++
++int manager_process_requests(sd_event_source *s, void *userdata) {
++        Manager *manager = userdata;
++        int r;
++
++        assert(manager);
++
++        for (;;) {
++                bool processed = false;
++                Request *req;
++                Iterator i;
++                ORDERED_SET_FOREACH(req, manager->request_queue, i) {
++                        switch(req->type) {
++                        default:
++                                return -EINVAL;
++                        }
++                        if (r < 0)
++                                link_enter_failed(req->link);
++                        if (r > 0) {
++                                ordered_set_remove(manager->request_queue, req);
++                                request_free(req);
++                                processed = true;
++                        }
++                }
++
++                if (!processed)
++                        break;
++        }
++
++        return 0;
++}
+diff --git a/src/network/networkd-queue.h b/src/network/networkd-queue.h
+new file mode 100644
+index 0000000000..4558ae548f
+--- /dev/null
++++ b/src/network/networkd-queue.h
+@@ -0,0 +1,42 @@
++/* SPDX-License-Identifier: LGPL-2.1-or-later */
++#pragma once
++
++#include "sd-event.h"
++
++#include "networkd-link.h"
++
++typedef struct Request Request;
++
++typedef int (*request_after_configure_handler_t)(Request*, void*);
++typedef void (*request_on_free_handler_t)(Request*);
++
++typedef enum RequestType {
++        _REQUEST_TYPE_MAX,
++        _REQUEST_TYPE_INVALID = -EINVAL,
++} RequestType;
++
++typedef struct Request {
++        Link *link;
++        RequestType type;
++        bool consume_object;
++        void *object;
++        void *userdata;
++        unsigned *message_counter;
++        link_netlink_message_handler_t netlink_handler;
++        request_after_configure_handler_t after_configure;
++        request_on_free_handler_t on_free;
++} Request;
++
++Request *request_free(Request *req);
++void request_drop(Request *req);
++
++int link_queue_request(
++                Link *link,
++                RequestType type,
++                void *object,
++                bool consume_object,
++                unsigned *message_counter,
++                link_netlink_message_handler_t netlink_handler,
++                Request **ret);
++
++int manager_process_requests(sd_event_source *s, void *userdata);
diff --git a/meta/recipes-core/systemd/systemd/network-also-drop-requests-when-link-enters-linger-state.patch b/meta/recipes-core/systemd/systemd/network-also-drop-requests-when-link-enters-linger-state.patch
new file mode 100644 (file)
index 0000000..4c402e7
--- /dev/null
@@ -0,0 +1,50 @@
+From 56001f023305ea99329e27141d6e6067596491a9 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Mon, 17 May 2021 15:32:57 +0900
+Subject: [PATCH] network: also drop requests when link enters linger state
+
+Otherwise, if link is removed, several references to the link in remain
+exist in requests.
+
+Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/56001f023305ea99329e27141d6e6067596491a9]
+Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com>
+
+---
+ src/network/networkd-link.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
+index 67d01ac44d..b56c232eca 100644
+--- a/src/network/networkd-link.c
++++ b/src/network/networkd-link.c
+@@ -1771,6 +1771,18 @@ static void link_drop_from_master(Link *link, NetDev *netdev) {
+         link_unref(set_remove(master->slaves, link));
+ }
++static void link_drop_requests(Link *link) {
++        Request *req;
++        Iterator i;
++
++        assert(link);
++        assert(link->manager);
++
++        ORDERED_SET_FOREACH(req, link->manager->request_queue, i)
++                if (req->link == link)
++                        request_drop(req);
++}
++
+ void link_drop(Link *link) {
+         if (!link)
+                 return;
+@@ -1782,6 +1793,8 @@ void link_drop(Link *link) {
+         /* Drop all references from other links and manager. Note that async netlink calls may have
+          * references to the link, and they will be dropped when we receive replies. */
++        link_drop_requests(link);
++
+         link_free_carrier_maps(link);
+         if (link->network) {
+-- 
+2.17.1
+
diff --git a/meta/recipes-core/systemd/systemd/network-fix-Link-reference-counter-issue.patch b/meta/recipes-core/systemd/systemd/network-fix-Link-reference-counter-issue.patch
new file mode 100644 (file)
index 0000000..a186bb4
--- /dev/null
@@ -0,0 +1,278 @@
+From cc2d7efc5ca09a7de4bec55e80476986839a655c Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Fri, 14 May 2021 15:58:15 +0900
+Subject: [PATCH] network: fix Link reference counter issue
+
+Previously, when link_new() fails, `link_unref()` was called, so,
+`Manager::links` may become dirty.
+This introduces `link_drop_or_unref()` and it will be called on
+failure.
+
+Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/cc2d7efc5ca09a7de4bec55e80476986839a655c]
+Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com>
+
+---
+ src/network/networkd-link.c | 240 ++++++++++++++++++------------------
+ 1 file changed, 122 insertions(+), 118 deletions(-)
+
+diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
+index b56c232eca..d493afda4c 100644
+--- a/src/network/networkd-link.c
++++ b/src/network/networkd-link.c
+@@ -540,109 +540,6 @@ static int link_update_flags(Link *link,
+         return 0;
+ }
+-static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
+-        _cleanup_(link_unrefp) Link *link = NULL;
+-        uint16_t type;
+-        const char *ifname, *kind = NULL;
+-        int r, ifindex;
+-        unsigned short iftype;
+-
+-        assert(manager);
+-        assert(message);
+-        assert(ret);
+-
+-        /* check for link kind */
+-        r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
+-        if (r == 0) {
+-                (void) sd_netlink_message_read_string(message, IFLA_INFO_KIND, &kind);
+-                r = sd_netlink_message_exit_container(message);
+-                if (r < 0)
+-                        return r;
+-        }
+-
+-        r = sd_netlink_message_get_type(message, &type);
+-        if (r < 0)
+-                return r;
+-        else if (type != RTM_NEWLINK)
+-                return -EINVAL;
+-
+-        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
+-        if (r < 0)
+-                return r;
+-        else if (ifindex <= 0)
+-                return -EINVAL;
+-
+-        r = sd_rtnl_message_link_get_type(message, &iftype);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
+-        if (r < 0)
+-                return r;
+-
+-        link = new(Link, 1);
+-        if (!link)
+-                return -ENOMEM;
+-
+-        *link = (Link) {
+-                .n_ref = 1,
+-                .manager = manager,
+-                .state = LINK_STATE_PENDING,
+-                .ifindex = ifindex,
+-                .iftype = iftype,
+-
+-                .n_dns = (unsigned) -1,
+-                .dns_default_route = -1,
+-                .llmnr = _RESOLVE_SUPPORT_INVALID,
+-                .mdns = _RESOLVE_SUPPORT_INVALID,
+-                .dnssec_mode = _DNSSEC_MODE_INVALID,
+-                .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
+-        };
+-
+-        link->ifname = strdup(ifname);
+-        if (!link->ifname)
+-                return -ENOMEM;
+-
+-        if (kind) {
+-                link->kind = strdup(kind);
+-                if (!link->kind)
+-                        return -ENOMEM;
+-        }
+-
+-        r = sd_netlink_message_read_u32(message, IFLA_MASTER, (uint32_t *)&link->master_ifindex);
+-        if (r < 0)
+-                log_link_debug_errno(link, r, "New device has no master, continuing without");
+-
+-        r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
+-        if (r < 0)
+-                log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
+-
+-        if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0)
+-                return -ENOMEM;
+-
+-        if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0)
+-                return -ENOMEM;
+-
+-        if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0)
+-                return -ENOMEM;
+-
+-        r = hashmap_ensure_allocated(&manager->links, NULL);
+-        if (r < 0)
+-                return r;
+-
+-        r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link);
+-        if (r < 0)
+-                return r;
+-
+-        r = link_update_flags(link, message, false);
+-        if (r < 0)
+-                return r;
+-
+-        *ret = TAKE_PTR(link);
+-
+-        return 0;
+-}
+-
+ void link_ntp_settings_clear(Link *link) {
+         link->ntp = strv_free(link->ntp);
+ }
+@@ -2030,9 +1927,9 @@ static void link_drop_requests(Link *lin
+                         request_drop(req);
+ }
+-void link_drop(Link *link) {
++Link *link_drop(Link *link) {
+         if (!link)
+-                return;
++                return NULL;
+         assert(link->manager);
+@@ -2057,7 +1954,7 @@ void link_drop(Link *link) {
+         /* The following must be called at last. */
+         assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link);
+-        link_unref(link);
++        return link_unref(link);
+ }
+ static int link_joined(Link *link) {
+@@ -3295,6 +3192,112 @@ ipv4ll_address_fail:
+         return 0;
+ }
++
++static Link *link_drop_or_unref(Link *link) {
++        if (!link)
++                return NULL;
++        if (!link->manager)
++                return link_unref(link);
++        return link_drop(link);
++}
++
++DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_drop_or_unref);
++
++static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
++        _cleanup_(link_drop_or_unrefp) Link *link = NULL;
++        uint16_t type;
++        _cleanup_free_ char *ifname = NULL, *kind = NULL;
++        int r, ifindex;
++        unsigned short iftype;
++
++        assert(manager);
++        assert(message);
++        assert(ret);
++
++        r = sd_netlink_message_get_type(message, &type);
++        if (r < 0)
++                return r;
++        else if (type != RTM_NEWLINK)
++                return -EINVAL;
++
++        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
++        if (r < 0)
++                return r;
++        else if (ifindex <= 0)
++                return -EINVAL;
++
++        r = sd_rtnl_message_link_get_type(message, &iftype);
++        if (r < 0)
++                return r;
++
++        r = sd_netlink_message_read_string_strdup(message, IFLA_IFNAME, &ifname);
++        if (r < 0)
++                return r;
++
++        /* check for link kind */
++        r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
++        if (r >= 0) {
++                (void) sd_netlink_message_read_string_strdup(message, IFLA_INFO_KIND, &kind);
++                r = sd_netlink_message_exit_container(message);
++                if (r < 0)
++                        return r;
++        }
++
++        link = new(Link, 1);
++        if (!link)
++                return -ENOMEM;
++
++        *link = (Link) {
++                .n_ref = 1,
++                .state = LINK_STATE_PENDING,
++                .ifindex = ifindex,
++                .iftype = iftype,
++                .ifname = TAKE_PTR(ifname),
++                .kind = TAKE_PTR(kind),
++
++                .n_dns = (unsigned) -1,
++                .dns_default_route = -1,
++                .llmnr = _RESOLVE_SUPPORT_INVALID,
++                .mdns = _RESOLVE_SUPPORT_INVALID,
++                .dnssec_mode = _DNSSEC_MODE_INVALID,
++                .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
++        };
++
++        r = hashmap_ensure_allocated(&manager->links, NULL);
++        if (r < 0)
++                return r;
++
++        r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link);
++        if (r < 0)
++                return r;
++
++        link->manager = manager;
++
++        r = sd_netlink_message_read_u32(message, IFLA_MASTER, (uint32_t*) &link->master_ifindex);
++        if (r < 0)
++                log_link_debug_errno(link, r, "New device has no master, continuing without");
++
++        r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
++        if (r < 0)
++                log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
++
++        if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0)
++                return -ENOMEM;
++
++        if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0)
++                return -ENOMEM;
++
++        if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0)
++                return -ENOMEM;
++
++        r = link_update_flags(link, message, false);
++        if (r < 0)
++                return r;
++
++        *ret = TAKE_PTR(link);
++
++        return 0;
++}
+ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
+         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
+
+--- a/src/network/networkd-link.h      2021-09-02 18:04:16.900542857 +0530
++++ b/src/network/networkd-link.h      2021-09-02 18:18:56.776571563 +0530
+@@ -175,7 +175,7 @@ DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_d
+ int link_get(Manager *m, int ifindex, Link **ret);
+ int link_add(Manager *manager, sd_netlink_message *message, Link **ret);
+-void link_drop(Link *link);
++Link *link_drop(Link *link);
+ int link_down(Link *link, link_netlink_message_handler_t callback);
+
diff --git a/meta/recipes-core/systemd/systemd/network-merge-link_drop-and-link_detach_from_manager.patch b/meta/recipes-core/systemd/systemd/network-merge-link_drop-and-link_detach_from_manager.patch
new file mode 100644 (file)
index 0000000..65bdc61
--- /dev/null
@@ -0,0 +1,67 @@
+From 63130eb36dc51e4fd50716c585f98ebe456ca7cf Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Mon, 17 May 2021 15:40:15 +0900
+Subject: [PATCH] network: merge link_drop() and link_detach_from_manager()
+
+link_detach_from_manager() is only called by link_drop(). It is not
+necessary to split such tiny function.
+
+Upstream-Status: Backport [https://github.com/systemd/systemd-stable/commit/63130eb36dc51e4fd50716c585f98ebe456ca7cf]
+Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com>
+
+---
+ src/network/networkd-link.c | 27 ++++++++++++---------------
+ 1 file changed, 12 insertions(+), 15 deletions(-)
+
+diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
+index 9d30e16b0a..67d01ac44d 100644
+--- a/src/network/networkd-link.c
++++ b/src/network/networkd-link.c
+@@ -2019,24 +2019,17 @@ static void link_drop_from_master(Link *link, NetDev *netdev) {
+         link_unref(set_remove(master->slaves, link));
+ }
+-static void link_detach_from_manager(Link *link) {
+-        if (!link || !link->manager)
+-                return;
+-
+-        link_unref(set_remove(link->manager->links_requesting_uuid, link));
+-        link_clean(link);
+-
+-        /* The following must be called at last. */
+-        assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link);
+-        link_unref(link);
+-}
+-
+ void link_drop(Link *link) {
+-        if (!link || link->state == LINK_STATE_LINGER)
++        if (!link)
+                 return;
++        assert(link->manager);
++
+         link_set_state(link, LINK_STATE_LINGER);
++        /* Drop all references from other links and manager. Note that async netlink calls may have
++         * references to the link, and they will be dropped when we receive replies. */
++
+         link_free_carrier_maps(link);
+         if (link->network) {
+@@ -2044,10 +2037,14 @@ void link_drop(Link *link) {
+                 link_drop_from_master(link, link->network->bond);
+         }
+-        log_link_debug(link, "Link removed");
++        link_unref(set_remove(link->manager->links_requesting_uuid, link));
+         (void) unlink(link->state_file);
+-        link_detach_from_manager(link);
++        link_clean(link);
++
++        /* The following must be called at last. */
++        assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link);
++        link_unref(link);
+ }
+ static int link_joined(Link *link) {
index 7a7eddcd45798a0bb76641afb4e4815cc21d2773..bf33b8d6a1f021096f1ab0d27df470979a53a23d 100644 (file)
@@ -22,6 +22,12 @@ SRC_URI += "file://touchscreen.rules \
            file://0003-implment-systemd-sysv-install-for-OE.patch \
            file://CVE-2021-33910.patch \
            file://CVE-2020-13529.patch \
+           file://basic-pass-allocation-info-for-ordered-set-new-and-introd.patch \
+           file://introduce-ordered_set_clear-free-with-destructor.patch \
+           file://network-add-skeleton-of-request-queue.patch \
+           file://network-merge-link_drop-and-link_detach_from_manager.patch \
+           file://network-also-drop-requests-when-link-enters-linger-state.patch \
+           file://network-fix-Link-reference-counter-issue.patch \
            "
 
 # patches needed by musl