1

I'm running a buildroot custom linux (kernel 4.9.87) on a custom board based on an Atmel Sama5d2.

I'm trying to configure the network on the eth0 interface using dhcp only at hotplug.

Originally, the interface was configured at boot using auto eth0 into /etc/network/interfaces

I changed it to allow-hotplug eth0 to have the following file

# cat /etc/network/interfaces 

auto lo
iface lo inet loopback

allow-hotplug eth0
iface eth0 inet dhcp

After this change, udhcpc is not run at boot and is not blocking linux boot for 30 seconds anymore if the cable is not plugged.

However, nothing happens when I plug or unplug the cable.

If I mannually run ifup -a I obtain an IP address on eth0 interface.

From this results, I don't think the problem comes from network configuration but more from handling low level events.

I've tried to monitor the plug/unplug of the cable using udevadm but I can't see any kernel event when I'm pluging and unpluging the cable (but I can see events from usb subsystem for example).

I have also written a udev rule to log events in case udevadm was not relaying this subsystem events.

# cat /etc/udev/rules.d/20-network.rules 
SUBSYSTEM=="net", ACTION=="add", RUN+="/test.sh add"
SUBSYSTEM=="net", ACTION=="remove" , RUN+="/test.sh remove" 

However, nothing is trigerred by this rule neither.


So right now I think I have an issue detecting network cable hotplug.

I could be a kernel configuration mistake as well as a hardware wiring mistake.

I don't really know how the plug/unplug event is detected at hardware level however I think that the event is sent to udev either directly by the driver itself or by one of the numerous kernel frameworks in which it's deployed.

Do you think I may be missing some kernel configuration ?

Do you think it's possible to trace the state cable at a lower level than using udev ? Maybe by directly interfacing with sysfs ?

Arkaik
  • 1,156

1 Answers1

8

This udev rule and script catches network interface changes:

/etc/udev/rules.d/90-netifchanges.rules:

# Call custom script when ethernet device(s) are changed/added/removed/etc in system
SUBSYSTEM=="net" \
, RUN+="/usr/bin/systemd-cat /usr/local/bin/netifchanges.sh '$env{ACTION}' '$name' '$id' '$sys$devpath'"

/usr/local/bin/netifchanges.sh script which logs to systemd journal:

#!/bin/bash -e

action=$1 ifname=$2 id=$3 syspath=$4

echo "Network interface $ifname ($id) $action" printenv

It can be tested without reboot with:

udevadm control --reload-rules && udevadm -d trigger -v --type devices --subsystem-match net

and then seeing the log with journalctl -xe.

If you're not running with systemd:

Remove /usr/bin/systemd-cat in RUN+=".." Replace echo with logger "..." or echo "stuff" > /dev/kmsg or other method used by your distro

Additionally you can see log events with adding dummy interface:

# ip link add dummy0 type dummy
# ip link set dummy0 up
# ip link set dummy0 down
# ip link delete dummy0

Also you can find lots of information about interface with udevadm for example:

# udevadm info -a /sys/class/net/eno1

Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device.

looking at device '/devices/pci0000:00/0000:00:19.0/net/eno1': KERNEL=="eno1" SUBSYSTEM=="net" DRIVER=="" ATTR{gro_flush_timeout}=="0" ATTR{proto_down}=="0" ATTR{addr_assign_type}=="0" ATTR{flags}=="0x1103" ATTR{netdev_group}=="0" ATTR{name_assign_type}=="4" ATTR{broadcast}=="ff:ff:ff:ff:ff:ff" ATTR{operstate}=="up" ATTR{link_mode}=="0" ATTR{dev_port}=="0" ATTR{address}=="74:d0:2b:2c:6e:d7" ATTR{duplex}=="full" ATTR{carrier_changes}=="4" ATTR{type}=="1" ATTR{addr_len}=="6" ATTR{dev_id}=="0x0" ATTR{iflink}=="3" ATTR{mtu}=="1500" ATTR{speed}=="1000" ATTR{carrier_down_count}=="2" ATTR{ifalias}=="" ATTR{carrier_up_count}=="2" ATTR{ifindex}=="3" ATTR{carrier}=="1" ATTR{tx_queue_len}=="1000" ATTR{dormant}=="0"

