Commit b0fd3ecb authored by Lubomir Rintel's avatar Lubomir Rintel

platform: add support for traffic filters

parent 32618200
......@@ -176,8 +176,11 @@ typedef enum {
NMP_OBJECT_TYPE_IP6_ADDRESS,
NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE,
NMP_OBJECT_TYPE_QDISC,
NMP_OBJECT_TYPE_TFILTER,
NMP_OBJECT_TYPE_LNK_GRE,
NMP_OBJECT_TYPE_LNK_INFINIBAND,
NMP_OBJECT_TYPE_LNK_IP6TNL,
......
......@@ -251,6 +251,7 @@ enum {
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,
};
......@@ -262,10 +263,11 @@ typedef enum {
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_LINK = (1LL << 6),
DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 10),
DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 11),
DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 12),
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 |
......@@ -273,7 +275,8 @@ typedef enum {
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_QDISCS,
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1,
} DelayedActionType;
......@@ -975,6 +978,8 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len)
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;
......@@ -1022,6 +1027,7 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len)
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");
......@@ -1031,6 +1037,7 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len)
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");
......@@ -2368,6 +2375,40 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
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
......@@ -2408,6 +2449,10 @@ nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_m
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;
}
......@@ -2890,6 +2935,93 @@ nla_put_failure:
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;
if (!(prio = nla_nest_start (msg, 1 /* priority */)))
goto nla_put_failure;
NLA_PUT_STRING (msg, TCA_ACT_KIND, action->kind);
if (strcmp (action->kind, "simple") == 0)
_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
******************************************************************/
......@@ -3292,6 +3424,7 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_from_object_type, NMPObj
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 (),
);
......@@ -3303,6 +3436,7 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_to_object_type, DelayedA
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 (),
);
......@@ -3314,6 +3448,7 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_all_to_idx, DelayedActio
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 (),
);
......@@ -3325,6 +3460,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType,
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"),
......@@ -3762,7 +3898,7 @@ cache_on_change (NMPlatform *platform,
{
int ifindex = 0;
/* if we remove a link (from netlink), we must refresh the addresses, routes and qdiscs */
/* 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;
......@@ -3778,7 +3914,8 @@ cache_on_change (NMPlatform *platform,
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_QDISCS,
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
NULL);
}
}
......@@ -4127,7 +4264,8 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio
if (!nlmsg)
continue;
if (klass->obj_type == NMP_OBJECT_TYPE_QDISC) {
if ( klass->obj_type == NMP_OBJECT_TYPE_QDISC
|| klass->obj_type == NMP_OBJECT_TYPE_TFILTER) {
struct tcmsg tcmsg = {
.tcm_family = AF_UNSPEC,
};
......@@ -4260,6 +4398,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
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;
......@@ -4284,6 +4423,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
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);
......@@ -4378,6 +4518,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
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);
......@@ -6244,6 +6385,9 @@ object_delete (NMPlatform *platform,
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;
}
......@@ -6373,6 +6517,45 @@ qdisc_add (NMPlatform *platform,
/*****************************************************************************/
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))
......@@ -6655,7 +6838,8 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
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_QDISCS,
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
NULL);
break;
default:
......@@ -6941,7 +7125,8 @@ constructed (GObject *_object)
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_QDISCS,
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
NULL);
delayed_action_handle_all (platform, FALSE);
......@@ -7108,6 +7293,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
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;
......
......@@ -3998,7 +3998,8 @@ nm_platform_object_delete (NMPlatform *self,
if (!NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE,
NMP_OBJECT_TYPE_QDISC))
NMP_OBJECT_TYPE_QDISC,
NMP_OBJECT_TYPE_TFILTER))
g_return_val_if_reached (FALSE);
_LOGD ("%s: delete %s",
......@@ -4399,6 +4400,72 @@ nm_platform_qdisc_sync (NMPlatform *self,
/*****************************************************************************/
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,
......@@ -5276,6 +5343,51 @@ nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b)
return 0;
}
const char *
nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len)
{
char str_dev[TO_STRING_DEV_BUF_SIZE];
if (!nm_utils_to_string_buffer_init_null (tfilter, &buf, &len))
return buf;
g_snprintf (buf, len, "%s%s family %d handle %x parent %x info %x",
tfilter->kind,
_to_string_dev (NULL, tfilter->ifindex, str_dev, sizeof (str_dev)),
tfilter->addr_family,
tfilter->handle,
tfilter->parent,
tfilter->info);
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);
}
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);
return 0;
}
void
nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h)
{
......@@ -6095,6 +6207,12 @@ log_qdisc (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformQdis
_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
......@@ -6369,4 +6487,5 @@ nm_platform_class_init (NMPlatformClass *platform_class)
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);
}
......@@ -237,6 +237,7 @@ typedef enum { /*< skip >*/
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;
......@@ -539,6 +540,27 @@ typedef struct {
guint32 info;
} NMPlatformQdisc;
typedef struct {
char sdata[32];
} NMPlatformActionSimple;
typedef struct {
const char *kind;
union {
NMPlatformActionSimple simple;
};
} NMPlatformAction;
typedef struct {
__NMPlatformObject_COMMON;
const char *kind;
int addr_family;
guint32 handle;
guint32 parent;
guint32 info;
NMPlatformAction action;
} NMPlatformTfilter;
#undef __NMPlatformObject_COMMON
......@@ -845,6 +867,10 @@ typedef struct {
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;
......@@ -866,6 +892,7 @@ typedef struct {
#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);
......@@ -1268,6 +1295,13 @@ 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);
......@@ -1283,6 +1317,7 @@ const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *addre
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,
......@@ -1319,6 +1354,7 @@ nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6
}
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);
......@@ -1336,6 +1372,7 @@ void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState
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);
......
......@@ -191,7 +191,8 @@ _idx_obj_part (const DedupMultiIdxType *idx_type,
NMP_OBJECT_TYPE_IP6_ADDRESS,
NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE,
NMP_OBJECT_TYPE_QDISC)
NMP_OBJECT_TYPE_QDISC,
NMP_OBJECT_TYPE_TFILTER)
|| !nmp_object_is_visible (obj_a)) {
if (h)
nm_hash_update_val (h, obj_a);
......@@ -739,6 +740,7 @@ _vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s",
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 +1037,10 @@ _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);