u32.c revision eed2afaab7aa72fae393a395a8879b91a922ff5e
144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/route/cls/u32.c		u32 classifier
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Copyright (c) 2005-2006 Siemens AG Oesterreich
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup cls_api
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup u32 Universal 32-bit Classifier
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-tc.h>
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/attr.h>
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/tc.h>
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/classifier.h>
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/classifier-modules.h>
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/cls/u32.h>
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @cond SKIP */
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_DIVISOR      0x001
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_HASH         0x002
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_CLASSID      0x004
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_LINK         0x008
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_PCNT         0x010
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_SELECTOR     0x020
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_ACTION       0x040
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_POLICE       0x080
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_INDEV        0x100
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @endcond */
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf
4344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct rtnl_u32 *u32_cls(struct rtnl_cls *cls)
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct rtnl_u32 *) cls->c_subdata;
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf
4844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct rtnl_u32 *u32_alloc(struct rtnl_cls *cls)
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!cls->c_subdata)
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf		cls->c_subdata = calloc(1, sizeof(struct rtnl_u32));
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return u32_cls(cls);
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf
5644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct tc_u32_sel *) u->cu_selector->d_data;
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf
6144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u->cu_selector)
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return u32_selector(u);
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf
6944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy u32_policy[TCA_U32_MAX+1] = {
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_DIVISOR]	= { .type = NLA_U32 },
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_HASH]		= { .type = NLA_U32 },
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_CLASSID]	= { .type = NLA_U32 },
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_LINK]		= { .type = NLA_U32 },
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_INDEV]		= { .type = NLA_STRING,
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf				    .maxlen = IFNAMSIZ },
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_SEL]		= { .minlen = sizeof(struct tc_u32_sel) },
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_PCNT]		= { .minlen = sizeof(struct tc_u32_pcnt) },
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf};
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf
8044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int u32_msg_parser(struct rtnl_cls *cls)
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[TCA_U32_MAX + 1];
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *u;
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf	u = u32_alloc(cls);
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u)
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout_nomem;
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_DIVISOR]) {
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_DIVISOR;
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_SEL]) {
100eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!u->cu_selector)
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout_nomem;
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_SELECTOR;
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_HASH]) {
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_HASH;
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_CLASSID]) {
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_CLASSID;
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_LINK]) {
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_LINK;
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_ACT]) {
122eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]);
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!u->cu_act)
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout_nomem;
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_ACTION;
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_POLICE]) {
129eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!u->cu_police)
13144d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout_nomem;
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_POLICE;
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
13444d362409d5469aed47d19e7908d19bd194493aThomas Graf
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_PCNT]) {
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct tc_u32_sel *sel;
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf		int pcnt_size;
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!tb[TCA_U32_SEL]) {
1408a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_MISSING_ATTR;
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
14344d362409d5469aed47d19e7908d19bd194493aThomas Graf
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf		sel = u->cu_selector->d_data;
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf		pcnt_size = sizeof(struct tc_u32_pcnt) +
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf				(sel->nkeys * sizeof(uint64_t));
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
1488a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_INVAL;
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf
152eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!u->cu_pcnt)
15444d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout_nomem;
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_PCNT;
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_INDEV]) {
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_INDEV;
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf
16544d362409d5469aed47d19e7908d19bd194493aThomas Graferrout_nomem:
1668a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	err = -NLE_NOMEM;
16744d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
16944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf
17144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void u32_free_data(struct rtnl_cls *cls)
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *u = u32_cls(cls);
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u)
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return;
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(u->cu_selector);
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(u->cu_act);
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(u->cu_police);
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(u->cu_pcnt);
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(cls->c_subdata);
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf
18644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *dst, *src = u32_cls(_src);
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf
19044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!src)
19144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst = u32_alloc(_dst);
19444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!dst)
1958a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->cu_selector)
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->cu_selector = nl_data_clone(src->cu_selector)))
1998a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->cu_act)
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->cu_act = nl_data_clone(src->cu_act)))
2038a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->cu_police)
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->cu_police = nl_data_clone(src->cu_police)))
2078a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->cu_pcnt)
21044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
2118a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
21444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf
21644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int u32_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf			  int line)
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *u = u32_cls(cls);
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[32];
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf
22244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u)
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto ignore;
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_DIVISOR)
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, " divisor %u", u->cu_divisor);
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf	else if (u->cu_mask & U32_ATTR_CLASSID)
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, " target %s",
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf
23144d362409d5469aed47d19e7908d19bd194493aThomas Grafignore:
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf
23544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf			  struct rtnl_cls *cls, struct rtnl_u32 *u, int line)
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_u32_key *key;
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf
24144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (sel->hmask || sel->hoff) {
24244d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* I guess this will never be used since the kernel only
24344d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * exports the selector if no divisor is set but hash offset
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * and hash mask make only sense in hash filters with divisor
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * set */
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, " offset at %u", sel->off);
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (sel->flags & TC_U32_VAROFFSET)
25344d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, " variable (at %u & 0x%x) >> %u",
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf				sel->offoff, ntohs(sel->offmask), sel->offshift);
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (sel->flags) {
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf		int flags = sel->flags;
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, " <");
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf	flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(TERMINAL);
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(OFFSET);
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(VAROFFSET);
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(EAT);
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef PRINT_FLAG
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, ">");
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 0; i < sel->nkeys; i++) {
27544d362409d5469aed47d19e7908d19bd194493aThomas Graf		key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "\n");
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "      match key at %s%u ",
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf		key->offmask ? "nexthdr+" : "", key->off);
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (key->offmask)
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, "[0x%u] ", key->offmask);
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (p->dp_type == NL_DUMP_STATS &&
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf		    (u->cu_mask & U32_ATTR_PCNT)) {
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf			struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf
29744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int u32_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p,
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf			 int line)
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *u = u32_cls(cls);
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_u32_sel *s;
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u)
30444d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto ignore;
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "no-selector\n");
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return line;
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf	s = u->cu_selector->d_data;
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump(p, "nkeys %u ", s->nkeys);
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf
31544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_HASH)
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "ht key 0x%x hash 0x%u",
31744d362409d5469aed47d19e7908d19bd194493aThomas Graf			TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_LINK)
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "link %u ", u->cu_link);
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_INDEV)
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "indev %s ", u->cu_indev);
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf
32544d362409d5469aed47d19e7908d19bd194493aThomas Graf	line = print_selector(p, s, cls, u, line);
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump(p, "\n");
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf
32844d362409d5469aed47d19e7908d19bd194493aThomas Grafignore:
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_ACTION       0x040
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_POLICE       0x080
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_data   act;
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_data   police;
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf
34044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p,
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf			  int line)
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *u = u32_cls(cls);
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u)
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto ignore;
34744d362409d5469aed47d19e7908d19bd194493aThomas Graf
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_PCNT) {
34944d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "\n");
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "%s         successful       hits\n");
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "%s           %8llu   %8llu\n",
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf			     pc->rhit, pc->rcnt);
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf
35644d362409d5469aed47d19e7908d19bd194493aThomas Grafignore:
35744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf
36044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_msg *u32_get_opts(struct rtnl_cls *cls)
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *u;
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
36444d362409d5469aed47d19e7908d19bd194493aThomas Graf
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf	u = u32_cls(cls);
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u)
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf	msg = nlmsg_alloc();
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!msg)
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_DIVISOR)
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor);
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_HASH)
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_put_u32(msg, TCA_U32_HASH, u->cu_hash);
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_CLASSID)
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid);
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf
38244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_LINK)
38344d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_put_u32(msg, TCA_U32_LINK, u->cu_link);
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf
38544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_SELECTOR)
38644d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_put_data(msg, TCA_U32_SEL, u->cu_selector);
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_ACTION)
38944d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_put_data(msg, TCA_U32_ACT, u->cu_act);
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf
39144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_POLICE)
39244d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_put_data(msg, TCA_U32_POLICE, u->cu_police);
39344d362409d5469aed47d19e7908d19bd194493aThomas Graf
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_INDEV)
39544d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_put_string(msg, TCA_U32_INDEV, u->cu_indev);
39644d362409d5469aed47d19e7908d19bd194493aThomas Graf
39744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return msg;
39844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
39944d362409d5469aed47d19e7908d19bd194493aThomas Graf
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
40144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attribute Modifications
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf
40544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
40644d362409d5469aed47d19e7908d19bd194493aThomas Graf			 int nodeid)
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
40844d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
40944d362409d5469aed47d19e7908d19bd194493aThomas Graf
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf	tca_set_handle((struct rtnl_tca *) cls, handle );
41144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
41244d362409d5469aed47d19e7908d19bd194493aThomas Graf
41344d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
41444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
41544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *u;
41644d362409d5469aed47d19e7908d19bd194493aThomas Graf
41744d362409d5469aed47d19e7908d19bd194493aThomas Graf	u = u32_alloc(cls);
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u)
4198a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
42044d362409d5469aed47d19e7908d19bd194493aThomas Graf
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf	u->cu_classid = classid;
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf	u->cu_mask |= U32_ATTR_CLASSID;
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
42544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
43044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Selector Modifications
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf
43444d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_u32_sel *sel;
43744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *u;
43844d362409d5469aed47d19e7908d19bd194493aThomas Graf
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf	u = u32_alloc(cls);
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u)
4418a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
44244d362409d5469aed47d19e7908d19bd194493aThomas Graf
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel = u32_selector_alloc(u);
44444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!sel)
4458a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
44644d362409d5469aed47d19e7908d19bd194493aThomas Graf
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->flags |= flags;
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf	u->cu_mask |= U32_ATTR_SELECTOR;
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
45144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
45244d362409d5469aed47d19e7908d19bd194493aThomas Graf
45344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
45444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Append new 32-bit key to the selector
45544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
45644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cls	classifier to be modifier
45744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg val	value to be matched (network byte-order)
45844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg mask	mask to be applied before matching (network byte-order)
45944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg off	offset, in bytes, to start matching
46044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg offmask	offset mask
46144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf * General selectors define the pattern, mask and offset the pattern will be
46344d362409d5469aed47d19e7908d19bd194493aThomas Graf * matched to the packet contents. Using the general selectors you can match
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf * virtually any single bit in the IP (or upper layer) header.
46544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
46644d362409d5469aed47d19e7908d19bd194493aThomas Graf*/
46744d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf		     int off, int offmask)
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_u32_sel *sel;
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_u32 *u;
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
47344d362409d5469aed47d19e7908d19bd194493aThomas Graf
47444d362409d5469aed47d19e7908d19bd194493aThomas Graf	u = u32_alloc(cls);
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u)
4768a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel = u32_selector_alloc(u);
47944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!sel)
4808a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
48344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
48444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
48544d362409d5469aed47d19e7908d19bd194493aThomas Graf
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf	/* the selector might have been moved by realloc */
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel = u32_selector(u);
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->keys[sel->nkeys].mask = mask;
49044d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->keys[sel->nkeys].val = val & mask;
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->keys[sel->nkeys].off = off;
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->keys[sel->nkeys].offmask = offmask;
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->nkeys++;
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf	u->cu_mask |= U32_ATTR_SELECTOR;
49544d362409d5469aed47d19e7908d19bd194493aThomas Graf
49644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
49744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
49844d362409d5469aed47d19e7908d19bd194493aThomas Graf
49944d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
50044d362409d5469aed47d19e7908d19bd194493aThomas Graf			   int off, int offmask)
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
50244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int shift = 24 - 8 * (off & 3);
50344d362409d5469aed47d19e7908d19bd194493aThomas Graf
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
50544d362409d5469aed47d19e7908d19bd194493aThomas Graf				htonl((uint32_t)mask << shift),
50644d362409d5469aed47d19e7908d19bd194493aThomas Graf				off & ~3, offmask);
50744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
50844d362409d5469aed47d19e7908d19bd194493aThomas Graf
50944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
51044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Append new selector key to match a 16-bit number
51144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
51244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cls	classifier to be modified
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg val	value to be matched (host byte-order)
51444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg mask	mask to be applied before matching (host byte-order)
51544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg off	offset, in bytes, to start matching
51644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg offmask	offset mask
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf*/
51844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf			    int off, int offmask)
52044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf	int shift = ((off & 3) == 0 ? 16 : 0);
52244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (off % 2)
5238a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_INVAL;
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf
52544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf				htonl((uint32_t)mask << shift),
52744d362409d5469aed47d19e7908d19bd194493aThomas Graf				off & ~3, offmask);
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
52944d362409d5469aed47d19e7908d19bd194493aThomas Graf
53044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
53144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Append new selector key to match a 32-bit number
53244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cls	classifier to be modified
53444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg val	value to be matched (host byte-order)
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg mask	mask to be applied before matching (host byte-order)
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg off	offset, in bytes, to start matching
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg offmask	offset mask
53844d362409d5469aed47d19e7908d19bd194493aThomas Graf*/
53944d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
54044d362409d5469aed47d19e7908d19bd194493aThomas Graf			    int off, int offmask)
54144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
54244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
54344d362409d5469aed47d19e7908d19bd194493aThomas Graf				off & ~3, offmask);
54444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
54544d362409d5469aed47d19e7908d19bd194493aThomas Graf
54644d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
54744d362409d5469aed47d19e7908d19bd194493aThomas Graf			     uint8_t bitmask, int off, int offmask)
54844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
54944d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
55044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
55144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
55244d362409d5469aed47d19e7908d19bd194493aThomas Graf
55344d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
55444d362409d5469aed47d19e7908d19bd194493aThomas Graf			      uint8_t bitmask, int off, int offmask)
55544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
55644d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i, err;
55744d362409d5469aed47d19e7908d19bd194493aThomas Graf
55844d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 1; i <= 4; i++) {
55944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (32 * i - bitmask <= 0) {
56044d362409d5469aed47d19e7908d19bd194493aThomas Graf			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
56144d362409d5469aed47d19e7908d19bd194493aThomas Graf						0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
56244d362409d5469aed47d19e7908d19bd194493aThomas Graf				return err;
56344d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf		else if (32 * i - bitmask < 32) {
56544d362409d5469aed47d19e7908d19bd194493aThomas Graf			uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
56644d362409d5469aed47d19e7908d19bd194493aThomas Graf			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
56744d362409d5469aed47d19e7908d19bd194493aThomas Graf						htonl(mask), off+4*(i-1), offmask)) < 0)
56844d362409d5469aed47d19e7908d19bd194493aThomas Graf				return err;
56944d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
57044d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* otherwise, if (32*i - bitmask >= 32) no key is generated */
57144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
57444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
57544d362409d5469aed47d19e7908d19bd194493aThomas Graf
57644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
57744d362409d5469aed47d19e7908d19bd194493aThomas Graf
57844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct rtnl_cls_ops u32_ops = {
57944d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_kind		= "u32",
58044d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msg_parser		= u32_msg_parser,
58144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_free_data		= u32_free_data,
58244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_clone		= u32_clone,
58344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_get_opts		= u32_get_opts,
58444d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_dump[NL_DUMP_BRIEF]	= u32_dump_brief,
58544d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_dump[NL_DUMP_FULL]	= u32_dump_full,
58644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_dump[NL_DUMP_STATS]	= u32_dump_stats,
58744d362409d5469aed47d19e7908d19bd194493aThomas Graf};
58844d362409d5469aed47d19e7908d19bd194493aThomas Graf
58944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __init u32_init(void)
59044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
59144d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_cls_register(&u32_ops);
59244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
59344d362409d5469aed47d19e7908d19bd194493aThomas Graf
59444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __exit u32_exit(void)
59544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
59644d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_cls_unregister(&u32_ops);
59744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
59844d362409d5469aed47d19e7908d19bd194493aThomas Graf
59944d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
600