|
|
Log in / Subscribe / Register

Kdbus meets linux-kernel

By Jonathan Corbet
November 4, 2014
There has been a long history of attempts to put interprocess messaging systems into the Linux kernel; in general, these attempts have not gotten very far. From the beginning, though, the expectations around "kdbus," an in-kernel implementation of the widely used D-Bus mechanism, have been higher than the usual. Kdbus has been under development for more than two years, and was unveiled at linux.conf.au in January. But it had never been posted to the linux-kernel mailing list for review and, with luck, eventual inclusion — until October 29, when Greg Kroah-Hartman posted a twelve-part series for consideration.

In short, kdbus is a mechanism by which processes can find each other and exchange messages. It is meant to facilitate certain kinds of interprocess communications in a way that is both secure and reasonably fast. For those wanting details, this document covers kdbus functionality in a fairly thorough way.

A whirlwind overview

For those not wanting to read an 1800-line file, here's a brief summary. When kdbus starts up, it creates a set of device nodes under /dev/kdbus; any actions involving kdbus require opening one or more of those nodes. A "bus" is essentially a namespace within which processes can communicate with each other. A fairly normal default configuration involves a single "system" bus for communicating with privileged services, and one "user" bus for each logged-in user. The user bus would be used, for example, to allow the processes implementing the user's desktop environment to talk to each other.

While there is a single bus namespace at boot time, things need not remain that way. A set of buses exists within a kdbus "domain"; domains are organized into a hierarchy. So, for example, a container-management system would create a new domain for each container, then use a bind mount to make the appropriate subtree of /dev/kdbus available within the container. Thereafter, processes within the container can communicate with each other without having any access to communications outside of the container. There is currently no provision for using kdbus to communicate between containers.

Messages are, at their simplest, a set of bytes with no interpretation by the kernel at all. Messages can pass file descriptors between processes; the passing of sealed files and memfds is also supported. Message recipients can specify a set of sender credentials that must be supplied with a message for policy checking; those credentials are attached to the message by the kernel. There is also a built-in policy mechanism describing which processes can adopt "well-known names" and which processes can communicate with which others.

Kdbus is intended to be fast with both large and small messages. For the largest of messages, zero-copy transfer between processes is supported. Experience has shown, though, that a message must be about 512KB or larger before page-mapping tricks become cheaper than just copying the data. There is support for broadcast messages, along with a mechanism based on bloom filters for filtering out unwanted broadcasts without waking up the (uninterested) recipients.

In general, kdbus is meant to be a replacement for D-Bus that addresses the various issues that have come up with the latter over time. The goal is not to be the ultimate messaging system for all possible applications. While the kdbus developers are open to the idea of adding more functionality in the future, they are trying to keep a lid on the complexity at this stage.

Reviews

Given the (systemd-ish) origins of the kdbus code, one might well have expected the discussion to be somewhat hostile at times. In truth, while there have been concerns expressed, the discussion has remained mostly friendly and entirely technical. Developers are taking a deep look at the code and discussing how it can be improved; one cannot say that kdbus is not getting a fair hearing.

One of the initial questions was, inevitably, why does this functionality need to be in the kernel in the first place? The kernel already provides a number of interprocess communication primitives, and tools like D-Bus have successfully used them for many years. See this message from Greg for a detailed answer. In short, it comes down to performance (fewer context switches to send a message), security (the kernel can ensure that credentials passed with messages are correct), race-free operation, the ability to use buses in early boot, and more. There do seem to be legitimate reasons to want this kind of functionality built into the kernel.

Credentials

The handling of credentials drew a couple of different criticisms; the first was that credentials are checked when a message is sent — not when the connection to the bus is first created. Eric Biederman raised concerns that failure to capture credentials at open() time could lead to exploitable vulnerabilities. He did not actually point out any such vulnerabilities, though, and, in the past, such vulnerabilities have tended to be associated with later read() and write() calls. Since kdbus does not support either call on any of its file descriptors, that kind of vulnerability should not be an issue here. Still, there is some discomfort among the more security-oriented reviewers that the late capture of credentials is asking for trouble.

Another problem, raised by Andy Lutomirski, is that checking credentials at message-sending time makes privilege-separation architectures impossible:

The issue is the following: if have the privilege needed to talk to journald, I may want to enhance security by opening a connection to journald (and capture that privilege) and then drop privilege. I should still be able to talk to journald.

If that privilege is checked every time a message is sent, the ability to drop privileges in this way is lost. Kdbus developer Daniel Mack responded that, in the D-Bus world (which carries over into the kdbus design), there is no concept of "opening a connection" to a service like journald. Instead, one connects to a bus and sends messages to services; each message has to stand on its own. As Daniel put it:

This is why we have this functionality of passing over the caller creds every time a method call is made. The focus is really on the individual method call transaction, each one is individually routed, dispatched and checked for permission. Hence, it should carry individual credential information from the time the call is issued.

This particular disagreement reflects a fundamental difference in how developers see kdbus being used. It does not look like an easy one to resolve without some significant design changes on the kdbus side; any such changes would move it away from the D-Bus model and are likely to encounter resistance from the kdbus developers.

A related issue, also raised by Andy, is that the recipient of a message specifies which credential information should accompany that message. This information can include user and group IDs, process command line, control group information, capabilities, security labels, the audit session information, and more. The sender of a message has no control over whether this information is sent. Andy thinks that sending this information will lead to information leaks and security problems.

