Skip to content

Commit 4ea1d83

Browse files
LorenzoBianconiputnopvut
authored andcommitted
controller: Send ARP/ND for stale mac_bindings entries.
Introduce the capability to actively refresh mac_binding entries available in OFTABLE_MAC_BINDING table when they are inactive for more than the configured threshold. Add the OFTABLE_MAC_BINDING table stats monitoring. This feature avoids possible unnecessary mac_entry removals if the destination is still alive but inactive for more than the configured value. Reduce threshold dump_period and cooldown_period to 3/16 of threshold value in order to not miss any re-arping time slot. Acked-by: Ales Musil <[email protected]> Acked-by: Mark Michelson <[email protected]> Reported-at: https://issues.redhat.com/browse/FDP-1135 Signed-off-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Mark Michelson <[email protected]>
1 parent 49d0f52 commit 4ea1d83

9 files changed

+516
-18
lines changed

controller/mac-cache.c

+129-9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <config.h>
1717
#include <stdbool.h>
1818

19+
#include "lflow.h"
1920
#include "lib/mac-binding-index.h"
2021
#include "local_data.h"
2122
#include "lport.h"
@@ -24,6 +25,7 @@
2425
#include "openvswitch/vlog.h"
2526
#include "ovn/logical-fields.h"
2627
#include "ovn-sb-idl.h"
28+
#include "pinctrl.h"
2729

2830
VLOG_DEFINE_THIS_MODULE(mac_cache);
2931

