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> --- net/netfilter/nf_flow_table_ip.c | 59 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c index 88b4d59..d88dafb 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -233,12 +233,40 @@ static void nf_flow_ipv4_xmit(struct flow_offload *flow, struct sk_buff *skb, neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb); } +static void 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; + +drop: + kfree_skb(skb); +} + 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; @@ -247,9 +275,15 @@ static void nf_flow_ipv4_xmit(struct flow_offload *flow, struct sk_buff *skb, 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; @@ -271,7 +305,14 @@ static void nf_flow_ipv4_xmit(struct flow_offload *flow, struct sk_buff *skb, return NF_DROP; flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; - nf_flow_ipv4_xmit(flow, skb, dir); + switch (family) { + case NFPROTO_IPV4: + nf_flow_ipv4_xmit(flow, skb, dir); + break; + case NFPROTO_BRIDGE: + nf_flow_bridge_xmit(flow, skb, dir); + break; + } return NF_STOLEN; } @@ -463,6 +504,7 @@ static void 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; @@ -470,9 +512,15 @@ static void nf_flow_ipv6_xmit(struct flow_offload *flow, struct sk_buff *skb, 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; @@ -494,7 +542,14 @@ static void nf_flow_ipv6_xmit(struct flow_offload *flow, struct sk_buff *skb, return NF_DROP; flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; - nf_flow_ipv6_xmit(flow, skb, dir); + switch (family) { + case NFPROTO_IPV6: + nf_flow_ipv6_xmit(flow, skb, dir); + break; + case NFPROTO_BRIDGE: + nf_flow_bridge_xmit(flow, skb, dir); + break; + } return NF_STOLEN; } -- 1.8.3.1