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-2009 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_api
     16  * @defgroup u32 Universal 32-bit Classifier
     17  *
     18  * @{
     19  */
     20 
     21 #include <netlink-local.h>
     22 #include <netlink-tc.h>
     23 #include <netlink/netlink.h>
     24 #include <netlink/attr.h>
     25 #include <netlink/utils.h>
     26 #include <netlink/route/tc.h>
     27 #include <netlink/route/classifier.h>
     28 #include <netlink/route/classifier-modules.h>
     29 #include <netlink/route/cls/u32.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_cls *cls)
     68 {
     69 	struct rtnl_u32 *u = rtnl_cls_data(cls);
     70 	struct nlattr *tb[TCA_U32_MAX + 1];
     71 	int err;
     72 
     73 	err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, 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_act = nl_data_alloc_attr(tb[TCA_U32_ACT]);
    106 		if (!u->cu_act)
    107 			goto errout_nomem;
    108 		u->cu_mask |= U32_ATTR_ACTION;
    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 		int 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_cls *cls)
    155 {
    156 	struct rtnl_u32 *u = rtnl_cls_data(cls);
    157 
    158 	nl_data_free(u->cu_selector);
    159 	nl_data_free(u->cu_act);
    160 	nl_data_free(u->cu_police);
    161 	nl_data_free(u->cu_pcnt);
    162 }
    163 
    164 static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
    165 {
    166 	struct rtnl_u32 *dst = rtnl_cls_data(_dst);
    167 	struct rtnl_u32 *src = rtnl_cls_data(_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 && !(dst->cu_act = nl_data_clone(src->cu_act)))
    174 		return -NLE_NOMEM;
    175 
    176 	if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
    177 		return -NLE_NOMEM;
    178 
    179 	if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
    180 		return -NLE_NOMEM;
    181 
    182 	return 0;
    183 }
    184 
    185 static void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
    186 {
    187 	struct rtnl_u32 *u = rtnl_cls_data(cls);
    188 	char buf[32];
    189 
    190 	if (u->cu_mask & U32_ATTR_DIVISOR)
    191 		nl_dump(p, " divisor %u", u->cu_divisor);
    192 	else if (u->cu_mask & U32_ATTR_CLASSID)
    193 		nl_dump(p, " target %s",
    194 			rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
    195 }
    196 
    197 static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
    198 			   struct rtnl_cls *cls, struct rtnl_u32 *u)
    199 {
    200 	int i;
    201 	struct tc_u32_key *key;
    202 
    203 	if (sel->hmask || sel->hoff) {
    204 		/* I guess this will never be used since the kernel only
    205 		 * exports the selector if no divisor is set but hash offset
    206 		 * and hash mask make only sense in hash filters with divisor
    207 		 * set */
    208 		nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
    209 	}
    210 
    211 	if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
    212 		nl_dump(p, " offset at %u", sel->off);
    213 
    214 		if (sel->flags & TC_U32_VAROFFSET)
    215 			nl_dump(p, " variable (at %u & 0x%x) >> %u",
    216 				sel->offoff, ntohs(sel->offmask), sel->offshift);
    217 	}
    218 
    219 	if (sel->flags) {
    220 		int flags = sel->flags;
    221 		nl_dump(p, " <");
    222 
    223 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
    224 	flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
    225 
    226 		PRINT_FLAG(TERMINAL);
    227 		PRINT_FLAG(OFFSET);
    228 		PRINT_FLAG(VAROFFSET);
    229 		PRINT_FLAG(EAT);
    230 #undef PRINT_FLAG
    231 
    232 		nl_dump(p, ">");
    233 	}
    234 
    235 
    236 	for (i = 0; i < sel->nkeys; i++) {
    237 		key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
    238 
    239 		nl_dump(p, "\n");
    240 		nl_dump_line(p, "      match key at %s%u ",
    241 			key->offmask ? "nexthdr+" : "", key->off);
    242 
    243 		if (key->offmask)
    244 			nl_dump(p, "[0x%u] ", key->offmask);
    245 
    246 		nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
    247 
    248 		if (p->dp_type == NL_DUMP_STATS &&
    249 		    (u->cu_mask & U32_ATTR_PCNT)) {
    250 			struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
    251 			nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
    252 		}
    253 	}
    254 }
    255 
    256 static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
    257 {
    258 	struct rtnl_u32 *u = rtnl_cls_data(cls);
    259 	struct tc_u32_sel *s;
    260 
    261 	if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
    262 		nl_dump(p, "no-selector\n");
    263 		return;
    264 	}
    265 
    266 	s = u->cu_selector->d_data;
    267 
    268 	nl_dump(p, "nkeys %u ", s->nkeys);
    269 
    270 	if (u->cu_mask & U32_ATTR_HASH)
    271 		nl_dump(p, "ht key 0x%x hash 0x%u",
    272 			TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
    273 
    274 	if (u->cu_mask & U32_ATTR_LINK)
    275 		nl_dump(p, "link %u ", u->cu_link);
    276 
    277 	if (u->cu_mask & U32_ATTR_INDEV)
    278 		nl_dump(p, "indev %s ", u->cu_indev);
    279 
    280 	print_selector(p, s, cls, u);
    281 	nl_dump(p, "\n");
    282 
    283 #if 0
    284 #define U32_ATTR_ACTION       0x040
    285 #define U32_ATTR_POLICE       0x080
    286 
    287 	struct nl_data   act;
    288 	struct nl_data   police;
    289 #endif
    290 }
    291 
    292 static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p)
    293 {
    294 	struct rtnl_u32 *u = rtnl_cls_data(cls);
    295 
    296 	if (u->cu_mask & U32_ATTR_PCNT) {
    297 		struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
    298 		nl_dump(p, "\n");
    299 		nl_dump_line(p, "    hit %8llu count %8llu\n",
    300 			     pc->rhit, pc->rcnt);
    301 	}
    302 }
    303 
    304 static int u32_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
    305 {
    306 	struct rtnl_u32 *u = rtnl_cls_data(cls);
    307 
    308 	if (u->cu_mask & U32_ATTR_DIVISOR)
    309 		NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
    310 
    311 	if (u->cu_mask & U32_ATTR_HASH)
    312 		NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
    313 
    314 	if (u->cu_mask & U32_ATTR_CLASSID)
    315 		NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
    316 
    317 	if (u->cu_mask & U32_ATTR_LINK)
    318 		NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
    319 
    320 	if (u->cu_mask & U32_ATTR_SELECTOR)
    321 		NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
    322 
    323 	if (u->cu_mask & U32_ATTR_ACTION)
    324 		NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act);
    325 
    326 	if (u->cu_mask & U32_ATTR_POLICE)
    327 		NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
    328 
    329 	if (u->cu_mask & U32_ATTR_INDEV)
    330 		NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
    331 
    332 	return 0;
    333 
    334 nla_put_failure:
    335 	return -NLE_NOMEM;
    336 }
    337 
    338 /**
    339  * @name Attribute Modifications
    340  * @{
    341  */
    342 
    343 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
    344 			 int nodeid)
    345 {
    346 	uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
    347 
    348 	tca_set_handle((struct rtnl_tca *) cls, handle );
    349 }
    350 
    351 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
    352 {
    353 	struct rtnl_u32 *u = rtnl_cls_data(cls);
    354 
    355 	u->cu_classid = classid;
    356 	u->cu_mask |= U32_ATTR_CLASSID;
    357 
    358 	return 0;
    359 }
    360 
    361 /** @} */
    362 
    363 /**
    364  * @name Selector Modifications
    365  * @{
    366  */
    367 
    368 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
    369 {
    370 	struct tc_u32_sel *sel;
    371 	struct rtnl_u32 *u = rtnl_cls_data(cls);
    372 
    373 	sel = u32_selector_alloc(u);
    374 	if (!sel)
    375 		return -NLE_NOMEM;
    376 
    377 	sel->flags |= flags;
    378 	u->cu_mask |= U32_ATTR_SELECTOR;
    379 
    380 	return 0;
    381 }
    382 
    383 /**
    384  * Append new 32-bit key to the selector
    385  *
    386  * @arg cls	classifier to be modifier
    387  * @arg val	value to be matched (network byte-order)
    388  * @arg mask	mask to be applied before matching (network byte-order)
    389  * @arg off	offset, in bytes, to start matching
    390  * @arg offmask	offset mask
    391  *
    392  * General selectors define the pattern, mask and offset the pattern will be
    393  * matched to the packet contents. Using the general selectors you can match
    394  * virtually any single bit in the IP (or upper layer) header.
    395  *
    396 */
    397 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
    398 		     int off, int offmask)
    399 {
    400 	struct tc_u32_sel *sel;
    401 	struct rtnl_u32 *u = rtnl_cls_data(cls);
    402 	int err;
    403 
    404 	sel = u32_selector_alloc(u);
    405 	if (!sel)
    406 		return -NLE_NOMEM;
    407 
    408 	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
    409 	if (err < 0)
    410 		return err;
    411 
    412 	/* the selector might have been moved by realloc */
    413 	sel = u32_selector(u);
    414 
    415 	sel->keys[sel->nkeys].mask = mask;
    416 	sel->keys[sel->nkeys].val = val & mask;
    417 	sel->keys[sel->nkeys].off = off;
    418 	sel->keys[sel->nkeys].offmask = offmask;
    419 	sel->nkeys++;
    420 	u->cu_mask |= U32_ATTR_SELECTOR;
    421 
    422 	return 0;
    423 }
    424 
    425 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
    426 			   int off, int offmask)
    427 {
    428 	int shift = 24 - 8 * (off & 3);
    429 
    430 	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
    431 				htonl((uint32_t)mask << shift),
    432 				off & ~3, offmask);
    433 }
    434 
    435 /**
    436  * Append new selector key to match a 16-bit number
    437  *
    438  * @arg cls	classifier to be modified
    439  * @arg val	value to be matched (host byte-order)
    440  * @arg mask	mask to be applied before matching (host byte-order)
    441  * @arg off	offset, in bytes, to start matching
    442  * @arg offmask	offset mask
    443 */
    444 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
    445 			    int off, int offmask)
    446 {
    447 	int shift = ((off & 3) == 0 ? 16 : 0);
    448 	if (off % 2)
    449 		return -NLE_INVAL;
    450 
    451 	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
    452 				htonl((uint32_t)mask << shift),
    453 				off & ~3, offmask);
    454 }
    455 
    456 /**
    457  * Append new selector key to match a 32-bit number
    458  *
    459  * @arg cls	classifier to be modified
    460  * @arg val	value to be matched (host byte-order)
    461  * @arg mask	mask to be applied before matching (host byte-order)
    462  * @arg off	offset, in bytes, to start matching
    463  * @arg offmask	offset mask
    464 */
    465 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
    466 			    int off, int offmask)
    467 {
    468 	return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
    469 				off & ~3, offmask);
    470 }
    471 
    472 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
    473 			     uint8_t bitmask, int off, int offmask)
    474 {
    475 	uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
    476 	return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
    477 }
    478 
    479 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
    480 			      uint8_t bitmask, int off, int offmask)
    481 {
    482 	int i, err;
    483 
    484 	for (i = 1; i <= 4; i++) {
    485 		if (32 * i - bitmask <= 0) {
    486 			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
    487 						0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
    488 				return err;
    489 		}
    490 		else if (32 * i - bitmask < 32) {
    491 			uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
    492 			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
    493 						htonl(mask), off+4*(i-1), offmask)) < 0)
    494 				return err;
    495 		}
    496 		/* otherwise, if (32*i - bitmask >= 32) no key is generated */
    497 	}
    498 
    499 	return 0;
    500 }
    501 
    502 /** @} */
    503 
    504 static struct rtnl_cls_ops u32_ops = {
    505 	.co_kind		= "u32",
    506 	.co_size		= sizeof(struct rtnl_u32),
    507 	.co_msg_parser		= u32_msg_parser,
    508 	.co_free_data		= u32_free_data,
    509 	.co_clone		= u32_clone,
    510 	.co_get_opts		= u32_get_opts,
    511 	.co_dump = {
    512 	    [NL_DUMP_LINE]	= u32_dump_line,
    513 	    [NL_DUMP_DETAILS]	= u32_dump_details,
    514 	    [NL_DUMP_STATS]	= u32_dump_stats,
    515 	},
    516 };
    517 
    518 static void __init u32_init(void)
    519 {
    520 	rtnl_cls_register(&u32_ops);
    521 }
    522 
    523 static void __exit u32_exit(void)
    524 {
    525 	rtnl_cls_unregister(&u32_ops);
    526 }
    527 
    528 /** @} */
    529