Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

1) Revert CHECKSUM_UNNECESSARY for UDP packet from conntrack.

2) Reject unsupported families when creating tables, from Phil Sutter.

3) GRE support for the flowtable, from Toshiaki Makita.

4) Add GRE offload support for act_ct, also from Toshiaki.

5) Update mlx5 driver to support for GRE flowtable offload,
   from Toshiaki Makita.

6) Oneliner to clean up incorrect indentation in nf_conntrack_bridge,
   from Jiapeng Chong.

* git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next:
  netfilter: bridge: clean up some inconsistent indenting
  net/mlx5: Support GRE conntrack offload
  act_ct: Support GRE offload
  netfilter: flowtable: Support GRE
  netfilter: nf_tables: Reject tables of unsupported family
  Revert "netfilter: conntrack: mark UDP zero checksum as CHECKSUM_UNNECESSARY"
====================

Link: https://lore.kernel.org/r/20220315091513.66544-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2022-03-15 11:52:25 -07:00
commit abe2fec8ee
9 changed files with 223 additions and 53 deletions

View File

@ -260,6 +260,7 @@ mlx5_tc_ct_rule_to_tuple(struct mlx5_ct_tuple *tuple, struct flow_rule *rule)
return -EOPNOTSUPP;
}
} else {
if (tuple->ip_proto != IPPROTO_GRE)
return -EOPNOTSUPP;
}
@ -809,7 +810,11 @@ mlx5_tc_ct_entry_add_rule(struct mlx5_tc_ct_priv *ct_priv,
attr->dest_chain = 0;
attr->dest_ft = mlx5e_tc_post_act_get_ft(ct_priv->post_act);
attr->ft = nat ? ct_priv->ct_nat : ct_priv->ct;
if (entry->tuple.ip_proto == IPPROTO_TCP ||
entry->tuple.ip_proto == IPPROTO_UDP)
attr->outer_match_level = MLX5_MATCH_L4;
else
attr->outer_match_level = MLX5_MATCH_L3;
attr->counter = entry->counter->counter;
attr->flags |= MLX5_ATTR_FLAG_NO_IN_PORT;
if (ct_priv->ns_type == MLX5_FLOW_NAMESPACE_FDB)
@ -1226,16 +1231,20 @@ mlx5_tc_ct_skb_to_tuple(struct sk_buff *skb, struct mlx5_ct_tuple *tuple,
struct flow_keys flow_keys;
skb_reset_network_header(skb);
skb_flow_dissect_flow_keys(skb, &flow_keys, 0);
skb_flow_dissect_flow_keys(skb, &flow_keys, FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP);
tuple->zone = zone;
if (flow_keys.basic.ip_proto != IPPROTO_TCP &&
flow_keys.basic.ip_proto != IPPROTO_UDP)
flow_keys.basic.ip_proto != IPPROTO_UDP &&
flow_keys.basic.ip_proto != IPPROTO_GRE)
return false;
if (flow_keys.basic.ip_proto == IPPROTO_TCP ||
flow_keys.basic.ip_proto == IPPROTO_UDP) {
tuple->port.src = flow_keys.ports.src;
tuple->port.dst = flow_keys.ports.dst;
}
tuple->n_proto = flow_keys.basic.n_proto;
tuple->ip_proto = flow_keys.basic.ip_proto;

View File

@ -63,10 +63,8 @@ static bool udp_error(struct sk_buff *skb,
}
/* Packet with no checksum */
if (!hdr->check) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (!hdr->check)
return false;
}
/* Checksum invalid? Ignore.
* We skip checking packets on the outgoing path

View File

@ -39,8 +39,14 @@ flow_offload_fill_dir(struct flow_offload *flow,
ft->l3proto = ctt->src.l3num;
ft->l4proto = ctt->dst.protonum;
switch (ctt->dst.protonum) {
case IPPROTO_TCP:
case IPPROTO_UDP:
ft->src_port = ctt->src.u.tcp.port;
ft->dst_port = ctt->dst.u.tcp.port;
break;
}
}
struct flow_offload *flow_offload_alloc(struct nf_conn *ct)

View File

@ -172,6 +172,7 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
struct flow_ports *ports;
unsigned int thoff;
struct iphdr *iph;
u8 ipproto;
if (!pskb_may_pull(skb, sizeof(*iph) + offset))
return -1;
@ -185,13 +186,19 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
thoff += offset;
switch (iph->protocol) {
ipproto = iph->protocol;
switch (ipproto) {
case IPPROTO_TCP:
*hdrsize = sizeof(struct tcphdr);
break;
case IPPROTO_UDP:
*hdrsize = sizeof(struct udphdr);
break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE:
*hdrsize = sizeof(struct gre_base_hdr);
break;
#endif
default:
return -1;
}
@ -202,15 +209,29 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
if (!pskb_may_pull(skb, thoff + *hdrsize))
return -1;
iph = (struct iphdr *)(skb_network_header(skb) + offset);
switch (ipproto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
break;
case IPPROTO_GRE: {
struct gre_base_hdr *greh;
greh = (struct gre_base_hdr *)(skb_network_header(skb) + thoff);
if ((greh->flags & GRE_VERSION) != GRE_VERSION_0)
return -1;
break;
}
}
iph = (struct iphdr *)(skb_network_header(skb) + offset);
tuple->src_v4.s_addr = iph->saddr;
tuple->dst_v4.s_addr = iph->daddr;
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
tuple->l3proto = AF_INET;
tuple->l4proto = iph->protocol;
tuple->l4proto = ipproto;
tuple->iifidx = dev->ifindex;
nf_flow_tuple_encap(skb, tuple);
@ -521,6 +542,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
struct flow_ports *ports;
struct ipv6hdr *ip6h;
unsigned int thoff;
u8 nexthdr;
thoff = sizeof(*ip6h) + offset;
if (!pskb_may_pull(skb, thoff))
@ -528,13 +550,19 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
switch (ip6h->nexthdr) {
nexthdr = ip6h->nexthdr;
switch (nexthdr) {
case IPPROTO_TCP:
*hdrsize = sizeof(struct tcphdr);
break;
case IPPROTO_UDP:
*hdrsize = sizeof(struct udphdr);
break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE:
*hdrsize = sizeof(struct gre_base_hdr);
break;
#endif
default:
return -1;
}
@ -545,15 +573,29 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
if (!pskb_may_pull(skb, thoff + *hdrsize))
return -1;
ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
switch (nexthdr) {
case IPPROTO_TCP:
case IPPROTO_UDP:
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
break;
case IPPROTO_GRE: {
struct gre_base_hdr *greh;
greh = (struct gre_base_hdr *)(skb_network_header(skb) + thoff);
if ((greh->flags & GRE_VERSION) != GRE_VERSION_0)
return -1;
break;
}
}
ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
tuple->src_v6 = ip6h->saddr;
tuple->dst_v6 = ip6h->daddr;
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
tuple->l3proto = AF_INET6;
tuple->l4proto = ip6h->nexthdr;
tuple->l4proto = nexthdr;
tuple->iifidx = dev->ifindex;
nf_flow_tuple_encap(skb, tuple);

View File

@ -174,6 +174,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP);
break;
case IPPROTO_UDP:
case IPPROTO_GRE:
break;
default:
return -EOPNOTSUPP;
@ -182,15 +183,22 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
key->basic.ip_proto = tuple->l4proto;
mask->basic.ip_proto = 0xff;
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_META) |
BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_BASIC);
switch (tuple->l4proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
key->tp.src = tuple->src_port;
mask->tp.src = 0xffff;
key->tp.dst = tuple->dst_port;
mask->tp.dst = 0xffff;
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_META) |
BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_BASIC) |
BIT(FLOW_DISSECTOR_KEY_PORTS);
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS);
break;
}
return 0;
}

View File

@ -1072,6 +1072,30 @@ static int nft_objname_hash_cmp(struct rhashtable_compare_arg *arg,
return strcmp(obj->key.name, k->name);
}
static bool nft_supported_family(u8 family)
{
return false
#ifdef CONFIG_NF_TABLES_INET
|| family == NFPROTO_INET
#endif
#ifdef CONFIG_NF_TABLES_IPV4
|| family == NFPROTO_IPV4
#endif
#ifdef CONFIG_NF_TABLES_ARP
|| family == NFPROTO_ARP
#endif
#ifdef CONFIG_NF_TABLES_NETDEV
|| family == NFPROTO_NETDEV
#endif
#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
|| family == NFPROTO_BRIDGE
#endif
#ifdef CONFIG_NF_TABLES_IPV6
|| family == NFPROTO_IPV6
#endif
;
}
static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const nla[])
{
@ -1086,6 +1110,9 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
u32 flags = 0;
int err;
if (!nft_supported_family(family))
return -EOPNOTSUPP;
lockdep_assert_held(&nft_net->commit_mutex);
attr = nla[NFTA_TABLE_NAME];
table = nft_table_lookup(net, attr, family, genmask,

View File

@ -298,6 +298,19 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
break;
case IPPROTO_UDP:
break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE: {
struct nf_conntrack_tuple *tuple;
if (ct->status & IPS_NAT_MASK)
goto out;
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
/* No support for GRE v1 */
if (tuple->src.u.gre.key || tuple->dst.u.gre.key)
goto out;
break;
}
#endif
default:
goto out;
}

