This a preliminary patch to add support on flow dissector for matching on ConnTrack information.
2 FIXMEs in place: - reusing nf_conn_labels may not be feasible, as we don't want to pull too much of ConnTrack into flow dissector. - CT may be there, but it may not be using labels. As hashing zeroes is different than not having the information, it should either be handled as a new dissector key or have an extra bit in flow_dissector_key_ct indicating its presence. Having it as an extra key may speed searches not using labels. Signed-off-by: Marcelo Ricardo Leitner <mleit...@redhat.com> --- include/net/flow_dissector.h | 17 ++++++++++++++ include/uapi/linux/netfilter/xt_connlabel.h | 5 +++++ net/core/flow_dissector.c | 25 +++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 6a4586dcdeded9b6cfe7d299d368b6a6ea6801cc..2b5a20a0f65c28d9907697ac3ef7e03d0e20209a 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -4,7 +4,9 @@ #include <linux/types.h> #include <linux/in6.h> +#include <linux/bits.h> #include <uapi/linux/if_ether.h> +#include <uapi/linux/netfilter/xt_connlabel.h> /** * struct flow_dissector_key_control: @@ -199,6 +201,19 @@ struct flow_dissector_key_ip { __u8 ttl; }; +/** + * struct flow_dissector_key_ct: + */ +struct flow_dissector_key_ct { + __u16 zone; + __u8 state; + __u32 mark; + /* FIXME: Use nf_conn_labels instead? But it pulls all netfilter */ +#define NF_CT_LABELS_MAX_SIZE ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE) + unsigned long label[NF_CT_LABELS_MAX_SIZE / sizeof(long)]; +#undef NF_CT_LABELS_MAX_SIZE +}; + enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ @@ -224,6 +239,7 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_CVLAN, /* struct flow_dissector_key_flow_vlan */ FLOW_DISSECTOR_KEY_ENC_IP, /* struct flow_dissector_key_ip */ FLOW_DISSECTOR_KEY_ENC_OPTS, /* struct flow_dissector_key_enc_opts */ + FLOW_DISSECTOR_KEY_CT, /* struct flow_dissector_key_ct */ FLOW_DISSECTOR_KEY_MAX, }; @@ -254,6 +270,7 @@ struct flow_keys { #define FLOW_KEYS_HASH_START_FIELD basic struct flow_dissector_key_basic basic; struct flow_dissector_key_tags tags; + struct flow_dissector_key_ct ct; struct flow_dissector_key_vlan vlan; struct flow_dissector_key_vlan cvlan; struct flow_dissector_key_keyid keyid; diff --git a/include/uapi/linux/netfilter/xt_connlabel.h b/include/uapi/linux/netfilter/xt_connlabel.h index 2312f0ec07b2791ffaece0a95eebaefa727f14be..20a1c1fe79a7676c4b9f8727c393443f2d545784 100644 --- a/include/uapi/linux/netfilter/xt_connlabel.h +++ b/include/uapi/linux/netfilter/xt_connlabel.h @@ -1,4 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _NF_CONNTRACK_CONNLABEL_H +#define _NF_CONNTRACK_CONNLABEL_H + #include <linux/types.h> #define XT_CONNLABEL_MAXBIT 127 @@ -11,3 +14,5 @@ struct xt_connlabel_mtinfo { __u16 bit; __u16 options; }; + +#endif diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 2e8d91e54179c32b41ab53b9fa424fe1691acde0..73336466423aedff9a6fc4724f6c6efe44d5225a 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -26,6 +26,8 @@ #include <scsi/fc/fc_fcoe.h> #include <uapi/linux/batadv_packet.h> #include <linux/bpf.h> +#include <net/netfilter/nf_conntrack.h> +#include <net/netfilter/nf_conntrack_labels.h> static DEFINE_MUTEX(flow_dissector_mutex); @@ -798,6 +800,29 @@ bool __skb_flow_dissect(const struct sk_buff *skb, } rcu_read_unlock(); + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_CT)) { + struct flow_dissector_key_ct *key_ct; + enum ip_conntrack_info ctinfo; + struct nf_conn_labels *labels; + struct nf_conn *ct; + + ct = nf_ct_get(skb, &ctinfo); + if (ct) { + key_ct = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_CT, + target_container); + key_ct->zone = ct->zone.id; + key_ct->state = ctinfo; + key_ct->mark = ct->mark; + labels = nf_ct_labels_find(ct); + /* FIXME: should this be a new key then? */ + if (labels) + memcpy(key_ct->label, labels->bits, + sizeof(key_ct->label)); + } + } + if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { struct ethhdr *eth = eth_hdr(skb); -- 2.20.1