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
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
[systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages
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? Can I filter them to just get the ones ending with /input/inputXX/eventXX? 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? 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) Thank you