/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* nm-platform.c - Handle runtime kernel networking configuration * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2015 Red Hat, Inc. */ #ifndef __NMP_OBJECT_H__ #define __NMP_OBJECT_H__ #include #include #include "nm-platform.h" #include "nm-multi-index.h" 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 can be indexed by NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT. * * Of one index type, there can be multiple indexes or not. * For example, of the index type NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX there * are multiple instances (for different route/addresses, v4/v6, per-ifindex). * * But one object, can only be indexed by one particular index of a * type. For example, a certain address instance is only indexed by * the index NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX with * matching v4/v6 and ifindex -- or maybe not at all if it isn't visible. * */ typedef enum { /*< skip >*/ /* all the objects of a certain type */ NMP_CACHE_ID_TYPE_OBJECT_TYPE, /* index for the link objects by ifname. */ NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, /* all the visible objects of a certain type */ NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY, /* indeces for the visible routes, ignoring ifindex. */ NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT, /* all the visible addresses/routes (by object-type) for an ifindex. */ NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX, /* three indeces for the visible routes, per ifindex. */ NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_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 */ /* NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY */ /* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT */ /* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT */ guint8 _id_type; guint8 obj_type; /* NMPObjectType as guint8 */ } object_type; struct { /* NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX */ /* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT */ /* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT */ guint8 _id_type; guint8 obj_type; /* NMPObjectType as guint8 */ int ifindex; } object_type_by_ifindex; struct { /* NMP_CACHE_ID_TYPE_LINK_BY_IFNAME */ guint8 _id_type; char ifname_short[IFNAMSIZ - 1]; /* don't include the trailing NUL so the struct fits in 4 bytes. */ } link_by_ifname; }; } NMPCacheId; extern NMPCacheId _nmp_cache_id_static; #define NMP_CACHE_ID_STATIC (&_nmp_cache_id_static) typedef struct { NMPObjectType obj_type; int addr_family; int rtm_gettype; int sizeof_data; int sizeof_public; NMPlatformSignalIdType signal_type_id; const char *obj_type_name; const char *signal_type; /* Only for NMPObjectLnk* types. */ NMLinkType lnk_link_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); int (*cmd_obj_cmp) (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); const char *(*cmd_obj_to_string) (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size); /* functions that operate on NMPlatformObject */ 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, char *buf, gsize len); int (*cmd_plobj_cmp) (const NMPlatformObject *obj1, const NMPlatformObject *obj2); } NMPClass; extern const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX]; typedef struct { NMPlatformLink _public; struct { bool is_in_netlink; /* Additional data that depends on the link-type (IFLA_INFO_DATA) */ NMPObject *lnk; } netlink; struct { GUdevDevice *device; } udev; } NMPObjectLink; typedef struct { NMPlatformLnkGre _public; } NMPObjectLnkGre; typedef struct { NMPlatformLnkInfiniband _public; } NMPObjectLnkInfiniband; typedef struct { NMPlatformLnkIp6Tnl _public; } NMPObjectLnkIp6Tnl; typedef struct { NMPlatformLnkIpIp _public; } NMPObjectLnkIpIp; typedef struct { NMPlatformLnkMacvlan _public; } NMPObjectLnkMacvlan; typedef NMPObjectLnkMacvlan NMPObjectLnkMacvtap; typedef struct { NMPlatformLnkSit _public; } NMPObjectLnkSit; typedef struct { NMPlatformLnkVlan _public; guint n_ingress_qos_map; guint n_egress_qos_map; const NMVlanQosMapping *ingress_qos_map; const NMVlanQosMapping *egress_qos_map; } NMPObjectLnkVlan; typedef struct { NMPlatformLnkVxlan _public; } NMPObjectLnkVxlan; 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; bool is_cached; union { NMPlatformObject object; NMPlatformLink link; NMPObjectLink _link; NMPlatformLnkGre lnk_gre; NMPObjectLnkGre _lnk_gre; NMPlatformLnkInfiniband lnk_infiniband; NMPObjectLnkInfiniband _lnk_infiniband; NMPlatformLnkIpIp lnk_ipip; NMPObjectLnkIpIp _lnk_ipip; NMPlatformLnkIp6Tnl lnk_ip6tnl; NMPObjectLnkIp6Tnl _lnk_ip6tnl; NMPlatformLnkMacvlan lnk_macvlan; NMPObjectLnkMacvlan _lnk_macvlan; NMPlatformLnkSit lnk_sit; NMPObjectLnkSit _lnk_sit; NMPlatformLnkVlan lnk_vlan; NMPObjectLnkVlan _lnk_vlan; NMPlatformLnkVxlan lnk_vxlan; NMPObjectLnkVxlan _lnk_vxlan; 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 NMPObjectType NMP_OBJECT_GET_TYPE (const NMPObject *obj) { nm_assert (!obj || NMP_OBJECT_IS_VALID (obj)); return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN; } const NMPClass *nmp_class_from_type (NMPObjectType obj_type); NMPObject *nmp_object_ref (NMPObject *object); void nmp_object_unref (NMPObject *object); NMPObject *nmp_object_new (NMPObjectType obj_type, const NMPlatformObject *plob); NMPObject *nmp_object_new_link (int ifindex); const NMPObject *nmp_object_stackinit (NMPObject *obj, NMPObjectType 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, guint32 peer_address); 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 nm_auto_nmpobj __attribute__((cleanup(_nm_auto_nmpobj_cleanup))) static inline void _nm_auto_nmpobj_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_object_type (NMPCacheId *id, NMPObjectType obj_type, gboolean visible_only); NMPCacheId *nmp_cache_id_init_addrroute_visible_by_ifindex (NMPCacheId *id, NMPObjectType obj_type, int ifindex); NMPCacheId *nmp_cache_id_init_routes_visible (NMPCacheId *id, NMPObjectType obj_type, gboolean with_default, gboolean with_non_default, int ifindex); NMPCacheId *nmp_cache_id_init_link_by_ifname (NMPCacheId *id, const char *ifname); 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, NMPObjectType 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 (gboolean use_udev); void nmp_cache_free (NMPCache *cache); #endif /* __NMP_OBJECT_H__ */