Skip to content

Commit

Permalink
ofctrl: Introduce ecmp_nexthop_monitor.
Browse files Browse the repository at this point in the history
Introduce ecmp_nexthop_monitor in ovn-controller in order to track and
flush ecmp-symmetric reply ct entires when requested by the CMS (e.g
removing the related static ecmp routes). CT entries are flushed using
the ethernet mac address stored in ct_label.

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Signed-off-by: 0-day Robot <robot@bytheb.org>
  • Loading branch information
LorenzoBianconi authored and ovsrobot committed Dec 20, 2024
1 parent ec011ab commit 78a6f34
Show file tree
Hide file tree
Showing 8 changed files with 760 additions and 1 deletion.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Post v24.09.0
- Add "arp-nd-max-timeout-sec" config option to vswitchd external-ids to
configure the interval (in seconds) between ovn-controller originated
ARP/ND packets used for tracking ECMP next hop MAC addresses.
- Auto flush ECMP symmetric reply connection states when an ECMP route is
removed by the CMS."

OVN v24.09.0 - 13 Sep 2024
--------------------------
Expand Down
4 changes: 3 additions & 1 deletion controller/automake.mk
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ controller_ovn_controller_SOURCES = \
controller/ct-zone.h \
controller/ct-zone.c \
controller/ovn-dns.c \
controller/ovn-dns.h
controller/ovn-dns.h \
controller/ecmp-next-hop-monitor.h \
controller/ecmp-next-hop-monitor.c

controller_ovn_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la
man_MANS += controller/ovn-controller.8
Expand Down
187 changes: 187 additions & 0 deletions controller/ecmp-next-hop-monitor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/* Copyright (c) 2024, Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <config.h>
#include "ct-zone.h"
#include "lib/ovn-util.h"
#include "lib/simap.h"
#include "openvswitch/hmap.h"
#include "openvswitch/ofp-ct.h"
#include "openvswitch/rconn.h"
#include "openvswitch/vlog.h"
#include "ovn/logical-fields.h"
#include "ovn-sb-idl.h"
#include "controller/ecmp-next-hop-monitor.h"

static struct hmap ecmp_nexthop;

struct ecmp_nexthop_data {
struct hmap_node hmap_node;
uint16_t zone_id;
char *nexthop;
char *mac;
};

void ecmp_nexthop_init(void)
{
hmap_init(&ecmp_nexthop);
}

static void
ecmp_nexthop_destroy_entry(struct ecmp_nexthop_data *e)
{
free(e->nexthop);
free(e->mac);
free(e);
}

static void
ecmp_nexthop_destroy_map(struct hmap *map)
{
struct ecmp_nexthop_data *e;
HMAP_FOR_EACH_POP (e, hmap_node, map) {
ecmp_nexthop_destroy_entry(e);
}
hmap_destroy(map);
}

void ecmp_nexthop_destroy(void)
{
ecmp_nexthop_destroy_map(&ecmp_nexthop);
}

static struct ecmp_nexthop_data *
ecmp_nexthop_alloc_entry(const char *nexthop, const char *mac,
const uint16_t zone_id, struct hmap *map)
{
struct ecmp_nexthop_data *e = xmalloc(sizeof *e);
e->nexthop = xstrdup(nexthop);
e->mac = xstrdup(mac);
e->zone_id = zone_id;

uint32_t hash = hash_string(nexthop, 0);
hash = hash_add(hash, hash_string(mac, 0));
hash = hash_add(hash, zone_id);
hmap_insert(map, &e->hmap_node, hash);

return e;
}

static struct ecmp_nexthop_data *
ecmp_nexthop_find_entry(const char *nexthop, const char *mac,
const uint16_t zone_id, struct hmap *map)
{
uint32_t hash = hash_string(nexthop, 0);
hash = hash_add(hash, hash_string(mac, 0));
hash = hash_add(hash, zone_id);

struct ecmp_nexthop_data *e;
HMAP_FOR_EACH_WITH_HASH (e, hmap_node, hash, map) {
if (!strcmp(e->nexthop, nexthop) &&
!strcmp(e->mac, mac) && e->zone_id == zone_id) {
return e;
}
}
return NULL;
}

#define OVN_CT_ECMP_ETH_LOW (((1ULL << OVN_CT_ECMP_ETH_1ST_BIT) - 1) << 32)
#define OVN_CT_ECMP_ETH_HIGH ((1ULL << (OVN_CT_ECMP_ETH_END_BIT - 63)) - 1)

static void
ecmp_nexthop_monitor_flush_ct_entry(const struct rconn *swconn,
const char *mac, uint16_t zone_id,
struct ovs_list *msgs)
{
struct eth_addr ea;
if (!ovs_scan(mac, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) {
return;
}

ovs_u128 mask = {
/* ct_label.ecmp_reply_eth BITS[32-79] */
.u64.hi = OVN_CT_ECMP_ETH_HIGH,
.u64.lo = OVN_CT_ECMP_ETH_LOW,
};

