Skip to content

Commit 1e981b3

Browse files
committed
pinctrl: Convert the put_ARP/ND methods to be lockless.
The put_ARP/ND were bound to pinctrl lock to prevent data races as they have used shared hmap to store the data that were later on added into SB. This is problematic in situations when main thread holds the lock and we have to process any put_ARP/ND packet. That contention would block the pinctrl thread from processing the incoming packets. The same can happen from the opposite side, pinctrl could be holding a lock, delaying main thread from processing other updates. To prevent that use the hmap only by pinctrl thread, this will ensure that we wait properly for the multicast timeout to expire and at the same time to do the deduplication. Once the entry is ready it will be shared by thread safe ring buffer and consumed by main thread. Signed-off-by: Ales Musil <amusil@redhat.com>
1 parent b50b8da commit 1e981b3

1 file changed

Lines changed: 74 additions & 65 deletions

File tree

controller/pinctrl.c

Lines changed: 74 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
#include "ovn-sb-idl.h"
6666
#include "ovn-dns.h"
6767
#include "garp_rarp.h"
68+
#include "spsc-ring.h"
6869

6970
VLOG_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

198206
static 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);
204211
static 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);
211217
static void send_mac_binding_buffered_pkts(struct rconn *swconn);
212218

213219
static void pinctrl_activation_strategy_handler(const struct match *md);
@@ -556,7 +562,7 @@ controller_event_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
556562
void
557563
pinctrl_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

47904797
static 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

47964805
static 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. */
48044814
static void
48054815
pinctrl_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

49874979
static 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

Comments
 (0)