</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>MaxAttempts=</varname></term>
+ <listitem>
+ <para>Specifies how many times the DHCPv4 client configuration should be attempted. Takes a
+ number or <literal>infinity</literal>. Defaults to <literal>infinity</literal>.
+ Note that the time between retries is increased exponentially, so the network will not be
+ overloaded even if this number is high.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>DUIDType=</varname></term>
<listitem>
table entry.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>VNI=</varname></term>
+ <listitem>
+ <para>The VXLAN Network Identifier (or VXLAN Segment ID) to use to connect to
+ the remote VXLAN tunnel endpoint. Takes a number in the range 1-16777215.
+ Defaults to unset.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
cpp = ' '.join(cc.cmd_array()) + ' -E'
+has_wstringop_truncation = cc.has_argument('-Wstringop-truncation')
+
#####################################################################
# compilation result tests
conf.set('_GNU_SOURCE', true)
conf.set('__SANE_USERSPACE_TYPES__', true)
+conf.set10('HAVE_WSTRINGOP_TRUNCATION', has_wstringop_truncation)
conf.set('SIZEOF_PID_T', cc.sizeof('pid_t', prefix : '#include <sys/types.h>'))
conf.set('SIZEOF_UID_T', cc.sizeof('uid_t', prefix : '#include <sys/types.h>'))
_Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"")
+#if HAVE_WSTRINGOP_TRUNCATION
+# define DISABLE_WARNING_STRINGOP_TRUNCATION \
+ _Pragma("GCC diagnostic push"); \
+ _Pragma("GCC diagnostic ignored \"-Wstringop-truncation\"")
+#else
+# define DISABLE_WARNING_STRINGOP_TRUNCATION \
+ _Pragma("GCC diagnostic push")
+#endif
+
#define REENABLE_WARNING \
_Pragma("GCC diagnostic pop")
#include "io-util.h"
#include "missing.h"
#include "random-util.h"
+#include "siphash24.h"
#include "time-util.h"
int rdrand(unsigned long *ret) {
#if defined(__i386__) || defined(__x86_64__)
static int have_rdrand = -1;
- unsigned char err;
+ uint8_t success;
if (have_rdrand < 0) {
uint32_t eax, ebx, ecx, edx;
return -EOPNOTSUPP;
}
- have_rdrand = !!(ecx & (1U << 30));
+/* Compat with old gcc where bit_RDRND didn't exist yet */
+#ifndef bit_RDRND
+#define bit_RDRND (1U << 30)
+#endif
+
+ have_rdrand = !!(ecx & bit_RDRND);
}
if (have_rdrand == 0)
asm volatile("rdrand %0;"
"setc %1"
: "=r" (*ret),
- "=qm" (err));
- msan_unpoison(&err, sizeof(err));
- if (!err)
+ "=qm" (success));
+ msan_unpoison(&success, sizeof(sucess));
+ if (!success)
return -EAGAIN;
return 0;
bool got_some = false;
int r;
- /* Gathers some randomness from the kernel (or the CPU if the RANDOM_ALLOW_RDRAND flag is set). This call won't
- * block, unless the RANDOM_BLOCK flag is set. If RANDOM_DONT_DRAIN is set, an error is returned if the random
- * pool is not initialized. Otherwise it will always return some data from the kernel, regardless of whether
- * the random pool is fully initialized or not. */
+ /* Gathers some randomness from the kernel (or the CPU if the RANDOM_ALLOW_RDRAND flag is set). This
+ * call won't block, unless the RANDOM_BLOCK flag is set. If RANDOM_MAY_FAIL is set, an error is
+ * returned if the random pool is not initialized. Otherwise it will always return some data from the
+ * kernel, regardless of whether the random pool is fully initialized or not. */
if (n == 0)
return 0;
if (FLAGS_SET(flags, RANDOM_ALLOW_RDRAND))
- /* Try x86-64' RDRAND intrinsic if we have it. We only use it if high quality randomness is not
- * required, as we don't trust it (who does?). Note that we only do a single iteration of RDRAND here,
- * even though the Intel docs suggest calling this in a tight loop of 10 invocations or so. That's
- * because we don't really care about the quality here. We generally prefer using RDRAND if the caller
- * allows us too, since this way we won't drain the kernel randomness pool if we don't need it, as the
- * pool's entropy is scarce. */
+ /* Try x86-64' RDRAND intrinsic if we have it. We only use it if high quality randomness is
+ * not required, as we don't trust it (who does?). Note that we only do a single iteration of
+ * RDRAND here, even though the Intel docs suggest calling this in a tight loop of 10
+ * invocations or so. That's because we don't really care about the quality here. We
+ * generally prefer using RDRAND if the caller allows us to, since this way we won't upset
+ * the kernel's random subsystem by accessing it before the pool is initialized (after all it
+ * will kmsg log about every attempt to do so)..*/
for (;;) {
unsigned long u;
size_t m;
break;
} else if (errno == EAGAIN) {
- /* The kernel has no entropy whatsoever. Let's remember to use the syscall the next
- * time again though.
+ /* The kernel has no entropy whatsoever. Let's remember to use the syscall
+ * the next time again though.
*
- * If RANDOM_DONT_DRAIN is set, return an error so that random_bytes() can produce some
- * pseudo-random bytes instead. Otherwise, fall back to /dev/urandom, which we know is empty,
- * but the kernel will produce some bytes for us on a best-effort basis. */
+ * If RANDOM_MAY_FAIL is set, return an error so that random_bytes() can
+ * produce some pseudo-random bytes instead. Otherwise, fall back to
+ * /dev/urandom, which we know is empty, but the kernel will produce some
+ * bytes for us on a best-effort basis. */
have_syscall = true;
if (got_some && FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
return 0;
}
- if (FLAGS_SET(flags, RANDOM_DONT_DRAIN))
+ if (FLAGS_SET(flags, RANDOM_MAY_FAIL))
return -ENODATA;
/* Use /dev/urandom instead */
return;
#if HAVE_SYS_AUXV_H
- /* The kernel provides us with 16 bytes of entropy in auxv, so let's
- * try to make use of that to seed the pseudo-random generator. It's
- * better than nothing... */
+ /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed
+ * the pseudo-random generator. It's better than nothing... But let's first hash it to make it harder
+ * to recover the original value by watching any pseudo-random bits we generate. After all the
+ * AT_RANDOM data might be used by other stuff too (in particular: ASLR), and we probably shouldn't
+ * leak the seed for that. */
- auxv = (const void*) getauxval(AT_RANDOM);
+ auxv = ULONG_TO_PTR(getauxval(AT_RANDOM));
if (auxv) {
- assert_cc(sizeof(x) <= 16);
- memcpy(&x, auxv, sizeof(x));
+ static const uint8_t auxval_hash_key[16] = {
+ 0x92, 0x6e, 0xfe, 0x1b, 0xcf, 0x00, 0x52, 0x9c, 0xcc, 0x42, 0xcf, 0xdc, 0x94, 0x1f, 0x81, 0x0f
+ };
+
+ x = (unsigned) siphash24(auxv, 16, auxval_hash_key);
} else
#endif
x = 0;
void random_bytes(void *p, size_t n) {
- if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_DONT_DRAIN|RANDOM_ALLOW_RDRAND) >= 0)
+ if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND) >= 0)
return;
/* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
typedef enum RandomFlags {
RANDOM_EXTEND_WITH_PSEUDO = 1 << 0, /* If we can't get enough genuine randomness, but some, fill up the rest with pseudo-randomness */
RANDOM_BLOCK = 1 << 1, /* Rather block than return crap randomness (only if the kernel supports that) */
- RANDOM_DONT_DRAIN = 1 << 2, /* If we can't get any randomness at all, return early with -EAGAIN */
+ RANDOM_MAY_FAIL = 1 << 2, /* If we can't get any randomness at all, return early with -ENODATA */
RANDOM_ALLOW_RDRAND = 1 << 3, /* Allow usage of the CPU RNG */
} RandomFlags;
-int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled upwith pseudo random, if not enough is available */
+int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */
void pseudo_random_bytes(void *p, size_t n); /* returns only pseudo-randommess (but possibly seeded from something better) */
void random_bytes(void *p, size_t n); /* returns genuine randomness if cheaply available, and pseudo randomness if not. */
return strlen(s);
}
+DISABLE_WARNING_STRINGOP_TRUNCATION;
+static inline void strncpy_exact(char *buf, const char *src, size_t buf_len) {
+ strncpy(buf, src, buf_len);
+}
+REENABLE_WARNING;
+
/* Like startswith(), but operates on arbitrary memory blocks */
static inline void *memory_startswith(const void *p, size_t sz, const char *token) {
size_t n;
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
-#define MAX_CLIENT_ATTEMPT 64
-
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
uint32_t mtu;
uint32_t xid;
usec_t start_time;
- unsigned attempt;
+ uint64_t attempt;
+ uint64_t max_attempts;
usec_t request_sent;
sd_event_source *timeout_t1;
sd_event_source *timeout_t2;
return 0;
}
+int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) {
+ assert_return(client, -EINVAL);
+
+ client->max_attempts = max_attempts;
+
+ return 0;
+}
+
int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
assert_return(client, -EINVAL);
(void) event_source_disable(client->timeout_t2);
(void) event_source_disable(client->timeout_expire);
- client->attempt = 1;
+ client->attempt = 0;
client->state = DHCP_STATE_INIT;
client->xid = 0;
case DHCP_STATE_REQUESTING:
case DHCP_STATE_BOUND:
- if (client->attempt < MAX_CLIENT_ATTEMPT)
- client->attempt *= 2;
+ if (client->attempt < client->max_attempts)
+ client->attempt++;
else
goto error;
- next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
+ next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
break;
r = client_send_discover(client);
if (r >= 0) {
client->state = DHCP_STATE_SELECTING;
- client->attempt = 1;
- } else {
- if (client->attempt >= MAX_CLIENT_ATTEMPT)
- goto error;
- }
+ client->attempt = 0;
+ } else if (client->attempt >= client->max_attempts)
+ goto error;
break;
case DHCP_STATE_SELECTING:
r = client_send_discover(client);
- if (r < 0 && client->attempt >= MAX_CLIENT_ATTEMPT)
+ if (r < 0 && client->attempt >= client->max_attempts)
goto error;
break;
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
r = client_send_request(client);
- if (r < 0 && client->attempt >= MAX_CLIENT_ATTEMPT)
+ if (r < 0 && client->attempt >= client->max_attempts)
goto error;
if (client->state == DHCP_STATE_INIT_REBOOT)
client->fd = asynchronous_close(client->fd);
client->state = DHCP_STATE_REBINDING;
- client->attempt = 1;
+ client->attempt = 0;
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
client->xid, client->mac_addr,
DHCP_CLIENT_DONT_DESTROY(client);
client->state = DHCP_STATE_RENEWING;
- client->attempt = 1;
+ client->attempt = 0;
return client_initialize_time_events(client);
}
if (r >= 0) {
client->state = DHCP_STATE_REQUESTING;
- client->attempt = 1;
+ client->attempt = 0;
r = event_reset_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
notify_event = r;
client->state = DHCP_STATE_BOUND;
- client->attempt = 1;
+ client->attempt = 0;
client->last_addr = client->lease->address;
.state = DHCP_STATE_INIT,
.ifindex = -1,
.fd = -1,
- .attempt = 1,
.mtu = DHCP_DEFAULT_MIN_SIZE,
.port = DHCP_PORT_CLIENT,
.anonymize = !!anonymize,
+ .max_attempts = (uint64_t) -1,
};
/* NOTE: this could be moved to a function. */
if (anonymize) {
LIST_REMOVE(prefix, ra->prefixes, cur);
ra->n_prefixes--;
+ sd_radv_prefix_unref(cur);
break;
}
return r;
for (m = reply; m; m = sd_netlink_message_next(m)) {
- union in_addr_union gw = {};
- struct ether_addr mac = {};
+ union in_addr_union gw = IN_ADDR_NULL;
+ struct ether_addr mac = ETHER_ADDR_NULL;
uint16_t type;
int ifi, fam;
for (m = reply; m; m = sd_netlink_message_next(m)) {
_cleanup_free_ char *pretty = NULL;
- union in_addr_union prefix = {};
+ union in_addr_union prefix = IN_ADDR_NULL;
uint8_t prefixlen;
uint32_t label;
}
/* And don't clash with configured but un-assigned addresses either */
- LIST_FOREACH(networks, n, p->manager->networks) {
+ ORDERED_HASHMAP_FOREACH(n, p->manager->networks, i) {
Address *a;
LIST_FOREACH(addresses, a, n->static_addresses) {
}
static int address_acquire(Link *link, Address *original, Address **ret) {
- union in_addr_union in_addr = {};
+ union in_addr_union in_addr = IN_ADDR_NULL;
struct in_addr broadcast = {};
_cleanup_(address_freep) Address *na = NULL;
int r;
r = sd_ipv4ll_start(link->ipv4ll);
if (r < 0) {
- log_link_warning(link, "Could not acquire IPv4 link-local address: %m");
+ log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
return;
}
}
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
}
+ if (link->network->dhcp_max_attempts > 0) {
+ r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
+ }
+
return dhcp4_set_client_identifier(link);
}
if (r < 0 && r != -EEXIST)
return r;
- r = manager_dhcp6_prefix_add(link->manager, &p->opt.in6_addr, link);
+ r = manager_dhcp6_prefix_add(link->manager, prefix, link);
if (r < 0)
return r;
&lifetime_preferred,
&lifetime_valid) >= 0) {
_cleanup_free_ char *buf = NULL;
- _cleanup_free_ Route *route = NULL;
+ Route *route;
- if (pd_prefix_len > 64)
+ if (pd_prefix_len >= 64)
continue;
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
- if (pd_prefix_len < 64) {
- r = route_new(&route);
- if (r < 0) {
- log_link_warning_errno(link, r, "Cannot create unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
- strnull(buf),
- pd_prefix_len);
- continue;
- }
-
- r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, 0, 0, 0, &route);
- if (r < 0) {
- log_link_warning_errno(link, r, "Failed to add unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
- strnull(buf),
- pd_prefix_len);
- continue;
- }
-
- route_update(route, NULL, 0, NULL, NULL, 0, 0, RTN_UNREACHABLE);
-
- r = route_remove(route, link, dhcp6_route_remove_handler);
- if (r < 0) {
- (void) in_addr_to_string(AF_INET6,
- &pd_prefix, &buf);
-
- log_link_warning_errno(link, r, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
- strnull(buf),
- pd_prefix_len);
+ r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, 0, 0, 0, &route);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to add unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ continue;
+ }
- continue;
- }
+ route_update(route, NULL, 0, NULL, NULL, 0, 0, RTN_UNREACHABLE);
- log_link_debug(link, "Removing unreachable route %s/%u",
- strnull(buf), pd_prefix_len);
+ r = route_remove(route, link, dhcp6_route_remove_handler);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ continue;
}
+
+ log_link_debug(link, "Removing unreachable route %s/%u",
+ strnull(buf), pd_prefix_len);
}
return 0;
continue;
assigned_link = manager_dhcp6_prefix_get(manager, &prefix.in6);
- if (assigned_link != NULL && assigned_link != link)
+ if (assigned_link && assigned_link != link)
continue;
(void) in_addr_to_string(AF_INET6, &prefix, &assigned_buf);
union in_addr_union pd_prefix;
uint8_t pd_prefix_len;
uint32_t lifetime_preferred, lifetime_valid;
- _cleanup_free_ char *buf = NULL;
Iterator i = ITERATOR_FIRST;
r = sd_dhcp6_client_get_lease(client, &lease);
&lifetime_preferred,
&lifetime_valid) >= 0) {
+ _cleanup_free_ char *buf = NULL;
+
+ (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
+
if (pd_prefix_len > 64) {
- (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s/%u",
strnull(buf), pd_prefix_len);
continue;
}
- if (pd_prefix_len < 48) {
- (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
+ if (pd_prefix_len < 48)
log_link_warning(link, "PD Prefix length < 48, looks unusual %s/%u",
strnull(buf), pd_prefix_len);
- }
if (pd_prefix_len < 64) {
- _cleanup_(route_freep) Route *route = NULL;
uint32_t table;
-
- (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
-
- r = route_new(&route);
- if (r < 0) {
- log_link_warning_errno(link, r, "Cannot create unreachable route for DHCPv6 delegated subnet %s/%u: %m",
- strnull(buf),
- pd_prefix_len);
- continue;
- }
+ Route *route;
table = link_get_dhcp_route_table(link);
log_link_debug(link, "Configuring unreachable route for %s/%u",
strnull(buf), pd_prefix_len);
-
} else
log_link_debug(link, "Not adding a blocking route since distributed prefix is /64");
#include "alloc-util.h"
#include "conf-parser.h"
#include "netdev/bridge.h"
+#include "netdev/vxlan.h"
#include "netlink-util.h"
#include "networkd-fdb.h"
#include "networkd-manager.h"
+#include "parse-util.h"
+#include "string-util.h"
#include "util.h"
#include "vlan-util.h"
*fdb_entry = (FdbEntry) {
.network = network,
.mac_addr = TAKE_PTR(mac_addr),
+ .vni = VXLAN_VID_MAX + 1,
};
LIST_PREPEND(static_fdb_entries, network->static_fdb_entries, fdb_entry);
int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
sd_netlink *rtnl;
- int r;
- uint8_t flags;
Bridge *bridge;
+ uint8_t flags;
+ int r;
assert(link);
assert(link->network);
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
}
+ if (fdb_entry->vni <= VXLAN_VID_MAX) {
+ r = sd_netlink_message_append_u32(req, NDA_VNI, fdb_entry->vni);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append NDA_VNI attribute: %m");
+ }
+
/* send message to the kernel to update its internal static MAC table. */
r = netlink_call_async(rtnl, NULL, req, set_fdb_handler,
link_netlink_destroy_callback, link);
return 0;
}
+
+int config_parse_fdb_vxlan_vni(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL;
+ Network *network = userdata;
+ uint32_t vni;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = fdb_entry_new_static(network, filename, section_line, &fdb_entry);
+ if (r < 0)
+ return log_oom();
+
+ r = safe_atou32(rvalue, &vni);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse VXLAN Network Identifier (VNI), ignoring assignment: %s",
+ rvalue);
+ return 0;
+ }
+
+ if (vni > VXLAN_VID_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "FDB invalid VXLAN Network Identifier (VNI), ignoring assignment: %s",
+ rvalue);
+ return 0;
+ }
+
+ fdb_entry->vni = vni;
+ fdb_entry = NULL;
+
+ return 0;
+}
Network *network;
NetworkConfigSection *section;
+ uint32_t vni;
+
int family;
uint16_t vlan_id;
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_hwaddr);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vlan_id);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_destination);
+CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vxlan_vni);
r = sd_ipv4ll_restart(ll);
if (r < 0)
- log_link_warning(link, "Could not acquire IPv4 link-local address");
+ log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
break;
case SD_IPV4LL_EVENT_BIND:
r = ipv4ll_address_claimed(ll, link);
r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", disabled);
if (r < 0)
- log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m",
- enable_disable(!disabled), link->ifname);
+ log_link_warning_errno(link, r, "Cannot %s IPv6: %m", enable_disable(!disabled));
else
log_link_info(link, "IPv6 successfully %sd", enable_disable(!disabled));
return 0;
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
-
static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
_cleanup_(link_unrefp) Link *link = NULL;
uint16_t type;
}
static Link *link_free(Link *link) {
- Link *carrier;
Address *address;
- Route *route;
- Iterator i;
assert(link);
- while ((route = set_first(link->routes)))
- route_free(route);
-
- while ((route = set_first(link->routes_foreign)))
- route_free(route);
-
- link->routes = set_free(link->routes);
- link->routes_foreign = set_free(link->routes_foreign);
+ link->routes = set_free_with_destructor(link->routes, route_free);
+ link->routes_foreign = set_free_with_destructor(link->routes_foreign, route_free);
- while ((address = set_first(link->addresses)))
- address_free(address);
-
- while ((address = set_first(link->addresses_foreign)))
- address_free(address);
-
- link->addresses = set_free(link->addresses);
- link->addresses_foreign = set_free(link->addresses_foreign);
+ link->addresses = set_free_with_destructor(link->addresses, address_free);
+ link->addresses_foreign = set_free_with_destructor(link->addresses_foreign, address_free);
while ((address = link->pool_addresses)) {
LIST_REMOVE(addresses, link->pool_addresses, address);
sd_device_unref(link->sd_device);
- HASHMAP_FOREACH (carrier, link->bound_to_links, i)
- hashmap_remove(link->bound_to_links, INT_TO_PTR(carrier->ifindex));
hashmap_free(link->bound_to_links);
-
- HASHMAP_FOREACH (carrier, link->bound_by_links, i)
- hashmap_remove(link->bound_by_links, INT_TO_PTR(carrier->ifindex));
hashmap_free(link->bound_by_links);
set_free_with_destructor(link->slaves, link_unref);
+ network_unref(link->network);
+
return mfree(link);
}
Link *link_unref(Link *link);
Link *link_ref(Link *link);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref);
int link_get(Manager *m, int ifindex, Link **ret);
unsigned char protocol, scope, tos, table, rt_type;
int family;
unsigned char dst_prefixlen, src_prefixlen;
- union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {};
+ union in_addr_union dst = IN_ADDR_NULL, gw = IN_ADDR_NULL, src = IN_ADDR_NULL, prefsrc = IN_ADDR_NULL;
Route *route = NULL;
int r;
int family;
unsigned char prefixlen;
unsigned char scope;
- union in_addr_union in_addr;
+ union in_addr_union in_addr = IN_ADDR_NULL;
struct ifa_cacheinfo cinfo;
Address *address = NULL;
char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0, protocol = 0;
struct fib_rule_port_range sport = {}, dport = {};
- union in_addr_union to = {}, from = {};
+ union in_addr_union to = IN_ADDR_NULL, from = IN_ADDR_NULL;
RoutingPolicyRule *rule = NULL;
uint32_t fwmark = 0, table = 0;
const char *iif = NULL, *oif = NULL;
DEFINE_PRIVATE_HASH_OPS(dhcp6_prefixes_hash_ops, struct in6_addr, dhcp6_prefixes_hash_func, dhcp6_prefixes_compare_func);
int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
+ _cleanup_free_ struct in6_addr *a = NULL;
_cleanup_free_ char *buf = NULL;
+ Link *assigned_link;
Route *route;
int r;
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
log_link_debug(link, "Adding prefix route %s/64", strnull(buf));
+ assigned_link = hashmap_get(m->dhcp6_prefixes, addr);
+ if (assigned_link) {
+ assert(assigned_link == link);
+ return 0;
+ }
+
+ a = newdup(struct in6_addr, addr, 1);
+ if (!a)
+ return -ENOMEM;
+
r = hashmap_ensure_allocated(&m->dhcp6_prefixes, &dhcp6_prefixes_hash_ops);
if (r < 0)
return r;
- return hashmap_put(m->dhcp6_prefixes, addr, link);
+ r = hashmap_put(m->dhcp6_prefixes, a, link);
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(a);
+ link_ref(link);
+ return 0;
}
static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
}
static int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
+ _cleanup_free_ struct in6_addr *a = NULL;
+ _cleanup_(link_unrefp) Link *l = NULL;
_cleanup_free_ char *buf = NULL;
Route *route;
- Link *l;
int r;
assert_return(m, -EINVAL);
assert_return(addr, -EINVAL);
- l = hashmap_remove(m->dhcp6_prefixes, addr);
+ l = hashmap_remove2(m->dhcp6_prefixes, addr, (void **) &a);
if (!l)
return -EINVAL;
(void) sd_radv_remove_prefix(l->radv, addr, 64);
- r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64,
- 0, 0, 0, &route);
+ r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64, 0, 0, 0, &route);
if (r < 0)
return r;
assert_return(m, -EINVAL);
assert_return(link, -EINVAL);
- HASHMAP_FOREACH_KEY(l, addr, m->dhcp6_prefixes, i) {
- if (l != link)
- continue;
-
- (void) manager_dhcp6_prefix_remove(m, addr);
- }
+ HASHMAP_FOREACH_KEY(l, addr, m->dhcp6_prefixes, i)
+ if (l == link)
+ (void) manager_dhcp6_prefix_remove(m, addr);
return 0;
}
if (r < 0)
return r;
- LIST_HEAD_INIT(m->networks);
-
r = sd_resolve_default(&m->resolve);
if (r < 0)
return r;
}
void manager_free(Manager *m) {
+ struct in6_addr *a;
AddressPool *pool;
- Network *network;
Link *link;
if (!m)
free(m->state_file);
- sd_netlink_unref(m->rtnl);
- sd_netlink_unref(m->genl);
- sd_resolve_unref(m->resolve);
-
- while ((link = hashmap_first(m->dhcp6_prefixes)))
- manager_dhcp6_prefix_remove_all(m, link);
+ while ((a = hashmap_first_key(m->dhcp6_prefixes)))
+ (void) manager_dhcp6_prefix_remove(m, a);
hashmap_free(m->dhcp6_prefixes);
while ((link = hashmap_steal_first(m->links))) {
m->links = hashmap_free_with_destructor(m->links, link_unref);
m->duids_requesting_uuid = set_free(m->duids_requesting_uuid);
- while ((network = m->networks))
- network_free(network);
- hashmap_free(m->networks_by_name);
+ m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
m->rules_foreign = set_free_with_destructor(m->rules_foreign, routing_policy_rule_free);
set_free_with_destructor(m->rules_saved, routing_policy_rule_free);
+ sd_netlink_unref(m->rtnl);
+ sd_netlink_unref(m->genl);
+ sd_resolve_unref(m->resolve);
+
sd_event_unref(m->event);
sd_device_monitor_unref(m->device_monitor);
Hashmap *links;
Hashmap *netdevs;
- Hashmap *networks_by_name;
+ OrderedHashmap *networks;
Hashmap *dhcp6_prefixes;
- LIST_HEAD(Network, networks);
LIST_HEAD(AddressPool, address_pools);
usec_t network_dirs_ts_usec;
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
_cleanup_(route_freep) Route *route = NULL;
- struct in6_addr gateway;
+ union in_addr_union gateway;
uint16_t lifetime;
unsigned preference;
uint32_t mtu;
if (lifetime == 0) /* not a default router */
return 0;
- r = sd_ndisc_router_get_address(rt, &gateway);
+ r = sd_ndisc_router_get_address(rt, &gateway.in6);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
- SET_FOREACH(address, link->addresses, i)
- if (!memcmp(&gateway, &address->in_addr.in6, sizeof(address->in_addr.in6))) {
+ SET_FOREACH(address, link->addresses, i) {
+ if (address->family != AF_INET6)
+ continue;
+ if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
char buffer[INET6_ADDRSTRLEN];
log_link_debug(link, "No NDisc route added, gateway %s matches local address",
buffer, sizeof(buffer)));
return 0;
}
+ }
- SET_FOREACH(address, link->addresses_foreign, i)
- if (!memcmp(&gateway, &address->in_addr.in6, sizeof(address->in_addr.in6))) {
+ SET_FOREACH(address, link->addresses_foreign, i) {
+ if (address->family != AF_INET6)
+ continue;
+ if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
char buffer[INET6_ADDRSTRLEN];
log_link_debug(link, "No NDisc route added, gateway %s matches local address",
buffer, sizeof(buffer)));
return 0;
}
+ }
r = sd_ndisc_router_get_preference(rt, &preference);
if (r < 0)
route->priority = link->network->dhcp_route_metric;
route->protocol = RTPROT_RA;
route->pref = preference;
- route->gw.in6 = gateway;
+ route->gw = gateway;
route->lifetime = time_now + lifetime * USEC_PER_SEC;
route->mtu = mtu;
_cleanup_strv_free_ char **l = NULL;
Manager *m = userdata;
Network *network;
+ Iterator i;
int r;
assert(bus);
assert(m);
assert(nodes);
- LIST_FOREACH(networks, network, m->networks) {
+ ORDERED_HASHMAP_FOREACH(network, m->networks, i) {
char *p;
p = network_bus_path(network);
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
+DHCP.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0
DHCP.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class)
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
BridgeFDB.Destination, config_parse_fdb_destination, 0, 0
+BridgeFDB.VNI, config_parse_fdb_vxlan_vni, 0, 0
BridgeVLAN.PVID, config_parse_brvlan_pvid, 0, 0
BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0
BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 0, 0
int network_load_one(Manager *manager, const char *filename) {
_cleanup_free_ char *fname = NULL, *name = NULL;
- _cleanup_(network_freep) Network *network = NULL;
+ _cleanup_(network_unrefp) Network *network = NULL;
_cleanup_fclose_ FILE *file = NULL;
const char *dropin_dirname;
char *d;
.filename = TAKE_PTR(fname),
.name = TAKE_PTR(name),
+ .manager = manager,
+ .n_ref = 1,
+
.required_for_online = true,
.required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
.dhcp = ADDRESS_FAMILY_NO,
/* To enable/disable RFC7844 Anonymity Profiles */
.dhcp_anonymize = false,
.dhcp_route_metric = DHCP_ROUTE_METRIC,
- /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
+ /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
.dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
.dhcp_route_table = RT_TABLE_MAIN,
.dhcp_route_table_set = false,
if (r < 0)
log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
- LIST_PREPEND(networks, manager->networks, network);
- network->manager = manager;
-
- r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
+ r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
if (r < 0)
return r;
- r = hashmap_put(manager->networks_by_name, network->name, network);
+ r = ordered_hashmap_put(manager->networks, network->name, network);
if (r < 0)
return r;
}
int network_load(Manager *manager) {
- Network *network;
_cleanup_strv_free_ char **files = NULL;
char **f;
int r;
assert(manager);
- while ((network = manager->networks))
- network_free(network);
+ ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
if (r < 0)
return log_error_errno(r, "Failed to enumerate network files: %m");
- STRV_FOREACH_BACKWARDS(f, files) {
+ STRV_FOREACH(f, files) {
r = network_load_one(manager, *f);
if (r < 0)
return r;
return 0;
}
-void network_free(Network *network) {
+static Network *network_free(Network *network) {
IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
RoutingPolicyRule *rule;
FdbEntry *fdb_entry;
Route *route;
if (!network)
- return;
+ return NULL;
free(network->filename);
hashmap_free(network->rules_by_section);
if (network->manager) {
- if (network->manager->networks)
- LIST_REMOVE(networks, network->manager->networks, network);
-
- if (network->manager->networks_by_name && network->name)
- hashmap_remove(network->manager->networks_by_name, network->name);
+ if (network->manager->networks && network->name)
+ ordered_hashmap_remove(network->manager->networks, network->name);
if (network->manager->duids_requesting_uuid)
set_remove(network->manager->duids_requesting_uuid, &network->duid);
set_free_free(network->dnssec_negative_trust_anchors);
- free(network);
+ return mfree(network);
}
+DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
+
int network_get_by_name(Manager *manager, const char *name, Network **ret) {
Network *network;
assert(name);
assert(ret);
- network = hashmap_get(manager->networks_by_name, name);
+ network = ordered_hashmap_get(manager->networks, name);
if (!network)
return -ENOENT;
Network **ret) {
const char *path = NULL, *driver = NULL, *devtype = NULL;
Network *network;
+ Iterator i;
assert(manager);
assert(ret);
(void) sd_device_get_devtype(device, &devtype);
}
- LIST_FOREACH(networks, network, manager->networks) {
+ ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
if (net_match_config(network->match_mac, network->match_path,
network->match_driver, network->match_type,
network->match_name,
*ret = network;
return 0;
}
- }
*ret = NULL;
assert(network);
assert(link);
- link->network = network;
+ link->network = network_ref(network);
if (network->n_dns > 0 ||
!strv_isempty(network->ntp) ||
return 0;
}
+int config_parse_dhcp_max_attempts(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = data;
+ uint64_t a;
+ int r;
+
+ assert(network);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ network->dhcp_max_attempts = 0;
+ return 0;
+ }
+
+ if (streq(rvalue, "infinity")) {
+ network->dhcp_max_attempts = (uint64_t) -1;
+ return 0;
+ }
+
+ r = safe_atou64(rvalue, &a);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse DHCP maximum attempts, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (a == 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s= must be positive integer or 'infinity', ignoring: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ network->dhcp_max_attempts = a;
+
+ return 0;
+}
+
DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
"Failed to parse DHCP use domains setting");
char *filename;
char *name;
+ unsigned n_ref;
+
Set *match_mac;
char **match_path;
char **match_driver;
char *dhcp_vendor_class_identifier;
char **dhcp_user_class;
char *dhcp_hostname;
+ uint64_t dhcp_max_attempts;
unsigned dhcp_route_metric;
uint32_t dhcp_route_table;
uint16_t dhcp_client_port;
char **ntp;
char **bind_carrier;
-
- LIST_FIELDS(Network, networks);
};
-void network_free(Network *network);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free);
+Network *network_ref(Network *network);
+Network *network_unref(Network *network);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_unref);
int network_load(Manager *manager);
int network_load_one(Manager *manager, const char *filename);
CONFIG_PARSER_PROTOTYPE(config_parse_ntp);
CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
CONFIG_PARSER_PROTOTYPE(config_parse_required_for_online);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
/* Legacy IPv4LL support */
CONFIG_PARSER_PROTOTYPE(config_parse_ipv4ll);
static void test_network_get(Manager *manager, sd_device *loopback) {
Network *network;
- const struct ether_addr mac = {};
+ const struct ether_addr mac = ETHER_ADDR_NULL;
/* let's assume that the test machine does not have a .network file
that applies to the loopback device... */
}
static void test_config_parse_address_one(const char *rvalue, int family, unsigned n_addresses, const union in_addr_union *u, unsigned char prefixlen) {
- _cleanup_(network_freep) Network *network = NULL;
+ _cleanup_(network_unrefp) Network *network = NULL;
assert_se(network = new0(Network, 1));
+ network->n_ref = 1;
assert_se(network->filename = strdup("hogehoge.network"));
assert_se(config_parse_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0);
assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0);
return write_entry_both(&store);
}
-_pure_ static const char *sanitize_id(const char *id) {
+static void copy_suffix(char *buf, size_t buf_size, const char *src) {
size_t l;
- assert(id);
- l = strlen(id);
-
- if (l <= sizeof(((struct utmpx*) NULL)->ut_id))
- return id;
-
- return id + l - sizeof(((struct utmpx*) NULL)->ut_id);
+ l = strlen(src);
+ if (l < buf_size)
+ strncpy(buf, src, buf_size);
+ else
+ memcpy(buf, src + l - buf_size, buf_size);
}
int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user) {
init_timestamp(&store, 0);
- /* ut_id needs only be nul-terminated if it is shorter than sizeof(ut_id) */
- strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id));
+ /* Copy the whole string if it fits, or just the suffix without the terminating NUL. */
+ copy_suffix(store.ut_id, sizeof(store.ut_id), id);
if (line)
- strncpy(store.ut_line, basename(line), sizeof(store.ut_line));
+ strncpy_exact(store.ut_line, line, sizeof(store.ut_line));
r = write_entry_both(&store);
if (r < 0)
setutxent();
- /* ut_id needs only be nul-terminated if it is shorter than sizeof(ut_id) */
- strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id));
+ /* Copy the whole string if it fits, or just the suffix without the terminating NUL. */
+ copy_suffix(store.ut_id, sizeof(store.ut_id), id);
found = getutxid(&lookup);
if (!found)
int sd_dhcp_client_set_mtu(
sd_dhcp_client *client,
uint32_t mtu);
+int sd_dhcp_client_set_max_attempts(
+ sd_dhcp_client *client,
+ uint64_t attempt);
int sd_dhcp_client_set_client_port(
sd_dhcp_client *client,
uint16_t port);
* If the vendor id appears in the page assume the page is
* invalid.
*/
- if (strneq((char *)&buffer[VENDOR_LENGTH], dev_scsi->vendor, VENDOR_LENGTH)) {
+ if (strneq((char*) buffer + VENDOR_LENGTH, dev_scsi->vendor, VENDOR_LENGTH)) {
log_debug("%s: invalid page0 data", dev_scsi->kernel);
return 1;
}
return 0;
}
-/*
- * The caller checks that serial is long enough to include the vendor +
- * model.
- */
-static int prepend_vendor_model(struct scsi_id_device *dev_scsi, char *serial) {
- int ind;
-
- strncpy(serial, dev_scsi->vendor, VENDOR_LENGTH);
- strncat(serial, dev_scsi->model, MODEL_LENGTH);
- ind = strlen(serial);
+static int append_vendor_model(
+ const struct scsi_id_device *dev_scsi,
+ char buf[static VENDOR_LENGTH + MODEL_LENGTH]) {
- /*
- * This is not a complete check, since we are using strncat/cpy
- * above, ind will never be too large.
- */
- if (ind != (VENDOR_LENGTH + MODEL_LENGTH))
+ if (strnlen(dev_scsi->vendor, VENDOR_LENGTH) != VENDOR_LENGTH)
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: bad vendor string \"%s\"",
+ dev_scsi->kernel, dev_scsi->vendor);
+ if (strnlen(dev_scsi->model, MODEL_LENGTH) != MODEL_LENGTH)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: expected length %d, got length %d",
- dev_scsi->kernel,
- (VENDOR_LENGTH + MODEL_LENGTH), ind);
- return ind;
+ "%s: bad model string \"%s\"",
+ dev_scsi->kernel, dev_scsi->model);
+ memcpy(buf, dev_scsi->vendor, VENDOR_LENGTH);
+ memcpy(buf + VENDOR_LENGTH, dev_scsi->model, MODEL_LENGTH);
+ return VENDOR_LENGTH + MODEL_LENGTH;
}
/*
* included in the identifier.
*/
if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC)
- if (prepend_vendor_model(dev_scsi, &serial[1]) < 0)
+ if (append_vendor_model(dev_scsi, serial + 1) < 0)
return 1;
i = 4; /* offset to the start of the identifier */
}
}
- strcpy(serial_short, &serial[s]);
+ strcpy(serial_short, serial + s);
if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) {
- strncpy(wwn, &serial[s], 16);
+ strncpy(wwn, serial + s, 16);
if (wwn_vendor_extension)
- strncpy(wwn_vendor_extension, &serial[s + 16], 16);
+ strncpy(wwn_vendor_extension, serial + s + 16, 16);
}
return 0;
* one or a small number of descriptors.
*/
for (j = 4; j <= (unsigned)page_83[3] + 3; j += page_83[j + 3] + 4) {
- retval = check_fill_0x83_id(dev_scsi, &page_83[j],
- &id_search_list[id_ind],
+ retval = check_fill_0x83_id(dev_scsi, page_83 + j,
+ id_search_list + id_ind,
serial, serial_short, len,
wwn, wwn_vendor_extension,
tgpt_group);
len = buf[3];
if (serial) {
serial[0] = 'S';
- ser_ind = prepend_vendor_model(dev_scsi, &serial[1]);
+ ser_ind = append_vendor_model(dev_scsi, serial + 1);
if (ser_ind < 0)
return 1;
ser_ind++; /* for the leading 'S' */
serial[ser_ind] = buf[i];
}
if (serial_short) {
- memcpy(serial_short, &buf[4], len);
+ memcpy(serial_short, buf + 4, len);
serial_short[len] = '\0';
}
return 0;
VLANId=
MACAddress=
Destination=
+VNI=
[DHCP]
UseDomains=
UseRoutes=
DefaultLeaseTimeSec=
EmitTimezone=
DNS=
+MaxAttempts=
[DHCPv4]
UseHostname=
UseMTU=
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
+LinkLocalAddressing=fallback
+IPv6AcceptRA=no
+
+[DHCP]
+MaxAttempts=1
'dhcp-client-route-metric.network',
'dhcp-client-route-table.network',
'dhcp-client-vrf.network',
- 'dhcp-client-with-ipv4ll-fallback.network',
+ 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
+ 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
'dhcp-client.network',
'dhcp-server-veth-peer.network',
'dhcp-v4-server-veth-peer.network',
print(output)
self.assertRegex(output, 'onlink')
- def test_dhcp_client_with_ipv4ll_fallback(self):
+ def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
- 'dhcp-client-with-ipv4ll-fallback.network')
+ 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
self.start_networkd(0)
+ self.wait_online(['veth-peer:carrier'])
self.start_dnsmasq(lease_time='2m')
self.wait_online(['veth99:routable', 'veth-peer:routable'])
self.search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
+ def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
+ self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
+ 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
+ self.start_networkd(0)
+ self.wait_online(['veth99:degraded', 'veth-peer:routable'])
+
+ output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
+ print(output)
+
+ output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic']).rstrip().decode('utf-8')
+ self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
+ output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link']).rstrip().decode('utf-8')
+ self.assertRegex(output, 'inet6 .* scope link')
+ output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic']).rstrip().decode('utf-8')
+ self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
+ output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link']).rstrip().decode('utf-8')
+ self.assertRegex(output, 'inet .* scope link')
+
if __name__ == '__main__':
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
verbosity=3))