When the instance is not running (after creation or after stop), there
is no need to keep the GHashTable around.
Create it when needed (during start) and clear it during stop. This
makes it slightly cheaper to keep a NMLldpListener instance around,
if it's currently not running.
NMDevice already keeps the NMLldpListener around, even after stopping
it. It's not clear whether the instance will be started again, so also
clear the GHashTable. Also, one effect is that if you initially were in
a network with many LLDP neibors, after stop and start, the GHashTable
now gets recreated and may not need to allocate a large internal array
as before.
We already rate limit change events by two seconds. When we notice
that something changed, we call data_changed_schedule().
Previously, that would immediately issue the change notification,
if ratelimiting currently was not in effect. That means, if we happen
go receive two LLDP neighbor events in short succession, then the
first one will trigger the change notification right away, while
the second will be rate limited.
Avoid that by always issue scheduling the change notification in
the background. And if we currently are not rate limited, with
an idle handler with low priority.
This changes the order to what the code did previously, before switching
from GVariantDict to GVariantBuilder. But it changes the actually
serialized order in the variant.
GVariantDict is basically a GHashTable, and during g_variant_dict_end()
it uses a GVariantBuilder to create the variant.
This is totally unnecessary in this case. It's probably unnecessary in
most use cases, because commonly we construct variants in a determined series
of steps and don't need to add/remove keys.
Aside the overhead, GHashTable also does not give a stable sort order,
which seems a pretty bad property in this case.
Note that the code changes the order in which we call
g_variant_builder_add() for the fields in code, to preserve the previous
order that GVariantDict actually created (at least, with my version of
glib).
The intermediate parsing step serves very little purpose.
The only use is to ensure that we always add the keys in a stable
order, but we can easily ensure that otherwise.
We only need to parse them to construct the GVariant. There is
no need to keep them around otherwise.
We still keep LldpAttrs array and don't construct the GVariant right
away. The benefit is that this way while parsing we set the array
fields, and afterwards, when we generate the string dictionary, the
keys are sorted.
Move the parsing of the LLDP attributes to a separate function.
In the next step, we will no longer keep all attribute around
and no longer parse them during lldp_neighbor_new().
One effect is that we can no longer (easily) declare the LLDP message as
invalid, if parsing the attributes fails. That makes IMO more sense,
because we should try to expose what little we could parse, and not
be forgiving to unexpected data. If we wanted, we still could hide such
neighbors entirely from being exposed, but that is not done, because
it seems better to expose the parts that were valid.
We actually only need to parse the attributes while constructing
the GVariant. In a first step decouple the tracking of the parsed
attributes from LldpNeighbor struct. More will follow.
Also, track sd_lldp_neighbor instance directly.
sd_lldp_neighbor is a perfectly reasonable container for keeping
track of the LLDP neighbor information. Just keep a reference to
it, and don't clone the data. Especially since the LLDP library
keeps a reference to this instance as well.
Also, to compare whether two neighbors are the same, it is sufficient
to only consider the raw data. Everything else depends on these fields
anyway.
This is only possible and useful becuase sd_lldp_neighbor is of course
immutable. It wouldn't make sense otherwise, but it also would be bad
design to mutate the sd_lldp_neighbor instances.
This couples our code slightly more to the systemd code, which we usually
try to avoid. But when we move away in the future from systemd LLDP library,
we anyway need to rework this heavily (and then too, we wouldn't want
to clone the data, when we could just share the reference).
Allocating and growing the buffer with realloc isn't really
complicated. Do that instead of using a CList.
Also, if there is only one element, then we can track it in-place.
NM_UTILS_LOOKUP_STR_DEFINE() is implemented via a switch statement.
You'd expect that the compiler could optimize that to plain lookup,
since all indexes are consecutive numbers. Anyway, my compiler doesn't,
so use the array ourself.
Note that NM_UTILS_LOOKUP_STR_DEFINE() is exactly intended to lookup
by enum/integer, if the enum values are not consecutive numbers. It may
not be best, when you can directly use the numbers as lookup index.
VARDICT sounds like it would be a variant of "a{sv}" type. But it
can be really any GVariant. Rename to make the type more generic.
This will be used to also hold a binary variant of type "ay".
Currently the LLDP parsing code uses GVariantBuild, which possibly does not
ensure a stable order of elements. Thus the test may not be stable.
However, that will be fixed very soon.
Yes, fewer lines of code is often better, if that means the code itself is
simpler. Code doesn't get simpler by cramping more in the same line.
Have every value on a separate line.
Also, vertically align the table.
We have the correct meta-data of supported properties for nmcli. It is
in clients/common. Use that for generating the manual page instead of
the properties that are part of libnm (some properties may be in libnm
but not supported by nmcli, or some properties may not be GObject
properties, and not detected as by GObject introspection).
"nm-settings-docs-nmcli.xml" will be generated by a tool that depends on
"clients/common/". The file should thus not be in libnm directory, otherwise
there is a circular dependency.
Move the file to "man/" directory.
For consistency, also move "nm-settings-docs-dbus.xml". Note that we
cannot move "nm-settings-docs-gir.xml" to "man/", because that one is
needed for building clients.
Like the previous commit. Move code that depends on libnm out
of shared to avoid circular dependency.
Also add a readme file explaining the reason for existence of
the helper library.
Like the previous commit. Move code that depends on libnm-core out
of shared to avoid circular dependency.
Also add a readme file explaining the reason for existence of
the helper libraries nm-libnm-core-intern and nm-libnm-core-aux.
The "shared" directory is used by libnm-core, it should thus only depend on
code that is in the "shared" directory. Otherwise there is a circular
dependency, and meson's subdir() does not work nicely.
Also, libnm-core is really part of (and also an extension of) libnm-core,
so it belongs there.
I guess, the original idea was that this is also an extension for libnm,
so another project could take these utility functions (by copying them
into their source tree) and use them. That is still possible, it's
just that the sources are no longer under the shared directory.
Also add a readme to explain the non-obvious meaning of these files.
Originally, these files were part of libnm-core and linked together.
However, that is a licensing violation, because the code is GPL-2.0+
licensed, while libnm-core also gets linked with libnm (it must thus
be LGPL-2.1+). The original intent behind moving the code to "shared/"
was to avoid the licensing issue, but also to prepare when we would add
a separate, GPL licensed libnm-keyfile. However, currently we hope to
be able to relicense the code, so that it actually could be exposed as
part of libnm. This is work in progress at ([1]).
[1] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/ ## 517
Anyway, the current directory layout is problematic. libnm-keyfile
depends on libnm-core, while libnm-core depends on code under shared.
That means, there is a circular dependency and meson's subdir() does
not work well.
Move the code.
There is no need that two XML files that essentially hold similar
information are fundamentally different. Make them more alike.
This way, we can use the same tools that operate on either of
these input files.
A significant part of NetworkManager's API are the connection profiles, documented
in `man nm-settings*`. But there are different aspects about profiles, depending
on what you are interested. There is the D-Bus API, nmcli options, keyfile format,
and ifcfg-rh format. Additionally, there is also libnm API.
Add distinct manual pages for the four aspects. Currently the two new manual
pages "nm-settings-dbus" and "nm-settings-nmcli" are still identical to the
former "nm-settings.5" manual. In the future, they will diverge to
account for the differences.
There are the following aspects:
- "dbus"
- "keyfile"
- "ifcfg-rh"
- "nmcli"
For "libnm" we don't generate a separate "nm-settings-libnm" manual
page. That is instead documented via gtk-doc.
Currently the keyfile and ifcfg-rh manual pages only detail settings
which differ. But later I think also these manual pages should contain
all settings that apply.
"nm-settings-docs-dbus.xml" is "nm-settings-docs-gir.xml" merged with
"nm-property-infos-dbus.xml". The name should reflect that, also because
we will get more files with this naming scheme.
The name is bad. For one, we will have more files of the same format
("nm-settings-docs-nmcli.xml").
Also, "libnm/nm-settings-docs.xml" and "libnm/nm-property-docs.xml" had
basically the same file format. Their name should be similar.
Also the tool to generate the file should have a name that reminds to
the file that it creates.
The naming was inconsistent. Rename.
- all the property infos of this kind a now consistently called
"libnm/nm-property-infos-$TAG.xml".
- the script to generate files "libnm/nm-property-infos-$TAG.xml" is
now called "libnm/generate-docs-nm-property-infos.pl".
"man/nm-settings%.xml" really should depend on "common.ent".
The reason is that XSL files like "man/nm-settings.xsl" include
"common.ent".
The previous code already tried to express that, but for some
reasons this dependency was not honored. Fix that.
However, that uncovers another problem with gtk-doc.make. If we do
that without the workaround for "docs/api/Makefile.am", then
$ ./autogen.sh && make V=1 SHELL='sh -x' distcheck
breaks.
The reason is not clear to me. The new dependency leads to rebuild
"man/nm-settings-keyfile.xml". But that is worse, somehow the file
"$(top_srcdir)/man/nm-settings-keyfile.xml" ends up being read-only.
Afterwards, gtk-doc.make does
setup-build.stamp:
-$(GTK_DOC_V_SETUP)if test "$(abs_srcdir)" != "$(abs_builddir)" ;
then \
files=`echo $(SETUP_FILES) $(DOC_MODULE).types`; \
if test "x$$files" != "x" ; then \
for file in $$files ; do \
destdir=`dirname $(abs_builddir)/$$file`; \
test -d "$$destdir" || mkdir -p "$$destdir"; \
test -f $(abs_srcdir)/$$file && \
cp -pf $(abs_srcdir)/$$file $(abs_builddir)/$$file || true;
\
done; \
fi; \
fi
$(AM_V_at)touch setup-build.stamp
so that the files in build dir are also read-only. Then, make distcheck
goes ahead and builds the files once again, which fails.
You are welcome to understand why this workaround is necessary. Please
then create a better fix.
The script "libnm/generate-setting-docs.py" generates property info based
on GObject introspection data.
Optionally, when creating the manual for D-Bus documentation, it would accept
an argument "--override" to merge the generated information with the information
from an XML generated by "libnm/generate-plugin-docs.xml". Change this.
Instead, let "libnm/generate-setting-docs.py" just do one thing: generate
the XML based on GObject introspection data. Then, a second script
"libnm/generate-docs-nm-settings-docs-merge.py" can merge the XMLs.
Note that currently the manual for "nm-settings-keyfile" only contains
information about properties that are explicitly mentioned for keyfile.
It think that is not right. In NetworkManager there are multiple "aspects"
about connection profiles: D-Bus, libnm, nmcli, keyfile and ifcfg-rh.
When we generate a manual page for any of these aspects, we should always
detail all properties. At least for nmcli and D-Bus. That means, we will
do the merging multiple times. Hence, keep the steps for parsing GObject
introspection data and the merging separate.
Also, "generate-setting-docs.py" and "generate-plugin-docs.pl" should
generate the same XML scheme, so that merge doesn't need special hacks.
That is currently not the case, for example, the override XML contains a
"format" attribute, while the other one contains a "type". Merging these
is a special hack. This should be unified.