platform: implement NMPObject and NMPCache
NMPObject is a simple "object" implemenation around NMPlatformObject. They are ref-counted and have a class-pointer. Several basic functions like equality, hash, to-string are implemented. NMPCache is can be used to store the NMPObject. Objects are indexed via their primary id, but there is also multi-lookup via NMCacheId and NMMultiIndex. Part of the implementation is inside "nm-linux-platform.c", because it depends on utility functions from there.
This commit is contained in:
@@ -52,6 +52,9 @@ typedef enum {
|
|||||||
/* In priority order; higher number == higher priority */
|
/* In priority order; higher number == higher priority */
|
||||||
NM_IP_CONFIG_SOURCE_UNKNOWN,
|
NM_IP_CONFIG_SOURCE_UNKNOWN,
|
||||||
|
|
||||||
|
/* platform internal flag used to mark routes with RTM_F_CLONED. */
|
||||||
|
_NM_IP_CONFIG_SOURCE_RTM_F_CLONED,
|
||||||
|
|
||||||
/* platform internal flag used to mark routes with protocol RTPROT_KERNEL. */
|
/* platform internal flag used to mark routes with protocol RTPROT_KERNEL. */
|
||||||
_NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
|
_NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2013 Red Hat, Inc.
|
* Copyright (C) 2012-2015 Red Hat, Inc.
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -436,7 +436,7 @@ nm_linux_platform_setup (void)
|
|||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
|
|
||||||
static ObjectType
|
ObjectType
|
||||||
_nlo_get_object_type (const struct nl_object *object)
|
_nlo_get_object_type (const struct nl_object *object)
|
||||||
{
|
{
|
||||||
const char *type_str;
|
const char *type_str;
|
||||||
@@ -1011,6 +1011,86 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_nmp_vt_cmd_plobj_init_from_nl_link (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
|
||||||
|
{
|
||||||
|
NMPlatformLink *obj = (NMPlatformLink *) _obj;
|
||||||
|
NMPObjectLink *obj_priv = (NMPObjectLink *) _obj;
|
||||||
|
struct rtnl_link *nlo = (struct rtnl_link *) _nlo;
|
||||||
|
const char *name;
|
||||||
|
struct nl_addr *nladdr;
|
||||||
|
|
||||||
|
nm_assert (memcmp (obj, ((char [sizeof (NMPObjectLink)]) { 0 }), sizeof (NMPObjectLink)) == 0);
|
||||||
|
|
||||||
|
obj->ifindex = rtnl_link_get_ifindex (nlo);
|
||||||
|
|
||||||
|
if (id_only)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
name = rtnl_link_get_name (nlo);
|
||||||
|
if (name)
|
||||||
|
g_strlcpy (obj->name, name, sizeof (obj->name));
|
||||||
|
obj->type = link_extract_type (platform, nlo);
|
||||||
|
obj->kind = g_intern_string (rtnl_link_get_type (nlo));
|
||||||
|
obj->flags = rtnl_link_get_flags (nlo);
|
||||||
|
obj->up = NM_FLAGS_HAS (obj->flags, IFF_UP);
|
||||||
|
obj->connected = NM_FLAGS_HAS (obj->flags, IFF_LOWER_UP);
|
||||||
|
obj->arp = !NM_FLAGS_HAS (obj->flags, IFF_NOARP);
|
||||||
|
obj->master = rtnl_link_get_master (nlo);
|
||||||
|
obj->parent = rtnl_link_get_link (nlo);
|
||||||
|
obj->mtu = rtnl_link_get_mtu (nlo);
|
||||||
|
obj->arptype = rtnl_link_get_arptype (nlo);
|
||||||
|
|
||||||
|
if (obj->type == NM_LINK_TYPE_VLAN)
|
||||||
|
obj->vlan_id = rtnl_link_vlan_get_id (nlo);
|
||||||
|
|
||||||
|
if ((nladdr = rtnl_link_get_addr (nlo))) {
|
||||||
|
unsigned int l = 0;
|
||||||
|
|
||||||
|
l = nl_addr_get_len (nladdr);
|
||||||
|
if (l > 0 && l <= NM_UTILS_HWADDR_LEN_MAX) {
|
||||||
|
G_STATIC_ASSERT (NM_UTILS_HWADDR_LEN_MAX == sizeof (obj->addr.data));
|
||||||
|
memcpy (obj->addr.data, nl_addr_get_binary_addr (nladdr), l);
|
||||||
|
obj->addr.len = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
|
||||||
|
if (_support_user_ipv6ll_get ()) {
|
||||||
|
guint8 mode = 0;
|
||||||
|
|
||||||
|
if (rtnl_link_inet6_get_addr_gen_mode (nlo, &mode) == 0)
|
||||||
|
obj->inet6_addr_gen_mode_inv = ~mode;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_LIBNL_INET6_TOKEN
|
||||||
|
if ((rtnl_link_inet6_get_token (nlo, &nladdr)) == 0) {
|
||||||
|
if ( nl_addr_get_family (nladdr) == AF_INET6
|
||||||
|
&& nl_addr_get_len (nladdr) == sizeof (struct in6_addr)) {
|
||||||
|
struct in6_addr *addr;
|
||||||
|
NMUtilsIPv6IfaceId *iid = &obj->inet6_token.iid;
|
||||||
|
|
||||||
|
addr = nl_addr_get_binary_addr (nladdr);
|
||||||
|
iid->id_u8[7] = addr->s6_addr[15];
|
||||||
|
iid->id_u8[6] = addr->s6_addr[14];
|
||||||
|
iid->id_u8[5] = addr->s6_addr[13];
|
||||||
|
iid->id_u8[4] = addr->s6_addr[12];
|
||||||
|
iid->id_u8[3] = addr->s6_addr[11];
|
||||||
|
iid->id_u8[2] = addr->s6_addr[10];
|
||||||
|
iid->id_u8[1] = addr->s6_addr[9];
|
||||||
|
iid->id_u8[0] = addr->s6_addr[8];
|
||||||
|
obj->inet6_token.is_valid = TRUE;
|
||||||
|
}
|
||||||
|
nl_addr_put (nladdr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
obj_priv->netlink.is_in_netlink = TRUE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Hack: Empty bridges and bonds have IFF_LOWER_UP flag and therefore they break
|
/* Hack: Empty bridges and bonds have IFF_LOWER_UP flag and therefore they break
|
||||||
* the carrier detection. This hack makes nm-platform think they don't have the
|
* the carrier detection. This hack makes nm-platform think they don't have the
|
||||||
* IFF_LOWER_UP flag. This seems to also apply to bonds (specifically) with all
|
* IFF_LOWER_UP flag. This seems to also apply to bonds (specifically) with all
|
||||||
@@ -1194,6 +1274,66 @@ _init_ip_address_lifetime (NMPlatformIPAddress *address, const struct rtnl_addr
|
|||||||
address->preferred = _get_remaining_time (address->timestamp, a_preferred);
|
address->preferred = _get_remaining_time (address->timestamp, a_preferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static guint32
|
||||||
|
_extend_lifetime (guint32 lifetime, guint32 seconds)
|
||||||
|
{
|
||||||
|
guint64 v;
|
||||||
|
|
||||||
|
if ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT
|
||||||
|
|| seconds == 0)
|
||||||
|
return lifetime;
|
||||||
|
|
||||||
|
v = (guint64) lifetime + (guint64) seconds;
|
||||||
|
return MIN (v, NM_PLATFORM_LIFETIME_PERMANENT - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The rtnl_addr object contains relative lifetimes @valid and @preferred
|
||||||
|
* that count in seconds, starting from the moment when the kernel constructed
|
||||||
|
* the netlink message.
|
||||||
|
*
|
||||||
|
* There is also a field rtnl_addr_last_update_time(), which is the absolute
|
||||||
|
* time in 1/100th of a second of clock_gettime (CLOCK_MONOTONIC) when the address
|
||||||
|
* was modified (wrapping every 497 days).
|
||||||
|
* Immediately at the time when the address was last modified, #NOW and @last_update_time
|
||||||
|
* are the same, so (only) in that case @valid and @preferred are anchored at @last_update_time.
|
||||||
|
* However, this is not true in general. As time goes by, whenever kernel sends a new address
|
||||||
|
* via netlink, the lifetimes keep counting down.
|
||||||
|
**/
|
||||||
|
static void
|
||||||
|
_nlo_rtnl_addr_get_lifetimes (const struct rtnl_addr *rtnladdr,
|
||||||
|
guint32 *out_timestamp,
|
||||||
|
guint32 *out_lifetime,
|
||||||
|
guint32 *out_preferred)
|
||||||
|
{
|
||||||
|
guint32 timestamp = 0;
|
||||||
|
gint32 now;
|
||||||
|
guint32 lifetime = rtnl_addr_get_valid_lifetime ((struct rtnl_addr *) rtnladdr);
|
||||||
|
guint32 preferred = rtnl_addr_get_preferred_lifetime ((struct rtnl_addr *) rtnladdr);
|
||||||
|
|
||||||
|
if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT
|
||||||
|
|| preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
|
||||||
|
if (preferred > lifetime)
|
||||||
|
preferred = lifetime;
|
||||||
|
timestamp = _rtnl_addr_last_update_time_to_nm (rtnladdr, &now);
|
||||||
|
|
||||||
|
if (now == 0) {
|
||||||
|
/* strange. failed to detect the last-update time and assumed that timestamp is 1. */
|
||||||
|
nm_assert (timestamp == 1);
|
||||||
|
now = nm_utils_get_monotonic_timestamp_s ();
|
||||||
|
}
|
||||||
|
if (timestamp < now) {
|
||||||
|
guint32 diff = now - timestamp;
|
||||||
|
|
||||||
|
lifetime = _extend_lifetime (lifetime, diff);
|
||||||
|
preferred = _extend_lifetime (preferred, diff);
|
||||||
|
} else
|
||||||
|
nm_assert (timestamp == now);
|
||||||
|
}
|
||||||
|
*out_timestamp = timestamp;
|
||||||
|
*out_lifetime = lifetime;
|
||||||
|
*out_preferred = preferred;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
init_ip4_address (NMPlatformIP4Address *address, struct rtnl_addr *rtnladdr)
|
init_ip4_address (NMPlatformIP4Address *address, struct rtnl_addr *rtnladdr)
|
||||||
{
|
{
|
||||||
@@ -1229,6 +1369,44 @@ init_ip4_address (NMPlatformIP4Address *address, struct rtnl_addr *rtnladdr)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_nmp_vt_cmd_plobj_init_from_nl_ip4_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
|
||||||
|
{
|
||||||
|
NMPlatformIP4Address *obj = (NMPlatformIP4Address *) _obj;
|
||||||
|
struct rtnl_addr *nlo = (struct rtnl_addr *) _nlo;
|
||||||
|
struct nl_addr *nladdr = rtnl_addr_get_local (nlo);
|
||||||
|
struct nl_addr *nlpeer = rtnl_addr_get_peer (nlo);
|
||||||
|
const char *label;
|
||||||
|
|
||||||
|
if (!nladdr || nl_addr_get_len (nladdr) != sizeof (obj->address))
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
|
||||||
|
obj->ifindex = rtnl_addr_get_ifindex (nlo);
|
||||||
|
obj->plen = rtnl_addr_get_prefixlen (nlo);
|
||||||
|
memcpy (&obj->address, nl_addr_get_binary_addr (nladdr), sizeof (obj->address));
|
||||||
|
|
||||||
|
if (id_only)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
obj->source = NM_IP_CONFIG_SOURCE_KERNEL;
|
||||||
|
_nlo_rtnl_addr_get_lifetimes (nlo,
|
||||||
|
&obj->timestamp,
|
||||||
|
&obj->lifetime,
|
||||||
|
&obj->preferred);
|
||||||
|
if (nlpeer) {
|
||||||
|
if (nl_addr_get_len (nlpeer) != sizeof (obj->peer_address))
|
||||||
|
g_warn_if_reached ();
|
||||||
|
else
|
||||||
|
memcpy (&obj->peer_address, nl_addr_get_binary_addr (nlpeer), sizeof (obj->peer_address));
|
||||||
|
}
|
||||||
|
label = rtnl_addr_get_label (nlo);
|
||||||
|
/* Check for ':'; we're only interested in labels used as interface aliases */
|
||||||
|
if (label && strchr (label, ':'))
|
||||||
|
g_strlcpy (obj->label, label, sizeof (obj->label));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
init_ip6_address (NMPlatformIP6Address *address, struct rtnl_addr *rtnladdr)
|
init_ip6_address (NMPlatformIP6Address *address, struct rtnl_addr *rtnladdr)
|
||||||
{
|
{
|
||||||
@@ -1258,6 +1436,41 @@ init_ip6_address (NMPlatformIP6Address *address, struct rtnl_addr *rtnladdr)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_nmp_vt_cmd_plobj_init_from_nl_ip6_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
|
||||||
|
{
|
||||||
|
NMPlatformIP6Address *obj = (NMPlatformIP6Address *) _obj;
|
||||||
|
struct rtnl_addr *nlo = (struct rtnl_addr *) _nlo;
|
||||||
|
struct nl_addr *nladdr = rtnl_addr_get_local (nlo);
|
||||||
|
struct nl_addr *nlpeer = rtnl_addr_get_peer (nlo);
|
||||||
|
|
||||||
|
if (!nladdr || nl_addr_get_len (nladdr) != sizeof (obj->address))
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
|
||||||
|
obj->ifindex = rtnl_addr_get_ifindex (nlo);
|
||||||
|
obj->plen = rtnl_addr_get_prefixlen (nlo);
|
||||||
|
memcpy (&obj->address, nl_addr_get_binary_addr (nladdr), sizeof (obj->address));
|
||||||
|
|
||||||
|
if (id_only)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
obj->source = NM_IP_CONFIG_SOURCE_KERNEL;
|
||||||
|
_nlo_rtnl_addr_get_lifetimes (nlo,
|
||||||
|
&obj->timestamp,
|
||||||
|
&obj->lifetime,
|
||||||
|
&obj->preferred);
|
||||||
|
obj->flags = rtnl_addr_get_flags (nlo);
|
||||||
|
|
||||||
|
if (nlpeer) {
|
||||||
|
if (nl_addr_get_len (nlpeer) != sizeof (obj->peer_address))
|
||||||
|
g_warn_if_reached ();
|
||||||
|
else
|
||||||
|
memcpy (&obj->peer_address, nl_addr_get_binary_addr (nlpeer), sizeof (obj->peer_address));
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static guint
|
static guint
|
||||||
source_to_rtprot (NMIPConfigSource source)
|
source_to_rtprot (NMIPConfigSource source)
|
||||||
{
|
{
|
||||||
@@ -1350,6 +1563,61 @@ init_ip4_route (NMPlatformIP4Route *route, struct rtnl_route *rtnlroute)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
|
||||||
|
{
|
||||||
|
NMPlatformIP4Route *obj = (NMPlatformIP4Route *) _obj;
|
||||||
|
struct rtnl_route *nlo = (struct rtnl_route *) _nlo;
|
||||||
|
struct nl_addr *dst, *gw;
|
||||||
|
struct rtnl_nexthop *nexthop;
|
||||||
|
|
||||||
|
if (rtnl_route_get_type (nlo) != RTN_UNICAST ||
|
||||||
|
rtnl_route_get_table (nlo) != RT_TABLE_MAIN ||
|
||||||
|
rtnl_route_get_tos (nlo) != 0 ||
|
||||||
|
rtnl_route_get_nnexthops (nlo) != 1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
nexthop = rtnl_route_nexthop_n (nlo, 0);
|
||||||
|
if (!nexthop)
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
|
||||||
|
dst = rtnl_route_get_dst (nlo);
|
||||||
|
if (!dst)
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
|
||||||
|
if (nl_addr_get_len (dst)) {
|
||||||
|
if (nl_addr_get_len (dst) != sizeof (obj->network))
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
memcpy (&obj->network, nl_addr_get_binary_addr (dst), sizeof (obj->network));
|
||||||
|
}
|
||||||
|
obj->ifindex = rtnl_route_nh_get_ifindex (nexthop);
|
||||||
|
obj->plen = nl_addr_get_prefixlen (dst);
|
||||||
|
obj->metric = rtnl_route_get_priority (nlo);
|
||||||
|
obj->scope_inv = nm_platform_route_scope_inv (rtnl_route_get_scope (nlo));
|
||||||
|
|
||||||
|
gw = rtnl_route_nh_get_gateway (nexthop);
|
||||||
|
if (gw) {
|
||||||
|
if (nl_addr_get_len (gw) != sizeof (obj->gateway))
|
||||||
|
g_warn_if_reached ();
|
||||||
|
else
|
||||||
|
memcpy (&obj->gateway, nl_addr_get_binary_addr (gw), sizeof (obj->gateway));
|
||||||
|
}
|
||||||
|
rtnl_route_get_metric (nlo, RTAX_ADVMSS, &obj->mss);
|
||||||
|
if (rtnl_route_get_flags (nlo) & RTM_F_CLONED) {
|
||||||
|
/* we must not straight way reject cloned routes, because we might have cached
|
||||||
|
* a non-cloned route. If we now receive an update of the route with the route
|
||||||
|
* being cloned, we must still return the object, so that we can remove the old
|
||||||
|
* one from the cache.
|
||||||
|
*
|
||||||
|
* This happens, because this route is not nmp_object_is_alive().
|
||||||
|
* */
|
||||||
|
obj->source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED;
|
||||||
|
} else
|
||||||
|
obj->source = rtprot_to_source (rtnl_route_get_protocol (nlo), TRUE);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
init_ip6_route (NMPlatformIP6Route *route, struct rtnl_route *rtnlroute)
|
init_ip6_route (NMPlatformIP6Route *route, struct rtnl_route *rtnlroute)
|
||||||
{
|
{
|
||||||
@@ -1390,6 +1658,56 @@ init_ip6_route (NMPlatformIP6Route *route, struct rtnl_route *rtnlroute)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_nmp_vt_cmd_plobj_init_from_nl_ip6_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
|
||||||
|
{
|
||||||
|
NMPlatformIP6Route *obj = (NMPlatformIP6Route *) _obj;
|
||||||
|
struct rtnl_route *nlo = (struct rtnl_route *) _nlo;
|
||||||
|
struct nl_addr *dst, *gw;
|
||||||
|
struct rtnl_nexthop *nexthop;
|
||||||
|
|
||||||
|
if (rtnl_route_get_type (nlo) != RTN_UNICAST ||
|
||||||
|
rtnl_route_get_table (nlo) != RT_TABLE_MAIN ||
|
||||||
|
rtnl_route_get_tos (nlo) != 0 ||
|
||||||
|
rtnl_route_get_nnexthops (nlo) != 1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
nexthop = rtnl_route_nexthop_n (nlo, 0);
|
||||||
|
if (!nexthop)
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
|
||||||
|
dst = rtnl_route_get_dst (nlo);
|
||||||
|
if (!dst)
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
|
||||||
|
if (nl_addr_get_len (dst)) {
|
||||||
|
if (nl_addr_get_len (dst) != sizeof (obj->network))
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
memcpy (&obj->network, nl_addr_get_binary_addr (dst), sizeof (obj->network));
|
||||||
|
}
|
||||||
|
obj->ifindex = rtnl_route_nh_get_ifindex (nexthop);
|
||||||
|
obj->plen = nl_addr_get_prefixlen (dst);
|
||||||
|
obj->metric = rtnl_route_get_priority (nlo);
|
||||||
|
|
||||||
|
if (id_only)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
gw = rtnl_route_nh_get_gateway (nexthop);
|
||||||
|
if (gw) {
|
||||||
|
if (nl_addr_get_len (gw) != sizeof (obj->gateway))
|
||||||
|
g_warn_if_reached ();
|
||||||
|
else
|
||||||
|
memcpy (&obj->gateway, nl_addr_get_binary_addr (gw), sizeof (obj->gateway));
|
||||||
|
}
|
||||||
|
rtnl_route_get_metric (nlo, RTAX_ADVMSS, &obj->mss);
|
||||||
|
if (rtnl_route_get_flags (nlo) & RTM_F_CLONED)
|
||||||
|
obj->source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED;
|
||||||
|
else
|
||||||
|
obj->source = rtprot_to_source (rtnl_route_get_protocol (nlo), TRUE);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static char to_string_buffer[255];
|
static char to_string_buffer[255];
|
||||||
|
|
||||||
#define SET_AND_RETURN_STRING_BUFFER(...) \
|
#define SET_AND_RETURN_STRING_BUFFER(...) \
|
||||||
@@ -2296,6 +2614,16 @@ build_rtnl_link (int ifindex, const char *name, NMLinkType type)
|
|||||||
return (struct nl_object *) rtnllink;
|
return (struct nl_object *) rtnllink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nl_object *
|
||||||
|
_nmp_vt_cmd_plobj_to_nl_link (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
|
||||||
|
{
|
||||||
|
const NMPlatformLink *obj = (const NMPlatformLink *) _obj;
|
||||||
|
|
||||||
|
return build_rtnl_link (obj->ifindex,
|
||||||
|
obj->name[0] ? obj->name : NULL,
|
||||||
|
obj->type);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
link_get_by_name (NMPlatform *platform, const char *name, NMPlatformLink *out_link)
|
link_get_by_name (NMPlatform *platform, const char *name, NMPlatformLink *out_link)
|
||||||
{
|
{
|
||||||
@@ -3782,6 +4110,40 @@ build_rtnl_addr (NMPlatform *platform,
|
|||||||
return (struct nl_object *) rtnladdr_copy;
|
return (struct nl_object *) rtnladdr_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nl_object *
|
||||||
|
_nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
|
||||||
|
{
|
||||||
|
const NMPlatformIP4Address *obj = (const NMPlatformIP4Address *) _obj;
|
||||||
|
|
||||||
|
return build_rtnl_addr (platform,
|
||||||
|
AF_INET,
|
||||||
|
obj->ifindex,
|
||||||
|
&obj->address,
|
||||||
|
obj->peer_address ? &obj->peer_address : NULL,
|
||||||
|
obj->plen,
|
||||||
|
obj->lifetime,
|
||||||
|
obj->preferred,
|
||||||
|
0,
|
||||||
|
obj->label[0] ? obj->label : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nl_object *
|
||||||
|
_nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
|
||||||
|
{
|
||||||
|
const NMPlatformIP6Address *obj = (const NMPlatformIP6Address *) _obj;
|
||||||
|
|
||||||
|
return build_rtnl_addr (platform,
|
||||||
|
AF_INET6,
|
||||||
|
obj->ifindex,
|
||||||
|
&obj->address,
|
||||||
|
!IN6_IS_ADDR_UNSPECIFIED (&obj->peer_address) ? &obj->peer_address : NULL,
|
||||||
|
obj->plen,
|
||||||
|
obj->lifetime,
|
||||||
|
obj->preferred,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
ip4_address_add (NMPlatform *platform,
|
ip4_address_add (NMPlatform *platform,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
@@ -4036,6 +4398,38 @@ build_rtnl_route (int family, int ifindex, NMIPConfigSource source,
|
|||||||
return (struct nl_object *) rtnlroute;
|
return (struct nl_object *) rtnlroute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nl_object *
|
||||||
|
_nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
|
||||||
|
{
|
||||||
|
const NMPlatformIP4Route *obj = (const NMPlatformIP4Route *) _obj;
|
||||||
|
|
||||||
|
return build_rtnl_route (AF_INET,
|
||||||
|
obj->ifindex,
|
||||||
|
obj->source,
|
||||||
|
&obj->network,
|
||||||
|
obj->plen,
|
||||||
|
&obj->gateway,
|
||||||
|
NULL,
|
||||||
|
obj->metric,
|
||||||
|
obj->mss);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nl_object *
|
||||||
|
_nmp_vt_cmd_plobj_to_nl_ip6_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
|
||||||
|
{
|
||||||
|
const NMPlatformIP6Route *obj = (const NMPlatformIP6Route *) _obj;
|
||||||
|
|
||||||
|
return build_rtnl_route (AF_INET6,
|
||||||
|
obj->ifindex,
|
||||||
|
obj->source,
|
||||||
|
&obj->network,
|
||||||
|
obj->plen,
|
||||||
|
&obj->gateway,
|
||||||
|
NULL,
|
||||||
|
obj->metric,
|
||||||
|
obj->mss);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
|
ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
|
||||||
in_addr_t network, int plen, in_addr_t gateway,
|
in_addr_t network, int plen, in_addr_t gateway,
|
||||||
|
@@ -2393,6 +2393,8 @@ source_to_string (NMIPConfigSource source)
|
|||||||
switch (source) {
|
switch (source) {
|
||||||
case _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
|
case _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
|
||||||
return "rtprot-kernel";
|
return "rtprot-kernel";
|
||||||
|
case _NM_IP_CONFIG_SOURCE_RTM_F_CLONED:
|
||||||
|
return "rtm-f-cloned";
|
||||||
case NM_IP_CONFIG_SOURCE_KERNEL:
|
case NM_IP_CONFIG_SOURCE_KERNEL:
|
||||||
return "kernel";
|
return "kernel";
|
||||||
case NM_IP_CONFIG_SOURCE_SHARED:
|
case NM_IP_CONFIG_SOURCE_SHARED:
|
||||||
@@ -2844,7 +2846,11 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
|
|||||||
_CMP_FIELD (a, b, inet6_addr_gen_mode_inv);
|
_CMP_FIELD (a, b, inet6_addr_gen_mode_inv);
|
||||||
_CMP_FIELD (a, b, inet6_token.is_valid);
|
_CMP_FIELD (a, b, inet6_token.is_valid);
|
||||||
_CMP_FIELD_STR_INTERNED (a, b, kind);
|
_CMP_FIELD_STR_INTERNED (a, b, kind);
|
||||||
_CMP_FIELD_STR0 (a, b, udi);
|
|
||||||
|
/* udi is not an interned string, but NMRefString. Hence,
|
||||||
|
* do a pointer comparison first. */
|
||||||
|
_CMP_FIELD_STR_INTERNED (a, b, udi);
|
||||||
|
|
||||||
_CMP_FIELD_STR_INTERNED (a, b, driver);
|
_CMP_FIELD_STR_INTERNED (a, b, driver);
|
||||||
if (a->addr.len)
|
if (a->addr.len)
|
||||||
_CMP_FIELD_MEMCMP_LEN (a, b, addr.data, a->addr.len);
|
_CMP_FIELD_MEMCMP_LEN (a, b, addr.data, a->addr.len);
|
||||||
|
@@ -91,8 +91,10 @@ struct _NMPlatformLink {
|
|||||||
/* NMPlatform initializes this field with a static string. */
|
/* NMPlatform initializes this field with a static string. */
|
||||||
const char *kind;
|
const char *kind;
|
||||||
|
|
||||||
/* Beware: NMPlatform initializes this string with an allocated string.
|
/* Beware: NMPlatform initializes this string with an allocated string
|
||||||
* Handle it properly (i.e. don't keep a reference to it). */
|
* (NMRefString). Handle it properly (i.e. don't keep a reference to it
|
||||||
|
* without incrementing the ref-counter).
|
||||||
|
* This property depends on @initialized. */
|
||||||
const char *udi;
|
const char *udi;
|
||||||
|
|
||||||
/* NMPlatform initializes this field with a static string. */
|
/* NMPlatform initializes this field with a static string. */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,12 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "nm-platform.h"
|
#include "nm-platform.h"
|
||||||
|
#include "nm-multi-index.h"
|
||||||
|
#include "nm-macros-internal.h"
|
||||||
|
|
||||||
|
#include <netlink/netlink.h>
|
||||||
|
#include <gudev/gudev.h>
|
||||||
|
|
||||||
|
|
||||||
typedef enum { /*< skip >*/
|
typedef enum { /*< skip >*/
|
||||||
OBJECT_TYPE_UNKNOWN,
|
OBJECT_TYPE_UNKNOWN,
|
||||||
@@ -36,4 +42,342 @@ typedef enum { /*< skip >*/
|
|||||||
OBJECT_TYPE_MAX = __OBJECT_TYPE_LAST - 1,
|
OBJECT_TYPE_MAX = __OBJECT_TYPE_LAST - 1,
|
||||||
} ObjectType;
|
} ObjectType;
|
||||||
|
|
||||||
|
typedef enum { /*< skip >*/
|
||||||
|
NMP_OBJECT_TO_STRING_ID,
|
||||||
|
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||||
|
NMP_OBJECT_TO_STRING_ALL,
|
||||||
|
} NMPObjectToStringMode;
|
||||||
|
|
||||||
|
typedef enum { /*< skip >*/
|
||||||
|
NMP_CACHE_OPS_UNCHANGED = NM_PLATFORM_SIGNAL_NONE,
|
||||||
|
NMP_CACHE_OPS_UPDATED = NM_PLATFORM_SIGNAL_CHANGED,
|
||||||
|
NMP_CACHE_OPS_ADDED = NM_PLATFORM_SIGNAL_ADDED,
|
||||||
|
NMP_CACHE_OPS_REMOVED = NM_PLATFORM_SIGNAL_REMOVED,
|
||||||
|
} NMPCacheOpsType;
|
||||||
|
|
||||||
|
/* The NMPCacheIdType are the different index types.
|
||||||
|
*
|
||||||
|
* An object of a certain object-type, can be candidate to being
|
||||||
|
* indexed by a certain NMPCacheIdType or not. For example, all
|
||||||
|
* objects are indexed via an index of type NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
||||||
|
* but only route objects are indexed by NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ALL.
|
||||||
|
*
|
||||||
|
* Of one index type, there can be different indexes or not.
|
||||||
|
* For example, there is only one single instance of
|
||||||
|
* NMP_CACHE_ID_TYPE_LINKS_VISIBLE_ONLY, because this instance is
|
||||||
|
* applicable for all link objects.
|
||||||
|
* But there are different instances of NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX
|
||||||
|
* type index, which differ in v4/v6, the ifindex, and whether the index
|
||||||
|
* is for routes or address instances.
|
||||||
|
*
|
||||||
|
* But one object, can only be indexed by one particular index of one
|
||||||
|
* type. For example, a certain address instance is only indexed by
|
||||||
|
* the index NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX with matching v4/v6
|
||||||
|
* and ifindex.
|
||||||
|
* */
|
||||||
|
typedef enum { /*< skip >*/
|
||||||
|
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
||||||
|
|
||||||
|
NMP_CACHE_ID_TYPE_LINKS_VISIBLE_ONLY,
|
||||||
|
|
||||||
|
NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX,
|
||||||
|
|
||||||
|
/* three indeces for the visibile routes. */
|
||||||
|
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ALL,
|
||||||
|
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT,
|
||||||
|
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT,
|
||||||
|
|
||||||
|
__NMP_CACHE_ID_TYPE_MAX,
|
||||||
|
NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1,
|
||||||
|
} NMPCacheIdType;
|
||||||
|
|
||||||
|
typedef struct _NMPObject NMPObject;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
NMMultiIndexId base;
|
||||||
|
guint8 _id_type; /* NMPCacheIdType as guint8 */
|
||||||
|
struct {
|
||||||
|
/* NMP_CACHE_ID_TYPE_OBJECT_TYPE */
|
||||||
|
guint8 _id_type;
|
||||||
|
guint8 obj_type; /* ObjectType as guint8 */
|
||||||
|
} object_type;
|
||||||
|
struct {
|
||||||
|
/* NMP_CACHE_ID_TYPE_LINKS_VISIBLE_ONLY */
|
||||||
|
guint8 _id_type;
|
||||||
|
|
||||||
|
/* the @_global_id is only defined by it's type and has no arguments.
|
||||||
|
* It is used by NMP_CACHE_ID_TYPE_LINKS_VISIBLE_ONLY. There is only
|
||||||
|
* one single occurence of an index of this type. */
|
||||||
|
} _global_id;
|
||||||
|
struct {
|
||||||
|
/* NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX */
|
||||||
|
guint8 _id_type;
|
||||||
|
guint8 obj_type; /* ObjectType as guint8 */
|
||||||
|
int ifindex;
|
||||||
|
} addrroute_by_ifindex;
|
||||||
|
struct {
|
||||||
|
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ALL */
|
||||||
|
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT */
|
||||||
|
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT */
|
||||||
|
guint8 _id_type;
|
||||||
|
guint8 is_v4;
|
||||||
|
int ifindex;
|
||||||
|
} routes_visible;
|
||||||
|
};
|
||||||
|
} NMPCacheId;
|
||||||
|
|
||||||
|
extern NMPCacheId _nmp_cache_id_static;
|
||||||
|
#define NMP_CACHE_ID_STATIC (&_nmp_cache_id_static)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ObjectType obj_type;
|
||||||
|
int addr_family;
|
||||||
|
int rtm_gettype;
|
||||||
|
int sizeof_data;
|
||||||
|
int sizeof_public;
|
||||||
|
const char *obj_type_name;
|
||||||
|
const char *nl_type;
|
||||||
|
const char *signal_type;
|
||||||
|
|
||||||
|
/* returns %FALSE, if the obj type would never have an entry for index type @id_type. If @obj has an index,
|
||||||
|
* initialize @id and set @out_id to it. Otherwise, @out_id is NULL. */
|
||||||
|
gboolean (*cmd_obj_init_cache_id) (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id);
|
||||||
|
|
||||||
|
gboolean (*cmd_obj_equal) (const NMPObject *obj1, const NMPObject *obj2);
|
||||||
|
void (*cmd_obj_copy) (NMPObject *dst, const NMPObject *src);
|
||||||
|
void (*cmd_obj_stackinit_id) (NMPObject *obj, const NMPObject *src);
|
||||||
|
void (*cmd_obj_dispose) (NMPObject *obj);
|
||||||
|
gboolean (*cmd_obj_is_alive) (const NMPObject *obj);
|
||||||
|
gboolean (*cmd_obj_is_visible) (const NMPObject *obj);
|
||||||
|
|
||||||
|
/* functions that operate on NMPlatformObject */
|
||||||
|
gboolean (*cmd_plobj_init_from_nl) (NMPlatform *platform, NMPlatformObject *obj, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache);
|
||||||
|
struct nl_object *(*cmd_plobj_to_nl) (NMPlatform *platform, const NMPlatformObject *obj, gboolean id_only);
|
||||||
|
void (*cmd_plobj_id_copy) (NMPlatformObject *dst, const NMPlatformObject *src);
|
||||||
|
gboolean (*cmd_plobj_id_equal) (const NMPlatformObject *obj1, const NMPlatformObject *obj2);
|
||||||
|
guint (*cmd_plobj_id_hash) (const NMPlatformObject *obj);
|
||||||
|
const char *(*cmd_plobj_to_string_id) (const NMPlatformObject *obj, char *buf, gsize buf_size);
|
||||||
|
const char *(*cmd_plobj_to_string) (const NMPlatformObject *obj);
|
||||||
|
int (*cmd_plobj_cmp) (const NMPlatformObject *obj1, const NMPlatformObject *obj2);
|
||||||
|
} NMPClass;
|
||||||
|
|
||||||
|
extern const NMPClass _nmp_classes[OBJECT_TYPE_MAX];
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMPlatformLink _public;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
guint8 is_in_netlink;
|
||||||
|
} netlink;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
GUdevDevice *device;
|
||||||
|
} udev;
|
||||||
|
} NMPObjectLink;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMPlatformIP4Address _public;
|
||||||
|
} NMPObjectIP4Address;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMPlatformIP4Route _public;
|
||||||
|
} NMPObjectIP4Route;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMPlatformIP6Address _public;
|
||||||
|
} NMPObjectIP6Address;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMPlatformIP6Route _public;
|
||||||
|
} NMPObjectIP6Route;
|
||||||
|
|
||||||
|
struct _NMPObject {
|
||||||
|
const NMPClass *_class;
|
||||||
|
int _ref_count;
|
||||||
|
guint8 is_cached;
|
||||||
|
union {
|
||||||
|
NMPlatformObject object;
|
||||||
|
|
||||||
|
NMPlatformLink link;
|
||||||
|
NMPObjectLink _link;
|
||||||
|
|
||||||
|
NMPlatformIPAddress ip_address;
|
||||||
|
NMPlatformIPXAddress ipx_address;
|
||||||
|
NMPlatformIP4Address ip4_address;
|
||||||
|
NMPlatformIP6Address ip6_address;
|
||||||
|
NMPObjectIP4Address _ip4_address;
|
||||||
|
NMPObjectIP6Address _ip6_address;
|
||||||
|
|
||||||
|
NMPlatformIPRoute ip_route;
|
||||||
|
NMPlatformIPXRoute ipx_route;
|
||||||
|
NMPlatformIP4Route ip4_route;
|
||||||
|
NMPlatformIP6Route ip6_route;
|
||||||
|
NMPObjectIP4Route _ip4_route;
|
||||||
|
NMPObjectIP6Route _ip6_route;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline gboolean
|
||||||
|
NMP_CLASS_IS_VALID (const NMPClass *klass)
|
||||||
|
{
|
||||||
|
return klass >= &_nmp_classes[0]
|
||||||
|
&& klass <= &_nmp_classes[G_N_ELEMENTS (_nmp_classes)]
|
||||||
|
&& ((((char *) klass) - ((char *) NULL)) % (&_nmp_classes[1] - &_nmp_classes[0])) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NMP_REF_COUNT_STACKINIT (G_MAXINT)
|
||||||
|
|
||||||
|
static inline NMPObject *
|
||||||
|
NMP_OBJECT_UP_CAST(const NMPlatformObject *plobj)
|
||||||
|
{
|
||||||
|
NMPObject *obj;
|
||||||
|
|
||||||
|
obj = plobj
|
||||||
|
? (NMPObject *) ( &(((char *) plobj)[-((int) G_STRUCT_OFFSET (NMPObject, object))]) )
|
||||||
|
: NULL;
|
||||||
|
nm_assert (!obj || (obj->_ref_count > 0 && NMP_CLASS_IS_VALID (obj->_class)));
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
#define NMP_OBJECT_UP_CAST(plobj) (NMP_OBJECT_UP_CAST ((const NMPlatformObject *) (plobj)))
|
||||||
|
|
||||||
|
static inline gboolean
|
||||||
|
NMP_OBJECT_IS_VALID (const NMPObject *obj)
|
||||||
|
{
|
||||||
|
nm_assert (!obj || ( obj
|
||||||
|
&& obj->_ref_count > 0
|
||||||
|
&& NMP_CLASS_IS_VALID (obj->_class)));
|
||||||
|
|
||||||
|
/* There isn't really much to check. Either @obj is NULL, or we must
|
||||||
|
* assume that it points to valid memory. */
|
||||||
|
return obj != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline gboolean
|
||||||
|
NMP_OBJECT_IS_STACKINIT (const NMPObject *obj)
|
||||||
|
{
|
||||||
|
nm_assert (!obj || NMP_OBJECT_IS_VALID (obj));
|
||||||
|
|
||||||
|
return obj && obj->_ref_count == NMP_REF_COUNT_STACKINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const NMPClass *
|
||||||
|
NMP_OBJECT_GET_CLASS (const NMPObject *obj)
|
||||||
|
{
|
||||||
|
nm_assert (NMP_OBJECT_IS_VALID (obj));
|
||||||
|
|
||||||
|
return obj->_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ObjectType
|
||||||
|
NMP_OBJECT_GET_TYPE (const NMPObject *obj)
|
||||||
|
{
|
||||||
|
nm_assert (!obj || NMP_OBJECT_IS_VALID (obj));
|
||||||
|
|
||||||
|
return obj ? obj->_class->obj_type : OBJECT_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const NMPClass *nmp_class_from_type (ObjectType obj_type);
|
||||||
|
|
||||||
|
NMPObject *nmp_object_ref (NMPObject *object);
|
||||||
|
void nmp_object_unref (NMPObject *object);
|
||||||
|
NMPObject *nmp_object_new (ObjectType obj_type, const NMPlatformObject *plob);
|
||||||
|
NMPObject *nmp_object_new_link (int ifindex);
|
||||||
|
|
||||||
|
const NMPObject *nmp_object_stackinit (NMPObject *obj, ObjectType obj_type, const NMPlatformObject *plobj);
|
||||||
|
const NMPObject *nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src);
|
||||||
|
const NMPObject *nmp_object_stackinit_id_link (NMPObject *obj, int ifindex);
|
||||||
|
const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen);
|
||||||
|
const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifindex, const struct in6_addr *address, int plen);
|
||||||
|
const NMPObject *nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex, guint32 network, int plen, guint32 metric);
|
||||||
|
const NMPObject *nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, int plen, guint32 metric);
|
||||||
|
|
||||||
|
const char *nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size);
|
||||||
|
int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2);
|
||||||
|
gboolean nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2);
|
||||||
|
void nmp_object_copy (NMPObject *dst, const NMPObject *src, gboolean id_only);
|
||||||
|
NMPObject *nmp_object_clone (const NMPObject *obj, gboolean id_only);
|
||||||
|
gboolean nmp_object_id_equal (const NMPObject *obj1, const NMPObject *obj2);
|
||||||
|
guint nmp_object_id_hash (const NMPObject *obj);
|
||||||
|
gboolean nmp_object_is_alive (const NMPObject *obj);
|
||||||
|
gboolean nmp_object_is_visible (const NMPObject *obj);
|
||||||
|
|
||||||
|
void _nmp_object_fixup_link_udev_fields (NMPObject *obj, gboolean use_udev);
|
||||||
|
|
||||||
|
#define auto_nmp_obj __attribute__((cleanup(_nmp_auto_obj_cleanup)))
|
||||||
|
static inline void
|
||||||
|
_nmp_auto_obj_cleanup (NMPObject **pobj)
|
||||||
|
{
|
||||||
|
nmp_object_unref (*pobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _NMPCache NMPCache;
|
||||||
|
|
||||||
|
typedef void (*NMPCachePreHook) (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data);
|
||||||
|
typedef gboolean (*NMPObjectMatchFn) (const NMPObject *obj, gpointer user_data);
|
||||||
|
|
||||||
|
gboolean nmp_cache_id_equal (const NMPCacheId *a, const NMPCacheId *b);
|
||||||
|
guint nmp_cache_id_hash (const NMPCacheId *id);
|
||||||
|
NMPCacheId *nmp_cache_id_clone (const NMPCacheId *id);
|
||||||
|
void nmp_cache_id_destroy (NMPCacheId *id);
|
||||||
|
|
||||||
|
NMPCacheId *nmp_cache_id_init (NMPCacheId *id, NMPCacheIdType id_type);
|
||||||
|
NMPCacheId *nmp_cache_id_init_object_type (NMPCacheId *id, ObjectType obj_type);
|
||||||
|
NMPCacheId *nmp_cache_id_init_links (NMPCacheId *id, gboolean visible_only);
|
||||||
|
NMPCacheId *nmp_cache_id_init_addrroute_by_ifindex (NMPCacheId *id, ObjectType obj_type, int ifindex);
|
||||||
|
NMPCacheId *nmp_cache_id_init_routes_visible (NMPCacheId *id, NMPCacheIdType id_type, gboolean is_v4, int ifindex);
|
||||||
|
|
||||||
|
const NMPlatformObject *const *nmp_cache_lookup_multi (const NMPCache *cache, const NMPCacheId *cache_id, guint *out_len);
|
||||||
|
GArray *nmp_cache_lookup_multi_to_array (const NMPCache *cache, ObjectType obj_type, const NMPCacheId *cache_id);
|
||||||
|
const NMPObject *nmp_cache_lookup_obj (const NMPCache *cache, const NMPObject *obj);
|
||||||
|
const NMPObject *nmp_cache_lookup_link (const NMPCache *cache, int ifindex);
|
||||||
|
|
||||||
|
const NMPObject *nmp_cache_lookup_link_full (const NMPCache *cache,
|
||||||
|
int ifindex,
|
||||||
|
const char *ifname,
|
||||||
|
gboolean visible_only,
|
||||||
|
NMLinkType link_type,
|
||||||
|
NMPObjectMatchFn match_fn,
|
||||||
|
gpointer user_data);
|
||||||
|
GHashTable *nmp_cache_lookup_all_to_hash (const NMPCache *cache,
|
||||||
|
NMPCacheId *cache_id,
|
||||||
|
GHashTable *hash);
|
||||||
|
|
||||||
|
gboolean nmp_cache_link_connected_needs_toggle (const NMPCache *cache, const NMPObject *master, const NMPObject *potential_slave, const NMPObject *ignore_slave);
|
||||||
|
const NMPObject *nmp_cache_link_connected_needs_toggle_by_ifindex (const NMPCache *cache, int master_ifindex, const NMPObject *potential_slave, const NMPObject *ignore_slave);
|
||||||
|
|
||||||
|
gboolean nmp_cache_use_udev_detect (void);
|
||||||
|
gboolean nmp_cache_use_udev_get (const NMPCache *cache);
|
||||||
|
gboolean nmp_cache_use_udev_set (NMPCache *cache, gboolean use_udev);
|
||||||
|
|
||||||
|
void ASSERT_nmp_cache_is_consistent (const NMPCache *cache);
|
||||||
|
|
||||||
|
NMPCacheOpsType nmp_cache_remove (NMPCache *cache, const NMPObject *obj, gboolean equals_by_ptr, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
|
||||||
|
NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache, const NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
|
||||||
|
NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
|
||||||
|
NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_device, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
|
||||||
|
NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
|
||||||
|
|
||||||
|
NMPCache *nmp_cache_new (void);
|
||||||
|
void nmp_cache_free (NMPCache *cache);
|
||||||
|
|
||||||
|
NMPObject *nmp_object_from_nl (NMPlatform *platform, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache);
|
||||||
|
struct nl_object *nmp_object_to_nl (NMPlatform *platform, const NMPObject *obj, gboolean id_only);
|
||||||
|
|
||||||
|
/* the following functions are currently implemented inside nm-linux-platform, because
|
||||||
|
* they depend on utility functions there. */
|
||||||
|
ObjectType _nlo_get_object_type (const struct nl_object *nlo);
|
||||||
|
gboolean _nmp_vt_cmd_plobj_init_from_nl_link (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
|
||||||
|
gboolean _nmp_vt_cmd_plobj_init_from_nl_ip4_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
|
||||||
|
gboolean _nmp_vt_cmd_plobj_init_from_nl_ip6_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
|
||||||
|
gboolean _nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
|
||||||
|
gboolean _nmp_vt_cmd_plobj_init_from_nl_ip6_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
|
||||||
|
struct nl_object *_nmp_vt_cmd_plobj_to_nl_link (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||||
|
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||||
|
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||||
|
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||||
|
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||||
|
|
||||||
#endif /* __NMP_OBJECT_H__ */
|
#endif /* __NMP_OBJECT_H__ */
|
||||||
|
@@ -24,6 +24,366 @@
|
|||||||
|
|
||||||
#include "nm-test-utils.h"
|
#include "nm-test-utils.h"
|
||||||
|
|
||||||
|
struct {
|
||||||
|
GList *udev_devices;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_nmp_object_id_equal (const NMPObject *a, const NMPObject *b)
|
||||||
|
{
|
||||||
|
gboolean a_b = nmp_object_id_equal (a, b);
|
||||||
|
|
||||||
|
g_assert (NM_IN_SET (a_b, FALSE, TRUE) && a_b == nmp_object_id_equal (b, a));
|
||||||
|
return a_b;
|
||||||
|
}
|
||||||
|
#define nmp_object_id_equal _nmp_object_id_equal
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_nmp_object_equal (const NMPObject *a, const NMPObject *b)
|
||||||
|
{
|
||||||
|
gboolean a_b = nmp_object_equal (a, b);
|
||||||
|
|
||||||
|
g_assert (NM_IN_SET (a_b, FALSE, TRUE) && a_b == nmp_object_equal (b, a));
|
||||||
|
return a_b;
|
||||||
|
}
|
||||||
|
#define nmp_object_equal _nmp_object_equal
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
_assert_cache_multi_lookup_contains (const NMPCache *cache, const NMPCacheId *cache_id, const NMPObject *obj, gboolean contains)
|
||||||
|
{
|
||||||
|
const NMPlatformObject *const *objects;
|
||||||
|
guint i, len;
|
||||||
|
gboolean found;
|
||||||
|
|
||||||
|
g_assert (cache_id);
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (obj));
|
||||||
|
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, obj) == obj);
|
||||||
|
|
||||||
|
objects = nmp_cache_lookup_multi (cache, cache_id, &len);
|
||||||
|
|
||||||
|
g_assert ((len == 0 && !objects) || (len > 0 && objects && !objects[len]));
|
||||||
|
|
||||||
|
found = FALSE;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
NMPObject *o;
|
||||||
|
|
||||||
|
g_assert (objects[i]);
|
||||||
|
o = NMP_OBJECT_UP_CAST (objects[i]);
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (o));
|
||||||
|
|
||||||
|
if (obj == o) {
|
||||||
|
g_assert (!found);
|
||||||
|
found = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (!!contains == found);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMPCache *cache;
|
||||||
|
NMPCacheOpsType expected_ops_type;
|
||||||
|
const NMPObject *obj_clone;
|
||||||
|
NMPObject *new_clone;
|
||||||
|
gboolean was_visible;
|
||||||
|
gboolean called;
|
||||||
|
} _NMPCacheUpdateData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
_nmp_cache_update_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data)
|
||||||
|
{
|
||||||
|
_NMPCacheUpdateData *data = user_data;
|
||||||
|
|
||||||
|
g_assert (data);
|
||||||
|
g_assert (!data->called);
|
||||||
|
g_assert (data->cache == cache);
|
||||||
|
|
||||||
|
g_assert_cmpint (data->expected_ops_type, ==, ops_type);
|
||||||
|
|
||||||
|
switch (ops_type) {
|
||||||
|
case NMP_CACHE_OPS_ADDED:
|
||||||
|
g_assert (!old);
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (new));
|
||||||
|
g_assert (nmp_object_is_alive (new));
|
||||||
|
g_assert (nmp_object_id_equal (data->obj_clone, new));
|
||||||
|
g_assert (nmp_object_equal (data->obj_clone, new));
|
||||||
|
break;
|
||||||
|
case NMP_CACHE_OPS_UPDATED:
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (old));
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (new));
|
||||||
|
g_assert (nmp_object_is_alive (old));
|
||||||
|
g_assert (nmp_object_is_alive (new));
|
||||||
|
g_assert (nmp_object_id_equal (data->obj_clone, new));
|
||||||
|
g_assert (nmp_object_id_equal (data->obj_clone, old));
|
||||||
|
g_assert (nmp_object_id_equal (old, new));
|
||||||
|
g_assert (nmp_object_equal (data->obj_clone, new));
|
||||||
|
g_assert (!nmp_object_equal (data->obj_clone, old));
|
||||||
|
g_assert (!nmp_object_equal (old, new));
|
||||||
|
break;
|
||||||
|
case NMP_CACHE_OPS_REMOVED:
|
||||||
|
g_assert (!new);
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (old));
|
||||||
|
g_assert (nmp_object_is_alive (old));
|
||||||
|
g_assert (nmp_object_id_equal (data->obj_clone, old));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
data->was_visible = old ? nmp_object_is_visible (old) : FALSE;
|
||||||
|
data->new_clone = new ? nmp_object_clone (new, FALSE) : NULL;
|
||||||
|
data->called = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCacheOpsType expected_ops_type)
|
||||||
|
{
|
||||||
|
NMPCacheOpsType ops_type;
|
||||||
|
NMPObject *obj2;
|
||||||
|
gboolean was_visible;
|
||||||
|
auto_nmp_obj NMPObject *obj_clone = nmp_object_clone (obj, FALSE);
|
||||||
|
auto_nmp_obj NMPObject *new_clone = NULL;
|
||||||
|
const NMPObject *obj_old;
|
||||||
|
_NMPCacheUpdateData data = {
|
||||||
|
.cache = cache,
|
||||||
|
.expected_ops_type = expected_ops_type,
|
||||||
|
.obj_clone = obj_clone,
|
||||||
|
};
|
||||||
|
|
||||||
|
obj_old = nmp_cache_lookup_link (cache, obj->object.ifindex);
|
||||||
|
if (obj_old && obj_old->_link.udev.device)
|
||||||
|
obj_clone->_link.udev.device = g_object_ref (obj_old->_link.udev.device);
|
||||||
|
_nmp_object_fixup_link_udev_fields (obj_clone, nmp_cache_use_udev_get (cache));
|
||||||
|
|
||||||
|
g_assert (cache);
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (obj));
|
||||||
|
|
||||||
|
ops_type = nmp_cache_update_netlink (cache, obj, &obj2, &was_visible, _nmp_cache_update_hook, &data);
|
||||||
|
|
||||||
|
new_clone = data.new_clone;
|
||||||
|
|
||||||
|
g_assert_cmpint (ops_type, ==, expected_ops_type);
|
||||||
|
|
||||||
|
if (ops_type != NMP_CACHE_OPS_UNCHANGED) {
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (obj2));
|
||||||
|
g_assert (data.called);
|
||||||
|
g_assert_cmpint (data.was_visible, ==, was_visible);
|
||||||
|
|
||||||
|
if (ops_type == NMP_CACHE_OPS_REMOVED)
|
||||||
|
g_assert (!data.new_clone);
|
||||||
|
else {
|
||||||
|
g_assert (data.new_clone);
|
||||||
|
g_assert (nmp_object_equal (obj2, data.new_clone));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g_assert (!data.called);
|
||||||
|
g_assert (!obj2 || was_visible == nmp_object_is_visible (obj2));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (!obj2 || nmp_object_id_equal (obj, obj2));
|
||||||
|
if (ops_type != NMP_CACHE_OPS_REMOVED && obj2)
|
||||||
|
g_assert (nmp_object_equal (obj, obj2));
|
||||||
|
|
||||||
|
if (out_obj)
|
||||||
|
*out_obj = obj2;
|
||||||
|
else
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
if (out_was_visible)
|
||||||
|
*out_was_visible = was_visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const NMPlatformLink pl_link_2 = {
|
||||||
|
.ifindex = 2,
|
||||||
|
.name = "eth0",
|
||||||
|
.type = NM_LINK_TYPE_ETHERNET,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const NMPlatformLink pl_link_3 = {
|
||||||
|
.ifindex = 3,
|
||||||
|
.name = "wlan0",
|
||||||
|
.type = NM_LINK_TYPE_WIFI,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_cache_link ()
|
||||||
|
{
|
||||||
|
NMPCache *cache;
|
||||||
|
NMPObject *obj1, *obj2;
|
||||||
|
NMPObject objs1;
|
||||||
|
gboolean was_visible;
|
||||||
|
NMPCacheId cache_id_storage;
|
||||||
|
GUdevDevice *udev_device_2 = g_list_nth_data (global.udev_devices, 0);
|
||||||
|
GUdevDevice *udev_device_3 = g_list_nth_data (global.udev_devices, 0);
|
||||||
|
NMPCacheOpsType ops_type;
|
||||||
|
|
||||||
|
cache = nmp_cache_new ();
|
||||||
|
|
||||||
|
nmp_cache_use_udev_set (cache, g_rand_int_range (nmtst_get_rand (), 0, 2));
|
||||||
|
|
||||||
|
/* if we have a link, and don't set is_in_netlink, adding it has no effect. */
|
||||||
|
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
|
||||||
|
g_assert (NMP_OBJECT_UP_CAST (&obj1->object) == obj1);
|
||||||
|
g_assert (!nmp_object_is_alive (obj1));
|
||||||
|
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert (!obj2);
|
||||||
|
g_assert (!was_visible);
|
||||||
|
g_assert (!nmp_cache_lookup_obj (cache, obj1));
|
||||||
|
g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)));
|
||||||
|
nmp_object_unref (obj1);
|
||||||
|
|
||||||
|
/* Only when setting @is_in_netlink the link is added. */
|
||||||
|
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
|
||||||
|
obj1->_link.netlink.is_in_netlink = TRUE;
|
||||||
|
g_assert (nmp_object_is_alive (obj1));
|
||||||
|
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_ADDED);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert (nmp_object_equal (obj1, obj2));
|
||||||
|
g_assert (!was_visible);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
|
||||||
|
g_assert (nmp_object_is_visible (obj2));
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, TRUE);
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
|
||||||
|
nmp_object_unref (obj1);
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
|
||||||
|
/* updating the same link with identical value, has no effect. */
|
||||||
|
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
|
||||||
|
obj1->_link.netlink.is_in_netlink = TRUE;
|
||||||
|
g_assert (nmp_object_is_alive (obj1));
|
||||||
|
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert (obj2 != obj1);
|
||||||
|
g_assert (nmp_object_equal (obj1, obj2));
|
||||||
|
g_assert (was_visible);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
|
||||||
|
nmp_object_unref (obj1);
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
|
||||||
|
/* remove the link from netlink */
|
||||||
|
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
|
||||||
|
g_assert (!nmp_object_is_alive (obj1));
|
||||||
|
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_REMOVED);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert (obj2 != obj1);
|
||||||
|
g_assert (was_visible);
|
||||||
|
g_assert (!nmp_cache_lookup_obj (cache, obj1));
|
||||||
|
g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)));
|
||||||
|
nmp_object_unref (obj1);
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
|
||||||
|
udev_device_2 = NULL;
|
||||||
|
if (udev_device_2) {
|
||||||
|
/* now add the link only with aspect UDEV. */
|
||||||
|
ops_type = nmp_cache_update_link_udev (cache, pl_link_2.ifindex, udev_device_2, &obj2, &was_visible, NULL, NULL);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED);
|
||||||
|
g_assert (!was_visible);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
|
||||||
|
g_assert (!nmp_object_is_visible (obj2));
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, FALSE);
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add it in netlink too. */
|
||||||
|
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
|
||||||
|
obj1->_link.netlink.is_in_netlink = TRUE;
|
||||||
|
g_assert (nmp_object_is_alive (obj1));
|
||||||
|
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_ADDED);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert (nmp_object_equal (obj1, obj2));
|
||||||
|
g_assert (!was_visible);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
|
||||||
|
g_assert (nmp_object_is_visible (obj2));
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, TRUE);
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
|
||||||
|
nmp_object_unref (obj1);
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
|
||||||
|
/* remove again from netlink. */
|
||||||
|
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
|
||||||
|
obj1->_link.netlink.is_in_netlink = FALSE;
|
||||||
|
g_assert (!nmp_object_is_alive (obj1));
|
||||||
|
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_REMOVED);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert (obj2 != obj1);
|
||||||
|
g_assert (was_visible);
|
||||||
|
if (udev_device_2) {
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
|
||||||
|
g_assert (!nmp_object_is_visible (obj2));
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, FALSE);
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
|
||||||
|
} else {
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, obj1) == NULL);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == NULL);
|
||||||
|
g_assert (nmp_object_is_visible (obj2));
|
||||||
|
}
|
||||||
|
nmp_object_unref (obj1);
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
|
||||||
|
/* now another link only with aspect UDEV. */
|
||||||
|
if (udev_device_3) {
|
||||||
|
/* now add the link only with aspect UDEV. */
|
||||||
|
ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, udev_device_3, &obj2, &was_visible, NULL, NULL);
|
||||||
|
g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (obj2));
|
||||||
|
g_assert (!was_visible);
|
||||||
|
g_assert (!nmp_object_is_visible (obj2));
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, FALSE);
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
|
||||||
|
g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, FALSE);
|
||||||
|
g_assert_cmpint (obj2->link.initialized, ==, FALSE);
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
|
||||||
|
/* add it in netlink too. */
|
||||||
|
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_3);
|
||||||
|
obj1->_link.netlink.is_in_netlink = TRUE;
|
||||||
|
g_assert (nmp_object_is_alive (obj1));
|
||||||
|
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UPDATED);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert (obj2 != obj1);
|
||||||
|
g_assert (nmp_object_equal (obj1, obj2));
|
||||||
|
g_assert (!was_visible);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
|
||||||
|
g_assert (nmp_object_is_visible (obj2));
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, TRUE);
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
|
||||||
|
g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE);
|
||||||
|
g_assert_cmpint (obj2->link.initialized, ==, TRUE);
|
||||||
|
nmp_object_unref (obj1);
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
|
||||||
|
/* remove UDEV. */
|
||||||
|
ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, NULL, &obj2, &was_visible, NULL, NULL);
|
||||||
|
g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_UPDATED);
|
||||||
|
ASSERT_nmp_cache_is_consistent (cache);
|
||||||
|
g_assert (was_visible);
|
||||||
|
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
|
||||||
|
g_assert (nmp_object_is_visible (obj2));
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, TRUE);
|
||||||
|
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
|
||||||
|
g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE);
|
||||||
|
g_assert_cmpint (obj2->link.initialized, ==, !nmp_cache_use_udev_get (cache));
|
||||||
|
nmp_object_unref (obj2);
|
||||||
|
}
|
||||||
|
|
||||||
|
nmp_cache_free (cache);
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
|
|
||||||
@@ -33,11 +393,34 @@ int
|
|||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
gs_unref_object GUdevClient *udev_client = NULL;
|
||||||
|
|
||||||
nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
|
nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
|
||||||
|
|
||||||
|
udev_client = g_udev_client_new ((const char *[]) { "net", NULL });
|
||||||
|
{
|
||||||
|
gs_unref_object GUdevEnumerator *udev_enumerator = g_udev_enumerator_new (udev_client);
|
||||||
|
|
||||||
|
g_udev_enumerator_add_match_subsystem (udev_enumerator, "net");
|
||||||
|
|
||||||
|
/* Demand that the device is initialized (udev rules ran,
|
||||||
|
* device has a stable name now) in case udev is running
|
||||||
|
* (not in a container). */
|
||||||
|
if (access ("/sys", W_OK) == 0)
|
||||||
|
g_udev_enumerator_add_match_is_initialized (udev_enumerator);
|
||||||
|
|
||||||
|
global.udev_devices = g_udev_enumerator_execute (udev_enumerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_test_add_func ("/nmp-object/cache_link", test_cache_link);
|
||||||
|
|
||||||
result = g_test_run ();
|
result = g_test_run ();
|
||||||
|
|
||||||
|
while (global.udev_devices) {
|
||||||
|
g_object_unref (global.udev_devices->data);
|
||||||
|
global.udev_devices = g_list_remove (global.udev_devices, global.udev_devices->data);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user