600-bridge_offload.patch 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. From: Felix Fietkau <[email protected]>
  2. Subject: bridge: Add a fast path for the bridge code
  3. This caches flows between MAC addresses on separate ports, including their VLAN
  4. in order to bypass the normal bridge forwarding code.
  5. In my test on MT7622, this reduces LAN->WLAN bridging CPU usage by 6-10%,
  6. potentially even more on weaker platforms
  7. Submitted-by: Felix Fietkau <[email protected]>
  8. ---
  9. include/linux/if_bridge.h | 1 +
  10. net/bridge/Makefile | 2 +-
  11. net/bridge/br.c | 8 +++
  12. net/bridge/br_device.c | 7 +++
  13. net/bridge/br_forward.c | 3 ++
  14. net/bridge/br_if.c | 7 ++-
  15. net/bridge/br_input.c | 5 ++
  16. net/bridge/br_offload.c | 436 +++++++++++++++
  17. net/bridge/br_private.h | 22 ++++-
  18. net/bridge/br_private_offload.h | 21 +++++
  19. net/bridge/br_stp.c | 3 +
  20. net/bridge/br_sysfs_br.c | 35 ++++++
  21. net/bridge/br_sysfs_if.c | 2 +
  22. net/bridge/br_vlan_tunnel.c | 3 ++
  23. 14 files changed, 552 insertions(+), 3 deletions(-)
  24. create mode 100644 net/bridge/br_offload.c
  25. create mode 100644 net/bridge/br_private_offload.h
  26. --- a/include/linux/if_bridge.h
  27. +++ b/include/linux/if_bridge.h
  28. @@ -57,6 +57,7 @@ struct br_ip_list {
  29. #define BR_MRP_LOST_CONT BIT(18)
  30. #define BR_MRP_LOST_IN_CONT BIT(19)
  31. #define BR_BPDU_FILTER BIT(20)
  32. +#define BR_OFFLOAD BIT(21)
  33. #define BR_DEFAULT_AGEING_TIME (300 * HZ)
  34. --- a/net/bridge/Makefile
  35. +++ b/net/bridge/Makefile
  36. @@ -5,7 +5,7 @@
  37. obj-$(CONFIG_BRIDGE) += bridge.o
  38. -bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
  39. +bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o br_offload.o \
  40. br_ioctl.o br_stp.o br_stp_bpdu.o \
  41. br_stp_if.o br_stp_timer.o br_netlink.o \
  42. br_netlink_tunnel.o br_arp_nd_proxy.o
  43. --- a/net/bridge/br.c
  44. +++ b/net/bridge/br.c
  45. @@ -18,6 +18,7 @@
  46. #include <net/switchdev.h>
  47. #include "br_private.h"
  48. +#include "br_private_offload.h"
  49. /*
  50. * Handle changes in state of network devices enslaved to a bridge.
  51. @@ -332,6 +333,10 @@ static int __init br_init(void)
  52. if (err)
  53. goto err_out;
  54. + err = br_offload_init();
  55. + if (err)
  56. + goto err_out0;
  57. +
  58. err = register_pernet_subsys(&br_net_ops);
  59. if (err)
  60. goto err_out1;
  61. @@ -375,6 +380,8 @@ err_out3:
  62. err_out2:
  63. unregister_pernet_subsys(&br_net_ops);
  64. err_out1:
  65. + br_offload_fini();
  66. +err_out0:
  67. br_fdb_fini();
  68. err_out:
  69. stp_proto_unregister(&br_stp_proto);
  70. @@ -396,6 +403,7 @@ static void __exit br_deinit(void)
  71. #if IS_ENABLED(CONFIG_ATM_LANE)
  72. br_fdb_test_addr_hook = NULL;
  73. #endif
  74. + br_offload_fini();
  75. br_fdb_fini();
  76. }
  77. --- a/net/bridge/br_device.c
  78. +++ b/net/bridge/br_device.c
  79. @@ -529,6 +529,8 @@ void br_dev_setup(struct net_device *dev
  80. br->bridge_hello_time = br->hello_time = 2 * HZ;
  81. br->bridge_forward_delay = br->forward_delay = 15 * HZ;
  82. br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
  83. + br->offload_cache_size = 128;
  84. + br->offload_cache_reserved = 8;
  85. dev->max_mtu = ETH_MAX_MTU;
  86. br_netfilter_rtable_init(br);
  87. --- a/net/bridge/br_fdb.c
  88. +++ b/net/bridge/br_fdb.c
  89. @@ -23,6 +23,7 @@
  90. #include <net/switchdev.h>
  91. #include <trace/events/bridge.h>
  92. #include "br_private.h"
  93. +#include "br_private_offload.h"
  94. static const struct rhashtable_params br_fdb_rht_params = {
  95. .head_offset = offsetof(struct net_bridge_fdb_entry, rhnode),
  96. @@ -513,6 +514,8 @@ static struct net_bridge_fdb_entry *fdb_
  97. fdb->key.vlan_id = vid;
  98. fdb->flags = flags;
  99. fdb->updated = fdb->used = jiffies;
  100. + INIT_HLIST_HEAD(&fdb->offload_in);
  101. + INIT_HLIST_HEAD(&fdb->offload_out);
  102. if (rhashtable_lookup_insert_fast(&br->fdb_hash_tbl,
  103. &fdb->rhnode,
  104. br_fdb_rht_params)) {
  105. @@ -734,6 +737,8 @@ static void fdb_notify(struct net_bridge
  106. struct sk_buff *skb;
  107. int err = -ENOBUFS;
  108. + br_offload_fdb_update(fdb);
  109. +
  110. if (swdev_notify)
  111. br_switchdev_fdb_notify(br, fdb, type);
  112. --- a/net/bridge/br_forward.c
  113. +++ b/net/bridge/br_forward.c
  114. @@ -16,6 +16,7 @@
  115. #include <linux/if_vlan.h>
  116. #include <linux/netfilter_bridge.h>
  117. #include "br_private.h"
  118. +#include "br_private_offload.h"
  119. /* Don't forward packets to originating port or forwarding disabled */
  120. static inline int should_deliver(const struct net_bridge_port *p,
  121. @@ -32,6 +33,8 @@ static inline int should_deliver(const s
  122. int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
  123. {
  124. + br_offload_output(skb);
  125. +
  126. skb_push(skb, ETH_HLEN);
  127. if (!is_skb_forwardable(skb->dev, skb))
  128. goto drop;
  129. --- a/net/bridge/br_if.c
  130. +++ b/net/bridge/br_if.c
  131. @@ -25,6 +25,7 @@
  132. #include <net/net_namespace.h>
  133. #include "br_private.h"
  134. +#include "br_private_offload.h"
  135. /*
  136. * Determine initial path cost based on speed.
  137. @@ -427,7 +428,7 @@ static struct net_bridge_port *new_nbp(s
  138. p->path_cost = port_cost(dev);
  139. p->priority = 0x8000 >> BR_PORT_BITS;
  140. p->port_no = index;
  141. - p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
  142. + p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | BR_OFFLOAD;
  143. br_init_port(p);
  144. br_set_state(p, BR_STATE_DISABLED);
  145. br_stp_port_timer_init(p);
  146. @@ -777,6 +778,9 @@ void br_port_flags_change(struct net_bri
  147. if (mask & BR_NEIGH_SUPPRESS)
  148. br_recalculate_neigh_suppress_enabled(br);
  149. +
  150. + if (mask & BR_OFFLOAD)
  151. + br_offload_port_state(p);
  152. }
  153. bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
  154. --- a/net/bridge/br_input.c
  155. +++ b/net/bridge/br_input.c
  156. @@ -22,6 +22,7 @@
  157. #include <linux/rculist.h>
  158. #include "br_private.h"
  159. #include "br_private_tunnel.h"
  160. +#include "br_private_offload.h"
  161. static int
  162. br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
  163. @@ -169,6 +170,7 @@ int br_handle_frame_finish(struct net *n
  164. dst->used = now;
  165. br_forward(dst->dst, skb, local_rcv, false);
  166. } else {
  167. + br_offload_skb_disable(skb);
  168. if (!mcast_hit)
  169. br_flood(br, skb, pkt_type, local_rcv, false);
  170. else
  171. @@ -287,6 +289,9 @@ static rx_handler_result_t br_handle_fra
  172. memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
  173. p = br_port_get_rcu(skb->dev);
  174. + if (br_offload_input(p, skb))
  175. + return RX_HANDLER_CONSUMED;
  176. +
  177. if (p->flags & BR_VLAN_TUNNEL) {
  178. if (br_handle_ingress_vlan_tunnel(skb, p,
  179. nbp_vlan_group_rcu(p)))
  180. --- /dev/null
  181. +++ b/net/bridge/br_offload.c
  182. @@ -0,0 +1,436 @@
  183. +// SPDX-License-Identifier: GPL-2.0-only
  184. +#include <linux/kernel.h>
  185. +#include <linux/workqueue.h>
  186. +#include "br_private.h"
  187. +#include "br_private_offload.h"
  188. +
  189. +static DEFINE_SPINLOCK(offload_lock);
  190. +
  191. +struct bridge_flow_key {
  192. + u8 dest[ETH_ALEN];
  193. + u8 src[ETH_ALEN];
  194. +#ifdef CONFIG_BRIDGE_VLAN_FILTERING
  195. + u16 vlan_tag;
  196. + bool vlan_present;
  197. +#endif
  198. +};
  199. +
  200. +struct bridge_flow {
  201. + struct net_bridge_port *port;
  202. + struct rhash_head node;
  203. + struct bridge_flow_key key;
  204. +#ifdef CONFIG_BRIDGE_VLAN_FILTERING
  205. + bool vlan_out_present;
  206. + u16 vlan_out;
  207. +#endif
  208. +
  209. + unsigned long used;
  210. + struct net_bridge_fdb_entry *fdb_in, *fdb_out;
  211. + struct hlist_node fdb_list_in, fdb_list_out;
  212. +
  213. + struct rcu_head rcu;
  214. +};
  215. +
  216. +static const struct rhashtable_params flow_params = {
  217. + .automatic_shrinking = true,
  218. + .head_offset = offsetof(struct bridge_flow, node),
  219. + .key_len = sizeof(struct bridge_flow_key),
  220. + .key_offset = offsetof(struct bridge_flow, key),
  221. +};
  222. +
  223. +static struct kmem_cache *offload_cache __read_mostly;
  224. +
  225. +static void
  226. +flow_rcu_free(struct rcu_head *head)
  227. +{
  228. + struct bridge_flow *flow;
  229. +
  230. + flow = container_of(head, struct bridge_flow, rcu);
  231. + kmem_cache_free(offload_cache, flow);
  232. +}
  233. +
  234. +static void
  235. +__br_offload_flow_free(struct bridge_flow *flow)
  236. +{
  237. + flow->used = 0;
  238. + hlist_del(&flow->fdb_list_in);
  239. + hlist_del(&flow->fdb_list_out);
  240. +
  241. + call_rcu(&flow->rcu, flow_rcu_free);
  242. +}
  243. +
  244. +static void
  245. +br_offload_flow_free(struct bridge_flow *flow)
  246. +{
  247. + if (rhashtable_remove_fast(&flow->port->offload.rht, &flow->node,
  248. + flow_params) != 0)
  249. + return;
  250. +
  251. + __br_offload_flow_free(flow);
  252. +}
  253. +
  254. +static bool
  255. +br_offload_flow_fdb_refresh_time(struct bridge_flow *flow,
  256. + struct net_bridge_fdb_entry *fdb)
  257. +{
  258. + if (!time_after(flow->used, fdb->updated))
  259. + return false;
  260. +
  261. + fdb->updated = flow->used;
  262. +
  263. + return true;
  264. +}
  265. +
  266. +
  267. +static void
  268. +br_offload_flow_refresh_time(struct bridge_flow *flow)
  269. +{
  270. + br_offload_flow_fdb_refresh_time(flow, flow->fdb_in);
  271. + br_offload_flow_fdb_refresh_time(flow, flow->fdb_out);
  272. +}
  273. +
  274. +static void
  275. +br_offload_destroy_cb(void *ptr, void *arg)
  276. +{
  277. + struct bridge_flow *flow = ptr;
  278. +
  279. + __br_offload_flow_free(flow);
  280. +}
  281. +
  282. +static bool
  283. +br_offload_need_gc(struct net_bridge_port *p)
  284. +{
  285. + return (atomic_read(&p->offload.rht.nelems) +
  286. + p->br->offload_cache_reserved) >= p->br->offload_cache_size;
  287. +}
  288. +
  289. +static void
  290. +br_offload_gc_work(struct work_struct *work)
  291. +{
  292. + struct rhashtable_iter hti;
  293. + struct net_bridge_port *p;
  294. + struct bridge_flow *gc_flow = NULL;
  295. + struct bridge_flow *flow;
  296. + unsigned long gc_used;
  297. +
  298. + p = container_of(work, struct net_bridge_port, offload.gc_work);
  299. +
  300. + if (!br_offload_need_gc(p))
  301. + return;
  302. +
  303. + rhashtable_walk_enter(&p->offload.rht, &hti);
  304. + rhashtable_walk_start(&hti);
  305. + while ((flow = rhashtable_walk_next(&hti)) != NULL) {
  306. + unsigned long used;
  307. +
  308. + if (IS_ERR(flow))
  309. + continue;
  310. +
  311. + used = READ_ONCE(flow->used);
  312. + if (!used)
  313. + continue;
  314. +
  315. + if (gc_flow && !time_before(used, gc_used))
  316. + continue;
  317. +
  318. + gc_flow = flow;
  319. + gc_used = used;
  320. + }
  321. + rhashtable_walk_stop(&hti);
  322. + rhashtable_walk_exit(&hti);
  323. +
  324. + if (!gc_flow)
  325. + return;
  326. +
  327. + spin_lock_bh(&offload_lock);
  328. + if (br_offload_need_gc(p) && gc_flow &&
  329. + gc_flow->used == gc_used)
  330. + br_offload_flow_free(gc_flow);
  331. + if (p->offload.enabled && br_offload_need_gc(p))
  332. + queue_work(system_long_wq, work);
  333. + spin_unlock_bh(&offload_lock);
  334. +
  335. +}
  336. +
  337. +void br_offload_port_state(struct net_bridge_port *p)
  338. +{
  339. + struct net_bridge_port_offload *o = &p->offload;
  340. + bool enabled = true;
  341. + bool flush = false;
  342. +
  343. + if (p->state != BR_STATE_FORWARDING ||
  344. + !(p->flags & BR_OFFLOAD))
  345. + enabled = false;
  346. +
  347. + spin_lock_bh(&offload_lock);
  348. + if (o->enabled == enabled)
  349. + goto out;
  350. +
  351. + if (enabled) {
  352. + if (!o->gc_work.func)
  353. + INIT_WORK(&o->gc_work, br_offload_gc_work);
  354. + rhashtable_init(&o->rht, &flow_params);
  355. + } else {
  356. + flush = true;
  357. + rhashtable_free_and_destroy(&o->rht, br_offload_destroy_cb, o);
  358. + }
  359. +
  360. + o->enabled = enabled;
  361. +
  362. +out:
  363. + spin_unlock_bh(&offload_lock);
  364. +
  365. + if (flush)
  366. + flush_work(&o->gc_work);
  367. +}
  368. +
  369. +void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb)
  370. +{
  371. + struct bridge_flow *f;
  372. + struct hlist_node *tmp;
  373. +
  374. + spin_lock_bh(&offload_lock);
  375. +
  376. + hlist_for_each_entry_safe(f, tmp, &fdb->offload_in, fdb_list_in)
  377. + br_offload_flow_free(f);
  378. +
  379. + hlist_for_each_entry_safe(f, tmp, &fdb->offload_out, fdb_list_out)
  380. + br_offload_flow_free(f);
  381. +
  382. + spin_unlock_bh(&offload_lock);
  383. +}
  384. +
  385. +static void
  386. +br_offload_prepare_key(struct net_bridge_port *p, struct bridge_flow_key *key,
  387. + struct sk_buff *skb)
  388. +{
  389. + memset(key, 0, sizeof(*key));
  390. + memcpy(key, eth_hdr(skb), 2 * ETH_ALEN);
  391. +#ifdef CONFIG_BRIDGE_VLAN_FILTERING
  392. + if (!br_opt_get(p->br, BROPT_VLAN_ENABLED))
  393. + return;
  394. +
  395. + if (!skb_vlan_tag_present(skb) || skb->vlan_proto != p->br->vlan_proto)
  396. + return;
  397. +
  398. + key->vlan_present = true;
  399. + key->vlan_tag = skb_vlan_tag_get_id(skb);
  400. +#endif
  401. +}
  402. +
  403. +void br_offload_output(struct sk_buff *skb)
  404. +{
  405. + struct net_bridge_port_offload *o;
  406. + struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
  407. + struct net_bridge_port *p, *inp;
  408. + struct net_device *dev;
  409. + struct net_bridge_fdb_entry *fdb_in, *fdb_out;
  410. + struct net_bridge_vlan_group *vg;
  411. + struct bridge_flow_key key;
  412. + struct bridge_flow *flow;
  413. + u16 vlan;
  414. +
  415. + if (!cb->offload)
  416. + return;
  417. +
  418. + rcu_read_lock();
  419. +
  420. + p = br_port_get_rcu(skb->dev);
  421. + if (!p)
  422. + goto out;
  423. +
  424. + o = &p->offload;
  425. + if (!o->enabled)
  426. + goto out;
  427. +
  428. + if (atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size)
  429. + goto out;
  430. +
  431. + dev = dev_get_by_index_rcu(dev_net(p->br->dev), cb->input_ifindex);
  432. + if (!dev)
  433. + goto out;
  434. +
  435. + inp = br_port_get_rcu(dev);
  436. + if (!inp)
  437. + goto out;
  438. +
  439. + vg = nbp_vlan_group_rcu(inp);
  440. + vlan = cb->input_vlan_present ? cb->input_vlan_tag : br_get_pvid(vg);
  441. + fdb_in = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_source, vlan);
  442. + if (!fdb_in || !fdb_in->dst)
  443. + goto out;
  444. +
  445. + vg = nbp_vlan_group_rcu(p);
  446. + vlan = skb_vlan_tag_present(skb) ? skb_vlan_tag_get_id(skb) : br_get_pvid(vg);
  447. + fdb_out = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_dest, vlan);
  448. + if (!fdb_out || !fdb_out->dst)
  449. + goto out;
  450. +
  451. + br_offload_prepare_key(p, &key, skb);
  452. +#ifdef CONFIG_BRIDGE_VLAN_FILTERING
  453. + key.vlan_present = cb->input_vlan_present;
  454. + key.vlan_tag = cb->input_vlan_tag;
  455. +#endif
  456. +
  457. + flow = kmem_cache_alloc(offload_cache, GFP_ATOMIC);
  458. + flow->port = inp;
  459. + memcpy(&flow->key, &key, sizeof(key));
  460. +
  461. +#ifdef CONFIG_BRIDGE_VLAN_FILTERING
  462. + flow->vlan_out_present = skb_vlan_tag_present(skb);
  463. + flow->vlan_out = skb_vlan_tag_get(skb);
  464. +#endif
  465. +
  466. + flow->fdb_in = fdb_in;
  467. + flow->fdb_out = fdb_out;
  468. + flow->used = jiffies;
  469. +
  470. + spin_lock_bh(&offload_lock);
  471. + if (!o->enabled ||
  472. + atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size ||
  473. + rhashtable_insert_fast(&inp->offload.rht, &flow->node, flow_params)) {
  474. + kmem_cache_free(offload_cache, flow);
  475. + goto out_unlock;
  476. + }
  477. +
  478. + hlist_add_head(&flow->fdb_list_in, &fdb_in->offload_in);
  479. + hlist_add_head(&flow->fdb_list_out, &fdb_out->offload_out);
  480. +
  481. + if (br_offload_need_gc(p))
  482. + queue_work(system_long_wq, &p->offload.gc_work);
  483. +
  484. +out_unlock:
  485. + spin_unlock_bh(&offload_lock);
  486. +
  487. +out:
  488. + rcu_read_unlock();
  489. +}
  490. +
  491. +bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb)
  492. +{
  493. + struct net_bridge_port_offload *o = &p->offload;
  494. + struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
  495. + struct bridge_flow_key key;
  496. + struct net_bridge_port *dst;
  497. + struct bridge_flow *flow;
  498. + unsigned long now = jiffies;
  499. + bool ret = false;
  500. +
  501. + if (skb->len < sizeof(key))
  502. + return false;
  503. +
  504. + if (!o->enabled)
  505. + return false;
  506. +
  507. + if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
  508. + return false;
  509. +
  510. + br_offload_prepare_key(p, &key, skb);
  511. +
  512. + rcu_read_lock();
  513. + flow = rhashtable_lookup(&o->rht, &key, flow_params);
  514. + if (!flow) {
  515. + cb->offload = 1;
  516. +#ifdef CONFIG_BRIDGE_VLAN_FILTERING
  517. + cb->input_vlan_present = key.vlan_present != 0;
  518. + cb->input_vlan_tag = key.vlan_tag;
  519. +#endif
  520. + cb->input_ifindex = p->dev->ifindex;
  521. + goto out;
  522. + }
  523. +
  524. + if (flow->fdb_in->dst != p)
  525. + goto out;
  526. +
  527. + dst = flow->fdb_out->dst;
  528. + if (!dst)
  529. + goto out;
  530. +
  531. + ret = true;
  532. +#ifdef CONFIG_BRIDGE_VLAN_FILTERING
  533. + if (!flow->vlan_out_present && key.vlan_present) {
  534. + __vlan_hwaccel_clear_tag(skb);
  535. + } else if (flow->vlan_out_present) {
  536. + if (skb_vlan_tag_present(skb) &&
  537. + skb->vlan_proto != p->br->vlan_proto) {
  538. + /* Protocol-mismatch, empty out vlan_tci for new tag */
  539. + skb_push(skb, ETH_HLEN);
  540. + skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto,
  541. + skb_vlan_tag_get(skb));
  542. + if (unlikely(!skb))
  543. + goto out;
  544. +
  545. + skb_pull(skb, ETH_HLEN);
  546. + skb_reset_mac_len(skb);
  547. + }
  548. +
  549. + __vlan_hwaccel_put_tag(skb, p->br->vlan_proto,
  550. + flow->vlan_out);
  551. + }
  552. +#endif
  553. +
  554. + skb->dev = dst->dev;
  555. + skb_push(skb, ETH_HLEN);
  556. +
  557. + if (skb_warn_if_lro(skb) || !is_skb_forwardable(skb->dev, skb)) {
  558. + kfree_skb(skb);
  559. + goto out;
  560. + }
  561. +
  562. + if (now - flow->used >= HZ) {
  563. + flow->used = now;
  564. + br_offload_flow_refresh_time(flow);
  565. + }
  566. +
  567. + skb_forward_csum(skb);
  568. + dev_queue_xmit(skb);
  569. +
  570. +out:
  571. + rcu_read_unlock();
  572. + return ret;
  573. +}
  574. +
  575. +static void
  576. +br_offload_check_gc(struct net_bridge *br)
  577. +{
  578. + struct net_bridge_port *p;
  579. +
  580. + spin_lock_bh(&br->lock);
  581. + list_for_each_entry(p, &br->port_list, list)
  582. + if (br_offload_need_gc(p))
  583. + queue_work(system_long_wq, &p->offload.gc_work);
  584. + spin_unlock_bh(&br->lock);
  585. +}
  586. +
  587. +
  588. +int br_offload_set_cache_size(struct net_bridge *br, unsigned long val)
  589. +{
  590. + br->offload_cache_size = val;
  591. + br_offload_check_gc(br);
  592. +
  593. + return 0;
  594. +}
  595. +
  596. +int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val)
  597. +{
  598. + br->offload_cache_reserved = val;
  599. + br_offload_check_gc(br);
  600. +
  601. + return 0;
  602. +}
  603. +
  604. +int __init br_offload_init(void)
  605. +{
  606. + offload_cache = kmem_cache_create("bridge_offload_cache",
  607. + sizeof(struct bridge_flow),
  608. + 0, SLAB_HWCACHE_ALIGN, NULL);
  609. + if (!offload_cache)
  610. + return -ENOMEM;
  611. +
  612. + return 0;
  613. +}
  614. +
  615. +void br_offload_fini(void)
  616. +{
  617. + kmem_cache_destroy(offload_cache);
  618. +}
  619. --- a/net/bridge/br_private.h
  620. +++ b/net/bridge/br_private.h
  621. @@ -207,7 +207,13 @@ struct net_bridge_fdb_entry {
  622. unsigned long updated ____cacheline_aligned_in_smp;
  623. unsigned long used;
  624. - struct rcu_head rcu;
  625. + union {
  626. + struct {
  627. + struct hlist_head offload_in;
  628. + struct hlist_head offload_out;
  629. + };
  630. + struct rcu_head rcu;
  631. + };
  632. };
  633. #define MDB_PG_FLAGS_PERMANENT BIT(0)
  634. @@ -280,6 +286,12 @@ struct net_bridge_mdb_entry {
  635. struct rcu_head rcu;
  636. };
  637. +struct net_bridge_port_offload {
  638. + struct rhashtable rht;
  639. + struct work_struct gc_work;
  640. + bool enabled;
  641. +};
  642. +
  643. struct net_bridge_port {
  644. struct net_bridge *br;
  645. struct net_device *dev;
  646. @@ -337,6 +349,7 @@ struct net_bridge_port {
  647. u16 backup_redirected_cnt;
  648. struct bridge_stp_xstats stp_xstats;
  649. + struct net_bridge_port_offload offload;
  650. };
  651. #define kobj_to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
  652. @@ -475,6 +488,9 @@ struct net_bridge {
  653. struct kobject *ifobj;
  654. u32 auto_cnt;
  655. + u32 offload_cache_size;
  656. + u32 offload_cache_reserved;
  657. +
  658. #ifdef CONFIG_NET_SWITCHDEV
  659. int offload_fwd_mark;
  660. #endif
  661. @@ -501,6 +517,10 @@ struct br_input_skb_cb {
  662. #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
  663. u8 br_netfilter_broute:1;
  664. #endif
  665. + u8 offload:1;
  666. + u8 input_vlan_present:1;
  667. + u16 input_vlan_tag;
  668. + int input_ifindex;
  669. #ifdef CONFIG_NET_SWITCHDEV
  670. int offload_fwd_mark;
  671. --- /dev/null
  672. +++ b/net/bridge/br_private_offload.h
  673. @@ -0,0 +1,21 @@
  674. +#ifndef __BR_OFFLOAD_H
  675. +#define __BR_OFFLOAD_H
  676. +
  677. +bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb);
  678. +void br_offload_output(struct sk_buff *skb);
  679. +void br_offload_port_state(struct net_bridge_port *p);
  680. +void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb);
  681. +int br_offload_init(void);
  682. +void br_offload_fini(void);
  683. +int br_offload_set_cache_size(struct net_bridge *br, unsigned long val);
  684. +int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val);
  685. +
  686. +static inline void br_offload_skb_disable(struct sk_buff *skb)
  687. +{
  688. + struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
  689. +
  690. + if (cb->offload)
  691. + cb->offload = 0;
  692. +}
  693. +
  694. +#endif
  695. --- a/net/bridge/br_stp.c
  696. +++ b/net/bridge/br_stp.c
  697. @@ -12,6 +12,7 @@
  698. #include "br_private.h"
  699. #include "br_private_stp.h"
  700. +#include "br_private_offload.h"
  701. /* since time values in bpdu are in jiffies and then scaled (1/256)
  702. * before sending, make sure that is at least one STP tick.
  703. @@ -52,6 +53,8 @@ void br_set_state(struct net_bridge_port
  704. (unsigned int) p->port_no, p->dev->name,
  705. br_port_state_names[p->state]);
  706. + br_offload_port_state(p);
  707. +
  708. if (p->br->stp_enabled == BR_KERNEL_STP) {
  709. switch (p->state) {
  710. case BR_STATE_BLOCKING:
  711. --- a/net/bridge/br_sysfs_br.c
  712. +++ b/net/bridge/br_sysfs_br.c
  713. @@ -18,6 +18,7 @@
  714. #include <linux/sched/signal.h>
  715. #include "br_private.h"
  716. +#include "br_private_offload.h"
  717. #define to_bridge(cd) ((struct net_bridge *)netdev_priv(to_net_dev(cd)))
  718. @@ -842,6 +843,38 @@ static ssize_t vlan_stats_per_port_store
  719. static DEVICE_ATTR_RW(vlan_stats_per_port);
  720. #endif
  721. +static ssize_t offload_cache_size_show(struct device *d,
  722. + struct device_attribute *attr,
  723. + char *buf)
  724. +{
  725. + struct net_bridge *br = to_bridge(d);
  726. + return sprintf(buf, "%u\n", br->offload_cache_size);
  727. +}
  728. +
  729. +static ssize_t offload_cache_size_store(struct device *d,
  730. + struct device_attribute *attr,
  731. + const char *buf, size_t len)
  732. +{
  733. + return store_bridge_parm(d, buf, len, br_offload_set_cache_size);
  734. +}
  735. +static DEVICE_ATTR_RW(offload_cache_size);
  736. +
  737. +static ssize_t offload_cache_reserved_show(struct device *d,
  738. + struct device_attribute *attr,
  739. + char *buf)
  740. +{
  741. + struct net_bridge *br = to_bridge(d);
  742. + return sprintf(buf, "%u\n", br->offload_cache_reserved);
  743. +}
  744. +
  745. +static ssize_t offload_cache_reserved_store(struct device *d,
  746. + struct device_attribute *attr,
  747. + const char *buf, size_t len)
  748. +{
  749. + return store_bridge_parm(d, buf, len, br_offload_set_cache_reserved);
  750. +}
  751. +static DEVICE_ATTR_RW(offload_cache_reserved);
  752. +
  753. static struct attribute *bridge_attrs[] = {
  754. &dev_attr_forward_delay.attr,
  755. &dev_attr_hello_time.attr,
  756. @@ -896,6 +929,8 @@ static struct attribute *bridge_attrs[]
  757. &dev_attr_vlan_stats_enabled.attr,
  758. &dev_attr_vlan_stats_per_port.attr,
  759. #endif
  760. + &dev_attr_offload_cache_size.attr,
  761. + &dev_attr_offload_cache_reserved.attr,
  762. NULL
  763. };
  764. --- a/net/bridge/br_sysfs_if.c
  765. +++ b/net/bridge/br_sysfs_if.c
  766. @@ -234,6 +234,7 @@ BRPORT_ATTR_FLAG(broadcast_flood, BR_BCA
  767. BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
  768. BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
  769. BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER);
  770. +BRPORT_ATTR_FLAG(offload, BR_OFFLOAD);
  771. #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
  772. static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
  773. @@ -288,6 +289,7 @@ static const struct brport_attribute *br
  774. &brport_attr_isolated,
  775. &brport_attr_bpdu_filter,
  776. &brport_attr_backup_port,
  777. + &brport_attr_offload,
  778. NULL
  779. };
  780. --- a/net/bridge/br_vlan_tunnel.c
  781. +++ b/net/bridge/br_vlan_tunnel.c
  782. @@ -15,6 +15,7 @@
  783. #include "br_private.h"
  784. #include "br_private_tunnel.h"
  785. +#include "br_private_offload.h"
  786. static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg,
  787. const void *ptr)
  788. @@ -180,6 +181,7 @@ int br_handle_ingress_vlan_tunnel(struct
  789. skb_dst_drop(skb);
  790. __vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
  791. + br_offload_skb_disable(skb);
  792. return 0;
  793. }
  794. @@ -203,6 +205,7 @@ int br_handle_egress_vlan_tunnel(struct
  795. if (err)
  796. return err;
  797. + br_offload_skb_disable(skb);
  798. tunnel_dst = rcu_dereference(vlan->tinfo.tunnel_dst);
  799. if (tunnel_dst && dst_hold_safe(&tunnel_dst->dst))
  800. skb_dst_set(skb, &tunnel_dst->dst);