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 *
9ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf * Copyright (c) 2003-2009 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 tc_u32_sel *u32_selector(struct rtnl_u32 *u)
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct tc_u32_sel *) u->cu_selector->d_data;
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf
4844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!u->cu_selector)
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return u32_selector(u);
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf
5644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy u32_policy[TCA_U32_MAX+1] = {
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_DIVISOR]	= { .type = NLA_U32 },
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_HASH]		= { .type = NLA_U32 },
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_CLASSID]	= { .type = NLA_U32 },
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_LINK]		= { .type = NLA_U32 },
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_INDEV]		= { .type = NLA_STRING,
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf				    .maxlen = IFNAMSIZ },
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_SEL]		= { .minlen = sizeof(struct tc_u32_sel) },
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_U32_PCNT]		= { .minlen = sizeof(struct tc_u32_pcnt) },
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf};
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf
6744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int u32_msg_parser(struct rtnl_cls *cls)
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
69ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *u = rtnl_cls_data(cls);
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[TCA_U32_MAX + 1];
71ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	int err;
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_DIVISOR]) {
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_DIVISOR;
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_SEL]) {
83eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!u->cu_selector)
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout_nomem;
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_SELECTOR;
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_HASH]) {
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_HASH;
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_CLASSID]) {
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_CLASSID;
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_LINK]) {
10044d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_LINK;
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_ACT]) {
105eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]);
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!u->cu_act)
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout_nomem;
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_ACTION;
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_POLICE]) {
112eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!u->cu_police)
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout_nomem;
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_POLICE;
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_PCNT]) {
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct tc_u32_sel *sel;
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf		int pcnt_size;
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!tb[TCA_U32_SEL]) {
1238a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_MISSING_ATTR;
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf		sel = u->cu_selector->d_data;
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf		pcnt_size = sizeof(struct tc_u32_pcnt) +
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf				(sel->nkeys * sizeof(uint64_t));
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
1318a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_INVAL;
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
13444d362409d5469aed47d19e7908d19bd194493aThomas Graf
135eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!u->cu_pcnt)
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout_nomem;
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_PCNT;
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
14044d362409d5469aed47d19e7908d19bd194493aThomas Graf
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_U32_INDEV]) {
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
14344d362409d5469aed47d19e7908d19bd194493aThomas Graf		u->cu_mask |= U32_ATTR_INDEV;
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf
14844d362409d5469aed47d19e7908d19bd194493aThomas Graferrout_nomem:
1498a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	err = -NLE_NOMEM;
15044d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf
15444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void u32_free_data(struct rtnl_cls *cls)
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
156ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *u = rtnl_cls_data(cls);
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(u->cu_selector);
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(u->cu_act);
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(u->cu_police);
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(u->cu_pcnt);
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf
16444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
16544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
166ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *dst = rtnl_cls_data(_dst);
167ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *src = rtnl_cls_data(_src);
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf
169ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	if (src->cu_selector &&
170ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	    !(dst->cu_selector = nl_data_clone(src->cu_selector)))
1718a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf
173ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act)))
174ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		return -NLE_NOMEM;
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf
176ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
177ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		return -NLE_NOMEM;
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf
179ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
180ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		return -NLE_NOMEM;
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf
185d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
18644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
187ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *u = rtnl_cls_data(cls);
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[32];
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf
19044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_DIVISOR)
191d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, " divisor %u", u->cu_divisor);
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf	else if (u->cu_mask & U32_ATTR_CLASSID)
193d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, " target %s",
19444d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf
197d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
198d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			   struct rtnl_cls *cls, struct rtnl_u32 *u)
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_u32_key *key;
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (sel->hmask || sel->hoff) {
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* I guess this will never be used since the kernel only
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * exports the selector if no divisor is set but hash offset
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * and hash mask make only sense in hash filters with divisor
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * set */
208d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
21044d362409d5469aed47d19e7908d19bd194493aThomas Graf
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
212d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, " offset at %u", sel->off);
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf
21444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (sel->flags & TC_U32_VAROFFSET)
215d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			nl_dump(p, " variable (at %u & 0x%x) >> %u",
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf				sel->offoff, ntohs(sel->offmask), sel->offshift);
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (sel->flags) {
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf		int flags = sel->flags;
221d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, " <");
22244d362409d5469aed47d19e7908d19bd194493aThomas Graf
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
224d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(TERMINAL);
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(OFFSET);
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(VAROFFSET);
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(EAT);
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef PRINT_FLAG
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf
232d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, ">");
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 0; i < sel->nkeys; i++) {
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf		key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf
239d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "\n");
240d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "      match key at %s%u ",
241d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			key->offmask ? "nexthdr+" : "", key->off);
24244d362409d5469aed47d19e7908d19bd194493aThomas Graf
24344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (key->offmask)
244d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			nl_dump(p, "[0x%u] ", key->offmask);
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf
246d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (p->dp_type == NL_DUMP_STATS &&
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf		    (u->cu_mask & U32_ATTR_PCNT)) {
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf			struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
251d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
25344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf
256d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
258ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *u = rtnl_cls_data(cls);
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_u32_sel *s;
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
262d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "no-selector\n");
263d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		return;
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf	s = u->cu_selector->d_data;
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf
268d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump(p, "nkeys %u ", s->nkeys);
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_HASH)
271d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "ht key 0x%x hash 0x%u",
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf			TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_LINK)
275d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "link %u ", u->cu_link);
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_INDEV)
278d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "indev %s ", u->cu_indev);
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf
280d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	print_selector(p, s, cls, u);
281d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump(p, "\n");
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_ACTION       0x040
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define U32_ATTR_POLICE       0x080
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_data   act;
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_data   police;
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf
292d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p)
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
294ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *u = rtnl_cls_data(cls);
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_PCNT) {
29744d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
298d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "\n");
299ff76549013c31082d303b3feef755bbd35e13ec6Denys Fedoryschenko		nl_dump_line(p, "    hit %8llu count %8llu\n",
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf			     pc->rhit, pc->rcnt);
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf
304ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Grafstatic int u32_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
306ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *u = rtnl_cls_data(cls);
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_DIVISOR)
309ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_HASH)
312ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_CLASSID)
315ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf
31744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_LINK)
318ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_SELECTOR)
321ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_ACTION)
324ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act);
32544d362409d5469aed47d19e7908d19bd194493aThomas Graf
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_POLICE)
327ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (u->cu_mask & U32_ATTR_INDEV)
330ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf		NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf
332ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	return 0;
333ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf
334ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Grafnla_put_failure:
335ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	return -NLE_NOMEM;
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attribute Modifications
34044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf
34344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf			 int nodeid)
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
34744d362409d5469aed47d19e7908d19bd194493aThomas Graf
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf	tca_set_handle((struct rtnl_tca *) cls, handle );
34944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf
35144d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
353ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *u = rtnl_cls_data(cls);
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf	u->cu_classid = classid;
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf	u->cu_mask |= U32_ATTR_CLASSID;
35744d362409d5469aed47d19e7908d19bd194493aThomas Graf
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
36444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Selector Modifications
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf
36844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_u32_sel *sel;
371ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *u = rtnl_cls_data(cls);
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel = u32_selector_alloc(u);
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!sel)
3758a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->flags |= flags;
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf	u->cu_mask |= U32_ATTR_SELECTOR;
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
38244d362409d5469aed47d19e7908d19bd194493aThomas Graf
38344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Append new 32-bit key to the selector
38544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
38644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cls	classifier to be modifier
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg val	value to be matched (network byte-order)
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg mask	mask to be applied before matching (network byte-order)
38944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg off	offset, in bytes, to start matching
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg offmask	offset mask
39144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
39244d362409d5469aed47d19e7908d19bd194493aThomas Graf * General selectors define the pattern, mask and offset the pattern will be
39344d362409d5469aed47d19e7908d19bd194493aThomas Graf * matched to the packet contents. Using the general selectors you can match
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf * virtually any single bit in the IP (or upper layer) header.
39544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
39644d362409d5469aed47d19e7908d19bd194493aThomas Graf*/
39744d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
39844d362409d5469aed47d19e7908d19bd194493aThomas Graf		     int off, int offmask)
39944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_u32_sel *sel;
401ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	struct rtnl_u32 *u = rtnl_cls_data(cls);
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel = u32_selector_alloc(u);
40544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!sel)
4068a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf
40844d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
40944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
41144d362409d5469aed47d19e7908d19bd194493aThomas Graf
41244d362409d5469aed47d19e7908d19bd194493aThomas Graf	/* the selector might have been moved by realloc */
41344d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel = u32_selector(u);
41444d362409d5469aed47d19e7908d19bd194493aThomas Graf
41544d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->keys[sel->nkeys].mask = mask;
41644d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->keys[sel->nkeys].val = val & mask;
41744d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->keys[sel->nkeys].off = off;
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->keys[sel->nkeys].offmask = offmask;
41944d362409d5469aed47d19e7908d19bd194493aThomas Graf	sel->nkeys++;
42044d362409d5469aed47d19e7908d19bd194493aThomas Graf	u->cu_mask |= U32_ATTR_SELECTOR;
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf
42544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf			   int off, int offmask)
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int shift = 24 - 8 * (off & 3);
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf
43044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf				htonl((uint32_t)mask << shift),
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf				off & ~3, offmask);
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Append new selector key to match a 16-bit number
43744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
43844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cls	classifier to be modified
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg val	value to be matched (host byte-order)
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg mask	mask to be applied before matching (host byte-order)
44144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg off	offset, in bytes, to start matching
44244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg offmask	offset mask
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf*/
44444d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
44544d362409d5469aed47d19e7908d19bd194493aThomas Graf			    int off, int offmask)
44644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int shift = ((off & 3) == 0 ? 16 : 0);
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (off % 2)
4498a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_INVAL;
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf
45144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
45244d362409d5469aed47d19e7908d19bd194493aThomas Graf				htonl((uint32_t)mask << shift),
45344d362409d5469aed47d19e7908d19bd194493aThomas Graf				off & ~3, offmask);
45444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
45544d362409d5469aed47d19e7908d19bd194493aThomas Graf
45644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
45744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Append new selector key to match a 32-bit number
45844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
45944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cls	classifier to be modified
46044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg val	value to be matched (host byte-order)
46144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg mask	mask to be applied before matching (host byte-order)
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg off	offset, in bytes, to start matching
46344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg offmask	offset mask
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf*/
46544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
46644d362409d5469aed47d19e7908d19bd194493aThomas Graf			    int off, int offmask)
46744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf				off & ~3, offmask);
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf
47244d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
47344d362409d5469aed47d19e7908d19bd194493aThomas Graf			     uint8_t bitmask, int off, int offmask)
47444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf
47944d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
48044d362409d5469aed47d19e7908d19bd194493aThomas Graf			      uint8_t bitmask, int off, int offmask)
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i, err;
48344d362409d5469aed47d19e7908d19bd194493aThomas Graf
48444d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 1; i <= 4; i++) {
48544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (32 * i - bitmask <= 0) {
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf						0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf				return err;
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
49044d362409d5469aed47d19e7908d19bd194493aThomas Graf		else if (32 * i - bitmask < 32) {
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf			uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf						htonl(mask), off+4*(i-1), offmask)) < 0)
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf				return err;
49544d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
49644d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* otherwise, if (32*i - bitmask >= 32) no key is generated */
49744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
49844d362409d5469aed47d19e7908d19bd194493aThomas Graf
49944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
50044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf
50244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
50344d362409d5469aed47d19e7908d19bd194493aThomas Graf
50444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct rtnl_cls_ops u32_ops = {
50544d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_kind		= "u32",
506ef858fb492dfe98e3ae194264fbc73649cf8493aThomas Graf	.co_size		= sizeof(struct rtnl_u32),
50744d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msg_parser		= u32_msg_parser,
50844d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_free_data		= u32_free_data,
50944d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_clone		= u32_clone,
51044d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_get_opts		= u32_get_opts,
511d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	.co_dump = {
512d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_LINE]	= u32_dump_line,
513d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_DETAILS]	= u32_dump_details,
514d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_STATS]	= u32_dump_stats,
515d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	},
51644d362409d5469aed47d19e7908d19bd194493aThomas Graf};
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf
51844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __init u32_init(void)
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
52044d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_cls_register(&u32_ops);
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
52244d362409d5469aed47d19e7908d19bd194493aThomas Graf
52344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __exit u32_exit(void)
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
52544d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_cls_unregister(&u32_ops);
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
52744d362409d5469aed47d19e7908d19bd194493aThomas Graf
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
529