|
16 | 16 | #include <config.h>
|
17 | 17 | #include <stdbool.h>
|
18 | 18 |
|
| 19 | +#include "lflow.h" |
19 | 20 | #include "lib/mac-binding-index.h"
|
20 | 21 | #include "local_data.h"
|
21 | 22 | #include "lport.h"
|
|
24 | 25 | #include "openvswitch/vlog.h"
|
25 | 26 | #include "ovn/logical-fields.h"
|
26 | 27 | #include "ovn-sb-idl.h"
|
| 28 | +#include "pinctrl.h" |
27 | 29 |
|
28 | 30 | VLOG_DEFINE_THIS_MODULE(mac_cache);
|
29 | 31 |
|
@@ -90,15 +92,20 @@ mac_cache_threshold_add(struct mac_cache_data *data,
|
90 | 92 | threshold = xmalloc(sizeof *threshold);
|
91 | 93 | threshold->dp_key = dp->tunnel_key;
|
92 | 94 | 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; |
95 | 97 |
|
96 | 98 | /* (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 |
99 | 106 | * time and risk it being removed. Giving it an extra 1/10 of the time
|
100 | 107 | * 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) |
102 | 109 | < (9 * value) / 10);
|
103 | 110 |
|
104 | 111 | hmap_insert(&data->thresholds, &threshold->hmap_node, dp->tunnel_key);
|
@@ -399,8 +406,10 @@ mac_binding_update_log(const char *action,
|
399 | 406 | }
|
400 | 407 |
|
401 | 408 | 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) |
404 | 413 | {
|
405 | 414 | struct mac_cache_data *cache_data = data;
|
406 | 415 | long long timewall_now = time_wall_msec();
|
@@ -495,8 +504,10 @@ fdb_update_log(const char *action,
|
495 | 504 | }
|
496 | 505 |
|
497 | 506 | 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) |
500 | 511 | {
|
501 | 512 | struct mac_cache_data *cache_data = data;
|
502 | 513 | long long timewall_now = time_wall_msec();
|
@@ -847,3 +858,112 @@ buffered_packets_db_lookup(struct buffered_packets *bp, struct ds *ip,
|
847 | 858 |
|
848 | 859 | eth_addr_from_string(smb->mac, mac);
|
849 | 860 | }
|
| 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 | +} |
0 commit comments