@@ -90,15 +92,20 @@ mac_cache_threshold_add(struct mac_cache_data *data,
9092
threshold = xmalloc(sizeof *threshold);
9193
threshold->dp_key = dp->tunnel_key;
9294
threshold->value = value;
93-
threshold->dump_period = value / 2;
94-
threshold->cooldown_period = value / 4;
95+
threshold->dump_period = (3 * value) / 16;
96+
threshold->cooldown_period = (3 * value) / 16;
9597

9698
/* (cooldown_period + dump_period) is the maximum time the timestamp may
97-
* be not updated. So, the sum of those times must be lower than the
98-
* threshold, otherwise we may fail to update an active MAC binding in
99+
* be not updated for an entry with IP + MAC combination from which we see
100+
* incoming traffic. For the entry that is used only in Tx direction
101+
* (e.g., an entry for a default gateway of the chassis) this time is
102+
* doubled, because an ARP/ND probe will need to be sent first and the
103+
* (cooldown_period + dump_period) will be the maximum time between such
104+
* probes. Hence, 2 * (cooldown_period + dump_period) should be less than
105+
* a threshold, otherwise we may fail to update an active MAC binding in
99106
* time and risk it being removed. Giving it an extra 1/10 of the time
100107
* for all the processing that needs to happen. */
101-
ovs_assert(threshold->cooldown_period + threshold->dump_period
108+
ovs_assert(2 * (threshold->cooldown_period + threshold->dump_period)
102109
< (9 * value) / 10);
103110

104111
hmap_insert(&data->thresholds, &threshold->hmap_node, dp->tunnel_key);
@@ -399,8 +406,10 @@ mac_binding_update_log(const char *action,
399406
}
400407

401408
void
402-
mac_binding_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
403-
void *data)
409+
mac_binding_stats_run(
410+
struct rconn *swconn OVS_UNUSED,
411+
struct ovsdb_idl_index *sbrec_port_binding_by_name OVS_UNUSED,
412+
struct ovs_list *stats_list, uint64_t *req_delay, void *data)
404413
{
405414
struct mac_cache_data *cache_data = data;
406415
long long timewall_now = time_wall_msec();
@@ -495,8 +504,10 @@ fdb_update_log(const char *action,
495504
}
496505

497506
void
498-
fdb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
499-
void *data)
507+
fdb_stats_run(struct rconn *swconn OVS_UNUSED,
508+
struct ovsdb_idl_index *sbrec_port_binding_by_name OVS_UNUSED,
509+
struct ovs_list *stats_list,
510+
uint64_t *req_delay, void *data)
500511
{
501512
struct mac_cache_data *cache_data = data;
502513
long long timewall_now = time_wall_msec();
@@ -847,3 +858,112 @@ buffered_packets_db_lookup(struct buffered_packets *bp, struct ds *ip,
847858

848859
eth_addr_from_string(smb->mac, mac);
849860
}
861+
862+
void
863+
mac_binding_probe_stats_process_flow_stats(
864+
struct ovs_list *stats_list,
865+
struct ofputil_flow_stats *ofp_stats)
866+
{
867+
struct mac_cache_stats *stats = xmalloc(sizeof *stats);
868+
869+
stats->idle_age_ms = ofp_stats->idle_age * 1000;
870+
stats->data.mb = (struct mac_binding_data) {
871+
.cookie = ntohll(ofp_stats->cookie),
872+
/* The port_key must be zero to match mac_binding_data_from_sbrec. */
873+
.port_key = 0,
874+
.dp_key = ntohll(ofp_stats->match.flow.metadata),
875+
};
876+
877+
if (ofp_stats->match.flow.regs[0]) {
878+
stats->data.mb.ip =
879+
in6_addr_mapped_ipv4(htonl(ofp_stats->match.flow.regs[0]));
880+
} else {
881+
ovs_be128 ip6 = hton128(flow_get_xxreg(&ofp_stats->match.flow, 1));
882+
memcpy(&stats->data.mb.ip, &ip6, sizeof stats->data.mb.ip);
883+
}
884+
885+
ovs_list_push_back(stats_list, &stats->list_node);
886+
}
887+
888+
void
889+
mac_binding_probe_stats_run(
890+
struct rconn *swconn,
891+
struct ovsdb_idl_index *sbrec_port_binding_by_name,
892+
struct ovs_list *stats_list,
893+
uint64_t *req_delay, void *data)
894+
{
895+
long long timewall_now = time_wall_msec();
896+
struct mac_cache_data *cache_data = data;
897+
898+
struct mac_cache_stats *stats;
899+
LIST_FOR_EACH_POP (stats, list_node, stats_list) {
900+
struct mac_binding *mb = mac_binding_find(&cache_data->mac_bindings,
901+
&stats->data.mb);
902+
if (!mb) {
903+
mac_binding_update_log("Probe: not found in the cache:",
904+
&stats->data.mb, false, NULL, 0, 0);
905+
free(stats);
906+
continue;
907+
}
908+
909+
struct mac_cache_threshold *threshold =
910+
mac_cache_threshold_find(cache_data, mb->data.dp_key);
911+
uint64_t since_updated_ms = timewall_now - mb->sbrec->timestamp;
912+
const struct sbrec_mac_binding *sbrec = mb->sbrec;
913+
914+
if (stats->idle_age_ms > threshold->value) {
915+
mac_binding_update_log("Not sending ARP/ND request for non-active",
916+
&mb->data, true, threshold,
917+
stats->idle_age_ms, since_updated_ms);
918+
free(stats);
919+
continue;
920+
}
921+
922+
if (since_updated_ms < threshold->cooldown_period) {
923+
mac_binding_update_log(
924+
"Not sending ARP/ND request for recently updated",
925+
&mb->data, true, threshold, stats->idle_age_ms,
926+
since_updated_ms);
927+
free(stats);
928+
continue;
929+
}
930+
931+
const struct sbrec_port_binding *pb =
932+
lport_lookup_by_name(sbrec_port_binding_by_name,
933+
sbrec->logical_port);
934+
if (!pb) {
935+
free(stats);
936+
continue;
937+
}
938+
939+
struct lport_addresses laddr;
940+
if (!extract_lsp_addresses(pb->mac[0], &laddr)) {
941+
free(stats);
942+
continue;
943+
}
944+
945+
if (laddr.n_ipv4_addrs || laddr.n_ipv6_addrs) {
946+
struct in6_addr local = laddr.n_ipv4_addrs
947+
? in6_addr_mapped_ipv4(laddr.ipv4_addrs[0].addr)
948+
: laddr.ipv6_addrs[0].addr;
949+
950+
mac_binding_update_log("Sending ARP/ND request for active",
951+
&mb->data, true, threshold,
952+
stats->idle_age_ms, since_updated_ms);
953+
954+
send_self_originated_neigh_packet(swconn,
955+
sbrec->datapath->tunnel_key,
956+
pb->tunnel_key, laddr.ea,
957+
&local, &mb->data.ip,
958+
OFTABLE_LOCAL_OUTPUT);
959+
}
960+
961+
free(stats);
962+
destroy_lport_addresses(&laddr);
963+
}
964+
965+
mac_cache_update_req_delay(&cache_data->thresholds, req_delay);
966+
if (*req_delay) {
967+
VLOG_DBG("MAC probe binding statistics delay: %"PRIu64, *req_delay);
968+
}
969+
}

controller/mac-cache.h

+17-4
Original file line numberDiff line numberDiff line change
@@ -180,15 +180,19 @@ void
180180
mac_binding_stats_process_flow_stats(struct ovs_list *stats_list,
181181
struct ofputil_flow_stats *ofp_stats);
182182

183-
void mac_binding_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
184-
void *data);
183+
void mac_binding_stats_run(
184+
struct rconn *swconn OVS_UNUSED,
185+
struct ovsdb_idl_index *sbrec_port_binding_by_name OVS_UNUSED,
186+
struct ovs_list *stats_list, uint64_t *req_delay, void *data);
185187

186188
/* FDB stat processing. */
187189
void fdb_stats_process_flow_stats(struct ovs_list *stats_list,
188190
struct ofputil_flow_stats *ofp_stats);
189191

190-
void fdb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
191-
void *data);
192+
void fdb_stats_run(
193+
struct rconn *swconn OVS_UNUSED,
194+
struct ovsdb_idl_index *sbrec_port_binding_by_name OVS_UNUSED,
195+
struct ovs_list *stats_list, uint64_t *req_delay, void *data);
192196