looking at parent device '/devices/pci0000:00/0000:00:19.0': KERNELS=="0000:00:19.0" SUBSYSTEMS=="pci" DRIVERS=="e1000e" ATTRS{device}=="0x1503" ATTRS{label}==" Onboard LAN" ATTRS{enable}=="1" ATTRS{irq}=="56" ATTRS{subsystem_vendor}=="0x1043" ATTRS{devspec}=="" ATTRS{revision}=="0x06" ATTRS{subsystem_device}=="0x849c" ATTRS{local_cpus}=="ff" ATTRS{local_cpulist}=="0-7" ATTRS{class}=="0x020000" ATTRS{driver_override}=="(null)" ATTRS{broken_parity_status}=="0" ATTRS{msi_bus}=="1" ATTRS{vendor}=="0x8086" ATTRS{consistent_dma_mask_bits}=="64" ATTRS{ari_enabled}=="0" ATTRS{index}=="1" ATTRS{numa_node}=="-1" ATTRS{d3cold_allowed}=="1" ATTRS{dma_mask_bits}=="64"

looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS==""

These link to sys files:

# cat /sys/class/net/eno1/operstate 
up

udevadm monitor can also be used:

# udevadm -d monitor -p -k -u --subsystem-match=net
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

KERNEL[99386.755966] add /devices/virtual/net/dummy0 (net) ACTION=add DEVPATH=/devices/virtual/net/dummy0 SUBSYSTEM=net INTERFACE=dummy0 IFINDEX=12 SEQNUM=6842

rx-0: sd-device-monitor: Received device does not pass filter, ignoring tx-0: sd-device-monitor: Received device does not pass filter, ignoring UDEV [99386.773912] add /devices/virtual/net/dummy0 (net) ACTION=add DEVPATH=/devices/virtual/net/dummy0 SUBSYSTEM=net INTERFACE=dummy0 IFINDEX=12 SEQNUM=6842 USEC_INITIALIZED=99386759873 ID_NET_NAMING_SCHEME=v240 ID_MM_CANDIDATE=1 ID_NET_DRIVER=dummy ID_NET_LINK_FILE=/usr/lib/systemd/network/99-default.link SYSTEMD_ALIAS=/sys/subsystem/net/devices/dummy0 TAGS=:systemd:

rx-0: sd-device-monitor: Received device does not pass filter, ignoring tx-0: sd-device-monitor: Received device does not pass filter, ignoring KERNEL[99392.704357] remove /devices/virtual/net/dummy0 (net) ACTION=remove DEVPATH=/devices/virtual/net/dummy0 SUBSYSTEM=net INTERFACE=dummy0 IFINDEX=12 SEQNUM=6847

UDEV [99392.715832] remove /devices/virtual/net/dummy0 (net) ACTION=remove DEVPATH=/devices/virtual/net/dummy0 SUBSYSTEM=net INTERFACE=dummy0 IFINDEX=12 SEQNUM=6847 USEC_INITIALIZED=99386759873 ID_NET_NAMING_SCHEME=v240 ID_MM_CANDIDATE=1 ID_NET_DRIVER=dummy ID_NET_LINK_FILE=/usr/lib/systemd/network/99-default.link SYSTEMD_ALIAS=/sys/subsystem/net/devices/dummy0 TAGS=:systemd:

raspi
  • 1,376
  • Why was this downvoted ? I haven't tried this solution yet as this question is a duplicate and I resolved it using ifplugd. However this post is full of information and offers another workaround to the question. So I upvote – Arkaik May 29 '19 at 14:28