ovs_be32 lo = get_unaligned_be32((void *)&ea.be16[1]);
ovs_u128 nexthop = {
.u64.hi = ntohs(ea.be16[0]),
.u64.lo = (uint64_t) ntohl(lo) << 32,
};

struct ofp_ct_match match = {
.labels = nexthop,
.labels_mask = mask,
};
struct ofpbuf *msg = ofp_ct_match_encode(&match, &zone_id,
rconn_get_version(swconn));
ovs_list_push_back(msgs, &msg->list_node);
}

void
ecmp_nexthop_monitor_run(const struct sbrec_ecmp_nexthop_table *enh_table,
const struct hmap *local_datapaths,
const struct shash *current_ct_zones,
const struct rconn *swconn, struct ovs_list *msgs)
{
struct hmap sb_ecmp_nexthop = HMAP_INITIALIZER(&sb_ecmp_nexthop);

const struct sbrec_ecmp_nexthop *sbrec_ecmp_nexthop;
SBREC_ECMP_NEXTHOP_TABLE_FOR_EACH (sbrec_ecmp_nexthop, enh_table) {
if (local_datapaths &&
!get_local_datapath(local_datapaths,
sbrec_ecmp_nexthop->datapath->tunnel_key)) {
continue;
}
const char *dp_name = smap_get(
&sbrec_ecmp_nexthop->datapath->external_ids, "name");
if (!dp_name) {
continue;
}

char *name = alloc_nat_zone_key(dp_name, "dnat");
struct ct_zone *ct_zone = shash_find_data(current_ct_zones, name);
free(name);

if (!ct_zone) {
continue;
}

if (!ecmp_nexthop_find_entry(sbrec_ecmp_nexthop->nexthop,
sbrec_ecmp_nexthop->mac, ct_zone->zone,
&ecmp_nexthop)) {
ecmp_nexthop_alloc_entry(sbrec_ecmp_nexthop->nexthop,
sbrec_ecmp_nexthop->mac,
ct_zone->zone, &ecmp_nexthop);
}
ecmp_nexthop_alloc_entry(sbrec_ecmp_nexthop->nexthop,
sbrec_ecmp_nexthop->mac, ct_zone->zone,
&sb_ecmp_nexthop);
}

struct ecmp_nexthop_data *e;
HMAP_FOR_EACH_SAFE (e, hmap_node, &ecmp_nexthop) {
if (!ecmp_nexthop_find_entry(e->nexthop, e->mac, e->zone_id,
&sb_ecmp_nexthop)) {
ecmp_nexthop_monitor_flush_ct_entry(swconn, e->mac,
e->zone_id, msgs);
hmap_remove(&ecmp_nexthop, &e->hmap_node);
ecmp_nexthop_destroy_entry(e);
}
}

ecmp_nexthop_destroy_map(&sb_ecmp_nexthop);
}
26 changes: 26 additions & 0 deletions controller/ecmp-next-hop-monitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Copyright (c) 2024, Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef OVN_ECMP_NEXT_HOP_MONITOR_H
#define OVN_ECMP_NEXT_HOP_MONITOR_H