193197
void mac_cache_stats_destroy(struct ovs_list *stats_list);
194198

@@ -221,4 +225,13 @@ bool buffered_packets_ctx_is_ready_to_send(struct buffered_packets_ctx *ctx);
221225

222226
bool buffered_packets_ctx_has_packets(struct buffered_packets_ctx *ctx);
223227

228+
void mac_binding_probe_stats_process_flow_stats(
229+
struct ovs_list *stats_list,
230+
struct ofputil_flow_stats *ofp_stats);
231+
232+
void mac_binding_probe_stats_run(
233+
struct rconn *swconn,
234+
struct ovsdb_idl_index *sbrec_port_binding_by_name,
235+
struct ovs_list *stats_list, uint64_t *req_delay, void *data);
236+
224237
#endif /* controller/mac-cache.h */

controller/ovn-controller.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -6342,7 +6342,8 @@ main(int argc, char *argv[])
63426342

63436343
mac_cache_data = engine_get_data(&en_mac_cache);
63446344
if (mac_cache_data) {
6345-
statctrl_run(ovnsb_idl_txn, mac_cache_data);
6345+
statctrl_run(ovnsb_idl_txn, sbrec_port_binding_by_name,
6346+
mac_cache_data);
63466347
}
63476348

63486349
ofctrl_seqno_update_create(

controller/pinctrl.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -5303,7 +5303,7 @@ send_garp_rarp_delete(const char *lport)
53035303
notify_pinctrl_handler();
53045304
}
53055305

