Commit Graph

145 Commits

Author SHA1 Message Date
Thomas Haller
22edeb5b69 core: track addresses for NMIP4Config/NMIP6Config via NMDedupMultiIndex
Reasons:

 - it adds an O(1) lookup index for accessing NMIPxConfig's addresses.
   Hence, operations like merge/intersect have now runtime O(n) instead
   of O(n^2).
   Arguably, we expect low numbers of addresses in general. For low
   numbers, the O(n^2) doesn't matter and quite likely in those cases
   the previous implementation was just fine -- maybe even faster.
   But the simple case works fine either way. It's important to scale
   well in the exceptional case.
 - the tracked objects can be shared between the various NMPI4Config,
   NMIP6Config instances with NMPlatform and everybody else.
 - the NMPObject can be treated generically, meaning it enables code to
   handle both IPv4 and IPv6, or addresses and routes. See for example
   _nm_ip_config_add_obj().
 - I want core to evolve to somewhere where we don't keep copies of
   NMPlatformIP4Address, et al. instances. Instead they shall all be
   shared. I hope this will reduce memory consumption (although tracking a
   reference consumes some memory too). Also, it shortcuts nmp_object_equal()
   when comparing the same object. Calling nmp_object_equal() on the
   identical objects would be a common case after the hash function
   pre-evaluates equality.
2017-07-25 06:44:12 +02:00
Thomas Haller
1c5d98292a c-list: add c_list_sort()
Add a stable, recursive merge sort for CList.

This could be improved by doing an iterative implementation.
The recursive implementation's stack depth is not an issue,
as it is bound by O(ln(n)). But an iterative implementation
would safe the overhead of O(n*log(n)) function calls and be
potentially faster.
2017-07-25 06:42:14 +02:00
Thomas Haller
ad5f5c81ef core: shortcut equal operator for identical object reference in NMDedupMultiIndex
And get rid of the unused obj_full_equality_allows_different_class.
It's hard to grasp how to implement different object types that can compare
despite having different klasses. The idea was, that stack allocated
objects (used as lookup needles), are some small lightweight objects,
that still compare equal to the full instance. But it's unused. Drop it.
2017-07-10 21:55:00 +02:00
Thomas Haller
930da031b2 core: fix NMDedupMultiIndex's _dict_idx_entries_hash()
Don't overwrite @h.

Fixes: f9202c2ac1
2017-07-10 21:55:00 +02:00
Thomas Haller
b2112ff471 platform: refactor NMPObject cast macros using _Generic()
This way, we also accept void pointers, while preserving constness.
2017-07-05 22:17:42 +02:00
Thomas Haller
aeaa1b3b98 platform: refactor nm_dedup_multi_objs_to_ptr_array_head()
by moving the core functionality to "nm-dedup-multi.c".

As the ref-counting mechanism now is part of "nm-dedup-multi.c",
this works better and is reusable outside of platform.
2017-07-05 18:37:39 +02:00
Thomas Haller
28340588d9 core: remove NMDedupMultiBox object and track NMDedupMultiObj instances directly
Implement the reference counting of NMPObject as part of
NMDedupMultiObj and get rid of NMDedupMultiBox.

With this change, the NMPObject is aware in which NMDedupMultiIndex
instance it is tracked.

- this saves an additional GSlice allocation for the NMDedupMultiBox.

- it is immediately known, whether an NMPObject is tracked by a
  certain NMDedupMultiIndex or not. This saves an additional hash
  lookup.

- previously, when all idx-types cease to reference an NMDedupMultiObj
  instance, it was removed. Now, a tracked objects stays in the
  NMDedupMultiIndex until it's last reference is deleted. This possibly
  extends the lifetime of the object and we may reuse it better.

- it is no longer possible to add one object to more then one
  NMDedupMultiIndex instance. As we anyway want to have only one
  instance to deduplicate the objects, this is fine.

- the ref-counting implementation is now part of NMDedupMultiObj.
  Previously, NMDedupMultiIndex could also track objects that were
  not ref-counted. Hoever, the object anyway *must* implement the
  NMDedupMultiObj API, so this flexibility is unneeded and was not
  used.

