6565#include "ovn-sb-idl.h"
6666#include "ovn-dns.h"
6767#include "garp_rarp.h"
68+ #include "spsc-ring.h"
6869
6970VLOG_DEFINE_THIS_MODULE (pinctrl );
7071
@@ -83,24 +84,31 @@ VLOG_DEFINE_THIS_MODULE(pinctrl);
8384 * and pinctrl_run().
8485 *
8586 *
86- * - put_arp/put_nd - These actions stores the IPv4/IPv6 and MAC addresses
87+ * - put_arp/put_nd - These actions store the IPv4/IPv6 and MAC addresses
8788 * in the 'MAC_Binding' table.
8889 * The function 'pinctrl_handle_put_mac_binding()' (which
89- * is called with in the pinctrl_handler thread), stores
90- * the IPv4/IPv6 and MAC addresses in the
91- * hmap - put_mac_bindings.
90+ * is called within the pinctrl_handler thread), pushes
91+ * the IPv4/IPv6 and MAC addresses directly into a
92+ * lock-free SPSC ring buffer ('mac_bindings_ring').
93+ * This does not require pinctrl_mutex. For multicast
94+ * replies, a special cookie value
95+ * (MAC_BINDINGS_MC_COOKIE) is set to signal the main
96+ * thread to apply a random delay.
9297 *
93- * pinctrl_run(), reads these mac bindings from the hmap
94- * 'put_mac_bindings' and writes to the 'MAC_Binding'
95- * table in the Southbound DB.
98+ * pinctrl_run() drains the ring in
99+ * run_put_mac_bindings(), inserts entries into the
100+ * main-thread-only hmap 'put_mac_bindings' (applying
101+ * a random delay for multicast replies to avoid
102+ * thundering herd), and writes expired entries to the
103+ * 'MAC_Binding' table in the Southbound DB.
96104 *
97105 * - arp/nd_ns - These actions generate an ARP/IPv6 Neighbor solicit
98106 * requests. The original packets are buffered and
99107 * injected back when put_arp/put_nd resolves
100108 * corresponding ARP/IPv6 Neighbor solicit requests.
101- * When pinctrl_run(), writes the mac bindings from the
102- * 'put_mac_bindings' hmap to the MAC_Binding table in
103- * SB DB, run_buffered_binding will add the buffered
109+ * When pinctrl_run() writes the mac bindings from the
110+ * ring buffer to the MAC_Binding table in SB DB,
111+ * run_buffered_binding will add the buffered
104112 * packets to buffered_mac_bindings and notify
105113 * pinctrl_handler.
106114 *
@@ -197,16 +205,14 @@ run_buffered_binding(const struct sbrec_mac_binding_table *mac_binding_table,
197205
198206static void pinctrl_handle_put_mac_binding (const struct flow * md ,
199207 const struct flow * headers ,
200- bool is_arp )
201- OVS_REQUIRES (pinctrl_mutex );
202- static void init_put_mac_bindings (void );
203- static void destroy_put_mac_bindings (void );
208+ bool is_arp );
209+ static void init_mac_bindings (void );
210+ static void destroy_mac_bindings (void );
204211static void run_put_mac_bindings (
205212 struct ovsdb_idl_txn * ovnsb_idl_txn ,
206213 struct ovsdb_idl_index * sbrec_datapath_binding_by_key ,
207214 struct ovsdb_idl_index * sbrec_port_binding_by_key ,
208- struct ovsdb_idl_index * sbrec_mac_binding_by_lport_ip )
209- OVS_REQUIRES (pinctrl_mutex );
215+ struct ovsdb_idl_index * sbrec_mac_binding_by_lport_ip );
210216static void wait_put_mac_bindings (void );
211217static void send_mac_binding_buffered_pkts (struct rconn * swconn );
212218
@@ -366,18 +372,15 @@ static void run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn,
366372 struct ovsdb_idl_index * sbrec_fdb_by_dp_key_mac ,
367373 struct ovsdb_idl_index * sbrec_port_binding_by_key ,
368374 struct ovsdb_idl_index * sbrec_datapath_binding_by_key ,
369- struct fdb * fdb , uint64_t cur_cfg )
370- OVS_REQUIRES (pinctrl_mutex );
375+ struct fdb * fdb , uint64_t cur_cfg );
371376static void run_put_fdbs (struct ovsdb_idl_txn * ovnsb_idl_txn ,
372377 struct ovsdb_idl_index * sbrec_port_binding_by_key ,
373378 struct ovsdb_idl_index * sbrec_datapath_binding_by_key ,
374379 struct ovsdb_idl_index * sbrec_fdb_by_dp_key_mac ,
375- uint64_t cur_cfg )
376- OVS_REQUIRES (pinctrl_mutex );
380+ uint64_t cur_cfg );
377381static void wait_put_fdbs (void );
378382static void pinctrl_handle_put_fdb (const struct flow * md ,
379- const struct flow * headers )
380- OVS_REQUIRES (pinctrl_mutex );
383+ const struct flow * headers );
381384
382385static void set_from_ctrl_flag_in_pkt_metadata (struct ofputil_packet_in * );
383386
@@ -556,7 +559,7 @@ controller_event_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
556559void
557560pinctrl_init (void )
558561{
559- init_put_mac_bindings ();
562+ init_mac_bindings ();
560563 init_send_arps_nds ();
561564 init_ipv6_ras ();
562565 init_ipv6_prefixd ();
@@ -3776,10 +3779,8 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
37763779 break ;
37773780
37783781 case ACTION_OPCODE_PUT_ARP :
3779- ovs_mutex_lock (& pinctrl_mutex );
37803782 pinctrl_handle_put_mac_binding (& pin .flow_metadata .flow , & headers ,
37813783 true);
3782- ovs_mutex_unlock (& pinctrl_mutex );
37833784 break ;
37843785
37853786 case ACTION_OPCODE_DHCP_RELAY_REQ_CHK :
@@ -3808,16 +3809,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
38083809 break ;
38093810
38103811 case ACTION_OPCODE_PUT_ND :
3811- ovs_mutex_lock (& pinctrl_mutex );
38123812 pinctrl_handle_put_mac_binding (& pin .flow_metadata .flow , & headers ,
38133813 false);
3814- ovs_mutex_unlock (& pinctrl_mutex );
38153814 break ;
38163815
38173816 case ACTION_OPCODE_PUT_FDB :
3818- ovs_mutex_lock (& pinctrl_mutex );
38193817 pinctrl_handle_put_fdb (& pin .flow_metadata .flow , & headers );
3820- ovs_mutex_unlock (& pinctrl_mutex );
38213818 break ;
38223819
38233820 case ACTION_OPCODE_PUT_DHCPV6_OPTS :
@@ -4757,7 +4754,7 @@ pinctrl_destroy(void)
47574754 destroy_buffered_packets_map ();
47584755 destroy_activated_ports ();
47594756 event_table_destroy ();
4760- destroy_put_mac_bindings ();
4757+ destroy_mac_bindings ();
47614758 destroy_put_vport_bindings ();
47624759 ip_mcast_snoop_destroy ();
47634760 destroy_svc_monitors ();
@@ -4782,37 +4779,42 @@ pinctrl_destroy(void)
47824779
47834780#define MAX_MAC_BINDING_DELAY_MSEC 50
47844781#define MAX_FDB_DELAY_MSEC 50
4785- #define MAX_MAC_BINDINGS 1000
4782+ #define MAX_MAC_BINDINGS 1024
4783+ #define MAC_BINDINGS_MC_COOKIE 0xff
4784+
47864785
4787- /* Contains "struct mac_binding"s. */
4786+ /* Contains "struct mac_binding"s. This is used by main thread only. */
47884787static struct hmap put_mac_bindings ;
4788+ /* Contains "struct mac_binding_data". This is populated by pinctrl thread
4789+ * and consumed by main thread. */
4790+ static struct spsc_ring mac_bindings_ring ;
47894791
47904792static void
4791- init_put_mac_bindings (void )
4793+ init_mac_bindings (void )
47924794{
47934795 hmap_init (& put_mac_bindings );
4796+ spsc_ring_init (& mac_bindings_ring , MAX_MAC_BINDINGS ,
4797+ sizeof (struct mac_binding_data ));
47944798}
47954799
47964800static void
4797- destroy_put_mac_bindings (void )
4801+ destroy_mac_bindings (void )
47984802{
47994803 mac_bindings_clear (& put_mac_bindings );
48004804 hmap_destroy (& put_mac_bindings );
4805+ spsc_ring_destroy (& mac_bindings_ring );
48014806}
48024807
48034808/* Called with in the pinctrl_handler thread context. */
48044809static void
48054810pinctrl_handle_put_mac_binding (const struct flow * md ,
48064811 const struct flow * headers ,
48074812 bool is_arp )
4808- OVS_REQUIRES (pinctrl_mutex )
48094813{
4810- if (hmap_count (& put_mac_bindings ) >= MAX_MAC_BINDINGS ) {
4811- COVERAGE_INC (pinctrl_drop_put_mac_binding );
4812- return ;
4813- }
4814-
48154814 struct mac_binding_data mb_data = (struct mac_binding_data ) {
4815+ .cookie = eth_addr_is_multicast (headers -> dl_dst )
4816+ ? MAC_BINDINGS_MC_COOKIE
4817+ : 0 ,
48164818 .dp_key = ntohll (md -> metadata ),
48174819 .port_key = md -> regs [MFF_LOG_INPORT - MFF_REG0 ],
48184820 .mac = headers -> dl_src ,
@@ -4825,18 +4827,13 @@ pinctrl_handle_put_mac_binding(const struct flow *md,
48254827 memcpy (& mb_data .ip , & ip6 , sizeof mb_data .ip );
48264828 }
48274829
4828- /* If the ARP reply was unicast we should not delay it,
4829- * there won't be any race. */
4830- uint32_t delay = eth_addr_is_multicast (headers -> dl_dst )
4831- ? random_range (MAX_MAC_BINDING_DELAY_MSEC ) + 1
4832- : 0 ;
4833- long long timestamp = time_msec () + delay ;
4834- mac_binding_add (& put_mac_bindings , mb_data , NULL , timestamp );
4835-
4836- /* We can send the buffered packet once the main ovn-controller
4837- * thread calls pinctrl_run() and it writes the mac_bindings stored
4838- * in 'put_mac_bindings' hmap into the Southbound MAC_Binding table. */
4839- notify_pinctrl_main ();
4830+ if (!spsc_ring_push (& mac_bindings_ring , & mb_data )) {
4831+ /* This shouldn't happen, the main thread drains the ring buffer
4832+ * every iteration. */
4833+ COVERAGE_INC (pinctrl_drop_put_mac_binding );
4834+ } else {
4835+ notify_pinctrl_main ();
4836+ }
48404837}
48414838
48424839/* Called with in the pinctrl_handler thread context. */
@@ -4898,14 +4895,32 @@ run_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn,
48984895 struct ovsdb_idl_index * sbrec_datapath_binding_by_key ,
48994896 struct ovsdb_idl_index * sbrec_port_binding_by_key ,
49004897 struct ovsdb_idl_index * sbrec_mac_binding_by_lport_ip )
4901- OVS_REQUIRES (pinctrl_mutex )
49024898{
4899+ long long now = time_msec ();
4900+
4901+ struct mac_binding_data mb_data ;
4902+ SPSC_RING_FOR_EACH_POP (& mac_bindings_ring , mb_data ) {
4903+ if (hmap_count (& put_mac_bindings ) >= MAX_MAC_BINDINGS ) {
4904+ COVERAGE_INC (pinctrl_drop_put_mac_binding );
4905+ continue ;
4906+ }
4907+
4908+ /* If the ARP reply was unicast we should not delay it,
4909+ * there won't be any race. */
4910+ uint32_t delay = mb_data .cookie == MAC_BINDINGS_MC_COOKIE
4911+ ? random_range (MAX_MAC_BINDING_DELAY_MSEC ) + 1
4912+ : 0 ;
4913+ /* Clear the cookie, it's needed just to know if it was delayed or
4914+ * not. */
4915+ mb_data .cookie = 0 ;
4916+
4917+ mac_binding_add (& put_mac_bindings , mb_data , NULL , now + delay );
4918+ }
4919+
49034920 if (!ovnsb_idl_txn ) {
49044921 return ;
49054922 }
49064923
4907- long long now = time_msec ();
4908-
49094924 struct mac_binding * mb ;
49104925 HMAP_FOR_EACH_SAFE (mb , hmap_node , & put_mac_bindings ) {
49114926 if (now >= mb -> timestamp ) {
@@ -4986,7 +5001,6 @@ run_buffered_binding(const struct sbrec_mac_binding_table *mac_binding_table,
49865001
49875002static void
49885003wait_put_mac_bindings (void )
4989- OVS_REQUIRES (pinctrl_mutex )
49905004{
49915005 struct mac_binding * mb ;
49925006 HMAP_FOR_EACH (mb , hmap_node , & put_mac_bindings ) {
@@ -8878,9 +8892,13 @@ pinctrl_split_buf_action_handler(struct rconn *swconn, struct dp_packet *pkt,
88788892 ofpbuf_uninit (& ofpacts );
88798893}
88808894
8881- #define MAX_FDB_ENTRIES 1000
8895+ #define MAX_FDB_ENTRIES 1024
88828896
8897+ /* Contains "struct fdb"s. This is used by main thread only. */
88838898static struct hmap put_fdbs ;
8899+ /* Contains "struct fdb_data". This is populated by pinctrl thread
8900+ * and consumed by main thread. */
8901+ static struct spsc_ring fdbs_ring ;
88848902
88858903/* MAC learning (fdb) related functions. Runs within the main
88868904 * ovn-controller thread context. */
@@ -8889,13 +8907,16 @@ static void
88898907init_fdb_entries (void )
88908908{
88918909 hmap_init (& put_fdbs );
8910+ spsc_ring_init (& fdbs_ring , MAX_FDB_ENTRIES ,
8911+ sizeof (struct fdb_data ));
88928912}
88938913
88948914static void
88958915destroy_fdb_entries (void )
88968916{
88978917 fdbs_clear (& put_fdbs );
88988918 hmap_destroy (& put_fdbs );
8919+ spsc_ring_destroy (& fdbs_ring );
88998920}
89008921
89018922static const struct sbrec_fdb *
@@ -8975,13 +8996,24 @@ run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn,
89758996 struct ovsdb_idl_index * sbrec_port_binding_by_key ,
89768997 struct ovsdb_idl_index * sbrec_datapath_binding_by_key ,
89778998 struct ovsdb_idl_index * sbrec_fdb_by_dp_key_mac , uint64_t cur_cfg )
8978- OVS_REQUIRES (pinctrl_mutex )
89798999{
9000+ long long now = time_msec ();
9001+
9002+ struct fdb_data fdb_data ;
9003+ SPSC_RING_FOR_EACH_POP (& fdbs_ring , fdb_data ) {
9004+ if (hmap_count (& put_fdbs ) >= MAX_FDB_ENTRIES ) {
9005+ COVERAGE_INC (pinctrl_drop_put_fdb );
9006+ continue ;
9007+ }
9008+
9009+ uint32_t delay = random_range (MAX_FDB_DELAY_MSEC ) + 1 ;
9010+ fdb_add (& put_fdbs , fdb_data , now + delay );
9011+ }
9012+
89809013 if (!ovnsb_idl_txn ) {
89819014 return ;
89829015 }
89839016
8984- long long now = time_msec ();
89859017 struct fdb * fdb ;
89869018 HMAP_FOR_EACH_SAFE (fdb , hmap_node , & put_fdbs ) {
89879019 if (fdb -> cfg >= 0 && pinctrl_is_sb_commited (fdb -> cfg , cur_cfg )) {
@@ -8997,7 +9029,6 @@ run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn,
89979029
89989030static void
89999031wait_put_fdbs (void )
9000- OVS_REQUIRES (pinctrl_mutex )
90019032{
90029033 struct fdb * fdb ;
90039034 HMAP_FOR_EACH (fdb , hmap_node , & put_fdbs ) {
@@ -9008,23 +9039,20 @@ wait_put_fdbs(void)
90089039/* Called with in the pinctrl_handler thread context. */
90099040static void
90109041pinctrl_handle_put_fdb (const struct flow * md , const struct flow * headers )
9011- OVS_REQUIRES (pinctrl_mutex )
90129042{
9013- if (hmap_count (& put_fdbs ) >= MAX_FDB_ENTRIES ) {
9014- COVERAGE_INC (pinctrl_drop_put_fdb );
9015- return ;
9016- }
9017-
90189043 struct fdb_data fdb_data = (struct fdb_data ) {
90199044 .dp_key = ntohll (md -> metadata ),
90209045 .port_key = md -> regs [MFF_LOG_INPORT - MFF_REG0 ],
90219046 .mac = headers -> dl_src ,
90229047 };
90239048
9024- uint32_t delay = random_range (MAX_FDB_DELAY_MSEC ) + 1 ;
9025- long long timestamp = time_msec () + delay ;
9026- fdb_add (& put_fdbs , fdb_data , timestamp );
9027- notify_pinctrl_main ();
9049+ if (!spsc_ring_push (& fdbs_ring , & fdb_data )) {
9050+ /* This shouldn't happen, the main thread drains the ring buffer
9051+ * every iteration. */
9052+ COVERAGE_INC (pinctrl_drop_put_fdb );
9053+ } else {
9054+ notify_pinctrl_main ();
9055+ }
90289056}
90299057
90309058/* This function sets the register bit 'MLF_FROM_CTRL_BIT'
0 commit comments