Compare commits

..

No commits in common. "be3e4467d481b4c39cc7299693a5d167a4690a86" and "f7c79f09117a383a776830dc59558c026bb79566" have entirely different histories.

13 changed files with 40 additions and 238 deletions

View File

@ -56,7 +56,7 @@ components:
script can optionally create boot loader entries that carry an initial boot script can optionally create boot loader entries that carry an initial boot
counter (the initial counter is configurable in `/etc/kernel/tries`). counter (the initial counter is configurable in `/etc/kernel/tries`).
## Details # Details
The boot counting data `systemd-boot` and `systemd-bless-boot.service` The boot counting data `systemd-boot` and `systemd-bless-boot.service`
manage is stored in the name of the boot loader entries. If a boot loader entry manage is stored in the name of the boot loader entries. If a boot loader entry
@ -149,7 +149,7 @@ scenario the first 4 steps are the same as above:
12. On the following boot (and all subsequent boots after that) the entry is 12. On the following boot (and all subsequent boots after that) the entry is
now seen with boot counting turned off, no further renaming takes place. now seen with boot counting turned off, no further renaming takes place.
## How to adapt this scheme to other setups # How to adapt this scheme to other setups
Of the stack described above many components may be replaced or augmented. Here Of the stack described above many components may be replaced or augmented. Here
are a couple of recommendations. are a couple of recommendations.
@ -180,7 +180,7 @@ are a couple of recommendations.
wrap them in a unit and order them after `boot-complete.target`, pulling it wrap them in a unit and order them after `boot-complete.target`, pulling it
in. in.
## FAQ # FAQ
1. *Why do you use file renames to store the counter? Why not a regular file?* 1. *Why do you use file renames to store the counter? Why not a regular file?*
— Mainly two reasons: it's relatively likely that renames can be implemented — Mainly two reasons: it's relatively likely that renames can be implemented

View File

@ -543,7 +543,7 @@ layout: default
time you need that please immediately undefine `basename()`, and add a time you need that please immediately undefine `basename()`, and add a
comment about it, so that no code ever ends up using the POSIX version! comment about it, so that no code ever ends up using the POSIX version!
## Committing to git # Committing to git
- Commit message subject lines should be prefixed with an appropriate component - Commit message subject lines should be prefixed with an appropriate component
name of some kind. For example "journal: ", "nspawn: " and so on. name of some kind. For example "journal: ", "nspawn: " and so on.

View File

@ -69,7 +69,7 @@ Once you're done, create a git commit for the update of the `po/*.po` file you
touched. Remember to undo the changes to the other `*.po` files (for instance, touched. Remember to undo the changes to the other `*.po` files (for instance,
using `git checkout -- po/` after you commit the changes you do want to keep.) using `git checkout -- po/` after you commit the changes you do want to keep.)
## Recompiling Translations # Recompiling Translations
You can recompile the `*.po` files using the following command: You can recompile the `*.po` files using the following command:

View File

@ -54,36 +54,32 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
return 1; return 1;
} }
int get_block_device(const char *path, dev_t *ret) { int get_block_device(const char *path, dev_t *dev) {
_cleanup_close_ int fd = -1;
struct stat st; struct stat st;
int r; struct statfs sfs;
assert(path); assert(path);
assert(ret); assert(dev);
/* Gets the block device directly backing a file system. If the block device is encrypted, returns /* Gets the block device directly backing a file system. If
* the device mapper block device. */ * the block device is encrypted, returns the device mapper
* block device. */
fd = open(path, O_NOFOLLOW|O_CLOEXEC); if (lstat(path, &st))
if (fd < 0)
return -errno;
if (fstat(fd, &st))
return -errno; return -errno;
if (major(st.st_dev) != 0) { if (major(st.st_dev) != 0) {
*ret = st.st_dev; *dev = st.st_dev;
return 1; return 1;
} }
r = btrfs_get_block_device_fd(fd, ret); if (statfs(path, &sfs) < 0)
if (r > 0) return -errno;
return 1;
if (r != -ENOTTY) /* not btrfs */
return r;
*ret = 0; if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
return btrfs_get_block_device(path, dev);
*dev = 0;
return 0; return 0;
} }

View File