- a downside is, that NMPObject grows by one pointer size, even if
  it isn't tracked in the NMDedupMultiIndex. But we really want to
  put all objects into the index for sharing and deduplication. So
  this downside should be acceptable. Still, code like
  nmp_object_stackinit*() needs to handle a larger object.
2017-07-05 18:37:39 +02:00
Thomas Haller
55e66cc7e6 platform: implement hash function for NMPlatformLnk types 2017-07-05 18:37:39 +02:00
Thomas Haller
f9202c2ac1 shared: add NMDedupMultiIndex "nm-dedup-multi.h"
Add the NMDedupMultiIndex cache. It basically tracks
objects as doubly linked list. With the addition that
each object and the list head is indexed by a hash table.
Also, it supports tracking multiple distinct lists,
all indexed by the idx-type instance.
It also deduplicates the tracked objects and shares them.

 - the objects that can be put into the cache must be immutable
   and ref-counted. That is, the cache will deduplicate them
   and share the reference. Also, as these objects are immutable
   and ref-counted, it is safe that users outside the cache
   own them too (as long as they keep them immutable and manage
   their reference properly).

   The deduplication uses obj_id_hash_func() and obj_id_equal_func().
   These functions must cover *every* aspect of the objects when
   comparing equality. For example nm_platform_ip4_route_cmp()
   would be a function that qualifies as obj_id_equal_func().

   The cache creates references to the objects as needed and
   gives them back. This happens via obj_get_ref() and
   obj_put_ref(). Note that obj_get_ref() is free to create
   a new object, for example to convert a stack-allocated object
   to a (ref-counted) heap allocated one.

   The deduplication process creates NMDedupIndexBox instances
   which are the ref-counted entity. In principle, the objects
   themself don't need to be ref-counted as that is handled by
   the boxing instance.

 - The cache doesn't only do deduplication. It is a multi-index,
   meaning, callers add objects using a index handle NMDedupMultiIdxType.
   The NMDedupMultiIdxType instance is the access handle to lookup
   the list and objects inside the cache. Note that the idx-type
   instance may partition the objects in distinct lists.

For all operations there are cross-references and  hash table lookups.
Hence, every operation of this data structure is O(1) and the memory
overhead for an index tracking an object is constant.

The cache preserves ordering (due to linked list) and exposes the list
as public API. This allows users to iterate the list without any
additional copying of elements.
2017-07-05 14:22:10 +02:00
Thomas Haller
b8bc80bcdb all: add base object type in "nm-obj.h"
Platform has it's own, simple implementation of object types:
NMPObject. Extract a base type and move it to "shared/nm-utils/nm-obj.h"
so it can be reused.

The base type is trival, but it allows us to implement other objects
which are compatible with NMPObjects. Currently there is no API for generic
NMObjBaseInst type, so compatible in this case only means, that they
can be used in the same context (see example below).
The only thing that you can do with a NMObjBaseInst is check it's
NMObjBaseClass.

Incidentally, NMObjBaseInst is also made compatible to GTypeInstance.
It means, an NMObjBaseInst is not necessarily a valid GTypeInstance (like NMPObject
is not), but it could be implemented as such.

For example, you could do:

    if (NMP_CLASS_IS_VALID ((NMPClass *) obj->klass)) {
        /* is an NMPObject */
    } else if (G_TYPE_CHECK_INSTANCE_TYPE (obj, NM_TYPE_SOMETHING)) {
        /* it a NMSometing GType */
    } else {
        /* something else? */
    }

The reason why NMPObject is not implemented as proper GTypeInstance is
because it would require us to register a GType (like
g_type_register_fundamental). However, then the NMPClass struct can
no longer be const and immutable memory. But we could.

