#ifndef _NET_FLOW_DISSECTOR_H
#define _NET_FLOW_DISSECTOR_H
#include <linux/types.h>
#include <linux/in6.h>
#include <linux/siphash.h>
#include <linux/string.h>
#include <uapi/linux/if_ether.h>
struct bpf_prog;
struct net;
struct sk_buff;
struct flow_dissector_key_control {
u16 thoff;
u16 addr_type;
u32 flags;
};
#define FLOW_DIS_IS_FRAGMENT BIT(0)
#define FLOW_DIS_FIRST_FRAG BIT(1)
#define FLOW_DIS_ENCAPSULATION BIT(2)
enum flow_dissect_ret {
FLOW_DISSECT_RET_OUT_GOOD,
FLOW_DISSECT_RET_OUT_BAD,
FLOW_DISSECT_RET_PROTO_AGAIN,
FLOW_DISSECT_RET_IPPROTO_AGAIN,
FLOW_DISSECT_RET_CONTINUE,
};
struct flow_dissector_key_basic {
__be16 n_proto;
u8 ip_proto;
u8 padding;
};
struct flow_dissector_key_tags {
u32 flow_label;
};
struct flow_dissector_key_vlan {
union {
struct {
u16 vlan_id:12,
vlan_dei:1,
vlan_priority:3;
};
__be16 vlan_tci;
};
__be16 vlan_tpid;
__be16 vlan_eth_type;
u16 padding;
};
struct flow_dissector_mpls_lse {
u32 mpls_ttl:8,
mpls_bos:1,
mpls_tc:3,
mpls_label:20;
};
#define FLOW_DIS_MPLS_MAX 7
struct flow_dissector_key_mpls {
struct flow_dissector_mpls_lse ls[FLOW_DIS_MPLS_MAX];
u8 used_lses;
};
static inline void dissector_set_mpls_lse(struct flow_dissector_key_mpls *mpls,
int lse_index)
{
mpls->used_lses |= 1 << lse_index;
}
#define FLOW_DIS_TUN_OPTS_MAX 255
struct flow_dissector_key_enc_opts {
u8 data[FLOW_DIS_TUN_OPTS_MAX];
u8 len;
__be16 dst_opt_type;
};
struct flow_dissector_key_keyid {
__be32 keyid;
};
struct flow_dissector_key_ipv4_addrs {
__be32 src;
__be32 dst;
};
struct flow_dissector_key_ipv6_addrs {
struct in6_addr src;
struct in6_addr dst;
};
struct flow_dissector_key_tipc {
__be32 key;
};
struct flow_dissector_key_addrs {
union {
struct flow_dissector_key_ipv4_addrs v4addrs;
struct flow_dissector_key_ipv6_addrs v6addrs;
struct flow_dissector_key_tipc tipckey;
};
};
struct flow_dissector_key_arp {
__u32 sip;
__u32 tip;
__u8 op;
unsigned char sha[ETH_ALEN];
unsigned char tha[ETH_ALEN];
};
struct flow_dissector_key_ports {
union {
__be32 ports;
struct {
__be16 src;
__be16 dst;
};
};
};
struct flow_dissector_key_ports_range {
union {
struct flow_dissector_key_ports tp;
struct {
struct flow_dissector_key_ports tp_min;
struct flow_dissector_key_ports tp_max;
};
};
};
struct flow_dissector_key_icmp {
struct {
u8 type;
u8 code;
};
u16 id;
};
struct flow_dissector_key_eth_addrs {
unsigned char dst[ETH_ALEN];
unsigned char src[ETH_ALEN];
};
struct flow_dissector_key_tcp {
__be16 flags;
};
struct flow_dissector_key_ip {
__u8 tos;
__u8 ttl;
};
struct flow_dissector_key_meta {
int ingress_ifindex;
u16 ingress_iftype;
u8 l2_miss;
};
struct flow_dissector_key_ct {
u16 ct_state;
u16 ct_zone;
u32 ct_mark;
u32 ct_labels[4];
};
struct flow_dissector_key_hash {
u32 hash;
};
struct flow_dissector_key_num_of_vlans {
u8 num_of_vlans;
};
struct flow_dissector_key_pppoe {
__be16 session_id;
__be16 ppp_proto;
__be16 type;
};
struct flow_dissector_key_l2tpv3 {
__be32 session_id;
};
struct flow_dissector_key_ipsec {
__be32 spi;
};
struct flow_dissector_key_cfm {
u8 mdl_ver;
u8 opcode;
};
#define FLOW_DIS_CFM_MDL_MASK GENMASK(7, 5)
#define FLOW_DIS_CFM_MDL_MAX 7
enum flow_dissector_key_id {
FLOW_DISSECTOR_KEY_CONTROL,
FLOW_DISSECTOR_KEY_BASIC,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
FLOW_DISSECTOR_KEY_PORTS,
FLOW_DISSECTOR_KEY_PORTS_RANGE,
FLOW_DISSECTOR_KEY_ICMP,
FLOW_DISSECTOR_KEY_ETH_ADDRS,
FLOW_DISSECTOR_KEY_TIPC,
FLOW_DISSECTOR_KEY_ARP,
FLOW_DISSECTOR_KEY_VLAN,
FLOW_DISSECTOR_KEY_FLOW_LABEL,
FLOW_DISSECTOR_KEY_GRE_KEYID,
FLOW_DISSECTOR_KEY_MPLS_ENTROPY,
FLOW_DISSECTOR_KEY_ENC_KEYID,
FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS,
FLOW_DISSECTOR_KEY_ENC_CONTROL,
FLOW_DISSECTOR_KEY_ENC_PORTS,
FLOW_DISSECTOR_KEY_MPLS,
FLOW_DISSECTOR_KEY_TCP,
FLOW_DISSECTOR_KEY_IP,
FLOW_DISSECTOR_KEY_CVLAN,
FLOW_DISSECTOR_KEY_ENC_IP,
FLOW_DISSECTOR_KEY_ENC_OPTS,
FLOW_DISSECTOR_KEY_META,
FLOW_DISSECTOR_KEY_CT,
FLOW_DISSECTOR_KEY_HASH,
FLOW_DISSECTOR_KEY_NUM_OF_VLANS,
FLOW_DISSECTOR_KEY_PPPOE,
FLOW_DISSECTOR_KEY_L2TPV3,
FLOW_DISSECTOR_KEY_CFM,
FLOW_DISSECTOR_KEY_IPSEC,
FLOW_DISSECTOR_KEY_MAX,
};
#define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0)
#define FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL BIT(1)
#define FLOW_DISSECTOR_F_STOP_AT_ENCAP BIT(2)
#define FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP BIT(3)
struct flow_dissector_key {
enum flow_dissector_key_id key_id;
size_t offset;
};
struct flow_dissector {
unsigned long long used_keys;
unsigned short int offset[FLOW_DISSECTOR_KEY_MAX];
};
struct flow_keys_basic {
struct flow_dissector_key_control control;
struct flow_dissector_key_basic basic;
};
struct flow_keys {
struct flow_dissector_key_control control;
#define FLOW_KEYS_HASH_START_FIELD basic
struct flow_dissector_key_basic basic __aligned(SIPHASH_ALIGNMENT);
struct flow_dissector_key_tags tags;
struct flow_dissector_key_vlan vlan;
struct flow_dissector_key_vlan cvlan;
struct flow_dissector_key_keyid keyid;
struct flow_dissector_key_ports ports;
struct flow_dissector_key_icmp icmp;
struct flow_dissector_key_addrs addrs;
};
#define FLOW_KEYS_HASH_OFFSET \
offsetof(struct flow_keys, FLOW_KEYS_HASH_START_FIELD)
__be32 flow_get_u32_src(const struct flow_keys *flow);
__be32 flow_get_u32_dst(const struct flow_keys *flow);
extern struct flow_dissector flow_keys_dissector;
extern struct flow_dissector flow_keys_basic_dissector;
#define FLOW_KEYS_DIGEST_LEN 16
struct flow_keys_digest {
u8 data[FLOW_KEYS_DIGEST_LEN];
};
void make_flow_keys_digest(struct flow_keys_digest *digest,
const struct flow_keys *flow);
static inline bool flow_keys_have_l4(const struct flow_keys *keys)
{
return (keys->ports.ports || keys->tags.flow_label);
}
u32 flow_hash_from_keys(struct flow_keys *keys);
void skb_flow_get_icmp_tci(const struct sk_buff *skb,
struct flow_dissector_key_icmp *key_icmp,
const void *data, int thoff, int hlen);
static inline bool dissector_uses_key(const struct flow_dissector *flow_dissector,
enum flow_dissector_key_id key_id)
{
return flow_dissector->used_keys & (1ULL << key_id);
}
static inline void *skb_flow_dissector_target(struct flow_dissector *flow_dissector,
enum flow_dissector_key_id key_id,
void *target_container)
{
return ((char *)target_container) + flow_dissector->offset[key_id];
}
struct bpf_flow_dissector {
struct bpf_flow_keys *flow_keys;
const struct sk_buff *skb;
const void *data;
const void *data_end;
};
static inline void
flow_dissector_init_keys(struct flow_dissector_key_control *key_control,
struct flow_dissector_key_basic *key_basic)
{
memset(key_control, 0, sizeof(*key_control));
memset(key_basic, 0, sizeof(*key_basic));
}
#ifdef CONFIG_BPF_SYSCALL
int flow_dissector_bpf_prog_attach_check(struct net *net,
struct bpf_prog *prog);
#endif /* CONFIG_BPF_SYSCALL */
#endif