--- zzzz-none-000/linux-5.4.213/net/bridge/br_device.c 2022-09-15 10:04:56.000000000 +0000 +++ alder-5690pro-762/linux-5.4.213/net/bridge/br_device.c 2024-08-14 09:02:13.000000000 +0000 @@ -14,6 +14,10 @@ #include #include #include +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) +#include +#include +#endif #include #include "br_private.h" @@ -34,6 +38,8 @@ const struct nf_br_ops *nf_ops; const unsigned char *dest; u16 vid = 0; + struct net_bridge_port *pdst; + br_get_dst_hook_t *get_dst_hook; rcu_read_lock(); nf_ops = rcu_dereference(nf_br_ops); @@ -75,10 +81,17 @@ br_do_suppress_nd(skb, br, vid, NULL, msg); } + get_dst_hook = rcu_dereference(br_get_dst_hook); + dest = eth_hdr(skb)->h_dest; if (is_broadcast_ether_addr(dest)) { br_flood(br, skb, BR_PKT_BROADCAST, false, true); } else if (is_multicast_ether_addr(dest)) { + br_multicast_handle_hook_t *multicast_handle_hook = + rcu_dereference(br_multicast_handle_hook); + if (!__br_get(multicast_handle_hook, true, NULL, skb)) + goto out; + if (unlikely(netpoll_tx_running(dev))) { br_flood(br, skb, BR_PKT_MULTICAST, false, true); goto out; @@ -94,11 +107,21 @@ br_multicast_flood(mdst, skb, false, true); else br_flood(br, skb, BR_PKT_MULTICAST, false, true); - } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) { - br_forward(dst->dst, skb, false, true); } else { - br_flood(br, skb, BR_PKT_UNICAST, false, true); + pdst = __br_get(get_dst_hook, NULL, NULL, &skb); + if (pdst) { + if (!skb) + goto out; + br_forward(pdst, skb, false, true); + } else { + dst = br_fdb_find_rcu(br, dest, vid); + if (dst) + br_forward(dst->dst, skb, false, true); + else + br_flood(br, skb, BR_PKT_UNICAST, false, true); + } } + out: rcu_read_unlock(); return NETDEV_TX_OK; @@ -380,6 +403,28 @@ .get_link = ethtool_op_get_link, }; +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) +static int br_flow_offload_check(struct flow_offload_hw_path *path) +{ + struct net_device *dev = path->dev; + struct net_bridge *br = netdev_priv(dev); + struct net_bridge_fdb_entry *dst; + + if (!(path->flags & FLOW_OFFLOAD_PATH_ETHERNET)) + return -EINVAL; + + dst = br_fdb_find_rcu(br, path->eth_dest, path->vlan_id); + if (!dst || !dst->dst) + return -ENOENT; + + path->dev = dst->dst->dev; + if (path->dev->netdev_ops->ndo_flow_offload_check) + return path->dev->netdev_ops->ndo_flow_offload_check(path); + + return 0; +} +#endif /* CONFIG_NF_FLOW_TABLE */ + static const struct net_device_ops br_netdev_ops = { .ndo_open = br_dev_open, .ndo_stop = br_dev_stop, @@ -408,6 +453,9 @@ .ndo_bridge_setlink = br_setlink, .ndo_bridge_dellink = br_dellink, .ndo_features_check = passthru_features_check, +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) + .ndo_flow_offload_check = br_flow_offload_check, +#endif }; static struct device_type br_type = { @@ -455,6 +503,8 @@ br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME; dev->max_mtu = ETH_MAX_MTU; + br->fdb_max_learned = CONFIG_BRIDGE_DEFAULT_FDB_MAX_LEARNED; + br_netfilter_rtable_init(br); br_stp_timer_init(br); br_multicast_init(br);