NMObjBaseInst may or may not be a GTypeInstance. In a sense, it's
a base type of GTypeInstance and all our objects should be based
on it (optionally, they we may make them valid GTypes too).
2017-07-05 14:22:10 +02:00
Thomas Haller
489e346e87 shared: add NM_HASH_COMBINE() function 2017-07-05 14:22:10 +02:00
Thomas Haller
26f04fd886 shared: update c-list
Reimport c-list from upstream. It allows iterating over const-list.
Upstream commit is 17e7781b3fe26e06bbe3817e8ed7418d80f63feb "build: update NEWS".
2017-07-05 14:22:10 +02:00
Thomas Haller
bb53b46bd1 shared: add nm_gstring_prepare() util 2017-06-14 14:04:57 +02:00
Thomas Haller
75f3c026eb shared/tests: expose end-time from NMTST_WAIT() macro 2017-05-31 10:46:43 +02:00
Thomas Haller
5235b1740f shared/tests: document how to disable slow tests at compile-time 2017-05-31 10:46:43 +02:00
Thomas Haller
ba05819c89 ifcfg-rh/tests: add test for reading NETMASK property 2017-05-30 11:10:19 +02:00
Yuri Chornoivan
0050e8bd34 all: fix typos in documentation, translated strings and comments
https://bugzilla.gnome.org/show_bug.cgi?id=783173
2017-05-28 17:33:37 +02:00
Thomas Haller
1056a28231 tests: extend nmtst_add_test_func() with setup and teardown functions 2017-05-27 23:16:56 +02:00
Thomas Haller
a2663803c3 shared: refactor nm_utils_is_power_of_two() to return false for 0
Returning TRUE for zero makes no sense. Obviously, zero is not a power
of two.

Also, the function is used to check whether a number has only one bit
(flag) set, so, an alternative name would be "has-one-bit-set", which
also should return FALSE for zero. All callers didn't really care for
the previous meaning "has-at-most-one-bit-set".

This also avoids the issue of checking (x >= 0), which causes
-Wtype-limits warnings for unsigned types. Which was avoided
by doing (x == 0 || x > 0), which caused -Wlogical-op warning,
which then was avoided (x == 0 || (x > 0 && 1)). Just don't.
2017-05-22 14:01:07 +02:00
Francesco Giudici
7c2ecaa4e0 build: work around GCC -Wlogical-op for "nm_utils_is_power_of_two" macros
We recently added -Wlogical-op in our build process
(commit #41e7fca59762dc928c9d67b555b1409c3477b2b0).
Seems that old versions of gcc (4.8.x) will hit that warning with our
implementation of our "nm_utils_is_power_of_two" and
"test_nm_utils_is_power_of_two_do" macros.
Fool it just adding an always TRUE check.
2017-05-22 12:05:51 +02:00
Thomas Haller
df6d27b33a shared: add nm_utils_str_utf8safe_*() API to sanitize UTF-8 strings
Use C-style backslash escaping to sanitize non-UTF-8 strings.
The functions are compatible with glib's g_strcompress() and
g_strescape().

The difference is only that g_strescape() escapes all non-printable,
non ASCII character as well, while nm_utils_str_utf8safe_escape()
-- depending on the flags -- preserves valid UTF-8 sequence except
backslash.

The flags allow to optionally escape ASCII control characters and
all non-ASCII (valid UTF-8) characters. But the option to preserve
valid UTF-8 (non-ASCII) characters verbatim, is what distinguishes
from g_strescape().
2017-05-19 09:46:08 +02:00
Thomas Haller
c15eae92c0 libnm: don't cunescape \x00 encoding in nm_udev_utils_property_decode()
UDev never creates such invalid escape sequences. Anyway,
we cannot accept a NUL character at this point. Just take
the ill escape verbatim -- it should never happen anyway.
2017-05-19 09:46:08 +02:00
Thomas Haller
9594ee6e69 libnm: fix unterminated NUL string when parsing UDev properties
This can result in trailing garbage (which fails UTF-8 validation
checks) or even worse, in read-out-of-bounds.

Fixes: 6808bf8195

https://bugzilla.redhat.com/show_bug.cgi?id=1443114
https://bugzilla.redhat.com/show_bug.cgi?id=1451160
https://bugzilla.redhat.com/show_bug.cgi?id=1451286
2017-05-19 09:46:08 +02:00
Thomas Haller
d079846330 shared: add "nm-utils/c-list.h" header
Include the circular, doubly-linked list implementation from
c-util/c-list [1], commit 864051de6e7e1c93c782064fbe3a86b4c17ac466.

[1] https://github.com/c-util/c-list
2017-05-11 18:26:07 +02:00
Thomas Haller
0893c3756e utils: fix maybe-uninitialized in "nm-udev-utils.c"
CC       shared/nm-utils/libnm_core_libnm_core_la-nm-udev-utils.lo
    In file included from ./shared/nm-utils/nm-glib.h:27:0,
                     from ./shared/nm-utils/nm-macros-internal.h:29,
                     from ./shared/nm-default.h:178,
                     from shared/nm-utils/nm-udev-utils.c:21:
    shared/nm-utils/nm-udev-utils.c: In function ‘nm_udev_client_enumerate_new’:
    ./shared/nm-utils/gsystem-local-alloc.h:53:50: error: ‘to_free’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
     GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free)
                                                      ^~~~~~
    shared/nm-utils/nm-udev-utils.c:147:18: note: ‘to_free’ was declared here
        gs_free char *to_free;
                      ^~~~~~~
    In file included from ./shared/nm-utils/nm-glib.h:27:0,
                     from ./shared/nm-utils/nm-macros-internal.h:29,
                     from ./shared/nm-default.h:178,
                     from shared/nm-utils/nm-udev-utils.c:21:
    shared/nm-utils/nm-udev-utils.c: In function ‘nm_udev_client_new’:
    ./shared/nm-utils/gsystem-local-alloc.h:53:50: error: ‘to_free’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
     GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free)
                                                      ^~~~~~
    shared/nm-utils/nm-udev-utils.c:243:20: note: ‘to_free’ was declared here
          gs_free char *to_free;
                        ^~~~~~~

