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+ * is called within the pinctrl_handler thread), stores
9091 * the IPv4/IPv6 and MAC addresses in the
91- * hmap - put_mac_bindings.
92+ * hmap - 'wait_mac_bindings'. This hmap is owned
93+ * exclusively by the pinctrl_handler thread and does
94+ * not require pinctrl_mutex.
9295 *
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.
96+ * When the multicast delay timer expires, entries are
97+ * pushed into a lock-free SPSC ring buffer
98+ * ('mac_bindings_ring') by
99+ * wait_mac_bindings_prepare_ready().
100+ *
101+ * pinctrl_run() drains the ring in
102+ * run_put_mac_bindings() and writes the mac bindings
103+ * to the '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,17 +205,15 @@ 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 );
210- static void wait_put_mac_bindings (void );
215+ struct ovsdb_idl_index * sbrec_mac_binding_by_lport_ip );
216+ static void wait_mac_bindings_prepare_ready (void );
211217static void send_mac_binding_buffered_pkts (struct rconn * swconn );
212218
213219static void pinctrl_activation_strategy_handler (const struct match * md );
@@ -556,7 +562,7 @@ controller_event_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
556562void
557563pinctrl_init (void )
558564{
559- init_put_mac_bindings ();
565+ init_mac_bindings ();
560566 init_send_arps_nds ();
561567 init_ipv6_ras ();
562568 init_ipv6_prefixd ();
@@ -3776,10 +3782,8 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
37763782 break ;
37773783
37783784 case ACTION_OPCODE_PUT_ARP :
3779- ovs_mutex_lock (& pinctrl_mutex );
37803785 pinctrl_handle_put_mac_binding (& pin .flow_metadata .flow , & headers ,
37813786 true);
3782- ovs_mutex_unlock (& pinctrl_mutex );
37833787 break ;
37843788
37853789 case ACTION_OPCODE_DHCP_RELAY_REQ_CHK :
@@ -3808,10 +3812,8 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
38083812 break ;
38093813
38103814 case ACTION_OPCODE_PUT_ND :
3811- ovs_mutex_lock (& pinctrl_mutex );
38123815 pinctrl_handle_put_mac_binding (& pin .flow_metadata .flow , & headers ,
38133816 false);
3814- ovs_mutex_unlock (& pinctrl_mutex );
38153817 break ;
38163818
38173819 case ACTION_OPCODE_PUT_FDB :
@@ -4100,6 +4102,8 @@ pinctrl_handler(void *arg_)
41004102 poll_timer_wait (5 );
41014103 }
41024104
4105+ wait_mac_bindings_prepare_ready ();
4106+
41034107 rconn_run_wait (swconn );
41044108 rconn_recv_wait (swconn );
41054109 if (rconn_is_connected (swconn )) {
@@ -4724,7 +4728,6 @@ pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn)
47244728{
47254729 ovs_mutex_lock (& pinctrl_mutex );
47264730 if (ovnsb_idl_txn ) {
4727- wait_put_mac_bindings ();
47284731 wait_controller_event ();
47294732 wait_put_vport_bindings ();
47304733 wait_put_fdbs ();
@@ -4757,7 +4760,7 @@ pinctrl_destroy(void)
47574760 destroy_buffered_packets_map ();
47584761 destroy_activated_ports ();
47594762 event_table_destroy ();
4760- destroy_put_mac_bindings ();
4763+ destroy_mac_bindings ();
47614764 destroy_put_vport_bindings ();
47624765 ip_mcast_snoop_destroy ();
47634766 destroy_svc_monitors ();
@@ -4782,36 +4785,37 @@ pinctrl_destroy(void)
47824785
47834786#define MAX_MAC_BINDING_DELAY_MSEC 50
47844787#define MAX_FDB_DELAY_MSEC 50
4785- #define MAX_MAC_BINDINGS 1000
4788+ #define MAX_MAC_BINDINGS 1024
4789+
47864790
4787- /* Contains "struct mac_binding"s. */
4788- static struct hmap put_mac_bindings ;
4791+ /* Contains "struct mac_binding"s. This is used by pinctrl thread only. */
4792+ static struct hmap wait_mac_bindings ;
4793+ /* Contains "struct mac_binding_data". This is populated by pinctrl thread
4794+ * and consumed by main thread. */
4795+ static struct spsc_ring mac_bindings_ring ;
47894796
47904797static void
4791- init_put_mac_bindings (void )
4798+ init_mac_bindings (void )
47924799{
4793- hmap_init (& put_mac_bindings );
4800+ hmap_init (& wait_mac_bindings );
4801+ spsc_ring_init (& mac_bindings_ring , MAX_MAC_BINDINGS ,
4802+ sizeof (struct mac_binding_data ));
47944803}
47954804
47964805static void
4797- destroy_put_mac_bindings (void )
4806+ destroy_mac_bindings (void )
47984807{
4799- mac_bindings_clear (& put_mac_bindings );
4800- hmap_destroy (& put_mac_bindings );
4808+ mac_bindings_clear (& wait_mac_bindings );
4809+ hmap_destroy (& wait_mac_bindings );
4810+ spsc_ring_destroy (& mac_bindings_ring );
48014811}
48024812
48034813/* Called with in the pinctrl_handler thread context. */
48044814static void
48054815pinctrl_handle_put_mac_binding (const struct flow * md ,
48064816 const struct flow * headers ,
48074817 bool is_arp )
4808- OVS_REQUIRES (pinctrl_mutex )
48094818{
4810- if (hmap_count (& put_mac_bindings ) >= MAX_MAC_BINDINGS ) {
4811- COVERAGE_INC (pinctrl_drop_put_mac_binding );
4812- return ;
4813- }
4814-
48154819 struct mac_binding_data mb_data = (struct mac_binding_data ) {
48164820 .dp_key = ntohll (md -> metadata ),
48174821 .port_key = md -> regs [MFF_LOG_INPORT - MFF_REG0 ],
@@ -4831,12 +4835,7 @@ pinctrl_handle_put_mac_binding(const struct flow *md,
48314835 ? random_range (MAX_MAC_BINDING_DELAY_MSEC ) + 1
48324836 : 0 ;
48334837 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 ();
4838+ mac_binding_add (& wait_mac_bindings , mb_data , NULL , timestamp );
48404839}
48414840
48424841/* Called with in the pinctrl_handler thread context. */
@@ -4864,29 +4863,29 @@ run_put_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn,
48644863 struct ovsdb_idl_index * sbrec_datapath_binding_by_key ,
48654864 struct ovsdb_idl_index * sbrec_port_binding_by_key ,
48664865 struct ovsdb_idl_index * sbrec_mac_binding_by_lport_ip ,
4867- const struct mac_binding * mb )
4866+ const struct mac_binding_data * mb_data )
48684867{
48694868 /* Convert logical datapath and logical port key into lport. */
48704869 const struct sbrec_port_binding * pb = lport_lookup_by_key (
48714870 sbrec_datapath_binding_by_key , sbrec_port_binding_by_key ,
4872- mb -> data . dp_key , mb -> data . port_key );
4871+ mb_data -> dp_key , mb_data -> port_key );
48734872 if (!pb ) {
48744873 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT (1 , 5 );
48754874
48764875 VLOG_WARN_RL (& rl , "unknown logical port with datapath %" PRIu32 " "
4877- "and port %" PRIu32 , mb -> data . dp_key , mb -> data . port_key );
4876+ "and port %" PRIu32 , mb_data -> dp_key , mb_data -> port_key );
48784877 return ;
48794878 }
48804879
48814880 /* Convert ethernet argument to string form for database. */
48824881 char mac_string [ETH_ADDR_STRLEN + 1 ];
48834882 snprintf (mac_string , sizeof mac_string ,
4884- ETH_ADDR_FMT , ETH_ADDR_ARGS (mb -> data . mac ));
4883+ ETH_ADDR_FMT , ETH_ADDR_ARGS (mb_data -> mac ));
48854884
48864885 struct ds ip_s = DS_EMPTY_INITIALIZER ;
4887- ipv6_format_mapped (& mb -> data . ip , & ip_s );
4886+ ipv6_format_mapped (& mb_data -> ip , & ip_s );
48884887 mac_binding_add_to_sb (ovnsb_idl_txn , sbrec_mac_binding_by_lport_ip ,
4889- pb -> logical_port , pb -> datapath , mb -> data . mac ,
4888+ pb -> logical_port , pb -> datapath , mb_data -> mac ,
48904889 ds_cstr (& ip_s ), false);
48914890 ds_destroy (& ip_s );
48924891}
@@ -4898,23 +4897,16 @@ run_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn,
48984897 struct ovsdb_idl_index * sbrec_datapath_binding_by_key ,
48994898 struct ovsdb_idl_index * sbrec_port_binding_by_key ,
49004899 struct ovsdb_idl_index * sbrec_mac_binding_by_lport_ip )
4901- OVS_REQUIRES (pinctrl_mutex )
49024900{
49034901 if (!ovnsb_idl_txn ) {
49044902 return ;
49054903 }
49064904
4907- long long now = time_msec ();
4908-
4909- struct mac_binding * mb ;
4910- HMAP_FOR_EACH_SAFE (mb , hmap_node , & put_mac_bindings ) {
4911- if (now >= mb -> timestamp ) {
4912- run_put_mac_binding (ovnsb_idl_txn ,
4913- sbrec_datapath_binding_by_key ,
4914- sbrec_port_binding_by_key ,
4915- sbrec_mac_binding_by_lport_ip , mb );
4916- mac_binding_remove (& put_mac_bindings , mb );
4917- }
4905+ struct mac_binding_data mb_data ;
4906+ SPSC_RING_FOR_EACH_POP (& mac_bindings_ring , mb_data ) {
4907+ run_put_mac_binding (ovnsb_idl_txn , sbrec_datapath_binding_by_key ,
4908+ sbrec_port_binding_by_key ,
4909+ sbrec_mac_binding_by_lport_ip , & mb_data );
49184910 }
49194911}
49204912
@@ -4985,12 +4977,29 @@ run_buffered_binding(const struct sbrec_mac_binding_table *mac_binding_table,
49854977}
49864978
49874979static void
4988- wait_put_mac_bindings (void )
4989- OVS_REQUIRES (pinctrl_mutex )
4980+ wait_mac_bindings_prepare_ready (void )
49904981{
4982+ long long now = time_msec ();
4983+ bool notify = false;
4984+
49914985 struct mac_binding * mb ;
4992- HMAP_FOR_EACH (mb , hmap_node , & put_mac_bindings ) {
4993- poll_timer_wait_until (mb -> timestamp );
4986+ HMAP_FOR_EACH_SAFE (mb , hmap_node , & wait_mac_bindings ) {
4987+ if (now < mb -> timestamp ) {
4988+ poll_timer_wait_until (mb -> timestamp );
4989+ continue ;
4990+ }
4991+
4992+ if (spsc_ring_push (& mac_bindings_ring , & mb -> data )) {
4993+ notify = true;
4994+ } else {
4995+ COVERAGE_INC (pinctrl_drop_put_mac_binding );
4996+ }
4997+
4998+ mac_binding_remove (& wait_mac_bindings , mb );
4999+ }
5000+
5001+ if (notify ) {
5002+ notify_pinctrl_main ();
49945003 }
49955004}
49965005
0 commit comments