Home | History | Annotate | Download | only in cls
      1 /*
      2  * lib/route/cls/u32.c		u32 classifier
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2013 Thomas Graf <tgraf (at) suug.ch>
     10  * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard (at) siemens.com>
     11  * Copyright (c) 2005-2006 Siemens AG Oesterreich
     12  */
     13 
     14 /**
     15  * @ingroup cls
     16  * @defgroup cls_u32 Universal 32-bit Classifier
     17  *
     18  * @{
     19  */
     20 
     21 #include <netlink-private/netlink.h>
     22 #include <netlink-private/tc.h>
     23 #include <netlink/netlink.h>
     24 #include <netlink/attr.h>
     25 #include <netlink/utils.h>
     26 #include <netlink-private/route/tc-api.h>
     27 #include <netlink/route/classifier.h>
     28 #include <netlink/route/cls/u32.h>
     29 #include <netlink/route/action.h>
     30 
     31 /** @cond SKIP */
     32 #define U32_ATTR_DIVISOR      0x001
     33 #define U32_ATTR_HASH         0x002
     34 #define U32_ATTR_CLASSID      0x004
     35 #define U32_ATTR_LINK         0x008
     36 #define U32_ATTR_PCNT         0x010
     37 #define U32_ATTR_SELECTOR     0x020
     38 #define U32_ATTR_ACTION       0x040
     39 #define U32_ATTR_POLICE       0x080
     40 #define U32_ATTR_INDEV        0x100
     41 /** @endcond */
     42 
     43 static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
     44 {
     45 	return (struct tc_u32_sel *) u->cu_selector->d_data;
     46 }
     47 
     48 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
     49 {
     50 	if (!u->cu_selector)
     51 		u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
     52 
     53 	return u32_selector(u);
     54 }
     55 
     56 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
     57 	[TCA_U32_DIVISOR]	= { .type = NLA_U32 },
     58 	[TCA_U32_HASH]		= { .type = NLA_U32 },
     59 	[TCA_U32_CLASSID]	= { .type = NLA_U32 },
     60 	[TCA_U32_LINK]		= { .type = NLA_U32 },
     61 	[TCA_U32_INDEV]		= { .type = NLA_STRING,
     62 				    .maxlen = IFNAMSIZ },
     63 	[TCA_U32_SEL]		= { .minlen = sizeof(struct tc_u32_sel) },
     64 	[TCA_U32_PCNT]		= { .minlen = sizeof(struct tc_u32_pcnt) },
     65 };
     66 
     67 static int u32_msg_parser(struct rtnl_tc *tc, void *data)
     68 {
     69 	struct rtnl_u32 *u = data;
     70 	struct nlattr *tb[TCA_U32_MAX + 1];
     71 	int err;
     72 
     73 	err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
     74 	if (err < 0)
     75 		return err;
     76 
     77 	if (tb[TCA_U32_DIVISOR]) {
     78 		u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
     79 		u->cu_mask |= U32_ATTR_DIVISOR;
     80 	}
     81 
     82 	if (tb[TCA_U32_SEL]) {
     83 		u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
     84 		if (!u->cu_selector)
     85 			goto errout_nomem;
     86 		u->cu_mask |= U32_ATTR_SELECTOR;
     87 	}
     88 
     89 	if (tb[TCA_U32_HASH]) {
     90 		u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
     91 		u->cu_mask |= U32_ATTR_HASH;
     92 	}
     93 
     94 	if (tb[TCA_U32_CLASSID]) {
     95 		u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
     96 		u->cu_mask |= U32_ATTR_CLASSID;
     97 	}
     98 
     99 	if (tb[TCA_U32_LINK]) {
    100 		u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
    101 		u->cu_mask |= U32_ATTR_LINK;
    102 	}
    103 
    104 	if (tb[TCA_U32_ACT]) {
    105 		u->cu_mask |= U32_ATTR_ACTION;
    106 		err = rtnl_act_parse(&u->cu_act, tb[TCA_U32_ACT]);
    107 		if (err)
    108 			return err;
    109 	}
    110 
    111 	if (tb[TCA_U32_POLICE]) {
    112 		u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
    113 		if (!u->cu_police)
    114 			goto errout_nomem;
    115 		u->cu_mask |= U32_ATTR_POLICE;
    116 	}
    117 
    118 	if (tb[TCA_U32_PCNT]) {
    119 		struct tc_u32_sel *sel;
    120 		size_t pcnt_size;
    121 
    122 		if (!tb[TCA_U32_SEL]) {
    123 			err = -NLE_MISSING_ATTR;
    124 			goto errout;
    125 		}
    126 
    127 		sel = u->cu_selector->d_data;
    128 		pcnt_size = sizeof(struct tc_u32_pcnt) +
    129 				(sel->nkeys * sizeof(uint64_t));
    130 		if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
    131 			err = -NLE_INVAL;
    132 			goto errout;
    133 		}
    134 
    135 		u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
    136 		if (!u->cu_pcnt)
    137 			goto errout_nomem;
    138 		u->cu_mask |= U32_ATTR_PCNT;
    139 	}
    140 
    141 	if (tb[TCA_U32_INDEV]) {
    142 		nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
    143 		u->cu_mask |= U32_ATTR_INDEV;
    144 	}
    145 
    146 	return 0;
    147 
    148 errout_nomem:
    149 	err = -NLE_NOMEM;
    150 errout:
    151 	return err;
    152 }
    153 
    154 static void u32_free_data(struct rtnl_tc *tc, void *data)
    155 {
    156 	struct rtnl_u32 *u = data;
    157 
    158 	if (u->cu_act)
    159 		rtnl_act_put_all(&u->cu_act);
    160 	nl_data_free(u->cu_selector);
    161 	nl_data_free(u->cu_police);
    162 	nl_data_free(u->cu_pcnt);
    163 }
    164 
    165 static int u32_clone(void *_dst, void *_src)
    166 {
    167 	struct rtnl_u32 *dst = _dst, *src = _src;
    168 
    169 	if (src->cu_selector &&
    170 	    !(dst->cu_selector = nl_data_clone(src->cu_selector)))
    171 		return -NLE_NOMEM;
    172 
    173 	if (src->cu_act) {
    174 		if (!(dst->cu_act = rtnl_act_alloc()))
    175 			return -NLE_NOMEM;
    176 
    177 		memcpy(dst->cu_act, src->cu_act, sizeof(struct rtnl_act));
    178 	}
    179 
    180 	if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
    181 		return -NLE_NOMEM;
    182 
    183 	if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
    184 		return -NLE_NOMEM;
    185 
    186 	return 0;
    187 }
    188 
    189 static void u32_dump_line(struct rtnl_tc *tc, void *data,
    190 			  struct nl_dump_params *p)
    191 {
    192 	struct rtnl_u32 *u = data;
    193 	char buf[32];
    194 
    195 	if (!u)
    196 		return;
    197 
    198 	if (u->cu_mask & U32_ATTR_DIVISOR)
    199 		nl_dump(p, " divisor %u", u->cu_divisor);
    200 	else if (u->cu_mask & U32_ATTR_CLASSID)
    201 		nl_dump(p, " target %s",
    202 			rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
    203 }
    204 
    205 static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
    206 			   struct rtnl_u32 *u)
    207 {
    208 	int i;
    209 	struct tc_u32_key *key;
    210 
    211 	if (sel->hmask || sel->hoff) {
    212 		/* I guess this will never be used since the kernel only
    213 		 * exports the selector if no divisor is set but hash offset
    214 		 * and hash mask make only sense in hash filters with divisor
    215 		 * set */
    216 		nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
    217 	}
    218 
    219 	if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
    220 		nl_dump(p, " offset at %u", sel->off);
    221 
    222 		if (sel->flags & TC_U32_VAROFFSET)
    223 			nl_dump(p, " variable (at %u & 0x%x) >> %u",
    224 				sel->offoff, ntohs(sel->offmask), sel->offshift);
    225 	}
    226 
    227 	if (sel->flags) {
    228 		int flags = sel->flags;
    229 		nl_dump(p, " <");
    230 
    231 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
    232 	flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
    233 
    234 		PRINT_FLAG(TERMINAL);
    235 		PRINT_FLAG(OFFSET);
    236 		PRINT_FLAG(VAROFFSET);
    237 		PRINT_FLAG(EAT);
    238 #undef PRINT_FLAG
    239 
    240 		nl_dump(p, ">");
    241 	}
    242 
    243 
    244 	for (i = 0; i < sel->nkeys; i++) {
    245 		key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
    246 
    247 		nl_dump(p, "\n");
    248 		nl_dump_line(p, "      match key at %s%u ",
    249 			key->offmask ? "nexthdr+" : "", key->off);
    250 
    251 		if (key->offmask)
    252 			nl_dump(p, "[0x%u] ", key->offmask);
    253 
    254 		nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
    255 
    256 		if (p->dp_type == NL_DUMP_STATS &&
    257 		    (u->cu_mask & U32_ATTR_PCNT)) {
    258 			struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
    259 			nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
    260 		}
    261 	}
    262 }
    263 
    264 static void u32_dump_details(struct rtnl_tc *tc, void *data,
    265 			     struct nl_dump_params *p)
    266 {
    267 	struct rtnl_u32 *u = data;
    268 	struct tc_u32_sel *s;
    269 
    270 	if (!u)
    271 		return;
    272 
    273 	if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
    274 		nl_dump(p, "no-selector\n");
    275 		return;
    276 	}
    277 
    278 	s = u->cu_selector->d_data;
    279 
    280 	nl_dump(p, "nkeys %u ", s->nkeys);
    281 
    282 	if (u->cu_mask & U32_ATTR_HASH)
    283 		nl_dump(p, "ht key 0x%x hash 0x%u",
    284 			TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
    285 
    286 	if (u->cu_mask & U32_ATTR_LINK)
    287 		nl_dump(p, "link %u ", u->cu_link);
    288 
    289 	if (u->cu_mask & U32_ATTR_INDEV)
    290 		nl_dump(p, "indev %s ", u->cu_indev);
    291 
    292 	print_selector(p, s, u);
    293 	nl_dump(p, "\n");
    294 }
    295 
    296 static void u32_dump_stats(struct rtnl_tc *tc, void *data,
    297 			   struct nl_dump_params *p)
    298 {
    299 	struct rtnl_u32 *u = data;
    300 
    301 	if (!u)
    302 		return;
    303 
    304 	if (u->cu_mask & U32_ATTR_PCNT) {
    305 		struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
    306 		nl_dump(p, "\n");
    307 		nl_dump_line(p, "    hit %8" PRIu64 " count %8" PRIu64 "\n",
    308 			     pc->rhit, pc->rcnt);
    309 	}
    310 }
    311 
    312 static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
    313 {
    314 	struct rtnl_u32 *u = data;
    315 
    316 	if (!u)
    317 		return 0;
    318 
    319 	if (u->cu_mask & U32_ATTR_DIVISOR)
    320 		NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
    321 
    322 	if (u->cu_mask & U32_ATTR_HASH)
    323 		NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
    324 
    325 	if (u->cu_mask & U32_ATTR_CLASSID)
    326 		NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
    327 
    328 	if (u->cu_mask & U32_ATTR_LINK)
    329 		NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
    330 
    331 	if (u->cu_mask & U32_ATTR_SELECTOR)
    332 		NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
    333 
    334 	if (u->cu_mask & U32_ATTR_ACTION) {
    335 		int err;
    336 
    337 		err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act);
    338 		if (err)
    339 			return err;
    340 	}
    341 
    342 	if (u->cu_mask & U32_ATTR_POLICE)
    343 		NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
    344 
    345 	if (u->cu_mask & U32_ATTR_INDEV)
    346 		NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
    347 
    348 	return 0;
    349 
    350 nla_put_failure:
    351 	return -NLE_NOMEM;
    352 }
    353 
    354 /**
    355  * @name Attribute Modifications
    356  * @{
    357  */
    358 
    359 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
    360 			 int nodeid)
    361 {
    362 	uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
    363 
    364 	rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
    365 }
    366 
    367 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
    368 {
    369 	struct rtnl_u32 *u;
    370 
    371 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
    372 		return -NLE_NOMEM;
    373 
    374 	u->cu_classid = classid;
    375 	u->cu_mask |= U32_ATTR_CLASSID;
    376 
    377 	return 0;
    378 }
    379 
    380 int rtnl_u32_set_divisor(struct rtnl_cls *cls, uint32_t divisor)
    381 {
    382 	struct rtnl_u32 *u;
    383 
    384 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
    385 		return -NLE_NOMEM;
    386 
    387 	u->cu_divisor = divisor;
    388 	u->cu_mask |= U32_ATTR_DIVISOR;
    389 	return 0;
    390 }
    391 
    392 int rtnl_u32_set_link(struct rtnl_cls *cls, uint32_t link)
    393 {
    394 	struct rtnl_u32 *u;
    395 
    396 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
    397 		return -NLE_NOMEM;
    398 
    399 	u->cu_link = link;
    400 	u->cu_mask |= U32_ATTR_LINK;
    401 	return 0;
    402 }
    403 
    404 int rtnl_u32_set_hashtable(struct rtnl_cls *cls, uint32_t ht)
    405 {
    406 	struct rtnl_u32 *u;
    407 
    408 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
    409 		return -NLE_NOMEM;
    410 
    411 	u->cu_hash = ht;
    412 	u->cu_mask |= U32_ATTR_HASH;
    413 	return 0;
    414 }
    415 
    416 int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
    417 {
    418 	struct rtnl_u32 *u;
    419 	struct tc_u32_sel *sel;
    420 	int err;
    421 
    422 	hashmask = htonl(hashmask);
    423 
    424 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
    425 		return -NLE_NOMEM;
    426 
    427 	sel = u32_selector_alloc(u);
    428 	if (!sel)
    429 		return -NLE_NOMEM;
    430 
    431 	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
    432 	if(err < 0)
    433 		return err;
    434 
    435 	sel = u32_selector(u);
    436 
    437 	sel->hmask = hashmask;
    438 	sel->hoff = offset;
    439 	return 0;
    440 }
    441 
    442 int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
    443 {
    444 	struct rtnl_u32 *u;
    445 	struct tc_u32_sel *sel;
    446 	int err;
    447 
    448 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
    449 		return -NLE_NOMEM;
    450 
    451 	sel = u32_selector_alloc(u);
    452 	if (!sel)
    453 		return -NLE_NOMEM;
    454 
    455 	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
    456 	if(err < 0)
    457 		return err;
    458 
    459 	sel = u32_selector(u);
    460 
    461 	sel->flags |= TC_U32_TERMINAL;
    462 	return 0;
    463 }
    464 
    465 int rtnl_u32_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
    466 {
    467 	struct rtnl_u32 *u;
    468 
    469 	if (!act)
    470 		return 0;
    471 
    472 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
    473 		return -NLE_NOMEM;
    474 
    475 	u->cu_mask |= U32_ATTR_ACTION;
    476 	/* In case user frees it */
    477 	rtnl_act_get(act);
    478 	return rtnl_act_append(&u->cu_act, act);
    479 }
    480 
    481 int rtnl_u32_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
    482 {
    483 	struct rtnl_u32 *u;
    484 	int ret;
    485 
    486 	if (!act)
    487 		return 0;
    488 
    489 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
    490 		return -NLE_NOMEM;
    491 
    492 	if (!(u->cu_mask & U32_ATTR_ACTION))
    493 		return -NLE_INVAL;
    494 
    495 	ret = rtnl_act_remove(&u->cu_act, act);
    496 	if (ret)
    497 		return ret;
    498 
    499 	if (!u->cu_act)
    500 		u->cu_mask &= ~U32_ATTR_ACTION;
    501 	rtnl_act_put(act);
    502 	return 0;
    503 }
    504 /** @} */
    505 
    506 /**
    507  * @name Selector Modifications
    508  * @{
    509  */
    510 
    511 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
    512 {
    513 	struct tc_u32_sel *sel;
    514 	struct rtnl_u32 *u;
    515 
    516 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
    517 		return -NLE_NOMEM;
    518 
    519 	sel = u32_selector_alloc(u);
    520 	if (!sel)
    521 		return -NLE_NOMEM;
    522 
    523 	sel->flags |= flags;
    524 	u->cu_mask |= U32_ATTR_SELECTOR;
    525 
    526 	return 0;
    527 }
    528 
    529 /**
    530  * Append new 32-bit key to the selector
    531  *
    532  * @arg cls	classifier to be modifier
    533  * @arg val	value to be matched (network byte-order)
    534  * @arg mask	mask to be applied before matching (network byte-order)
    535  * @arg off	offset, in bytes, to start matching
    536  * @arg offmask	offset mask
    537  *
    538  * General selectors define the pattern, mask and offset the pattern will be
    539  * matched to the packet contents. Using the general selectors you can match
    540  * virtually any single bit in the IP (or upper layer) header.
    541  *
    542 */
    543 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
    544 		     int off, int offmask)
    545 {
    546 	struct tc_u32_sel *sel;
    547 	struct rtnl_u32 *u;
    548 	int err;
    549 
    550 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
    551 		return -NLE_NOMEM;
    552 
    553 	sel = u32_selector_alloc(u);
    554 	if (!sel)
    555 		return -NLE_NOMEM;
    556 
    557 	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
    558 	if (err < 0)
    559 		return err;
    560 
    561 	/* the selector might have been moved by realloc */
    562 	sel = u32_selector(u);
    563 
    564 	sel->keys[sel->nkeys].mask = mask;
    565 	sel->keys[sel->nkeys].val = val & mask;
    566 	sel->keys[sel->nkeys].off = off;
    567 	sel->keys[sel->nkeys].offmask = offmask;
    568 	sel->nkeys++;
    569 	u->cu_mask |= U32_ATTR_SELECTOR;
    570 
    571 	return 0;
    572 }
    573 
    574 /**
    575  * Get the 32-bit key from the selector
    576  *
    577  * @arg cls	classifier to be retrieve
    578  * @arg index	the index of the array of keys, start with 0
    579  * @arg val	pointer to store value after masked (network byte-order)
    580  * @arg mask	pointer to store the mask (network byte-order)
    581  * @arg off	pointer to store the offset
    582  * @arg offmask	pointer to store offset mask
    583  *
    584 */
    585 int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index,
    586 		     uint32_t *val, uint32_t *mask, int *off, int *offmask)
    587 {
    588 	struct tc_u32_sel *sel;
    589 	struct rtnl_u32 *u;
    590 
    591 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
    592 		return -NLE_NOMEM;
    593 
    594 	if (!(u->cu_mask & U32_ATTR_SELECTOR))
    595 		return -NLE_INVAL;
    596 
    597 	/* the selector might have been moved by realloc */
    598 	sel = u32_selector(u);
    599 	if (index >= sel->nkeys)
    600 		return -NLE_RANGE;
    601 
    602 	*mask = sel->keys[index].mask;
    603 	*val = sel->keys[index].val;
    604 	*off = sel->keys[index].off;
    605 	*offmask = sel->keys[index].offmask;
    606 	return 0;
    607 }
    608 
    609 
    610 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
    611 			   int off, int offmask)
    612 {
    613 	int shift = 24 - 8 * (off & 3);
    614 
    615 	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
    616 				htonl((uint32_t)mask << shift),
    617 				off & ~3, offmask);
    618 }
    619 
    620 /**
    621  * Append new selector key to match a 16-bit number
    622  *
    623  * @arg cls	classifier to be modified
    624  * @arg val	value to be matched (host byte-order)
    625  * @arg mask	mask to be applied before matching (host byte-order)
    626  * @arg off	offset, in bytes, to start matching
    627  * @arg offmask	offset mask
    628 */
    629 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
    630 			    int off, int offmask)
    631 {
    632 	int shift = ((off & 3) == 0 ? 16 : 0);
    633 	if (off % 2)
    634 		return -NLE_INVAL;
    635 
    636 	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
    637 				htonl((uint32_t)mask << shift),
    638 				off & ~3, offmask);
    639 }
    640 
    641 /**
    642  * Append new selector key to match a 32-bit number
    643  *
    644  * @arg cls	classifier to be modified
    645  * @arg val	value to be matched (host byte-order)
    646  * @arg mask	mask to be applied before matching (host byte-order)
    647  * @arg off	offset, in bytes, to start matching
    648  * @arg offmask	offset mask
    649 */
    650 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
    651 			    int off, int offmask)
    652 {
    653 	return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
    654 				off & ~3, offmask);
    655 }
    656 
    657 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, const struct in_addr *addr,
    658 			     uint8_t bitmask, int off, int offmask)
    659 {
    660 	uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
    661 	return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
    662 }
    663 
    664 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, const struct in6_addr *addr,
    665 			      uint8_t bitmask, int off, int offmask)
    666 {
    667 	int i, err;
    668 
    669 	for (i = 1; i <= 4; i++) {
    670 		if (32 * i - bitmask <= 0) {
    671 			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
    672 						0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
    673 				return err;
    674 		}
    675 		else if (32 * i - bitmask < 32) {
    676 			uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
    677 			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
    678 						htonl(mask), off+4*(i-1), offmask)) < 0)
    679 				return err;
    680 		}
    681 		/* otherwise, if (32*i - bitmask >= 32) no key is generated */
    682 	}
    683 
    684 	return 0;
    685 }
    686 
    687 /** @} */
    688 
    689 static struct rtnl_tc_ops u32_ops = {
    690 	.to_kind		= "u32",
    691 	.to_type		= RTNL_TC_TYPE_CLS,
    692 	.to_size		= sizeof(struct rtnl_u32),
    693 	.to_msg_parser		= u32_msg_parser,
    694 	.to_free_data		= u32_free_data,
    695 	.to_clone		= u32_clone,
    696 	.to_msg_fill		= u32_msg_fill,
    697 	.to_dump = {
    698 	    [NL_DUMP_LINE]	= u32_dump_line,
    699 	    [NL_DUMP_DETAILS]	= u32_dump_details,
    700 	    [NL_DUMP_STATS]	= u32_dump_stats,
    701 	},
    702 };
    703 
    704 static void __init u32_init(void)
    705 {
    706 	rtnl_tc_register(&u32_ops);
    707 }
    708 
    709 static void __exit u32_exit(void)
    710 {
    711 	rtnl_tc_unregister(&u32_ops);
    712 }
    713 
    714 /** @} */
    715