Re: [systemd-devel] Filter/Parse NETLINK_KOBJECT_UEVENT Messages

2021-09-14 Thread Ryan McClue
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

2021-09-14 Thread Ryan McClue
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

2021-09-14 Thread Lennart Poettering
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

2021-09-13 Thread Mantas Mikulėnas
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

2021-09-13 Thread Ryan McClue
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

2021-09-13 Thread Mantas Mikulėnas
(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

2021-09-13 Thread Lennart Poettering
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

2021-09-13 Thread Mantas Mikulėnas
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