diff options
| author | Michael Biebl <biebl@debian.org> | 2017-12-12 15:53:07 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2017-12-12 15:53:07 +0100 |
| commit | afcd268ea7b1149fbfb66bce4eca659b675da0a2 (patch) | |
| tree | c3fca2203ad17434daf3ccf576582bd66aa41ab2 /src/platform/nm-linux-platform.c | |
| parent | 417f6015c3dc8c47cf27daa59f64e0e36c521b9c (diff) | |
New upstream version 1.10.2 upstream/1.10.2
Diffstat (limited to 'src/platform/nm-linux-platform.c')
| -rw-r--r-- | src/platform/nm-linux-platform.c | 460 |
1 files changed, 403 insertions, 57 deletions
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; |