void ecmp_nexthop_init(void);
void ecmp_nexthop_destroy(void);
void ecmp_nexthop_monitor_run(const struct sbrec_ecmp_nexthop_table *enh_table,
const struct hmap *local_datapaths,
const struct shash *current_ct_zones,
const struct rconn *swconn,
struct ovs_list *msgs);
#endif /* OVN_ECMP_NEXT_HOP_MONITOR_H */
9 changes: 9 additions & 0 deletions controller/ofctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "vswitch-idl.h"
#include "ovn-sb-idl.h"
#include "ct-zone.h"
#include "ecmp-next-hop-monitor.h"

VLOG_DEFINE_THIS_MODULE(ofctrl);

Expand Down Expand Up @@ -425,6 +426,7 @@ ofctrl_init(struct ovn_extend_table *group_table,
tx_counter = rconn_packet_counter_create();
hmap_init(&installed_lflows);
hmap_init(&installed_pflows);
ecmp_nexthop_init();
ovs_list_init(&flow_updates);
ovn_init_symtab(&symtab);
groups = group_table;
Expand Down Expand Up @@ -877,6 +879,7 @@ ofctrl_destroy(void)
expr_symtab_destroy(&symtab);
shash_destroy(&symtab);
ofctrl_meter_bands_destroy();
ecmp_nexthop_destroy();
}

uint64_t
Expand Down Expand Up @@ -2662,8 +2665,11 @@ void
ofctrl_put(struct ovn_desired_flow_table *lflow_table,
struct ovn_desired_flow_table *pflow_table,
struct shash *pending_ct_zones,
struct shash *current_ct_zones,
struct hmap *pending_lb_tuples,
const struct hmap *local_datapaths,
struct ovsdb_idl_index *sbrec_meter_by_name,
const struct sbrec_ecmp_nexthop_table *enh_table,
uint64_t req_cfg,
bool lflows_changed,
bool pflows_changed)
Expand Down Expand Up @@ -2704,6 +2710,9 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table,
/* OpenFlow messages to send to the switch to bring it up-to-date. */
struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);

ecmp_nexthop_monitor_run(enh_table, local_datapaths,
current_ct_zones, swconn, &msgs);

/* Iterate through ct zones that need to be flushed. */
struct shash_node *iter;
SHASH_FOR_EACH(iter, pending_ct_zones) {
Expand Down
4 changes: 4 additions & 0 deletions controller/ofctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct ofpbuf;
struct ovsrec_bridge;
struct ovsrec_open_vswitch_table;
struct sbrec_meter_table;
struct sbrec_ecmp_nexthop_table;
struct shash;

struct ovn_desired_flow_table {
Expand All @@ -57,8 +58,11 @@ enum mf_field_id ofctrl_get_mf_field_id(void);
void ofctrl_put(struct ovn_desired_flow_table *lflow_table,
struct ovn_desired_flow_table *pflow_table,
struct shash *pending_ct_zones,
struct shash *current_ct_zones,
struct hmap *pending_lb_tuples,
const struct hmap *local_datapaths,
struct ovsdb_idl_index *sbrec_meter_by_name,
const struct sbrec_ecmp_nexthop_table *enh_table,
uint64_t nb_cfg,
bool lflow_changed,
bool pflow_changed);
Expand Down
5 changes: 5 additions & 0 deletions controller/ovn-controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -5834,8 +5834,13 @@ main(int argc, char *argv[])
ofctrl_put(&lflow_output_data->flow_table,
&pflow_output_data->flow_table,
&ct_zones_data->ctx.pending,
&ct_zones_data->ctx.current,
&lb_data->removed_tuples,
runtime_data ?
&runtime_data->local_datapaths : NULL,
sbrec_meter_by_name,
sbrec_ecmp_nexthop_table_get(
ovnsb_idl_loop.idl),
ofctrl_seqno_get_req_cfg(),
engine_node_changed(&en_lflow_output),
engine_node_changed(&en_pflow_output));
Expand Down
Loading

0 comments on commit 78a6f34

Please sign in to comment.