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> 
   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 
   43 static inline struct tc_u32_sel *u32_selector(
struct rtnl_u32 *u)
 
   45         return (
struct tc_u32_sel *) u->cu_selector->d_data;
 
   48 static inline struct tc_u32_sel *u32_selector_alloc(
struct rtnl_u32 *u)
 
   51                 u->cu_selector = 
nl_data_alloc(NULL, 
sizeof(
struct tc_u32_sel));
 
   53         return u32_selector(u);
 
   56 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
 
   58         [TCA_U32_HASH]          = { .type = 
NLA_U32 },
 
   59         [TCA_U32_CLASSID]       = { .type = 
NLA_U32 },
 
   60         [TCA_U32_LINK]          = { .type = 
NLA_U32 },
 
   63         [TCA_U32_SEL]           = { .minlen = 
sizeof(
struct tc_u32_sel) },
 
   64         [TCA_U32_PCNT]          = { .minlen = 
sizeof(
struct tc_u32_pcnt) },
 
   67 static int u32_msg_parser(
struct rtnl_tc *tc, 
void *data)
 
   69         struct rtnl_u32 *u = data;
 
   70         struct nlattr *tb[TCA_U32_MAX + 1];
 
   73         err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
 
   77         if (tb[TCA_U32_DIVISOR]) {
 
   79                 u->cu_mask |= U32_ATTR_DIVISOR;
 
   82         if (tb[TCA_U32_SEL]) {
 
   86                 u->cu_mask |= U32_ATTR_SELECTOR;
 
   89         if (tb[TCA_U32_HASH]) {
 
   91                 u->cu_mask |= U32_ATTR_HASH;
 
   94         if (tb[TCA_U32_CLASSID]) {
 
   96                 u->cu_mask |= U32_ATTR_CLASSID;
 
   99         if (tb[TCA_U32_LINK]) {
 
  101                 u->cu_mask |= U32_ATTR_LINK;
 
  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]);
 
  111         if (tb[TCA_U32_POLICE]) {
 
  115                 u->cu_mask |= U32_ATTR_POLICE;
 
  118         if (tb[TCA_U32_PCNT]) {
 
  119                 struct tc_u32_sel *sel;
 
  122                 if (!tb[TCA_U32_SEL]) {
 
  123                         err = -NLE_MISSING_ATTR;
 
  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) {
 
  138                 u->cu_mask |= U32_ATTR_PCNT;
 
  141         if (tb[TCA_U32_INDEV]) {
 
  142                 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
 
  143                 u->cu_mask |= U32_ATTR_INDEV;
 
  154 static void u32_free_data(
struct rtnl_tc *tc, 
void *data)
 
  156         struct rtnl_u32 *u = data;
 
  159                 rtnl_act_put_all(&u->cu_act);
 
  165 static int u32_clone(
void *_dst, 
void *_src)
 
  167         struct rtnl_u32 *dst = _dst, *src = _src;
 
  169         if (src->cu_selector &&
 
  173         if (src->cu_act && !(dst->cu_act = rtnl_act_alloc()))
 
  175         memcpy(dst->cu_act, src->cu_act, 
sizeof(
struct rtnl_act));
 
  177         if (src->cu_police && !(dst->cu_police = 
nl_data_clone(src->cu_police)))
 
  180         if (src->cu_pcnt && !(dst->cu_pcnt = 
nl_data_clone(src->cu_pcnt)))
 
  186 static void u32_dump_line(
struct rtnl_tc *tc, 
void *data,
 
  189         struct rtnl_u32 *u = data;
 
  195         if (u->cu_mask & U32_ATTR_DIVISOR)
 
  196                 nl_dump(p, 
" divisor %u", u->cu_divisor);
 
  197         else if (u->cu_mask & U32_ATTR_CLASSID)
 
  202 static void print_selector(
struct nl_dump_params *p, 
struct tc_u32_sel *sel,
 
  206         struct tc_u32_key *key;
 
  208         if (sel->hmask || sel->hoff) {
 
  213                 nl_dump(p, 
" hash at %u & 0x%x", sel->hoff, sel->hmask);
 
  216         if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
 
  217                 nl_dump(p, 
" offset at %u", sel->off);
 
  219                 if (sel->flags & TC_U32_VAROFFSET)
 
  220                         nl_dump(p, 
" variable (at %u & 0x%x) >> %u",
 
  221                                 sel->offoff, ntohs(sel->offmask), sel->offshift);
 
  225                 int flags = sel->flags;
 
  228 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \ 
  229         flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); } 
  231                 PRINT_FLAG(TERMINAL);
 
  233                 PRINT_FLAG(VAROFFSET);
 
  241         for (i = 0; i < sel->nkeys; i++) {
 
  242                 key = (
struct tc_u32_key *) ((
char *) sel + 
sizeof(*sel)) + i;
 
  245                 nl_dump_line(p, 
"      match key at %s%u ",
 
  246                         key->offmask ? 
"nexthdr+" : 
"", key->off);
 
  249                         nl_dump(p, 
"[0x%u] ", key->offmask);
 
  251                 nl_dump(p, 
"& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
 
  254                     (u->cu_mask & U32_ATTR_PCNT)) {
 
  255                         struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
 
  256                         nl_dump(p, 
" successful %" PRIu64, pcnt->kcnts[i]);
 
  261 static void u32_dump_details(
struct rtnl_tc *tc, 
void *data,
 
  264         struct rtnl_u32 *u = data;
 
  265         struct tc_u32_sel *s;
 
  270         if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
 
  275         s = u->cu_selector->d_data;
 
  277         nl_dump(p, 
"nkeys %u ", s->nkeys);
 
  279         if (u->cu_mask & U32_ATTR_HASH)
 
  280                 nl_dump(p, 
"ht key 0x%x hash 0x%u",
 
  281                         TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
 
  283         if (u->cu_mask & U32_ATTR_LINK)
 
  284                 nl_dump(p, 
"link %u ", u->cu_link);
 
  286         if (u->cu_mask & U32_ATTR_INDEV)
 
  287                 nl_dump(p, 
"indev %s ", u->cu_indev);
 
  289         print_selector(p, s, u);
 
  293 #define U32_ATTR_ACTION       0x040 
  294 #define U32_ATTR_POLICE       0x080 
  297         struct nl_data   police;
 
  301 static void u32_dump_stats(
struct rtnl_tc *tc, 
void *data,
 
  304         struct rtnl_u32 *u = data;
 
  309         if (u->cu_mask & U32_ATTR_PCNT) {
 
  310                 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
 
  312                 nl_dump_line(p, 
"    hit %8" PRIu64 
" count %8" PRIu64 
"\n",
 
  317 static int u32_msg_fill(
struct rtnl_tc *tc, 
void *data, 
struct nl_msg *msg)
 
  319         struct rtnl_u32 *u = data;
 
  324         if (u->cu_mask & U32_ATTR_DIVISOR)
 
  327         if (u->cu_mask & U32_ATTR_HASH)
 
  330         if (u->cu_mask & U32_ATTR_CLASSID)
 
  333         if (u->cu_mask & U32_ATTR_LINK)
 
  336         if (u->cu_mask & U32_ATTR_SELECTOR)
 
  339         if (u->cu_mask & U32_ATTR_ACTION) {
 
  342                 err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act);
 
  347         if (u->cu_mask & U32_ATTR_POLICE)
 
  350         if (u->cu_mask & U32_ATTR_INDEV)
 
  364 void rtnl_u32_set_handle(
struct rtnl_cls *cls, 
int htid, 
int hash,
 
  367         uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
 
  372 int rtnl_u32_set_classid(
struct rtnl_cls *cls, uint32_t classid)
 
  379         u->cu_classid = classid;
 
  380         u->cu_mask |= U32_ATTR_CLASSID;
 
  385 int rtnl_u32_set_divisor(
struct rtnl_cls *cls, uint32_t divisor)
 
  392         u->cu_divisor = divisor;
 
  393         u->cu_mask |= U32_ATTR_DIVISOR;
 
  397 int rtnl_u32_set_link(
struct rtnl_cls *cls, uint32_t link)
 
  405         u->cu_mask |= U32_ATTR_LINK;
 
  409 int rtnl_u32_set_hashtable(
struct rtnl_cls *cls, uint32_t ht)
 
  417         u->cu_mask |= U32_ATTR_HASH;
 
  421 int rtnl_u32_set_hashmask(
struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
 
  424         struct tc_u32_sel *sel;
 
  427         hashmask = htonl(hashmask);
 
  432         sel = u32_selector_alloc(u);
 
  436         err = 
nl_data_append(u->cu_selector, NULL, 
sizeof(
struct tc_u32_key));
 
  440         sel = u32_selector(u);
 
  442         sel->hmask = hashmask;
 
  447 int rtnl_u32_set_cls_terminal(
struct rtnl_cls *cls)
 
  450         struct tc_u32_sel *sel;
 
  456         sel = u32_selector_alloc(u);
 
  460         err = 
nl_data_append(u->cu_selector, NULL, 
sizeof(
struct tc_u32_key));
 
  464         sel = u32_selector(u);
 
  466         sel->flags |= TC_U32_TERMINAL;
 
  470 int rtnl_u32_add_action(
struct rtnl_cls *cls, 
struct rtnl_act *act)
 
  480         u->cu_mask |= U32_ATTR_ACTION;
 
  481         return rtnl_act_append(&u->cu_act, act);
 
  484 int rtnl_u32_del_action(
struct rtnl_cls *cls, 
struct rtnl_act *act)
 
  495         if (!(u->cu_mask & U32_ATTR_ACTION))
 
  498         ret = rtnl_act_remove(&u->cu_act, act);
 
  500                 u->cu_mask &= ~U32_ATTR_ACTION;
 
  510 int rtnl_u32_set_flags(
struct rtnl_cls *cls, 
int flags)
 
  512         struct tc_u32_sel *sel;
 
  518         sel = u32_selector_alloc(u);
 
  523         u->cu_mask |= U32_ATTR_SELECTOR;
 
  543                      int off, 
int offmask)
 
  545         struct tc_u32_sel *sel;
 
  552         sel = u32_selector_alloc(u);
 
  556         err = 
nl_data_append(u->cu_selector, NULL, 
sizeof(
struct tc_u32_key));
 
  561         sel = u32_selector(u);
 
  563         sel->keys[sel->nkeys].mask = mask;
 
  564         sel->keys[sel->nkeys].val = val & mask;
 
  565         sel->keys[sel->nkeys].off = off;
 
  566         sel->keys[sel->nkeys].offmask = offmask;
 
  568         u->cu_mask |= U32_ATTR_SELECTOR;
 
  585                      uint32_t *val, uint32_t *mask, 
int *off, 
int *offmask)
 
  587         struct tc_u32_sel *sel;
 
  593         if (!(u->cu_mask & U32_ATTR_SELECTOR))
 
  597         sel = u32_selector(u);
 
  598         if (index >= sel->nkeys)
 
  601         *mask = sel->keys[index].mask;
 
  602         *val = sel->keys[index].val;
 
  603         *off = sel->keys[index].off;
 
  604         *offmask = sel->keys[index].offmask;
 
  609 int rtnl_u32_add_key_uint8(
struct rtnl_cls *cls, uint8_t val, uint8_t mask,
 
  610                            int off, 
int offmask)
 
  612         int shift = 24 - 8 * (off & 3);
 
  615                                 htonl((uint32_t)mask << shift),
 
  629                             int off, 
int offmask)
 
  631         int shift = ((off & 3) == 0 ? 16 : 0);
 
  636                                 htonl((uint32_t)mask << shift),
 
  650                             int off, 
int offmask)
 
  656 int rtnl_u32_add_key_in_addr(
struct rtnl_cls *cls, 
struct in_addr *addr,
 
  657                              uint8_t bitmask, 
int off, 
int offmask)
 
  659         uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
 
  663 int rtnl_u32_add_key_in6_addr(
struct rtnl_cls *cls, 
struct in6_addr *addr,
 
  664                               uint8_t bitmask, 
int off, 
int offmask)
 
  668         for (i = 1; i <= 4; i++) {
 
  669                 if (32 * i - bitmask <= 0) {
 
  671                                                 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
 
  674                 else if (32 * i - bitmask < 32) {
 
  675                         uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
 
  677                                                 htonl(mask), off+4*(i-1), offmask)) < 0)
 
  688 static struct rtnl_tc_ops u32_ops = {
 
  690         .to_type                = RTNL_TC_TYPE_CLS,
 
  691         .to_size                = 
sizeof(
struct rtnl_u32),
 
  692         .to_msg_parser          = u32_msg_parser,
 
  693         .to_free_data           = u32_free_data,
 
  694         .to_clone               = u32_clone,
 
  695         .to_msg_fill            = u32_msg_fill,
 
  703 static void __init u32_init(
void)
 
  708 static void __exit u32_exit(
void)