Instead, Andy said, the sending process should explicitly specify which credential information should accompany a message and that security-related requests should explicitly document what credentials are required. "Otherwise it becomes unclear what things convey privilege when, and that will lead immediately to incomprehensible security models, and that will lead to exploits." The response from kdbus developer Tom Gundersen is that "by simply connecting to the bus and sending a message to some service, you implicitly agree to passing some metadata along to the service". It allows the recipient to be sure that the necessary information will be supplied, even if the recipient's security model changes (requiring different information) in the future. Again, Andy disagrees, insisting that the provision of credentials should be a matter of negotiation between both sides.

Namespace and device issues

Both Eric and Andy also raised an entirely different set of concerns having to do with the way the domain namespace works. The decision to attach globally visible names to domains leads to some unfortunate consequences in their view. The first (and smaller) of these is that the existence of a namespace forces kdbus domains into a hierarchical structure, even though there is nothing that is actually hierarchical about them. Each domain is an independent entity with no particular relation to its parent domain outside of the naming scheme.

The real problem, though, is that a global namespace implies the need for some sort of control to keep malicious processes from polluting that namespace. That, in turn, means that creating a kdbus domain is a privileged operation. Quite a bit of work has gone into allowing unprivileged users to create containers. But if a new container cannot be given a kdbus domain without privilege, that model breaks down. Lennart Poettering acknowledged this concern in an apparently private email publicly responded to by Andy; he said that allowing unprivileged domain creation should be possible, as long as the checks for namespace collisions remain in place.

Andy's reply there was that none of the other container-oriented primitives have global names, and that there is a reason for that: avoidance of just this type of namespace collision possibility. Kdbus domains, he asserts, would be better off without the globally visible names. There would appear to be a couple of reasons why these names exist. One would be to make it easy for a privileged process to tap into any domain and watch traffic for debugging purposes. That particular need could probably be met by way of a domain pointer in each process's /proc area.

The bigger problem relates to another fundamental kdbus design decision: to base the whole thing around device nodes found in /dev. If there are kdbus devices for multiple domains in /dev, they must be organized into that directory's hierarchical namespace. Such a namespace is essentially unavoidable if the device nodes are to be available to (and, importantly, locatable by) processes in the system. For this reason, a couple of reviewers have said that the device abstraction is a mistake. Rather than implementing kdbus operations as a set of ioctl() calls on a device, perhaps kdbus should have a set of dedicated system calls that would eliminate the need for the device nodes altogether. That would also eliminate the need for a global kdbus domain namespace.

Eric expressed a related concern: the use of device nodes implies the existence of dynamically allocated device numbers. That will interfere with the checkpointing and restoring of containers, since there is no way to guarantee that the same device numbers will be available when the container is restored. That breaks a use case that works with D-Bus today, so Eric has described it as a regression.

Going forward

From one perspective, the response on the mailing list should be encouraging for the kdbus developers. While the obligatory "why do this in the kernel?" questions were asked, there does not appear to be much fundamental opposition to putting this kind of functionality into the kernel. That suggests that, sooner or later, the kernel will have an answer for users who have asked for a native messaging solution.

The form of that solution remains up in the air, though. Kdbus will clearly have to change to address the review comments that have been posted (and those yet to come); how radical that change needs to be remains to be seen. It could be that, as Alan Cox put it, "it would be far more constructive to treat the current kdbus as a proof of concept/prototype or even a draft requirements specification". Or perhaps the concerns that have been raised can be addressed with a simpler set of changes.

Either way, it does not look like the long-playing kdbus story will come to a close anytime soon. That may be frustrating for those who are waiting for this functionality to become available in a mainline kernel. But this process can only be hurried so much if the end result is to be a solution that will stand the test of time. Once kdbus goes into the kernel it will become much harder to change, so it is worth taking the time to get the interface (and its semantics) right first.

Index entries for this article
Kernelkdbus
KernelMessage passing


to post comments

Kdbus meets linux-kernel

