summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-10-14 12:15:09 +0200
committerLennart Poettering <lennart@poettering.net>2015-10-14 12:15:09 +0200
commit9ea79b459edef51e3ccc1ddde07c7b1399bed601 (patch)
treea688c4d5e81f1a7da2f384af3b9681400f2eb6a1
parentade37eb98c2fedefd0c1645d0cd083c171dba194 (diff)
parentce6c77ebf12f80c807ad7589a1fb565fabc6a543 (diff)
Merge pull request #1530 from teg/network-fixes-2
networkd/libsystemd-network: collection of trivial patches v2
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c9
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c11
-rw-r--r--src/libsystemd-network/sd-icmp6-nd.c6
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c39
-rw-r--r--src/libsystemd-network/test-ipv4ll.c11
-rw-r--r--src/libsystemd/sd-netlink/rtnl-message.c60
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c13
-rw-r--r--src/network/networkd-address-pool.c4
-rw-r--r--src/network/networkd-address.c262
-rw-r--r--src/network/networkd-address.h12
-rw-r--r--src/network/networkd-dhcp4.c32
-rw-r--r--src/network/networkd-dhcp6.c4
-rw-r--r--src/network/networkd-ipv4ll.c14
-rw-r--r--src/network/networkd-link.c255
-rw-r--r--src/network/networkd-link.h7
-rw-r--r--src/network/networkd-manager.c182
-rw-r--r--src/network/networkd-network.c8
-rw-r--r--src/network/networkd-route.c47
-rw-r--r--src/network/networkd-route.h4
-rw-r--r--src/network/networkd.h2
-rw-r--r--src/network/test-network.c13
-rw-r--r--src/systemd/sd-ipv4ll.h1
-rw-r--r--src/systemd/sd-netlink.h4
23 files changed, 617 insertions, 383 deletions
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 141b836a0d..28e012afca 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -1265,8 +1265,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
log_dhcp_client(client, "lease expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- lifetime_timeout - time_now, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
/* don't arm earlier timeouts if this has already expired */
if (lifetime_timeout <= time_now)
@@ -1292,8 +1291,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
log_dhcp_client(client, "T2 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- t2_timeout - time_now, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
/* don't arm earlier timeout if this has already expired */
if (t2_timeout <= time_now)
@@ -1318,8 +1316,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
log_dhcp_client(client, "T1 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- t1_timeout - time_now, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
return 0;
}
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index acb31a16c2..9cd4bd3032 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -595,8 +595,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
}
log_dhcp6_client(client, "Next retransmission in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- client->retransmit_time, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
r = sd_event_add_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
@@ -1048,9 +1047,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
log_dhcp6_client(client, "T1 expires in %s",
- format_timespan(time_string,
- FORMAT_TIMESPAN_MAX,
- timeout, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t1,
@@ -1072,9 +1069,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
log_dhcp6_client(client, "T2 expires in %s",
- format_timespan(time_string,
- FORMAT_TIMESPAN_MAX,
- timeout, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t2,
diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c
index bedcac8d9e..f014cac628 100644
--- a/src/libsystemd-network/sd-icmp6-nd.c
+++ b/src/libsystemd-network/sd-icmp6-nd.c
@@ -444,8 +444,7 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
log_icmp6_nd(nd, "New prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
prefix->len, lifetime,
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- lifetime * USEC_PER_SEC, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC));
LIST_PREPEND(prefixes, nd->prefixes, prefix);
@@ -466,8 +465,7 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
log_icmp6_nd(nd, "Update prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
prefix->len, lifetime,
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- lifetime * USEC_PER_SEC, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC));
}
r = icmp6_ra_prefix_set_timeout(nd, prefix, lifetime * USEC_PER_SEC);
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index dd427ddd78..57bd337a9a 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -25,6 +25,7 @@
#include <arpa/inet.h>
#include "event-util.h"
+#include "in-addr-util.h"
#include "list.h"
#include "random-util.h"
#include "refcnt.h"
@@ -232,6 +233,39 @@ bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
return sd_ipv4acd_is_running(ll->acd);
}
+static bool ipv4ll_address_is_valid(const struct in_addr *address) {
+ uint32_t addr;
+
+ assert(address);
+
+ if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address))
+ return false;
+
+ addr = be32toh(address->s_addr);
+
+ if ((addr & 0x0000FF00) == 0x0000 ||
+ (addr & 0x0000FF00) == 0xFF00)
+ return false;
+
+ return true;
+}
+
+int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
+ int r;
+
+ assert_return(ll, -EINVAL);
+ assert_return(address, -EINVAL);
+ assert_return(ipv4ll_address_is_valid(address), -EINVAL);
+
+ r = sd_ipv4acd_set_address(ll->acd, address);
+ if (r < 0)
+ return r;
+
+ ll->address = address->s_addr;
+
+ return 0;
+}
+
static int ipv4ll_pick_address(sd_ipv4ll *ll) {
struct in_addr in_addr;
be32_t addr;
@@ -247,18 +281,15 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
return r;
addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
} while (addr == ll->address ||
- (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
(ntohl(addr) & 0x0000FF00) == 0x0000 ||
(ntohl(addr) & 0x0000FF00) == 0xFF00);
in_addr.s_addr = addr;
- r = sd_ipv4acd_set_address(ll->acd, &in_addr);
+ r = sd_ipv4ll_set_address(ll, &in_addr);
if (r < 0)
return r;
- ll->address = addr;
-
return 0;
}
diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c
index e72204d992..b67a9f17d7 100644
--- a/src/libsystemd-network/test-ipv4ll.c
+++ b/src/libsystemd-network/test-ipv4ll.c
@@ -100,6 +100,7 @@ int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_ad
}
static void test_public_api_setters(sd_event *e) {
+ struct in_addr address = {};
unsigned seed = 0;
sd_ipv4ll *ll;
struct ether_addr mac_addr = {
@@ -118,6 +119,16 @@ static void test_public_api_setters(sd_event *e) {
assert_se(sd_ipv4ll_set_callback(NULL, NULL, NULL) == -EINVAL);
assert_se(sd_ipv4ll_set_callback(ll, NULL, NULL) == 0);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+ address.s_addr |= htobe32(169U << 24 | 254U << 16);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+ address.s_addr |= htobe32(0x00FF);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+ address.s_addr |= htobe32(0xF000);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == 0);
+ address.s_addr |= htobe32(0x0F00);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+
assert_se(sd_ipv4ll_set_address_seed(NULL, seed) == -EINVAL);
assert_se(sd_ipv4ll_set_address_seed(ll, seed) == 0);
diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c
index 2f31f4ee69..03049bd31f 100644
--- a/src/libsystemd/sd-netlink/rtnl-message.c
+++ b/src/libsystemd/sd-netlink/rtnl-message.c
@@ -99,6 +99,66 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
return 0;
}
+int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(protocol, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *protocol = rtm->rtm_protocol;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(scope, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *scope = rtm->rtm_scope;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(tos, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *tos = rtm->rtm_tos;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(table, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *table = rtm->rtm_table;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
struct rtmsg *rtm;
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index d248869c8d..f4a0a358a9 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -856,8 +856,6 @@ int sd_netlink_add_match(sd_netlink *rtnl,
switch (type) {
case RTM_NEWLINK:
- case RTM_SETLINK:
- case RTM_GETLINK:
case RTM_DELLINK:
r = socket_join_broadcast_group(rtnl, RTNLGRP_LINK);
if (r < 0)
@@ -865,7 +863,6 @@ int sd_netlink_add_match(sd_netlink *rtnl,
break;
case RTM_NEWADDR:
- case RTM_GETADDR:
case RTM_DELADDR:
r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
if (r < 0)
@@ -876,6 +873,16 @@ int sd_netlink_add_match(sd_netlink *rtnl,
return r;
break;
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_ROUTE);
+ if (r < 0)
+ return r;
+
+ r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_ROUTE);
+ if (r < 0)
+ return r;
+ break;
default:
return -EOPNOTSUPP;
}
diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c
index d609daafde..b3450c1456 100644
--- a/src/network/networkd-address-pool.c
+++ b/src/network/networkd-address-pool.c
@@ -21,6 +21,7 @@
#include "networkd.h"
#include "networkd-address-pool.h"
+#include "set.h"
int address_pool_new(
Manager *m,
@@ -96,9 +97,10 @@ static bool address_pool_prefix_is_taken(
HASHMAP_FOREACH(l, p->manager->links, i) {
Address *a;
+ Iterator j;
/* Don't clash with assigned addresses */
- LIST_FOREACH(addresses, a, l->addresses) {
+ SET_FOREACH(a, l->addresses, j) {
if (a->family != p->family)
continue;
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 388beb5d4c..316ae2e4cb 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -21,26 +21,37 @@
#include <net/if.h>
-#include "utf8.h"
-#include "util.h"
#include "conf-parser.h"
#include "firewall-util.h"
#include "netlink-util.h"
+#include "set.h"
+#include "utf8.h"
+#include "util.h"
#include "networkd.h"
#include "networkd-address.h"
-static void address_init(Address *address) {
- assert(address);
+int address_new(Address **ret) {
+ _cleanup_address_free_ Address *address = NULL;
+
+ address = new0(Address, 1);
+ if (!address)
+ return -ENOMEM;
address->family = AF_UNSPEC;
address->scope = RT_SCOPE_UNIVERSE;
address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
+
+ *ret = address;
+ address = NULL;
+
+ return 0;
}
int address_new_static(Network *network, unsigned section, Address **ret) {
_cleanup_address_free_ Address *address = NULL;
+ int r;
if (section) {
address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
@@ -52,11 +63,9 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
}
}
- address = new0(Address, 1);
- if (!address)
- return -ENOMEM;
-
- address_init(address);
+ r = address_new(&address);
+ if (r < 0)
+ return r;
address->network = network;
@@ -74,21 +83,6 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
return 0;
}
-int address_new_dynamic(Address **ret) {
- _cleanup_address_free_ Address *address = NULL;
-
- address = new0(Address, 1);
- if (!address)
- return -ENOMEM;
-
- address_init(address);
-
- *ret = address;
- address = NULL;
-
- return 0;
-}
-
void address_free(Address *address) {
if (!address)
return;
@@ -101,10 +95,110 @@ void address_free(Address *address) {
UINT_TO_PTR(address->section));
}
+ if (address->link)
+ set_remove(address->link->addresses, address);
+
free(address);
}
-int address_establish(Address *address, Link *link) {
+static void address_hash_func(const void *b, struct siphash *state) {
+ const Address *a = b;
+
+ assert(a);
+
+ siphash24_compress(&a->family, sizeof(a->family), state);
+
+ switch (a->family) {
+ case AF_INET:
+ siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
+
+ /* peer prefix */
+ if (a->prefixlen != 0) {
+ uint32_t prefix;
+
+ if (a->in_addr_peer.in.s_addr != 0)
+ prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
+ else
+ prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
+
+ siphash24_compress(&prefix, sizeof(prefix), state);
+ }
+
+ /* fallthrough */
+ case AF_INET6:
+ /* local address */
+ siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
+
+ break;
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ break;
+ }
+}
+
+static int address_compare_func(const void *c1, const void *c2) {
+ const Address *a1 = c1, *a2 = c2;
+
+ if (a1->family < a2->family)
+ return -1;
+ if (a1->family > a2->family)
+ return 1;
+
+ switch (a1->family) {
+ /* use the same notion of equality as the kernel does */
+ case AF_INET:
+ if (a1->prefixlen < a2->prefixlen)
+ return -1;
+ if (a1->prefixlen > a2->prefixlen)
+ return 1;
+
+ /* compare the peer prefixes */
+ if (a1->prefixlen != 0) {
+ /* make sure we don't try to shift by 32.
+ * See ISO/IEC 9899:TC3 § 6.5.7.3. */
+ uint32_t b1, b2;
+
+ if (a1->in_addr_peer.in.s_addr != 0)
+ b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
+ else
+ b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
+
+ if (a2->in_addr_peer.in.s_addr != 0)
+ b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
+ else
+ b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
+
+ if (b1 < b2)
+ return -1;
+ if (b1 > b2)
+ return 1;
+ }
+
+ /* fall-through */
+ case AF_INET6:
+ return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ return 0;
+ }
+}
+
+static const struct hash_ops address_hash_ops = {
+ .hash = address_hash_func,
+ .compare = address_compare_func
+};
+
+bool address_equal(Address *a1, Address *a2) {
+ if (a1 == a2)
+ return true;
+
+ if (!a1 || !a2)
+ return false;
+
+ return address_compare_func(a1, a2) == 0;
+}
+
+static int address_establish(Address *address, Link *link) {
bool masq;
int r;
@@ -131,7 +225,43 @@ int address_establish(Address *address, Link *link) {
return 0;
}
-int address_release(Address *address, Link *link) {
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+ _cleanup_address_free_ Address *address = NULL;
+ int r;
+
+ assert(link);
+ assert(in_addr);
+ assert(ret);
+
+ r = address_new(&address);
+ if (r < 0)
+ return r;
+
+ address->family = family;
+ address->in_addr = *in_addr;
+ address->prefixlen = prefixlen;
+
+ r = set_ensure_allocated(&link->addresses, &address_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(link->addresses, address);
+ if (r < 0)
+ return r;
+
+ address->link = link;
+
+ r = address_establish(address, link);
+ if (r < 0)
+ return r;
+
+ *ret = address;
+ address = NULL;
+
+ return 0;
+}
+
+static int address_release(Address *address, Link *link) {
int r;
assert(address);
@@ -152,7 +282,36 @@ int address_release(Address *address, Link *link) {
return 0;
}
-int address_drop(Address *address, Link *link,
+int address_drop(Address *address) {
+ assert(address);
+
+ address_release(address, address->link);
+ address_free(address);
+
+ return 0;
+}
+
+int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+ Address address = {}, *existing;
+
+ assert(link);
+ assert(in_addr);
+ assert(ret);
+
+ address.family = family;
+ address.in_addr = *in_addr;
+ address.prefixlen = prefixlen;
+
+ existing = set_get(link->addresses, &address);
+ if (!existing)
+ return -ENOENT;
+
+ *ret = existing;
+
+ return 0;
+}
+
+int address_remove(Address *address, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
int r;
@@ -292,7 +451,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
} else if (original->family == AF_INET6)
in_addr.in6.s6_addr[15] |= 1;
- r = address_new_dynamic(&na);
+ r = address_new(&na);
if (r < 0)
return r;
@@ -580,49 +739,8 @@ int config_parse_label(const char *unit,
return 0;
}
-bool address_equal(Address *a1, Address *a2) {
- /* same object */
- if (a1 == a2)
- return true;
-
- /* one, but not both, is NULL */
- if (!a1 || !a2)
- return false;
-
- if (a1->family != a2->family)
- return false;
-
- switch (a1->family) {
- /* use the same notion of equality as the kernel does */
- case AF_UNSPEC:
- return true;
-
- case AF_INET:
- if (a1->prefixlen != a2->prefixlen)
- return false;
- else if (a1->prefixlen == 0)
- /* make sure we don't try to shift by 32.
- * See ISO/IEC 9899:TC3 § 6.5.7.3. */
- return true;
- else {
- uint32_t b1, b2;
-
- b1 = be32toh(a1->in_addr.in.s_addr);
- b2 = be32toh(a2->in_addr.in.s_addr);
-
- return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
- }
-
- case AF_INET6: {
- uint64_t *b1, *b2;
-
- b1 = (uint64_t*)&a1->in_addr.in6;
- b2 = (uint64_t*)&a2->in_addr.in6;
+bool address_is_ready(const Address *a) {
+ assert(a);
- return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
- }
-
- default:
- assert_not_reached("Invalid address family");
- }
+ return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
}
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 39789a2382..425344fe48 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -38,6 +38,8 @@ struct Address {
Network *network;
unsigned section;
+ Link *link;
+
int family;
unsigned char prefixlen;
unsigned char scope;
@@ -56,14 +58,16 @@ struct Address {
};
int address_new_static(Network *network, unsigned section, Address **ret);
-int address_new_dynamic(Address **ret);
+int address_new(Address **ret);
void address_free(Address *address);
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_drop(Address *address);
int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback);
int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_establish(Address *address, Link *link);
-int address_release(Address *address, Link *link);
+int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback);
bool address_equal(Address *a1, Address *a2);
+bool address_is_ready(const Address *a);
DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
#define _cleanup_address_free_ _cleanup_(address_freep)
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 04f04df117..5d9bfcea7c 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -72,11 +72,11 @@ static int link_set_dhcp_routes(Link *link) {
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
- r = route_new_dynamic(&route, RTPROT_DHCP);
+ r = route_new(&route, RTPROT_DHCP);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
- r = route_new_dynamic(&route_gw, RTPROT_DHCP);
+ r = route_new(&route_gw, RTPROT_DHCP);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
@@ -120,7 +120,7 @@ static int link_set_dhcp_routes(Link *link) {
for (i = 0; i < n; i++) {
_cleanup_route_free_ Route *route = NULL;
- r = route_new_dynamic(&route, RTPROT_DHCP);
+ r = route_new(&route, RTPROT_DHCP);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
@@ -162,45 +162,45 @@ static int dhcp_lease_lost(Link *link) {
for (i = 0; i < n; i++) {
_cleanup_route_free_ Route *route = NULL;
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
+ r = route_new(&route, RTPROT_UNSPEC);
if (r >= 0) {
route->family = AF_INET;
route->in_addr.in = routes[i].gw_addr;
route->dst_addr.in = routes[i].dst_addr;
route->dst_prefixlen = routes[i].dst_prefixlen;
- route_drop(route, link,
- &link_route_drop_handler);
+ route_remove(route, link,
+ &link_route_remove_handler);
}
}
}
}
- r = address_new_dynamic(&address);
+ r = address_new(&address);
if (r >= 0) {
r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
if (r >= 0) {
_cleanup_route_free_ Route *route_gw = NULL;
_cleanup_route_free_ Route *route = NULL;
- r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
+ r = route_new(&route_gw, RTPROT_UNSPEC);
if (r >= 0) {
route_gw->family = AF_INET;
route_gw->dst_addr.in = gateway;
route_gw->dst_prefixlen = 32;
route_gw->scope = RT_SCOPE_LINK;
- route_drop(route_gw, link,
- &link_route_drop_handler);
+ route_remove(route_gw, link,
+ &link_route_remove_handler);
}
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
+ r = route_new(&route, RTPROT_UNSPEC);
if (r >= 0) {
route->family = AF_INET;
route->in_addr.in = gateway;
- route_drop(route, link,
- &link_route_drop_handler);
+ route_remove(route, link,
+ &link_route_remove_handler);
}
}
@@ -214,7 +214,7 @@ static int dhcp_lease_lost(Link *link) {
address->in_addr.in = addr;
address->prefixlen = prefixlen;
- address_drop(address, link, &link_address_drop_handler);
+ address_remove(address, link, &link_address_remove_handler);
}
}
@@ -267,7 +267,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
link_enter_failed(link);
} else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
link_set_dhcp_routes(link);
@@ -288,7 +288,7 @@ static int dhcp4_update_address(Link *link,
prefixlen = in_addr_netmask_to_prefixlen(netmask);
- r = address_new_dynamic(&addr);
+ r = address_new(&addr);
if (r < 0)
return r;
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 3cb7b8d9ca..2f9ecf7a89 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -58,7 +58,7 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
link_enter_failed(link);
} else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
return 1;
}
@@ -69,7 +69,7 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
int r;
_cleanup_address_free_ Address *addr = NULL;
- r = address_new_dynamic(&addr);
+ r = address_new(&addr);
if (r < 0)
return r;
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 1902b3d23a..01ee9f9f4a 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -42,7 +42,7 @@ static int ipv4ll_address_lost(Link *link) {
log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
- r = address_new_dynamic(&address);
+ r = address_new(&address);
if (r < 0) {
log_link_error_errno(link, r, "Could not allocate address: %m");
return r;
@@ -53,9 +53,9 @@ static int ipv4ll_address_lost(Link *link) {
address->prefixlen = 16;
address->scope = RT_SCOPE_LINK;
- address_drop(address, link, &link_address_drop_handler);
+ address_remove(address, link, &link_address_remove_handler);
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
+ r = route_new(&route, RTPROT_UNSPEC);
if (r < 0) {
log_link_error_errno(link, r, "Could not allocate route: %m");
return r;
@@ -65,7 +65,7 @@ static int ipv4ll_address_lost(Link *link) {
route->scope = RT_SCOPE_LINK;
route->metrics = IPV4LL_ROUTE_METRIC;
- route_drop(route, link, &link_route_drop_handler);
+ route_remove(route, link, &link_route_remove_handler);
link_client_handler(link);
@@ -105,7 +105,7 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void
log_link_error_errno(link, r, "could not set ipv4ll address: %m");
link_enter_failed(link);
} else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
link->ipv4ll_address = true;
@@ -133,7 +133,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
ADDRESS_FMT_VAL(address));
- r = address_new_dynamic(&ll_addr);
+ r = address_new(&ll_addr);
if (r < 0)
return r;
@@ -149,7 +149,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
link->ipv4ll_address = false;
- r = route_new_dynamic(&route, RTPROT_STATIC);
+ r = route_new(&route, RTPROT_STATIC);
if (r < 0)
return r;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index aa09065cf5..f6cc1f8ee2 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -23,15 +23,16 @@
#include <linux/if.h>
#include <unistd.h>
-#include "util.h"
-#include "virt.h"
-#include "fileio.h"
-#include "socket-util.h"
#include "bus-util.h"
-#include "udev-util.h"
-#include "netlink-util.h"
#include "dhcp-lease-internal.h"
+#include "fileio.h"
+#include "netlink-util.h"
#include "network-internal.h"
+#include "set.h"
+#include "socket-util.h"
+#include "udev-util.h"
+#include "util.h"
+#include "virt.h"
#include "networkd-link.h"
#include "networkd-netdev.h"
@@ -291,10 +292,10 @@ static void link_free(Link *link) {
if (!link)
return;
- while ((address = link->addresses)) {
- LIST_REMOVE(addresses, link->addresses, address);
- address_free(address);
- }
+ while (!set_isempty(link->addresses))
+ address_free(set_first(link->addresses));
+
+ set_free(link->addresses);
while ((address = link->pool_addresses)) {
LIST_REMOVE(addresses, link->pool_addresses, address);
@@ -336,15 +337,28 @@ static void link_free(Link *link) {
}
Link *link_unref(Link *link) {
- if (link && (-- link->n_ref <= 0))
- link_free(link);
+ if (!link)
+ return NULL;
+
+ assert(link->n_ref > 0);
+
+ link->n_ref --;
+
+ if (link->n_ref > 0)
+ return NULL;
+
+ link_free(link);
return NULL;
}
Link *link_ref(Link *link) {
- if (link)
- assert_se(++ link->n_ref >= 2);
+ if (!link)
+ return NULL;
+
+ assert(link->n_ref > 0);
+
+ link->n_ref ++;
return link;
}
@@ -531,7 +545,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_link_warning_errno(link, r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not set route: %m");
if (link->link_messages == 0) {
log_link_debug(link, "Routes set");
@@ -572,7 +586,7 @@ static int link_enter_set_routes(Link *link) {
return 0;
}
-int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
@@ -585,7 +599,7 @@ int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ESRCH)
- log_link_warning_errno(link, r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not drop route: %m");
return 1;
}
@@ -609,9 +623,9 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_link_warning_errno(link, r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "could not set address: %m");
else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
if (link->link_messages == 0) {
log_link_debug(link, "Addresses set");
@@ -854,7 +868,7 @@ static int link_enter_set_addresses(Link *link) {
return 0;
}
-int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
@@ -867,7 +881,7 @@ int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *use
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EADDRNOTAVAIL)
- log_link_warning_errno(link, r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not drop address: %m");
return 1;
}
@@ -1019,7 +1033,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
r = sd_netlink_message_get_errno(m);
if (r < 0)
- log_link_warning_errno(link, r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not set MTU: %m");
return 1;
}
@@ -1207,7 +1221,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
if (r < 0)
/* we warn but don't fail the link, as it may be
brought up later */
- log_link_warning_errno(link, r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not bring up interface: %m");
return 1;
}
@@ -1294,7 +1308,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *user
r = sd_netlink_message_get_errno(m);
if (r < 0)
- log_link_warning_errno(link, r, "%-*s: could not bring down interface: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not bring down interface: %m");
return 1;
}
@@ -1616,7 +1630,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *us
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_link_error_errno(link, r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname);
+ log_link_error_errno(link, r, "Could not join netdev: %m");
link_enter_failed(link);
return 1;
} else
@@ -2011,179 +2025,6 @@ int link_initialized(Link *link, struct udev_device *device) {
return 0;
}
-static Address* link_get_equal_address(Link *link, Address *needle) {
- Address *i;
-
- assert(link);
- assert(needle);
-
- LIST_FOREACH(addresses, i, link->addresses)
- if (address_equal(i, needle))
- return i;
-
- return NULL;
-}
-
-int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
- Manager *m = userdata;
- Link *link = NULL;
- uint16_t type;
- _cleanup_address_free_ Address *address = NULL;
- unsigned char flags;
- Address *existing;
- char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
- const char *valid_str = NULL;
- int r, ifindex;
-
- assert(rtnl);
- assert(message);
- assert(m);
-
- if (sd_netlink_message_is_error(message)) {
- r = sd_netlink_message_get_errno(message);
- if (r < 0)
- log_warning_errno(r, "rtnl: failed to receive address: %m");
-
- return 0;
- }
-
- r = sd_netlink_message_get_type(message, &type);
- if (r < 0) {
- log_warning_errno(r, "rtnl: could not get message type: %m");
- return 0;
- } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
- log_warning("rtnl: received unexpected message type when processing address");
- return 0;
- }
-
- r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
- if (r < 0) {
- log_warning_errno(r, "rtnl: could not get ifindex from address: %m");
- return 0;
- } else if (ifindex <= 0) {
- log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
- return 0;
- } else {
- r = link_get(m, ifindex, &link);
- if (r < 0 || !link) {
- /* when enumerating we might be out of sync, but we will
- * get the address again, so just ignore it */
- if (!m->enumerating)
- log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
- return 0;
- }
- }
-
- r = address_new_dynamic(&address);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_addr_get_family(message, &address->family);
- if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
- log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
- return 0;
- }
-
- r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
- return 0;
- }
-
- r = sd_rtnl_message_addr_get_scope(message, &address->scope);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
- return 0;
- }
-
- r = sd_rtnl_message_addr_get_flags(message, &flags);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
- return 0;
- }
- address->flags = flags;
-
- switch (address->family) {
- case AF_INET:
- r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
- return 0;
- }
-
- break;
-
- case AF_INET6:
- r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
- return 0;
- }
-
- break;
-
- default:
- assert_not_reached("invalid address family");
- }
-
- if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
- log_link_warning(link, "Could not print address");
- return 0;
- }
-
- r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &address->cinfo);
- if (r >= 0) {
- if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
- valid_str = "ever";
- else
- valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
- address->cinfo.ifa_valid * USEC_PER_SEC,
- USEC_PER_SEC);
- }
-
- existing = link_get_equal_address(link, address);
-
- switch (type) {
- case RTM_NEWADDR:
- if (existing) {
- log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
-
-
- existing->scope = address->scope;
- existing->flags = address->flags;
- existing->cinfo = address->cinfo;
-
- } else {
- log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
-
- LIST_PREPEND(addresses, link->addresses, address);
- address_establish(address, link);
-
- address = NULL;
-
- link_save(link);
- }
-
- break;
-
- case RTM_DELADDR:
-
- if (existing) {
- log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
- address_release(existing, link);
- LIST_REMOVE(addresses, link->addresses, existing);
- address_free(existing);
- } else
- log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
-
- break;
- default:
- assert_not_reached("Received invalid RTNL message type");
- }
-
- return 1;
-}
-
int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
Link *link;
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
@@ -2207,8 +2048,10 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
/* not in a container, udev will be around */
sprintf(ifindex_str, "n%d", link->ifindex);
device = udev_device_new_from_device_id(m->udev, ifindex_str);
- if (!device)
- return log_link_warning_errno(link, errno, "Could not find udev device: %m");
+ if (!device) {
+ r = log_link_warning_errno(link, errno, "Could not find udev device: %m");
+ goto failed;
+ }
if (udev_device_get_is_initialized(device) <= 0) {
/* not yet ready */
@@ -2218,17 +2061,20 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
r = link_initialized(link, device);
if (r < 0)
- return r;
+ goto failed;
} else {
/* we are calling a callback directly, so must take a ref */
link_ref(link);
r = link_initialized_and_synced(m->rtnl, NULL, link);
if (r < 0)
- return r;
+ goto failed;
}
return 0;
+failed:
+ link_enter_failed(link);
+ return r;
}
static int link_carrier_gained(Link *link) {
@@ -2425,10 +2271,11 @@ static void link_update_operstate(Link *link) {
else if (link_has_carrier(link)) {
Address *address;
uint8_t scope = RT_SCOPE_NOWHERE;
+ Iterator i;
/* if we have carrier, check what addresses we have */
- LIST_FOREACH(addresses, address, link->addresses) {
- if (address->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
+ SET_FOREACH(address, link->addresses, i) {
+ if (!address_is_ready(address))
continue;
if (address->scope < scope)
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 7b219c6854..b81bae3830 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -83,7 +83,7 @@ struct Link {
unsigned link_messages;
unsigned enslaving;
- LIST_HEAD(Address, addresses);
+ Set *addresses;
sd_dhcp_client *dhcp_client;
sd_dhcp_lease *dhcp_lease;
@@ -120,8 +120,8 @@ 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);
-int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
-int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
void link_enter_failed(Link *link);
int link_initialized(Link *link, struct udev_device *device);
@@ -129,7 +129,6 @@ int link_initialized(Link *link, struct udev_device *device);
void link_client_handler(Link *link);
int link_update(Link *link, sd_netlink_message *message);
-int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata);
int link_save(Link *link);
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index b4259cafef..07e47b668c 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -277,6 +277,166 @@ static int manager_connect_udev(Manager *m) {
return 0;
}
+int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+ Manager *m = userdata;
+ Link *link = NULL;
+ uint16_t type;
+ unsigned char flags;
+ int family;
+ unsigned char prefixlen;
+ unsigned char scope;
+ union in_addr_union in_addr;
+ struct ifa_cacheinfo cinfo;
+ Address *address = NULL;
+ char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
+ const char *valid_str = NULL;
+ int r, ifindex;
+
+ assert(rtnl);
+ assert(message);
+ assert(m);
+
+ if (sd_netlink_message_is_error(message)) {
+ r = sd_netlink_message_get_errno(message);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to receive address: %m");
+
+ return 0;
+ }
+
+ r = sd_netlink_message_get_type(message, &type);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get message type: %m");
+ return 0;
+ } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
+ log_warning("rtnl: received unexpected message type when processing address");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get ifindex from address: %m");
+ return 0;
+ } else if (ifindex <= 0) {
+ log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
+ return 0;
+ } else {
+ r = link_get(m, ifindex, &link);
+ if (r < 0 || !link) {
+ /* when enumerating we might be out of sync, but we will
+ * get the address again, so just ignore it */
+ if (!m->enumerating)
+ log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
+ return 0;
+ }
+ }
+
+ r = sd_rtnl_message_addr_get_family(message, &family);
+ if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
+ log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_scope(message, &scope);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_flags(message, &flags);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
+ return 0;
+ }
+
+ switch (family) {
+ case AF_INET:
+ r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ case AF_INET6:
+ r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ default:
+ assert_not_reached("invalid address family");
+ }
+
+ if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) {
+ log_link_warning(link, "Could not print address");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
+ if (r >= 0) {
+ if (cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
+ valid_str = "ever";
+ else
+ valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
+ cinfo.ifa_valid * USEC_PER_SEC,
+ USEC_PER_SEC);
+ }
+
+ address_get(link, family, &in_addr, prefixlen, &address);
+
+ switch (type) {
+ case RTM_NEWADDR:
+ if (address) {
+ log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+
+ address->scope = scope;
+ address->flags = flags;
+ address->cinfo = cinfo;
+
+ } else {
+ r = address_add(link, family, &in_addr, prefixlen, &address);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to add address %s/%u: %m", buf, prefixlen);
+ return 0;
+ } else
+ log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+
+ address->scope = scope;
+ address->flags = flags;
+ address->cinfo = cinfo;
+
+ link_save(link);
+ }
+
+ break;
+
+ case RTM_DELADDR:
+
+ if (address) {
+ log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+ address_drop(address);
+ } else
+ log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+
+ break;
+ default:
+ assert_not_reached("Received invalid RTNL message type");
+ }
+
+ return 1;
+}
+
static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
Manager *m = userdata;
Link *link = NULL;
@@ -410,11 +570,11 @@ static int manager_connect_rtnl(Manager *m) {
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
+ r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &manager_rtnl_process_address, m);
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
+ r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &manager_rtnl_process_address, m);
if (r < 0)
return r;
@@ -477,14 +637,6 @@ void manager_free(Manager *m) {
free(m->state_file);
- sd_event_source_unref(m->udev_event_source);
- udev_monitor_unref(m->udev_monitor);
- udev_unref(m->udev);
-
- sd_bus_unref(m->bus);
- sd_bus_slot_unref(m->prepare_for_sleep_slot);
- sd_event_source_unref(m->bus_retry_event_source);
-
while ((link = hashmap_first(m->links)))
link_unref(link);
hashmap_free(m->links);
@@ -504,6 +656,14 @@ void manager_free(Manager *m) {
sd_netlink_unref(m->rtnl);
sd_event_unref(m->event);
+ sd_event_source_unref(m->udev_event_source);
+ udev_monitor_unref(m->udev_monitor);
+ udev_unref(m->udev);
+
+ sd_bus_unref(m->bus);
+ sd_bus_slot_unref(m->prepare_for_sleep_slot);
+ sd_event_source_unref(m->bus_retry_event_source);
+
free(m);
}
@@ -633,7 +793,7 @@ int manager_rtnl_enumerate_addresses(Manager *m) {
m->enumerating = true;
- k = link_rtnl_process_address(m->rtnl, addr, m);
+ k = manager_rtnl_process_address(m->rtnl, addr, m);
if (k < 0)
r = k;
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 5d22598fc0..bdee7f1923 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -326,12 +326,12 @@ int network_get(Manager *manager, struct udev_device *device,
(void) safe_atou8(attr, &name_assign_type);
if (name_assign_type == NET_NAME_ENUM)
- log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
- IFNAMSIZ, ifname, network->filename);
+ log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
+ ifname, network->filename);
else
- log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+ log_debug("%s: found matching network '%s'", ifname, network->filename);
} else
- log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+ log_debug("%s: found matching network '%s'", ifname, network->filename);
*ret = network;
return 0;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index ee1ddd81fe..1c8302ffaa 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -26,8 +26,26 @@
#include "networkd.h"
#include "networkd-route.h"
+int route_new(Route **ret, unsigned char rtm_protocol) {
+ _cleanup_route_free_ Route *route = NULL;
+
+ route = new0(Route, 1);
+ if (!route)
+ return -ENOMEM;
+
+ route->family = AF_UNSPEC;
+ route->scope = RT_SCOPE_UNIVERSE;
+ route->protocol = rtm_protocol;
+
+ *ret = route;
+ route = NULL;
+
+ return 0;
+}
+
int route_new_static(Network *network, unsigned section, Route **ret) {
_cleanup_route_free_ Route *route = NULL;
+ int r;
if (section) {
route = hashmap_get(network->routes_by_section,
@@ -40,13 +58,9 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
}
}
- route = new0(Route, 1);
- if (!route)
- return -ENOMEM;
-
- route->family = AF_UNSPEC;
- route->scope = RT_SCOPE_UNIVERSE;
- route->protocol = RTPROT_STATIC;
+ r = route_new(&route, RTPROT_STATIC);
+ if (r < 0)
+ return r;
route->network = network;
@@ -64,23 +78,6 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
return 0;
}
-int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
- _cleanup_route_free_ Route *route = NULL;
-
- route = new0(Route, 1);
- if (!route)
- return -ENOMEM;
-
- route->family = AF_UNSPEC;
- route->scope = RT_SCOPE_UNIVERSE;
- route->protocol = rtm_protocol;
-
- *ret = route;
- route = NULL;
-
- return 0;
-}
-
void route_free(Route *route) {
if (!route)
return;
@@ -96,7 +93,7 @@ void route_free(Route *route) {
free(route);
}
-int route_drop(Route *route, Link *link,
+int route_remove(Route *route, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
int r;
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index 11e94d44fb..e3ed1be866 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -46,10 +46,10 @@ struct Route {
};
int route_new_static(Network *network, unsigned section, Route **ret);
-int route_new_dynamic(Route **ret, unsigned char rtm_protocol);
+int route_new(Route **ret, unsigned char rtm_protocol);
void route_free(Route *route);
int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
-int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback);
+int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback);
DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
#define _cleanup_route_free_ _cleanup_(route_freep)
diff --git a/src/network/networkd.h b/src/network/networkd.h
index eea57ac158..cbec6d5b7e 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -80,6 +80,8 @@ bool manager_should_reload(Manager *m);
int manager_rtnl_enumerate_links(Manager *m);
int manager_rtnl_enumerate_addresses(Manager *m);
+int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
+
int manager_send_changed(Manager *m, const char *property, ...) _sentinel_;
int manager_save(Manager *m);
diff --git a/src/network/test-network.c b/src/network/test-network.c
index 5909cc790e..bac1d6781d 100644
--- a/src/network/test-network.c
+++ b/src/network/test-network.c
@@ -143,8 +143,8 @@ static void test_network_get(Manager *manager, struct udev_device *loopback) {
static void test_address_equality(void) {
_cleanup_address_free_ Address *a1 = NULL, *a2 = NULL;
- assert_se(address_new_dynamic(&a1) >= 0);
- assert_se(address_new_dynamic(&a2) >= 0);
+ assert_se(address_new(&a1) >= 0);
+ assert_se(address_new(&a2) >= 0);
assert_se(address_equal(NULL, NULL));
assert_se(!address_equal(a1, NULL));
@@ -158,17 +158,18 @@ static void test_address_equality(void) {
assert_se(address_equal(a1, a2));
assert_se(inet_pton(AF_INET, "192.168.3.9", &a1->in_addr.in));
- assert_se(address_equal(a1, a2));
+ assert_se(!address_equal(a1, a2));
assert_se(inet_pton(AF_INET, "192.168.3.9", &a2->in_addr.in));
assert_se(address_equal(a1, a2));
+ assert_se(inet_pton(AF_INET, "192.168.3.10", &a1->in_addr_peer.in));
+ assert_se(address_equal(a1, a2));
+ assert_se(inet_pton(AF_INET, "192.168.3.11", &a2->in_addr_peer.in));
+ assert_se(address_equal(a1, a2));
a1->prefixlen = 10;
assert_se(!address_equal(a1, a2));
a2->prefixlen = 10;
assert_se(address_equal(a1, a2));
- assert_se(inet_pton(AF_INET, "192.168.3.10", &a2->in_addr.in));
- assert_se(address_equal(a1, a2));
-
a1->family = AF_INET6;
assert_se(!address_equal(a1, a2));
diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h
index 677505f0c6..cc85140acd 100644
--- a/src/systemd/sd-ipv4ll.h
+++ b/src/systemd/sd-ipv4ll.h
@@ -43,6 +43,7 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
+int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed);
bool sd_ipv4ll_is_running(sd_ipv4ll *ll);
int sd_ipv4ll_start(sd_ipv4ll *ll);
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index e09b8c8e2d..8e1b06ee9a 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -137,6 +137,10 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char
int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope);
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol);
+int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope);
+int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos);
+int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table);
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len);
int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len);