Be careful when matching on Ethernet addresses in systemd-networkd
A not uncommon pattern in networkd is to write a
file that selects the hardware to work on by MAC address, because that's
often more stable than many of the other alternatives. For instance,
you might write a .link file for your motherboard like this:
[Match] MACAddress=2c:fd:a1:xx:xx:xx [Link] Description=Onboard motherboard port MACAddressPolicy=persistent Name=em0
Unfortunately this is dangerous, because some virtual devices
inherit Ethernet addresses from their parent device and networkd
will allow virtual devices to match against just Ethernet addresses.
In particular VLANs inherit the Ethernet address from their underlying
network device, so if you have one or more VLANs on top of
they will all match this (and then they'll try to rename themselves
em0). The same can happen
if you have a
.network file that matches with MACAddress in order
to deal with variable network names for the same underlying connection.
(If you have a real device that matches this way and creates VLANs on top of itself, networkd may be smart enough to recognize that it has a recursive situation, or it may blow up. I haven't tested.)
In other words, if you tell networkd that a
.link or a
file applies to anything with a specific Ethernet address, networkd
takes that to really mean anything. You may have meant this to apply
(only) to your actual Ethernet device, but the
.link file doesn't
say that and networkd won't infer it.
In systemd v245 or later, what you probably want is to restrict any
Ethernet hardware matches to real Ethernet devices with the additional
requirement of '
[Match] MACAddress=2c:fd:a1:xx:xx:xx Type=ether
(Systemd v245 was released in February of 2020 and is in Ubuntu
20.04 and the current versions of Fedora, but isn't in Debian stable.
Support for the current meaning of
Type= that allows matching
ether' was added in this commit
as a result of issue #14952. To my surprise,
this significant improvement doesn't seem to have been noted in the
ether' type applies to both PCI Ethernet ports and USB
Ethernet devices, but it doesn't apply to wireless devices; those
wlan'. As the manpage covers, '
networkctl list' can tell
you what your devices are. VLANs are type '
If you have a systemd (and thus a systemd-networkd) that's older
than v245, I think the only thing you can do is match on a property
of the device, obtained from '
udevadm info /sys/class/net/<what>'.
For a lot of physical hardware, the obvious property is that it's
on a PCI bus:
[Match] MACAddress=2c:fd:a1:xx:xx:xx Property=ID_BUS=pci
(I have to say that I haven't tested this, I'm just following the manpage.)
However, USB Ethernet devices are '
ID_BUS=usb', not PCI, while
a laptop's onboard wireless most likely is a PCI device, which is
the case on my Dell XPS 13. My laptop's
wireless device is also '
DEVTYPE=wlan', while even now real
Ethernet devices have no
DEVTYPE (as of systemd v248 on a
Fedora 34 virtual machine).
(This elaborates on a tweet of mine.)
PS: I'm not sure whether the matching here is being done by systemd-networkd, the systemd version of udevd, or both of them. It's quite possible that both programs and subsystems are doing it at different times and in different circumstances.
I should keep track of what Python packages I install through
These days I'm increasingly making use of installing Python packages
pip, whether this is into a PyPy environment or with '
pip install --user' for things
like python-lsp-server. Having done this for a
while, complete with trying to keep up with potential package
upgrades, I've come to the conclusion that I should explicitly keep
track of what packages I install, recording this in some place I
can find it again.
There are two problems (or issues) that push me to this. The first
is that as far as I know, Pip doesn't keep track of a distinction
between packages that you've asked it to install and the dependencies
of those packages. All of the packages show up in '
pip list', and
any can show up in '
pip list --outdated'. My understanding is
that in the normal, expected use of Pip you'll keep track of this
in your project in a requirements file,
then use that to build the project's virtualenv. This is not really
the model of installing commands, especially commands like
that have install time options.
The second issue is that Pip installed packages are implicitly
for a specific version of Python. If you
rely on the system Python (instead of your own version) and that
version gets upgraded, suddenly '
pip list' will report nothing
(and you will in fact have no packages available). At this point
you need to somehow recover the list of installed packages and
re-install all of them (unless you resort to unclean hacks).
Explicitly keeping track of this list in advance is easier than
having to dig it out at the time.
Having an explicit list helps in other situations. Perhaps you started out installing all of your tools under CPython, but now you want to see how well they'll work under PyPy. Perhaps you're building a new PyPy based environment with a new version of PyPy and want to start over from scratch. Perhaps you think package versions and dependencies have gotten snarled and you're carrying surplus packages, so you want to delete everything and start over from scratch.
(Starting over from scratch can also be the easiest way to get the
best version of dependencies, since the packages you're directly
installing may have maximum version constraints that will trip you
up if you just directly '
pip install --upgrade ...' dependencies.)
PS: Possibly there's ways to do all of this with Pip today, especially things like 'upgrade this and all of its dependencies to the most recent versions that are acceptable'. I'm not well versed in Pip, since mostly I use it as a program installer.