On Wed, Jun 7, 2023 at 12:39 PM Numan Siddique <[email protected]> wrote:
>
> On Fri, Jun 2, 2023 at 12:13 AM Han Zhou <[email protected]> wrote:
> >
> > This patch introduces a change handler for NB logical_switch within the
> > 'northd' node. It specifically handles cases where logical switch ports
> > in the tracked logical switches are changed (added/updated/deleted).
> > Only regular logical switch ports - which are common for VMs/Pods - are
> > addressed. For other scenarios, it reverts to recompute.
> >
> > This update avoids recompute in the northd node (especially the
> > resource-intensive build_ports()) for NB changes of VIF
> > add/update/delete. However, it does not eliminate the need for lflow
> > recompute.
> >
> > Below are the performance test results simulating an ovn-k8s topology of
> > 500 nodes x 50 lsp per node:
> >
> > Before:
> > ovn-nbctl --wait=hv --print-wait-time lsp-del lsp_1_0001_01
> > ovn-northd completion: 955ms
> > ovn-nbctl --wait=hv --print-wait-time lsp-add ls_1_0001 lsp_1_0001_01
-- lsp-set-addresses lsp_1_0001_01 "ff:f1:bb:00:01:01 1.0.1.101" --
lsp-set-port-security lsp_1_0001_01 "ff:f1:bb:00:01:01 1.0.1.101"
> > ovn-northd completion: 919ms
> >
> > After:
> > ovn-nbctl --wait=hv --print-wait-time lsp-del lsp_1_0001_01
> > ovn-northd completion: 776ms
> > ovn-nbctl --wait=hv --print-wait-time lsp-add ls_1_0001 lsp_1_0001_01
-- lsp-set-addresses lsp_1_0001_01 "ff:f1:bb:00:01:01 1.0.1.101" --
lsp-set-port-security lsp_1_0001_01 "ff:f1:bb:00:01:01 1.0.1.101"
> > ovn-northd completion: 773ms
> >
> > Both addition and deletion show ~20% reduction of ovn-northd completion
> > time. Note: the test uses only 1 thread of ovn-northd for flow
> > recompute. Using multithread should show a larger percentage of
> > improvement.
> >
> > Signed-off-by: Han Zhou <[email protected]>
> > Reviewed-by: Ales Musil <[email protected]>
>
> Few nits below.
>
> Acked-by: Numan Siddique <[email protected]>
>
> Numan
>
>
> > ---
> > lib/ovn-util.c | 15 ++
> > lib/ovn-util.h | 1 +
> > northd/en-northd.c | 130 ++++++---
> > northd/en-northd.h | 2 +
> > northd/inc-proc-northd.c | 12 +-
> > northd/northd.c | 567 +++++++++++++++++++++++++++++++++------
> > northd/northd.h | 27 +-
> > tests/ovn-northd.at | 58 ++++
> > 8 files changed, 685 insertions(+), 127 deletions(-)
> >
> > diff --git a/lib/ovn-util.c b/lib/ovn-util.c
> > index bffb521cfd9d..da2a9d45ac64 100644
> > --- a/lib/ovn-util.c
> > +++ b/lib/ovn-util.c
> > @@ -720,6 +720,21 @@ ovn_allocate_tnlid(struct hmap *set, const char
*name, uint32_t min,
> > return 0;
> > }
> >
> > +bool
> > +ovn_free_tnlid(struct hmap *tnlids, uint32_t tnlid)
> > +{
> > + uint32_t hash = hash_int(tnlid, 0);
> > + struct tnlid_node *node;
> > + HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash, tnlids) {
> > + if (node->tnlid == tnlid) {
> > + hmap_remove(tnlids, &node->hmap_node);
> > + free(node);
> > + return true;
> > + }
> > + }
> > + return false;
> > +}
> > +
> > char *
> > ovn_chassis_redirect_name(const char *port_name)
> > {
> > diff --git a/lib/ovn-util.h b/lib/ovn-util.h
> > index b17b0e2364c5..9681a12219a9 100644
> > --- a/lib/ovn-util.h
> > +++ b/lib/ovn-util.h
> > @@ -167,6 +167,7 @@ bool ovn_add_tnlid(struct hmap *set, uint32_t
tnlid);
> > bool ovn_tnlid_present(struct hmap *tnlids, uint32_t tnlid);
> > uint32_t ovn_allocate_tnlid(struct hmap *set, const char *name,
uint32_t min,
> > uint32_t max, uint32_t *hint);
> > +bool ovn_free_tnlid(struct hmap *tnlids, uint32_t tnlid);
> >
> > static inline void
> > get_unique_lport_key(uint64_t dp_tunnel_key, uint64_t lport_tunnel_key,
> > diff --git a/northd/en-northd.c b/northd/en-northd.c
> > index a3dc37e198e3..f2bf98f774b1 100644
> > --- a/northd/en-northd.c
> > +++ b/northd/en-northd.c
> > @@ -31,92 +31,103 @@
> >
> > VLOG_DEFINE_THIS_MODULE(en_northd);
> >
> > -void en_northd_run(struct engine_node *node, void *data)
> > +static void
> > +northd_get_input_data(struct engine_node *node,
> > + struct northd_input *input_data)
> > {
> > - const struct engine_context *eng_ctx = engine_get_context();
> > -
> > - struct northd_input input_data;
> > -
> > - northd_destroy(data);
> > - northd_init(data);
> > -
> > - input_data.sbrec_chassis_by_name =
> > + input_data->sbrec_chassis_by_name =
> > engine_ovsdb_node_get_index(
> > engine_get_input("SB_chassis", node),
> > "sbrec_chassis_by_name");
> > - input_data.sbrec_chassis_by_hostname =
> > + input_data->sbrec_chassis_by_hostname =
> > engine_ovsdb_node_get_index(
> > engine_get_input("SB_chassis", node),
> > "sbrec_chassis_by_hostname");
> > - input_data.sbrec_ha_chassis_grp_by_name =
> > + input_data->sbrec_ha_chassis_grp_by_name =
> > engine_ovsdb_node_get_index(
> > engine_get_input("SB_ha_chassis_group", node),
> > "sbrec_ha_chassis_grp_by_name");
> > - input_data.sbrec_ip_mcast_by_dp =
> > + input_data->sbrec_ip_mcast_by_dp =
> > engine_ovsdb_node_get_index(
> > engine_get_input("SB_ip_multicast", node),
> > "sbrec_ip_mcast_by_dp");
> > - input_data.sbrec_static_mac_binding_by_lport_ip =
> > + input_data->sbrec_static_mac_binding_by_lport_ip =
> > engine_ovsdb_node_get_index(
> > engine_get_input("SB_static_mac_binding", node),
> > "sbrec_static_mac_binding_by_lport_ip");
> > + input_data->sbrec_fdb_by_dp_and_port =
> > + engine_ovsdb_node_get_index(
> > + engine_get_input("SB_fdb", node),
> > + "sbrec_fdb_by_dp_and_port");
> >
> > - input_data.nbrec_nb_global_table =
> > + input_data->nbrec_nb_global_table =
> > EN_OVSDB_GET(engine_get_input("NB_nb_global", node));
> > - input_data.nbrec_logical_switch_table =
> > + input_data->nbrec_logical_switch_table =
> > EN_OVSDB_GET(engine_get_input("NB_logical_switch", node));
> > - input_data.nbrec_logical_router_table =
> > + input_data->nbrec_logical_router_table =
> > EN_OVSDB_GET(engine_get_input("NB_logical_router", node));
> > - input_data.nbrec_load_balancer_table =
> > + input_data->nbrec_load_balancer_table =
> > EN_OVSDB_GET(engine_get_input("NB_load_balancer", node));
> > - input_data.nbrec_load_balancer_group_table =
> > + input_data->nbrec_load_balancer_group_table =
> > EN_OVSDB_GET(engine_get_input("NB_load_balancer_group", node));
> > - input_data.nbrec_port_group_table =
> > + input_data->nbrec_port_group_table =
> > EN_OVSDB_GET(engine_get_input("NB_port_group", node));
> > - input_data.nbrec_meter_table =
> > + input_data->nbrec_meter_table =
> > EN_OVSDB_GET(engine_get_input("NB_meter", node));
> > - input_data.nbrec_acl_table =
> > + input_data->nbrec_acl_table =
> > EN_OVSDB_GET(engine_get_input("NB_acl", node));
> > - input_data.nbrec_static_mac_binding_table =
> > + input_data->nbrec_static_mac_binding_table =
> > EN_OVSDB_GET(engine_get_input("NB_static_mac_binding", node));
> > - input_data.nbrec_chassis_template_var_table =
> > + input_data->nbrec_chassis_template_var_table =
> > EN_OVSDB_GET(engine_get_input("NB_chassis_template_var",
node));
> > - input_data.nbrec_mirror_table =
> > + input_data->nbrec_mirror_table =
> > EN_OVSDB_GET(engine_get_input("NB_mirror", node));
> >
> > - input_data.sbrec_sb_global_table =
> > + input_data->sbrec_sb_global_table =
> > EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
> > - input_data.sbrec_datapath_binding_table =
> > + input_data->sbrec_datapath_binding_table =
> > EN_OVSDB_GET(engine_get_input("SB_datapath_binding", node));
> > - input_data.sbrec_port_binding_table =
> > + input_data->sbrec_port_binding_table =
> > EN_OVSDB_GET(engine_get_input("SB_port_binding", node));
> > - input_data.sbrec_mac_binding_table =
> > + input_data->sbrec_mac_binding_table =
> > EN_OVSDB_GET(engine_get_input("SB_mac_binding", node));
> > - input_data.sbrec_ha_chassis_group_table =
> > + input_data->sbrec_ha_chassis_group_table =
> > EN_OVSDB_GET(engine_get_input("SB_ha_chassis_group", node));
> > - input_data.sbrec_chassis_table =
> > + input_data->sbrec_chassis_table =
> > EN_OVSDB_GET(engine_get_input("SB_chassis", node));
> > - input_data.sbrec_fdb_table =
> > + input_data->sbrec_fdb_table =
> > EN_OVSDB_GET(engine_get_input("SB_fdb", node));
> > - input_data.sbrec_load_balancer_table =
> > + input_data->sbrec_load_balancer_table =
> > EN_OVSDB_GET(engine_get_input("SB_load_balancer", node));
> > - input_data.sbrec_service_monitor_table =
> > + input_data->sbrec_service_monitor_table =
> > EN_OVSDB_GET(engine_get_input("SB_service_monitor", node));
> > - input_data.sbrec_port_group_table =
> > + input_data->sbrec_port_group_table =
> > EN_OVSDB_GET(engine_get_input("SB_port_group", node));
> > - input_data.sbrec_meter_table =
> > + input_data->sbrec_meter_table =
> > EN_OVSDB_GET(engine_get_input("SB_meter", node));
> > - input_data.sbrec_dns_table =
> > + input_data->sbrec_dns_table =
> > EN_OVSDB_GET(engine_get_input("SB_dns", node));
> > - input_data.sbrec_ip_multicast_table =
> > + input_data->sbrec_ip_multicast_table =
> > EN_OVSDB_GET(engine_get_input("SB_ip_multicast", node));
> > - input_data.sbrec_static_mac_binding_table =
> > + input_data->sbrec_static_mac_binding_table =
> > EN_OVSDB_GET(engine_get_input("SB_static_mac_binding", node));
> > - input_data.sbrec_chassis_template_var_table =
> > + input_data->sbrec_chassis_template_var_table =
> > EN_OVSDB_GET(engine_get_input("SB_chassis_template_var",
node));
> > - input_data.sbrec_mirror_table =
> > + input_data->sbrec_mirror_table =
> > EN_OVSDB_GET(engine_get_input("SB_mirror", node));
> > +}
> >
> > +void
> > +en_northd_run(struct engine_node *node, void *data)
> > +{
> > + const struct engine_context *eng_ctx = engine_get_context();
> > +
> > + struct northd_input input_data;
> > +
> > + northd_destroy(data);
> > + northd_init(data);
> > +
> > + northd_get_input_data(node, &input_data);
> > northd_run(&input_data, data,
> > eng_ctx->ovnnb_idl_txn,
> > eng_ctx->ovnsb_idl_txn);
> > @@ -148,17 +159,48 @@ northd_nb_nb_global_handler(struct engine_node
*node,
> > return true;
> > }
> >
> > -void *en_northd_init(struct engine_node *node OVS_UNUSED,
> > - struct engine_arg *arg OVS_UNUSED)
> > +bool
> > +northd_nb_logical_switch_handler(struct engine_node *node,
> > + void *data)
> > {
> > - struct northd_data *data = xmalloc(sizeof *data);
> > + const struct engine_context *eng_ctx = engine_get_context();
> > + struct northd_data *nd = data;
> > +
> > + struct northd_input input_data;
> > +
> > + northd_get_input_data(node, &input_data);
> > +
> > + if (!northd_handle_ls_changes(eng_ctx->ovnsb_idl_txn, &input_data,
nd)) {
> > + return false;
> > + }
> > +
> > + if (nd->change_tracked) {
> > + engine_set_node_state(node, EN_UPDATED);
> > + }
> > +
> > + return true;
> > +}
> > +
> > +void
> > +*en_northd_init(struct engine_node *node OVS_UNUSED,
> > + struct engine_arg *arg OVS_UNUSED)
> > +{
> > + struct northd_data *data = xzalloc(sizeof *data);
> >
> > northd_init(data);
> >
> > return data;
> > }
> >
> > -void en_northd_cleanup(void *data)
> > +void
> > +en_northd_cleanup(void *data)
> > {
> > northd_destroy(data);
> > }
> > +
> > +void
> > +en_northd_clear_tracked_data(void *data_)
> > +{
> > + struct northd_data *data = data_;
> > + destroy_northd_data_tracked_changes(data);
> > +}
> > diff --git a/northd/en-northd.h b/northd/en-northd.h
> > index 8d8343b459a6..a53a162bda48 100644
> > --- a/northd/en-northd.h
> > +++ b/northd/en-northd.h
> > @@ -13,6 +13,8 @@ void en_northd_run(struct engine_node *node
OVS_UNUSED, void *data OVS_UNUSED);
> > void *en_northd_init(struct engine_node *node OVS_UNUSED,
> > struct engine_arg *arg);
> > void en_northd_cleanup(void *data);
> > +void en_northd_clear_tracked_data(void *data);
> > bool northd_nb_nb_global_handler(struct engine_node *, void *data
OVS_UNUSED);
> > +bool northd_nb_logical_switch_handler(struct engine_node *, void
*data);
> >
> > #endif /* EN_NORTHD_H */
> > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> > index 863c9323c444..f992a9ec8420 100644
> > --- a/northd/inc-proc-northd.c
> > +++ b/northd/inc-proc-northd.c
> > @@ -128,7 +128,7 @@ enum sb_engine_node {
> >
> > /* Define engine nodes for other nodes. They should be defined as
static to
> > * avoid sparse errors. */
> > -static ENGINE_NODE(northd, "northd");
> > +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(northd, "northd");
> > static ENGINE_NODE(lflow, "lflow");
> > static ENGINE_NODE(mac_binding_aging, "mac_binding_aging");
> > static ENGINE_NODE(mac_binding_aging_waker, "mac_binding_aging_waker");
> > @@ -143,7 +143,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> > * on the second argument */
> > engine_add_input(&en_northd, &en_nb_nb_global,
> > northd_nb_nb_global_handler);
> > - engine_add_input(&en_northd, &en_nb_logical_switch, NULL);
> > + engine_add_input(&en_northd, &en_nb_logical_switch,
> > + northd_nb_logical_switch_handler);
> > engine_add_input(&en_northd, &en_nb_port_group, NULL);
> > engine_add_input(&en_northd, &en_nb_load_balancer, NULL);
> > engine_add_input(&en_northd, &en_nb_load_balancer_group, NULL);
> > @@ -252,6 +253,13 @@ void inc_proc_northd_init(struct ovsdb_idl_loop
*nb,
> > "sbrec_address_set_by_name",
> > sbrec_address_set_by_name);
> >
> > + struct ovsdb_idl_index *sbrec_fdb_by_dp_and_port
> > + = ovsdb_idl_index_create2(sb->idl, &sbrec_fdb_col_dp_key,
> > + &sbrec_fdb_col_port_key);
> > + engine_ovsdb_node_add_index(&en_sb_fdb,
> > + "sbrec_fdb_by_dp_and_port",
> > + sbrec_fdb_by_dp_and_port);
> > +
> > struct northd_data *northd_data =
> > engine_get_internal_data(&en_northd);
> > unixctl_command_register("debug/chassis-features-list", "", 0, 0,
> > diff --git a/northd/northd.c b/northd/northd.c
> > index d79f075681d9..1a4e24978642 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -19,6 +19,7 @@
> >
> > #include "debug.h"
> > #include "bitmap.h"
> > +#include "coverage.h"
> > #include "dirs.h"
> > #include "ipam.h"
> > #include "openvswitch/dynamic-string.h"
> > @@ -59,6 +60,8 @@
> >
> > VLOG_DEFINE_THIS_MODULE(northd);
> >
> > +COVERAGE_DEFINE(northd_run);
> > +
> > static bool controller_event_en;
> > static bool lflow_hash_lock_initialized = false;
> >
> > @@ -807,13 +810,20 @@ ovn_datapath_create(struct hmap *datapaths, const
struct uuid *key,
> > od->port_key_hint = 0;
> > hmap_insert(datapaths, &od->key_node, uuid_hash(&od->key));
> > od->lr_group = NULL;
> > - ovs_list_init(&od->port_list);
> > + hmap_init(&od->ports);
> > return od;
> > }
> >
> > static void ovn_ls_port_group_destroy(struct hmap *nb_pgs);
> > static void destroy_mcast_info_for_datapath(struct ovn_datapath *od);
> >
> > +static void
> > +destroy_ports_for_datapath(struct ovn_datapath *od)
> > +{
> > + ovs_assert(hmap_is_empty(&od->ports));
> > + hmap_destroy(&od->ports);
> > +}
> > +
> > static void
> > ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od)
> > {
> > @@ -834,6 +844,7 @@ ovn_datapath_destroy(struct hmap *datapaths, struct
ovn_datapath *od)
> > free(od->l3dgw_ports);
> > ovn_ls_port_group_destroy(&od->nb_pgs);
> > destroy_mcast_info_for_datapath(od);
> > + destroy_ports_for_datapath(od);
> >
> > free(od);
> > }
> > @@ -1480,6 +1491,9 @@ struct ovn_port {
> > struct lport_addresses *ps_addrs; /* Port security addresses. */
> > unsigned int n_ps_addrs;
> >
> > + bool lsp_can_be_inc_processed; /* If it can be incrementally
processed when
> > + the port changes. */
> > +
> > /* Logical router port data. */
> > const struct nbrec_logical_router_port *nbrp; /* May be NULL. */
> >
> > @@ -1521,11 +1535,16 @@ struct ovn_port {
> >
> > struct ovs_list list; /* In list of similar records. */
> >
> > - struct ovs_list dp_node;
> > + struct hmap_node dp_node; /* Node in od->ports. */
> >
> > struct lport_addresses proxy_arp_addrs;
> > +
> > + /* Temporarily used for traversing a list (or hmap) of ports. */
> > + bool visited;
> > };
> >
> > +static bool lsp_can_be_inc_processed(const struct
nbrec_logical_switch_port *);
> > +
> > static bool
> > is_l3dgw_port(const struct ovn_port *op)
> > {
> > @@ -1585,6 +1604,9 @@ ovn_port_set_nb(struct ovn_port *op,
> > const struct nbrec_logical_router_port *nbrp)
> > {
> > op->nbsp = nbsp;
> > + if (nbsp) {
> > + op->lsp_can_be_inc_processed = lsp_can_be_inc_processed(nbsp);
> > + }
> > op->nbrp = nbrp;
> > init_mcast_port_info(&op->mcast_info, op->nbsp, op->nbrp);
> > }
> > @@ -1610,35 +1632,46 @@ ovn_port_create(struct hmap *ports, const char
*key,
> > }
> >
> > static void
> > -ovn_port_destroy(struct hmap *ports, struct ovn_port *port)
> > +ovn_port_destroy_orphan(struct ovn_port *port)
> > {
> > - if (port) {
> > - /* Don't remove port->list. It is used within build_ports()
as a
> > - * private list and once we've exited that function it is not
safe to
> > - * use it. */
> > - hmap_remove(ports, &port->key_node);
> > + if (port->tunnel_key) {
> > + ovs_assert(port->od);
> > + ovn_free_tnlid(&port->od->port_tnlids, port->tunnel_key);
> > + }
> > + for (int i = 0; i < port->n_lsp_addrs; i++) {
> > + destroy_lport_addresses(&port->lsp_addrs[i]);
> > + }
> > + free(port->lsp_addrs);
> >
> > - if (port->peer) {
> > - port->peer->peer = NULL;
> > - }
> > + if (port->peer) {
> > + port->peer->peer = NULL;
> > + }
> >
> > - for (int i = 0; i < port->n_lsp_addrs; i++) {
> > - destroy_lport_addresses(&port->lsp_addrs[i]);
> > - }
> > - free(port->lsp_addrs);
> > + for (int i = 0; i < port->n_ps_addrs; i++) {
> > + destroy_lport_addresses(&port->ps_addrs[i]);
> > + }
> > + free(port->ps_addrs);
> >
> > - for (int i = 0; i < port->n_ps_addrs; i++) {
> > - destroy_lport_addresses(&port->ps_addrs[i]);
> > - }
> > - free(port->ps_addrs);
> > + destroy_routable_addresses(&port->routables);
> >
> > - destroy_routable_addresses(&port->routables);
> > + destroy_lport_addresses(&port->lrp_networks);
> > + destroy_lport_addresses(&port->proxy_arp_addrs);
> > + free(port->json_key);
> > + free(port->key);
> > + free(port);
> > +}
> >
> > - destroy_lport_addresses(&port->lrp_networks);
> > - destroy_lport_addresses(&port->proxy_arp_addrs);
> > - free(port->json_key);
> > - free(port->key);
> > - free(port);
> > +static void
> > +ovn_port_destroy(struct hmap *ports, struct ovn_port *port)
> > +{
> > + if (port) {
> > + /* Don't remove port->list. The node should be removed from
such lists
> > + * before calling this function. */
>
> nit: Please update the comment accordingly (from list to hmap)
This comment is indeed for the port->list. So I kept it as is.
>
>
>
> > + hmap_remove(ports, &port->key_node);
> > + if (port->od && !port->l3dgw_port) {
> > + hmap_remove(&port->od->ports, &port->dp_node);
> > + }
> > + ovn_port_destroy_orphan(port);
> > }
> > }
> >
> > @@ -2408,6 +2441,53 @@ tag_alloc_create_new_tag(struct hmap
*tag_alloc_table,
> > }
> >
> >
> > +static void
> > +parse_lsp_addrs(struct ovn_port *op)
> > +{
> > + const struct nbrec_logical_switch_port *nbsp = op->nbsp;
> > + ovs_assert(nbsp);
> > + op->lsp_addrs
> > + = xmalloc(sizeof *op->lsp_addrs * nbsp->n_addresses);
> > + for (size_t j = 0; j < nbsp->n_addresses; j++) {
> > + if (!strcmp(nbsp->addresses[j], "unknown")) {
> > + op->has_unknown = true;
> > + continue;
> > + }
> > + if (!strcmp(nbsp->addresses[j], "router")) {
> > + continue;
> > + }
> > + if (is_dynamic_lsp_address(nbsp->addresses[j])) {
> > + continue;
> > + } else if (!extract_lsp_addresses(nbsp->addresses[j],
> > + &op->lsp_addrs[op->n_lsp_addrs])) {
> > + static struct vlog_rate_limit rl
> > + = VLOG_RATE_LIMIT_INIT(1, 1);
> > + VLOG_INFO_RL(&rl, "invalid syntax '%s' in logical "
> > + "switch port addresses. No MAC "
> > + "address found",
> > + op->nbsp->addresses[j]);
> > + continue;
> > + }
> > + op->n_lsp_addrs++;
> > + }
> > + op->n_lsp_non_router_addrs = op->n_lsp_addrs;
> > +
> > + op->ps_addrs
> > + = xmalloc(sizeof *op->ps_addrs * nbsp->n_port_security);
> > + for (size_t j = 0; j < nbsp->n_port_security; j++) {
> > + if (!extract_lsp_addresses(nbsp->port_security[j],
> > + &op->ps_addrs[op->n_ps_addrs])) {
> > + static struct vlog_rate_limit rl
> > + = VLOG_RATE_LIMIT_INIT(1, 1);
> > + VLOG_INFO_RL(&rl, "invalid syntax '%s' in port "
> > + "security. No MAC address found",
> > + op->nbsp->port_security[j]);
> > + continue;
> > + }
> > + op->n_ps_addrs++;
> > + }
> > +}
> > +
> > static void
> > join_logical_ports(const struct sbrec_port_binding_table
*sbrec_pb_table,
> > struct hmap *ls_datapaths, struct hmap
*lr_datapaths,
> > @@ -2504,49 +2584,11 @@ join_logical_ports(const struct
sbrec_port_binding_table *sbrec_pb_table,
> > od->has_vtep_lports = true;
> > }
> >
> > - op->lsp_addrs
> > - = xmalloc(sizeof *op->lsp_addrs * nbsp->n_addresses);
> > - for (size_t j = 0; j < nbsp->n_addresses; j++) {
> > - if (!strcmp(nbsp->addresses[j], "unknown")) {
> > - op->has_unknown = true;
> > - continue;
> > - }
> > - if (!strcmp(nbsp->addresses[j], "router")) {
> > - continue;
> > - }
> > - if (is_dynamic_lsp_address(nbsp->addresses[j])) {
> > - continue;
> > - } else if (!extract_lsp_addresses(nbsp->addresses[j],
> > -
&op->lsp_addrs[op->n_lsp_addrs])) {
> > - static struct vlog_rate_limit rl
> > - = VLOG_RATE_LIMIT_INIT(1, 1);
> > - VLOG_INFO_RL(&rl, "invalid syntax '%s' in logical "
> > - "switch port addresses. No MAC "
> > - "address found",
> > - op->nbsp->addresses[j]);
> > - continue;
> > - }
> > - op->n_lsp_addrs++;
> > - }
> > - op->n_lsp_non_router_addrs = op->n_lsp_addrs;
> > -
> > - op->ps_addrs
> > - = xmalloc(sizeof *op->ps_addrs *
nbsp->n_port_security);
> > - for (size_t j = 0; j < nbsp->n_port_security; j++) {
> > - if (!extract_lsp_addresses(nbsp->port_security[j],
> > -
&op->ps_addrs[op->n_ps_addrs])) {
> > - static struct vlog_rate_limit rl
> > - = VLOG_RATE_LIMIT_INIT(1, 1);
> > - VLOG_INFO_RL(&rl, "invalid syntax '%s' in port "
> > - "security. No MAC address found",
> > - op->nbsp->port_security[j]);
> > - continue;
> > - }
> > - op->n_ps_addrs++;
> > - }
> > + parse_lsp_addrs(op);
> >
> > op->od = od;
> > - ovs_list_push_back(&od->port_list, &op->dp_node);
> > + hmap_insert(&od->ports, &op->dp_node,
> > + hmap_node_hash(&op->key_node));
> > tag_alloc_add_existing_tags(tag_alloc_table, nbsp);
> > }
> > }
> > @@ -2593,7 +2635,8 @@ join_logical_ports(const struct
sbrec_port_binding_table *sbrec_pb_table,
> >
> > op->lrp_networks = lrp_networks;
> > op->od = od;
> > - ovs_list_push_back(&od->port_list, &op->dp_node);
> > + hmap_insert(&od->ports, &op->dp_node,
> > + hmap_node_hash(&op->key_node));
> >
> > if (!od->redirect_bridged) {
> > const char *redirect_type =
> > @@ -3314,6 +3357,10 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn
*ovnsb_txn,
> > struct smap new;
> > smap_init(&new);
> > if (is_cr_port(op)) {
> > + ovs_assert(sbrec_chassis_by_name);
> > + ovs_assert(sbrec_chassis_by_hostname);
> > + ovs_assert(sbrec_ha_chassis_grp_by_name);
> > + ovs_assert(active_ha_chassis_grps);
> > const char *redirect_type = smap_get(&op->nbrp->options,
> > "redirect-type");
> >
> > @@ -3423,8 +3470,10 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn
*ovnsb_txn,
> > struct smap options;
> >
> > if (has_qos && !queue_id) {
> > + ovs_assert(queue_id_bitmap);
> > queue_id = allocate_queueid(queue_id_bitmap);
> > } else if (!has_qos && queue_id) {
> > + ovs_assert(queue_id_bitmap);
> > bitmap_set0(queue_id_bitmap, queue_id);
> > queue_id = 0;
> > }
> > @@ -3473,6 +3522,10 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn
*ovnsb_txn,
> > sbrec_port_binding_set_nat_addresses(op->sb, NULL, 0);
> >
> > if (!strcmp(op->nbsp->type, "external")) {
> > + ovs_assert(sbrec_chassis_by_name);
> > + ovs_assert(sbrec_chassis_by_hostname);
> > + ovs_assert(sbrec_ha_chassis_grp_by_name);
> > + ovs_assert(active_ha_chassis_grps);
> > if (op->nbsp->ha_chassis_group) {
> > sync_ha_chassis_group_for_sbpb(
> > ovnsb_txn, sbrec_chassis_by_name,
> > @@ -3729,6 +3782,24 @@ cleanup_stale_fdb_entries(const struct
sbrec_fdb_table *sbrec_fdb_table,
> > }
> > }
> >
> > +static void
> > +delete_fdb_entry(struct ovsdb_idl_index *sbrec_fdb_by_dp_and_port,
> > + uint32_t dp_key, uint32_t port_key)
> > +{
> > + struct sbrec_fdb *target =
> > + sbrec_fdb_index_init_row(sbrec_fdb_by_dp_and_port);
> > + sbrec_fdb_index_set_dp_key(target, dp_key);
> > + sbrec_fdb_index_set_port_key(target, port_key);
> > +
> > + struct sbrec_fdb *fdb_e =
sbrec_fdb_index_find(sbrec_fdb_by_dp_and_port,
> > + target);
> > + sbrec_fdb_index_destroy_row(target);
> > +
> > + if (fdb_e) {
> > + sbrec_fdb_delete(fdb_e);
> > + }
> > +}
> > +
> > struct service_monitor_info {
> > struct hmap_node hmap_node;
> > const struct sbrec_service_monitor *sbrec_mon;
> > @@ -3820,14 +3891,15 @@ ovn_lb_svc_create(struct ovsdb_idl_txn
*ovnsb_txn, struct ovn_northd_lb *lb,
> > }
> > ds_destroy(&key);
> >
> > - backend_nb->op = op;
> > - backend_nb->svc_mon_src_ip = svc_mon_src_ip;
> > -
> > if (!lb_vip_nb->lb_health_check || !op || !svc_mon_src_ip
||
> > !lsp_is_enabled(op->nbsp)) {
> > + free(svc_mon_src_ip);
> > continue;
> > }
> >
> > + backend_nb->op = op;
> > + backend_nb->svc_mon_src_ip = svc_mon_src_ip;
> > +
> > const char *protocol = lb->nlb->protocol;
> > if (!protocol || !protocol[0]) {
> > protocol = "tcp";
> > @@ -4155,7 +4227,7 @@ build_lrouter_lb_reachable_ips(struct
ovn_datapath *od,
> > ovs_be32 vip_ip4 =
in6_addr_get_mapped_ipv4(&lb->vips[i].vip);
> > struct ovn_port *op;
> >
> > - LIST_FOR_EACH (op, dp_node, &od->port_list) {
> > + HMAP_FOR_EACH (op, dp_node, &od->ports) {
> > if (lrouter_port_ipv4_reachable(op, vip_ip4)) {
> > sset_add(&od->lb_ips->ips_v4_reachable,
> > lb->vips[i].vip_str);
> > @@ -4165,7 +4237,7 @@ build_lrouter_lb_reachable_ips(struct
ovn_datapath *od,
> > } else {
> > struct ovn_port *op;
> >
> > - LIST_FOR_EACH (op, dp_node, &od->port_list) {
> > + HMAP_FOR_EACH (op, dp_node, &od->ports) {
> > if (lrouter_port_ipv6_reachable(op, &lb->vips[i].vip))
{
> > sset_add(&od->lb_ips->ips_v6_reachable,
> > lb->vips[i].vip_str);
> > @@ -4538,7 +4610,10 @@ ovn_port_add_tnlid(struct ovn_port *op, uint32_t
tunnel_key)
> > return added;
> > }
> >
> > -static void
> > +/* Returns false if the requested key is confict with another
allocated key, so
> > + * that the I-P engine can fallback to recompute if needed; otherwise
return
> > + * true (even if the key is not allocated). */
> > +static bool
> > ovn_port_assign_requested_tnl_id(
> > const struct sbrec_chassis_table *sbrec_chassis_table, struct
ovn_port *op)
> > {
> > @@ -4553,7 +4628,7 @@ ovn_port_assign_requested_tnl_id(
> > VLOG_WARN_RL(&rl, "Tunnel key %"PRIu32" for port %s "
> > "is incompatible with VXLAN",
> > tunnel_key, op_get_name(op));
> > - return;
> > + return true;
> > }
> > if (!ovn_port_add_tnlid(op, tunnel_key)) {
> > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
1);
> > @@ -4561,11 +4636,13 @@ ovn_port_assign_requested_tnl_id(
> > "%"PRIu32" as another LSP or LRP",
> > op->nbsp ? "switch" : "router",
> > op_get_name(op), tunnel_key);
> > + return false;
> > }
> > }
> > + return true;
> > }
> >
> > -static void
> > +static bool
> > ovn_port_allocate_key(const struct sbrec_chassis_table
*sbrec_chassis_table,
> > struct hmap *ports,
> > struct ovn_port *op)
> > @@ -4581,8 +4658,10 @@ ovn_port_allocate_key(const struct
sbrec_chassis_table *sbrec_chassis_table,
> > }
> > ovs_list_remove(&op->list);
> > ovn_port_destroy(ports, op);
> > + return false;
> > }
> > }
> > + return true;
> > }
> >
> > /* Updates the southbound Port_Binding table so that it contains the
logical
> > @@ -4605,6 +4684,8 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn,
> > struct hmap *ls_ports, struct hmap *lr_ports)
> > {
> > struct ovs_list sb_only, nb_only, both;
> > + /* XXX: Add tag_alloc_table and queue_id_bitmap as part of
northd_data
> > + * to improve I-P. */
> > struct hmap tag_alloc_table = HMAP_INITIALIZER(&tag_alloc_table);
> > unsigned long *queue_id_bitmap =
bitmap_allocate(QDISC_MAX_QUEUE_ID + 1);
> > bitmap_set1(queue_id_bitmap, 0);
> > @@ -4711,6 +4792,329 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn,
> > sset_destroy(&active_ha_chassis_grps);
> > }
> >
> > +void
> > +destroy_northd_data_tracked_changes(struct northd_data *nd)
> > +{
> > + struct ls_change *ls_change;
> > + LIST_FOR_EACH_SAFE (ls_change, list_node,
> > + &nd->tracked_ls_changes.updated) {
> > + struct ovn_port *op;
> > + LIST_FOR_EACH (op, list, &ls_change->added_ports) {
> > + ovs_list_remove(&op->list);
> > + }
> > + LIST_FOR_EACH (op, list, &ls_change->updated_ports) {
> > + ovs_list_remove(&op->list);
> > + }
> > + LIST_FOR_EACH_SAFE (op, list, &ls_change->deleted_ports) {
> > + ovs_list_remove(&op->list);
> > + ovn_port_destroy_orphan(op);
> > + }
> > + ovs_list_remove(&ls_change->list_node);
> > + free(ls_change);
> > + }
> > +
> > + nd->change_tracked = false;
> > +}
> > +
> > +/* Check if a changed LSP can be handled incrementally within the I-P
engine
> > + * node en_northd.
> > + */
> > +static bool
> > +lsp_can_be_inc_processed(const struct nbrec_logical_switch_port *nbsp)
> > +{
> > + /* Currently only support normal VIF. */
> nit: s/Currently only support normal VIF/ Support only normal VIF for now
>
>
> > + if (nbsp->type[0]) {
> > + return false;
> > + }
> > +
> > + /* Currently not support tag allocation. */
> nit: s/Currently not support tag allocation/ Do not support tag
> allocation for now
>
> Same small nits for below comments.
>
> I'm fine if you want to ignore these.
>
Thanks for the suggestion! Updated.
Regards,
Han
>
> > + if ((nbsp->parent_name && nbsp->parent_name[0]) || nbsp->tag ||
> > + nbsp->tag_request) {
> > + return false;
> > + }
> > +
> > + /* Currently not support port with qos settings (need special
handling for
> > + * qdisc_queue_id sync. */
> > + if (port_has_qos_params( ->options)) {
> > + return false;
> > + }
> > +
> > + for (size_t j = 0; j < nbsp->n_addresses; j++) {
> > + /* Currently not support dynamic address handling. */
> > + if (is_dynamic_lsp_address(nbsp->addresses[j])) {
> > + return false;
> > + }
> > + /* Currently not support "unknown" address handling. XXX:
Need to
> > + * handle od->has_unknown change and track it when the first
LSP with
> > + * 'unknown' is added or when the last one is removed. */
> > + if (!strcmp(nbsp->addresses[j], "unknown")) {
> > + return false;
> > + }
> > + }
> > +
> > + return true;
> > +}
> > +
> > +static bool
> > +ls_port_has_changed(const struct nbrec_logical_switch_port *old,
> > + const struct nbrec_logical_switch_port *new)
> > +{
> > + if (old != new) {
> > + return true;
> > + }
> > + /* XXX: Need a better OVSDB IDL interface for this check. */
> > + return (nbrec_logical_switch_port_row_get_seqno(new,
> > + OVSDB_IDL_CHANGE_MODIFY) > 0);
> > +}
> > +
> > +static struct ovn_port *
> > +ovn_port_find_in_datapath(struct ovn_datapath *od, const char *name)
> > +{
> > + struct ovn_port *op;
> > + HMAP_FOR_EACH_WITH_HASH (op, dp_node, hash_string(name, 0),
&od->ports) {
> > + if (!strcmp(op->key, name)) {
> > + return op;
> > + }
> > + }
> > + return NULL;
> > +}
> > +
> > +static struct ovn_port *
> > +ls_port_create(struct ovsdb_idl_txn *ovnsb_txn, struct hmap *ls_ports,
> > + const char *key, const struct nbrec_logical_switch_port
*nbsp,
> > + struct ovn_datapath *od, const struct
sbrec_port_binding *sb,
> > + const struct sbrec_mirror_table *sbrec_mirror_table,
> > + const struct sbrec_chassis_table *sbrec_chassis_table,
> > + struct ovsdb_idl_index *sbrec_chassis_by_name,
> > + struct ovsdb_idl_index *sbrec_chassis_by_hostname)
> > +{
> > + struct ovn_port *op = ovn_port_create(ls_ports, key, nbsp, NULL,
> > + NULL);
> > + parse_lsp_addrs(op);
> > + op->od = od;
> > + hmap_insert(&od->ports, &op->dp_node,
hmap_node_hash(&op->key_node));
> > +
> > + /* Assign explicitly requested tunnel ids first. */
> > + if (!ovn_port_assign_requested_tnl_id(sbrec_chassis_table, op)) {
> > + return NULL;
> > + }
> > + if (sb) {
> > + op->sb = sb;
> > + /* Keep nonconflicting tunnel IDs that are already assigned. */
> > + if (!op->tunnel_key) {
> > + ovn_port_add_tnlid(op, op->sb->tunnel_key);
> > + }
> > + } else {
> > + /* XXX: the new SB port_binding will change in IDL, so need to
handle
> > + * SB port_binding updates incrementally to achieve end-to-end
> > + * incremental processing. */
> > + op->sb = sbrec_port_binding_insert(ovnsb_txn);
> > + sbrec_port_binding_set_logical_port(op->sb, op->key);
> > + }
> > + /* Assign new tunnel ids where needed. */
> > + if (!ovn_port_allocate_key(sbrec_chassis_table, ls_ports, op)) {
> > + return NULL;
> > + }
> > + ovn_port_update_sbrec(ovnsb_txn, sbrec_chassis_by_name,
> > + sbrec_chassis_by_hostname, NULL,
sbrec_mirror_table,
> > + op, NULL, NULL);
> > + return op;
> > +}
> > +
> > +static bool
> > +check_ls_changes_other_than_lsp(const struct nbrec_logical_switch *ls)
> > +{
> > + /* Check if the columns are changed in this row. */
> > + enum nbrec_logical_switch_column_id col;
> > + for (col = 0; col < NBREC_LOGICAL_SWITCH_N_COLUMNS; col++) {
> > + if (nbrec_logical_switch_is_updated(ls, col) &&
> > + col != NBREC_LOGICAL_SWITCH_COL_PORTS) {
> > + return true;
> > + }
> > + }
> > +
> > + /* Check if the referenced rows are changed.
> > + XXX: Need a better OVSDB IDL interface for this check. */
> > + for (size_t i = 0; i < ls->n_acls; i++) {
> > + if (nbrec_acl_row_get_seqno(ls->acls[i],
> > + OVSDB_IDL_CHANGE_MODIFY) > 0) {
> > + return true;
> > + }
> > + }
> > + if (ls->copp && nbrec_copp_row_get_seqno(ls->copp,
> > + OVSDB_IDL_CHANGE_MODIFY) > 0) {
> > + return true;
> > + }
> > + for (size_t i = 0; i < ls->n_dns_records; i++) {
> > + if (nbrec_dns_row_get_seqno(ls->dns_records[i],
> > + OVSDB_IDL_CHANGE_MODIFY) > 0) {
> > + return true;
> > + }
> > + }
> > + for (size_t i = 0; i < ls->n_forwarding_groups; i++) {
> > + if
(nbrec_forwarding_group_row_get_seqno(ls->forwarding_groups[i],
> > + OVSDB_IDL_CHANGE_MODIFY) > 0) {
> > + return true;
> > + }
> > + }
> > + for (size_t i = 0; i < ls->n_load_balancer; i++) {
> > + if (nbrec_load_balancer_row_get_seqno(ls->load_balancer[i],
> > + OVSDB_IDL_CHANGE_MODIFY) > 0) {
> > + return true;
> > + }
> > + }
> > + for (size_t i = 0; i < ls->n_load_balancer_group; i++) {
> > + if
(nbrec_load_balancer_group_row_get_seqno(ls->load_balancer_group[i],
> > + OVSDB_IDL_CHANGE_MODIFY) > 0) {
> > + return true;
> > + }
> > + }
> > + for (size_t i = 0; i < ls->n_qos_rules; i++) {
> > + if (nbrec_qos_row_get_seqno(ls->qos_rules[i],
> > + OVSDB_IDL_CHANGE_MODIFY) > 0) {
> > + return true;
> > + }
> > + }
> > + return false;
> > +}
> > +
> > +/* Return true if changes are handled incrementally, false otherwise.
> > + * When there are any changes, try to track what's exactly changed and
set
> > + * northd_data->change_tracked accordingly: change tracked - true,
otherwise,
> > + * false. */
> > +bool
> > +northd_handle_ls_changes(struct ovsdb_idl_txn *ovnsb_idl_txn,
> > + const struct northd_input *ni,
> > + struct northd_data *nd)
> > +{
> > + const struct nbrec_logical_switch *changed_ls;
> > + struct ls_change *ls_change = NULL;
> > +
> > + NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (changed_ls,
> > +
ni->nbrec_logical_switch_table) {
> > + ls_change = NULL;
> > + if (nbrec_logical_switch_is_new(changed_ls) ||
> > + nbrec_logical_switch_is_deleted(changed_ls)) {
> > + goto fail;
> > + }
> > + struct ovn_datapath *od = ovn_datapath_find(
> > + &nd->ls_datapaths.datapaths,
> > + &changed_ls->header_.uuid);
> > + if (!od) {
> > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
1);
> > + VLOG_WARN_RL(&rl, "Internal error: a tracked updated LS
doesn't "
> > + "exist in ls_datapaths: "UUID_FMT,
> > + UUID_ARGS(&changed_ls->header_.uuid));
> > + goto fail;
> > + }
> > +
> > + /* Now only able to handle lsp changes. */
> > + if (check_ls_changes_other_than_lsp(changed_ls)) {
> > + goto fail;
> > + }
> > +
> > + ls_change = xzalloc(sizeof *ls_change);
> > + ls_change->od = od;
> > + ovs_list_init(&ls_change->added_ports);
> > + ovs_list_init(&ls_change->deleted_ports);
> > + ovs_list_init(&ls_change->updated_ports);
> > +
> > + struct ovn_port *op;
> > + HMAP_FOR_EACH (op, dp_node, &od->ports) {
> > + op->visited = false;
> > + }
> > +
> > + /* Compare the individual ports in the old and new Logical
Switches */
> > + for (size_t j = 0; j < changed_ls->n_ports; ++j) {
> > + struct nbrec_logical_switch_port *new_nbsp =
changed_ls->ports[j];
> > + op = ovn_port_find_in_datapath(od, new_nbsp->name);
> > +
> > + if (!op) {
> > + if (!lsp_can_be_inc_processed(new_nbsp)) {
> > + goto fail;
> > + }
> > + op = ls_port_create(ovnsb_idl_txn, &nd->ls_ports,
> > + new_nbsp->name, new_nbsp, od, NULL,
> > + ni->sbrec_mirror_table,
> > + ni->sbrec_chassis_table,
> > + ni->sbrec_chassis_by_name,
> > + ni->sbrec_chassis_by_hostname);
> > + if (!op) {
> > + goto fail;
> > + }
> > + ovs_list_push_back(&ls_change->added_ports,
> > + &op->list);
> > + } else if (ls_port_has_changed(op->nbsp, new_nbsp)) {
> > + /* Existing port updated */
> > + bool temp = false;
> > + if (lsp_is_type_changed(op->sb, new_nbsp, &temp) ||
> > + !op->lsp_can_be_inc_processed ||
> > + !lsp_can_be_inc_processed(new_nbsp)) {
> > + goto fail;
> > + }
> > + const struct sbrec_port_binding *sb = op->sb;
> > + if (sset_contains(&nd->svc_monitor_lsps,
new_nbsp->name)) {
> > + /* This port is used for svc monitor, which may be
impacted
> > + * by this change. Fallback to recompute. */
> > + goto fail;
> > + }
> > + ovn_port_destroy(&nd->ls_ports, op);
> > + op = ls_port_create(ovnsb_idl_txn, &nd->ls_ports,
> > + new_nbsp->name, new_nbsp, od, sb,
> > + ni->sbrec_mirror_table,
> > + ni->sbrec_chassis_table,
> > + ni->sbrec_chassis_by_name,
> > + ni->sbrec_chassis_by_hostname);
> > + if (!op) {
> > + goto fail;
> > + }
> > + ovs_list_push_back(&ls_change->updated_ports,
&op->list);
> > + }
> > + op->visited = true;
> > + }
> > +
> > + /* Check for deleted ports */
> > + HMAP_FOR_EACH_SAFE (op, dp_node, &od->ports) {
> > + if (!op->visited) {
> > + if (!op->lsp_can_be_inc_processed) {
> > + goto fail;
> > + }
> > + if (sset_contains(&nd->svc_monitor_lsps, op->key)) {
> > + /* This port was used for svc monitor, which may be
> > + * impacted by this deletion. Fallback to
recompute. */
> > + goto fail;
> > + }
> > + ovs_list_push_back(&ls_change->deleted_ports,
> > + &op->list);
> > + hmap_remove(&nd->ls_ports, &op->key_node);
> > + hmap_remove(&od->ports, &op->dp_node);
> > + sbrec_port_binding_delete(op->sb);
> > + delete_fdb_entry(ni->sbrec_fdb_by_dp_and_port,
od->tunnel_key,
> > + op->tunnel_key);
> > + }
> > + }
> > +
> > + if (!ovs_list_is_empty(&ls_change->added_ports) ||
> > + !ovs_list_is_empty(&ls_change->updated_ports) ||
> > + !ovs_list_is_empty(&ls_change->deleted_ports)) {
> > + ovs_list_push_back(&nd->tracked_ls_changes.updated,
> > + &ls_change->list_node);
> > + } else {
> > + free(ls_change);
> > + }
> > + }
> > +
> > + if (!ovs_list_is_empty(&nd->tracked_ls_changes.updated)) {
> > + nd->change_tracked = true;
> > + }
> > + return true;
> > +
> > +fail:
> > + free(ls_change);
> > + destroy_northd_data_tracked_changes(nd);
> > + return false;
> > +}
> > +
> > struct multicast_group {
> > const char *name;
> > uint16_t key; /*
OVN_MIN_MULTICAST...OVN_MAX_MULTICAST. */
> > @@ -6072,7 +6476,7 @@ build_interconn_mcast_snoop_flows(struct
ovn_datapath *od,
> >
> > struct ovn_port *op;
> >
> > - LIST_FOR_EACH (op, dp_node, &od->port_list) {
> > + HMAP_FOR_EACH (op, dp_node, &od->ports) {
> > if (!lsp_is_remote(op->nbsp)) {
> > continue;
> > }
> > @@ -12394,7 +12798,7 @@ build_mcast_lookup_flows_for_lrouter(
> > * own mac addresses.
> > */
> > struct ovn_port *op;
> > - LIST_FOR_EACH (op, dp_node, &od->port_list) {
> > + HMAP_FOR_EACH (op, dp_node, &od->ports) {
> > ds_clear(match);
> > ds_put_format(match, "eth.src == %s && igmp",
> > op->lrp_networks.ea_s);
> > @@ -16476,9 +16880,6 @@ destroy_datapaths_and_ports(struct
ovn_datapaths *ls_datapaths,
> > }
> > }
> >
> > - ovn_datapaths_destroy(ls_datapaths);
> > - ovn_datapaths_destroy(lr_datapaths);
> > -
> > struct ovn_port *port;
> > HMAP_FOR_EACH_SAFE (port, key_node, ls_ports) {
> > ovn_port_destroy(ls_ports, port);
> > @@ -16489,6 +16890,9 @@ destroy_datapaths_and_ports(struct
ovn_datapaths *ls_datapaths,
> > ovn_port_destroy(lr_ports, port);
> > }
> > hmap_destroy(lr_ports);
> > +
> > + ovn_datapaths_destroy(ls_datapaths);
> > + ovn_datapaths_destroy(lr_datapaths);
> > }
> >
> > void
> > @@ -16510,6 +16914,8 @@ northd_init(struct northd_data *data)
> > };
> > data->ovn_internal_version_changed = false;
> > sset_init(&data->svc_monitor_lsps);
> > + data->change_tracked = false;
> > + ovs_list_init(&data->tracked_ls_changes.updated);
> > }
> >
> > void
> > @@ -16976,6 +17382,7 @@ void northd_run(struct northd_input *input_data,
> > struct ovsdb_idl_txn *ovnnb_txn,
> > struct ovsdb_idl_txn *ovnsb_txn)
> > {
> > + COVERAGE_INC(northd_run);
> > stopwatch_start(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec());
> > ovnnb_db_run(input_data, data, ovnnb_txn, ovnsb_txn);
> > stopwatch_stop(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec());
> > diff --git a/northd/northd.h b/northd/northd.h
> > index b26828bb7111..1fd9bed477e7 100644
> > --- a/northd/northd.h
> > +++ b/northd/northd.h
> > @@ -65,6 +65,7 @@ struct northd_input {
> > struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name;
> > struct ovsdb_idl_index *sbrec_ip_mcast_by_dp;
> > struct ovsdb_idl_index *sbrec_static_mac_binding_by_lport_ip;
> > + struct ovsdb_idl_index *sbrec_fdb_by_dp_and_port;
> > };
> >
> > struct chassis_features {
> > @@ -83,6 +84,22 @@ struct ovn_datapaths {
> > struct ovn_datapath **array;
> > };
> >
> > +/* Track what's changed for a single LS.
> > + * Now only track port changes. */
> > +struct ls_change {
> > + struct ovs_list list_node;
> > + struct ovn_datapath *od;
> > + struct ovs_list added_ports;
> > + struct ovs_list deleted_ports;
> > + struct ovs_list updated_ports;
> > +};
> > +
> > +/* Track what's changed for logical switches.
> > + * Now only track updated ones (added or deleted may be supported in
the
> > + * future). */
> > +struct tracked_ls_changes {
> > + struct ovs_list updated; /* Contains struct ls_change */
> > +};
> >
> > struct northd_data {
> > /* Global state for 'en-northd'. */
> > @@ -98,6 +115,8 @@ struct northd_data {
> > bool ovn_internal_version_changed;
> > struct chassis_features features;
> > struct sset svc_monitor_lsps;
> > + bool change_tracked;
> > + struct tracked_ls_changes tracked_ls_changes;
> > };
> >
> > struct lflow_data {
> > @@ -292,13 +311,19 @@ struct ovn_datapath {
> > /* Port groups related to the datapath, used only when nbs is NOT
NULL. */
> > struct hmap nb_pgs;
> >
> > - struct ovs_list port_list;
> > + /* Map of ovn_port objects belonging to this datapath.
> > + * This map doesn't include derived ports. */
> > + struct hmap ports;
> > };
> >
> > void northd_run(struct northd_input *input_data,
> > struct northd_data *data,
> > struct ovsdb_idl_txn *ovnnb_txn,
> > struct ovsdb_idl_txn *ovnsb_txn);
> > +bool northd_handle_ls_changes(struct ovsdb_idl_txn *,
> > + const struct northd_input *,
> > + struct northd_data *);
> > +void destroy_northd_data_tracked_changes(struct northd_data *);
> > void northd_destroy(struct northd_data *data);
> > void northd_init(struct northd_data *data);
> > void northd_indices_create(struct northd_data *data,
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index 6736429ae201..74ae84530112 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -9481,3 +9481,61 @@ AT_CHECK([ovn-sbctl lflow-list sw | grep
ls_out_pre_lb | grep priority=110 | gre
> >
> > AT_CLEANUP
> > ])
> > +
> > +OVN_FOR_EACH_NORTHD_NO_HV([
> > +AT_SETUP([LSP incremental processing])
> > +ovn_start
> > +
> > +net_add n1
> > +sim_add hv1
> > +as hv1
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.11
> > +ovs-vsctl add-port br-int lsp0-0 -- set interface lsp0-0
external_ids:iface-id=lsp0-0
> > +ovs-vsctl add-port br-int lsp0-1 -- set interface lsp0-1
external_ids:iface-id=lsp0-1
> > +ovs-vsctl add-port br-int lsp0-2 -- set interface lsp0-2
external_ids:iface-id=lsp0-2
> > +
> > +check ovn-nbctl --wait=hv ls-add ls0
> > +
> > +check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
> > +check ovn-nbctl --wait=hv lsp-add ls0 lsp0-0 -- lsp-set-addresses
lsp0-0 "unknown"
> > +OVS_WAIT_UNTIL([test `as northd ovn-appctl -t NORTHD_TYPE
inc-engine/show-stats northd recompute` = 5])
> > +OVS_WAIT_UNTIL([test `as northd ovn-appctl -t NORTHD_TYPE
inc-engine/show-stats lflow recompute` = 5])
> > +
> > +check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
> > +check ovn-nbctl --wait=hv lsp-add ls0 lsp0-1 -- lsp-set-addresses
lsp0-1 "aa:aa:aa:00:00:01 192.168.0.11"
> > +AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats
northd recompute], [0], [3
> > +])
> > +AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats
lflow recompute], [0], [6
> > +])
> > +
> > +check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
> > +check ovn-nbctl --wait=hv lsp-add ls0 lsp0-2 -- lsp-set-addresses
lsp0-2 "aa:aa:aa:00:00:02 192.168.0.12"
> > +AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats
northd recompute], [0], [3
> > +])
> > +AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats
lflow recompute], [0], [6
> > +])
> > +
> > +check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
> > +check ovn-nbctl --wait=hv lsp-del lsp0-1
> > +AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats
northd recompute], [0], [1
> > +])
> > +AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats
lflow recompute], [0], [2
> > +])
> > +
> > +check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
> > +check ovn-nbctl --wait=hv lsp-set-addresses lsp0-2 "aa:aa:aa:00:00:88
192.168.0.88"
> > +AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats
northd recompute], [0], [1
> > +])
> > +AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats
lflow recompute], [0], [2
> > +])
> > +
> > +# No change, no recompute
> > +check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
> > +check ovn-nbctl --wait=sb sync
> > +AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats
northd recompute], [0], [0
> > +])
> > +
> > +OVN_CLEANUP([hv1])
> > +AT_CLEANUP
> > +])
> > --
> > 2.30.2
> >
> >
> > _______________________________________________
> > dev mailing list
> > [email protected]
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev