mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-12 09:17:44 +03:00
Merge pull request #11681 from yuwata/network-link-enslaved-operstate
network: introduce new 'enslaved' operstate
This commit is contained in:
commit
1cfece4a45
@ -118,13 +118,21 @@
|
||||
<varlistentry>
|
||||
<term>carrier</term>
|
||||
<listitem>
|
||||
<para>the link has a carrier</para>
|
||||
<para>the link has a carrier, or for bond master, all bonding slave network interfaces are
|
||||
enslaved to the master.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>degraded</term>
|
||||
<listitem>
|
||||
<para>the link has carrier and addresses valid on the local link configured</para>
|
||||
<para>the link has carrier and addresses valid on the local link configured, or for bond
|
||||
master, one of the bonding slave network interfaces is in off, no-carrier, or dormant</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>enslaved</term>
|
||||
<listitem>
|
||||
<para>the link has carrier and is enslaved to other network interfaces</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
@ -65,7 +65,7 @@ static void operational_state_to_color(const char *state, const char **on, const
|
||||
assert(on);
|
||||
assert(off);
|
||||
|
||||
if (streq_ptr(state, "routable")) {
|
||||
if (STRPTR_IN_SET(state, "routable", "enslaved")) {
|
||||
*on = ansi_highlight_green();
|
||||
*off = ansi_normal();
|
||||
} else if (streq_ptr(state, "degraded")) {
|
||||
|
@ -351,7 +351,7 @@ int address_update(
|
||||
address->scope = scope;
|
||||
address->cinfo = *cinfo;
|
||||
|
||||
link_update_operstate(address->link);
|
||||
link_update_operstate(address->link, true);
|
||||
link_check_ready(address->link);
|
||||
|
||||
if (!ready &&
|
||||
@ -380,7 +380,7 @@ int address_drop(Address *address) {
|
||||
address_release(address);
|
||||
address_free(address);
|
||||
|
||||
link_update_operstate(link);
|
||||
link_update_operstate(link, true);
|
||||
|
||||
if (link && !ready)
|
||||
link_check_ready(link);
|
||||
|
@ -70,6 +70,9 @@ static bool link_dhcp6_enabled(Link *link) {
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
if (link->network->bond)
|
||||
return false;
|
||||
|
||||
return link->network->dhcp & ADDRESS_FAMILY_IPV6;
|
||||
}
|
||||
|
||||
@ -82,6 +85,9 @@ static bool link_dhcp4_enabled(Link *link) {
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
if (link->network->bond)
|
||||
return false;
|
||||
|
||||
return link->network->dhcp & ADDRESS_FAMILY_IPV4;
|
||||
}
|
||||
|
||||
@ -94,6 +100,9 @@ static bool link_dhcp4_server_enabled(Link *link) {
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
if (link->network->bond)
|
||||
return false;
|
||||
|
||||
return link->network->dhcp_server;
|
||||
}
|
||||
|
||||
@ -109,6 +118,9 @@ static bool link_ipv4ll_enabled(Link *link) {
|
||||
if (STRPTR_IN_SET(link->kind, "vrf", "wireguard"))
|
||||
return false;
|
||||
|
||||
if (link->network->bond)
|
||||
return false;
|
||||
|
||||
return link->network->link_local & ADDRESS_FAMILY_IPV4;
|
||||
}
|
||||
|
||||
@ -127,6 +139,9 @@ static bool link_ipv6ll_enabled(Link *link) {
|
||||
if (STRPTR_IN_SET(link->kind, "vrf", "wireguard"))
|
||||
return false;
|
||||
|
||||
if (link->network->bond)
|
||||
return false;
|
||||
|
||||
return link->network->link_local & ADDRESS_FAMILY_IPV6;
|
||||
}
|
||||
|
||||
@ -136,7 +151,7 @@ static bool link_ipv6_enabled(Link *link) {
|
||||
if (!socket_ipv6_is_supported())
|
||||
return false;
|
||||
|
||||
if (link->network->bridge)
|
||||
if (link->network->bridge || link->network->bond)
|
||||
return false;
|
||||
|
||||
/* DHCPv6 client will not be started if no IPv6 link-local address is configured. */
|
||||
@ -303,8 +318,9 @@ static int link_enable_ipv6(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void link_update_operstate(Link *link) {
|
||||
void link_update_operstate(Link *link, bool also_update_bond_master) {
|
||||
LinkOperationalState operstate;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (link->kernel_operstate == IF_OPER_DORMANT)
|
||||
@ -346,11 +362,38 @@ void link_update_operstate(Link *link) {
|
||||
else
|
||||
operstate = LINK_OPERSTATE_OFF;
|
||||
|
||||
if (IN_SET(operstate, LINK_OPERSTATE_DEGRADED, LINK_OPERSTATE_CARRIER) &&
|
||||
link->flags & IFF_SLAVE)
|
||||
operstate = LINK_OPERSTATE_ENSLAVED;
|
||||
|
||||
if (IN_SET(operstate, LINK_OPERSTATE_CARRIER, LINK_OPERSTATE_ENSLAVED, LINK_OPERSTATE_ROUTABLE) &&
|
||||
!hashmap_isempty(link->bond_slaves)) {
|
||||
Iterator i;
|
||||
Link *slave;
|
||||
|
||||
HASHMAP_FOREACH(slave, link->bond_slaves, i) {
|
||||
link_update_operstate(slave, false);
|
||||
|
||||
if (IN_SET(slave->operstate,
|
||||
LINK_OPERSTATE_OFF, LINK_OPERSTATE_NO_CARRIER, LINK_OPERSTATE_DORMANT))
|
||||
operstate = LINK_OPERSTATE_DEGRADED;
|
||||
}
|
||||
}
|
||||
|
||||
if (link->operstate != operstate) {
|
||||
link->operstate = operstate;
|
||||
link_send_changed(link, "OperationalState", NULL);
|
||||
link_dirty(link);
|
||||
}
|
||||
|
||||
if (also_update_bond_master && link->network && link->network->bond) {
|
||||
Link *master;
|
||||
|
||||
if (link_get(link->manager, link->network->bond->ifindex, &master) < 0)
|
||||
return;
|
||||
|
||||
link_update_operstate(master, true);
|
||||
}
|
||||
}
|
||||
|
||||
#define FLAG_STRING(string, flag, old, new) \
|
||||
@ -425,7 +468,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) {
|
||||
link->flags = flags;
|
||||
link->kernel_operstate = operstate;
|
||||
|
||||
link_update_operstate(link);
|
||||
link_update_operstate(link, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -606,6 +649,8 @@ static Link *link_free(Link *link) {
|
||||
hashmap_remove(link->bound_by_links, INT_TO_PTR(carrier->ifindex));
|
||||
hashmap_free(link->bound_by_links);
|
||||
|
||||
hashmap_free(link->bond_slaves);
|
||||
|
||||
return mfree(link);
|
||||
}
|
||||
|
||||
@ -1539,7 +1584,26 @@ static int link_set_bridge(Link *link) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int link_bond_set(Link *link) {
|
||||
static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(link);
|
||||
assert(link->ifname);
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not set bonding interface: %m");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_set_bond(Link *link) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
|
||||
@ -1582,7 +1646,7 @@ static int link_bond_set(Link *link) {
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
|
||||
|
||||
r = netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
|
||||
r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_bond_handler,
|
||||
link_netlink_destroy_callback, link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||
@ -1592,6 +1656,29 @@ static int link_bond_set(Link *link) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int link_append_bond_slave(Link *link) {
|
||||
Link *master;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
assert(link->network->bond);
|
||||
|
||||
r = link_get(link->manager, link->network->bond->ifindex, &master);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_ensure_allocated(&master->bond_slaves, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_put(master->bond_slaves, INT_TO_PTR(link->ifindex), link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_lldp_save(Link *link) {
|
||||
_cleanup_free_ char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
@ -2393,9 +2480,13 @@ static int link_joined(Link *link) {
|
||||
}
|
||||
|
||||
if (link->network->bond) {
|
||||
r = link_bond_set(link);
|
||||
r = link_set_bond(link);
|
||||
if (r < 0)
|
||||
log_link_error_errno(link, r, "Could not set bond message: %m");
|
||||
|
||||
r = link_append_bond_slave(link);
|
||||
if (r < 0)
|
||||
log_link_error_errno(link, r, "Failed to add to bond master's slave list: %m");
|
||||
}
|
||||
|
||||
if (link->network->use_br_vlan &&
|
||||
@ -4200,6 +4291,7 @@ static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
|
||||
[LINK_OPERSTATE_DORMANT] = "dormant",
|
||||
[LINK_OPERSTATE_CARRIER] = "carrier",
|
||||
[LINK_OPERSTATE_DEGRADED] = "degraded",
|
||||
[LINK_OPERSTATE_ENSLAVED] = "enslaved",
|
||||
[LINK_OPERSTATE_ROUTABLE] = "routable",
|
||||
};
|
||||
|
||||
|
@ -34,6 +34,7 @@ typedef enum LinkOperationalState {
|
||||
LINK_OPERSTATE_DORMANT,
|
||||
LINK_OPERSTATE_CARRIER,
|
||||
LINK_OPERSTATE_DEGRADED,
|
||||
LINK_OPERSTATE_ENSLAVED,
|
||||
LINK_OPERSTATE_ROUTABLE,
|
||||
_LINK_OPERSTATE_MAX,
|
||||
_LINK_OPERSTATE_INVALID = -1
|
||||
@ -128,6 +129,7 @@ typedef struct Link {
|
||||
|
||||
Hashmap *bound_by_links;
|
||||
Hashmap *bound_to_links;
|
||||
Hashmap *bond_slaves;
|
||||
} Link;
|
||||
|
||||
typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
|
||||
@ -150,7 +152,7 @@ int link_initialized(Link *link, sd_device *device);
|
||||
|
||||
void link_check_ready(Link *link);
|
||||
|
||||
void link_update_operstate(Link *link);
|
||||
void link_update_operstate(Link *link, bool also_update_bond_master);
|
||||
int link_update(Link *link, sd_netlink_message *message);
|
||||
|
||||
void link_dirty(Link *link);
|
||||
|
6
test/test-network/conf/bond99.network
Normal file
6
test/test-network/conf/bond99.network
Normal file
@ -0,0 +1,6 @@
|
||||
[Match]
|
||||
Name=bond99
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
DHCP=yes
|
@ -3,6 +3,7 @@ Name=veth-peer
|
||||
|
||||
[Network]
|
||||
Address=192.168.5.1/24
|
||||
IPv6AcceptRA=false
|
||||
DHCPServer=yes
|
||||
|
||||
[DHCPServer]
|
||||
|
6
test/test-network/conf/veth-bond.network
Normal file
6
test/test-network/conf/veth-bond.network
Normal file
@ -0,0 +1,6 @@
|
||||
[Match]
|
||||
Name=veth99
|
||||
|
||||
[Network]
|
||||
Bond=bond99
|
||||
IPv6AcceptRA=false
|
7
test/test-network/conf/vlan6.netdev
Normal file
7
test/test-network/conf/vlan6.netdev
Normal file
@ -0,0 +1,7 @@
|
||||
[NetDev]
|
||||
Name=vlan6
|
||||
Kind=vlan
|
||||
MTUBytes=1500
|
||||
|
||||
[VLAN]
|
||||
Id=6
|
6
test/test-network/conf/vlan6.network
Normal file
6
test/test-network/conf/vlan6.network
Normal file
@ -0,0 +1,6 @@
|
||||
[Match]
|
||||
Name=vlan6
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=false
|
||||
Address=100.100.100.2/24
|
@ -1004,6 +1004,80 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
|
||||
output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
|
||||
self.assertRegex(output, 'State: routable \(configured\)')
|
||||
|
||||
class NetworkdNetWorkBondTests(unittest.TestCase, Utilities):
|
||||
links = [
|
||||
'bond99',
|
||||
'veth99']
|
||||
|
||||
units = [
|
||||
'25-bond.netdev',
|
||||
'25-veth.netdev',
|
||||
'bond99.network',
|
||||
'dhcp-server.network',
|
||||
'veth-bond.network']
|
||||
|
||||
def setUp(self):
|
||||
self.link_remove(self.links)
|
||||
|
||||
def tearDown(self):
|
||||
self.link_remove(self.links)
|
||||
self.remove_unit_from_networkd_path(self.units)
|
||||
|
||||
def test_bridge_property(self):
|
||||
self.copy_unit_to_networkd_unit_path('25-bond.netdev', '25-veth.netdev', 'bond99.network',
|
||||
'dhcp-server.network', 'veth-bond.network')
|
||||
self.start_networkd()
|
||||
|
||||
self.assertTrue(self.link_exits('bond99'))
|
||||
self.assertTrue(self.link_exits('veth99'))
|
||||
self.assertTrue(self.link_exits('veth-peer'))
|
||||
|
||||
output = subprocess.check_output(['ip', '-d', 'link', 'show', 'veth-peer']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'UP,LOWER_UP')
|
||||
|
||||
output = subprocess.check_output(['ip', '-d', 'link', 'show', 'veth99']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
|
||||
|
||||
output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond99']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'MASTER,UP,LOWER_UP')
|
||||
|
||||
output = subprocess.check_output(['networkctl', 'status', 'veth-peer']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'State: routable \(configured\)')
|
||||
|
||||
output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'State: enslaved \(configured\)')
|
||||
|
||||
output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'State: routable \(configured\)')
|
||||
|
||||
self.assertEqual(subprocess.call(['ip', 'link', 'set', 'veth99', 'down']), 0)
|
||||
time.sleep(2)
|
||||
|
||||
output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'State: off \(configured\)')
|
||||
|
||||
output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'State: degraded \(configured\)')
|
||||
|
||||
self.assertEqual(subprocess.call(['ip', 'link', 'set', 'veth99', 'up']), 0)
|
||||
time.sleep(2)
|
||||
|
||||
output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'State: enslaved \(configured\)')
|
||||
|
||||
output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'State: routable \(configured\)')
|
||||
|
||||
class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
|
||||
links = [
|
||||
'bridge99',
|
||||
|
Loading…
Reference in New Issue
Block a user