Vincent Bernat [Thu, 10 Jan 2013 19:23:57 +0000 (20:23 +0100)]
Mac OS X support.
This includes bond, VLAN and bridge support. Mac OS X is pretty
similar to FreeBSD except for bonding which is different. Bonding code
is stolen from ifconfig.c. Header files from XNU are
shipped because they are missing from Mac OS X developer tools.
Still missing:
- integration into launchd
- homebrew formula
- DMI part (through ioreg)
Vincent Bernat [Mon, 7 Jan 2013 20:59:32 +0000 (21:59 +0100)]
priv: mirror the exit status of the child
When exiting because the child has exited, the privileged processus
will mirror the exit status and the signal that killed the child if
any. This allows monitoring daemon like systemd to detect an
unexpected exit.
Vincent Bernat [Sun, 6 Jan 2013 23:24:31 +0000 (00:24 +0100)]
debian: provide an upstart job
lldpd daemonization seems to confuse upstart (I think this is because
it also forks the monitor process, otherwise the daemonization is
pretty classic). Therefore, when we detect we are run by
upstart (because of UPSTART_JOB variable), we raise the SIGSTOP signal
instead of daemonizing. Upstart notices it and will resume us and
consider we are ready. No more misleading fork.
Vincent Bernat [Sun, 6 Jan 2013 13:45:53 +0000 (14:45 +0100)]
build: fix generation of ChangeLog
We must be able to have one when git is not present because we include
it in dist, but we also must generate it on each release. The previous
fix would keep the ChangeLog empty or not updated. We use a PHONY
target instead (and not a real PHONY target since we cannot add it
because automake doesn't like it).
Vincent Bernat [Sun, 6 Jan 2013 10:43:33 +0000 (11:43 +0100)]
lldpcli: make readline library optional.
And improve compatibility. We should be compatible with BSD
libedit. However, we are not compatible with older versions that lack
`rl_insert_text()` and `rl_delete_text()`.
Vincent Bernat [Sun, 6 Jan 2013 09:47:21 +0000 (10:47 +0100)]
lldpcli: switch to GNU Readline.
libedit is not available on old versions of Linux distro. We try to
use Readline API instead which may be compatible with the libedit
version available in BSD.
This means that we have to write our own tokenizer. This also means
that we can make Readline optional.
Vincent Bernat [Sat, 5 Jan 2013 15:59:41 +0000 (16:59 +0100)]
configure: detect libedit without pkg-config
BSD comes with libedit shipped and without pkg-config being able to
detect it. Fallback to manual detection of the headers and check if we
can compile a program with it.
Vincent Bernat [Sat, 5 Jan 2013 12:24:10 +0000 (13:24 +0100)]
lib: add a function to retrieve a map
Some values can only take a discrete number of int values. We have a
map to display them as string. We provide this map through a function
and we also accept values from this map as string input. This is a
slight change in the API but it should be backward compatible.
Vincent Bernat [Mon, 31 Dec 2012 17:57:07 +0000 (18:57 +0100)]
*bsd: listen on PF_ROUTE socket to get interface changes
Only OpenBSD is able to filter messages. We could filter messages for
FreeBSD and NetBSD after receiving them but we don't bother doing
it. Any change will trigger a rescan of the interfaces. Since this
cannot happen more than once per second, this should be OK for most
people.
Vincent Bernat [Mon, 31 Dec 2012 17:25:42 +0000 (18:25 +0100)]
event: use a separate event timer for each port
Each port will have its own live with its own timer. If a port just
appeared, it will have its own 30 seconds timer. We also notice
changes independently on each port, so the timer is reset on each
change on a given port.
Also, as a safeguard, update port-related information every 10
minutes. We can catch changes in addresses this way (otherwise,
detecting them via netlink is noisy).
Vincent Bernat [Sun, 30 Dec 2012 18:12:52 +0000 (19:12 +0100)]
marshal: ensure that two identic structures are serialized in the same way
Because we serialized pointers unchanged and use them to track
substructures, two identic structures located at different places in
the memory were serialized as two different buffers. It is easy to use
"dummy" pointers instead of real ones and then be able to compare two
structures by serializing them and compare the resulting buffers.
However, those two structures should be calloced to make this
works. When allocating from the stack, use of designated initializers
don't mean anything about padded memory (no guarantee that it will be
set to 0).
Vincent Bernat [Sun, 23 Dec 2012 10:11:38 +0000 (11:11 +0100)]
netlink: listen to netlink changes to trigger interface updates
This allows to detect "link down" or new interfaces in a timely
manner. There is still a global event loop for sending LLDPDU to each
port (no per-port sending loop).
Vincent Bernat [Thu, 27 Dec 2012 22:25:26 +0000 (23:25 +0100)]
OpenBSD support.
With VLAN, bonding and bridge support as well. Tested with OpenBSD
5.2.
To ease porting, we also shop `netinet/if_ether.h` which is a stripped
down version of the one contained in OpenBSD (without kernel and ARP
stuff). Including correctly this header has always been a pain, even
when supporting only Linux.
Vincent Bernat [Tue, 25 Dec 2012 18:43:48 +0000 (19:43 +0100)]
Add support for FreeBSD.
lldpd is now able to run on FreeBSD (at least Debian
GNU/kFreeBSD). Adaptation to other BSD should be easy. The support is
complete and include VLAN, bridges and link aggregation.
Vincent Bernat [Tue, 25 Dec 2012 11:15:36 +0000 (12:15 +0100)]
interfaces: sending/receiving on raw interfaces is OS specific
On Linux, we can send/receive with `recvfrom()`. With BSD and the use
of BPF, we send receive from BPF buffers. Therefore, ethernet
operations are moved into `interfaces-linux.c`.
Vincent Bernat [Tue, 25 Dec 2012 10:40:06 +0000 (11:40 +0100)]
interfaces: setting up raw interface with BPF filter is OS specific
On Linux, setting up a BPF filter on an interface means using
`setsockopt()` on a raw socket. On BSD, we need to open `/dev/bpf` as
a raw socket and attach the interface to it. Therefore, physical
interface initialization cannot be abstracted.
Vincent Bernat [Mon, 24 Dec 2012 16:56:01 +0000 (17:56 +0100)]
interfaces: abstraction of interfaces/devices
To prepare support of additional OS, interfaces have been abstracted
into a proper structure. It is still expected that each OS should have
its own `update_interfaces()` that will discover interfaces and set
the appropriate `lldpd_hardware` structures. However, helper functions
have been setup with the assumption that interfaces are put in an
abstract `interfaces_device_list`. It is expected that
`update_interfaces()` build such a list with all sensible
information (VLAN, bond, bridge, drivers, ...). Once this is done,
`interfaces_helper_*` function can be called to do most of the work.
Another change is that VLAN stuff, bridge stuff and bonding stuff is
discovered only once instead of using functions each time we need to
know something. This should lower the number of ioctl call (which can
be costly on some special hardware, for example with Marvell
DSA). This also enable to discover some of those stuff through
Netlink.
Vincent Bernat [Sun, 23 Dec 2012 15:26:38 +0000 (16:26 +0100)]
netlink: fix bogus alignment warnings
The fix is stolen from XORP: we insert an intermediate cast to
`(void*)` to avoid the warning. Netlink stuff is already taking care
of the alignment issue, the compiler just doesn't know. This means
that the headers we copied from the kernel should be modified with:
sed -i -e 's/\*)(((char\*/*)(void*)(((char*/g' \
-e 's/(void\*)(void\*)/(void*)/g' include/**/*.h
Vincent Bernat [Sun, 23 Dec 2012 12:08:26 +0000 (13:08 +0100)]
marshal: respect GCC strict-aliasing rule
Strict-aliasing states that when a derefencing pointers to objects of
different types will never refer to the same memory location. A
complete explanation is available here:
http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
While `void*` is a special kind, `void**` is not. Therefore, we
respect strict-aliasing by using an intermediate variable.
Vincent Bernat [Sat, 22 Dec 2012 22:45:48 +0000 (23:45 +0100)]
interfaces: disable the use of ioctl for bridges
ioctl for bridges are not needed since 2.6.14. Moreover, they don't
play well with some drivers and they have an undefined behaviour in
32/64 bits mixed environment. Instead, we use sysfs.
Moreover, we define a new configure option `--enable-oldies` which
allows the use of those ioctl. Currently, anything not needed with a
2.6.18 kernel will be declared as oldies and disabled by default.
Vincent Bernat [Sat, 22 Dec 2012 20:14:18 +0000 (21:14 +0100)]
build: ship a include/ directory
Some (old) distributions are shipping outdated kernel headers. Some
oddities were detected in `configure` and corrected in `compat.h` but
this is cumbersome. Like `iproute`, we now ship a "complete" include/
directory containing the missing bits. It comes from a 3.6.9
kernel. Using too recent headers with too old kernel should not be a
problem. Those headers are just definition and there was not guarantee
that the kernel used to compile was the one which will be used to run.
Vincent Bernat [Sat, 22 Dec 2012 19:25:23 +0000 (20:25 +0100)]
interfaces: harmonize arguments of detection functions
Some detection functions were requiring a name, other an index. We
always use a `struct netlink_interface`. The only drawback is that
those functions can only be called in the context where this structure
exists, i.e when discovering interfaces. In the case of bonding, we
used one function to detect if the interface was active. We replace
this by an unconditional replacement of the source MAC address by 0.
Vincent Bernat [Sat, 22 Dec 2012 19:23:07 +0000 (20:23 +0100)]
lldpd: fix debug message when discarding a received frame
There are legit reasons to discard a received frame. This happens on
bond interfaces. Fix the message to just say we have discarded a
frame, not we are not able to receive something.
Vincent Bernat [Thu, 20 Dec 2012 07:28:29 +0000 (08:28 +0100)]
interfaces: switch to Netlink to gather interface-related information
Instead of using getifaddrs() which gives incomplete information, we
use Netlink which is supported since a long time. Many information are
supported by Netlink: bonding, bridging, VLAN... Unfortunately, the
degree of support depends on the version of the kernel:
- IFLA_VLAN_* stuff is available since 2.6.23 only.
- IFLA_MASTER seems to be supported since ages (at least
2.4.32). However, it does not allow to differentiate a bridge and a
bonding. It does not apply to a VLAN.
- IFLA_LINK is not sent for a VLAN before 2.6.23.
- IFLA_BRPORT_* has just landed in Linux.
- IFLA_LINKINFO and IFLA_INFO_KIND which could help detect the kind
of device are only available since 2.6.23.
So, in summary, we can't reliably use Netlink to gather VLAN, bridging
and bonding information if we want to support 2.6.18 kernels. When
2.6.23 will be the minimal version, we could do some interesting
things. Also, it seems that ethtool stuff is not available through
Netlink.
This commit also happens to prepare the support of additional OS. Only
interfaces-linux.c (and netlink.c) are now Linux specific. Adding
support for KFreeBSD should be easy enough. More code factorisation
will happen then.
Vincent Bernat [Wed, 19 Dec 2012 22:35:58 +0000 (23:35 +0100)]
build: use a simplified autogen.sh script
The previous one was fairly complete but did not manage to generate
what was needed to get the build prepared. The bug is in autoreconf
which was calling `libtoolize` in `libevent` before doing it for the
main project. Hence, `ltmain.sh` was not found. It is still surprising
that we have such hackish build systems in 2012.
Vincent Bernat [Wed, 19 Dec 2012 21:15:27 +0000 (22:15 +0100)]
libevent: use a git submodule
Instead of shipping the whole tarball for libevent in git, just use a
submodule against the official repository. ./autogen.sh is also
updated to be able to compile it.
Vincent Bernat [Mon, 17 Dec 2012 06:48:02 +0000 (07:48 +0100)]
lldpctl: new JSON output
JSON output is done with "Jansson", a convenient JSON library. The
output may be a bit difficult to use when a multivalued field with
only one value is present. In this case, it is not put into an
array. For example, if there is only one neighbor, you get:
`{interface:{eth0: ...}}` while you will get this for two neighbors:
`{interface:[{eth0:...},{eth1:...}]}`.
Vincent Bernat [Mon, 12 Nov 2012 15:36:55 +0000 (16:36 +0100)]
lldpd: add possibility to disable LLDP
LLDP was mandatory. It is now possible to disable it entirely with
`-ll`. In this case, when no neighbor is detected, the first enabled
protocol will be used. For example, with `-ll -c`, lldpd will act as a
pure CDP daemon.