diff options
Diffstat (limited to 'src/platform')
| -rw-r--r-- | src/platform/nm-fake-platform.c | 28 | ||||
| -rw-r--r-- | src/platform/nm-linux-platform.c | 460 | ||||
| -rw-r--r-- | src/platform/nm-platform.c | 383 | ||||
| -rw-r--r-- | src/platform/nm-platform.h | 114 | ||||
| -rw-r--r-- | src/platform/nmp-netns.c | 5 | ||||
| -rw-r--r-- | src/platform/nmp-object.c | 103 | ||||
| -rw-r--r-- | src/platform/nmp-object.h | 85 | ||||
| -rw-r--r-- | src/platform/tests/test-common.c | 54 | ||||
| -rw-r--r-- | src/platform/tests/test-common.h | 20 | ||||
| -rw-r--r-- | src/platform/tests/test-link.c | 15 | ||||
| -rw-r--r-- | src/platform/tests/test-nmp-object.c | 91 | ||||
| -rw-r--r-- | src/platform/tests/test-route.c | 208 |
12 files changed, 1294 insertions, 272 deletions
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index c199c5ed..be430152 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2012–2013 Red Hat, Inc. + * Copyright (C) 2012–2017 Red Hat, Inc. */ #include "nm-default.h" @@ -1056,11 +1056,11 @@ ipx_address_delete (NMPlatform *platform, peer_addr_i = peer_addr ? *((guint32 *) peer_addr) : 0; nmp_cache_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - addr_family == AF_INET - ? NMP_OBJECT_TYPE_IP4_ADDRESS - : NMP_OBJECT_TYPE_IP6_ADDRESS, - 0), + nm_platform_lookup_object (platform, + addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ADDRESS + : NMP_OBJECT_TYPE_IP6_ADDRESS, + 0), &o) { const NMPObject *obj_old = NULL; @@ -1144,9 +1144,9 @@ ipx_route_delete (NMPlatform *platform, } nmp_cache_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - obj_type, - ifindex), + nm_platform_lookup_object (platform, + obj_type, + ifindex), &o) { const NMPObject *obj_old = NULL; @@ -1190,7 +1190,7 @@ ipx_route_delete (NMPlatform *platform, } static gboolean -ip_route_delete (NMPlatform *platform, const NMPObject *obj) +object_delete (NMPlatform *platform, const NMPObject *obj) { g_assert (NM_IS_FAKE_PLATFORM (platform)); g_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, @@ -1254,9 +1254,9 @@ ip_route_add (NMPlatform *platform, gboolean has_route_to_gw = FALSE; nmp_cache_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - NMP_OBJECT_GET_TYPE (obj), - 0), + nm_platform_lookup_object (platform, + NMP_OBJECT_GET_TYPE (obj), + 0), &o) { if (addr_family == AF_INET) { const NMPlatformIP4Route *item = NMP_OBJECT_CAST_IP4_ROUTE (o); @@ -1462,5 +1462,5 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->ip6_address_delete = ip6_address_delete; platform_class->ip_route_add = ip_route_add; - platform_class->ip_route_delete = ip_route_delete; + platform_class->object_delete = object_delete; } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index c4c93ed3..10d1a6ef 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2012-2015 Red Hat, Inc. + * Copyright (C) 2012 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -54,6 +54,29 @@ #include "nm-utils/unaligned.h" #include "nm-utils/nm-udev-utils.h" +/*****************************************************************************/ + +/* re-implement <linux/tc_act/tc_defact.h> to build against kernel + * headers that lack this. */ + +#include <linux/pkt_cls.h> + +struct tc_defact { + tc_gen; +}; + +enum { + TCA_DEF_UNSPEC, + TCA_DEF_TM, + TCA_DEF_PARMS, + TCA_DEF_DATA, + TCA_DEF_PAD, + __TCA_DEF_MAX +}; +#define TCA_DEF_MAX (__TCA_DEF_MAX - 1) + +/*****************************************************************************/ + #define VLAN_FLAG_MVRP 0x8 /* nm-internal error codes for libnl. Make sure they don't overlap. */ @@ -227,27 +250,33 @@ enum { DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS, + DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS, _DELAYED_ACTION_IDX_REFRESH_ALL_NUM, }; typedef enum { DELAYED_ACTION_TYPE_NONE = 0, - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_LINKS), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 5), - DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 6), - DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 7), - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 8), + DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << /* 0 */ DELAYED_ACTION_IDX_REFRESH_ALL_LINKS), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << /* 1 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << /* 2 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << /* 3 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << /* 4 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = (1LL << /* 5 */ DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS), + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = (1LL << /* 6 */ DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS), + DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 7), + DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 11), + DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 12), + DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 13), __DELAYED_ACTION_TYPE_MAX, DELAYED_ACTION_TYPE_REFRESH_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1, } DelayedActionType; @@ -941,17 +970,25 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) b = buf; switch (hdr->nlmsg_type) { - case RTM_NEWLINK: s = "NEWLINK"; break; - case RTM_DELLINK: s = "DELLINK"; break; - case RTM_NEWADDR: s = "NEWADDR"; break; - case RTM_DELADDR: s = "DELADDR"; break; - case RTM_NEWROUTE: s = "NEWROUTE"; break; - case RTM_DELROUTE: s = "DELROUTE"; break; - default: s = NULL; break; + case RTM_NEWLINK: s = "RTM_NEWLINK"; break; + case RTM_DELLINK: s = "RTM_DELLINK"; break; + case RTM_NEWADDR: s = "RTM_NEWADDR"; break; + case RTM_DELADDR: s = "RTM_DELADDR"; break; + case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; + case RTM_DELROUTE: s = "RTM_DELROUTE"; break; + case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; + case RTM_DELQDISC: s = "RTM_DELQDISC"; break; + case RTM_NEWTFILTER: s = "RTM_NEWTFILTER"; break; + case RTM_DELTFILTER: s = "RTM_DELTFILTER"; break; + case NLMSG_NOOP: s = "NLMSG_NOOP"; break; + case NLMSG_ERROR: s = "NLMSG_ERROR"; break; + case NLMSG_DONE: s = "NLMSG_DONE"; break; + case NLMSG_OVERRUN: s = "NLMSG_OVERRUN"; break; + default: s = NULL; break; } if (s) - nm_utils_strbuf_append (&buf, &len, "RTM_%s", s); + nm_utils_strbuf_append_str (&buf, &len, s); else nm_utils_strbuf_append (&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); @@ -989,6 +1026,8 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) case RTM_NEWLINK: case RTM_NEWADDR: case RTM_NEWROUTE: + case RTM_NEWQDISC: + case RTM_NEWTFILTER: _F (NLM_F_REPLACE, "replace"); _F (NLM_F_EXCL, "excl"); _F (NLM_F_CREATE, "create"); @@ -997,6 +1036,8 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) case RTM_GETLINK: case RTM_GETADDR: case RTM_GETROUTE: + case RTM_DELQDISC: + case RTM_DELTFILTER: _F (NLM_F_DUMP, "dump"); _F (NLM_F_ROOT, "root"); _F (NLM_F_MATCH, "match"); @@ -2291,17 +2332,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) obj->ip6_route.rt_pref = nla_get_u8 (tb[RTA_PREF]); } - if (NM_FLAGS_HAS (rtm->rtm_flags, 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->ip_route.rt_cloned = TRUE; - } - + obj->ip_route.r_rtm_flags = rtm->rtm_flags; obj->ip_route.rt_source = nmp_utils_ip_config_source_from_rtprot (rtm->rtm_protocol); obj_result = obj; @@ -2310,6 +2341,74 @@ errout: return obj_result; } +static NMPObject * +_new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) +{ + NMPObject *obj = NULL; + const struct tcmsg *tcm; + struct nlattr *tb[TCA_MAX + 1]; + int err; + static const struct nla_policy policy[TCA_MAX + 1] = { + [TCA_KIND] = { .type = NLA_STRING }, + }; + + if (!nlmsg_valid_hdr (nlh, sizeof (*tcm))) + return NULL; + tcm = nlmsg_data (nlh); + + err = nlmsg_parse (nlh, sizeof (*tcm), tb, TCA_MAX, policy); + if (err < 0) + return NULL; + + if (!tb[TCA_KIND]) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_QDISC, NULL); + + obj->qdisc.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); + obj->qdisc.ifindex = tcm->tcm_ifindex; + obj->qdisc.addr_family = tcm->tcm_family; + obj->qdisc.handle = tcm->tcm_handle; + obj->qdisc.parent = tcm->tcm_parent; + obj->qdisc.info = tcm->tcm_info; + + return obj; +} + +static NMPObject * +_new_from_nl_tfilter (struct nlmsghdr *nlh, gboolean id_only) +{ + NMPObject *obj = NULL; + const struct tcmsg *tcm; + struct nlattr *tb[TCA_MAX + 1]; + int err; + static const struct nla_policy policy[TCA_MAX + 1] = { + [TCA_KIND] = { .type = NLA_STRING }, + }; + + if (!nlmsg_valid_hdr (nlh, sizeof (*tcm))) + return NULL; + tcm = nlmsg_data (nlh); + + err = nlmsg_parse (nlh, sizeof (*tcm), tb, TCA_MAX, policy); + if (err < 0) + return NULL; + + if (!tb[TCA_KIND]) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_TFILTER, NULL); + + obj->tfilter.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); + obj->tfilter.ifindex = tcm->tcm_ifindex; + obj->tfilter.addr_family = tcm->tcm_family; + obj->tfilter.handle = tcm->tcm_handle; + obj->tfilter.parent = tcm->tcm_parent; + obj->tfilter.info = tcm->tcm_info; + + return obj; +} + /** * nmp_object_new_from_nl: * @platform: (allow-none): for creating certain objects, the constructor wants to check @@ -2346,6 +2445,14 @@ nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_m case RTM_DELROUTE: case RTM_GETROUTE: return _new_from_nl_route (msghdr, id_only); + case RTM_NEWQDISC: + case RTM_DELQDISC: + case RTM_GETQDISC: + return _new_from_nl_qdisc (msghdr, id_only); + case RTM_NEWTFILTER: + case RTM_DELTFILTER: + case RTM_GETTFILTER: + return _new_from_nl_tfilter (msghdr, id_only); default: return NULL; } @@ -2700,7 +2807,9 @@ _nl_msg_new_route (int nlmsg_type, ? nm_platform_route_scope_inv (obj->ip4_route.scope_inv) : RT_SCOPE_NOWHERE, .rtm_type = RTN_UNICAST, - .rtm_flags = 0, + .rtm_flags = obj->ip_route.r_rtm_flags & (is_v4 + ? (unsigned) (RTNH_F_ONLINK) + : (unsigned) 0), .rtm_dst_len = obj->ip_route.plen, .rtm_src_len = is_v4 ? 0 @@ -2797,6 +2906,124 @@ nla_put_failure: g_return_val_if_reached (NULL); } +static struct nl_msg * +_nl_msg_new_qdisc (int nlmsg_type, + int nlmsg_flags, + const NMPlatformQdisc *qdisc) +{ + struct nl_msg *msg; + struct tcmsg tcm = { + .tcm_family = qdisc->addr_family, + .tcm_ifindex = qdisc->ifindex, + .tcm_handle = qdisc->handle, + .tcm_parent = qdisc->parent, + .tcm_info = qdisc->info, + }; + + msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + return NULL; + + if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind); + + return msg; +nla_put_failure: + nlmsg_free (msg); + g_return_val_if_reached (NULL); +} + +static gboolean +_add_action_simple (struct nl_msg *msg, + const NMPlatformActionSimple *simple) +{ + struct nlattr *act_options; + struct tc_defact sel = { 0, }; + + if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS))) + goto nla_put_failure; + + NLA_PUT (msg, TCA_DEF_PARMS, sizeof (sel), &sel); + NLA_PUT (msg, TCA_DEF_DATA, sizeof (simple->sdata), simple->sdata); + + nla_nest_end (msg, act_options); + + return TRUE; + +nla_put_failure: + return FALSE; +} + +static gboolean +_add_action (struct nl_msg *msg, + const NMPlatformAction *action) +{ + struct nlattr *prio; + + nm_assert (action || action->kind); + + if (!(prio = nla_nest_start (msg, 1 /* priority */))) + goto nla_put_failure; + + NLA_PUT_STRING (msg, TCA_ACT_KIND, action->kind); + + if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) + _add_action_simple (msg, &action->simple); + + nla_nest_end (msg, prio); + + return TRUE; + +nla_put_failure: + return FALSE; +} + +static struct nl_msg * +_nl_msg_new_tfilter (int nlmsg_type, + int nlmsg_flags, + const NMPlatformTfilter *tfilter) +{ + struct nl_msg *msg; + struct nlattr *tc_options; + struct nlattr *act_tab; + struct tcmsg tcm = { + .tcm_family = tfilter->addr_family, + .tcm_ifindex = tfilter->ifindex, + .tcm_handle = tfilter->handle, + .tcm_parent = tfilter->parent, + .tcm_info = tfilter->info, + }; + + msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + return NULL; + + if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + NLA_PUT_STRING (msg, TCA_KIND, tfilter->kind); + + if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS))) + goto nla_put_failure; + + if (!(act_tab = nla_nest_start (msg, TCA_OPTIONS))) // 3 TCA_ACT_KIND TCA_ACT_KIND + goto nla_put_failure; + + if (tfilter->action.kind) + _add_action (msg, &tfilter->action); + + nla_nest_end (msg, tc_options); + + nla_nest_end (msg, act_tab); + + return msg; +nla_put_failure: + nlmsg_free (msg); + g_return_val_if_reached (NULL); +} + /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -2867,7 +3094,7 @@ struct _NMLinuxPlatformClass { G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) -#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE_VOID(self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM) +#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM, NMPlatform) NMPlatform * nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support) @@ -3198,6 +3425,8 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_from_object_type, NMPObj NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ADDRESS, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES), NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP4_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES), NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES), + NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_QDISC, DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS), + NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_TFILTER, DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), ); @@ -3208,6 +3437,8 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_to_object_type, DelayedA NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, NMP_OBJECT_TYPE_QDISC), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NMP_OBJECT_TYPE_TFILTER), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), ); @@ -3218,6 +3449,8 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_all_to_idx, DelayedActio NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), ); @@ -3228,6 +3461,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType, NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, "refresh-all-ip6-addresses"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"), @@ -3665,7 +3900,7 @@ cache_on_change (NMPlatform *platform, { int ifindex = 0; - /* if we remove a link (from netlink), we must refresh the addresses and routes */ + /* if we remove a link (from netlink), we must refresh the addresses, routes, qdiscs and tfilters */ if ( cache_op == NMP_CACHE_OPS_REMOVED && obj_old /* <-- nonsensical, make coverity happy */) ifindex = obj_old->link.ifindex; @@ -3680,7 +3915,9 @@ cache_on_change (NMPlatform *platform, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); } } @@ -4003,9 +4240,6 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags); const NMPClass *klass = nmp_class_from_type (obj_type); nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct rtgenmsg gmsg = { - .rtgen_family = klass->addr_family, - }; int nle; gint *out_refresh_all_in_progess; @@ -4032,7 +4266,18 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio if (!nlmsg) continue; - nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); + if ( klass->obj_type == NMP_OBJECT_TYPE_QDISC + || klass->obj_type == NMP_OBJECT_TYPE_TFILTER) { + struct tcmsg tcmsg = { + .tcm_family = AF_UNSPEC, + }; + nle = nlmsg_append (nlmsg, &tcmsg, sizeof (tcmsg), NLMSG_ALIGNTO); + } else { + struct rtgenmsg gmsg = { + .rtgen_family = klass->addr_family, + }; + nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); + } if (nle < 0) continue; @@ -4154,6 +4399,8 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_NEWADDR: case RTM_NEWLINK: case RTM_NEWROUTE: + case RTM_NEWQDISC: + case RTM_NEWTFILTER: is_dump = delayed_action_refresh_all_in_progress (platform, delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj))); break; @@ -4177,6 +4424,8 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_NEWLINK: case RTM_NEWADDR: case RTM_GETLINK: + case RTM_NEWQDISC: + case RTM_NEWTFILTER: cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new); if (cache_op != NMP_CACHE_OPS_UNCHANGED) { cache_on_change (platform, cache_op, obj_old, obj_new); @@ -4189,7 +4438,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event gboolean resync_required = FALSE; gboolean only_dirty = FALSE; - if (obj->ip_route.rt_cloned) { + if (NM_FLAGS_HAS (obj->ip_route.r_rtm_flags, RTM_F_CLONED)) { /* a cloned route might be a response for RTM_GETROUTE. Check, whether it is. */ nm_assert (!nmp_object_is_alive (obj)); priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); @@ -4270,13 +4519,14 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_DELLINK: case RTM_DELADDR: case RTM_DELROUTE: + case RTM_DELQDISC: + case RTM_DELTFILTER: cache_op = nmp_cache_remove_netlink (cache, obj, &obj_old, &obj_new); if (cache_op != NMP_CACHE_OPS_UNCHANGED) { cache_on_change (platform, cache_op, obj_old, obj_new); nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); } break; - default: break; } @@ -5652,7 +5902,7 @@ tun_add (NMPlatform *platform, const char *name, gboolean tap, if (out_link) *out_link = obj ? &obj->link : NULL; - close (fd); + nm_close (fd); return !!obj; } @@ -5886,15 +6136,15 @@ link_can_assume (NMPlatform *platform, int ifindex) if (link->link.master > 0) return TRUE; - nmp_lookup_init_addrroute (&lookup, - NMP_OBJECT_TYPE_IP4_ADDRESS, - ifindex); + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP4_ADDRESS, + ifindex); if (nmp_cache_lookup (cache, &lookup)) return TRUE; - nmp_lookup_init_addrroute (&lookup, - NMP_OBJECT_TYPE_IP6_ADDRESS, - ifindex); + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP6_ADDRESS, + ifindex); nmp_cache_iter_for_each (&iter, nmp_cache_lookup (cache, &lookup), &o) { @@ -6120,19 +6370,30 @@ ip_route_add (NMPlatform *platform, } static gboolean -ip_route_delete (NMPlatform *platform, - const NMPObject *obj) +object_delete (NMPlatform *platform, + const NMPObject *obj) { nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)); - if (!NMP_OBJECT_IS_STACKINIT (obj)) obj_keep_alive = nmp_object_ref (obj); - nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj); + switch (NMP_OBJECT_GET_TYPE (obj)) { + case NMP_OBJECT_TYPE_IP4_ROUTE: + case NMP_OBJECT_TYPE_IP6_ROUTE: + nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj); + break; + case NMP_OBJECT_TYPE_QDISC: + nlmsg = _nl_msg_new_qdisc (RTM_DELQDISC, 0, NMP_OBJECT_CAST_QDISC (obj)); + break; + case NMP_OBJECT_TYPE_TFILTER: + nlmsg = _nl_msg_new_tfilter (RTM_DELTFILTER, 0, NMP_OBJECT_CAST_TFILTER (obj)); + break; + default: + break; + } + if (!nlmsg) g_return_val_if_reached (FALSE); return do_delete_object (platform, obj, nlmsg); @@ -6219,6 +6480,84 @@ ip_route_get (NMPlatform *platform, /*****************************************************************************/ +static NMPlatformError +qdisc_add (NMPlatform *platform, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc) +{ + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + int nle; + char s_buf[256]; + nm_auto_nlmsg struct nl_msg *msg = NULL; + + msg = _nl_msg_new_qdisc (RTM_NEWQDISC, flags, qdisc); + + event_handler_read_netlink (platform, FALSE); + + nle = _nl_send_nlmsg (platform, msg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + if (nle < 0) { + _LOGE ("do-add-qdisc: failed sending netlink request \"%s\" (%d)", + nl_geterror (nle), -nle); + return NM_PLATFORM_ERROR_NETLINK; + } + + delayed_action_handle_all (platform, FALSE); + + nm_assert (seq_result); + + _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK + ? LOGL_DEBUG + : LOGL_WARN, + "do-add-qdisc: %s", + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); + + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) + return NM_PLATFORM_ERROR_SUCCESS; + + return NM_PLATFORM_ERROR_UNSPECIFIED; +} + +/*****************************************************************************/ + +static NMPlatformError +tfilter_add (NMPlatform *platform, + NMPNlmFlags flags, + const NMPlatformTfilter *tfilter) +{ + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + int nle; + char s_buf[256]; + nm_auto_nlmsg struct nl_msg *msg = NULL; + + msg = _nl_msg_new_tfilter (RTM_NEWTFILTER, flags, tfilter); + + event_handler_read_netlink (platform, FALSE); + + nle = _nl_send_nlmsg (platform, msg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + if (nle < 0) { + _LOGE ("do-add-tfilter: failed sending netlink request \"%s\" (%d)", + nl_geterror (nle), -nle); + return NM_PLATFORM_ERROR_NETLINK; + } + + delayed_action_handle_all (platform, FALSE); + + nm_assert (seq_result); + + _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK + ? LOGL_DEBUG + : LOGL_WARN, + "do-add-tfilter: %s", + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); + + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) + return NM_PLATFORM_ERROR_SUCCESS; + + return NM_PLATFORM_ERROR_UNSPECIFIED; +} + +/*****************************************************************************/ + #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) #define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) #define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP)) @@ -6500,7 +6839,9 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); break; default: @@ -6760,13 +7101,13 @@ constructed (GObject *_object) RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, + RTNLGRP_TC, 0); g_assert (!nle); _LOGD ("Netlink socket for events established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh), nl_socket_get_fd (priv->nlh)); priv->event_channel = g_io_channel_unix_new (nl_socket_get_fd (priv->nlh)); g_io_channel_set_encoding (priv->event_channel, NULL, NULL); - g_io_channel_set_close_on_unref (priv->event_channel, TRUE); channel_flags = g_io_channel_get_flags (priv->event_channel); status = g_io_channel_set_flags (priv->event_channel, @@ -6785,7 +7126,9 @@ constructed (GObject *_object) DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); delayed_action_handle_all (platform, FALSE); @@ -6942,15 +7285,18 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_ipip_add = link_ipip_add; platform_class->link_sit_add = link_sit_add; + platform_class->object_delete = object_delete; platform_class->ip4_address_add = ip4_address_add; platform_class->ip6_address_add = ip6_address_add; platform_class->ip4_address_delete = ip4_address_delete; platform_class->ip6_address_delete = ip6_address_delete; platform_class->ip_route_add = ip_route_add; - platform_class->ip_route_delete = ip_route_delete; platform_class->ip_route_get = ip_route_get; + platform_class->qdisc_add = qdisc_add; + platform_class->tfilter_add = tfilter_add; + platform_class->check_kernel_support = check_kernel_support; platform_class->process_events = process_events; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index ffc4b395..2ca379e4 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -508,6 +508,7 @@ nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *pathid, int di { char *value = NULL; gint32 ret; + int errsv; _CHECK_SELF (self, klass, fallback); @@ -522,7 +523,9 @@ nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *pathid, int di } ret = _nm_utils_ascii_str_to_int64 (value, base, min, max, fallback); + errsv = errno; g_free (value); + errno = errsv; return ret; } @@ -3343,9 +3346,9 @@ delete_and_next: } plat_addresses = nm_platform_lookup_clone (self, - nmp_lookup_init_addrroute (&lookup, - NMP_OBJECT_TYPE_IP4_ADDRESS, - ifindex), + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP4_ADDRESS, + ifindex), NULL, NULL); if (plat_addresses) plat_subnets = ip4_addr_subnets_build_index (plat_addresses, TRUE, TRUE); @@ -3485,9 +3488,9 @@ nm_platform_ip6_address_sync (NMPlatform *self, /* Delete unknown addresses */ plat_addresses = nm_platform_lookup_clone (self, - nmp_lookup_init_addrroute (&lookup, - NMP_OBJECT_TYPE_IP6_ADDRESS, - ifindex), + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP6_ADDRESS, + ifindex), NULL, NULL); if (plat_addresses) { for (i = 0; i < plat_addresses->len; i++) { @@ -3608,11 +3611,11 @@ nm_platform_ip_route_get_prune_list (NMPlatform *self, NM_IP_ROUTE_TABLE_SYNC_MODE_FULL, NM_IP_ROUTE_TABLE_SYNC_MODE_ALL)); - nmp_lookup_init_addrroute (&lookup, - addr_family == AF_INET - ? NMP_OBJECT_TYPE_IP4_ROUTE - : NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex); + nmp_lookup_init_object (&lookup, + addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex); head_entry = nm_platform_lookup (self, &lookup); if (!head_entry) return NULL; @@ -3729,7 +3732,7 @@ nm_platform_ip_route_sync (NMPlatform *self, /* we need to replace the existing route with a (slightly) differnt * one. Delete it first. */ - if (!nm_platform_ip_route_delete (self, plat_o)) { + if (!nm_platform_object_delete (self, plat_o)) { /* ignore error. */ } } @@ -3810,7 +3813,7 @@ nm_platform_ip_route_sync (NMPlatform *self, prune_o)) continue; - if (!nm_platform_ip_route_delete (self, prune_o)) { + if (!nm_platform_object_delete (self, prune_o)) { /* ignore error... */ } } @@ -3988,20 +3991,22 @@ nm_platform_ip6_route_add (NMPlatform *self, } gboolean -nm_platform_ip_route_delete (NMPlatform *self, - const NMPObject *obj) +nm_platform_object_delete (NMPlatform *self, + const NMPObject *obj) { _CHECK_SELF (self, klass, FALSE); if (!NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)) + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC, + NMP_OBJECT_TYPE_TFILTER)) g_return_val_if_reached (FALSE); - _LOGD ("route: delete IPv%c route %s", - NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_IP4_ROUTE ? '4' : '6', + _LOGD ("%s: delete %s", + NMP_OBJECT_GET_CLASS (obj)->obj_type_name, nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - return klass->ip_route_delete (self, obj); + return klass->object_delete (self, obj); } /*****************************************************************************/ @@ -4112,7 +4117,7 @@ again: _LOGT ("ip4-dev-route: delete %s", nmp_object_to_string (p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - nm_platform_ip_route_delete (self, p_obj); + nm_platform_object_delete (self, p_obj); goto again; } @@ -4329,6 +4334,138 @@ nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self, /*****************************************************************************/ +NMPlatformError +nm_platform_qdisc_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc) +{ + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + _LOGD ("adding or updating a qdisc: %s", nm_platform_qdisc_to_string (qdisc, NULL, 0)); + return klass->qdisc_add (self, flags, qdisc); +} + +gboolean +nm_platform_qdisc_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_qdiscs) +{ + gs_unref_ptrarray GPtrArray *plat_qdiscs = NULL; + NMPLookup lookup; + guint i; + gboolean success = TRUE; + gs_unref_hashtable GHashTable *known_qdiscs_idx = NULL; + + nm_assert (NM_IS_PLATFORM (self)); + nm_assert (ifindex > 0); + + known_qdiscs_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal); + + if (known_qdiscs) { + for (i = 0; i < known_qdiscs->len; i++) { + const NMPObject *q = g_ptr_array_index (known_qdiscs, i); + + g_hash_table_insert (known_qdiscs_idx, (gpointer) q, (gpointer) q); + } + } + + plat_qdiscs = nm_platform_lookup_clone (self, + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_QDISC, + ifindex), + NULL, NULL); + + + if (plat_qdiscs) { + for (i = 0; i < plat_qdiscs->len; i++) { + const NMPObject *q = g_ptr_array_index (plat_qdiscs, i); + + if (!g_hash_table_lookup (known_qdiscs_idx, q)) + success &= nm_platform_object_delete (self, q); + } + } + + if (known_qdiscs) { + for (i = 0; i < known_qdiscs->len; i++) { + const NMPObject *q = g_ptr_array_index (known_qdiscs, i); + + success &= (nm_platform_qdisc_add (self, NMP_NLM_FLAG_ADD, + NMP_OBJECT_CAST_QDISC (q)) == NM_PLATFORM_ERROR_SUCCESS); + } + } + + return success; +} + +/*****************************************************************************/ + +NMPlatformError +nm_platform_tfilter_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformTfilter *tfilter) +{ + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + _LOGD ("adding or updating a tfilter: %s", nm_platform_tfilter_to_string (tfilter, NULL, 0)); + return klass->tfilter_add (self, flags, tfilter); +} + +gboolean +nm_platform_tfilter_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_tfilters) +{ + gs_unref_ptrarray GPtrArray *plat_tfilters = NULL; + NMPLookup lookup; + guint i; + gboolean success = TRUE; + gs_unref_hashtable GHashTable *known_tfilters_idx = NULL; + + nm_assert (NM_IS_PLATFORM (self)); + nm_assert (ifindex > 0); + + known_tfilters_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal); + + if (known_tfilters) { + for (i = 0; i < known_tfilters->len; i++) { + const NMPObject *q = g_ptr_array_index (known_tfilters, i); + + g_hash_table_insert (known_tfilters_idx, (gpointer) q, (gpointer) q); + } + } + + plat_tfilters = nm_platform_lookup_clone (self, + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_TFILTER, + ifindex), + NULL, NULL); + + + if (plat_tfilters) { + for (i = 0; i < plat_tfilters->len; i++) { + const NMPObject *q = g_ptr_array_index (plat_tfilters, i); + + if (!g_hash_table_lookup (known_tfilters_idx, q)) + success &= nm_platform_object_delete (self, q); + } + } + + if (known_tfilters) { + for (i = 0; i < known_tfilters->len; i++) { + const NMPObject *q = g_ptr_array_index (known_tfilters, i); + + success &= (nm_platform_tfilter_add (self, NMP_NLM_FLAG_ADD, + NMP_OBJECT_CAST_TFILTER (q)) == NM_PLATFORM_ERROR_SUCCESS); + } + } + + return success; +} + +/*****************************************************************************/ + const char * nm_platform_vlan_qos_mapping_to_string (const char *name, const NMVlanQosMapping *map, @@ -4976,6 +5113,40 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *bu return buf; } +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_rtm_flags_to_string, unsigned, + NM_UTILS_FLAGS2STR (RTNH_F_DEAD, "dead"), + NM_UTILS_FLAGS2STR (RTNH_F_PERVASIVE, "pervasive"), + NM_UTILS_FLAGS2STR (RTNH_F_ONLINK, "onlink"), + NM_UTILS_FLAGS2STR (8 /*RTNH_F_OFFLOAD*/, "offload"), + NM_UTILS_FLAGS2STR (16 /*RTNH_F_LINKDOWN*/, "linkdown"), + NM_UTILS_FLAGS2STR (32 /*RTNH_F_UNRESOLVED*/, "unresolved"), + + NM_UTILS_FLAGS2STR (RTM_F_NOTIFY, "notify"), + NM_UTILS_FLAGS2STR (RTM_F_CLONED, "cloned"), + NM_UTILS_FLAGS2STR (RTM_F_EQUALIZE, "equalize"), + NM_UTILS_FLAGS2STR (RTM_F_PREFIX, "prefix"), + NM_UTILS_FLAGS2STR (0x1000 /*RTM_F_LOOKUP_TABLE*/, "lookup-table"), + NM_UTILS_FLAGS2STR (0x2000 /*RTM_F_FIB_MATCH*/, "fib-match"), +); + +#define _RTM_FLAGS_TO_STRING_MAXLEN 200 + +static const char * +_rtm_flags_to_string_full (char *buf, gsize buf_size, unsigned rtm_flags) +{ + const char *buf0 = buf; + + nm_assert (buf_size >= _RTM_FLAGS_TO_STRING_MAXLEN); + + if (!rtm_flags) + return ""; + + nm_utils_strbuf_append_str (&buf, &buf_size, " rtm_flags "); + _rtm_flags_to_string (rtm_flags, buf, buf_size); + nm_assert (strlen (buf) < buf_size); + return buf0; +} + /** * nm_platform_ip4_route_to_string: * @route: pointer to NMPlatformIP4Route route structure @@ -4997,6 +5168,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi char str_table[30]; char str_scope[30], s_source[50]; char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; + char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -5015,7 +5187,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi " metric %"G_GUINT32_FORMAT " mss %"G_GUINT32_FORMAT " rt-src %s" /* protocol */ - "%s" /* cloned */ + "%s" /* rtm_flags */ "%s%s" /* scope */ "%s%s" /* pref-src */ "%s" /* tos */ @@ -5033,7 +5205,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi route->metric, route->mss, nmp_utils_ip_config_source_to_string (route->rt_source, s_source, sizeof (s_source)), - route->rt_cloned ? " cloned" : "", + _rtm_flags_to_string_full (str_rtm_flags, sizeof (str_rtm_flags), route->r_rtm_flags), route->scope_inv ? " scope " : "", route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "", route->pref_src ? " pref-src " : "", @@ -5069,6 +5241,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi char str_pref2[30]; char str_dev[TO_STRING_DEV_BUF_SIZE], s_source[50]; char str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; + char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -5092,7 +5265,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi " mss %"G_GUINT32_FORMAT " rt-src %s" /* protocol */ "%s" /* source */ - "%s" /* cloned */ + "%s" /* rtm_flags */ "%s%s" /* pref-src */ "%s" /* window */ "%s" /* cwnd */ @@ -5112,7 +5285,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi route->src_plen || !IN6_IS_ADDR_UNSPECIFIED (&route->src) ? nm_sprintf_buf (s_src_all, " src %s/%u", nm_utils_inet6_ntop (&route->src, s_src), (unsigned) route->src_plen) : "", - route->rt_cloned ? " cloned" : "", + _rtm_flags_to_string_full (str_rtm_flags, sizeof (str_rtm_flags), route->r_rtm_flags), s_pref_src[0] ? " pref-src " : "", s_pref_src[0] ? s_pref_src : "", route->window || route->lock_window ? nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window) : "", @@ -5125,6 +5298,129 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi return buf; } +const char * +nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len) +{ + char str_dev[TO_STRING_DEV_BUF_SIZE]; + + if (!nm_utils_to_string_buffer_init_null (qdisc, &buf, &len)) + return buf; + + g_snprintf (buf, len, "%s%s family %d handle %x parent %x info %x", + qdisc->kind, + _to_string_dev (NULL, qdisc->ifindex, str_dev, sizeof (str_dev)), + qdisc->addr_family, + qdisc->handle, + qdisc->parent, + qdisc->info); + + return buf; +} + +void +nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h) +{ + nm_hash_update_str (h, obj->kind); + nm_hash_update_vals (h, + obj->ifindex, + obj->addr_family, + obj->handle, + obj->parent, + obj->info); +} + +int +nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b) +{ + NM_CMP_SELF (a, b); + NM_CMP_FIELD (a, b, ifindex); + NM_CMP_FIELD (a, b, parent); + NM_CMP_FIELD_STR_INTERNED (a, b, kind); + NM_CMP_FIELD (a, b, addr_family); + NM_CMP_FIELD (a, b, handle); + NM_CMP_FIELD (a, b, info); + + return 0; +} + +const char * +nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len) +{ + char str_dev[TO_STRING_DEV_BUF_SIZE]; + char act_buf[300]; + char *p; + gsize l; + + if (!nm_utils_to_string_buffer_init_null (tfilter, &buf, &len)) + return buf; + + if (tfilter->action.kind) { + p = act_buf; + l = sizeof (act_buf); + + nm_utils_strbuf_append (&p, &l, " \"%s\"", tfilter->action.kind); + if (nm_streq (tfilter->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { + gs_free char *t = NULL; + + nm_utils_strbuf_append (&p, &l, + " (\"%s\")", + nm_utils_str_utf8safe_escape (tfilter->action.kind, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL + | NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII, + &t)); + } + } else + act_buf[0] = '\0'; + + g_snprintf (buf, len, "%s%s family %d handle %x parent %x info %x%s", + tfilter->kind, + _to_string_dev (NULL, tfilter->ifindex, str_dev, sizeof (str_dev)), + tfilter->addr_family, + tfilter->handle, + tfilter->parent, + tfilter->info, + act_buf); + + return buf; +} + +void +nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h) +{ + nm_hash_update_str (h, obj->kind); + nm_hash_update_vals (h, + obj->ifindex, + obj->addr_family, + obj->handle, + obj->parent, + obj->info); + nm_hash_update_str (h, obj->action.kind); + if (obj->action.kind) { + if (nm_streq (obj->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) + nm_hash_update_str (h, obj->action.simple.sdata); + } +} + +int +nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b) +{ + NM_CMP_SELF (a, b); + NM_CMP_FIELD (a, b, ifindex); + NM_CMP_FIELD (a, b, parent); + NM_CMP_FIELD_STR_INTERNED (a, b, kind); + NM_CMP_FIELD (a, b, addr_family); + NM_CMP_FIELD (a, b, handle); + NM_CMP_FIELD (a, b, info); + + NM_CMP_FIELD_STR_INTERNED (a, b, action.kind); + if (a->action.kind) { + if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) + NM_CMP_FIELD_STR (a, b, action.simple.sdata); + } + + return 0; +} + void nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h) { @@ -5538,6 +5834,7 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, + obj->r_rtm_flags & RTNH_F_ONLINK, NM_HASH_COMBINE_BOOLS (guint8, obj->lock_window, obj->lock_cwnd, @@ -5563,8 +5860,8 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, + obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK), NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5589,8 +5886,8 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, + obj->r_rtm_flags, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5627,6 +5924,8 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route NM_CMP_FIELD (a, b, initcwnd); NM_CMP_FIELD (a, b, initrwnd); NM_CMP_FIELD (a, b, mtu); + NM_CMP_DIRECT (a->r_rtm_flags & RTNH_F_ONLINK, + b->r_rtm_flags & RTNH_F_ONLINK); NM_CMP_FIELD_UNSAFE (a, b, lock_window); NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd); NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd); @@ -5660,7 +5959,11 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route } NM_CMP_FIELD (a, b, mss); NM_CMP_FIELD (a, b, pref_src); - NM_CMP_FIELD_UNSAFE (a, b, rt_cloned); + if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { + NM_CMP_DIRECT (a->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK), + b->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK)); + } else + NM_CMP_FIELD (a, b, r_rtm_flags); NM_CMP_FIELD (a, b, tos); NM_CMP_FIELD_UNSAFE (a, b, lock_window); NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd); @@ -5717,8 +6020,8 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo obj->src_plen, nmp_utils_ip_config_source_round_trip_rtprot (obj->rt_source), obj->mss, + obj->r_rtm_flags & RTM_F_CLONED, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5744,8 +6047,8 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo obj->src_plen, obj->rt_source, obj->mss, + obj->r_rtm_flags, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5810,7 +6113,11 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route NM_CMP_FIELD (a, b, rt_source); } NM_CMP_FIELD (a, b, mss); - NM_CMP_FIELD_UNSAFE (a, b, rt_cloned); + if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { + NM_CMP_DIRECT (a->r_rtm_flags & RTM_F_CLONED, + b->r_rtm_flags & RTM_F_CLONED); + } else + NM_CMP_FIELD (a, b, r_rtm_flags); NM_CMP_FIELD_UNSAFE (a, b, lock_window); NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd); NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd); @@ -5927,6 +6234,18 @@ log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatform _LOGD ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route, NULL, 0)); } +static void +log_qdisc (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformQdisc *qdisc, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + _LOGD ("signal: qdisc %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_qdisc_to_string (qdisc, NULL, 0)); +} + +static void +log_tfilter (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformTfilter *tfilter, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + _LOGD ("signal: tfilter %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_tfilter_to_string (tfilter, NULL, 0)); +} + /*****************************************************************************/ void @@ -6200,4 +6519,6 @@ nm_platform_class_init (NMPlatformClass *platform_class) SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, log_ip6_address); SIGNAL (NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, log_ip4_route); SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route); + SIGNAL (NM_PLATFORM_SIGNAL_ID_QDISC, NM_PLATFORM_SIGNAL_QDISC_CHANGED, log_qdisc); + SIGNAL (NM_PLATFORM_SIGNAL_ID_TFILTER, NM_PLATFORM_SIGNAL_TFILTER_CHANGED, log_tfilter); } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index d155c109..f6bf02bf 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2017 Red Hat, Inc. */ #ifndef __NETWORKMANAGER_PLATFORM_H__ @@ -236,6 +236,8 @@ typedef enum { /*< skip >*/ NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, + NM_PLATFORM_SIGNAL_ID_QDISC, + NM_PLATFORM_SIGNAL_ID_TFILTER, _NM_PLATFORM_SIGNAL_ID_LAST, } NMPlatformSignalIdType; @@ -375,13 +377,6 @@ typedef union { \ guint8 plen; \ \ - /* the route has rtm_flags set to RTM_F_CLONED. Such a route - * is hidden by platform and does not exist from the point-of-view - * of platform users. This flag is internal to track those hidden - * routes. Such a route is not alive, according to nmp_object_is_alive(). */ \ - bool rt_cloned:1; \ - \ - \ /* RTA_METRICS: * * For IPv4 routes, these properties are part of their @@ -401,6 +396,18 @@ typedef union { bool lock_initrwnd:1; \ bool lock_mtu:1; \ \ + /* rtnh_flags + * + * Routes with rtm_flags RTM_F_CLONED are hidden by platform and + * do not exist from the point-of-view of platform users. + * Such a route is not alive, according to nmp_object_is_alive(). + * + * XXX: currently we ignore all flags except RTM_F_CLONED + * and RTNH_F_ONLINK for IPv4. + * We also may not properly consider the flags as part of the ID + * in route-cmp. */ \ + unsigned r_rtm_flags; \ + \ /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \ guint32 mss; \ \ @@ -441,23 +448,11 @@ typedef struct { }; } NMPlatformIPRoute; -#if _NM_CC_SUPPORT_GENERIC -#define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \ - (_Generic ((route), \ - const NMPlatformIPRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIPRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - const NMPlatformIPXRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIPXRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - const NMPlatformIP4Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIP4Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - const NMPlatformIP6Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIP6Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - const void *: ((const NMPlatformIPRoute *) (route))->plen, \ - void *: ((const NMPlatformIPRoute *) (route))->plen) == 0) -#else +#define NM_PLATFORM_IP_ROUTE_CAST(route) \ + NM_CONSTCAST (NMPlatformIPRoute, (route), NMPlatformIPXRoute, NMPlatformIP4Route, NMPlatformIP6Route) + #define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \ - ( ((const NMPlatformIPRoute *) (route))->plen <= 0 ) -#endif + (NM_PLATFORM_IP_ROUTE_CAST (route)->plen <= 0) struct _NMPlatformIP4Route { __NMPlatformIPRoute_COMMON; @@ -534,6 +529,37 @@ typedef union { #undef __NMPlatformIPRoute_COMMON +typedef struct { + __NMPlatformObject_COMMON; + const char *kind; + int addr_family; + guint32 handle; + guint32 parent; + guint32 info; +} NMPlatformQdisc; + +typedef struct { + char sdata[32]; +} NMPlatformActionSimple; + +typedef struct { + const char *kind; + union { + NMPlatformActionSimple simple; + }; +} NMPlatformAction; + +#define NM_PLATFORM_ACTION_KIND_SIMPLE "simple" + +typedef struct { + __NMPlatformObject_COMMON; + const char *kind; + int addr_family; + guint32 handle; + guint32 parent; + guint32 info; + NMPlatformAction action; +} NMPlatformTfilter; #undef __NMPlatformObject_COMMON @@ -805,6 +831,8 @@ typedef struct { gboolean (*mesh_set_channel) (NMPlatform *, int ifindex, guint32 channel); gboolean (*mesh_set_ssid) (NMPlatform *, int ifindex, const guint8 *ssid, gsize len); + gboolean (*object_delete) (NMPlatform *, const NMPObject *obj); + gboolean (*ip4_address_add) (NMPlatform *, int ifindex, in_addr_t address, @@ -829,14 +857,20 @@ typedef struct { NMPNlmFlags flags, int addr_family, const NMPlatformIPRoute *route); - gboolean (*ip_route_delete) (NMPlatform *, const NMPObject *obj); - NMPlatformError (*ip_route_get) (NMPlatform *self, int addr_family, gconstpointer address, int oif_ifindex, NMPObject **out_route); + NMPlatformError (*qdisc_add) (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc); + + NMPlatformError (*tfilter_add) (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformTfilter *tfilter); + NMPlatformKernelSupportFlags (*check_kernel_support) (NMPlatform * self, NMPlatformKernelSupportFlags request_flags); } NMPlatformClass; @@ -857,6 +891,8 @@ typedef struct { #define NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED "ip6-address-changed" #define NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED "ip4-route-changed" #define NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED "ip6-route-changed" +#define NM_PLATFORM_SIGNAL_QDISC_CHANGED "qdisc-changed" +#define NM_PLATFORM_SIGNAL_TFILTER_CHANGED "tfilter-changed" const char *nm_platform_signal_change_type_to_string (NMPlatformSignalChangeType change_type); @@ -1194,6 +1230,8 @@ NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); +gboolean nm_platform_object_delete (NMPlatform *self, const NMPObject *route); + gboolean nm_platform_ip4_address_add (NMPlatform *self, int ifindex, in_addr_t address, @@ -1228,8 +1266,6 @@ NMPlatformError nm_platform_ip_route_add (NMPlatform *self, NMPlatformError nm_platform_ip4_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route); NMPlatformError nm_platform_ip6_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route); -gboolean nm_platform_ip_route_delete (NMPlatform *self, const NMPObject *route); - GPtrArray *nm_platform_ip_route_get_prune_list (NMPlatform *self, int addr_family, int ifindex, @@ -1252,6 +1288,20 @@ NMPlatformError nm_platform_ip_route_get (NMPlatform *self, int oif_ifindex, NMPObject **out_route); +NMPlatformError nm_platform_qdisc_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc); +gboolean nm_platform_qdisc_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_qdiscs); + +NMPlatformError nm_platform_tfilter_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformTfilter *tfilter); +gboolean nm_platform_tfilter_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_tfilters); + const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len); const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len); @@ -1266,6 +1316,8 @@ const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *addre const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len); const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len); const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len); +const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len); +const char *nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len); const char *nm_platform_vlan_qos_mapping_to_string (const char *name, const NMVlanQosMapping *map, @@ -1301,6 +1353,9 @@ nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6 return nm_platform_ip6_route_cmp (a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL); } +int nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b); +int nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b); + void nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h); void nm_platform_ip4_address_hash_update (const NMPlatformIP4Address *obj, NMHashState *h); void nm_platform_ip6_address_hash_update (const NMPlatformIP6Address *obj, NMHashState *h); @@ -1316,6 +1371,9 @@ void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState * void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h); void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h); +void nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h); +void nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h); + NMPlatformKernelSupportFlags nm_platform_check_kernel_support (NMPlatform *self, NMPlatformKernelSupportFlags request_flags); diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c index 34215828..bc305f01 100644 --- a/src/platform/nmp-netns.c +++ b/src/platform/nmp-netns.c @@ -290,6 +290,7 @@ _netns_new (GError **error) g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "Failed opening netns: %s", g_strerror (errsv)); + errno = errsv; return NULL; } @@ -300,6 +301,7 @@ _netns_new (GError **error) "Failed opening mntns: %s", g_strerror (errsv)); nm_close (fd_net); + errno = errsv; return NULL; } @@ -479,6 +481,7 @@ nmp_netns_new (void) if (!_stack_peek ()) { /* there are no netns instances. We cannot create a new one * (because after unshare we couldn't return to the original one). */ + errno = ENOTSUP; return NULL; } @@ -508,6 +511,7 @@ nmp_netns_new (void) self = _netns_new (&error); if (!self) { + errsv = errno; _LOGE (NULL, "failed to create netns after unshare: %s", error->message); g_clear_error (&error); goto err_out; @@ -518,6 +522,7 @@ nmp_netns_new (void) return self; err_out: _netns_switch_pop (NULL, _CLONE_NS_ALL); + errno = errsv; return NULL; } diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index a8600705..1a9b9325 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -15,7 +15,7 @@ * 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. + * Copyright (C) 2015 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -186,11 +186,13 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, } return 1; - case NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX: + case NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX: if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE) + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC, + NMP_OBJECT_TYPE_TFILTER) || !nmp_object_is_visible (obj_a)) { if (h) nm_hash_update_val (h, obj_a); @@ -737,6 +739,8 @@ _vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->peer_address != obj->address ? "," : "", obj->peer_address != obj->address ? nm_utils_inet4_ntop (nm_utils_ip4_address_clear_host_address (obj->peer_address, obj->plen), buf2) : ""); _vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1)); +_vt_cmd_plobj_to_string_id (qdisc, NMPlatformQdisc, "%d: %d", obj->ifindex, obj->parent); +_vt_cmd_plobj_to_string_id (tfilter, NMPlatformTfilter, "%d: %d", obj->ifindex, obj->parent); void nmp_object_hash_update (const NMPObject *obj, NMHashState *h) @@ -1035,6 +1039,14 @@ _vt_cmd_plobj_id_cmp (ip6_address, NMPlatformIP6Address, /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ NM_CMP_FIELD_IN6ADDR (obj1, obj2, address); ) +_vt_cmd_plobj_id_cmp (qdisc, NMPlatformQdisc, + NM_CMP_FIELD (obj1, obj2, ifindex); + NM_CMP_FIELD (obj1, obj2, parent); +) +_vt_cmd_plobj_id_cmp (tfilter, NMPlatformTfilter, + NM_CMP_FIELD (obj1, obj2, ifindex); + NM_CMP_FIELD (obj1, obj2, handle); +) static int _vt_cmd_plobj_id_cmp_ip4_route (const NMPlatformObject *obj1, const NMPlatformObject *obj2) @@ -1113,6 +1125,16 @@ _vt_cmd_plobj_id_hash_update (ip4_route, NMPlatformIP4Route, { _vt_cmd_plobj_id_hash_update (ip6_route, NMPlatformIP6Route, { nm_platform_ip6_route_hash_update (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, h); }) +_vt_cmd_plobj_id_hash_update (qdisc, NMPlatformQdisc, { + nm_hash_update_vals (h, + obj->ifindex, + obj->parent); +}) +_vt_cmd_plobj_id_hash_update (tfilter, NMPlatformTfilter, { + nm_hash_update_vals (h, + obj->ifindex, + obj->handle); +}) static inline void _vt_cmd_plobj_hash_update_ip4_route (const NMPlatformObject *obj, NMHashState *h) @@ -1170,7 +1192,20 @@ _vt_cmd_obj_is_alive_ipx_route (const NMPObject *obj) * Instead we create a dead object, and nmp_cache_update_netlink() * will remove the old version of the update. **/ - return obj->object.ifindex > 0 && !obj->ip_route.rt_cloned; + return obj->object.ifindex > 0 + && !NM_FLAGS_HAS (obj->ip_route.r_rtm_flags, RTM_F_CLONED); +} + +static gboolean +_vt_cmd_obj_is_alive_qdisc (const NMPObject *obj) +{ + return obj->object.ifindex > 0; +} + +static gboolean +_vt_cmd_obj_is_alive_tfilter (const NMPObject *obj) +{ + return obj->object.ifindex > 0; } gboolean @@ -1202,6 +1237,12 @@ _vt_cmd_obj_is_visible_link (const NMPObject *obj) /*****************************************************************************/ +static const guint8 _supported_cache_ids_object[] = { + NMP_CACHE_ID_TYPE_OBJECT_TYPE, + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, + 0, +}; + static const guint8 _supported_cache_ids_link[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, @@ -1210,13 +1251,13 @@ static const guint8 _supported_cache_ids_link[] = { static const guint8 _supported_cache_ids_ipx_address[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX, + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, 0, }; static const guint8 _supported_cache_ids_ipx_route[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX, + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, 0, @@ -1501,6 +1542,8 @@ nmp_lookup_init_obj_type (NMPLookup *lookup, case NMP_OBJECT_TYPE_IP6_ADDRESS: case NMP_OBJECT_TYPE_IP4_ROUTE: case NMP_OBJECT_TYPE_IP6_ROUTE: + case NMP_OBJECT_TYPE_QDISC: + case NMP_OBJECT_TYPE_TFILTER: o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; return _L (lookup); @@ -1528,9 +1571,9 @@ nmp_lookup_init_link_by_ifname (NMPLookup *lookup, } const NMPLookup * -nmp_lookup_init_addrroute (NMPLookup *lookup, - NMPObjectType obj_type, - int ifindex) +nmp_lookup_init_object (NMPLookup *lookup, + NMPObjectType obj_type, + int ifindex) { NMPObject *o; @@ -1538,7 +1581,9 @@ nmp_lookup_init_addrroute (NMPLookup *lookup, nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)); + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC, + NMP_OBJECT_TYPE_TFILTER)); if (ifindex <= 0) { return nmp_lookup_init_obj_type (lookup, @@ -1547,7 +1592,7 @@ nmp_lookup_init_addrroute (NMPLookup *lookup, o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); o->object.ifindex = ifindex; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX; return _L (lookup); } @@ -2566,6 +2611,42 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_ip6_route, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp_full, }, + [NMP_OBJECT_TYPE_QDISC - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_QDISC, + .sizeof_data = sizeof (NMPObjectQdisc), + .sizeof_public = sizeof (NMPlatformQdisc), + .obj_type_name = "qdisc", + .rtm_gettype = RTM_GETQDISC, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_QDISC, + .signal_type = NM_PLATFORM_SIGNAL_QDISC_CHANGED, + .supported_cache_ids = _supported_cache_ids_object, + .cmd_obj_is_alive = _vt_cmd_obj_is_alive_qdisc, + .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_qdisc, + .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_qdisc, + .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_qdisc, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_qdisc_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_qdisc_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_qdisc_cmp, + }, + [NMP_OBJECT_TYPE_TFILTER - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_TFILTER, + .sizeof_data = sizeof (NMPObjectTfilter), + .sizeof_public = sizeof (NMPlatformTfilter), + .obj_type_name = "tfilter", + .rtm_gettype = RTM_GETTFILTER, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_TFILTER, + .signal_type = NM_PLATFORM_SIGNAL_TFILTER_CHANGED, + .supported_cache_ids = _supported_cache_ids_object, + .cmd_obj_is_alive = _vt_cmd_obj_is_alive_tfilter, + .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_tfilter, + .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_tfilter, + .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_tfilter, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_tfilter_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_tfilter_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_tfilter_cmp, + }, [NMP_OBJECT_TYPE_LNK_GRE - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_GRE, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 41fd08cb..e3862f2d 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -15,7 +15,7 @@ * 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. + * Copyright (C) 2015 - 2017 Red Hat, Inc. */ #ifndef __NMP_OBJECT_H__ @@ -35,8 +35,8 @@ typedef enum { /*< skip >*/ 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_UPDATED = NM_PLATFORM_SIGNAL_CHANGED, NMP_CACHE_OPS_REMOVED = NM_PLATFORM_SIGNAL_REMOVED, } NMPCacheOpsType; @@ -48,12 +48,12 @@ typedef enum { /*< skip >*/ * 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_BY_IFINDEX there + * For example, of the index type NMP_CACHE_ID_TYPE_OBJECT_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_BY_IFINDEX with + * the index NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX with * matching v4/v6 and ifindex -- or maybe not at all if it isn't visible. * */ typedef enum { /*< skip >*/ @@ -82,8 +82,8 @@ typedef enum { /*< skip >*/ * separate for IPv4 and IPv6. */ NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, - /* all the addresses/routes (by object-type) for an ifindex. */ - NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX, + /* all the objects that have an ifindex (by object-type) for an ifindex. */ + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, /* Consider all the destination fields of a route, that is, the ID without the ifindex * and gateway (meaning: network/plen,metric). @@ -225,6 +225,14 @@ typedef struct { NMPlatformIP6Route _public; } NMPObjectIP6Route; +typedef struct { + NMPlatformQdisc _public; +} NMPObjectQdisc; + +typedef struct { + NMPlatformTfilter _public; +} NMPObjectTfilter; + struct _NMPObject { union { NMDedupMultiObj parent; @@ -276,6 +284,11 @@ struct _NMPObject { NMPlatformIP6Route ip6_route; NMPObjectIP4Route _ip4_route; NMPObjectIP6Route _ip6_route; + + NMPlatformQdisc qdisc; + NMPObjectQdisc _qdisc; + NMPlatformTfilter tfilter; + NMPObjectTfilter _tfilter; }; }; @@ -341,7 +354,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_LINK); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->link : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->link : NULL; \ }) #define NMP_OBJECT_CAST_IP_ADDRESS(obj) \ @@ -349,7 +362,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip_address : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip_address : NULL; \ }) #define NMP_OBJECT_CAST_IPX_ADDRESS(obj) \ @@ -357,7 +370,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ipx_address : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ipx_address : NULL; \ }) #define NMP_OBJECT_CAST_IP4_ADDRESS(obj) \ @@ -365,7 +378,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip4_address : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_address : NULL; \ }) #define NMP_OBJECT_CAST_IP6_ADDRESS(obj) \ @@ -373,7 +386,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip6_address : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_address : NULL; \ }) #define NMP_OBJECT_CAST_IPX_ROUTE(obj) \ @@ -381,7 +394,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ipx_route : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ipx_route : NULL; \ }) #define NMP_OBJECT_CAST_IP_ROUTE(obj) \ @@ -389,7 +402,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip_route : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip_route : NULL; \ }) #define NMP_OBJECT_CAST_IP4_ROUTE(obj) \ @@ -397,7 +410,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP4_ROUTE); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip4_route : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_route : NULL; \ }) #define NMP_OBJECT_CAST_IP6_ROUTE(obj) \ @@ -405,7 +418,23 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP6_ROUTE); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip6_route : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_route : NULL; \ + }) + +#define NMP_OBJECT_CAST_QDISC(obj) \ + ({ \ + typeof (obj) _obj = (obj); \ + \ + nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_QDISC); \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->qdisc : NULL; \ + }) + +#define NMP_OBJECT_CAST_TFILTER(obj) \ + ({ \ + typeof (obj) _obj = (obj); \ + \ + nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_TFILTER); \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->tfilter : NULL; \ }) const NMPClass *nmp_class_from_type (NMPObjectType obj_type); @@ -536,9 +565,9 @@ const NMPLookup *nmp_lookup_init_obj_type (NMPLookup *lookup, NMPObjectType obj_type); const NMPLookup *nmp_lookup_init_link_by_ifname (NMPLookup *lookup, const char *ifname); -const NMPLookup *nmp_lookup_init_addrroute (NMPLookup *lookup, - NMPObjectType obj_type, - int ifindex); +const NMPLookup *nmp_lookup_init_object (NMPLookup *lookup, + NMPObjectType obj_type, + int ifindex); const NMPLookup *nmp_lookup_init_route_default (NMPLookup *lookup, NMPObjectType obj_type); const NMPLookup *nmp_lookup_init_route_by_weak_id (NMPLookup *lookup, @@ -717,26 +746,26 @@ nm_platform_lookup_link_by_ifname (NMPlatform *platform, } static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_addrroute (NMPlatform *platform, - NMPObjectType obj_type, - int ifindex) +nm_platform_lookup_object (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex) { NMPLookup lookup; - nmp_lookup_init_addrroute (&lookup, obj_type, ifindex); + nmp_lookup_init_object (&lookup, obj_type, ifindex); return nm_platform_lookup (platform, &lookup); } static inline GPtrArray * -nm_platform_lookup_addrroute_clone (NMPlatform *platform, - NMPObjectType obj_type, - int ifindex, - NMPObjectPredicateFunc predicate, - gpointer user_data) +nm_platform_lookup_object_clone (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex, + NMPObjectPredicateFunc predicate, + gpointer user_data) { NMPLookup lookup; - nmp_lookup_init_addrroute (&lookup, obj_type, ifindex); + nmp_lookup_init_object (&lookup, obj_type, ifindex); return nm_platform_lookup_clone (platform, &lookup, predicate, user_data); } diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 18076712..9a12f8f9 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2016 Red Hat, Inc. + * Copyright 2016 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -78,9 +78,9 @@ _ipx_address_get_all (NMPlatform *self, int ifindex, NMPObjectType obj_type) g_assert (NM_IS_PLATFORM (self)); g_assert (ifindex > 0); g_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); - nmp_lookup_init_addrroute (&lookup, - obj_type, - ifindex); + nmp_lookup_init_object (&lookup, + obj_type, + ifindex); return nmp_cache_lookup_to_array (nm_platform_lookup (self, &lookup), obj_type, FALSE /*addresses are always visible. */); @@ -108,9 +108,9 @@ nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t n nm_platform_process_events (platform); nm_dedup_multi_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - NMP_OBJECT_TYPE_IP4_ROUTE, - ifindex)) { + nm_platform_lookup_object (platform, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex)) { const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (iter.current->obj); if ( r->ifindex != ifindex @@ -120,7 +120,7 @@ nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t n continue; } - return nm_platform_ip_route_delete (platform, NMP_OBJECT_UP_CAST (r)); + return nm_platform_object_delete (platform, NMP_OBJECT_UP_CAST (r)); } return TRUE; @@ -134,9 +134,9 @@ nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_ nm_platform_process_events (platform); nm_dedup_multi_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex)) { + nm_platform_lookup_object (platform, + NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex)) { const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (iter.current->obj); if ( r->ifindex != ifindex @@ -146,7 +146,7 @@ nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_ continue; } - return nm_platform_ip_route_delete (platform, NMP_OBJECT_UP_CAST (r)); + return nm_platform_object_delete (platform, NMP_OBJECT_UP_CAST (r)); } return TRUE; @@ -1703,8 +1703,8 @@ nmtstp_namespace_create (int unshare_flags, GError **error) errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "pipe() failed with %d (%s)", errsv, strerror (errsv)); - close (pipefd_c2p[0]); - close (pipefd_c2p[1]); + nm_close (pipefd_c2p[0]); + nm_close (pipefd_c2p[1]); return FALSE; } @@ -1713,18 +1713,18 @@ nmtstp_namespace_create (int unshare_flags, GError **error) errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "fork() failed with %d (%s)", errsv, strerror (errsv)); - close (pipefd_c2p[0]); - close (pipefd_c2p[1]); - close (pipefd_p2c[0]); - close (pipefd_p2c[1]); + nm_close (pipefd_c2p[0]); + nm_close (pipefd_c2p[1]); + nm_close (pipefd_p2c[0]); + nm_close (pipefd_p2c[1]); return FALSE; } if (pid == 0) { char read_buf[1]; - close (pipefd_c2p[0]); /* close read-end */ - close (pipefd_p2c[1]); /* close write-end */ + nm_close (pipefd_c2p[0]); /* close read-end */ + nm_close (pipefd_p2c[1]); /* close write-end */ if (unshare (unshare_flags) != 0) { errsv = errno; @@ -1742,7 +1742,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) if (errsv == 0) errsv = -2; } - close (pipefd_c2p[1]); + nm_close (pipefd_c2p[1]); /* wait until parent process terminates (or kills us). */ if (errsv == 0) { @@ -1750,19 +1750,19 @@ nmtstp_namespace_create (int unshare_flags, GError **error) r = read (pipefd_p2c[0], read_buf, sizeof (read_buf)); } while (r < 0 && errno == EINTR); } - close (pipefd_p2c[0]); + nm_close (pipefd_p2c[0]); _exit (0); } - close (pipefd_c2p[1]); /* close write-end */ - close (pipefd_p2c[0]); /* close read-end */ + nm_close (pipefd_c2p[1]); /* close write-end */ + nm_close (pipefd_p2c[0]); /* close read-end */ /* sync with child process. */ do { r = read (pipefd_c2p[0], &errsv, sizeof (errsv)); } while (r < 0 && errno == EINTR); - close (pipefd_c2p[0]); + nm_close (pipefd_c2p[0]); if ( r != sizeof (errsv) || errsv != 0) { @@ -1775,7 +1775,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "child process signaled failure %d (%s)", errsv, strerror (errsv)); } - close (pipefd_p2c[1]); + nm_close (pipefd_p2c[1]); kill (pid, SIGKILL); do { pid2 = waitpid (pid, &status, 0); @@ -1809,7 +1809,7 @@ nmtstp_namespace_handle_release (NMTstpNamespaceHandle *ns_handle) g_return_if_fail (ns_handle->pid > 0); - close (ns_handle->pipe_fd); + nm_close (ns_handle->pipe_fd); ns_handle->pipe_fd = 0; kill (ns_handle->pid, SIGKILL); diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 4010aa2f..fb406a3f 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -227,22 +227,22 @@ static inline GPtrArray * nmtstp_ip4_route_get_all (NMPlatform *platform, int ifindex) { - return nm_platform_lookup_addrroute_clone (platform, - NMP_OBJECT_TYPE_IP4_ROUTE, - ifindex, - nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel, - NULL); + return nm_platform_lookup_object_clone (platform, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex, + nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel, + NULL); } static inline GPtrArray * nmtstp_ip6_route_get_all (NMPlatform *platform, int ifindex) { - return nm_platform_lookup_addrroute_clone (platform, - NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex, - nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel, - NULL); + return nm_platform_lookup_object_clone (platform, + NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex, + nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel, + NULL); } /*****************************************************************************/ diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 9c72371c..d3a10bd6 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -1916,6 +1916,7 @@ _test_netns_check_skip (void) static int support = -1; static int support_errsv = 0; NMPNetns *netns; + gs_unref_object NMPNetns *netns2 = NULL; netns = nmp_netns_get_current (); if (!netns) { @@ -1931,10 +1932,20 @@ _test_netns_check_skip (void) support_errsv = errno; } if (!support) { - _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv)); - g_test_skip ("No netns support (setns failed)"); + _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv)); + g_test_skip ("No netns support (setns failed)"); return TRUE; } + + netns2 = nmp_netns_new (); + if (!netns2) { + /* skip tests for https://bugzilla.gnome.org/show_bug.cgi?id=790214 */ + g_assert_cmpint (errno, ==, EINVAL); + g_test_skip ("No netns support to create another netns"); + return TRUE; + } + nmp_netns_pop (netns2); + return FALSE; } diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index a02388d2..3228de83 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -15,12 +15,13 @@ * 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. + * Copyright (C) 2015 - 2017 Red Hat, Inc. */ #include "nm-default.h" #include <libudev.h> +#include <linux/pkt_sched.h> #include "platform/nmp-object.h" #include "nm-utils/nm-udev-utils.h" @@ -454,6 +455,93 @@ test_cache_link (void) nmp_cache_free (cache); } +const char noqueue[] = "noqueue"; +const char fq_codel[] = "fq_codel"; +const char ingress[] = "ingress"; + +static const NMPlatformQdisc pl_qdisc_1a = { + .ifindex = 1, + .kind = noqueue, + .addr_family = AF_UNSPEC, + .handle = 0, + .parent = TC_H_ROOT, + .info = 0, +}; + +static const NMPlatformQdisc pl_qdisc_1b = { + .ifindex = 1, + .kind = fq_codel, + .addr_family = AF_UNSPEC, + .handle = 0, + .parent = TC_H_ROOT, + .info = 0, +}; + +static const NMPlatformQdisc pl_qdisc_1c = { + .ifindex = 1, + .kind = ingress, + .addr_family = AF_UNSPEC, + .handle = TC_H_MAKE(TC_H_INGRESS, 0), + .parent = TC_H_INGRESS, + .info = 0, +}; + +static const NMPlatformQdisc pl_qdisc_2 = { + .ifindex = 2, + .kind = fq_codel, + .addr_family = AF_UNSPEC, + .handle = 0, + .parent = TC_H_ROOT, + .info = 0, +}; + +static void +test_cache_qdisc (void) +{ + NMPCache *cache; + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = NULL; + NMPLookup lookup; + const NMDedupMultiHeadEntry *head_entry; + nm_auto_nmpobj NMPObject *obj1a = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_1a); + nm_auto_nmpobj NMPObject *obj1b = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_1b); + nm_auto_nmpobj NMPObject *obj1c = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_1c); + nm_auto_nmpobj NMPObject *obj2 = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_2); + + multi_idx = nm_dedup_multi_index_new (); + cache = nmp_cache_new (multi_idx, nmtst_get_rand_int () % 2); + + g_assert (nmp_cache_lookup_obj (cache, obj1a) == NULL); + + g_assert (nmp_cache_update_netlink (cache, obj1a, FALSE, NULL, NULL) == NMP_CACHE_OPS_ADDED); + g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1a); + g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1a); + g_assert (nmp_cache_lookup_obj (cache, obj2) == NULL); + + g_assert (nmp_cache_update_netlink (cache, obj1b, FALSE, NULL, NULL) == NMP_CACHE_OPS_UPDATED); + g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj2) == NULL); + + g_assert (nmp_cache_update_netlink (cache, obj1c, FALSE, NULL, NULL) == NMP_CACHE_OPS_ADDED); + g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj1c) == obj1c); + g_assert (nmp_cache_lookup_obj (cache, obj2) == NULL); + + g_assert (nmp_cache_update_netlink (cache, obj2, FALSE, NULL, NULL) == NMP_CACHE_OPS_ADDED); + g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj2) == obj2); + + head_entry = nmp_cache_lookup (cache, + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_QDISC, + 1)); + g_assert (head_entry->len == 2); + + nmp_cache_free (cache); +} + /*****************************************************************************/ NMTST_DEFINE (); @@ -500,6 +588,7 @@ main (int argc, char **argv) g_test_add_func ("/nmp-object/obj-base", test_obj_base); g_test_add_func ("/nmp-object/cache_link", test_cache_link); + g_test_add_func ("/nmp-object/cache_qdisc", test_cache_qdisc); result = g_test_run (); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 2c00fada..fe97db07 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2016 Red Hat, Inc. + * Copyright 2016 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -31,6 +31,42 @@ #define EX NMTSTP_ENV1_EX static void +_wait_for_ipv4_addr_device_route (NMPlatform *platform, + gint64 timeout_ms, + int ifindex, + in_addr_t addr, + guint8 plen) +{ + /* Wait that the addresses gets a device-route. After adding a address, + * the device route is not added immediately. It takes a moment... */ + + addr = nm_utils_ip4_address_clear_host_address (addr, plen); + NMTST_WAIT_ASSERT (400, { + NMDedupMultiIter iter; + NMPLookup lookup; + const NMPObject *o; + + nmp_cache_iter_for_each (&iter, + nm_platform_lookup (platform, + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex)), + &o) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (o); + + if ( r->plen == plen + && addr == nm_utils_ip4_address_clear_host_address (r->network, plen) + && r->metric == 0 + && r->scope_inv == nm_platform_route_scope_inv (RT_SCOPE_LINK) + && r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + return; + } + nmtstp_assert_wait_for_signal (platform, + (nmtst_wait_end_us - g_get_monotonic_time ()) / 1000); + }); +} + +static void _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, gint64 timeout_ms, int ifindex, @@ -44,7 +80,7 @@ _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, * small amount of time, which prevents the immediate addition of the route * with RTA_PREFSRC */ - NMTST_WAIT_ASSERT (400, { + NMTST_WAIT_ASSERT (timeout_ms, { gboolean should_wait = FALSE; const NMPlatformIP6Address *plt_addr; @@ -63,7 +99,6 @@ _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, }); } - static void ip4_route_callback (NMPlatform *platform, int obj_type_i, int ifindex, const NMPlatformIP4Route *received, int change_type_i, SignalData *data) { @@ -417,7 +452,7 @@ test_ip_route_get (void) g_assert (!NMP_OBJECT_IS_STACKINIT (route)); g_assert (route->parent._ref_count == 1); r = NMP_OBJECT_CAST_IP4_ROUTE (route); - g_assert (r->rt_cloned); + g_assert (NM_FLAGS_HAS (r->r_rtm_flags, RTM_F_CLONED)); g_assert (r->ifindex == ifindex); g_assert (r->network == a); g_assert (r->plen == 32); @@ -448,63 +483,114 @@ test_ip4_zero_gateway (void) } static void -test_ip4_route_options (void) +test_ip4_route_options (gconstpointer test_data) { - int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); - NMPlatformIP4Route route = { }; - in_addr_t network; - GPtrArray *routes; - NMPlatformIP4Route rts[1]; + const int TEST_IDX = GPOINTER_TO_INT (test_data); + const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + gs_unref_ptrarray GPtrArray *routes = NULL; +#define RTS_MAX 3 + NMPlatformIP4Route rts_add[RTS_MAX] = { }; + NMPlatformIP4Route rts_cmp[RTS_MAX] = { }; + NMPlatformIP4Address addr[1] = { }; + guint i; + guint rts_n = 0; + guint addr_n = 0; - inet_pton (AF_INET, "172.16.1.0", &network); + switch (TEST_IDX) { + case 1: + rts_add[rts_n++] = ((NMPlatformIP4Route) { + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string ("172.16.1.0"), + .plen = 24, + .metric = 20, + .tos = 0x28, + .window = 10000, + .cwnd = 16, + .initcwnd = 30, + .initrwnd = 50, + .mtu = 1350, + .lock_cwnd = TRUE, + }); + break; + case 2: + addr[addr_n++] = ((NMPlatformIP4Address) { + .ifindex = IFINDEX, + .address = nmtst_inet4_from_string ("172.16.1.5"), + .peer_address = nmtst_inet4_from_string ("172.16.1.5"), + .plen = 24, + .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, + .preferred = NM_PLATFORM_LIFETIME_PERMANENT, + .n_ifa_flags = 0, + }); + rts_add[rts_n++] = ((NMPlatformIP4Route) { + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string ("172.17.1.0"), + .gateway = nmtst_inet4_from_string ("172.16.1.1"), + .plen = 24, + .metric = 20, + }); + rts_add[rts_n++] = ((NMPlatformIP4Route) { + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string ("172.19.1.0"), + .gateway = nmtst_inet4_from_string ("172.18.1.1"), + .r_rtm_flags = RTNH_F_ONLINK, + .plen = 24, + .metric = 20, + }); + break; + default: + g_assert_not_reached (); + break; + } + g_assert (rts_n <= G_N_ELEMENTS (rts_add)); + g_assert (addr_n <= G_N_ELEMENTS (addr)); - route.ifindex = ifindex; - route.rt_source = NM_IP_CONFIG_SOURCE_USER; - route.network = network; - route.plen = 24; - route.metric = 20; - route.tos = 0x28; - route.window = 10000; - route.cwnd = 16; - route.initcwnd = 30; - route.initrwnd = 50; - route.mtu = 1350; - route.lock_cwnd = TRUE; + for (i = 0; i < addr_n; i++) { + const NMPlatformIP4Address *a = &addr[i]; + + g_assert (a->ifindex == IFINDEX); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, + a->ifindex, + a->address, + a->plen, + a->peer_address, + a->lifetime, + a->preferred, + a->n_ifa_flags, + a->label)); + if (a->peer_address == a->address) + _wait_for_ipv4_addr_device_route (NM_PLATFORM_GET, 200, a->ifindex, a->address, a->plen); + } - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &route) == NM_PLATFORM_ERROR_SUCCESS); + for (i = 0; i < rts_n; i++) + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]) == NM_PLATFORM_ERROR_SUCCESS); - /* Test route listing */ - routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex); - memset (rts, 0, sizeof (rts)); - rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); - rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK); - rts[0].network = network; - rts[0].plen = 24; - rts[0].ifindex = ifindex; - rts[0].metric = 20; - rts[0].tos = 0x28; - rts[0].window = 10000; - rts[0].cwnd = 16; - rts[0].initcwnd = 30; - rts[0].initrwnd = 50; - rts[0].mtu = 1350; - rts[0].lock_cwnd = TRUE; - g_assert_cmpint (routes->len, ==, 1); - nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE); + for (i = 0; i < rts_n; i++) { + rts_cmp[i] = rts_add[i]; + nm_platform_ip_route_normalize (AF_INET, NM_PLATFORM_IP_ROUTE_CAST (&rts_cmp[i])); + } - /* Remove route */ - g_assert (nm_platform_ip_route_delete (NM_PLATFORM_GET, routes->pdata[0])); + routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, IFINDEX); + g_assert_cmpint (routes->len, ==, rts_n); + nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts_cmp, routes->len, TRUE); - g_ptr_array_unref (routes); + for (i = 0; i < rts_n; i++) { + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, IFINDEX, + rts_add[i].network, rts_add[i].plen, + rts_add[i].metric)); + } +#undef RTS_MAX } - static void test_ip6_route_options (gconstpointer test_data) { const int TEST_IDX = GPOINTER_TO_INT (test_data); const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); - GPtrArray *routes; + gs_unref_ptrarray GPtrArray *routes = NULL; #define RTS_MAX 3 NMPlatformIP6Route rts_add[RTS_MAX] = { }; NMPlatformIP6Route rts_cmp[RTS_MAX] = { }; @@ -582,6 +668,8 @@ test_ip6_route_options (gconstpointer test_data) default: g_assert_not_reached (); } + g_assert (rts_n <= G_N_ELEMENTS (rts_add)); + g_assert (addr_n <= G_N_ELEMENTS (addr)); for (i = 0; i < addr_n; i++) { g_assert (addr[i].ifindex == IFINDEX); @@ -595,28 +683,19 @@ test_ip6_route_options (gconstpointer test_data) addr[i].preferred, addr[i].n_ifa_flags)); } - _wait_for_ipv6_addr_non_tentative (NM_PLATFORM_GET, 400, IFINDEX, addr_n, addr_in6); for (i = 0; i < rts_n; i++) g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]) == NM_PLATFORM_ERROR_SUCCESS); - routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX); - switch (TEST_IDX) { - case 1: - case 2: - case 3: - for (i = 0; i < rts_n; i++) { - rts_cmp[i] = rts_add[i]; - rts_cmp[i].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); - } - break; - default: - g_assert_not_reached (); + for (i = 0; i < rts_n; i++) { + rts_cmp[i] = rts_add[i]; + nm_platform_ip_route_normalize (AF_INET6, NM_PLATFORM_IP_ROUTE_CAST (&rts_cmp[i])); } + + routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX); g_assert_cmpint (routes->len, ==, rts_n); nmtst_platform_ip6_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts_cmp, routes->len, TRUE); - g_ptr_array_unref (routes); for (i = 0; i < rts_n; i++) { g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, IFINDEX, @@ -631,6 +710,7 @@ test_ip6_route_options (gconstpointer test_data) rts_add[i].network, rts_add[i].plen); } +#undef RTS_MAX } /*****************************************************************************/ @@ -714,7 +794,7 @@ again_find_idx: order_len--; r->ifindex = iface_data[idx].ifindex; - g_assert (nm_platform_ip_route_delete (platform, &o)); + g_assert (nm_platform_object_delete (platform, &o)); } head_entry = nm_platform_lookup (platform, @@ -771,7 +851,9 @@ _nmtstp_setup_tests (void) add_test_func ("/route/ip4", test_ip4_route); add_test_func ("/route/ip6", test_ip6_route); add_test_func ("/route/ip4_metric0", test_ip4_route_metric0); - add_test_func ("/route/ip4_options", test_ip4_route_options); + add_test_func_data ("/route/ip4_options/1", test_ip4_route_options, GINT_TO_POINTER (1)); + if (nmtstp_is_root_test ()) + add_test_func_data ("/route/ip4_options/2", test_ip4_route_options, GINT_TO_POINTER (2)); add_test_func_data ("/route/ip6_options/1", test_ip6_route_options, GINT_TO_POINTER (1)); add_test_func_data ("/route/ip6_options/2", test_ip6_route_options, GINT_TO_POINTER (2)); add_test_func_data ("/route/ip6_options/3", test_ip6_route_options, GINT_TO_POINTER (3)); |