From: wenxu <wenxu@xxxxxxxxx> With nf_conntrack_bridge function. The bridge family can do conntrack it self. The flow offload function based on the conntrack. This patch a bridge family operation in nf_flow_table_ip. Signed-off-by: wenxu <wenxu@xxxxxxxxx> --- v7: rebase with upstream fix net/netfilter/nf_flow_table_ip.c | 64 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c index 1c598af..6336f32 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -267,23 +267,59 @@ static int nf_flow_ipv4_xmit(struct flow_offload *flow, struct sk_buff *skb, return NF_STOLEN; } +static int nf_flow_bridge_xmit(struct flow_offload *flow, struct sk_buff *skb, + enum flow_offload_tuple_dir dir) +{ + struct net_device *outdev; + u16 vlan_tag, vlan_proto; + + vlan_tag = flow->tuplehash[dir].tuple.dst.dst_port.dst_vlan_tag; + vlan_proto = flow->tuplehash[dir].tuple.dst.dst_port.vlan_proto; + outdev = flow->tuplehash[dir].tuple.dst.dst_port.dev; + skb->dev = outdev; + + if (vlan_tag) + __vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tag); + else + __vlan_hwaccel_clear_tag(skb); + + skb_push(skb, ETH_HLEN); + if (!is_skb_forwardable(skb->dev, skb)) + goto drop; + + dev_queue_xmit(skb); + return NF_STOLEN; + +drop: + kfree_skb(skb); + return NF_STOLEN; +} + unsigned int nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { struct flow_offload_tuple_rhash *tuplehash; struct nf_flowtable *flow_table = priv; + int family = flow_table->type->family; struct flow_offload_tuple tuple = {}; enum flow_offload_tuple_dir dir; struct flow_offload *flow; unsigned int thoff; + int ret; if (skb->protocol != htons(ETH_P_IP)) return NF_ACCEPT; + if (family != NFPROTO_BRIDGE && family != NFPROTO_IPV4) + return NF_ACCEPT; + if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0) return NF_ACCEPT; + if (family == NFPROTO_BRIDGE && skb_vlan_tag_present(skb)) + tuple.vlan_tag = skb_vlan_tag_get_id(skb); + tuplehash = flow_offload_lookup(flow_table, &tuple); if (tuplehash == NULL) return NF_ACCEPT; @@ -305,8 +341,16 @@ static int nf_flow_ipv4_xmit(struct flow_offload *flow, struct sk_buff *skb, return NF_DROP; flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; + switch (family) { + case NFPROTO_IPV4: + ret = nf_flow_ipv4_xmit(flow, skb, state, dir); + break; + case NFPROTO_BRIDGE: + ret = nf_flow_bridge_xmit(flow, skb, dir); + break; + } - return nf_flow_ipv4_xmit(flow, skb, state, dir); + return ret; } EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook); @@ -511,16 +555,24 @@ static int nf_flow_ipv6_xmit(struct flow_offload *flow, struct sk_buff *skb, { struct flow_offload_tuple_rhash *tuplehash; struct nf_flowtable *flow_table = priv; + int family = flow_table->type->family; struct flow_offload_tuple tuple = {}; enum flow_offload_tuple_dir dir; struct flow_offload *flow; + int ret; if (skb->protocol != htons(ETH_P_IPV6)) return NF_ACCEPT; + if (family != NFPROTO_BRIDGE && family != NFPROTO_IPV6) + return NF_ACCEPT; + if (nf_flow_tuple_ipv6(skb, state->in, &tuple) < 0) return NF_ACCEPT; + if (family == NFPROTO_BRIDGE && skb_vlan_tag_present(skb)) + tuple.vlan_tag = skb_vlan_tag_get_id(skb); + tuplehash = flow_offload_lookup(flow_table, &tuple); if (tuplehash == NULL) return NF_ACCEPT; @@ -542,7 +594,15 @@ static int nf_flow_ipv6_xmit(struct flow_offload *flow, struct sk_buff *skb, return NF_DROP; flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; + switch (family) { + case NFPROTO_IPV6: + ret = nf_flow_ipv6_xmit(flow, skb, state, dir); + break; + case NFPROTO_BRIDGE: + ret = nf_flow_bridge_xmit(flow, skb, dir); + break; + } - return nf_flow_ipv6_xmit(flow, skb, state, dir); + return ret; } EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook); -- 1.8.3.1