@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b DefaultDependencies = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
- readonly s OnSuccesJobMode = '...';
+ readonly s OnSuccessJobMode = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s OnFailureJobMode = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
<!--property CanFreeze is not documented!-->
- <!--property OnSuccesJobMode is not documented!-->
+ <!--property OnSuccessJobMode is not documented!-->
<!--property OnFailureJobMode is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="DefaultDependencies"/>
- <variablelist class="dbus-property" generated="True" extra-ref="OnSuccesJobMode"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="OnSuccessJobMode"/>
<variablelist class="dbus-property" generated="True" extra-ref="OnFailureJobMode"/>
<varlistentry>
<term><varname>ReceiveChecksumOffload=</varname></term>
<listitem>
- <para>Takes a boolean. If set to true, the hardware offload for checksumming of ingress
+ <para>Takes a boolean. If set to true, hardware offload for checksumming of ingress
network packets is enabled. When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>TransmitChecksumOffload=</varname></term>
<listitem>
- <para>Takes a boolean. If set to true, the hardware offload for checksumming of egress
+ <para>Takes a boolean. If set to true, hardware offload for checksumming of egress
network packets is enabled. When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>TCPSegmentationOffload=</varname></term>
<listitem>
- <para>Takes a boolean. If set to true, the TCP Segmentation Offload (TSO) is enabled.
+ <para>Takes a boolean. If set to true, TCP Segmentation Offload (TSO) is enabled.
When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>TCP6SegmentationOffload=</varname></term>
<listitem>
- <para>Takes a boolean. If set to true, the TCP6 Segmentation Offload (tx-tcp6-segmentation) is enabled.
+ <para>Takes a boolean. If set to true, TCP6 Segmentation Offload (tx-tcp6-segmentation) is enabled.
When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>GenericSegmentationOffload=</varname></term>
<listitem>
- <para>Takes a boolean. If set to true, the Generic Segmentation Offload (GSO) is enabled.
+ <para>Takes a boolean. If set to true, Generic Segmentation Offload (GSO) is enabled.
When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>GenericReceiveOffload=</varname></term>
<listitem>
- <para>Takes a boolean. If set to true, the Generic Receive Offload (GRO) is enabled.
+ <para>Takes a boolean. If set to true, Generic Receive Offload (GRO) is enabled.
When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>LargeReceiveOffload=</varname></term>
<listitem>
- <para>Takes a boolean. If set to true, the Large Receive Offload (LRO) is enabled.
+ <para>Takes a boolean. If set to true, Large Receive Offload (LRO) is enabled.
When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RxFlowControl=</varname></term>
<listitem>
- <para>Takes a boolean. When set, enables the receive flow control, also known as the ethernet
+ <para>Takes a boolean. When set, enables receive flow control, also known as the ethernet
receive PAUSE message (generate and send ethernet PAUSE frames). When unset, the kernel's
default will be used.</para>
</listitem>
<varlistentry>
<term><varname>TxFlowControl=</varname></term>
<listitem>
- <para>Takes a boolean. When set, enables the transmit flow control, also known as the ethernet
+ <para>Takes a boolean. When set, enables transmit flow control, also known as the ethernet
transmit PAUSE message (respond to received ethernet PAUSE frames). When unset, the kernel's
default will be used.</para>
</listitem>
<varlistentry>
<term><varname>AutoNegotiationFlowControl=</varname></term>
<listitem>
- <para>Takes a boolean. When set, the auto negotiation enables the interface to exchange state
+ <para>Takes a boolean. When set, auto negotiation enables the interface to exchange state
advertisements with the connected peer so that the two devices can agree on the ethernet
PAUSE configuration. When unset, the kernel's default will be used.</para>
</listitem>
<term><varname>Priority=</varname></term>
<listitem>
<para>Specifies the priority of this rule. <varname>Priority=</varname> is an unsigned
- integer. Higher number means lower priority, and rules get processed in order of increasing number.</para>
+ integer in the range 0…4294967295. Higher number means lower priority, and rules get
+ processed in order of increasing number. Defaults to unset, and the kernel will pick
+ a value dynamically.</para>
</listitem>
</varlistentry>
<varlistentry>
'--dry-run[Do not actually trigger the event.]' \
'--quiet[Suppress error logging in triggering events.]' \
'--type=[Trigger a specific type of devices.]:types:(devices subsystems failed)' \
- '--action=[Type of event to be triggered.]:actions:(add change remove)' \
+ '--action=[Type of event to be triggered.]:actions:(add change remove move online offline bind unbind)' \
'--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \
'--subsystem-nomatch=[Do not trigger events for devices which belong to a matching subsystem.]' \
'--attr-match=attribute=[Trigger events for devices with a matching sysfs attribute.]' \
(( $+functions[_udevadm_test] )) ||
_udevadm_test(){
_arguments \
- '--action=[The action string.]:actions:(add change remove)' \
+ '--action=[The action string.]:actions:(add change remove move online offline bind unbind)' \
'--subsystem=[The subsystem string.]' \
'--help[Print help text.]' \
'*::devpath:_files -P /sys/ -W /sys'
if (streq(member, "IPIngressFilterPath"))
info->ip_filters_custom_ingress = !strv_isempty(l);
else if (streq(member, "IPEgressFilterPath"))
- info->ip_filters_custom_ingress = !strv_isempty(l);
+ info->ip_filters_custom_egress = !strv_isempty(l);
return 0;
}
*entry = (ConfigEntry) {
.type = type,
.title = StrDuplicate(title),
- .version = StrDuplicate(version),
+ .version = version ? StrDuplicate(version) : NULL,
.device = device,
.loader = StrDuplicate(loader),
.id = StrDuplicate(id),
handover(image, ST, params);
}
-EFI_STATUS linux_exec(EFI_HANDLE *image,
+EFI_STATUS linux_exec(EFI_HANDLE image,
CHAR8 *cmdline, UINTN cmdline_len,
UINTN linux_addr,
UINTN initrd_addr, UINTN initrd_size) {
UINT8 _pad9[276];
} __attribute__((packed));
-EFI_STATUS linux_exec(EFI_HANDLE *image,
+EFI_STATUS linux_exec(EFI_HANDLE image,
CHAR8 *cmdline, UINTN cmdline_size,
UINTN linux_addr,
UINTN initrd_addr, UINTN initrd_size);
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, (CHAR16*) L"\\loader\\random-seed", EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL);
if (EFI_ERROR(err)) {
- if (err != EFI_NOT_FOUND)
+ if (err != EFI_NOT_FOUND && err != EFI_WRITE_PROTECTED)
Print(L"Failed to open random seed file: %r\n", err);
return err;
}
assert(u);
+ if (!u->cgroup_path)
+ return 0;
+
r = cg_get_keyed_attribute_graceful(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.events",
STRV_MAKE("populated", "frozen"), values);
if (r < 0)
}
}
+void unit_cgroup_catchup(Unit *u) {
+ assert(u);
+
+ if (!UNIT_HAS_CGROUP_CONTEXT(u))
+ return;
+
+ /* We dropped the inotify watch during reexec/reload, so we need to
+ * check these as they may have changed.
+ * Note that (currently) the kernel doesn't actually update cgroup
+ * file modification times, so we can't just serialize and then check
+ * the mtime for file(s) we are interested in. */
+ (void) unit_check_cgroup_events(u);
+ unit_add_to_cgroup_oom_queue(u);
+}
+
bool unit_cgroup_delegate(Unit *u) {
CGroupContext *c;
const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
+void unit_cgroup_catchup(Unit *u);
+
bool unit_cgroup_delegate(Unit *u);
int compare_job_priority(const void *a, const void *b);
SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("OnSuccesJobMode", "s", property_get_job_mode, offsetof(Unit, on_success_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("OnSuccesJobMode", "s", property_get_job_mode, offsetof(Unit, on_success_job_mode), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* deprecated */
+ SD_BUS_PROPERTY("OnSuccessJobMode", "s", property_get_job_mode, offsetof(Unit, on_success_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
assert(!m->cleanup_queue);
assert(!m->gc_unit_queue);
assert(!m->gc_job_queue);
+ assert(!m->cgroup_realize_queue);
+ assert(!m->cgroup_empty_queue);
+ assert(!m->cgroup_oom_queue);
+ assert(!m->target_deps_queue);
assert(!m->stop_when_unneeded_queue);
assert(!m->start_when_upheld_queue);
assert(!m->stop_when_bound_queue);
if (u->in_dbus_queue)
LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
+ if (u->in_cleanup_queue)
+ LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
+
if (u->in_gc_queue)
LIST_REMOVE(gc_queue, u->manager->gc_unit_queue, u);
if (u->in_cgroup_empty_queue)
LIST_REMOVE(cgroup_empty_queue, u->manager->cgroup_empty_queue, u);
- if (u->in_cleanup_queue)
- LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
+ if (u->in_cgroup_oom_queue)
+ LIST_REMOVE(cgroup_oom_queue, u->manager->cgroup_oom_queue, u);
if (u->in_target_deps_queue)
LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
int unit_coldplug(Unit *u) {
int r = 0, q;
char **i;
- Job *uj;
assert(u);
r = q;
}
- uj = u->job ?: u->nop_job;
- if (uj) {
- q = job_coldplug(uj);
+ if (u->job) {
+ q = job_coldplug(u->job);
+ if (q < 0 && r >= 0)
+ r = q;
+ }
+ if (u->nop_job) {
+ q = job_coldplug(u->nop_job);
if (q < 0 && r >= 0)
r = q;
}
if (UNIT_VTABLE(u)->catchup)
UNIT_VTABLE(u)->catchup(u);
+
+ unit_cgroup_catchup(u);
}
static bool fragment_mtime_newer(const char *path, usec_t mtime, bool path_masked) {
/* Order the mount unit we generate relative to the post unit, so that DefaultDependencies= on the
* target unit won't affect us. */
- if (post && !FLAGS_SET(flags, MOUNT_AUTOMOUNT) && !FLAGS_SET(flags, MOUNT_NOAUTO))
+ if (post && !FLAGS_SET(flags, MOUNT_AUTOMOUNT) && !FLAGS_SET(flags, MOUNT_NOAUTO) &&
+ !FLAGS_SET(flags, MOUNT_NOFAIL))
fprintf(f, "Before=%s\n", post);
if (passno != 0) {
if (curl_easy_setopt(c, CURLOPT_LOW_SPEED_LIMIT, 30L) != CURLE_OK)
return -EIO;
+ if (curl_easy_setopt(c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_FILE) != CURLE_OK)
+ return -EIO;
+
*ret = TAKE_PTR(c);
return 0;
}
if (s->runtime_journal)
return s->runtime_journal;
+ /* If we are not in persistent mode, then we need return NULL immediately rather than opening a
+ * persistent journal of any sort.
+ *
+ * Fixes https://github.com/systemd/systemd/issues/20390 */
+ if (!IN_SET(s->storage, STORAGE_AUTO, STORAGE_PERSISTENT))
+ return NULL;
+
if (uid_for_system_journal(uid))
return s->system_journal;
if (server->bound_leases[pool_offset] == existing_lease) {
server->bound_leases[pool_offset] = NULL;
- hashmap_remove(server->leases_by_client_id, existing_lease);
+ hashmap_remove(server->leases_by_client_id, &existing_lease->client_id);
dhcp_lease_free(existing_lease);
if (server->callback)
if (lease->ia.addresses) {
lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1));
- lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t1));
+ lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t2));
}
break;
dhcp6_message_type_to_string(message->type));
return -EINVAL;
}
+ }
- } else {
- if (lease->ia.addresses) {
- lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
- lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2);
- }
+ if (lease->ia.addresses) {
+ lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
+ lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2);
+ }
- if (lease->pd.addresses) {
- lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
- lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
- }
+ if (lease->pd.addresses) {
+ lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
+ lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
}
client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);
#include "conf-parser.h"
#include "macvlan.h"
#include "macvlan-util.h"
+#include "networkd-network.h"
#include "parse-util.h"
DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
assert(netdev);
assert(link);
assert(netdev->ifname);
+ assert(link->network);
if (netdev->kind == NETDEV_KIND_MACVLAN)
m = MACVLAN(netdev);
return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACVLAN_MODE attribute: %m");
}
+ /* set the nopromisc flag if Promiscuous= of the link is explicitly set to false */
+ if (m->mode == NETDEV_MACVLAN_MODE_PASSTHRU && link->network->promiscuous == 0) {
+ r = sd_netlink_message_append_u16(req, IFLA_MACVLAN_FLAGS, MACVLAN_FLAG_NOPROMISC);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACVLAN_FLAGS attribute: %m");
+ }
+
if (m->bc_queue_length != UINT32_MAX) {
r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_BC_QUEUE_LEN, m->bc_queue_length);
if (r < 0)
if (r <= 0)
return r;
- r = address_get(link, req->address, &a);
- if (r < 0)
- return r;
-
- r = address_configure(a, link, req->netlink_handler);
+ r = address_configure(req->address, link, req->netlink_handler);
if (r < 0)
return r;
/* To prevent a double decrement on failure in after_configure(). */
req->message_counter = NULL;
+ r = address_get(link, req->address, &a);
+ if (r < 0)
+ return r;
+
if (req->after_configure) {
r = req->after_configure(req, a);
if (r < 0)
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <net/if.h>
#include <netinet/in.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include "ethtool-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "format-util.h"
#include "fs-util.h"
#include "ipvlan.h"
#include "missing_network.h"
}
static int link_update_name(Link *link, sd_netlink_message *message) {
+ char ifname_from_index[IF_NAMESIZE + 1];
const char *ifname;
int r;
if (streq(ifname, link->ifname))
return 0;
+ if (!format_ifname(link->ifindex, ifname_from_index))
+ return log_link_debug_errno(link, SYNTHETIC_ERRNO(ENXIO), "Could not get interface name for index %i.", link->ifindex);
+
+ if (!streq(ifname, ifname_from_index)) {
+ log_link_debug(link, "New interface name '%s' received from the kernel does not correspond "
+ "with the name currently configured on the actual interface '%s'. Ignoring.",
+ ifname, ifname_from_index);
+ return 0;
+ }
+
log_link_info(link, "Interface name change detected, renamed to %s.", ifname);
hashmap_remove(link->manager->links_by_name, link->ifname);
assert(link);
assert(rt);
- r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
+ /* Do not use clock_boottime_or_monotonic() here, as the kernel internally manages cstamp and
+ * tstamp with jiffies, and it is not increased while the system is suspended. */
+ r = sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &time_now);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
}
}
- if (nexthop->onlink <= 0 &&
- in_addr_is_set(nexthop->family, &nexthop->gw) &&
- !manager_address_is_reachable(link->manager, nexthop->family, &nexthop->gw))
- return false;
-
- return true;
+ return gateway_is_ready(link, nexthop->onlink, nexthop->family, &nexthop->gw);
}
int request_process_nexthop(Request *req) {
FAMILY_ADDRESS_SIZE(family) * 8) > 0;
}
-bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address) {
- Link *link;
+static bool prefix_route_address_is_reachable(const Address *a, int family, const union in_addr_union *address) {
+ assert(a);
+ assert(IN_SET(family, AF_INET, AF_INET6));
+ assert(address);
- assert(manager);
+ if (a->family != family)
+ return false;
+ if (!address_is_ready(a))
+ return false;
+ if (FLAGS_SET(a->flags, IFA_F_NOPREFIXROUTE))
+ return false;
+ if (in_addr_is_set(a->family, &a->in_addr_peer))
+ return false;
+
+ return in_addr_prefix_intersect(
+ family,
+ &a->in_addr,
+ a->prefixlen,
+ address,
+ FAMILY_ADDRESS_SIZE(family) * 8) > 0;
+}
+
+static bool link_address_is_reachable(Link *link, int family, const union in_addr_union *address) {
+ Route *route;
+
+ assert(link);
+ assert(link->manager);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
- HASHMAP_FOREACH(link, manager->links_by_index) {
- Route *route;
- SET_FOREACH(route, link->routes)
- if (route_address_is_reachable(route, family, address))
+ SET_FOREACH(route, link->routes)
+ if (route_address_is_reachable(route, family, address))
+ return true;
+ SET_FOREACH(route, link->routes_foreign)
+ if (route_address_is_reachable(route, family, address))
+ return true;
+
+ /* If we do not manage foreign routes, then there may exist a prefix route we do not know,
+ * which was created on configuring an address. Hence, also check the addresses. */
+ if (!link->manager->manage_foreign_routes) {
+ Address *a;
+
+ SET_FOREACH(a, link->addresses)
+ if (prefix_route_address_is_reachable(a, family, address))
return true;
- SET_FOREACH(route, link->routes_foreign)
- if (route_address_is_reachable(route, family, address))
+ SET_FOREACH(a, link->addresses_foreign)
+ if (prefix_route_address_is_reachable(a, family, address))
return true;
}
return 0;
}
+bool gateway_is_ready(Link *link, int onlink, int family, const union in_addr_union *gw) {
+ assert(link);
+ assert(gw);
+
+ if (onlink > 0)
+ return true;
+
+ if (!in_addr_is_set(family, gw))
+ return true;
+
+ if (family == AF_INET6 && in6_addr_is_link_local(&gw->in6))
+ return true;
+
+ return link_address_is_reachable(link, family, gw);
+}
+
static int route_is_ready_to_configure(const Route *route, Link *link) {
MultipathRoute *m;
NextHop *nh = NULL;
return r;
}
- if (route->gateway_onlink <= 0 &&
- in_addr_is_set(route->gw_family, &route->gw) > 0 &&
- !manager_address_is_reachable(link->manager, route->gw_family, &route->gw))
+ if (!gateway_is_ready(link, route->gateway_onlink, route->gw_family, &route->gw))
return false;
ORDERED_SET_FOREACH(m, route->multipath_routes) {
union in_addr_union a = m->gateway.address;
Link *l = NULL;
- if (route->gateway_onlink <= 0 &&
- !manager_address_is_reachable(link->manager, m->gateway.family, &a))
- return false;
-
if (m->ifname) {
if (link_get_by_name(link->manager, m->ifname, &l) < 0)
return false;
}
if (l && !link_is_ready_to_configure(l, true))
return false;
+
+ if (!gateway_is_ready(l ?: link, route->gateway_onlink, m->gateway.family, &a))
+ return false;
}
return true;
int route_remove(const Route *route, Manager *manager, Link *link);
int link_has_route(Link *link, const Route *route);
-bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address);
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret);
+bool gateway_is_ready(Link *link, int onlink, int family, const union in_addr_union *gw);
int link_drop_routes(Link *link);
int link_drop_foreign_routes(Link *link);
siphash24_compress(&rule->type, sizeof(rule->type), state);
siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
- siphash24_compress(&rule->priority, sizeof(rule->priority), state);
+ siphash24_compress_boolean(rule->priority_set, state);
+ if (rule->priority_set)
+ siphash24_compress(&rule->priority, sizeof(rule->priority), state);
siphash24_compress(&rule->table, sizeof(rule->table), state);
siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state);
if (r != 0)
return r;
- r = CMP(a->priority, b->priority);
+ r = CMP(a->priority_set, b->priority_set);
if (r != 0)
return r;
+ if (a->priority_set) {
+ r = CMP(a->priority, b->priority);
+ if (r != 0)
+ return r;
+ }
+
r = CMP(a->table, b->table);
if (r != 0)
return r;
routing_policy_rule_compare_func,
routing_policy_rule_free);
-static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
+static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *rule, bool require_priority, RoutingPolicyRule **ret) {
RoutingPolicyRule *existing;
+ int r;
assert(m);
return 0;
}
+ if (!require_priority && rule->priority_set) {
+ _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
+
+ r = routing_policy_rule_dup(rule, &tmp);
+ if (r < 0)
+ return r;
+
+ tmp->priority_set = false;
+
+ existing = set_get(m->rules, tmp);
+ if (existing) {
+ if (ret)
+ *ret = existing;
+ return 1;
+ }
+ }
+
return -ENOENT;
}
if (r < 0)
return r;
- r = routing_policy_rule_get(m, rule, &existing);
+ r = routing_policy_rule_get(m, rule, true, &existing);
if (r == -ENOENT) {
/* Rule does not exist, use a new one. */
r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
return 1;
}
+static int routing_policy_rule_update_priority(RoutingPolicyRule *rule, uint32_t priority) {
+ int r;
+
+ assert(rule);
+ assert(rule->manager);
+
+ if (rule->priority_set)
+ return 0;
+
+ if (!set_remove(rule->manager->rules, rule))
+ return -ENOENT;
+
+ rule->priority = priority;
+ rule->priority_set = true;
+
+ r = set_put(rule->manager->rules, rule);
+ if (r <= 0) {
+ /* Undo */
+ rule->priority_set = false;
+ assert_se(set_put(rule->manager->rules, rule) > 0);
+ return r == 0 ? -EEXIST : r;
+ }
+
+ return 1;
+}
+
static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, const char *str, const Link *link, const Manager *m) {
_cleanup_free_ char *from = NULL, *to = NULL, *table = NULL;
return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
}
- r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
+ if (rule->priority_set) {
+ r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
+ }
if (rule->tos > 0) {
r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
continue;
}
+ if (!foreign) {
+ _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
+
+ /* The rule may be configured without priority. Try to find without priority. */
+
+ k = routing_policy_rule_dup(rule, &tmp);
+ if (k < 0) {
+ if (r >= 0)
+ r = k;
+ continue;
+ }
+
+ tmp->priority_set = false;
+
+ k = links_have_routing_policy_rule(m, tmp, except);
+ if (k != 0) {
+ if (k < 0 && r >= 0)
+ r = k;
+ continue;
+ }
+ }
+
k = routing_policy_rule_remove(rule, m);
if (k < 0 && r >= 0)
r = k;
}
static const RoutingPolicyRule kernel_rules[] = {
- { .family = AF_INET, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
- { .family = AF_INET, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
- { .family = AF_INET, .priority = 32767, .table = RT_TABLE_DEFAULT, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
- { .family = AF_INET6, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
- { .family = AF_INET6, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
+ { .family = AF_INET, .priority_set = true, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
+ { .family = AF_INET, .priority_set = true, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
+ { .family = AF_INET, .priority_set = true, .priority = 32767, .table = RT_TABLE_DEFAULT, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
+ { .family = AF_INET6, .priority_set = true, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
+ { .family = AF_INET6, .priority_set = true, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
};
static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *rule) {
log_warning_errno(r, "rtnl: could not get FRA_PRIORITY attribute, ignoring: %m");
return 0;
}
+ /* The kernel does not send priority if priority is zero. So, the flag below must be always set
+ * even if the message does not contain FRA_PRIORITY. */
+ tmp->priority_set = true;
r = sd_netlink_message_read_u32(message, FRA_TABLE, &tmp->table);
if (r < 0 && r != -ENODATA) {
* protocol of the received rule is RTPROT_KERNEL or RTPROT_STATIC. */
tmp->protocol = routing_policy_rule_is_created_by_kernel(tmp) ? RTPROT_KERNEL : RTPROT_STATIC;
- (void) routing_policy_rule_get(m, tmp, &rule);
+ (void) routing_policy_rule_get(m, tmp, false, &rule);
switch (type) {
case RTM_NEWRULE:
- if (rule)
+ if (rule) {
log_routing_policy_rule_debug(tmp, "Received remembered", NULL, m);
- else if (!m->manage_foreign_routes)
+ r = routing_policy_rule_update_priority(rule, tmp->priority);
+ if (r < 0)
+ log_warning_errno(r, "Failed to update priority of remembered routing policy rule, ignoring: %m");
+ } else if (!m->manage_foreign_routes)
log_routing_policy_rule_debug(tmp, "Ignoring received foreign", NULL, m);
else {
log_routing_policy_rule_debug(tmp, "Remembering foreign", NULL, m);
if (r < 0)
return log_oom();
+ if (isempty(rvalue)) {
+ n->priority = 0;
+ n->priority_set = false;
+ TAKE_PTR(n);
+ return 0;
+ }
+
r = safe_atou32(rvalue, &n->priority);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
return 0;
}
+ n->priority_set = true;
TAKE_PTR(n);
return 0;
NetworkConfigSection *section;
bool invert_rule;
+ bool priority_set;
uint8_t tos;
uint8_t type;
log_link_debug(link, "Setting %s", set_link_operation_to_string(op));
- if (IN_SET(op, SET_LINK_BOND, SET_LINK_CAN)) {
+ if (op == SET_LINK_BOND) {
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->master_ifindex);
if (r < 0)
return log_link_debug_errno(link, r, "Could not allocate RTM_NEWLINK message: %m");
+ } else if (op == SET_LINK_CAN) {
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->ifindex);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not allocate RTM_NEWLINK message: %m");
} else {
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
if (s->possible_feature_level > level) {
s->possible_feature_level = level;
dns_server_reset_counters(s);
+ log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", strna(dns_server_string_full(s)));
}
-
- log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", strna(dns_server_string_full(s)));
}
void dns_server_packet_invalid(DnsServer *s, DnsServerFeatureLevel level) {
DNS_PACKET_RD(q->request_packet),
!!q->request_packet->opt,
edns0_do,
- DNS_PACKET_AD(q->request_packet) && dns_query_fully_authenticated(q),
+ (DNS_PACKET_AD(q->request_packet) || DNS_PACKET_DO(q->request_packet)) && dns_query_fully_authenticated(q),
DNS_PACKET_CD(q->request_packet),
q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
dns_packet_has_nsid_request(q->request_packet) > 0 && !q->stub_listener_extra);
DNS_PACKET_RD(p),
!!p->opt,
DNS_PACKET_DO(p),
- DNS_PACKET_AD(p) && authenticated,
+ (DNS_PACKET_AD(p) || DNS_PACKET_DO(p)) && authenticated,
DNS_PACKET_CD(p),
l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
dns_packet_has_nsid_request(p) > 0 && !l);
break;
}
- /* Reduce this feature level by one and try again. */
- switch (t->current_feature_level) {
- case DNS_SERVER_FEATURE_LEVEL_TLS_DO:
- t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN;
- break;
- case DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN + 1:
- /* Skip plain TLS when TLS is not supported */
- t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN - 1;
- break;
- default:
- t->clamp_feature_level_servfail = t->current_feature_level - 1;
- }
+ /* SERVFAIL can happen for many reasons and may be transient.
+ * To avoid unnecessary downgrades retry once with the initial level.
+ * Check for clamp_feature_level_servfail having an invalid value as a sign that this is the
+ * first attempt to downgrade. If so, clamp to the current value so that the transaction
+ * is retried without actually downgrading. If the next try also fails we will downgrade by
+ * hitting the else branch below. */
+ if (DNS_PACKET_RCODE(p) == DNS_RCODE_SERVFAIL &&
+ t->clamp_feature_level_servfail < 0) {
+ t->clamp_feature_level_servfail = t->current_feature_level;
+ log_debug("Server returned error %s, retrying transaction.",
+ dns_rcode_to_string(DNS_PACKET_RCODE(p)));
+ } else {
+ /* Reduce this feature level by one and try again. */
+ switch (t->current_feature_level) {
+ case DNS_SERVER_FEATURE_LEVEL_TLS_DO:
+ t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN;
+ break;
+ case DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN + 1:
+ /* Skip plain TLS when TLS is not supported */
+ t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN - 1;
+ break;
+ default:
+ t->clamp_feature_level_servfail = t->current_feature_level - 1;
+ }
- log_debug("Server returned error %s, retrying transaction with reduced feature level %s.",
- dns_rcode_to_string(DNS_PACKET_RCODE(p)),
- dns_server_feature_level_to_string(t->clamp_feature_level_servfail));
+ log_debug("Server returned error %s, retrying transaction with reduced feature level %s.",
+ dns_rcode_to_string(DNS_PACKET_RCODE(p)),
+ dns_server_feature_level_to_string(t->clamp_feature_level_servfail));
+ }
dns_transaction_retry(t, false /* use the same server */);
return;
}
/* Get directory creation time (not available everywhere, but that's OK */
- (void) fd_getcrtime(dfd, &crtime);
+ (void) fd_getcrtime(fd, &crtime);
/* If the IMMUTABLE bit is set, we consider the directory read-only. Since the ioctl is not
* supported everywhere we ignore failures. */
#include "util.h"
static int sethostname_idempotent_full(const char *s, bool really) {
- char buf[HOST_NAME_MAX + 1] = {};
+ char buf[HOST_NAME_MAX + 1];
assert(s);
- if (gethostname(buf, sizeof(buf) - 1) < 0)
+ if (gethostname(buf, sizeof(buf)) < 0)
return -errno;
if (streq(buf, s))
}
bool get_hostname_filtered(char ret[static HOST_NAME_MAX + 1]) {
- char buf[HOST_NAME_MAX + 1] = {};
+ char buf[HOST_NAME_MAX + 1];
/* Returns true if we got a good hostname, false otherwise. */
- if (gethostname(buf, sizeof(buf) - 1) < 0)
+ if (gethostname(buf, sizeof(buf)) < 0)
return false; /* This can realistically only fail with ENAMETOOLONG.
* Let's treat that case the same as an invalid hostname. */
}
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
+ _cleanup_(utxent_cleanup) bool utmpx = false;
struct utmpx lookup = {
.ut_type = INIT_PROCESS /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
}, store, store_wtmp, *found;
assert(id);
- setutxent();
+ utmpx = utxent_start();
/* 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);
bool (*match_tty)(const char *tty, void *userdata),
void *userdata) {
+ _cleanup_(utxent_cleanup) bool utmpx = false;
_cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
char date[FORMAT_TIMESTAMP_MAX];
struct utmpx *u;
message) < 0)
return -ENOMEM;
- setutxent();
+ utmpx = utxent_start();
r = 0;
printf("big_enum2_pos → %zu\n", sizeof(big_enum2_pos));
printf("big_enum2_neg → %zu\n", sizeof(big_enum2_neg));
+ printf("timeval: %zu\n", sizeof(struct timeval));
+ printf("timespec: %zu\n", sizeof(struct timespec));
return 0;
}
.iov_base = &ntpmsg,
.iov_len = sizeof(ntpmsg),
};
- CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct timeval))) control;
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct timespec))) control;
union sockaddr_union server_addr;
struct msghdr msghdr = {
.msg_iov = &iov,
r = link_config_get(ctx, dev, &link);
if (r < 0) {
- if (r == -ENOENT)
- return log_device_debug_errno(dev, r, "No matching link configuration found.");
if (r == -ENODEV)
return log_device_debug_errno(dev, r, "Link vanished while searching for configuration for it.");
+ if (r == -ENOENT) {
+ log_device_debug_errno(dev, r, "No matching link configuration found, ignoring device.");
+ return 0;
+ }
return log_device_error_errno(dev, r, "Failed to get link config: %m");
}
[ "$ARCH" ] || ARCH=$(uname -m)
case $ARCH in
ppc64*)
- KERNEL_BIN="/boot/vmlinux-$KERNEL_VER"
- CONSOLE=hvc0
- ;;
+ # Ubuntu ppc64* calls the kernel binary as vmlinux-*, RHEL/CentOS
+ # uses the "standard" vmlinuz- prefix
+ [[ -e "/boot/vmlinux-$KERNEL_VER" ]] && KERNEL_BIN="/boot/vmlinux-$KERNEL_VER" || KERNEL_BIN="/boot/vmlinuz-$KERNEL_VER"
+ CONSOLE=hvc0
+ ;;
*)
- KERNEL_BIN="/boot/vmlinuz-$KERNEL_VER"
- ;;
+ KERNEL_BIN="/boot/vmlinuz-$KERNEL_VER"
+ ;;
esac
fi
fi
Family=ipv6
Blackhole=yes
+[NextHop]
+Id=8
+Gateway=fe80::222:4dff:ff:ff:ff:ff
+
[NextHop]
Gateway=192.168.5.2
[Route]
Gateway=2001:1234:5:8fff:ff:ff:ff:ff
+[Route]
+Destination=2001:1234:5:afff:ff:ff:ff:ff/128
+Gateway=fe80::222:4dff:ff:ff:ff:ff
+
[Route]
Destination=149.10.124.64
Scope=link
--- /dev/null
+[Network]
+ManageForeignRoutes=no
network_unit_file_path='/run/systemd/network'
networkd_runtime_directory='/run/systemd/netif'
+networkd_conf_dropin_path='/run/systemd/networkd.conf.d'
networkd_ci_path='/run/networkd-ci'
network_sysctl_ipv6_path='/proc/sys/net/ipv6/conf'
network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf'
global running_units
os.makedirs(network_unit_file_path, exist_ok=True)
+ os.makedirs(networkd_conf_dropin_path, exist_ok=True)
os.makedirs(networkd_ci_path, exist_ok=True)
shutil.rmtree(networkd_ci_path)
if (os.path.exists(os.path.join(network_unit_file_path, unit + '.d'))):
shutil.rmtree(os.path.join(network_unit_file_path, unit + '.d'))
+def copy_networkd_conf_dropin(*dropins):
+ """Copy networkd.conf dropin files into the testbed."""
+ for dropin in dropins:
+ shutil.copy(os.path.join(networkd_ci_path, dropin), networkd_conf_dropin_path)
+
+def remove_networkd_conf_dropin(dropins):
+ """Remove previously copied networkd.conf dropin files from the testbed."""
+ for dropin in dropins:
+ if (os.path.exists(os.path.join(networkd_conf_dropin_path, dropin))):
+ os.remove(os.path.join(networkd_conf_dropin_path, dropin))
+
def start_dnsmasq(additional_options='', ipv4_range='192.168.5.10,192.168.5.200', ipv6_range='2600::10,2600::20', lease_time='1h'):
dnsmasq_command = f'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --port=0 ' + additional_options
check_output(dnsmasq_command)
'routing-policy-rule-reconfigure2.network',
]
+ networkd_conf_dropins = [
+ 'networkd-manage-foreign-routes-no.conf',
+ ]
+
routing_policy_rule_tables = ['7', '8', '9', '10', '1011']
routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
remove_routes(self.routes)
remove_links(self.links)
remove_unit_from_networkd_path(self.units)
+ remove_networkd_conf_dropin(self.networkd_conf_dropins)
stop_networkd(show_logs=True)
call('ip netns del ns99', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
self.assertRegex(output, 'lookup 7')
self.assertRegex(output, 'uidrange 100-200')
- def test_route_static(self):
+ def _test_route_static(self, manage_foreign_routes):
+ if not manage_foreign_routes:
+ copy_networkd_conf_dropin('networkd-manage-foreign-routes-no.conf')
+
copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
start_networkd()
self.wait_online(['dummy98:routable'])
print(output)
self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output)
self.assertIn('2001:1234:5:8f63::1 proto kernel', output)
+ self.assertIn('2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static', output)
print('### ip -6 route show default')
output = check_output('ip -6 route show default')
print(output)
self.assertEqual(output, '')
+ self.tearDown()
+
+ def test_route_static(self):
+ for manage_foreign_routes in [True, False]:
+ with self.subTest(manage_foreign_routes=manage_foreign_routes):
+ self._test_route_static(manage_foreign_routes)
+
@expectedFailureIfRTA_VIAIsNotSupported()
def test_route_via_ipv6(self):
copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev')
self.assertIn('id 3 dev veth99', output)
self.assertIn('id 4 dev veth99', output)
self.assertRegex(output, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
+ self.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output)
self.assertRegex(output, r'id [0-9]* via 192.168.5.2 dev veth99')
output = check_output('ip nexthop list dev dummy98')
output = check_output('ip rule list table 100')
print(output)
- self.assertIn('0: from all to 8.8.8.8 lookup 100', output)
+ self.assertIn('from all to 8.8.8.8 lookup 100', output)
class NetworkdLLDPTests(unittest.TestCase, Utilities):
links = ['veth99']