Posted Nov 5, 2014 2:01 UTC (Wed) by riking (subscriber, #95706) [Link] (2 responses)

> Messages can pass file descriptors between processes; the passing of sealed files and memfds is also supported.
> ...
> Kdbus is intended to be fast with both large and small messages. For the largest of messages, zero-copy transfer between processes is supported. Experience has shown, though, that a message must be about 512KB or larger before page-mapping tricks become cheaper than just copying the data.

To clarify, the zero-copy mechanism *is* sealed memfd file descriptor passing.

Kdbus meets linux-kernel

Posted Nov 5, 2014 14:05 UTC (Wed) by cesarb (subscriber, #6266) [Link] (1 responses)

So, it's the sender's decision whether to zero-copy, instead of the kernel's?

Kdbus meets linux-kernel

Posted Nov 5, 2014 14:41 UTC (Wed) by dvdhrm (subscriber, #85474) [Link]

> So, it's the sender's decision whether to zero-copy, instead of the kernel's?

The sender needs to provide data in a way suitable for zero-copy. For kdbus, this means it has to be in a memfd. Whether the kernel passes this data around via the fd, or whether it inlines it into the receiver's buffer, is *not* controlled by the sender. So far, kdbus always passes data the same way it received it, though.

clarity of concept

Posted Nov 5, 2014 18:32 UTC (Wed) by tstover (guest, #56283) [Link] (42 responses)

I'm a reasonably clever developer with a "posix api oriented" view of Linux, so I simply can not be the only one who feels this way. About once a year for the last 10 years or so (how long has dbus been around?), I have one of those "let me try to understand d-bus" afternoons. I get the concept of pipes, sockets, bus, messages, etc. I use those all the time. Then somewhere in the "documentation" the high level concept jumps over into this other narrative about CORBA/COM/IDL style software componentry with mappings between object members and methods across processes with proxy objects etc. At which point I no longer want to care. "New" ideas are great, but nothing is ever "real" until it can be expressed in terms of a simple and clean C example. The idea of a device node has its drawbacks as mentioned in the article, but at least that would allow one imagine a read()/write() paradigm of some sort. Of course that would be too much clarity. Instead, I'm sure the idea is work with some type of broker object paradigm realized with 4-6 levels of abstractions, code generation, and XML for good measure. DBUS always sounds like something good. Though, when you "try to care", you end up trying to cure a head ache.

clarity of concept

Posted Nov 5, 2014 21:34 UTC (Wed) by nix (subscriber, #2304) [Link]

It's just a remote procedure call. I'm fairly sure they're C, if sunrpc is any evidence...

clarity of concept

Posted Nov 5, 2014 22:21 UTC (Wed) by hp (guest, #5220) [Link] (5 responses)

If it's any consolation it's much simpler than CORBA or COM. Go try to figure those out!

I think the gap is simply that if you haven't done UI development (GNOME, KDE, etc.) you don't see the problems dbus solves. But dbus has been successful for a reason.

What dbus helps you do is build a single UI from a swarm of processes on a single machine. That's the fundamental architecture of GNOME and KDE (and other traditional X setups, too).

This involves IPC, but also discovery and lifecycle problems. How do you locate and use a service? How do you ensure there's only one copy of a service? How do you close down all the services in a user session? Stuff like that.

dbus and its protocol are really just modeled on X11. dbus services = X selections, dbus messages = a thing you could have hacked on X client messages if you wanted to, etc. With dbus though it isn't tied to an X session and is less hacky, and so it can also be used for systemwide services and stuff.

Prior to dbus, GNOME and KDE both tried CORBA, and KDE had a dbus-like system called DCOP. dbus is really just a code cleanup of DCOP in some sense, and DCOP was a (drastic) simplification of CORBA. Both desktops were also using various hacks layered on top of the X server which were replaced by dbus. So there was a lot of prior experience and dbus was the synthesis of lessons learned.

clarity of concept

Posted Dec 26, 2014 18:25 UTC (Fri) by Ferk (guest, #100369) [Link] (4 responses)

> This involves IPC, but also discovery and lifecycle problems. How do you locate and use a service? How do you ensure there's only one copy of a service? How do you close down all the services in a user session? Stuff like that

Aren't these problems already solved by sysadmins since long time in UNIX systems?

It has been normal practice to write files in /var/run/SERVICENAME.pid to store the pid of the process.. this gives you both a way to know if it's running and a way to send a TERM signal if needed.

Also, you can use UNIX domain sockets for communication with a service, as long as the path to the socket is agreed on (I guess you have to agree on a namespace for dbus anyway.. so what would be the difference?)

Are there really problems in UI development that do not happen for system processes?

I think that the real problem is that the Linux Desktop has been from the beginning setting itself apart from the Linux Server systems. Freedesktop.org only thinks on desktop systems, it never takes into account system services, I don't see any sincere attempt to get standard that would work for all the system tools as a whole and they completely disregards the UNIX philosophy.

clarity of concept

Posted Dec 27, 2014 1:09 UTC (Sat) by pizza (subscriber, #46) [Link]

> It has been normal practice to write files in /var/run/SERVICENAME.pid to store the pid of the process.. this gives you both a way to know if it's running and a way to send a TERM signal if needed.

...Unless the process aborted uncleanly and another process got started using the same PID. (Which has happened to me more times than I can count...)

/var/run/${foo}.pid may be a common convention, but it is far from reliable. Blindly sending a signal to the contents of ${foo}.pid is just asking for trouble.

> Aren't these problems already solved by sysadmins since long time in UNIX systems?

s/already solved/sorta worked around most of the time by hacks and bandaids (except when they aren't)/

clarity of concept

Posted Dec 27, 2014 1:13 UTC (Sat) by cortana (subscriber, #24596) [Link]

Alas race conditions mean that by the time you have read the pid from the pidfile, the process may have already died and its id reused by another process.

And trawling around in /run doesn't tell my web browser how to communicate with my password manager, or my file manager how to talk with the bluetooth service.

clarity of concept

Posted Dec 27, 2014 3:26 UTC (Sat) by mathstuf (subscriber, #69389) [Link]

Don't forget that you want /var/run/$service/$service.pid so that it can't be mucked with by other users.

clarity of concept

Posted Dec 28, 2014 21:12 UTC (Sun) by flussence (guest, #85566) [Link]

> It has been normal practice to write files in /var/run/SERVICENAME.pid to store the pid of the process.. this gives you both a way to know if it's running and a way to send a TERM signal if needed.

While that works, it's far less reliable than simply having a supervisor fork the process and catching SIGCHLD when it exits - which is instantaneous, not vulnerable to pid wraparound exploits, doesn't require creating a directory per daemon to store its pid securely without root privileges...

We've already learned the hard way to stop making this mistake of putting dynamic runtime data in static files with /etc/mtab, it's long past time for the pidfile idiom to die too.

clarity of concept

Posted Nov 5, 2014 23:24 UTC (Wed) by mezcalero (subscriber, #45103) [Link] (32 responses)

Actually I think it's not too difficult to map D-Bus concepts to C (and classic UNIX) concepts in an understandable way. I mean, most programs today use C in a more or less object-oriented fashion (even though the language itself doesn't really have any syntactic sugar for that), and as D-Bus is object-oriented you can map things relatively easily.

  • What OO/D-Bus calls a "method" translates to a C "function".
  • What OO/D-Bus calls an "interface" translates to a C "struct" plus the functions you'd use to modify the struct.
  • What D-Bus calls an "object path" in a way translates in C to a pointer to a specific instance of a struct.
  • What D-Bus calls a method "signature" is really like a C signature, or function prototype if you so will.
  • What OO/D-Bus calls a "service" one could translate more or less to a UNIX socket.
  • And finally, the concept of a "bus" one could translate to a directory in the file system that multiple UNIX sockets are placed in.

Now, if you want to call a function on some other process via D-Bus, then you would do a method call, passing an object path, its interface, and the right arguments according to the method's signature, and send that to a specific service, on a specific bus.

And that's really all there is to it. If you understood C then D-Bus isn't particularly difficult. That said, libdbus-1 doesn't really help in making D-Bus digestable. Because it wanted to be a library that people should use for writing higher-level language bindings for, it is a bit too verbose I guess. In systemd we decided to provide a new D-Bus library that's supposed to be easier to use. With that in place calling a D-Bus method becomes really easy:

{
        sd_bus *bus;
        sd_bus_new_system(&bus);
        sd_bus_call_method(bus, 
                "org.freedesktop.timedate1",
                "/org/freedesktop/timedate1",
                "org.freedesktop.timedate1"
                "SetTimezone"
                NULL,
                NULL, 
                "sb",
                "Europe/Berlin",
                1);
       sd_bus_unref(bus);
}

This connects to the system bus (which is where all system services are found on), then call a method on the "org.freedesktop.timedate1" service, referencing an object by its path "/org/freedesktop/timedate1", selecting its interface "org.freedesktop.timedate1", invoking the "SetTimezone" method call. The two NULL pointers are for getting back a more verbose error on failure and for getting some other response data back. In thise case for the sake of just being an example we pass that as NULL because we aren't interested. Then, the signature of the call is "sb", meaning a string followed by a boolean. And finally, that's the wo arguments we pass.

Ignoring the fact that this example doesn't do any error checking this is really as easy as it gets. In effectively four lines of pure C code you can fire off an RPC call.

Now, D-Bus does substantially more than just what the example above shows. It has a scheme for getting notifications back from bus objects ("signals"), it knows introspection, and authentication and all that stuff. But in the essence its really as easy as the example above shows.

Hope this is useful,

Lennart

clarity of concept

Posted Nov 6, 2014 0:46 UTC (Thu) by sdalley (subscriber, #18550) [Link] (1 responses)

Thank you for this friendly and informative post!

And while I'm at it, thank you too for your part in *documenting* systemd. http://www.freedesktop.org/wiki/Software/systemd/ . I wish the networking side of Linux was documented so well and accessibly.

Stuff that's not documented can't be used by mere mortals.

clarity of concept

Posted Nov 18, 2014 17:26 UTC (Tue) by nix (subscriber, #2304) [Link]

... unless it has next to no capabilities. sysvinit, for example, could be used by mere mortals because you can hardly do anything with it, so there's hardly anything to document. :)

(Though it *is* actually documented, the documentation is hardly ever consulted because, well, who the hell changes /etc/inittab anyway?)

clarity of concept

Posted Nov 6, 2014 1:58 UTC (Thu) by lsl (subscriber, #86508) [Link] (8 responses)

Thanks, Lennart. That was definitely useful.

The stuttering on the destination, path and interface arguments stands out and immediately reminds one of the mentioned heavyweight object system things. Sure, it's cosmetic and probably makes total sense to someone accustomed to D-Bus but…yuck!

When almost every call (aside from tests) looks like that (from grepping the systemd repo), there has to be some other way…

Anyway, I will now try to actually understand D-Bus/kdbus before making any additional comments. ☺

clarity of concept

Posted Nov 6, 2014 8:37 UTC (Thu) by alexl (guest, #19068) [Link] (7 responses)

The "stuttering" is because the example is a bit simple.

The first "org.freedesktop.timedate1" is the destination process, and the "org.freedesktop." part is a java-style reverse-dns prefix to handle the fact that the namespace in dbus is global.

The "/org/freedesktop/timedate1" is the object in this process that we wish to talk to. Since this service typically only has one interesting object and we need a standardized place for it we use something similar to the destination name. It could technically be "/", but then it would be hard for the timeddate1 service to also serve other objects.

The second "org.freedesktop.timedate1" is the interface name we wish to call a method on. An object in dbus may implement several interfaces, and in this case it probably also implements the standard "org.freedesktop.DBus.Properties" and "org.freedesktop.DBus.Introspectable" interfaces too. Think of this as a namespace for the method name argument.

In this case we're just calling the "normal" methods on the timedate service, but we need to name that something and typically it gets the same name as the destination.

clarity of concept

Posted Nov 6, 2014 23:29 UTC (Thu) by iabervon (subscriber, #722) [Link] (6 responses)

It would be nice if the default interface for a service were the service's name, so you wouldn't have to say, "I want org.freedesktop.timedate1, and I want it to act like a org.freedesktop.timedate1", but could say, "I want org.freedesktop.timedate1 (and I want it to act like itself)".

I think this object path is actually a bit misguided, though. If there were two objects in this service, the most likely situation would be something like what I've got on my desktop, where I've got one clock in the local time zone and one in UTC. Paths like "/clocks/me" and "/clocks/universal" would identify different things that this service would want to manage, while leaving room for other sorts of object that the service might also want to manage (maybe /zoneinfo/Buenos_Aires, to report the system's time zone rules for Buenos Aires, so that you can send someone an iCal meeting and they'll know what you expect the UTC offset to be, in case their system's timezone data isn't the same). If you name your object based on your service name, chances are that, if you ever have a second object, it will have equal claim to that name, defeating the purpose of obligatorily having names.

clarity of concept

Posted Nov 7, 2014 1:29 UTC (Fri) by hp (guest, #5220) [Link]

You could do that as a convention in the client library (have a function that takes one name and derives the others from it). There isn't a need for a protocol change for it.

It isn't necessarily good practice for services to have one object with everything in one interface anyhow, though it's probably fine for a very simple service.

The object names are only namespaced because a single process may contain unrelated modules. For example all GTK apps could have objects available under /org/gtk.

If you know your process doesn't have multiple modules you could name an object /foo just as you can have a global variable in C called foo instead of my_namespace_foo. What is "OK" is a judgment developers have to make.

There are also cases where a strategy like naming each object with a GUID or something makes sense.

clarity of concept

Posted Nov 7, 2014 3:44 UTC (Fri) by luto (subscriber, #39314) [Link]

I actually think that the reverse anti-stuttering approach might have been better. These cases are examples where the client wants a singleton object in the context of either the running system or the desktop session. The client doesn't really give a crap what service provides the timezone object; it wants to access the timezone object.

What if there were a pseudo-service org.freedesktop.dbus.singletons with the special property that different real services could register different well-known names under the singletons service.

Then you could talk to /org/freedesktop/timedate1 in the singletons pseudo-service.

Anyway, the stuttering issue isn't really a problem, other than aesthetics.

clarity of concept

Posted Nov 11, 2014 21:34 UTC (Tue) by javispedro (guest, #83660) [Link] (3 responses)

I think D-Bus has always had problems in the design of their "broker" service. For example the "com.example.interface at /com/example/interface path" pattern is way too common in most D-Bus servers and it doesn't look right to me. I don't understand for example why one needs to create e.g. /timedate1 and /timedate2 instead of being able to create a single /timedate object which implements the multiple versioned interfaces. I suppose it has something to do with (non-namespaced) properties or similar, but it looks like a design problem.

Also, quite common operations such as e.g. "look for any/all objects implementing interface com.example.interface", which are often used in the complex IPC libraries, are missing in core D-Bus. Thus, one is forced to spawn a multitude of registrar-like daemons for every possible interface. Or, alternatively, "abuse" service names like the MPRIS specification does.

clarity of concept

Posted Nov 11, 2014 23:46 UTC (Tue) by HelloWorld (guest, #56129) [Link] (2 responses)

> I don't understand for example why one needs to create ...
One doesn't.

clarity of concept

Posted Nov 12, 2014 0:31 UTC (Wed) by javispedro (guest, #83660) [Link] (1 responses)

That's why I don't understand it :) But on any running system, I have plenty of services doing this with their object paths, e.g. polkit, udisks, nm/mm, nautilus...

clarity of concept

Posted Nov 16, 2014 21:46 UTC (Sun) by HelloWorld (guest, #56129) [Link]

I suspect that that's due to implementation details. This kind of thing is supported well by D-Bus itself, but not by languages like, say, Java.
http://stackoverflow.com/questions/2598009/method-name-co...

Perhaps similar issues led to what you're observing.

clarity of concept

Posted Nov 6, 2014 3:02 UTC (Thu) by jake (editor, #205) [Link]

Allow me to join the chorus: very useful and well explained, thanks!

jake

clarity of concept

Posted Nov 6, 2014 16:29 UTC (Thu) by atai (subscriber, #10977) [Link] (8 responses)

Now, with regards to Lennart, just hope that the new dbus library is still usable by itself, like the traditional dbus implementation, on Unix-ish systems without dependency or requiring systemd or the Linux kernel so it with the kernel patches discussed here do not turn dbus into a Linux-specific thing but just to make dbus fast on the Linux kernel.

clarity of concept

Posted Nov 6, 2014 16:47 UTC (Thu) by rahulsundaram (subscriber, #21946) [Link]

Do you realize you are replying to Lennart?

clarity of concept

Posted Nov 6, 2014 17:26 UTC (Thu) by ebassi (subscriber, #54855) [Link]

the current DBus daemon and client library still exist, and are maintained, for other OSes.

wrappers on top, like GDBus and QtDBus, either use the DBus daemon or kdbus depending on what's available.

clarity of concept

Posted Nov 6, 2014 22:05 UTC (Thu) by mezcalero (subscriber, #45103) [Link] (1 responses)

sd-bus supports both the classic dbus1 AF_UNIX transport as well as kdbus as backend. Applications written against the library should in most ways not see any difference. A couple of things won't be available on AF_UNIX though. For example, the credentials concept is much more powerful on kdbus than on AF_UNIX and we cannot emulate that on AF_UNIX.

sd-bus as a library should work fine on non-systemd systems too. A couple of things won't be available then though. For example, it offers APIs to connect to the system bus of local running OS containers, and to system busses of remote systems via SSH.

sd-bus is not portable to other kernels however. We make use of a multitude of Linux APIs, and it's not feasable really to port it, like the rest of systemd. And we will not accept patches for that.

However, this shouldn't really be a problem, as libdbus-1 and gdbus are both powerful libraries that are portable, and can also be used to talk to dbus. If portability to other OSes matters to you you can simply opt for one of those libraries.

Lennart

clarity of concept

Posted Nov 18, 2014 17:29 UTC (Tue) by nix (subscriber, #2304) [Link]

This encourages user applications to become gratuitously nonportable and seems like a bad move.

Libraries meant for general use should be portable, even if the system as a whole that they are part of is not.

clarity of concept

Posted Nov 7, 2014 11:47 UTC (Fri) by judas_iscariote (guest, #47386) [Link] (3 responses)

If developers of other unix systems have the need of such library then it is up to them to provide it, if you expect linux userspace plumbers to do the job for other systems you are fooling yourself.

That said, libdbus-1 is still available, maintained and portable, so people can use that for whatever they need. making sd_bus portable will actually be harmful and a supreme waste of time.

clarity of concept

Posted Nov 7, 2014 14:33 UTC (Fri) by foom (subscriber, #14868) [Link] (2 responses)

If they had the same api that might be true. But having two different APIs for the same thing, one easier to use only implemented in a non-portable library, the other harder to use and implemented in a portable library, is just a stupid situation to end up in. (I'd expect someone to make a portable implementation of the sdbus api.)

clarity of concept

Posted Nov 7, 2014 15:28 UTC (Fri) by ebassi (subscriber, #54855) [Link] (1 responses)

why would you port the systemd DBus API?

the GDBus and QtDBus API are already portable, thread safe, well documented, and available on various systems, if you don't want to use libdbus-1.

clarity of concept

Posted Nov 7, 2014 19:01 UTC (Fri) by krake (guest, #55996) [Link]

Indeed!

I think a lot of people are under the misconception that libdbus-1 is intended to be used by application developers.

Its main purpose is to provide the basic protocol support for usage in actual application libraries, very similar to how XCB provides basic X11 protocol support for toolkits.

And quite some of the application developer facing D-Bus libraries have moved to their own protocol implementations, e.g. to provide better integration with the target stack's capabilities.

clarity of concept

Posted Nov 9, 2014 15:16 UTC (Sun) by meyert (subscriber, #32097) [Link]

Is the handling of array of a struct still a pain, or does this become also much easier? Handling of a array of struct in libdbus is really not nice. You must use iterators everywhere...

clarity of concept

Posted Nov 11, 2014 16:13 UTC (Tue) by ceplm (subscriber, #41334) [Link] (8 responses)

I know this is completely offtopic for kDBUS, but we have now moved to the general dBUS waters anyway. And thank you for nice explanation, it makes a lot of sense.

However, one thing which have bothered me always: why is DBUS API so horribly complicated. In the good old days of DCOP (and now I don't care about that particular technology, just that the API could be way simpler) I was able to write this in KJS:

#!/usr/bin/env kjscmd

var dcop = new DCOPClient(this);
var box = new QHBox(this);
var go = new KPushButton(box);
var loc = new KLineEdit(box);

go.pixmap = StdIcons.DesktopIcon("go",32);
go.connect(go, "clicked()", this, "getWeather");

dcop.attach();
box.show();

function getWeather() {
if ( dcop.isAttached() ) {
var icn = new Image(this);
icn.pixmap = dcop.call("KWeatherService",
"WeatherService","icon(QString)", loc.text);
icn.smoothScale(32,32);
go.pixmap = icn.pixmap;
}
}

application.exec();

And that was everything I needed (including complete GUI). The call to DCOP itself was way more simple. I understand that DBUS is capable of doing way more complicated things, but why is it pushed down our throat? I just need a way how to address a simple object and method on it. So why the call you have shown couldn't be just something way more simple like:

impomrt dbus

bus = dbus.get_bus(dbus.SESSION_BUS)
bus.call('org.freedesktop.timedate1', 'SetTimezon', 'Europe/Berlin')

In the moment I don't need more than one object with one method (or few method) why do I need to deal with all this other stuff?

clarity of concept

Posted Nov 11, 2014 16:53 UTC (Tue) by nybble41 (subscriber, #55106) [Link] (6 responses)

The existing Python interface to DBUS has a few more layers than your proposal, but it doesn't seem _that_ complicated:

> import dbus
> 
> dbus.SessionBus() \
>     .get_object('org.freedesktop.timedate1', '/org/freedesktop/timedate1') \
>     .SetTimezone('Europe/Berlin', dbus_interface='org.freedesktop.timedate1')

That's three method calls, the same as your DCOP example. There are more details here: http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html#making-method-calls.

clarity of concept

Posted Nov 12, 2014 11:08 UTC (Wed) by ceplm (subscriber, #41334) [Link] (5 responses)

Which is exactly what I was trying to say: WTF we need any interfaces here at all. Why cannot I have (adjusted to your exmaple):

> import dbus
>
> dbus.SessionBus().get_object('org.freedesktop.timedate1').SetTimezone('Europe/Berlin')

And of course, I would hope for some more Pythonic binding, so it would be more like.

> dbus.SessionBus.get_object('org.freedesktop.timedate1').SetTimezone('Europe/Berlin')

or perhaps

> dbus.SessionBus['org.freedesktop.timedate1'].SetTimezone('Europe/Berlin')

Why do I have to bother with interfaces at all?

Matěj

clarity of concept

Posted Nov 12, 2014 12:22 UTC (Wed) by mchapman (subscriber, #66589) [Link]

> Why do I have to bother with interfaces at all?

It's unclear whether your question is "why do I have to specify an interface" or "why does D-Bus have interfaces at all".

The first problem is, of course, just an artefact of the library you're using. You could have a D-Bus library that somehow determined what interface you wanted automatically, for instance.

As for why D-Bus has interfaces at all, the way I understand it is that it provides an additional degree of modularity. A good example of their use is the systemd D-Bus API [1]. All systemd units can be manipulated via D-Bus objects. There are features that are common to all systemd units, but there are also features that are specific to each systemd unit type. So a D-Bus object for a "service" unit, for instance, implements both the org.freedesktop.systemd1.Unit and org.freedesktop.systemd1.Service interfaces, the D-Bus object for a "socket" unit implements both the org.freedesktop.systemd1.Unit and org.freedesktop.systemd1.Socket interfaces, and so on for each of the other systemd unit types.

Now it would certainly be possible to munge all the methods and properties for Unit into each of Service, Socket, Timer, etc.... but then what about the methods and properties that are independent of systemd? Should they be merged as well? Most (or is it all?) D-Bus objects implement the org.freedesktop.DBus.Introspectable interface, for instance.

Interfaces are fundamentally just a namespacing mechanism -- you can have the same method name in two different interfaces implemented by the one object, but namespacing allow sets of methods and properties to be mixed and matched in different ways.

[1] http://www.freedesktop.org/wiki/Software/systemd/dbus/

clarity of concept

Posted Nov 16, 2014 21:23 UTC (Sun) by HelloWorld (guest, #56129) [Link] (3 responses)

> Which is exactly what I was trying to say: WTF we need any interfaces here at all.
Because that allows an object to implement multiple interfaces that contain methods of the same name but with different semantics.

There's an interesting blog post that explains why this is important:
http://existentialtype.wordpress.com/2011/04/16/modules-m...

clarity of concept

Posted Nov 17, 2014 7:16 UTC (Mon) by ceplm (subscriber, #41334) [Link] (2 responses)

I was missing a word in my rant: why we need MANDATORY interfaces? Surely they could be optional, and for large objects they could be essential (although, it could be argued that too big objects are a design bug), but why should the time zone setting object (with just a few methods) should have multiple interfaces.

clarity of concept

Posted Nov 17, 2014 11:24 UTC (Mon) by mchapman (subscriber, #66589) [Link] (1 responses)

> I was missing a word in my rant: why we need MANDATORY interfaces?

Please see my earlier post. All D-Bus objects can -- and in my experience, usually do -- implement methods and properties from multiple interfaces. Now it may be perfectly logical to have a "default" interface per object which handles unqualified names, but that seems like it's best just handled by your client library. If your client library doesn't make this easy for you, use a different one.

Anyway, this discussion is pretty moot. The D-Bus specification [1] has been around for over a decade, and although it may have its warts it works well enough most of the time. You can argue that it's wrong, but it's not going to change the fact that it already exists.

[1] http://dbus.freedesktop.org/doc/dbus-specification.html

clarity of concept

Posted Nov 17, 2014 21:37 UTC (Mon) by ceplm (subscriber, #41334) [Link]

First, of course, this discussion is completely moot, I don’t expect anything to change. However, I don’t think it is useless to discuss completely theoretical questions. Actually, I really do enjoy, that I could finally express my thoughts and doubts about the API.

Second, argument “API sucks, but it could be meliorated by library” is in my opinion just that, an admission that API sucks.

clarity of concept

Posted Nov 14, 2014 17:53 UTC (Fri) by stef0x77 (guest, #88431) [Link]

Cockpit http://cockpit-project.org/ is hands down the easiest way to use DBus. For example, log into Cockpit, and type stuff like this in your javascript console to get a taste:

proxy = cockpit.dbus('org.freedesktop.hostname1').proxy()
proxy.Hostname
proxy.SetStaticHostname('mypinkpony.local', true)

You need Cockpit 0.31 or later. See here for a full example:

http://stef.thewalter.net/using-dbus-from-javascript-in-c...

... and here for full documentation:

http://files.cockpit-project.org/guide/latest/api-cockpit...

clarity of concept

Posted Nov 13, 2014 21:16 UTC (Thu) by oak (guest, #2786) [Link]

DBUS had already in the beginning (decade ago) couple of other important philosophical differences from doing C-code (or using CORBA):
* CORBA calls are by default synchronous, like function calls, but DBUS calls are by default asynchronous. If you don't expect reply, but are just notifying something, messages are fire & forget
* Message recipients don't need to exist before being called, DBUS daemon can "auto-activate" them when messages are sent to them

Re: clarity of concept

Posted Nov 7, 2014 4:30 UTC (Fri) by ldo (guest, #40946) [Link] (1 responses)

I found it easier to make sense of it in a higher-level language, like Python, in this example.

Re: clarity of concept

Posted Nov 16, 2014 20:46 UTC (Sun) by HelloWorld (guest, #56129) [Link]

What I found rather irritating when I tried to use D-Bus from Python once was that object paths are really just glorified strings, not true object references. That's because to actually do anything with an object path, you also need to know the D-Bus connection it belongs to. And that's actually rather lame in my opinion, there's no reason to not just have a single global namespace for all objects on the bus.

Kdbus meets linux-kernel

Posted Nov 6, 2014 2:47 UTC (Thu) by quotemstr (subscriber, #45331) [Link] (5 responses)

At a fundamental level, I still don't understand what we can achieve by adding a new IPC primitive to the kernel that we can't achieve by adding a few features to AF_UNIX and a few new sendmsg flags.

Kdbus meets linux-kernel

Posted Nov 6, 2014 4:28 UTC (Thu) by Cyberax (✭ supporter ✭, #52523) [Link] (1 responses)

One of the major DBUS features is multicasting and asynchronous signals.

There were patches to add multicast to AF_UNIX sockets but the network maintainer was a major roadblock. He basically told the kdbus developers to !@ck off and use IP multicasting for it. And that he wouldn't merge kdbus no matter how well it's written.

Kdbus meets linux-kernel

Posted Nov 6, 2014 10:28 UTC (Thu) by etienne (guest, #25256) [Link]

> One of the major DBUS features is multicasting and asynchronous signals.

Just two simple questions, from a non specialist:
DBUS requests looks a bit like SNMP, and even if SNMP docs is real crap it is reasonably easy to use - what would be the major difference between them?
(It would be nice to be able to ask another computer which timezone it is living in)

Adding multicast to AF_UNIX sockets is maybe wrong, but is it really less efficient to talk over an IP sockets to localhost (some short-circuit and zero copy network drivers are already probably implemented, isn't it)?

Kdbus meets linux-kernel

Posted Nov 6, 2014 8:48 UTC (Thu) by alexl (guest, #19068) [Link] (2 responses)

At a fundamental level it is not needed. In fact, we have dbus implementation that are not in the kernel. All that is needed to implement such a userspace dbus is a minimal way to connect to a socket and send bits (and optionally pass fd:s).

However, being in the kernel has certain advantages:

* Routing can use less context switches
The non-kernel dbus has to do the routing in a daemon process that all
clients connect to. This means any message needs to be sent first to the
daemon and then to the target process. In the kernel we can route direct from source to target process.

* Less copying of messages
As per the above, we need to copy and parse the message into the daemon
process first, and then into the destination.

* Security verification can be done in the kernel
Atm the dbus daemon applies things like uid limits and selinux policy on
dbus messages. If this is done in the kernel there is a higher level of
trust and auditing of this.

There has been multiple tries to make dbus work in the kernel. Some have involved modifying AF_UNIX or making a new network domain that have some of the dbus semantics. However, they have all been shot down by the network subsystem maintainer with permanent NACKs. This is why this new version uses device nodes instead.

Kdbus meets linux-kernel

Posted Nov 8, 2014 22:28 UTC (Sat) by suckfish (guest, #69919) [Link]

I'm very much reminded of the situation with the tux in-kernel-HTTP-server around a decade ago.

There, putting HTTP in-kernel was proposed for reasons with much in common with those stated for kdbus.

In that case, the outcome was that over a period of some time, tux's goals were broken down into a (fairly small) set of very generic in-kernel functionality.

This was pleasantly win-win : not only was the generic functionality useful outside of HTTP-servers, from memory the result was better for HTTP usage also.

[A couple of other success stories of breaking out kernel-space primitives from complex user-space systems spring to mind also: X11 and pthreads.]

Kdbus meets linux-kernel

Posted Nov 13, 2014 21:52 UTC (Thu) by oak (guest, #2786) [Link]

From analyzing DBUS daemon on mobile devices (nearly a decade ago), I remember DBUS daemon having following performance issues:
  • Latency: context switching issue could be solved just by specifying suitably sized (smaller than default) socket buffers for the daemon.
  • Throughput: daemon did internally so much marshaling & demarshaling that instead of it being IO-bound (like it should), it was CPU bound. Has it been fixed yet to do marshal & demarshal only once per message?
  • Message buffering: this was both daemon implementation & protocol issue. Multiple processes subscribed to system status messages that could be generated in huge amounts, and recipients of those messages may get frozen e.g. by container groups.

    Until recipients read their messages, daemon buffers them, and DBUS daemon could (easily) become largest memory user in the system. After recipients were unfrozen, system spent also a lot of CPU churning through all the buffered messages, although only last one of them was relevant. In many cases D-BUS didn't return most of the memory dirtied by the buffering back to system because of DBUS allocator memory fragmentation.

    In that particular device/setup this problem could be worked around by recipients unsubscribing from those messages before they got into a situation where they could be frozen. I think proper solution would have been a new "status" message type, for which daemon would store just the last one version per recipient.

    What would happen with system kbus in similar situation, if frozen recipient is being constantly sent e.g. audio data (this was mentioned as one of the use-cases for kdbus by Greg)?


Copyright © 2014, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds