在 2019/11/21 17:54, wenxu@xxxxxxxxx 写道: > From: wenxu <wenxu@xxxxxxxxx> > > This patch support both ipv4 and ipv6 tunnel_id, tunnel_src and > tunnel_dst match for flowtable offload > > Signed-off-by: wenxu <wenxu@xxxxxxxxx> > --- > v2: add ecn_control to match outer addr > > net/netfilter/nf_flow_table_offload.c | 67 +++++++++++++++++++++++++++++++++-- > 1 file changed, 65 insertions(+), 2 deletions(-) > > diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c > index 653866f..656095c 100644 > --- a/net/netfilter/nf_flow_table_offload.c > +++ b/net/netfilter/nf_flow_table_offload.c > @@ -26,10 +26,16 @@ struct flow_offload_work { > > struct nf_flow_key { > struct flow_dissector_key_control control; > + struct flow_dissector_key_control enc_control; > struct flow_dissector_key_basic basic; > union { > struct flow_dissector_key_ipv4_addrs ipv4; > }; > + struct flow_dissector_key_keyid enc_key_id; > + union { > + struct flow_dissector_key_ipv4_addrs enc_ipv4; > + struct flow_dissector_key_ipv6_addrs enc_ipv6; > + }; > struct flow_dissector_key_tcp tcp; > struct flow_dissector_key_ports tp; > } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ > @@ -49,11 +55,61 @@ struct nf_flow_rule { > (__match)->dissector.offset[__type] = \ > offsetof(struct nf_flow_key, __field) > > +static void nf_flow_rule_lwt_match(struct nf_flow_match *match, > + struct ip_tunnel_info *tun_info) > +{ > + struct nf_flow_key *mask = &match->mask; > + struct nf_flow_key *key = &match->key; > + unsigned int enc_keys; > + > + if (!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX)) > + return; > + > + NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_ENC_CONTROL, enc_control); > + NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id); > + key->enc_key_id.keyid = tunnel_id_to_key32(tun_info->key.tun_id); > + mask->enc_key_id.keyid = 0xffffffff; > + enc_keys = BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | > + BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL); > + > + if (ip_tunnel_info_af(tun_info) == AF_INET) { > + NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, > + enc_ipv4); > + key->enc_ipv4.src = tun_info->key.u.ipv4.dst; > + key->enc_ipv4.dst = tun_info->key.u.ipv4.src; > + if (key->enc_ipv4.src) > + mask->enc_ipv4.src = 0xffffffff; > + if (key->enc_ipv4.dst) > + mask->enc_ipv4.dst = 0xffffffff; > + enc_keys |= BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS); > + key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; > + } else { > + memcpy(&key->enc_ipv6.src, &tun_info->key.u.ipv6.dst, > + sizeof(struct in6_addr)); > + memcpy(&key->enc_ipv6.dst, &tun_info->key.u.ipv6.src, > + sizeof(struct in6_addr)); > + if (memcmp(&key->enc_ipv6.src, &in6addr_any, > + sizeof(struct in6_addr))) > + memset(&key->enc_ipv6.src, 0xff, > + sizeof(struct in6_addr)); > + if (memcmp(&key->enc_ipv6.dst, &in6addr_any, > + sizeof(struct in6_addr))) > + memset(&key->enc_ipv6.dst, 0xff, > + sizeof(struct in6_addr)); > + enc_keys |= BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS); > + key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; > + } > + > + match->dissector.used_keys |= enc_keys; > +} > + > static int nf_flow_rule_match(struct nf_flow_match *match, > - const struct flow_offload_tuple *tuple) > + const struct flow_offload_tuple *tuple, > + struct dst_entry *other_dst) > { > struct nf_flow_key *mask = &match->mask; > struct nf_flow_key *key = &match->key; > + struct ip_tunnel_info *tun_info; > > NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_CONTROL, control); > NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_BASIC, basic); > @@ -61,6 +117,11 @@ static int nf_flow_rule_match(struct nf_flow_match *match, > NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_TCP, tcp); > NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_PORTS, tp); > > + if (other_dst->lwtstate) { > + tun_info = lwt_tun_info(other_dst->lwtstate); > + nf_flow_rule_lwt_match(match, tun_info); > + } > + > switch (tuple->l3proto) { > case AF_INET: > key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; > @@ -468,6 +529,7 @@ int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow, > const struct flow_offload *flow = offload->flow; > const struct flow_offload_tuple *tuple; > struct nf_flow_rule *flow_rule; > + struct dst_entry *other_dst; > int err = -ENOMEM; > > flow_rule = kzalloc(sizeof(*flow_rule), GFP_KERNEL); > @@ -483,7 +545,8 @@ int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow, > flow_rule->rule->match.key = &flow_rule->match.key; > > tuple = &flow->tuplehash[dir].tuple; > - err = nf_flow_rule_match(&flow_rule->match, tuple); > + other_dst = flow->tuplehash[!dir].tuple.dst_cache; > + err = nf_flow_rule_match(&flow_rule->match, tuple, other_dst); > if (err < 0) > goto err_flow_match; >