View File

@ -420,6 +420,19 @@ static void tcf_ct_flow_table_process_conn(struct tcf_ct_flow_table *ct_ft,
break;
case IPPROTO_UDP:
break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE: {
struct nf_conntrack_tuple *tuple;
if (ct->status & IPS_NAT_MASK)
return;
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
/* No support for GRE v1 */
if (tuple->src.u.gre.key || tuple->dst.u.gre.key)
return;
break;
}
#endif
default:
return;
}
@ -439,6 +452,8 @@ tcf_ct_flow_table_fill_tuple_ipv4(struct sk_buff *skb,
struct flow_ports *ports;
unsigned int thoff;
struct iphdr *iph;
size_t hdrsize;
u8 ipproto;
if (!pskb_network_may_pull(skb, sizeof(*iph)))
return false;
@ -450,29 +465,54 @@ tcf_ct_flow_table_fill_tuple_ipv4(struct sk_buff *skb,
unlikely(thoff != sizeof(struct iphdr)))
return false;
if (iph->protocol != IPPROTO_TCP &&
iph->protocol != IPPROTO_UDP)
ipproto = iph->protocol;
switch (ipproto) {
case IPPROTO_TCP:
hdrsize = sizeof(struct tcphdr);
break;
case IPPROTO_UDP:
hdrsize = sizeof(*ports);
break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE:
hdrsize = sizeof(struct gre_base_hdr);
break;
#endif
default:
return false;
}
if (iph->ttl <= 1)
return false;
if (!pskb_network_may_pull(skb, iph->protocol == IPPROTO_TCP ?
thoff + sizeof(struct tcphdr) :
thoff + sizeof(*ports)))
if (!pskb_network_may_pull(skb, thoff + hdrsize))
return false;
iph = ip_hdr(skb);
if (iph->protocol == IPPROTO_TCP)
switch (ipproto) {
case IPPROTO_TCP:
*tcph = (void *)(skb_network_header(skb) + thoff);
fallthrough;
case IPPROTO_UDP:
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_v4.s_addr = iph->saddr;
tuple->dst_v4.s_addr = iph->daddr;
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
break;
case IPPROTO_GRE: {
struct gre_base_hdr *greh;
greh = (struct gre_base_hdr *)(skb_network_header(skb) + thoff);
if ((greh->flags & GRE_VERSION) != GRE_VERSION_0)
return false;
break;
}
}
iph = ip_hdr(skb);
tuple->src_v4.s_addr = iph->saddr;
tuple->dst_v4.s_addr = iph->daddr;
tuple->l3proto = AF_INET;
tuple->l4proto = iph->protocol;
tuple->l4proto = ipproto;
return true;
}
@ -485,36 +525,63 @@ tcf_ct_flow_table_fill_tuple_ipv6(struct sk_buff *skb,
struct flow_ports *ports;
struct ipv6hdr *ip6h;
unsigned int thoff;
size_t hdrsize;
u8 nexthdr;
if (!pskb_network_may_pull(skb, sizeof(*ip6h)))
return false;
ip6h = ipv6_hdr(skb);
thoff = sizeof(*ip6h);
if (ip6h->nexthdr != IPPROTO_TCP &&
ip6h->nexthdr != IPPROTO_UDP)
return false;
nexthdr = ip6h->nexthdr;
switch (nexthdr) {
case IPPROTO_TCP:
hdrsize = sizeof(struct tcphdr);
break;
case IPPROTO_UDP:
hdrsize = sizeof(*ports);
break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE:
hdrsize = sizeof(struct gre_base_hdr);
break;
#endif
default:
return -1;
}
if (ip6h->hop_limit <= 1)
return false;
thoff = sizeof(*ip6h);
if (!pskb_network_may_pull(skb, ip6h->nexthdr == IPPROTO_TCP ?
thoff + sizeof(struct tcphdr) :
thoff + sizeof(*ports)))
if (!pskb_network_may_pull(skb, thoff + hdrsize))
return false;
ip6h = ipv6_hdr(skb);
if (ip6h->nexthdr == IPPROTO_TCP)
switch (nexthdr) {
case IPPROTO_TCP:
*tcph = (void *)(skb_network_header(skb) + thoff);
fallthrough;
case IPPROTO_UDP:
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_v6 = ip6h->saddr;
tuple->dst_v6 = ip6h->daddr;
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
break;
case IPPROTO_GRE: {
struct gre_base_hdr *greh;
greh = (struct gre_base_hdr *)(skb_network_header(skb) + thoff);
if ((greh->flags & GRE_VERSION) != GRE_VERSION_0)
return false;
break;
}
}
ip6h = ipv6_hdr(skb);
tuple->src_v6 = ip6h->saddr;
tuple->dst_v6 = ip6h->daddr;
tuple->l3proto = AF_INET6;
tuple->l4proto = ip6h->nexthdr;
tuple->l4proto = nexthdr;
return true;
}