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