5306-
static void
5306+
void
53075307
send_self_originated_neigh_packet(struct rconn *swconn,
53085308
uint32_t dp_key, uint32_t port_key,
53095309
struct eth_addr eth,

controller/pinctrl.h

+7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct ovsdb_idl_index;
3131
struct ovsdb_idl_txn;
3232
struct ovsrec_bridge;
3333
struct ovsrec_open_vswitch_table;
34+
struct rconn;
3435
struct sbrec_chassis;
3536
struct sbrec_dns_table;
3637
struct sbrec_controller_event_table;
@@ -77,4 +78,10 @@ struct activated_port {
7778
void tag_port_as_activated_in_engine(struct activated_port *ap);
7879
struct ovs_list *get_ports_to_activate_in_engine(void);
7980
bool pinctrl_is_port_activated(int64_t dp_key, int64_t port_key);
81+
void send_self_originated_neigh_packet(struct rconn *swconn,
82+
uint32_t dp_key, uint32_t port_key,
83+
struct eth_addr eth,
84+
struct in6_addr *local,
85+
struct in6_addr *target,
86+
uint8_t table_id);
8087
#endif /* controller/pinctrl.h */

controller/statctrl.c

+26-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ VLOG_DEFINE_THIS_MODULE(statctrl);
3939
enum stat_type {
4040
STATS_MAC_BINDING = 0,
4141
STATS_FDB,
42+
STATS_MAC_BINDING_PROBE,
4243
STATS_MAX,
4344
};
4445

@@ -62,7 +63,10 @@ struct stats_node {
6263
struct ofputil_flow_stats *ofp_stats);
6364
/* Function to process the parsed stats.
6465
* This function runs in main thread locked behind mutex. */
65-
void (*run)(struct ovs_list *stats_list, uint64_t *req_delay, void *data);
66+
void (*run)(struct rconn *swconn,
67+
struct ovsdb_idl_index *sbrec_port_binding_by_name,
68+
struct ovs_list *stats_list,
69+
uint64_t *req_delay, void *data);
6670
};
6771

6872
#define STATS_NODE(NAME, REQUEST, DESTROY, PROCESS, RUN) \
@@ -145,20 +149,37 @@ statctrl_init(void)
145149
STATS_NODE(FDB, fdb_request, mac_cache_stats_destroy,
146150
fdb_stats_process_flow_stats, fdb_stats_run);
147151

152+
struct ofputil_flow_stats_request mac_binding_probe_request = {
153+
.cookie = htonll(0),
154+
.cookie_mask = htonll(0),
155+
.out_port = OFPP_ANY,
156+
.out_group = OFPG_ANY,
157+
.table_id = OFTABLE_MAC_BINDING,
158+
};
159+
STATS_NODE(MAC_BINDING_PROBE, mac_binding_probe_request,
160+
mac_cache_stats_destroy,
161+
mac_binding_probe_stats_process_flow_stats,
162+
mac_binding_probe_stats_run);
163+
148164
statctrl_ctx.thread = ovs_thread_create("ovn_statctrl",
149165
statctrl_thread_handler,
150166
&statctrl_ctx);
151167
}
152168

153169
void
154170
statctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
171+
struct ovsdb_idl_index *sbrec_port_binding_by_name,
155172
struct mac_cache_data *mac_cache_data)
156173
{
157174
if (!ovnsb_idl_txn) {
158175
return;
159176
}
160177

161-
void *node_data[STATS_MAX] = {mac_cache_data, mac_cache_data};
178+
void *node_data[STATS_MAX] = {
179+
mac_cache_data,
180+
mac_cache_data,
181+
mac_cache_data
182+
};
162183

163184
bool schedule_updated = false;
164185
long long now = time_msec();
@@ -168,7 +189,9 @@ statctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
168189
struct stats_node *node = &statctrl_ctx.nodes[i];
169190
uint64_t prev_delay = node->request_delay;
170191

171-
node->run(&node->stats_list, &node->request_delay, node_data[i]);
192+
node->run(statctrl_ctx.swconn,
193+
sbrec_port_binding_by_name, &node->stats_list,
194+
&node->request_delay, node_data[i]);
172195

173196
schedule_updated |=
174197
statctrl_update_next_request_timestamp(node, now, prev_delay);

controller/statctrl.h

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
void statctrl_init(void);
2222
void statctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
23+
struct ovsdb_idl_index *sbrec_port_binding_by_name,
2324
struct mac_cache_data *mac_cache_data);
2425

2526
void statctrl_update_swconn(const char *target, int probe_interval);

0 commit comments

Comments
 (0)