mirror of
https://github.com/systemd/systemd
synced 2025-09-28 16:24:45 +02:00
Compare commits
12 Commits
8dd294c5a9
...
3e405f28f4
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3e405f28f4 | ||
![]() |
87970ee5bc | ||
![]() |
8d0d1a309e | ||
![]() |
bb1a570018 | ||
![]() |
17547fb5cb | ||
![]() |
16a36b5616 | ||
![]() |
896e678bea | ||
![]() |
665ffc7fba | ||
![]() |
e676b4fc8b | ||
![]() |
a853652ae9 | ||
![]() |
2236d75df9 | ||
![]() |
61135582e0 |
@ -52,4 +52,13 @@
|
||||
Before each file, the filename is printed as a comment.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='json'>
|
||||
<term><option>--json=</option><replaceable>MODE</replaceable></term>
|
||||
|
||||
<listitem><para>Shows output formatted as JSON. Expects one of <literal>short</literal> (for the
|
||||
shortest possible output without any redundant whitespace or line breaks), <literal>pretty</literal>
|
||||
(for a pretty version of the same, with indentation and line breaks) or <literal>off</literal> (to turn
|
||||
off JSON output, the default).</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
@ -162,15 +162,6 @@
|
||||
operation begins.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--json=</option><replaceable>MODE</replaceable></term>
|
||||
|
||||
<listitem><para>Shows output formatted as JSON. Expects one of <literal>short</literal> (for the
|
||||
shortest possible output without any redundant whitespace or line breaks), <literal>pretty</literal>
|
||||
(for a pretty version of the same, with indentation and line breaks) or <literal>off</literal> (to turn
|
||||
off json output).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
@ -237,6 +228,9 @@
|
||||
url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification</ulink>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-legend" />
|
||||
<xi:include href="standard-options.xml" xpointer="json" />
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
|
@ -278,15 +278,6 @@
|
||||
and graphic illustrating the changes applied.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--json=</option><replaceable>MODE</replaceable></term>
|
||||
|
||||
<listitem><para>Shows output formatted as JSON. Expects one of <literal>short</literal> (for the
|
||||
shortest possible output without any redundant whitespace or line breaks), <literal>pretty</literal>
|
||||
(for a pretty version of the same, with indentation and line breaks) or <literal>off</literal> (to turn
|
||||
off json output).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--definitions=</option></term>
|
||||
|
||||
@ -321,6 +312,9 @@
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-legend" />
|
||||
<xi:include href="standard-options.xml" xpointer="json" />
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -211,14 +211,6 @@
|
||||
<filename>/opt/</filename> hierarchies, but below some specified root directory.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--json=</option></term>
|
||||
|
||||
<listitem><para>Generate JSON output, instead of human readable tabular output. Takes one of
|
||||
<literal>short</literal>, <literal>pretty</literal> or <literal>off</literal> in order to control the
|
||||
output style, or explicitly disabling JSON output.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--force</option></term>
|
||||
|
||||
@ -229,6 +221,8 @@
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-legend" />
|
||||
<xi:include href="standard-options.xml" xpointer="json" />
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -249,6 +249,36 @@
|
||||
if <literal>RequiredForOnline=no</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>ActivationPolicy=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the policy for <command>systemd-networkd</command> managing the link
|
||||
administrative state. Specifically, this controls how <command>systemd-networkd</command>
|
||||
changes the network device's <literal>IFF_UP</literal> flag, which is sometimes
|
||||
controlled by system administrators by running e.g., <command>ip set dev eth0 up</command>
|
||||
or <command>ip set dev eth0 down</command>, and can also be changed with
|
||||
<command>networkctl up eth0</command> or <command>networkctl down eth0</command>.</para>
|
||||
|
||||
<para>Takes one of <literal>up</literal>, <literal>always-up</literal>,
|
||||
<literal>manual</literal>, <literal>always-down</literal>, <literal>down</literal>,
|
||||
or <literal>bound</literal>. When <literal>manual</literal>, <command>systemd-networkd</command>
|
||||
will not change the link's admin state automatically; the system administrator must bring the
|
||||
interface up or down manually, as desired. When <literal>up</literal> (the default) or
|
||||
<literal>always-up</literal>, or <literal>down</literal> or <literal>always-down</literal>,
|
||||
<command>systemd-networkd</command> will set the link up or down, respectively,
|
||||
when the interface is (re)configured. When <literal>always-up</literal> or
|
||||
<literal>always-down</literal>, <command>systemd-networkd</command> will set the link up
|
||||
or down, respectively, any time <command>systemd-networkd</command> detects a change in
|
||||
the administrative state. When <varname>BindCarrier=</varname> is also set, this is
|
||||
automatically set to <literal>bound</literal> and any other value is ignored.</para>
|
||||
|
||||
<para>The administrative state is not the same as the carrier state, so using
|
||||
<literal>always-up</literal> does not mean the link will never lose carrier. The link
|
||||
carrier depends on both the administrative state as well as the network device's physical
|
||||
connection. However, to avoid reconfiguration failures, when using <literal>always-up</literal>,
|
||||
<varname>IgnoreCarrierLoss=</varname> is forced to true.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
@ -592,8 +622,9 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
|
||||
<listitem>
|
||||
<para>A link name or a list of link names. When set, controls the behavior of the current
|
||||
link. When all links in the list are in an operational down state, the current link is brought
|
||||
down. When at least one link has carrier, the current interface is brought up.
|
||||
</para>
|
||||
down. When at least one link has carrier, the current interface is brought up.</para>
|
||||
|
||||
<para>This forces <varname>ActivationPolicy=</varname> to be set to <literal>bound</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -966,6 +997,10 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
|
||||
of the interface even if its carrier is lost. When unset, the value specified with
|
||||
<option>ConfigureWithoutCarrier=</option> is used.
|
||||
</para>
|
||||
|
||||
<para>When <varname>ActivationPolicy=</varname> is set to <literal>always-up</literal>, this
|
||||
is forced to <literal>true</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
@ -239,8 +239,6 @@ static int list_bus_names(int argc, char **argv, void *userdata) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set columns to display: %m");
|
||||
|
||||
table_set_header(table, arg_legend);
|
||||
|
||||
HASHMAP_FOREACH_KEY(v, k, names) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
|
||||
@ -357,14 +355,7 @@ static int list_bus_names(int argc, char **argv, void *userdata) {
|
||||
return log_error_errno(r, "Failed to fill line: %m");
|
||||
}
|
||||
|
||||
if (arg_json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
|
||||
(void) pager_open(arg_pager_flags);
|
||||
|
||||
r = table_print_json(table, NULL, arg_json_format_flags);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
|
||||
return 0;
|
||||
return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
|
||||
}
|
||||
|
||||
static void print_subtree(const char *prefix, const char *path, char **l) {
|
||||
@ -2255,6 +2246,8 @@ static int help(void) {
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
(void) pager_open(arg_pager_flags);
|
||||
|
||||
printf("%s [OPTIONS...] COMMAND ...\n\n"
|
||||
"%sIntrospect the D-Bus IPC bus.%s\n"
|
||||
"\nCommands:\n"
|
||||
|
@ -46,6 +46,8 @@ static const char *arg_target = NULL;
|
||||
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK;
|
||||
static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
|
||||
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||
static PagerFlags arg_pager_flags = 0;
|
||||
static bool arg_legend = true;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_verity_settings, verity_settings_done);
|
||||
|
||||
@ -63,6 +65,8 @@ static int help(void) {
|
||||
"%1$s [OPTIONS...] --copy-to IMAGE [SOURCE] PATH\n\n"
|
||||
"%5$sDissect a file system OS image.%6$s\n\n"
|
||||
"%3$sOptions:%4$s\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --no-legend Do not show the headers and footers\n"
|
||||
" -r --read-only Mount read-only\n"
|
||||
" --fsck=BOOL Run fsck before mounting\n"
|
||||
" --mkdir Make mount directory before mounting, if missing\n"
|
||||
@ -96,6 +100,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_NO_PAGER,
|
||||
ARG_NO_LEGEND,
|
||||
ARG_DISCARD,
|
||||
ARG_FSCK,
|
||||
ARG_ROOT_HASH,
|
||||
@ -108,6 +114,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
|
||||
{ "mount", no_argument, NULL, 'm' },
|
||||
{ "read-only", no_argument, NULL, 'r' },
|
||||
{ "discard", required_argument, NULL, ARG_DISCARD },
|
||||
@ -137,6 +145,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_NO_PAGER:
|
||||
arg_pager_flags |= PAGER_DISABLE;
|
||||
break;
|
||||
|
||||
case ARG_NO_LEGEND:
|
||||
arg_legend = false;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
arg_action = ACTION_MOUNT;
|
||||
break;
|
||||
@ -339,6 +355,9 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
|
||||
assert(m);
|
||||
assert(d);
|
||||
|
||||
if (arg_json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
|
||||
(void) pager_open(arg_pager_flags);
|
||||
|
||||
if (arg_json_format_flags & JSON_FORMAT_OFF)
|
||||
printf(" Name: %s\n", basename(arg_image));
|
||||
|
||||
@ -482,7 +501,9 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
|
||||
}
|
||||
|
||||
if (arg_json_format_flags & JSON_FORMAT_OFF) {
|
||||
r = table_print(t, stdout);
|
||||
(void) table_set_header(t, arg_legend);
|
||||
|
||||
r = table_print(t, NULL);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
} else {
|
||||
|
@ -113,8 +113,6 @@ static int list_homes(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
int r;
|
||||
|
||||
(void) pager_open(arg_pager_flags);
|
||||
|
||||
r = acquire_bus(&bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -175,11 +173,9 @@ static int list_homes(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return table_log_sort_error(r);
|
||||
|
||||
table_set_header(table, arg_legend);
|
||||
|
||||
r = table_print_json(table, stdout, arg_json_format_flags);
|
||||
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (arg_legend && (arg_json_format_flags & JSON_FORMAT_OFF)) {
|
||||
|
@ -212,6 +212,27 @@ _public_ int sd_network_link_get_required_operstate_for_online(int ifindex, char
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_activation_policy(int ifindex, char **policy) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(policy, -EINVAL);
|
||||
|
||||
r = network_link_get_string(ifindex, "ACTIVATION_POLICY", &s);
|
||||
if (r < 0) {
|
||||
if (r != -ENODATA)
|
||||
return r;
|
||||
|
||||
/* For compatibility, assuming up. */
|
||||
s = strdup("up");
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*policy = TAKE_PTR(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
|
||||
return network_link_get_string(ifindex, "LLMNR", llmnr);
|
||||
}
|
||||
|
@ -1387,7 +1387,7 @@ static int link_status_one(
|
||||
|
||||
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL;
|
||||
_cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL,
|
||||
*setup_state = NULL, *operational_state = NULL, *lease_file = NULL;
|
||||
*setup_state = NULL, *operational_state = NULL, *lease_file = NULL, *activation_policy = NULL;
|
||||
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL,
|
||||
*on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup;
|
||||
_cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
|
||||
@ -2062,6 +2062,16 @@ static int link_status_one(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_network_link_get_activation_policy(info->ifindex, &activation_policy);
|
||||
if (r >= 0) {
|
||||
r = table_add_many(table,
|
||||
TABLE_EMPTY,
|
||||
TABLE_STRING, "Activation Policy:",
|
||||
TABLE_STRING, activation_policy);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
if (lease) {
|
||||
const void *client_id;
|
||||
size_t client_id_len;
|
||||
|
@ -1831,17 +1831,38 @@ static int link_joined(Link *link) {
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
if (!hashmap_isempty(link->bound_to_links)) {
|
||||
switch (link->network->activation_policy) {
|
||||
case ACTIVATION_POLICY_BOUND:
|
||||
r = link_handle_bound_to_list(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (!(link->flags & IFF_UP)) {
|
||||
break;
|
||||
case ACTIVATION_POLICY_UP:
|
||||
if (link->activated)
|
||||
break;
|
||||
_fallthrough_;
|
||||
case ACTIVATION_POLICY_ALWAYS_UP:
|
||||
r = link_up(link);
|
||||
if (r < 0) {
|
||||
link_enter_failed(link);
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
case ACTIVATION_POLICY_DOWN:
|
||||
if (link->activated)
|
||||
break;
|
||||
_fallthrough_;
|
||||
case ACTIVATION_POLICY_ALWAYS_DOWN:
|
||||
r = link_down(link, NULL);
|
||||
if (r < 0) {
|
||||
link_enter_failed(link);
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
link->activated = true;
|
||||
|
||||
if (link->network->bridge) {
|
||||
r = link_set_bridge(link);
|
||||
@ -2254,6 +2275,7 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for
|
||||
return r;
|
||||
|
||||
link_set_state(link, LINK_STATE_INITIALIZED);
|
||||
link->activated = false;
|
||||
link_dirty(link);
|
||||
|
||||
/* link_configure_duid() returns 0 if it requests product UUID. In that case,
|
||||
@ -2658,6 +2680,16 @@ int link_carrier_reset(Link *link) {
|
||||
static int link_admin_state_up(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link->network)
|
||||
return 0;
|
||||
|
||||
if (link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN) {
|
||||
log_link_info(link, "ActivationPolicy is \"always-off\", forcing link down");
|
||||
return link_down(link, NULL);
|
||||
}
|
||||
|
||||
/* We set the ipv6 mtu after the device mtu, but the kernel resets
|
||||
* ipv6 mtu on NETDEV_UP, so we need to reset it. The check for
|
||||
* ipv6_mtu_set prevents this from trying to set it too early before
|
||||
@ -2672,6 +2704,21 @@ static int link_admin_state_up(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_admin_state_down(Link *link) {
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link->network)
|
||||
return 0;
|
||||
|
||||
if (link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
|
||||
log_link_info(link, "ActivationPolicy is \"always-on\", forcing link up");
|
||||
return link_up(link);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_update(Link *link, sd_netlink_message *m) {
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
hw_addr_data hw_addr;
|
||||
@ -2784,9 +2831,14 @@ int link_update(Link *link, sd_netlink_message *m) {
|
||||
r = link_admin_state_up(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (link_was_admin_up && !(link->flags & IFF_UP))
|
||||
} else if (link_was_admin_up && !(link->flags & IFF_UP)) {
|
||||
log_link_info(link, "Link DOWN");
|
||||
|
||||
r = link_admin_state_down(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = link_update_lldp(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -2959,6 +3011,9 @@ int link_save(Link *link) {
|
||||
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
|
||||
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
|
||||
|
||||
fprintf(f, "ACTIVATION_POLICY=%s\n",
|
||||
activation_policy_to_string(link->network->activation_policy));
|
||||
|
||||
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
|
||||
|
||||
/************************************************************/
|
||||
|
@ -129,6 +129,7 @@ typedef struct Link {
|
||||
bool setting_genmode:1;
|
||||
bool ipv6_mtu_set:1;
|
||||
bool bridge_mdb_configured:1;
|
||||
bool activated:1;
|
||||
|
||||
sd_dhcp_server *dhcp_server;
|
||||
|
||||
|
@ -66,6 +66,7 @@ Link.Multicast, config_parse_tristate,
|
||||
Link.AllMulticast, config_parse_tristate, 0, offsetof(Network, allmulticast)
|
||||
Link.Promiscuous, config_parse_tristate, 0, offsetof(Network, promiscuous)
|
||||
Link.Unmanaged, config_parse_bool, 0, offsetof(Network, unmanaged)
|
||||
Link.ActivationPolicy, config_parse_activation_policy, 0, offsetof(Network, activation_policy)
|
||||
Link.RequiredForOnline, config_parse_required_for_online, 0, 0
|
||||
SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, 0
|
||||
SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, 0
|
||||
|
@ -225,9 +225,6 @@ int network_verify(Network *network) {
|
||||
if (network->dhcp_use_gateway < 0)
|
||||
network->dhcp_use_gateway = network->dhcp_use_routes;
|
||||
|
||||
if (network->ignore_carrier_loss < 0)
|
||||
network->ignore_carrier_loss = network->configure_without_carrier;
|
||||
|
||||
if (network->dhcp_critical >= 0) {
|
||||
if (network->keep_configuration >= 0)
|
||||
log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
|
||||
@ -239,6 +236,30 @@ int network_verify(Network *network) {
|
||||
network->keep_configuration = KEEP_CONFIGURATION_NO;
|
||||
}
|
||||
|
||||
if (!strv_isempty(network->bind_carrier)) {
|
||||
if (!IN_SET(network->activation_policy, _ACTIVATION_POLICY_INVALID, ACTIVATION_POLICY_BOUND))
|
||||
log_warning("%s: ActivationPolicy=bound is required with BindCarrier=. "
|
||||
"Setting ActivationPolicy=bound.", network->filename);
|
||||
network->activation_policy = ACTIVATION_POLICY_BOUND;
|
||||
} else if (network->activation_policy == ACTIVATION_POLICY_BOUND) {
|
||||
log_warning("%s: ActivationPolicy=bound requires BindCarrier=. "
|
||||
"Ignoring ActivationPolicy=bound.", network->filename);
|
||||
network->activation_policy = ACTIVATION_POLICY_UP;
|
||||
}
|
||||
|
||||
if (network->activation_policy == _ACTIVATION_POLICY_INVALID)
|
||||
network->activation_policy = ACTIVATION_POLICY_UP;
|
||||
|
||||
if (network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
|
||||
if (network->ignore_carrier_loss == false)
|
||||
log_warning("%s: IgnoreCarrierLoss=false conflicts with ActivationPolicy=always-up. "
|
||||
"Setting IgnoreCarrierLoss=true.", network->filename);
|
||||
network->ignore_carrier_loss = true;
|
||||
}
|
||||
|
||||
if (network->ignore_carrier_loss < 0)
|
||||
network->ignore_carrier_loss = network->configure_without_carrier;
|
||||
|
||||
if (network->keep_configuration < 0)
|
||||
network->keep_configuration = KEEP_CONFIGURATION_NO;
|
||||
|
||||
@ -316,6 +337,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
|
||||
.required_for_online = true,
|
||||
.required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
|
||||
.activation_policy = _ACTIVATION_POLICY_INVALID,
|
||||
.arp = -1,
|
||||
.multicast = -1,
|
||||
.allmulticast = -1,
|
||||
@ -1247,3 +1269,15 @@ static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_link_local_address_gen_mode, ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode, "Failed to parse IPv6 link local address generation mode");
|
||||
|
||||
static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
|
||||
[ACTIVATION_POLICY_UP] = "up",
|
||||
[ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
|
||||
[ACTIVATION_POLICY_MANUAL] = "manual",
|
||||
[ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
|
||||
[ACTIVATION_POLICY_DOWN] = "down",
|
||||
[ACTIVATION_POLICY_BOUND] = "bound",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");
|
||||
|
@ -47,6 +47,17 @@ typedef enum IPv6LinkLocalAddressGenMode {
|
||||
_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID = -1
|
||||
} IPv6LinkLocalAddressGenMode;
|
||||
|
||||
typedef enum ActivationPolicy {
|
||||
ACTIVATION_POLICY_UP,
|
||||
ACTIVATION_POLICY_ALWAYS_UP,
|
||||
ACTIVATION_POLICY_MANUAL,
|
||||
ACTIVATION_POLICY_ALWAYS_DOWN,
|
||||
ACTIVATION_POLICY_DOWN,
|
||||
ACTIVATION_POLICY_BOUND,
|
||||
_ACTIVATION_POLICY_MAX,
|
||||
_ACTIVATION_POLICY_INVALID = -1
|
||||
} ActivationPolicy;
|
||||
|
||||
typedef struct Manager Manager;
|
||||
|
||||
typedef struct NetworkDHCPServerEmitAddress {
|
||||
@ -93,6 +104,7 @@ struct Network {
|
||||
bool unmanaged;
|
||||
bool required_for_online; /* Is this network required to be considered online? */
|
||||
LinkOperationalStateRange required_operstate_for_online;
|
||||
ActivationPolicy activation_policy;
|
||||
|
||||
/* misc settings */
|
||||
bool configure_without_carrier;
|
||||
@ -334,6 +346,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_required_for_online);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_keep_configuration);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_rx_tx_queues);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_activation_policy);
|
||||
|
||||
const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||
|
||||
@ -342,3 +355,6 @@ KeepConfiguration keep_configuration_from_string(const char *s) _pure_;
|
||||
|
||||
const char* ipv6_link_local_address_gen_mode_to_string(IPv6LinkLocalAddressGenMode s) _const_;
|
||||
IPv6LinkLocalAddressGenMode ipv6_link_local_address_gen_mode_from_string(const char *s) _pure_;
|
||||
|
||||
const char* activation_policy_to_string(ActivationPolicy i) _const_;
|
||||
ActivationPolicy activation_policy_from_string(const char *s) _pure_;
|
||||
|
@ -107,6 +107,8 @@ static int arg_pretty = -1;
|
||||
static uint64_t arg_size = UINT64_MAX;
|
||||
static bool arg_size_auto = false;
|
||||
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||
static PagerFlags arg_pager_flags = 0;
|
||||
static bool arg_legend = true;
|
||||
static void *arg_key = NULL;
|
||||
static size_t arg_key_size = 0;
|
||||
static char *arg_tpm2_device = NULL;
|
||||
@ -1918,11 +1920,7 @@ static int context_dump_partitions(Context *context, const char *node) {
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
r = table_print_json(t, stdout, arg_json_format_flags);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
|
||||
return 0;
|
||||
return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
|
||||
}
|
||||
|
||||
static void context_bar_char_process_partition(
|
||||
@ -3479,6 +3477,8 @@ static int help(void) {
|
||||
"\n%sGrow and add partitions to partition table.%s\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --no-legend Do not show the headers and footers\n"
|
||||
" --dry-run=BOOL Whether to run dry-run operation\n"
|
||||
" --empty=MODE One of refuse, allow, require, force, create; controls\n"
|
||||
" how to handle empty disks lacking partition tables\n"
|
||||
@ -3510,6 +3510,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_NO_PAGER,
|
||||
ARG_NO_LEGEND,
|
||||
ARG_DRY_RUN,
|
||||
ARG_EMPTY,
|
||||
ARG_DISCARD,
|
||||
@ -3529,6 +3531,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
|
||||
{ "dry-run", required_argument, NULL, ARG_DRY_RUN },
|
||||
{ "empty", required_argument, NULL, ARG_EMPTY },
|
||||
{ "discard", required_argument, NULL, ARG_DISCARD },
|
||||
@ -3561,6 +3565,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_NO_PAGER:
|
||||
arg_pager_flags |= PAGER_DISABLE;
|
||||
break;
|
||||
|
||||
case ARG_NO_LEGEND:
|
||||
arg_legend = false;
|
||||
break;
|
||||
|
||||
case ARG_DRY_RUN:
|
||||
r = parse_boolean(optarg);
|
||||
if (r < 0)
|
||||
|
@ -2550,3 +2550,30 @@ int table_print_json(Table *t, FILE *f, JsonFormatFlags flags) {
|
||||
|
||||
return fflush_and_check(f);
|
||||
}
|
||||
|
||||
int table_print_with_pager(
|
||||
Table *t,
|
||||
JsonFormatFlags json_format_flags,
|
||||
PagerFlags pager_flags,
|
||||
bool show_header) {
|
||||
|
||||
bool saved_header;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
|
||||
/* A all-in-one solution for showing tables, and turning on a pager first. Also optionally suppresses
|
||||
* the table header and logs about any error. */
|
||||
|
||||
if (json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
|
||||
(void) pager_open(pager_flags);
|
||||
|
||||
saved_header = t->header;
|
||||
t->header = show_header;
|
||||
r = table_print_json(t, stdout, json_format_flags);
|
||||
t->header = saved_header;
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "json.h"
|
||||
#include "macro.h"
|
||||
#include "pager.h"
|
||||
|
||||
typedef enum TableDataType {
|
||||
TABLE_EMPTY,
|
||||
@ -129,6 +130,8 @@ const void *table_get_at(Table *t, size_t row, size_t column);
|
||||
int table_to_json(Table *t, JsonVariant **ret);
|
||||
int table_print_json(Table *t, FILE *f, JsonFormatFlags json_flags);
|
||||
|
||||
int table_print_with_pager(Table *t, JsonFormatFlags json_format_flags, PagerFlags pager_flags, bool show_header);
|
||||
|
||||
#define table_log_add_error(r) \
|
||||
log_error_errno(r, "Failed to add cell(s) to table: %m")
|
||||
|
||||
|
@ -35,6 +35,7 @@ static char **arg_hierarchies = NULL; /* "/usr" + "/opt" by default */
|
||||
static char *arg_root = NULL;
|
||||
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||
static PagerFlags arg_pager_flags = 0;
|
||||
static bool arg_legend = true;
|
||||
static bool arg_force = false;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_hierarchies, strv_freep);
|
||||
@ -226,12 +227,9 @@ static int verb_status(int argc, char **argv, void *userdata) {
|
||||
|
||||
(void) table_set_sort(t, (size_t) 0, (size_t) -1);
|
||||
|
||||
if (arg_json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
|
||||
(void) pager_open(arg_pager_flags);
|
||||
|
||||
r = table_print_json(t, stdout, arg_json_format_flags);
|
||||
r = table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
return r;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -860,14 +858,7 @@ static int verb_list(int argc, char **argv, void *userdata) {
|
||||
|
||||
(void) table_set_sort(t, (size_t) 0, (size_t) -1);
|
||||
|
||||
if (arg_json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
|
||||
(void) pager_open(arg_pager_flags);
|
||||
|
||||
r = table_print_json(t, stdout, arg_json_format_flags);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
|
||||
return 0;
|
||||
return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
|
||||
}
|
||||
|
||||
static int verb_help(int argc, char **argv, void *userdata) {
|
||||
@ -890,6 +881,7 @@ static int verb_help(int argc, char **argv, void *userdata) {
|
||||
" --version Show package version\n"
|
||||
"\n%3$sOptions:%4$s\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --no-legend Do not show the headers and footers\n"
|
||||
" --root=PATH Operate relative to root path\n"
|
||||
" --json=pretty|short|off\n"
|
||||
" Generate JSON output\n"
|
||||
@ -909,6 +901,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_NO_PAGER,
|
||||
ARG_NO_LEGEND,
|
||||
ARG_ROOT,
|
||||
ARG_JSON,
|
||||
ARG_FORCE,
|
||||
@ -918,6 +911,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
|
||||
{ "root", required_argument, NULL, ARG_ROOT },
|
||||
{ "json", required_argument, NULL, ARG_JSON },
|
||||
{ "force", no_argument, NULL, ARG_FORCE },
|
||||
@ -943,6 +937,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_pager_flags |= PAGER_DISABLE;
|
||||
break;
|
||||
|
||||
case ARG_NO_LEGEND:
|
||||
arg_legend = false;
|
||||
break;
|
||||
|
||||
case ARG_ROOT:
|
||||
r = parse_path_argument_and_warn(optarg, false, &arg_root);
|
||||
if (r < 0)
|
||||
|
@ -103,6 +103,11 @@ int sd_network_link_get_address_state(int ifindex, char **state);
|
||||
*/
|
||||
int sd_network_link_get_required_for_online(int ifindex);
|
||||
|
||||
/* Get activation policy for ifindex.
|
||||
* Possible values are as specified for ActivationPolicy=
|
||||
*/
|
||||
int sd_network_link_get_activation_policy(int ifindex, char **policy);
|
||||
|
||||
/* Get path to .network file applied to link */
|
||||
int sd_network_link_get_network_file(int ifindex, char **filename);
|
||||
|
||||
|
@ -30,6 +30,7 @@ Host=
|
||||
MACAddress=
|
||||
PermanentMACAddress=
|
||||
[Link]
|
||||
ActivationPolicy=
|
||||
RequiredForOnline=
|
||||
ARP=
|
||||
AllMulticast=
|
||||
|
6
test/test-network/conf/25-activation-policy.network
Normal file
6
test/test-network/conf/25-activation-policy.network
Normal file
@ -0,0 +1,6 @@
|
||||
[Match]
|
||||
Name=test1
|
||||
|
||||
[Network]
|
||||
Address=192.168.10.30/24
|
||||
Gateway=192.168.10.1
|
@ -0,0 +1,2 @@
|
||||
[Link]
|
||||
ActivationPolicy=always-down
|
@ -0,0 +1,2 @@
|
||||
[Link]
|
||||
ActivationPolicy=always-up
|
@ -0,0 +1,2 @@
|
||||
[Link]
|
||||
ActivationPolicy=down
|
@ -0,0 +1,2 @@
|
||||
[Link]
|
||||
ActivationPolicy=manual
|
@ -0,0 +1,2 @@
|
||||
[Link]
|
||||
ActivationPolicy=up
|
@ -1755,6 +1755,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
'25-address-peer-ipv4.network',
|
||||
'25-address-preferred-lifetime-zero.network',
|
||||
'25-address-static.network',
|
||||
'25-activation-policy.network',
|
||||
'25-bind-carrier.network',
|
||||
'25-bond-active-backup-slave.netdev',
|
||||
'25-fibrule-invert.network',
|
||||
@ -2711,6 +2712,53 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
|
||||
self.wait_operstate('test1', 'routable')
|
||||
|
||||
def _test_activation_policy(self, test):
|
||||
self.setUp()
|
||||
conffile = '25-activation-policy.network'
|
||||
if test:
|
||||
conffile = f'{conffile}.d/{test}.conf'
|
||||
copy_unit_to_networkd_unit_path('11-dummy.netdev', conffile, dropins=False)
|
||||
start_networkd()
|
||||
|
||||
always = test.startswith('always')
|
||||
if test == 'manual':
|
||||
initial_up = 'UP' in check_output('ip link show test1')
|
||||
else:
|
||||
initial_up = not test.endswith('down') # note: default is up
|
||||
expect_up = initial_up
|
||||
next_up = not expect_up
|
||||
|
||||
# if initial expected state is down, must wait for setup_state to reach configuring
|
||||
# so systemd-networkd considers it 'activated'
|
||||
setup_state = None if initial_up else 'configuring'
|
||||
|
||||
for iteration in range(4):
|
||||
with self.subTest(iteration=iteration, expect_up=expect_up):
|
||||
operstate = 'routable' if expect_up else 'off'
|
||||
self.wait_operstate('test1', operstate, setup_state=setup_state, setup_timeout=20)
|
||||
setup_state = None
|
||||
|
||||
if expect_up:
|
||||
self.assertIn('UP', check_output('ip link show test1'))
|
||||
self.assertIn('192.168.10.30/24', check_output('ip address show test1'))
|
||||
self.assertIn('default via 192.168.10.1', check_output('ip route show'))
|
||||
else:
|
||||
self.assertIn('DOWN', check_output('ip link show test1'))
|
||||
|
||||
if next_up:
|
||||
check_output('ip link set dev test1 up')
|
||||
else:
|
||||
check_output('ip link set dev test1 down')
|
||||
expect_up = initial_up if always else next_up
|
||||
next_up = not next_up
|
||||
|
||||
self.tearDown()
|
||||
|
||||
def test_activation_policy(self):
|
||||
for test in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
|
||||
with self.subTest(test=test):
|
||||
self._test_activation_policy(test)
|
||||
|
||||
def test_domain(self):
|
||||
copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
|
||||
start_networkd()
|
||||
@ -2985,6 +3033,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
|
||||
self.assertRegex(data, r'OPER_STATE=routable')
|
||||
self.assertRegex(data, r'REQUIRED_FOR_ONLINE=yes')
|
||||
self.assertRegex(data, r'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
|
||||
self.assertRegex(data, r'ACTIVATION_POLICY=up')
|
||||
self.assertRegex(data, r'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
|
||||
self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
|
||||
self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
|
||||
|
Loading…
x
Reference in New Issue
Block a user