From 39d445cbb55d338eff9e8f337594333be2ccea20 Mon Sep 17 00:00:00 2001 From: Przemyslaw Czarnota Date: Tue, 7 Aug 2018 10:09:19 +0200 Subject: flower: add support for more TCA_FLOWER_* properties --- include/netlink-private/types.h | 15 +- include/netlink/route/cls/flower.h | 22 ++ lib/route/cls/flower.c | 370 +++++++++++++++++++++++- libnl-route-3.sym | 22 ++ tests/test-flower-filter-with-actions.c | 113 ++++++-- 5 files changed, 507 insertions(+), 35 deletions(-) --- a/include/netlink-private/types.h +++ b/include/netlink-private/types.h @@ -618,11 +618,22 @@ struct rtnl_mall struct rtnl_flower { - uint16_t fl_vlan_id; - uint8_t fl_vlan_prio; + uint32_t fl_vlan_id; + uint32_t fl_vlan_prio; + uint16_t fl_vlan_eth_type; char fl_indev[IFNAMSIZ]; struct rtnl_act* fl_act; uint32_t fl_flags; + uint32_t fl_classid; + uint8_t fl_eth_dst[ETH_ALEN]; + uint8_t fl_eth_dst_mask[ETH_ALEN]; + uint8_t fl_eth_src[ETH_ALEN]; + uint8_t fl_eth_src_mask[ETH_ALEN]; + uint8_t fl_ip_tos; + uint8_t fl_ip_tos_mask; + uint32_t fl_cvlan_id; + uint32_t fl_cvlan_prio; + uint16_t fl_cvlan_eth_type; int fl_mask; }; --- a/include/netlink/route/cls/flower.h +++ b/include/netlink/route/cls/flower.h @@ -32,6 +32,28 @@ extern int rtnl_flower_get_vlan_prio(str extern int rtnl_flower_add_action(struct rtnl_cls *, struct rtnl_act *); extern int rtnl_flower_del_action(struct rtnl_cls *, struct rtnl_act *); extern struct rtnl_act *rtnl_flower_get_action(struct rtnl_cls *); +extern int rtnl_flower_set_vlan_eth_type(struct rtnl_cls *, uint16_t); +extern int rtnl_flower_get_vlan_eth_type(struct rtnl_cls *, uint16_t *); +extern int rtnl_flower_set_classid(struct rtnl_cls *, uint32_t); +extern int rtnl_flower_get_classid(struct rtnl_cls *, uint32_t *); +extern int rtnl_flower_set_eth_dst(struct rtnl_cls *, const uint8_t *, unsigned int); +extern int rtnl_flower_get_eth_dst(struct rtnl_cls *, uint8_t *, unsigned int); +extern int rtnl_flower_set_eth_dst_mask(struct rtnl_cls *, const uint8_t *, unsigned int); +extern int rtnl_flower_get_eth_dst_mask(struct rtnl_cls *, uint8_t *, unsigned int); +extern int rtnl_flower_set_eth_src(struct rtnl_cls *, const uint8_t *, unsigned int); +extern int rtnl_flower_get_eth_src(struct rtnl_cls *, uint8_t *, unsigned int); +extern int rtnl_flower_set_eth_src_mask(struct rtnl_cls *, const uint8_t *, unsigned int); +extern int rtnl_flower_get_eth_src_mask(struct rtnl_cls *, uint8_t *, unsigned int); +extern int rtnl_flower_set_ip_tos(struct rtnl_cls *, uint8_t); +extern int rtnl_flower_get_ip_tos(struct rtnl_cls *, uint8_t *); +extern int rtnl_flower_set_ip_tos_mask(struct rtnl_cls *, uint8_t); +extern int rtnl_flower_get_ip_tos_mask(struct rtnl_cls *, uint8_t *); +extern int rtnl_flower_set_cvlan_id(struct rtnl_cls *, uint32_t); +extern int rtnl_flower_get_cvlan_id(struct rtnl_cls *, uint32_t *); +extern int rtnl_flower_set_cvlan_prio(struct rtnl_cls *, uint32_t); +extern int rtnl_flower_get_cvlan_prio(struct rtnl_cls *, uint32_t *); +extern int rtnl_flower_set_cvlan_eth_type(struct rtnl_cls *, uint16_t); +extern int rtnl_flower_get_cvlan_eth_type(struct rtnl_cls *, uint16_t *); #ifdef __cplusplus } --- a/lib/route/cls/flower.c +++ b/lib/route/cls/flower.c @@ -29,19 +29,66 @@ #include /** @cond SKIP */ -#define FLOWER_ATTR_KEY_VLAN_ID 0x001 -#define FLOWER_ATTR_KEY_VLAN_PRIO 0x002 -#define FLOWER_ATTR_INDEV 0x004 -#define FLOWER_ATTR_ACTION 0x008 -#define FLOWER_ATTR_FLAGS 0x010 +#define FLOWER_ATTR_KEY_VLAN_ID (0x1 << 0) +#define FLOWER_ATTR_KEY_VLAN_PRIO (0x1 << 1) +#define FLOWER_ATTR_KEY_VLAN_ETH_TYPE (0x1 << 2) +#define FLOWER_ATTR_INDEV (0x1 << 3) +#define FLOWER_ATTR_ACTION (0x1 << 4) +#define FLOWER_ATTR_FLAGS (0x1 << 5) +#define FLOWER_ATTR_CLASSID (0x1 << 6) +#define FLOWER_ATTR_KEY_ETH_DST (0x1 << 7) +#define FLOWER_ATTR_KEY_ETH_DST_MASK (0x1 << 8) +#define FLOWER_ATTR_KEY_ETH_SRC (0x1 << 9) +#define FLOWER_ATTR_KEY_ETH_SRC_MASK (0x1 << 10) +#define FLOWER_ATTR_KEY_IP_TOS (0x1 << 11) +#define FLOWER_ATTR_KEY_IP_TOS_MASK (0x1 << 12) +#define FLOWER_ATTR_KEY_CVLAN_ID (0x1 << 13) +#define FLOWER_ATTR_KEY_CVLAN_PRIO (0x1 << 14) +#define FLOWER_ATTR_KEY_CVLAN_ETH_TYPE (0x1 << 15) /** @endcond */ +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#define GETTER(cls, prop, value, size, key) \ + do { \ + struct rtnl_flower *f = rtnl_tc_data(TC_CAST(cls)); \ + if (!f) \ + return -NLE_NOMEM; \ + if (!(f->fl_mask & (key))) \ + return -NLE_MISSING_ATTR; \ + if (!(value)) \ + return -NLE_INVAL; \ + memcpy((value), &f->prop, MIN(sizeof(f->prop), size)); \ + } while (0) + +#define SETTER(cls, prop, value, size, key) \ + do { \ + struct rtnl_flower *f = rtnl_tc_data(TC_CAST(cls)); \ + if (!f) \ + return -NLE_NOMEM; \ + memcpy(&f->prop, (value), MIN(sizeof(f->prop), size)); \ + f->fl_mask |= key; \ + } while (0) + static struct nla_policy flower_policy[TCA_FLOWER_MAX + 1] = { [TCA_FLOWER_INDEV] = {.type = NLA_STRING, .maxlen = IFNAMSIZ}, + [TCA_FLOWER_CLASSID] = {.type = NLA_U32}, [TCA_FLOWER_KEY_VLAN_ID] = {.type = NLA_U16}, [TCA_FLOWER_KEY_VLAN_PRIO] = {.type = NLA_U8}, + [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = {.type = NLA_U16}, [TCA_FLOWER_KEY_ETH_TYPE] = {.type = NLA_U16}, - [TCA_FLOWER_FLAGS] = {.type = NLA_U32} + [TCA_FLOWER_FLAGS] = {.type = NLA_U32}, + [TCA_FLOWER_KEY_ETH_DST] = {.minlen = ETH_ALEN, .maxlen = ETH_ALEN}, + [TCA_FLOWER_KEY_ETH_DST_MASK] = {.minlen = ETH_ALEN, .maxlen = ETH_ALEN}, + [TCA_FLOWER_KEY_ETH_SRC] = {.minlen = ETH_ALEN, .maxlen = ETH_ALEN}, + [TCA_FLOWER_KEY_ETH_SRC_MASK] = {.minlen = ETH_ALEN, .maxlen = ETH_ALEN}, + [TCA_FLOWER_KEY_IP_TOS] = {.type = NLA_U8}, + [TCA_FLOWER_KEY_IP_TOS_MASK] = {.type = NLA_U8}, + [TCA_FLOWER_KEY_CVLAN_ID] = {.type = NLA_U16}, + [TCA_FLOWER_KEY_CVLAN_PRIO] = {.type = NLA_U8}, + [TCA_FLOWER_KEY_CVLAN_ETH_TYPE] = {.type = NLA_U16}, }; static int flower_msg_parser(struct rtnl_tc *tc, void *data) @@ -54,6 +101,11 @@ static int flower_msg_parser(struct rtnl if (err < 0) return err; + if (tb[TCA_FLOWER_CLASSID]) { + f->fl_classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]); + f->fl_mask |= FLOWER_ATTR_CLASSID; + } + if (tb[TCA_FLOWER_KEY_VLAN_ID]) { f->fl_vlan_id = nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]); f->fl_mask |= FLOWER_ATTR_KEY_VLAN_ID; @@ -64,6 +116,12 @@ static int flower_msg_parser(struct rtnl f->fl_mask |= FLOWER_ATTR_KEY_VLAN_PRIO; } + if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) { + f->fl_vlan_eth_type = + ntohs(nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE])); + f->fl_mask |= FLOWER_ATTR_KEY_VLAN_ETH_TYPE; + } + if (tb[TCA_FLOWER_INDEV]) { nla_strlcpy(f->fl_indev, tb[TCA_FLOWER_INDEV], IFNAMSIZ); f->fl_mask |= FLOWER_ATTR_INDEV; @@ -74,6 +132,56 @@ static int flower_msg_parser(struct rtnl f->fl_mask |= FLOWER_ATTR_FLAGS; } + if (tb[TCA_FLOWER_KEY_ETH_DST]) { + nla_memcpy(f->fl_eth_dst, tb[TCA_FLOWER_KEY_ETH_DST], + sizeof(f->fl_eth_dst)); + f->fl_mask |= FLOWER_ATTR_KEY_ETH_DST; + } + + if (tb[TCA_FLOWER_KEY_ETH_DST_MASK]) { + nla_memcpy(f->fl_eth_dst_mask, tb[TCA_FLOWER_KEY_ETH_DST_MASK], + sizeof(f->fl_eth_dst_mask)); + f->fl_mask |= FLOWER_ATTR_KEY_ETH_DST_MASK; + } + + if (tb[TCA_FLOWER_KEY_ETH_SRC]) { + nla_memcpy(f->fl_eth_src, tb[TCA_FLOWER_KEY_ETH_SRC], + sizeof(f->fl_eth_src)); + f->fl_mask |= FLOWER_ATTR_KEY_ETH_SRC; + } + + if (tb[TCA_FLOWER_KEY_ETH_SRC_MASK]) { + nla_memcpy(f->fl_eth_src_mask, tb[TCA_FLOWER_KEY_ETH_SRC_MASK], + sizeof(f->fl_eth_src_mask)); + f->fl_mask |= FLOWER_ATTR_KEY_ETH_SRC_MASK; + } + + if (tb[TCA_FLOWER_KEY_IP_TOS]) { + f->fl_ip_tos = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS]); + f->fl_mask |= FLOWER_ATTR_KEY_IP_TOS; + } + + if (tb[TCA_FLOWER_KEY_IP_TOS_MASK]) { + f->fl_ip_tos_mask = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS_MASK]); + f->fl_mask |= FLOWER_ATTR_KEY_IP_TOS_MASK; + } + + if (tb[TCA_FLOWER_KEY_CVLAN_ID]) { + f->fl_cvlan_id = nla_get_u16(tb[TCA_FLOWER_KEY_CVLAN_ID]); + f->fl_mask |= FLOWER_ATTR_KEY_CVLAN_ID; + } + + if (tb[TCA_FLOWER_KEY_CVLAN_PRIO]) { + f->fl_cvlan_prio = nla_get_u8(tb[TCA_FLOWER_KEY_CVLAN_PRIO]); + f->fl_mask |= FLOWER_ATTR_KEY_CVLAN_PRIO; + } + + if (tb[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]) { + f->fl_cvlan_eth_type = + ntohs(nla_get_u16(tb[TCA_FLOWER_KEY_CVLAN_ETH_TYPE])); + f->fl_mask |= FLOWER_ATTR_KEY_CVLAN_ETH_TYPE; + } + if (tb[TCA_FLOWER_ACT]) { f->fl_mask |= FLOWER_ATTR_ACTION; err = rtnl_act_parse(&f->fl_act, tb[TCA_FLOWER_ACT]); @@ -123,22 +231,68 @@ static void flower_dump_details(struct r struct nl_dump_params *p) { struct rtnl_flower *f = data; + int i; if (!f) return; + if (f->fl_mask & FLOWER_ATTR_CLASSID) + nl_dump(p, " classid %u", f->fl_classid); + if (f->fl_mask & FLOWER_ATTR_KEY_VLAN_ID) nl_dump(p, " vlan_id %u", f->fl_vlan_id); if (f->fl_mask & FLOWER_ATTR_KEY_VLAN_PRIO) nl_dump(p, " vlan_prio %u", f->fl_vlan_prio); + if (f->fl_mask & FLOWER_ATTR_KEY_VLAN_ETH_TYPE) + nl_dump(p, " vlan_prio %u", f->fl_vlan_eth_type); + if (f->fl_mask & FLOWER_ATTR_INDEV) nl_dump(p, " indev %s", f->fl_indev); if (f->fl_mask & FLOWER_ATTR_FLAGS) nl_dump(p, " flags 0x%08X", f->fl_flags); + if (f->fl_mask & FLOWER_ATTR_KEY_ETH_DST) { + nl_dump(p, " eth_dst"); + for (i = 0; i < ARRAY_SIZE(f->fl_eth_dst); ++i) + nl_dump(p, " 0x%02X", f->fl_eth_dst[i]); + } + + if (f->fl_mask & FLOWER_ATTR_KEY_ETH_DST_MASK) { + nl_dump(p, " eth_dst_mask"); + for (i = 0; i < ARRAY_SIZE(f->fl_eth_dst_mask); ++i) + nl_dump(p, " 0x%02X", f->fl_eth_dst_mask[i]); + } + + if (f->fl_mask & FLOWER_ATTR_KEY_ETH_SRC) { + nl_dump(p, " eth_src"); + for (i = 0; i < ARRAY_SIZE(f->fl_eth_src); ++i) + nl_dump(p, " 0x%02X", f->fl_eth_src[i]); + } + + if (f->fl_mask & FLOWER_ATTR_KEY_ETH_SRC_MASK) { + nl_dump(p, " eth_src_mask"); + for (i = 0; i < ARRAY_SIZE(f->fl_eth_src_mask); ++i) + nl_dump(p, " 0x%02X", f->fl_eth_src_mask[i]); + } + + if (f->fl_mask & FLOWER_ATTR_KEY_CVLAN_ID) + nl_dump(p, " cvlan_id %u", f->fl_cvlan_id); + + if (f->fl_mask & FLOWER_ATTR_KEY_CVLAN_PRIO) + nl_dump(p, " cvlan_prio %u", f->fl_cvlan_prio); + + if (f->fl_mask & FLOWER_ATTR_KEY_CVLAN_ETH_TYPE) + nl_dump(p, " cvlan_prio %u", f->fl_cvlan_eth_type); + + if (f->fl_mask & FLOWER_ATTR_KEY_IP_TOS) + nl_dump(p, " flags %u", f->fl_flags); + + if (f->fl_mask & FLOWER_ATTR_KEY_IP_TOS_MASK) + nl_dump(p, " flags 0x%08X", f->fl_flags); + nl_dump(p, "\n"); } @@ -150,18 +304,60 @@ static int flower_msg_fill(struct rtnl_t if (!f) return 0; + if (f->fl_mask & FLOWER_ATTR_CLASSID) + NLA_PUT_U32(msg, TCA_FLOWER_CLASSID, f->fl_classid); + if (f->fl_mask & FLOWER_ATTR_INDEV) NLA_PUT_STRING(msg, TCA_FLOWER_INDEV, f->fl_indev); if (f->fl_mask & FLOWER_ATTR_KEY_VLAN_ID) - NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ID, f->fl_vlan_id); + NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ID, + (uint16_t) f->fl_vlan_id); if (f->fl_mask & FLOWER_ATTR_KEY_VLAN_PRIO) - NLA_PUT_U8(msg, TCA_FLOWER_KEY_VLAN_PRIO, f->fl_vlan_prio); + NLA_PUT_U8(msg, TCA_FLOWER_KEY_VLAN_PRIO, + (uint8_t) f->fl_vlan_prio); + + if (f->fl_mask & FLOWER_ATTR_KEY_VLAN_ETH_TYPE) + NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ETH_TYPE, + htons(f->fl_vlan_eth_type)); if (f->fl_mask & FLOWER_ATTR_FLAGS) NLA_PUT_U32(msg, TCA_FLOWER_FLAGS, f->fl_flags); + if (f->fl_mask & FLOWER_ATTR_KEY_ETH_DST) + NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST, sizeof(f->fl_eth_dst), + f->fl_eth_dst); + + if (f->fl_mask & FLOWER_ATTR_KEY_ETH_DST_MASK) + NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST_MASK, + sizeof(f->fl_eth_dst_mask), f->fl_eth_dst_mask); + + if (f->fl_mask & FLOWER_ATTR_KEY_ETH_SRC) + NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC, sizeof(f->fl_eth_src), + f->fl_eth_src); + + if (f->fl_mask & FLOWER_ATTR_KEY_ETH_SRC_MASK) + NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC_MASK, + sizeof(f->fl_eth_src_mask), f->fl_eth_src_mask); + + if (f->fl_mask & FLOWER_ATTR_KEY_IP_TOS) + NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS, f->fl_ip_tos); + + if (f->fl_mask & FLOWER_ATTR_KEY_IP_TOS_MASK) + NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS_MASK, f->fl_ip_tos_mask); + + if (f->fl_mask & FLOWER_ATTR_KEY_CVLAN_ID) + NLA_PUT_U16(msg, TCA_FLOWER_KEY_CVLAN_ID, + (uint16_t) f->fl_cvlan_id); + + if (f->fl_mask & FLOWER_ATTR_KEY_CVLAN_PRIO) + NLA_PUT_U8(msg, TCA_FLOWER_KEY_CVLAN_PRIO, + (uint8_t) f->fl_cvlan_prio); + + if (f->fl_mask & FLOWER_ATTR_KEY_CVLAN_ETH_TYPE) + NLA_PUT_U16(msg, TCA_FLOWER_KEY_CVLAN_ETH_TYPE, htons(f->fl_cvlan_eth_type)); + if (f->fl_mask & FLOWER_ATTR_ACTION) { int err; @@ -381,6 +577,164 @@ int rtnl_flower_del_action(struct rtnl_c return 0; } +int rtnl_flower_set_vlan_eth_type(struct rtnl_cls *cls, uint16_t vlan_eth_type) +{ + SETTER(cls, fl_vlan_eth_type, &vlan_eth_type, sizeof(vlan_eth_type), + FLOWER_ATTR_KEY_VLAN_ETH_TYPE); + return 0; +} + +int rtnl_flower_get_vlan_eth_type(struct rtnl_cls *cls, + uint16_t *vlan_eth_type) +{ + GETTER(cls, fl_vlan_eth_type, vlan_eth_type, sizeof(*vlan_eth_type), + FLOWER_ATTR_KEY_VLAN_ETH_TYPE); + return 0; +} + +int rtnl_flower_set_classid(struct rtnl_cls *cls, uint32_t classid) +{ + SETTER(cls, fl_classid, &classid, sizeof(classid), FLOWER_ATTR_CLASSID); + return 0; +} + +int rtnl_flower_get_classid(struct rtnl_cls *cls, uint32_t *classid) +{ + GETTER(cls, fl_classid, classid, sizeof(*classid), FLOWER_ATTR_CLASSID); + return 0; +} + +int rtnl_flower_set_eth_dst(struct rtnl_cls *cls, const uint8_t *eth_dst, + unsigned int size) +{ + SETTER(cls, fl_eth_dst, eth_dst, size, FLOWER_ATTR_KEY_ETH_DST); + return 0; +} + +int rtnl_flower_get_eth_dst(struct rtnl_cls *cls, uint8_t *eth_dst, + unsigned int size) +{ + GETTER(cls, fl_eth_dst, eth_dst, size, FLOWER_ATTR_KEY_ETH_DST); + return 0; +} + +int rtnl_flower_set_eth_dst_mask(struct rtnl_cls *cls, + const uint8_t *eth_dst_mask, + unsigned int size) +{ + SETTER(cls, fl_eth_dst_mask, eth_dst_mask, size, + FLOWER_ATTR_KEY_ETH_DST_MASK); + return 0; +} + +int rtnl_flower_get_eth_dst_mask(struct rtnl_cls *cls, uint8_t *eth_dst_mask, + unsigned int size) +{ + GETTER(cls, fl_eth_dst_mask, eth_dst_mask, size, + FLOWER_ATTR_KEY_ETH_DST_MASK); + return 0; +} + +int rtnl_flower_set_eth_src(struct rtnl_cls *cls, const uint8_t *eth_src, + unsigned int size) +{ + SETTER(cls, fl_eth_src, eth_src, size, FLOWER_ATTR_KEY_ETH_SRC); + return 0; +} + +int rtnl_flower_get_eth_src(struct rtnl_cls *cls, uint8_t *eth_src, + unsigned int size) +{ + GETTER(cls, fl_eth_src, eth_src, size, FLOWER_ATTR_KEY_ETH_SRC); + return 0; +} + +int rtnl_flower_set_eth_src_mask(struct rtnl_cls *cls, + const uint8_t *eth_src_mask, + unsigned int size) +{ + SETTER(cls, fl_eth_src_mask, eth_src_mask, size, + FLOWER_ATTR_KEY_ETH_SRC_MASK); + return 0; +} + +int rtnl_flower_get_eth_src_mask(struct rtnl_cls *cls, uint8_t *eth_src_mask, + unsigned int size) +{ + GETTER(cls, fl_eth_src_mask, eth_src_mask, size, + FLOWER_ATTR_KEY_ETH_SRC_MASK); + return 0; +} + +int rtnl_flower_set_ip_tos(struct rtnl_cls *cls, uint8_t ip_tos) +{ + SETTER(cls, fl_ip_tos, &ip_tos, sizeof(ip_tos), FLOWER_ATTR_KEY_IP_TOS); + return 0; +} + +int rtnl_flower_get_ip_tos(struct rtnl_cls *cls, uint8_t *ip_tos) +{ + GETTER(cls, fl_ip_tos, ip_tos, sizeof(*ip_tos), FLOWER_ATTR_KEY_IP_TOS); + return 0; +} + +int rtnl_flower_set_ip_tos_mask(struct rtnl_cls *cls, uint8_t ip_tos_mask) +{ + SETTER(cls, fl_ip_tos_mask, &ip_tos_mask, sizeof(ip_tos_mask), + FLOWER_ATTR_KEY_IP_TOS_MASK); + return 0; +} + +int rtnl_flower_get_ip_tos_mask(struct rtnl_cls *cls, uint8_t *ip_tos_mask) +{ + GETTER(cls, fl_ip_tos_mask, ip_tos_mask, sizeof(*ip_tos_mask), + FLOWER_ATTR_KEY_IP_TOS_MASK); + return 0; +} + +int rtnl_flower_set_cvlan_id(struct rtnl_cls *cls, uint32_t cvlan_id) +{ + SETTER(cls, fl_cvlan_id, &cvlan_id, sizeof(cvlan_id), + FLOWER_ATTR_KEY_CVLAN_ID); + return 0; +} + +int rtnl_flower_get_cvlan_id(struct rtnl_cls *cls, uint32_t *cvlan_id) +{ + GETTER(cls, fl_cvlan_id, cvlan_id, sizeof(*cvlan_id), + FLOWER_ATTR_KEY_CVLAN_ID); + return 0; +} + +int rtnl_flower_set_cvlan_prio(struct rtnl_cls *cls, uint32_t cvlan_prio) +{ + SETTER(cls, fl_cvlan_prio, &cvlan_prio, sizeof(cvlan_prio), + FLOWER_ATTR_KEY_CVLAN_PRIO); + return 0; +} + +int rtnl_flower_get_cvlan_prio(struct rtnl_cls *cls, uint32_t *cvlan_prio) +{ + GETTER(cls, fl_cvlan_prio, cvlan_prio, sizeof(*cvlan_prio), + FLOWER_ATTR_KEY_CVLAN_PRIO); + return 0; +} + +int +rtnl_flower_set_cvlan_eth_type(struct rtnl_cls *cls, uint16_t cvlan_eth_type) +{ + SETTER(cls, fl_cvlan_eth_type, &cvlan_eth_type, sizeof(cvlan_eth_type), + FLOWER_ATTR_KEY_CVLAN_ETH_TYPE); + return 0; +} + +int rtnl_flower_get_cvlan_eth_type(struct rtnl_cls *cls, + uint16_t *cvlan_eth_type) +{ + GETTER(cls, fl_cvlan_eth_type, cvlan_eth_type, sizeof(*cvlan_eth_type), + FLOWER_ATTR_KEY_CVLAN_ETH_TYPE); + return 0; +} /** @} */ --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -864,6 +864,28 @@ global: rtnl_flower_add_action; rtnl_flower_del_action; rtnl_flower_get_action; + rtnl_flower_set_vlan_eth_type; + rtnl_flower_get_vlan_eth_type; + rtnl_flower_set_classid; + rtnl_flower_get_classid; + rtnl_flower_set_eth_dst; + rtnl_flower_get_eth_dst; + rtnl_flower_set_eth_dst_mask; + rtnl_flower_get_eth_dst_mask; + rtnl_flower_set_eth_src; + rtnl_flower_get_eth_src; + rtnl_flower_set_eth_src_mask; + rtnl_flower_get_eth_src_mask; + rtnl_flower_set_ip_tos; + rtnl_flower_get_ip_tos; + rtnl_flower_set_ip_tos_mask; + rtnl_flower_get_ip_tos_mask; + rtnl_flower_set_cvlan_id; + rtnl_flower_get_cvlan_id; + rtnl_flower_set_cvlan_prio; + rtnl_flower_get_cvlan_prio; + rtnl_flower_set_cvlan_eth_type; + rtnl_flower_get_cvlan_eth_type; # The following symbols were added during the development of 3.2.26. # Keep them in libnl_3 to avoid breaking users. --- a/tests/test-flower-filter-with-actions.c +++ b/tests/test-flower-filter-with-actions.c @@ -127,7 +127,7 @@ static int check_if_flower_is_created_co } if (!strstr - (output, "filter parent ffff:fff1 protocol 802.1Q pref 1 flower handle 0x1")) { + (output, "filter parent ffff:fff1 protocol 802.1Q pref 1 flower")) { printf("unexpected flower classifier\n"); ret = -1; goto err; @@ -139,6 +139,30 @@ static int check_if_flower_is_created_co goto err; } + if (!strstr(output, "eth_type ipv4")) { + printf("unexpected eth_type\n"); + ret = -1; + goto err; + } + + if (!strstr(output, "dst_mac 01:80:c2:00:00:00/24")) { + printf("unexpected dst_mac\n"); + ret = -1; + goto err; + } + + if (!strstr(output, "src_mac 01:80:c2:00:00:00/24")) { + printf("unexpected src_mac\n"); + ret = -1; + goto err; + } + + if (!strstr(output, "classid 8000:1")) { + printf("unexpected classid\n"); + ret = -1; + goto err; + } + err: if (ret) printf(output); @@ -150,22 +174,28 @@ err: static int test_flower_classifier_is_created(struct nl_sock *sock, struct nl_cache *link_cache) { - struct rtnl_cls *cls; - struct rtnl_act *act; + struct rtnl_cls *cls = NULL; + struct rtnl_act *act = NULL; int err = 0; int ifindex; + static const uint8_t dst[ETH_ALEN] = + { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; + static const uint8_t src[ETH_ALEN] = + { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; + static const uint8_t mask[ETH_ALEN] = + { 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00 }; cls = rtnl_cls_alloc(); if (!cls) { printf("Unable to allocate classifier\n"); err = -1; - goto err_classifier; + goto error; } err = rtnl_tc_set_kind(TC_CAST(cls), "flower"); if (err) { printf("Unable to set kind to flower classifier\n"); - goto err_classifier; + goto error; } rtnl_cls_set_prio(cls, 1); @@ -174,14 +204,14 @@ static int test_flower_classifier_is_cre err = nl_cache_refill(sock, link_cache); if (err) { printf("Unable to refill cache\n"); - goto err_cache; + goto error; } ifindex = rtnl_link_name2i(link_cache, "d0"); if (!ifindex) { printf("Unable to get link name\n"); err = -1; - goto err_link_name; + goto error; } rtnl_tc_set_ifindex(TC_CAST(cls), ifindex); @@ -190,24 +220,60 @@ static int test_flower_classifier_is_cre err = rtnl_flower_set_indev(cls, "d0"); if (err) { printf("Unable to set indev\n"); - goto err_indev; + goto error; } err = rtnl_flower_set_vlan_id(cls, 7); if (err) { printf("Unable to set vlan_id: %d\n", err); - goto err_vlan_id; + goto error; } err = rtnl_flower_set_vlan_prio(cls, 1); if (err) { printf("Unable to set vlan_prio: %d\n", err); - goto err_vlan_prio; + goto error; + } + + err = rtnl_flower_set_vlan_eth_type(cls, ETH_P_IP); + if (err) { + printf("Unable to set vlan_eth_type: %d\n", err); + goto error; + } + + err = rtnl_flower_set_eth_dst(cls, dst, sizeof(dst)); + if (err) { + printf("Unable to set eth_dst: %d\n", err); + goto error; + } + + err = rtnl_flower_set_eth_dst_mask(cls, mask, sizeof(mask)); + if (err) { + printf("Unable to set eth_dst_mask: %d\n", err); + goto error; + } + + err = rtnl_flower_set_eth_src(cls, src, sizeof(src)); + if (err) { + printf("Unable to set eth_src: %d\n", err); + goto error; + } + + err = rtnl_flower_set_eth_src_mask(cls, mask, sizeof(mask)); + if (err) { + printf("Unable to set eth_src_mask: %d\n", err); + goto error; + } + + err = rtnl_flower_set_classid(cls, TC_HANDLE(0x8000, 0x1)); + if (err) { + printf("Unable to set classid: %d\n", err); + goto error; } act = rtnl_act_alloc(); if (!act) { printf("Unable to allocate action\n"); err = -1; - goto err_action; + goto error; } rtnl_tc_set_kind(TC_CAST(act), "gact"); @@ -216,13 +282,13 @@ static int test_flower_classifier_is_cre err = rtnl_flower_add_action(cls, act); if (err) { printf("Unable to add action"); - goto err_action_add; + goto error; } err = rtnl_cls_add(sock, cls, NLM_F_CREATE); if (err) { printf("Unable to create classifier: %d\n", err); - goto err_cls_add; + goto error; } err = check_if_flower_is_created_correctly(); @@ -230,17 +296,13 @@ static int test_flower_classifier_is_cre printf("Flower classifier was not created correctly\n"); rtnl_cls_delete(sock, cls, 0); -err_cls_add: -err_action_add: - rtnl_act_put(act); -err_action: -err_vlan_prio: -err_vlan_id: -err_indev: -err_link_name: -err_cache: - rtnl_cls_put(cls); -err_classifier: + +error: + if (act) + rtnl_act_put(act); + if (cls) + rtnl_cls_put(cls); + return err; } @@ -251,7 +313,7 @@ static int check_if_flower_with_vlan_is_ output = run_command("tc -s -d filter show dev d0 ingress"); - if (!strstr(output, "vlan push id 777 protocol 802.1Q priority 5")) { + if (!strstr(output, "push id 777 protocol 802.1Q priority 5")) { printf("unexpected vlan action options\n"); ret = -1; goto err; @@ -358,6 +420,7 @@ err_cls_add: err_action_add: rtnl_act_put(act); err_action: +err_vlan_eth_type: err_vlan_prio: err_vlan_id: err_indev: