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

Reply via email to