Fixes: e32839838e
2017-05-10 15:34:23 +02:00
Thomas Haller
1f40bb13cf shared: cast from/to argument to unsigned for GFlags in _nm_utils_enum_get_values() 2017-04-27 18:01:58 +02:00
Beniamino Galvani
d19553392b libnm-core,shared: fix typo in '(allow-none)' annotation 2017-04-27 09:00:55 +02:00
Thomas Haller
7861ce7560 shared: add NM_PTRARRAY_EMPTY() util 2017-04-12 11:24:03 +02:00
Thomas Haller
31d0d0ef83 shared: add NM_PTRARRAY_LEN() utility macro
I used to use g_strv_length ((char **) p) instead, but that feels
ugly because it g_strv_length() is not designed to operate on
arbitrary pointer arrays.
2017-04-12 11:24:03 +02:00
Thomas Haller
9800b1dccc libnm: move public nm_utils_enum_*() functions back to libnm-core
Commit a8730c51c8 moved the enum
utils from libnm-core to shared/nm-utils.

However, three of those functions are part of public API in libnm.
So, when statically linking against "shared/nm-utils/nm-enum-utils.c"
and dynamically linking against libnm.so, those symbols are present
twice and cause a linker failure.

Fix that by moving the public API back to libnm-core.

Fixes: a8730c51c8
2017-04-05 18:38:31 +02:00
Thomas Haller
d5bcc5826e shared: move NM_UTILS_LOOKUP() macro shared utils 2017-04-05 16:53:06 +02:00
Thomas Haller
d1c6d64e6a shared: move _nm_utils_strv_cleanup() to shared utils 2017-04-05 16:53:06 +02:00
Thomas Haller
b9fa0e0a19 utils: add _nm_utils_enum_from_str_full() to support aliases 2017-03-30 13:09:58 +02:00
Thomas Haller
a8730c51c8 libnm: move enum utils to new shared file shared/nm-utils/nm-enum-utils.h
libnm contains the public function nm_utils_enum_from_str() et al.
The function is not flexible enough for nmcli's usecase. So, I would
need another public function like nm_utils_enum_from_str_full() that
has an extended API.

That was already required previously for ifcfg-rh writer, but in that
case I could just add it as internal API as libnm-core is linked statically
with NetworkManager.

I don't want to commit to a public API for an utility function. So move
the code instead to the shared directory, so that nmcli may link
statically against it and use the internal API.
2017-03-30 13:09:58 +02:00
Thomas Haller
f53218ed7c cli: add property type for enum and showcase for ipv6.addr-gen-mode 2017-03-30 13:09:58 +02:00
Thomas Haller
23298bfc88 cli: move utils function from common.h to nm-meta-setting-desc.c
These functions are only used by nm-meta-setting-desc.c. Make them internal.
Unfortunately, they are part of "common.h" which cannot be used without
the rest of nmcli. Still todo.
2017-03-30 13:09:58 +02:00
Thomas Haller
e4c0a4d0f2 shared: minor change to NM_FLAGS_HAS() and nm_utils_is_power_of_two() macros
NM_FLAGS_HAS() should reject negative flag values. So check for > 0.
Also change parentheses and line wrap.
2017-03-23 18:04:13 +01:00
Thomas Haller
6808bf8195 udev: add and use nm_udev_utils_property_decode() function
DRY.
2017-03-22 12:41:06 +01:00
Thomas Haller
c48c13b8e5 udev: only create monitor in NMUdevClient when needed
GUdevClient always creates a monitor instance, even if there are no subsystems
or handlers defined. Hence the first iteration of NMUdevClient did that as
well.