@ -1350,7 +1350,7 @@ int link_set_mtu(Link *link, uint32_t mtu) {
if (link_ipv6_enabled(link) && mtu < IPV6_MIN_MTU) { if (link_ipv6_enabled(link) && mtu < IPV6_MIN_MTU) {
log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as " log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as "
"IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes"); "IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes: %m");
mtu = IPV6_MIN_MTU; mtu = IPV6_MIN_MTU;
} }
@ -2387,23 +2387,9 @@ static int link_set_ipv6_mtu(Link *link) {
if (link->network->ipv6_mtu == 0) if (link->network->ipv6_mtu == 0)
return 0; return 0;
/* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
* on the interface. Bump up IPv6 MTU bytes to IPV6_MTU_MIN. */
if (link->network->ipv6_mtu < IPV6_MIN_MTU) {
log_link_notice(link, "Bumping IPv6 MTU to "STRINGIFY(IPV6_MIN_MTU)" byte minimum required");
link->network->ipv6_mtu = IPV6_MIN_MTU;
}
r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu); r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu);
if (r < 0) { if (r < 0)
if (link->mtu < link->network->ipv6_mtu)
log_link_warning(link, "Cannot set IPv6 MTU %"PRIu32" higher than device MTU %"PRIu32,
link->network->ipv6_mtu, link->mtu);
else
log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface: %m"); log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface: %m");
}
link->ipv6_mtu_set = true;
return 0; return 0;
} }
@ -2710,6 +2696,10 @@ static int link_configure(Link *link) {
if (r < 0) if (r < 0)
return r; return r;
r = link_set_ipv6_mtu(link);
if (r < 0)
return r;
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) { if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) {
r = ipv4ll_configure(link); r = ipv4ll_configure(link);
if (r < 0) if (r < 0)
@ -2786,12 +2776,6 @@ static int link_configure_after_setting_mtu(Link *link) {
if (link->setting_mtu) if (link->setting_mtu)
return 0; return 0;
/* The kernel resets ipv6 mtu after changing device mtu;
* we must set this here, after we've set device mtu */
r = link_set_ipv6_mtu(link);
if (r < 0)
return r;
if (link_has_carrier(link) || link->network->configure_without_carrier) { if (link_has_carrier(link) || link->network->configure_without_carrier) {
r = link_acquire_conf(link); r = link_acquire_conf(link);
if (r < 0) if (r < 0)
@ -3500,30 +3484,11 @@ int link_carrier_reset(Link *link) {
return 0; return 0;
} }
/* This is called every time an interface admin state changes to up;
* specifically, when IFF_UP flag changes from unset to set */
static int link_admin_state_up(Link *link) {
int r;
/* 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
* the link->network has been setup; we only need to reset it
* here if we've already set it during normal initialization. */
if (link->ipv6_mtu_set) {
r = link_set_ipv6_mtu(link);
if (r < 0)
return r;
}
return 0;
}
int link_update(Link *link, sd_netlink_message *m) { int link_update(Link *link, sd_netlink_message *m) {
struct ether_addr mac; struct ether_addr mac;
const char *ifname; const char *ifname;
uint32_t mtu; uint32_t mtu;
bool had_carrier, carrier_gained, carrier_lost, link_was_admin_up; bool had_carrier, carrier_gained, carrier_lost;
int old_master, r; int old_master, r;
assert(link); assert(link);
@ -3653,22 +3618,12 @@ int link_update(Link *link, sd_netlink_message *m) {
old_master = link->master_ifindex; old_master = link->master_ifindex;
(void) sd_netlink_message_read_u32(m, IFLA_MASTER, (uint32_t *) &link->master_ifindex); (void) sd_netlink_message_read_u32(m, IFLA_MASTER, (uint32_t *) &link->master_ifindex);
link_was_admin_up = link->flags & IFF_UP;
had_carrier = link_has_carrier(link); had_carrier = link_has_carrier(link);
r = link_update_flags(link, m, old_master != link->master_ifindex); r = link_update_flags(link, m, old_master != link->master_ifindex);
if (r < 0) if (r < 0)
return r; return r;
if (!link_was_admin_up && (link->flags & IFF_UP)) {
log_link_info(link, "Link UP");
r = link_admin_state_up(link);
if (r < 0)
return r;
} else if (link_was_admin_up && !(link->flags & IFF_UP))
log_link_info(link, "Link DOWN");
r = link_update_lldp(link); r = link_update_lldp(link);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -116,7 +116,6 @@ typedef struct Link {
bool routing_policy_rules_configured:1; bool routing_policy_rules_configured:1;
bool qdiscs_configured:1; bool qdiscs_configured:1;
bool setting_mtu:1; bool setting_mtu:1;
bool ipv6_mtu_set:1;
LIST_HEAD(Address, pool_addresses); LIST_HEAD(Address, pool_addresses);

View File

@ -1,5 +0,0 @@
[Match]
OriginalName=dummy98
[Link]
MTUBytes=1600

View File

@ -1,4 +0,0 @@
[NetDev]
Name=dummy98
Kind=dummy
MTUBytes=1600

View File

@ -1,7 +0,0 @@
[Match]
Name=dummy98
[Network]
IPv6AcceptRA=no
Address=10.1.2.3/16
Address=2001:db8:0:f101::15/64

View File

@ -1,2 +0,0 @@
[Network]
IPv6MTUBytes=1400

View File

@ -1,2 +0,0 @@
[Network]
IPv6MTUBytes=1550

View File

@ -1,2 +0,0 @@
[Link]
MTUBytes=1600

View File

@ -142,8 +142,6 @@ def setUpModule():
running_units.append(u) running_units.append(u)
drop_in = [ drop_in = [
'[Unit]',
'StartLimitIntervalSec=0',
'[Service]', '[Service]',
'Restart=no', 'Restart=no',
'ExecStart=', 'ExecStart=',
@ -218,8 +216,8 @@ def tearDownModule():
for u in running_units: for u in running_units:
check_output(f'systemctl start {u}') check_output(f'systemctl start {u}')
def read_link_attr(*args): def read_link_attr(link, dev, attribute):
with open(os.path.join('/sys/class/net/', *args)) as f: with open(os.path.join(os.path.join(os.path.join('/sys/class/net/', link), dev), attribute)) as f:
return f.readline().strip() return f.readline().strip()
def read_bridge_port_attr(bridge, link, attribute): def read_bridge_port_attr(bridge, link, attribute):
@ -269,33 +267,14 @@ def read_ipv4_sysctl_attr(link, attribute):
with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute)) as f: with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute)) as f:
return f.readline().strip() return f.readline().strip()
def copy_unit_to_networkd_unit_path(*units, dropins=True): def copy_unit_to_networkd_unit_path(*units):
"""Copy networkd unit files into the testbed.
Any networkd unit file type can be specified, as well as drop-in files.
By default, all drop-ins for a specified unit file are copied in;
to avoid that specify dropins=False.
When a drop-in file is specified, its unit file is also copied in automatically.
"""
print() print()
for unit in units: for unit in units:
if dropins and os.path.exists(os.path.join(networkd_ci_path, unit + '.d')):
copytree(os.path.join(networkd_ci_path, unit + '.d'), os.path.join(network_unit_file_path, unit + '.d'))
if unit.endswith('.conf'):
dropin = unit
dropindir = os.path.join(network_unit_file_path, os.path.dirname(dropin))
os.makedirs(dropindir, exist_ok=True)
shutil.copy(os.path.join(networkd_ci_path, dropin), dropindir)
unit = os.path.dirname(dropin).rstrip('.d')
shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path) shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path)
if (os.path.exists(os.path.join(networkd_ci_path, unit + '.d'))):
copytree(os.path.join(networkd_ci_path, unit + '.d'), os.path.join(network_unit_file_path, unit + '.d'))
def remove_unit_from_networkd_path(units): def remove_unit_from_networkd_path(units):
"""Remove previously copied unit files from the testbed.
Drop-ins will be removed automatically.
"""
for unit in units: for unit in units:
if (os.path.exists(os.path.join(network_unit_file_path, unit))): if (os.path.exists(os.path.join(network_unit_file_path, unit))):
os.remove(os.path.join(network_unit_file_path, unit)) os.remove(os.path.join(network_unit_file_path, unit))
@ -373,7 +352,7 @@ class Utilities():
def check_operstate(self, link, expected, show_status=True, setup_state='configured'): def check_operstate(self, link, expected, show_status=True, setup_state='configured'):
self.assertRegex(get_operstate(link, show_status, setup_state), expected) self.assertRegex(get_operstate(link, show_status, setup_state), expected)
def wait_online(self, links_with_operstate, timeout='20s', bool_any=False, setup_state='configured', setup_timeout=5): def wait_online(self, links_with_operstate, timeout='20s', bool_any=False, setup_state='configured'):
args = wait_online_cmd + [f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate] args = wait_online_cmd + [f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
if bool_any: if bool_any:
args += ['--any'] args += ['--any']
@ -384,23 +363,13 @@ class Utilities():
output = check_output(*networkctl_cmd, 'status', link.split(':')[0], env=env) output = check_output(*networkctl_cmd, 'status', link.split(':')[0], env=env)
print(output) print(output)
raise raise
if not bool_any and setup_state: if not bool_any:
# check at least once now, then once per sec for setup_timeout secs
for secs in range(setup_timeout + 1):
for link in links_with_operstate: for link in links_with_operstate:
output = check_output(*networkctl_cmd, 'status', link.split(':')[0]) output = check_output(*networkctl_cmd, 'status', link.split(':')[0])
print(output) print(output)
if not re.search(rf'(?m)^\s*State:.*({setup_state}).*$', output): for line in output.splitlines():
# this link isn't in the right state; break into the sleep below if 'State:' in line:
break self.assertRegex(line, setup_state)
else:
# all the links were in the right state; break to exit the timer loop
break
# don't bother sleeping if time is up
if secs < setup_timeout:
time.sleep(1)
else:
self.fail(f'link {link} state does not match {setup_state}')
def wait_address(self, link, address_regex, scope='global', ipv='', timeout_sec=100): def wait_address(self, link, address_regex, scope='global', ipv='', timeout_sec=100):
for i in range(timeout_sec): for i in range(timeout_sec):
@ -3335,101 +3304,6 @@ class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
print(output) print(output)
self.assertRegex(output, '2001:db8:0:1::/64 proto ra') self.assertRegex(output, '2001:db8:0:1::/64 proto ra')
class NetworkdMTUTests(unittest.TestCase, Utilities):
links = ['dummy98']
units = [
'12-dummy.netdev',
'12-dummy-mtu.netdev',
'12-dummy-mtu.link',
'12-dummy.network',
]
def setUp(self):
remove_links(self.links)
stop_networkd(show_logs=False)
def tearDown(self):
remove_log_file()
remove_links(self.links)
remove_unit_from_networkd_path(self.units)
stop_networkd(show_logs=True)
def check_mtu(self, mtu, ipv6_mtu=None, reset=True):
if not ipv6_mtu:
ipv6_mtu = mtu
# test normal start
start_networkd()
self.wait_online(['dummy98:routable'])
self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu)
self.assertEqual(read_link_attr('dummy98', 'mtu'), mtu)
# test normal restart
restart_networkd()
self.wait_online(['dummy98:routable'])
self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu)
self.assertEqual(read_link_attr('dummy98', 'mtu'), mtu)
if reset:
self.reset_check_mtu(mtu, ipv6_mtu)
def reset_check_mtu(self, mtu, ipv6_mtu=None):
''' test setting mtu/ipv6_mtu with interface already up '''
stop_networkd()
# note - changing the device mtu resets the ipv6 mtu
run('ip link set up mtu 1501 dev dummy98')
run('ip link set up mtu 1500 dev dummy98')
self.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
self.check_mtu(mtu, ipv6_mtu, reset=False)
def test_mtu_network(self):
copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
self.check_mtu('1600')
def test_mtu_netdev(self):
copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins=False)
# note - MTU set by .netdev happens ONLY at device creation!
self.check_mtu('1600', reset=False)
def test_mtu_link(self):
copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins=False)
# must reload udev because it only picks up new files after 3 second delay
call('udevadm control --reload')
# note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
self.check_mtu('1600', reset=False)
def test_ipv6_mtu(self):
''' set ipv6 mtu without setting device mtu '''
copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
self.check_mtu('1500', '1400')
def test_ipv6_mtu_toolarge(self):
''' try set ipv6 mtu over device mtu (it shouldn't work) '''
copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
self.check_mtu('1500', '1500')
def test_mtu_network_ipv6_mtu(self):
''' set ipv6 mtu and set device mtu via network file '''
copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
self.check_mtu('1600', '1550')
def test_mtu_netdev_ipv6_mtu(self):
''' set ipv6 mtu and set device mtu via netdev file '''
copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
self.check_mtu('1600', '1550', reset=False)
def test_mtu_link_ipv6_mtu(self):
''' set ipv6 mtu and set device mtu via link file '''
copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
# must reload udev because it only picks up new files after 3 second delay
call('udevadm control --reload')
self.check_mtu('1600', '1550', reset=False)
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir') parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')