Re: [systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages
Sorry, I should clarify. The code in sd-device related to BPF I don't understand. What is the 'input' in BPF? Sent from ProtonMail mobile Original Message On 14 Sep. 2021, 5:24 pm, Lennart Poettering wrote: > On Di, 14.09.21 01:08, Ryan McClue (re.mcc...@protonmail.com) wrote: > >> I understand this is slightly off-topic, but I'm completely new to >> BPF. Analyzing libudev source and Internet I understand the general >> idea. However, I don't understand how information/what information >> is passed to the filter from the socket. For example, in my case the >> socket payload, i.e. buf_str = >> add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/event14 > >> 1. How do I pass this string to the sock_filter/sock_fprog >> structures? > > You don't. The bpf filtering, and in particular the bloom filter that > is used for that is mostly internal to udev, and not something that is > consider official API and should be reimplemented. > > Use sd-device/libudev, it implements all of this, and is the only official API > to the bpf bloom filter stuff udev does there. > > Lennart > > -- > Lennart Poettering, Berlin
Re: [systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages
Earlier you said that .nl_groups = 2 will get kernel uevents augmented by udev. So, at some stage doesn't udev have to parse the raw kernel uevents, i.e. .nl_groups = 1? How does it do this? Does it use BPF to achieve this or the string parsing? -- Ryan McClue, Sydney ‐‐‐ Original Message ‐‐‐ On Tuesday, September 14th, 2021 at 5:24 PM, Lennart Poettering wrote: > On Di, 14.09.21 01:08, Ryan McClue (re.mcc...@protonmail.com) wrote: > > > I understand this is slightly off-topic, but I'm completely new to > > > > BPF. Analyzing libudev source and Internet I understand the general > > > > idea. However, I don't understand how information/what information > > > > is passed to the filter from the socket. For example, in my case the > > > > socket payload, i.e. buf_str = > > > > add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/event14 > > > 1. How do I pass this string to the sock_filter/sock_fprog > > > > structures? > > You don't. The bpf filtering, and in particular the bloom filter that > > is used for that is mostly internal to udev, and not something that is > > consider official API and should be reimplemented. > > Use sd-device/libudev, it implements all of this, and is the only official API > > to the bpf bloom filter stuff udev does there. > > Lennart > > - > > Lennart Poettering, Berlin
Re: [systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages
On Di, 14.09.21 01:08, Ryan McClue (re.mcc...@protonmail.com) wrote: > I understand this is slightly off-topic, but I'm completely new to > BPF. Analyzing libudev source and Internet I understand the general > idea. However, I don't understand how information/what information > is passed to the filter from the socket. For example, in my case the > socket payload, i.e. buf_str = > add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/event14 > 1. How do I pass this string to the sock_filter/sock_fprog > structures? You don't. The bpf filtering, and in particular the bloom filter that is used for that is mostly internal to udev, and not something that is consider official API and should be reimplemented. Use sd-device/libudev, it implements all of this, and is the only official API to the bpf bloom filter stuff udev does there. Lennart -- Lennart Poettering, Berlin
Re: [systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages
On Tue, Sep 14, 2021 at 4:08 AM Ryan McClue wrote: > I understand this is slightly off-topic, but I'm completely new to BPF. > Analyzing libudev source and Internet I understand the general idea. > However, I don't understand how information/what information is passed to > the filter from the socket. For example, in my case the socket payload, > i.e. buf_str = > *add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/event14* > 1. How do I pass this string to the *sock_filter/sock_fprog* structures? > As far as I know – you don't. Once you attach the filter to the socket, it automatically gets invoked with each packet's payload as the input (whatever counts as "input" for BPF, I'm not entirely sure), and you don't need to pass anything anywhere manually. Note that this is not eBPF but the traditional cBPF that's used e.g. by tcpdump/libpcap. > 2. Is a correct way of filtering these to implement string parsing to > check for '/event' sub-string in EPF bytecode? > See sd_device_monitor_filter_update() in src/libsystemd/sd-device/device-monitor.c (nowadays, sd-device has all the interesting code, while libudev is a thin wrapper around it). -- Mantas Mikulėnas
Re: [systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages
I understand this is slightly off-topic, but I'm completely new to BPF. Analyzing libudev source and Internet I understand the general idea. However, I don't understand how information/what information is passed to the filter from the socket. For example, in my case the socket payload, i.e. buf_str = add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/event14 1. How do I pass this string to the sock_filter/sock_fprog structures? 2. Is a correct way of filtering these to implement string parsing to check for '/event' sub-string in EPF bytecode? I completely agree that using libudev is the way to go (and *a lot* more sane), however this is for my own understanding. Just by investigating this I have found out more about how udev works and now BPF. ‐‐‐ Original Message ‐‐‐ On Monday, September 13th, 2021 at 7:57 PM, Mantas Mikulėnas wrote: > On Mon, Sep 13, 2021 at 12:29 PM Ryan McClue wrote: > >> Currently, I'm listening to NETLINK_KOBJECT_UEVENT messages with the >> following code: >> >> union UeventBuffer { >> struct nlmsghdr netlink_header; >> char raw[8192]; >> }; >> int sock = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, >> NETLINK_KOBJECT_UEVENT); >> >> struct sockaddr_nl addr = {}; >> addr.nl_family = AF_NETLINK; >> addr.nl_groups = 1 << 0; >> bind(sock, (struct sockaddr *), sizeof(addr)); >> >> UeventBuffer buf = {}; >> struct iovec iov = {}; >> iov.iov_base = >> iov.iov_len = sizeof(buf); >> >> struct msghdr msg = {}; >> struct sockaddr_nl src_addr = {}; >> msg.msg_name = _addr; >> msg.msg_namelen = sizeof(src_addr); >> msg.msg_iov = >> msg.msg_iovlen = 1; >> >> int bytes = recvmsg(sock, , 0); >> char *buf_str = buf.raw; >> // parse this buf_str ... >> >> I have a few questions to clarify my understanding and to make this more >> robust: >> 1. If I add an Xbox One controller, which evtest shows to be >> /dev/input/event14 I get a whole host of messages, e.g: >> add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0 >> add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38 >> add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/event14 >> add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/js0 >> bind@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0 >> add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.1 >> add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.2 >> bind@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4 >> add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.2 >> change@/devices/pci:00/:00:14.0/usb1/1-2/1-2.2 >> Why so many? > > It represents the actual device and subsystem layering in Linux – first > there's a USB device (on hub 1-2 port 4), then USB interfaces on that device > (1.0 to 1.2), then an input-layer device (input38), then two different /dev > nodes exposed by it (generic evdev and what I *think* is legacy joydev? Not > sure if it's "legacy" or "still current".) > > They are necessary; for example, the 1st event that informs systemd-udevd > about the low-level USB device is what causes the correct device driver > module to be loaded in the first place. > >> Can I filter them to just get the ones ending with /input/inputXX/eventXX? > > It seems you're supposed to use BPF filters via SO_ATTACH_FILTER; at least > that's what libudev does. > >> 2. Currently this only picks up input devices. How would I listen to /snd >> devices, /hid devices, etc.? I assume some change to nl_groups, however what >> should this be and where is this documented? > > There's just one group for all events. > > (If I remember correctly, group 1 has all events straight from the kernel, > group 2 is the same events augmented and retransmitted by udev. Normally > programs want the latter. Both have the same events and include all devices, > though.) > >> 3. Currently, I'm manually parsing the buf_str to extract the command and >> device. Are there some supplied macros that parse this information in a more >> robust way? (as is the case for RTNETLINK) > > Well, systemd supplies a whole libudev library, so I would generally > recommend using that – *instead of* manually working with netlink... (Or more > recently sd-device, but I don't think libudev is likely to be going *poof* > anytime soon, especially if you're looking for compatibility with older > systems or eudev-using distros.) > > Start with udev_monitor_new_from_netlink() and use > udev_monitor_filter_add_match_*() to filter by subsystem, devtype, or some > arbitrary property, then you'll receive events already parsed. That's 3 lines > of code in comparison to your 30. > > -- > > Mantas Mikulėnas
Re: [systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages
(Added list back again) On Mon, Sep 13, 2021 at 1:55 PM Ryan McClue wrote: > Thank you for the response Mantas. > If I change the nl_groups to 2, it prints libudev a handle of times and I > then get a segfault. > In regards to this picking up all devices: if I add/remove my Bose > speakers connected with a stereo jack cable, this does not appear in the > messages. Can this be detected? > > Speakers aren't seen as a standalone device (the audio jack is really just an audio jack, not a device bus). You should be able detect when speakers are connected, but you'll do this through audio mixer events from ALSA (I'm not sure how PulseAudio does it, but something /dev/snd/control*), or alternatively through evdev (there's a /dev/input/event* node which produces SW_HEADPHONE_INSERT) – but not through device uevents. -- Mantas Mikulėnas
Re: [systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages
On Mo, 13.09.21 09:29, Ryan McClue (re.mcc...@protonmail.com) wrote: > Currently, I'm listening to NETLINK_KOBJECT_UEVENT messages with the > following code: Don't. Use the sd-device API from C. Or the old libudev API. Listening to uevents directly means you either only get the kernel's own data (i.e. no udev props added by userspace), or you'll have to reimplement the extended packet format udev uses when propagating the messages. But the latter is not really considered stable (i mean, effectively it is, we haven't changed it in years, but it's still undocumented, and we keep the liberty to change it if we must). Lennart -- Lennart Poettering, Berlin
Re: [systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages
On Mon, Sep 13, 2021 at 12:29 PM Ryan McClue wrote: > Currently, I'm listening to NETLINK_KOBJECT_UEVENT messages with the > following code: > > union UeventBuffer { > struct nlmsghdr netlink_header; > char raw[8192]; > }; > int sock = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, > NETLINK_KOBJECT_UEVENT); > > struct sockaddr_nl addr = {}; > addr.nl_family = AF_NETLINK; > addr.nl_groups = 1 << 0; > bind(sock, (struct sockaddr *), sizeof(addr)); > > UeventBuffer buf = {}; > struct iovec iov = {}; > iov.iov_base = > iov.iov_len = sizeof(buf); > > struct msghdr msg = {}; > struct sockaddr_nl src_addr = {}; > msg.msg_name = _addr; > msg.msg_namelen = sizeof(src_addr); > msg.msg_iov = > msg.msg_iovlen = 1; > > int bytes = recvmsg(sock, , 0); > char *buf_str = buf.raw; > // parse this buf_str ... > > I have a few questions to clarify my understanding and to make this more > robust: > 1. If I add an Xbox One controller, which evtest shows to be > /dev/input/event14 I get a whole host of messages, e.g: > *add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0* > > *add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38* > > *add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/event14* > > *add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/js0* > *bind@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0* > *add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.1* > *add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4/1-2.4:1.2* > *bind@/devices/pci:00/:00:14.0/usb1/1-2/1-2.4* > *add@/devices/pci:00/:00:14.0/usb1/1-2/1-2.2* > *change@/devices/pci:00/:00:14.0/usb1/1-2/1-2.2* > Why so many? > It represents the actual device and subsystem layering in Linux – first there's a USB device (on hub 1-2 port 4), then USB interfaces on that device (1.0 to 1.2), then an input-layer device (input38), then two different /dev nodes exposed by it (generic evdev and what I *think* is legacy joydev? Not sure if it's "legacy" or "still current".) They are necessary; for example, the 1st event that informs systemd-udevd about the low-level USB device is what causes the correct device driver module to be loaded in the first place. > Can I filter them to just get the ones ending with /input/inputXX/eventXX? > It seems you're supposed to use BPF filters via SO_ATTACH_FILTER; at least that's what libudev does. > 2. Currently this only picks up input devices. How would I listen to /snd > devices, /hid devices, etc.? I assume some change to nl_groups, however > what should this be and where is this documented? > There's just one group for all events. (If I remember correctly, group 1 has all events straight from the kernel, group 2 is the same events augmented and retransmitted by udev. Normally programs want the latter. Both have the same events and include all devices, though.) > 3. Currently, I'm manually parsing the *buf_str* to extract the command > and device. Are there some supplied macros that parse this information in a > more robust way? (as is the case for RTNETLINK) > Well, systemd supplies a whole libudev library, so I would generally recommend using that – *instead of* manually working with netlink... (Or more recently sd-device, but I don't think libudev is likely to be going *poof* anytime soon, especially if you're looking for compatibility with older systems or eudev-using distros.) Start with udev_monitor_new_from_netlink() and use udev_monitor_filter_add_match_*() to filter by subsystem, devtype, or some arbitrary property, then you'll receive events already parsed. That's 3 lines of code in comparison to your 30. -- Mantas Mikulėnas