I think that can be avoided however. We only need a monitor when there is
a event handler subscribed. Contrary to GUdevClient, we know that from the
very beginning.
2017-03-22 12:41:06 +01:00
Thomas Haller
e32839838e udev: drop libgudev in favor of libudev
libgudev is just a wrapper around libudev. We can
use libudev directly and drop the dependency for
libgudev.
2017-03-22 12:41:06 +01:00
Beniamino Galvani
f4a8a7f2a6 shared: increase max number of args for _NM_UTILS_MACRO_REST
30 should be enough for anybody.
2017-03-21 18:46:52 +01:00
Thomas Haller
c59532ee40 shared: trigger -Wenum-conversion warning in NM_IN_SET*() macros
and add NM_IN_SET*_TYPED() macros, which allow to explicitly select
the type of "x".
2017-03-16 18:27:33 +01:00
Thomas Haller
c2dc1c6fa3 shared/trivial: minor style fixes in "nm-utils/nm-macros-internal.h" 2017-03-16 12:09:22 +01:00
Thomas Haller
e207e53450 all: use "static inline" instead of "inline static" 2017-03-14 11:23:46 +01:00
Thomas Haller
7d88bd24f3 shared: add _NM_GET_PRIVATE_VOID() macro
_NM_GET_PRIVATE() macro is used to implement a standard private-getter, but it
requires that "self" is a pointer of either "const type *" or "type *". That
is great in most cases, but sometimes we have predominatly self pointers of
different type, so it would require a lot of casts.

Add a different form _NM_GET_PRIVATE_VOID() where self pointer can be any
non-const pointer and returns a non-const private pointer after casting.
2017-03-10 11:06:02 +01:00
Beniamino Galvani
c55c631233 shared: add test utilities for IP routes
Add utility functions to check the value of a route attribute.
2017-03-06 15:20:25 +01:00
Thomas Haller
9a64168c87 all: use "static inline" keywords instead of "inline static"
Use a consistent order of "static inline". This seems the prefered
order in general, and we also use it more often already.
2017-02-23 15:28:27 +01:00
Thomas Haller
7e3b47deac shared: cleanup nm_strquote_a() and nm_sprintf_bufa()
- simplify nm_strquote_a().

- use '"' for quoting instad of '\''.

- have nm_sprintf_bufa() evalute @n_elements only once.
2017-02-10 17:31:16 +01:00
Thomas Haller
7d6b8bab70 all: use NM_CACHED_QUARK_FCN() instead of G_DEFINE_QUARK()
I think NM_CACHED_QUARK_FCN() is better because:

- the implementation is in our hand, meaning it is clear that
  putting a "static" before NM_CACHED_QUARK_FCN() is guaranteed to
  work -- without relying on G_DEFINE_QUARK() to be defined in a way
  that this works (in fact, we currently never do that and instead
  make all functions non-static).
- it does not construct function names by appending "_quark".
  Thus you can grep for the entire function name and finding
  the place where it is implemented.
- same with the stings, where the new macro doesn't stringify the
  argument, which is less surpising. Again, now you can grep
  for the string including the double quoting.

(yes, I really use grep to understand the source-code)
2017-02-10 14:33:52 +01:00
Thomas Haller
23040d68fc shared: add NM_CACHED_QUARK() and NM_CACHED_QUARK_FCN() macros
NM_CACHED_QUARK_FCN() is a replacement for G_DEFINE_QUARK().
G_DEFINE_QUARK() is mostly used to define GError quarks. As
such, it always appends _quark() to the function name, which
is unfavorable because it makes it harder to grep for the
definition of the function.

In general I think that macros that defined symbols by concatenating
something should be avoided because that makes it harder to locate
where the symbol was defined.
2017-02-10 14:33:52 +01:00