6 #include <netlink-private/netlink.h>
7 #include <netlink-private/tc.h>
8 #include <netlink/netlink.h>
9 #include <netlink/attr.h>
10 #include <netlink/utils.h>
11 #include <netlink-private/route/tc-api.h>
12 #include <netlink/route/classifier.h>
13 #include <netlink/route/action.h>
14 #include <netlink/route/cls/flower.h>
18 #define FLOWER_ATTR_FLAGS (1 << 0)
19 #define FLOWER_ATTR_ACTION (1 << 1)
20 #define FLOWER_ATTR_VLAN_ID (1 << 2)
21 #define FLOWER_ATTR_VLAN_PRIO (1 << 3)
22 #define FLOWER_ATTR_VLAN_ETH_TYPE (1 << 4)
23 #define FLOWER_ATTR_DST_MAC (1 << 5)
24 #define FLOWER_ATTR_DST_MAC_MASK (1 << 6)
25 #define FLOWER_ATTR_SRC_MAC (1 << 7)
26 #define FLOWER_ATTR_SRC_MAC_MASK (1 << 8)
27 #define FLOWER_ATTR_IP_DSCP (1 << 9)
28 #define FLOWER_ATTR_IP_DSCP_MASK (1 << 10)
29 #define FLOWER_ATTR_PROTO (1 << 11)
32 #define FLOWER_DSCP_MAX 0xe0
33 #define FLOWER_DSCP_MASK_MAX 0xe0
34 #define FLOWER_VID_MAX 4095
35 #define FLOWER_VLAN_PRIO_MAX 7
37 static struct nla_policy flower_policy[TCA_FLOWER_MAX + 1] = {
39 [TCA_FLOWER_KEY_ETH_TYPE] = { .type =
NLA_U16 },
40 [TCA_FLOWER_KEY_ETH_DST] = { .maxlen = ETH_ALEN },
41 [TCA_FLOWER_KEY_ETH_DST_MASK] = { .maxlen = ETH_ALEN },
42 [TCA_FLOWER_KEY_ETH_SRC] = { .maxlen = ETH_ALEN },
43 [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .maxlen = ETH_ALEN },
44 [TCA_FLOWER_KEY_VLAN_ID] = { .type =
NLA_U16 },
45 [TCA_FLOWER_KEY_VLAN_PRIO] = { .type =
NLA_U8 },
46 [TCA_FLOWER_KEY_IP_TOS] = { .type =
NLA_U8 },
47 [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type =
NLA_U8 },
48 [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type =
NLA_U16 },
51 static int flower_msg_parser(
struct rtnl_tc *tc,
void *data)
53 struct rtnl_flower *f = data;
54 struct nlattr *tb[TCA_FLOWER_MAX + 1];
57 err = tca_parse(tb, TCA_FLOWER_MAX, tc, flower_policy);
61 if (tb[TCA_FLOWER_FLAGS]) {
63 f->cf_mask |= FLOWER_ATTR_FLAGS;
66 if (tb[TCA_FLOWER_ACT]) {
67 err = rtnl_act_parse(&f->cf_act, tb[TCA_FLOWER_ACT]);
71 f->cf_mask |= FLOWER_ATTR_ACTION;
74 if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
75 f->cf_proto =
nla_get_u16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
76 f->cf_mask |= FLOWER_ATTR_PROTO;
79 if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
80 f->cf_vlan_id =
nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]);
81 f->cf_mask |= FLOWER_ATTR_VLAN_ID;
84 if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
85 f->cf_vlan_prio =
nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]);
86 f->cf_mask |= FLOWER_ATTR_VLAN_PRIO;
89 if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
90 f->cf_vlan_ethtype =
nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
91 f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE;
94 if (tb[TCA_FLOWER_KEY_ETH_DST]) {
95 nla_memcpy(f->cf_dst_mac, tb[TCA_FLOWER_KEY_ETH_DST], ETH_ALEN);
96 f->cf_mask |= FLOWER_ATTR_DST_MAC;
99 if (tb[TCA_FLOWER_KEY_ETH_DST_MASK]) {
100 nla_memcpy(f->cf_dst_mac_mask, tb[TCA_FLOWER_KEY_ETH_DST_MASK], ETH_ALEN);
101 f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK;
104 if (tb[TCA_FLOWER_KEY_ETH_SRC]) {
105 nla_memcpy(f->cf_src_mac, tb[TCA_FLOWER_KEY_ETH_SRC], ETH_ALEN);
106 f->cf_mask |= FLOWER_ATTR_SRC_MAC;
109 if (tb[TCA_FLOWER_KEY_ETH_SRC_MASK]) {
110 nla_memcpy(f->cf_src_mac_mask, tb[TCA_FLOWER_KEY_ETH_SRC_MASK], ETH_ALEN);
111 f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK;
114 if (tb[TCA_FLOWER_KEY_IP_TOS]) {
115 f->cf_ip_dscp =
nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS]);
116 f->cf_mask |= FLOWER_ATTR_IP_DSCP;
119 if (tb[TCA_FLOWER_KEY_IP_TOS_MASK]) {
120 f->cf_ip_dscp_mask =
nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS_MASK]);
121 f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK;
127 static int flower_msg_fill(
struct rtnl_tc *tc,
void *data,
struct nl_msg *msg)
129 struct rtnl_flower *f = data;
135 if (f->cf_mask & FLOWER_ATTR_FLAGS)
138 if (f->cf_mask & FLOWER_ATTR_ACTION) {
139 err = rtnl_act_fill(msg, TCA_FLOWER_ACT, f->cf_act);
144 if (f->cf_mask & FLOWER_ATTR_PROTO)
145 NLA_PUT_U16(msg, TCA_FLOWER_KEY_ETH_TYPE, f->cf_proto);
147 if (f->cf_mask & FLOWER_ATTR_VLAN_ID)
148 NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ID, f->cf_vlan_id);
150 if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO)
151 NLA_PUT_U8(msg, TCA_FLOWER_KEY_VLAN_PRIO, f->cf_vlan_prio);
153 if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE)
154 NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ETH_TYPE, f->cf_vlan_ethtype);
156 if (f->cf_mask & FLOWER_ATTR_DST_MAC)
157 NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST, ETH_ALEN, f->cf_dst_mac);
159 if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK)
160 NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST_MASK, ETH_ALEN, f->cf_dst_mac_mask);
162 if (f->cf_mask & FLOWER_ATTR_SRC_MAC)
163 NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC, ETH_ALEN, f->cf_src_mac);
165 if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK)
166 NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC_MASK, ETH_ALEN, f->cf_src_mac_mask);
168 if (f->cf_mask & FLOWER_ATTR_IP_DSCP)
169 NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS, f->cf_ip_dscp);
171 if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK)
172 NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS_MASK, f->cf_ip_dscp_mask);
180 static void flower_free_data(
struct rtnl_tc *tc,
void *data)
182 struct rtnl_flower *f = data;
185 rtnl_act_put_all(&f->cf_act);
188 static int flower_clone(
void *_dst,
void *_src)
190 struct rtnl_flower *dst = _dst, *src = _src;
193 if (!(dst->cf_act = rtnl_act_alloc()))
196 memcpy(dst->cf_act, src->cf_act,
sizeof(
struct rtnl_act));
199 nl_init_list_head(&dst->cf_act->ce_list);
201 if ( src->cf_act->c_opts
202 && !(dst->cf_act->c_opts =
nl_data_clone(src->cf_act->c_opts)))
205 if ( src->cf_act->c_xstats
206 && !(dst->cf_act->c_xstats =
nl_data_clone(src->cf_act->c_xstats)))
209 if ( src->cf_act->c_subdata
210 && !(dst->cf_act->c_subdata =
nl_data_clone(src->cf_act->c_subdata)))
213 if (dst->cf_act->c_link) {
217 dst->cf_act->a_next = NULL;
223 static void flower_dump_details(
struct rtnl_tc *tc,
void *data,
226 struct rtnl_flower *f = data;
231 if (f->cf_mask & FLOWER_ATTR_FLAGS)
232 nl_dump(p,
" flags %u", f->cf_flags);
234 if (f->cf_mask & FLOWER_ATTR_PROTO)
235 nl_dump(p,
" protocol %u", f->cf_proto);
237 if (f->cf_mask & FLOWER_ATTR_VLAN_ID)
238 nl_dump(p,
" vlan_id %u", f->cf_vlan_id);
240 if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO)
241 nl_dump(p,
" vlan_prio %u", f->cf_vlan_prio);
243 if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE)
244 nl_dump(p,
" vlan_ethtype %u", f->cf_vlan_ethtype);
246 if (f->cf_mask & FLOWER_ATTR_DST_MAC)
247 nl_dump(p,
" dst_mac %02x:%02x:%02x:%02x:%02x:%02x",
248 f->cf_dst_mac[0], f->cf_dst_mac[1],
249 f->cf_dst_mac[2], f->cf_dst_mac[3],
250 f->cf_dst_mac[4], f->cf_dst_mac[5]);
252 if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK)
253 nl_dump(p,
" dst_mac_mask %02x:%02x:%02x:%02x:%02x:%02x",
254 f->cf_dst_mac_mask[0], f->cf_dst_mac_mask[1],
255 f->cf_dst_mac_mask[2], f->cf_dst_mac_mask[3],
256 f->cf_dst_mac_mask[4], f->cf_dst_mac_mask[5]);
258 if (f->cf_mask & FLOWER_ATTR_SRC_MAC)
259 nl_dump(p,
" src_mac %02x:%02x:%02x:%02x:%02x:%02x",
260 f->cf_src_mac[0], f->cf_src_mac[1],
261 f->cf_src_mac[2], f->cf_src_mac[3],
262 f->cf_src_mac[4], f->cf_src_mac[5]);
264 if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK)
265 nl_dump(p,
" src_mac_mask %02x:%02x:%02x:%02x:%02x:%02x",
266 f->cf_src_mac_mask[0], f->cf_src_mac_mask[1],
267 f->cf_src_mac_mask[2], f->cf_src_mac_mask[3],
268 f->cf_src_mac_mask[4], f->cf_src_mac_mask[5]);
270 if (f->cf_mask & FLOWER_ATTR_IP_DSCP)
271 nl_dump(p,
" dscp %u", f->cf_ip_dscp);
273 if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK)
274 nl_dump(p,
" dscp_mask %u", f->cf_ip_dscp_mask);
288 int rtnl_flower_set_proto(
struct rtnl_cls *cls, uint16_t proto)
290 struct rtnl_flower *f;
295 f->cf_proto = htons(proto);
296 f->cf_mask |= FLOWER_ATTR_PROTO;
307 int rtnl_flower_get_proto(
struct rtnl_cls *cls, uint16_t *proto)
309 struct rtnl_flower *f;
314 if (!(f->cf_mask & FLOWER_ATTR_PROTO))
315 return -NLE_MISSING_ATTR;
317 *proto = ntohs(f->cf_proto);
328 int rtnl_flower_set_vlan_id(
struct rtnl_cls *cls, uint16_t vid)
330 struct rtnl_flower *f;
335 if (vid > FLOWER_VID_MAX)
339 f->cf_mask |= FLOWER_ATTR_VLAN_ID;
350 int rtnl_flower_get_vlan_id(
struct rtnl_cls *cls, uint16_t *vid)
352 struct rtnl_flower *f;
357 if (!(f->cf_mask & FLOWER_ATTR_VLAN_ID))
358 return -NLE_MISSING_ATTR;
360 *vid = f->cf_vlan_id;
371 int rtnl_flower_set_vlan_prio(
struct rtnl_cls *cls, uint8_t prio)
373 struct rtnl_flower *f;
378 if (prio > FLOWER_VLAN_PRIO_MAX)
381 f->cf_vlan_prio = prio;
382 f->cf_mask |= FLOWER_ATTR_VLAN_PRIO;
393 int rtnl_flower_get_vlan_prio(
struct rtnl_cls *cls, uint8_t *prio)
395 struct rtnl_flower *f;
400 if (!(f->cf_mask & FLOWER_ATTR_VLAN_PRIO))
401 return -NLE_MISSING_ATTR;
403 *prio = f->cf_vlan_prio;
414 int rtnl_flower_set_vlan_ethtype(
struct rtnl_cls *cls, uint16_t ethtype)
416 struct rtnl_flower *f;
421 if (!(f->cf_mask & FLOWER_ATTR_PROTO))
422 return -NLE_MISSING_ATTR;
424 if (f->cf_proto != htons(ETH_P_8021Q))
427 f->cf_vlan_ethtype = htons(ethtype);
428 f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE;
440 int rtnl_flower_set_dst_mac(
struct rtnl_cls *cls,
unsigned char *mac,
443 struct rtnl_flower *f;
449 memcpy(f->cf_dst_mac, mac, ETH_ALEN);
450 f->cf_mask |= FLOWER_ATTR_DST_MAC;
453 memcpy(f->cf_dst_mac_mask, mask, ETH_ALEN);
454 f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK;
470 int rtnl_flower_get_dst_mac(
struct rtnl_cls *cls,
unsigned char *mac,
473 struct rtnl_flower *f;
478 if (!(f->cf_mask & FLOWER_ATTR_DST_MAC))
479 return -NLE_MISSING_ATTR;
482 memcpy(mac, f->cf_dst_mac, ETH_ALEN);
485 memcpy(mask, f->cf_dst_mac_mask, ETH_ALEN);
497 int rtnl_flower_set_src_mac(
struct rtnl_cls *cls,
unsigned char *mac,
500 struct rtnl_flower *f;
506 memcpy(f->cf_src_mac, mac, ETH_ALEN);
507 f->cf_mask |= FLOWER_ATTR_SRC_MAC;
510 memcpy(f->cf_src_mac_mask, mask, ETH_ALEN);
511 f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK;
527 int rtnl_flower_get_src_mac(
struct rtnl_cls *cls,
unsigned char *mac,
530 struct rtnl_flower *f;
535 if (!(f->cf_mask & FLOWER_ATTR_SRC_MAC))
536 return -NLE_MISSING_ATTR;
539 memcpy(mac, f->cf_src_mac, ETH_ALEN);
542 memcpy(mask, f->cf_src_mac_mask, ETH_ALEN);
554 int rtnl_flower_set_ip_dscp(
struct rtnl_cls *cls, uint8_t dscp, uint8_t mask)
556 struct rtnl_flower *f;
561 if (dscp > FLOWER_DSCP_MAX)
564 if (mask > FLOWER_DSCP_MASK_MAX)
567 f->cf_ip_dscp = dscp;
568 f->cf_mask |= FLOWER_ATTR_IP_DSCP;
571 f->cf_ip_dscp_mask = mask;
572 f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK;
585 int rtnl_flower_get_ip_dscp(
struct rtnl_cls *cls, uint8_t *dscp, uint8_t *mask)
587 struct rtnl_flower *f;
592 if (!(f->cf_mask & FLOWER_ATTR_IP_DSCP))
593 return -NLE_MISSING_ATTR;
595 *dscp = f->cf_ip_dscp;
596 *mask = f->cf_ip_dscp_mask;
607 int rtnl_flower_append_action(
struct rtnl_cls *cls,
struct rtnl_act *act)
609 struct rtnl_flower *f;
617 f->cf_mask |= FLOWER_ATTR_ACTION;
620 return rtnl_act_append(&f->cf_act, act);
629 int rtnl_flower_del_action(
struct rtnl_cls *cls,
struct rtnl_act *act)
631 struct rtnl_flower *f;
640 if (!(f->cf_mask & FLOWER_ATTR_ACTION))
643 ret = rtnl_act_remove(&f->cf_act, act);
648 f->cf_mask &= ~FLOWER_ATTR_ACTION;
659 struct rtnl_act* rtnl_flower_get_action(
struct rtnl_cls *cls)
661 struct rtnl_flower *f;
666 if (!(f->cf_mask & FLOWER_ATTR_ACTION))
669 rtnl_act_get(f->cf_act);
680 int rtnl_flower_set_flags(
struct rtnl_cls *cls,
int flags)
682 struct rtnl_flower *f;
688 f->cf_mask |= FLOWER_ATTR_FLAGS;
695 static struct rtnl_tc_ops flower_ops = {
697 .to_type = RTNL_TC_TYPE_CLS,
698 .to_size =
sizeof(
struct rtnl_flower),
699 .to_msg_parser = flower_msg_parser,
700 .to_free_data = flower_free_data,
701 .to_clone = flower_clone,
702 .to_msg_fill = flower_msg_fill,
708 static void __init flower_init(
void)
713 static void __exit flower_exit(
void)
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
struct nl_data * nl_data_clone(const struct nl_data *src)
Clone an abstract data object.
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Attribute validation policy.
uint16_t type
Type of attribute or NLA_UNSPEC.