New match on ct state, mark, and label from ct_info on the skb. This can be set via sending the packet to ct via the ct action.
Signed-off-by: Paul Blakey <pa...@mellanox.com> --- include/uapi/linux/pkt_cls.h | 17 ++++++ net/sched/cls_flower.c | 126 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 02ac251..121f1ef 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -497,11 +497,28 @@ enum { TCA_FLOWER_KEY_PORT_DST_MIN, /* be16 */ TCA_FLOWER_KEY_PORT_DST_MAX, /* be16 */ + TCA_FLOWER_KEY_CT_STATE, + TCA_FLOWER_KEY_CT_STATE_MASK, + TCA_FLOWER_KEY_CT_ZONE, + TCA_FLOWER_KEY_CT_ZONE_MASK, + TCA_FLOWER_KEY_CT_MARK, + TCA_FLOWER_KEY_CT_MARK_MASK, + TCA_FLOWER_KEY_CT_LABELS, + TCA_FLOWER_KEY_CT_LABELS_MASK, + __TCA_FLOWER_MAX, }; #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) + +#define TCA_FLOWER_KEY_CT_FLAGS_NEW 0x01 /* Beginning of a new connection. */ +#define TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED 0x02 /* Part of an existing connection. */ +#define TCA_FLOWER_KEY_CT_FLAGS_RELATED 0x04 /* Related to an established connection. */ +#define TCA_FLOWER_KEY_CT_FLAGS_INVALID 0x10 /* Could not track connection. */ +#define TCA_FLOWER_KEY_CT_FLAGS_TRACKED 0x20 /* Conntrack has occurred. */ + + enum { TCA_FLOWER_KEY_ENC_OPTS_UNSPEC, TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index f6aa57f..bf74a31 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -29,6 +29,9 @@ #include <net/dst.h> #include <net/dst_metadata.h> +#include <net/netfilter/nf_conntrack_core.h> +#include <net/netfilter/nf_conntrack_labels.h> + struct fl_flow_key { int indev_ifindex; struct flow_dissector_key_control control; @@ -57,6 +60,11 @@ struct fl_flow_key { struct flow_dissector_key_enc_opts enc_opts; struct flow_dissector_key_ports tp_min; struct flow_dissector_key_ports tp_max; + + u8 ct_state; + u16 ct_zone; + u32 ct_mark; + u32 ct_labels[NF_CT_LABELS_MAX_SIZE / sizeof(u32)]; } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ struct fl_flow_mask_range { @@ -265,19 +273,55 @@ static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask, return __fl_lookup(mask, mkey); } +static u8 fl_ct_get_state(enum ip_conntrack_info ctinfo) +{ + u8 ct_state = TCA_FLOWER_KEY_CT_FLAGS_TRACKED; + + switch (ctinfo) { + case IP_CT_ESTABLISHED: + case IP_CT_ESTABLISHED_REPLY: + ct_state |= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED; + break; + case IP_CT_RELATED: + case IP_CT_RELATED_REPLY: + ct_state |= TCA_FLOWER_KEY_CT_FLAGS_RELATED; + break; + case IP_CT_NEW: + ct_state |= TCA_FLOWER_KEY_CT_FLAGS_NEW; + break; + default: + break; + } + + return ct_state; +} + static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct tcf_result *res) { struct cls_fl_head *head = rcu_dereference_bh(tp->root); - struct cls_fl_filter *f; - struct fl_flow_mask *mask; - struct fl_flow_key skb_key; + enum ip_conntrack_info ctinfo; struct fl_flow_key skb_mkey; + struct fl_flow_key skb_key; + struct fl_flow_mask *mask; + struct nf_conn_labels *cl; + struct cls_fl_filter *f; + struct nf_conn *ct; list_for_each_entry_rcu(mask, &head->masks, list) { fl_clear_masked_range(&skb_key, mask); skb_key.indev_ifindex = skb->skb_iif; + ct = nf_ct_get(skb, &ctinfo); + if (ct) { + skb_key.ct_state = fl_ct_get_state(ctinfo); + skb_key.ct_zone = ct->zone.id; + skb_key.ct_mark = ct->mark; + + cl = nf_ct_labels_find(ct); + if (cl) + memcpy(skb_key.ct_labels, cl->bits, sizeof(skb_key.ct_labels)); + } /* skb_flow_dissect() does not set n_proto in case an unknown * protocol, so do it rather here. */ @@ -562,6 +606,14 @@ static void *fl_get(struct tcf_proto *tp, u32 handle) [TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ENC_OPTS] = { .type = NLA_NESTED }, [TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NLA_NESTED }, + [TCA_FLOWER_KEY_CT_STATE] = { .type = NLA_U8 }, + [TCA_FLOWER_KEY_CT_STATE_MASK] = { .type = NLA_U8 }, + [TCA_FLOWER_KEY_CT_ZONE] = { .type = NLA_U16 }, + [TCA_FLOWER_KEY_CT_ZONE_MASK] = { .type = NLA_U16 }, + [TCA_FLOWER_KEY_CT_MARK] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_CT_MARK_MASK] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_CT_LABELS] = { .type = NLA_UNSPEC, .len = 16 }, + [TCA_FLOWER_KEY_CT_LABELS_MASK] = { .type = NLA_UNSPEC, .len = 16 }, }; static const struct nla_policy @@ -872,6 +924,36 @@ static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key, return 0; } +static int fl_set_key_ct(struct nlattr **tb, struct fl_flow_key *key, + struct fl_flow_key *mask, + struct netlink_ext_ack *extack) +{ + size_t label_len = 0; + + if (tb[TCA_FLOWER_KEY_CT_STATE]) { + key->ct_state = nla_get_u8(tb[TCA_FLOWER_KEY_CT_STATE]); + mask->ct_state = nla_get_u8(tb[TCA_FLOWER_KEY_CT_STATE_MASK]); + } + + if (tb[TCA_FLOWER_KEY_CT_ZONE_MASK]) { + key->ct_zone = nla_get_u16(tb[TCA_FLOWER_KEY_CT_ZONE]); + mask->ct_zone = nla_get_u16(tb[TCA_FLOWER_KEY_CT_ZONE_MASK]); + } + + if (tb[TCA_FLOWER_KEY_CT_MARK_MASK]) { + key->ct_mark = nla_get_u32(tb[TCA_FLOWER_KEY_CT_MARK]); + mask->ct_mark = nla_get_u32(tb[TCA_FLOWER_KEY_CT_MARK_MASK]); + } + + if (tb[TCA_FLOWER_KEY_CT_LABELS_MASK]) { + label_len = nla_len(tb[TCA_FLOWER_KEY_CT_LABELS]); + memcpy(key->ct_labels, nla_data(tb[TCA_FLOWER_KEY_CT_LABELS]), label_len); + memcpy(mask->ct_labels, nla_data(tb[TCA_FLOWER_KEY_CT_LABELS_MASK]), label_len); + } + + return 0; +} + static int fl_set_key(struct net *net, struct nlattr **tb, struct fl_flow_key *key, struct fl_flow_key *mask, struct netlink_ext_ack *extack) @@ -1082,6 +1164,10 @@ static int fl_set_key(struct net *net, struct nlattr **tb, return ret; } + ret = fl_set_key_ct(tb, key, mask, extack); + if (ret) + return ret; + if (tb[TCA_FLOWER_KEY_FLAGS]) ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags); @@ -1761,6 +1847,37 @@ static int fl_dump_key_geneve_opt(struct sk_buff *skb, return -EMSGSIZE; } +static int fl_dump_key_ct(struct sk_buff *skb, + struct fl_flow_key *key, + struct fl_flow_key *mask) +{ + if(fl_dump_key_val(skb, &key->ct_state, TCA_FLOWER_KEY_CT_STATE, + &mask->ct_state, TCA_FLOWER_KEY_CT_STATE_MASK, + sizeof(key->ct_state))) + goto nla_put_failure; + + if (fl_dump_key_val(skb, &key->ct_zone, TCA_FLOWER_KEY_CT_ZONE, + &mask->ct_zone, TCA_FLOWER_KEY_CT_ZONE_MASK, + sizeof(key->ct_zone))) + goto nla_put_failure; + + if (fl_dump_key_val(skb, &key->ct_mark, TCA_FLOWER_KEY_CT_MARK, + &mask->ct_mark, TCA_FLOWER_KEY_CT_MARK_MASK, + sizeof(key->ct_mark))) + goto nla_put_failure; + + if (fl_dump_key_val(skb, &key->ct_labels, TCA_FLOWER_KEY_CT_LABELS, + &mask->ct_labels, TCA_FLOWER_KEY_CT_LABELS_MASK, + sizeof(key->ct_labels))) + goto nla_put_failure; + + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + + static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type, struct flow_dissector_key_enc_opts *enc_opts) { @@ -1994,6 +2111,9 @@ static int fl_dump_key(struct sk_buff *skb, struct net *net, fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts)) goto nla_put_failure; + if (fl_dump_key_ct(skb, key, mask)) + goto nla_put_failure; + if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) goto nla_put_failure; -- 1.8.3.1