diff mbox series

[ovs-dev,v2] ovn-controller: Fix port group I-P when they contain non-vif ports.

Message ID 20210630140054.29134-1-dceara@redhat.com
State Accepted
Headers show
Series [ovs-dev,v2] ovn-controller: Fix port group I-P when they contain non-vif ports. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot success github build: passed

Commit Message

Dumitru Ceara June 30, 2021, 2 p.m. UTC
It's valid that port_groups contain non-vif ports, they can actually
contain any type of logical_switch_port.

Also, there's no need to allocate a new sset containing the local ports'
names every time the I-P engine processes a change.  We were already
maintaining a set of "local_lport_ids".  These correspond to port
bindings that are relevant locally (including non-vif ports).  Extend
it to include the locally relevant lport names too and rename the
structure an its helper functions to related_lport*.

Reported-at: https://github.com/ovn-org/ovn/pull/61#issuecomment-865094163
Reported-by: Antonio Ojea <aojea@redhat.com>
Fixes: 0cfeba6b55e3 ("ovn-controller: Fix port group conjunction flow explosion problem.")
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
---
v2:
- Addressed Numan's and Han's comments:
  - add struct related_lports
  - add test case.
---
 controller/binding.c        | 79 ++++++++++++++++++-------------------
 controller/binding.h        | 31 ++++++++-------
 controller/lflow.c          |  2 +-
 controller/lflow.h          |  2 +-
 controller/ovn-controller.c | 48 +++++++++-------------
 tests/ovn.at                | 44 +++++++++++++++++++++
 6 files changed, 120 insertions(+), 86 deletions(-)

Comments

Han Zhou June 30, 2021, 11:03 p.m. UTC | #1
On Wed, Jun 30, 2021 at 7:01 AM Dumitru Ceara <dceara@redhat.com> wrote:
>
> It's valid that port_groups contain non-vif ports, they can actually
> contain any type of logical_switch_port.
>
> Also, there's no need to allocate a new sset containing the local ports'
> names every time the I-P engine processes a change.  We were already
> maintaining a set of "local_lport_ids".  These correspond to port
> bindings that are relevant locally (including non-vif ports).  Extend
> it to include the locally relevant lport names too and rename the
> structure an its helper functions to related_lport*.
>
> Reported-at: https://github.com/ovn-org/ovn/pull/61#issuecomment-865094163
> Reported-by: Antonio Ojea <aojea@redhat.com>
> Fixes: 0cfeba6b55e3 ("ovn-controller: Fix port group conjunction flow
explosion problem.")
> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> ---
> v2:
> - Addressed Numan's and Han's comments:
>   - add struct related_lports
>   - add test case.
> ---
>  controller/binding.c        | 79 ++++++++++++++++++-------------------
>  controller/binding.h        | 31 ++++++++-------
>  controller/lflow.c          |  2 +-
>  controller/lflow.h          |  2 +-
>  controller/ovn-controller.c | 48 +++++++++-------------
>  tests/ovn.at                | 44 +++++++++++++++++++++
>  6 files changed, 120 insertions(+), 86 deletions(-)
>
> diff --git a/controller/binding.c b/controller/binding.c
> index 7fde0fdbb..594babc98 100644
> --- a/controller/binding.c
> +++ b/controller/binding.c
> @@ -531,38 +531,41 @@ remove_local_lports(const char *iface_id, struct
binding_ctx_out *b_ctx)
>      }
>  }
>
> -/* Add a port binding ID (of the form "dp-key"_"port-key") to the set of
local
> - * lport IDs. Also track if the set has changed.
> +/* Add a port binding to the set of locally relevant lports.
> + * Also track if the set has changed.
>   */
>  static void
> -update_local_lport_ids(const struct sbrec_port_binding *pb,
> -                       struct binding_ctx_out *b_ctx)
> +update_related_lport(const struct sbrec_port_binding *pb,
> +                     struct binding_ctx_out *b_ctx)
>  {
>      char buf[16];
>      get_unique_lport_key(pb->datapath->tunnel_key, pb->tunnel_key,
>                           buf, sizeof(buf));
> -    if (sset_add(b_ctx->local_lport_ids, buf) != NULL) {
> -        b_ctx->local_lport_ids_changed = true;
> +    if (sset_add(&b_ctx->related_lports->lport_ids, buf) != NULL) {
> +        b_ctx->related_lports_changed = true;
>
>          if (b_ctx->tracked_dp_bindings) {
>              /* Add the 'pb' to the tracked_datapaths. */
>              tracked_binding_datapath_lport_add(pb,
b_ctx->tracked_dp_bindings);
>          }
>      }
> +    sset_add(&b_ctx->related_lports->lport_names, pb->logical_port);
>  }
>
> -/* Remove a port binding id from the set of local lport IDs. Also track
if
> - * the set has changed.
> +/* Remove a port binding id from the set of locally relevant lports.
> + * Also track if the set has changed.
>   */
>  static void
> -remove_local_lport_ids(const struct sbrec_port_binding *pb,
> -                       struct binding_ctx_out *b_ctx)
> +remove_related_lport(const struct sbrec_port_binding *pb,
> +                     struct binding_ctx_out *b_ctx)
>  {
>      char buf[16];
>      get_unique_lport_key(pb->datapath->tunnel_key, pb->tunnel_key,
>                           buf, sizeof(buf));
> -    if (sset_find_and_delete(b_ctx->local_lport_ids, buf)) {
> -        b_ctx->local_lport_ids_changed = true;
> +    sset_find_and_delete(&b_ctx->related_lports->lport_names,
> +                         pb->logical_port);
> +    if (sset_find_and_delete(&b_ctx->related_lports->lport_ids, buf)) {
> +        b_ctx->related_lports_changed = true;
>
>          if (b_ctx->tracked_dp_bindings) {
>              /* Add the 'pb' to the tracked_datapaths. */
> @@ -678,6 +681,20 @@ static struct binding_lport
*binding_lport_check_and_cleanup(
>
>  static char *get_lport_type_str(enum en_lport_type lport_type);
>
> +void
> +related_lports_init(struct related_lports *rp)
> +{
> +    sset_init(&rp->lport_names);
> +    sset_init(&rp->lport_ids);
> +}
> +
> +void
> +related_lports_destroy(struct related_lports *rp)
> +{
> +    sset_destroy(&rp->lport_names);
> +    sset_destroy(&rp->lport_ids);
> +}
> +
>  void
>  local_binding_data_init(struct local_binding_data *lbinding_data)
>  {
> @@ -1172,7 +1189,7 @@ release_binding_lport(const struct sbrec_chassis
*chassis_rec,
>                        struct binding_ctx_out *b_ctx_out)
>  {
>      if (is_binding_lport_this_chassis(b_lport, chassis_rec)) {
> -        remove_local_lport_ids(b_lport->pb, b_ctx_out);
> +        remove_related_lport(b_lport->pb, b_ctx_out);
>          if (!release_lport(b_lport->pb, sb_readonly,
>                             b_ctx_out->tracked_dp_bindings,
>                             b_ctx_out->if_mgr)) {
> @@ -1214,7 +1231,7 @@ consider_vif_lport_(const struct sbrec_port_binding
*pb,
>                                 pb->datapath, false,
>                                 b_ctx_out->local_datapaths,
>                                 b_ctx_out->tracked_dp_bindings);
> -            update_local_lport_ids(pb, b_ctx_out);
> +            update_related_lport(pb, b_ctx_out);
>              update_local_lports(pb->logical_port, b_ctx_out);
>              if (b_lport->lbinding->iface && qos_map &&
b_ctx_in->ovs_idl_txn) {
>                  get_qos_params(pb, qos_map);
> @@ -1405,7 +1422,7 @@ consider_virtual_lport(const struct
sbrec_port_binding *pb,
>       * its entry from the local_lport_ids if present.  This is required
>       * when a virtual port moves from one chassis to other.*/
>      if (!virtual_b_lport) {
> -        remove_local_lport_ids(pb, b_ctx_out);
> +        remove_related_lport(pb, b_ctx_out);
>      }
>
>      return true;
> @@ -1430,7 +1447,7 @@ consider_nonvif_lport_(const struct
sbrec_port_binding *pb,
>                             b_ctx_out->local_datapaths,
>                             b_ctx_out->tracked_dp_bindings);
>
> -        update_local_lport_ids(pb, b_ctx_out);
> +        update_related_lport(pb, b_ctx_out);
>          return claim_lport(pb, NULL, b_ctx_in->chassis_rec, NULL,
>                             !b_ctx_in->ovnsb_idl_txn, false,
>                             b_ctx_out->tracked_dp_bindings,
> @@ -1482,7 +1499,7 @@ consider_localnet_lport(const struct
sbrec_port_binding *pb,
>          get_qos_params(pb, qos_map);
>      }
>
> -    update_local_lport_ids(pb, b_ctx_out);
> +    update_related_lport(pb, b_ctx_out);
>  }
>
>  static bool
> @@ -1512,7 +1529,7 @@ consider_ha_lport(const struct sbrec_port_binding
*pb,
>                             pb->datapath, false,
>                             b_ctx_out->local_datapaths,
>                             b_ctx_out->tracked_dp_bindings);
> -        update_local_lport_ids(pb, b_ctx_out);
> +        update_related_lport(pb, b_ctx_out);
>      }
>
>      return consider_nonvif_lport_(pb, our_chassis, false, b_ctx_in,
b_ctx_out);
> @@ -1634,7 +1651,7 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct
binding_ctx_out *b_ctx_out)
>          case LP_PATCH:
>          case LP_LOCALPORT:
>          case LP_VTEP:
> -            update_local_lport_ids(pb, b_ctx_out);
> +            update_related_lport(pb, b_ctx_out);
>              break;
>
>          case LP_VIF:
> @@ -1895,7 +1912,7 @@ remove_pb_from_local_datapath(const struct
sbrec_port_binding *pb,
>                                struct binding_ctx_out *b_ctx_out,
>                                struct local_datapath *ld)
>  {
> -    remove_local_lport_ids(pb, b_ctx_out);
> +    remove_related_lport(pb, b_ctx_out);
>      if (!strcmp(pb->type, "patch") ||
>          !strcmp(pb->type, "l3gateway")) {
>          remove_local_datapath_peer_port(pb, ld,
b_ctx_out->local_datapaths);
> @@ -2502,7 +2519,7 @@ delete_done:
>          case LP_PATCH:
>          case LP_LOCALPORT:
>          case LP_VTEP:
> -            update_local_lport_ids(pb, b_ctx_out);
> +            update_related_lport(pb, b_ctx_out);
>              if (lport_type ==  LP_PATCH) {
>                  if (!ld) {
>                      /* If 'ld' for this lport is not present, then check
if
> @@ -2926,23 +2943,3 @@ cleanup:
>
>      return b_lport;
>  }
> -
> -struct sset *
> -binding_collect_local_binding_lports(struct local_binding_data
*lbinding_data)
> -{
> -    struct sset *lports = xzalloc(sizeof *lports);
> -    sset_init(lports);
> -    struct shash_node *shash_node;
> -    SHASH_FOR_EACH (shash_node, &lbinding_data->lports) {
> -        struct binding_lport *b_lport = shash_node->data;
> -        sset_add(lports, b_lport->name);
> -    }
> -    return lports;
> -}
> -
> -void
> -binding_destroy_local_binding_lports(struct sset *lports)
> -{
> -    sset_destroy(lports);
> -    free(lports);
> -}
> diff --git a/controller/binding.h b/controller/binding.h
> index 8f3289476..a08011ae2 100644
> --- a/controller/binding.h
> +++ b/controller/binding.h
> @@ -22,6 +22,7 @@
>  #include "openvswitch/hmap.h"
>  #include "openvswitch/uuid.h"
>  #include "openvswitch/list.h"
> +#include "sset.h"
>
>  struct hmap;
>  struct ovsdb_idl;
> @@ -56,6 +57,19 @@ struct binding_ctx_in {
>      const struct ovsrec_interface_table *iface_table;
>  };
>
> +/* Locally relevant port bindings, e.g., VIFs that might be bound
locally,
> + * patch ports.
> + */
> +struct related_lports {
> +    struct sset lport_names; /* Set of port names. */
> +    struct sset lport_ids;   /* Set of
<datapath-tunnel-key>_<port-tunnel-key>
> +                              * IDs for fast lookup.
> +                              */
> +};
> +
> +void related_lports_init(struct related_lports *);
> +void related_lports_destroy(struct related_lports *);
> +
>  struct binding_ctx_out {
>      struct hmap *local_datapaths;
>      struct local_binding_data *lbinding_data;
> @@ -65,11 +79,9 @@ struct binding_ctx_out {
>      /* Track if local_lports have been updated. */
>      bool local_lports_changed;
>
> -    /* sset of local lport ids in the format
> -     * <datapath-tunnel-key>_<port-tunnel-key>. */
> -    struct sset *local_lport_ids;
> -    /* Track if local_lport_ids has been updated. */
> -    bool local_lport_ids_changed;
> +    /* Port bindings that are relevant to the local chassis. */
> +    struct related_lports *related_lports;
> +    bool related_lports_changed;
>
>      /* Track if non-vif port bindings (e.g., patch, external) have been
>       * added/deleted.
> @@ -133,13 +145,4 @@ bool binding_handle_port_binding_changes(struct
binding_ctx_in *,
>  void binding_tracked_dp_destroy(struct hmap *tracked_datapaths);
>
>  void binding_dump_local_bindings(struct local_binding_data *, struct ds
*);
> -
> -/* Generates a sset of lport names from local_binding_data.
> - * Note: the caller is responsible for destroying and freeing the
returned
> - * sset, by calling binding_detroy_local_binding_lports(). */
> -struct sset *binding_collect_local_binding_lports(struct
local_binding_data *);
> -
> -/* Destroy and free the lports sset returned by
> - * binding_collect_local_binding_lports(). */
> -void binding_destroy_local_binding_lports(struct sset *lports);
>  #endif /* controller/binding.h */
> diff --git a/controller/lflow.c b/controller/lflow.c
> index 34eca135a..abb01f0ce 100644
> --- a/controller/lflow.c
> +++ b/controller/lflow.c
> @@ -625,7 +625,7 @@ add_matches_to_flow_table(const struct
sbrec_logical_flow *lflow,
>                  get_unique_lport_key(dp_id, port_id, buf, sizeof(buf));
>                  lflow_resource_add(l_ctx_out->lfrr,
REF_TYPE_PORTBINDING, buf,
>                                     &lflow->header_.uuid);
> -                if (!sset_contains(l_ctx_in->local_lport_ids, buf)) {
> +                if (!sset_contains(l_ctx_in->related_lport_ids, buf)) {
>                      VLOG_DBG("lflow "UUID_FMT
>                               " port %s in match is not local, skip",
>                               UUID_ARGS(&lflow->header_.uuid),
> diff --git a/controller/lflow.h b/controller/lflow.h
> index e98edf81d..699f9c2d5 100644
> --- a/controller/lflow.h
> +++ b/controller/lflow.h
> @@ -144,7 +144,7 @@ struct lflow_ctx_in {
>      const struct shash *addr_sets;
>      const struct shash *port_groups;
>      const struct sset *active_tunnels;
> -    const struct sset *local_lport_ids;
> +    const struct sset *related_lport_ids;
>  };
>
>  struct lflow_ctx_out {
> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> index b6afb8fb9..3bb8b22eb 100644
> --- a/controller/ovn-controller.c
> +++ b/controller/ovn-controller.c
> @@ -1014,9 +1014,10 @@ struct ed_type_runtime_data {
>       * local hypervisor, and localnet ports. */
>      struct sset local_lports;
>
> -    /* Contains the same ports as local_lports, but in the format:
> -     * <datapath-tunnel-key>_<port-tunnel-key> */
> -    struct sset local_lport_ids;
> +    /* Port bindings that are relevant to the local chassis (VIFs bound
> +     * localy, patch ports).
> +     */
> +    struct related_lports related_lports;
>      struct sset active_tunnels;
>
>      /* runtime data engine private data. */
> @@ -1109,7 +1110,7 @@ en_runtime_data_init(struct engine_node *node
OVS_UNUSED,
>
>      hmap_init(&data->local_datapaths);
>      sset_init(&data->local_lports);
> -    sset_init(&data->local_lport_ids);
> +    related_lports_init(&data->related_lports);
>      sset_init(&data->active_tunnels);
>      sset_init(&data->egress_ifaces);
>      smap_init(&data->local_iface_ids);
> @@ -1127,7 +1128,7 @@ en_runtime_data_cleanup(void *data)
>      struct ed_type_runtime_data *rt_data = data;
>
>      sset_destroy(&rt_data->local_lports);
> -    sset_destroy(&rt_data->local_lport_ids);
> +    related_lports_destroy(&rt_data->related_lports);
>      sset_destroy(&rt_data->active_tunnels);
>      sset_destroy(&rt_data->egress_ifaces);
>      smap_destroy(&rt_data->local_iface_ids);
> @@ -1219,8 +1220,8 @@ init_binding_ctx(struct engine_node *node,
>      b_ctx_out->local_datapaths = &rt_data->local_datapaths;
>      b_ctx_out->local_lports = &rt_data->local_lports;
>      b_ctx_out->local_lports_changed = false;
> -    b_ctx_out->local_lport_ids = &rt_data->local_lport_ids;
> -    b_ctx_out->local_lport_ids_changed = false;
> +    b_ctx_out->related_lports = &rt_data->related_lports;
> +    b_ctx_out->related_lports_changed = false;
>      b_ctx_out->non_vif_ports_changed = false;
>      b_ctx_out->egress_ifaces = &rt_data->egress_ifaces;
>      b_ctx_out->lbinding_data = &rt_data->lbinding_data;
> @@ -1235,7 +1236,6 @@ en_runtime_data_run(struct engine_node *node, void
*data)
>      struct ed_type_runtime_data *rt_data = data;
>      struct hmap *local_datapaths = &rt_data->local_datapaths;
>      struct sset *local_lports = &rt_data->local_lports;
> -    struct sset *local_lport_ids = &rt_data->local_lport_ids;
>      struct sset *active_tunnels = &rt_data->active_tunnels;
>
>      static bool first_run = true;
> @@ -1252,12 +1252,12 @@ en_runtime_data_run(struct engine_node *node,
void *data)
>          hmap_clear(local_datapaths);
>          local_binding_data_destroy(&rt_data->lbinding_data);
>          sset_destroy(local_lports);
> -        sset_destroy(local_lport_ids);
> +        related_lports_destroy(&rt_data->related_lports);
>          sset_destroy(active_tunnels);
>          sset_destroy(&rt_data->egress_ifaces);
>          smap_destroy(&rt_data->local_iface_ids);
>          sset_init(local_lports);
> -        sset_init(local_lport_ids);
> +        related_lports_init(&rt_data->related_lports);
>          sset_init(active_tunnels);
>          sset_init(&rt_data->egress_ifaces);
>          smap_init(&rt_data->local_iface_ids);
> @@ -1327,7 +1327,7 @@ runtime_data_sb_port_binding_handler(struct
engine_node *node, void *data)
>      }
>
>      rt_data->local_lports_changed = b_ctx_out.local_lports_changed;
> -    if (b_ctx_out.local_lport_ids_changed ||
> +    if (b_ctx_out.related_lports_changed ||
>              b_ctx_out.non_vif_ports_changed ||
>              b_ctx_out.local_lports_changed ||
>              !hmap_is_empty(b_ctx_out.tracked_dp_bindings)) {
> @@ -1638,11 +1638,8 @@ en_port_groups_run(struct engine_node *node, void
*data)
>      struct ed_type_runtime_data *rt_data =
>          engine_get_input_data("runtime_data", node);
>
> -    struct sset *local_b_lports = binding_collect_local_binding_lports(
> -        &rt_data->lbinding_data);
> -    port_groups_init(pg_table, local_b_lports, &pg->port_group_ssets,
> -                     &pg->port_groups_cs_local);
> -    binding_destroy_local_binding_lports(local_b_lports);
> +    port_groups_init(pg_table, &rt_data->related_lports.lport_names,
> +                     &pg->port_group_ssets, &pg->port_groups_cs_local);
>
>      engine_set_node_state(node, EN_UPDATED);
>  }
> @@ -1659,12 +1656,9 @@ port_groups_sb_port_group_handler(struct
engine_node *node, void *data)
>      struct ed_type_runtime_data *rt_data =
>          engine_get_input_data("runtime_data", node);
>
> -    struct sset *local_b_lports = binding_collect_local_binding_lports(
> -        &rt_data->lbinding_data);
> -    port_groups_update(pg_table, local_b_lports, &pg->port_group_ssets,
> -                       &pg->port_groups_cs_local, &pg->new, &pg->deleted,
> -                       &pg->updated);
> -    binding_destroy_local_binding_lports(local_b_lports);
> +    port_groups_update(pg_table, &rt_data->related_lports.lport_names,
> +                       &pg->port_group_ssets, &pg->port_groups_cs_local,
> +                       &pg->new, &pg->deleted, &pg->updated);
>
>      if (!sset_is_empty(&pg->new) || !sset_is_empty(&pg->deleted) ||
>              !sset_is_empty(&pg->updated)) {
> @@ -1697,9 +1691,6 @@ port_groups_runtime_data_handler(struct engine_node
*node, void *data)
>          goto out;
>      }
>
> -    struct sset *local_b_lports = binding_collect_local_binding_lports(
> -        &rt_data->lbinding_data);
> -
>      const struct sbrec_port_group *pg_sb;
>      SBREC_PORT_GROUP_TABLE_FOR_EACH (pg_sb, pg_table) {
>          struct sset *pg_lports = shash_find_data(&pg->port_group_ssets,
> @@ -1726,13 +1717,12 @@ port_groups_runtime_data_handler(struct
engine_node *node, void *data)
>          if (need_update) {
>              expr_const_sets_add_strings(&pg->port_groups_cs_local,
pg_sb->name,
>                                          (const char *const *)
pg_sb->ports,
> -                                        pg_sb->n_ports, local_b_lports);
> +                                        pg_sb->n_ports,
> +
 &rt_data->related_lports.lport_names);
>              sset_add(&pg->updated, pg_sb->name);
>          }
>      }
>
> -    binding_destroy_local_binding_lports(local_b_lports);
> -
>  out:
>      if (!sset_is_empty(&pg->new) || !sset_is_empty(&pg->deleted) ||
>              !sset_is_empty(&pg->updated)) {
> @@ -2042,7 +2032,7 @@ init_lflow_ctx(struct engine_node *node,
>      l_ctx_in->addr_sets = addr_sets;
>      l_ctx_in->port_groups = port_groups;
>      l_ctx_in->active_tunnels = &rt_data->active_tunnels;
> -    l_ctx_in->local_lport_ids = &rt_data->local_lport_ids;
> +    l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids;
>
>      l_ctx_out->flow_table = &fo->flow_table;
>      l_ctx_out->group_table = &fo->group_table;
> diff --git a/tests/ovn.at b/tests/ovn.at
> index db1a0a35c..7a718d4b6 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -26805,6 +26805,50 @@ OVN_CLEANUP([hv1])
>  AT_CLEANUP
>  ])
>
> +# Tests that ACLs referencing port groups that include ports connected to
> +# logical routers are correctly applied.
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([ovn -- ACL with Port Group including router ports])
> +ovn_start
> +net_add n1
> +
> +sim_add hv1
> +as hv1
> +ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.1
> +
> +check ovn-nbctl \
> +    -- lr-add lr \
> +    -- ls-add ls \
> +    -- lrp-add lr lrp_ls 00:00:00:00:00:01 42.42.42.1/24 \
> +    -- lsp-add ls ls_lr \
> +    -- lsp-set-addresses ls_lr router \
> +    -- lsp-set-type ls_lr router \
> +    -- lsp-set-options ls_lr router-port=lr_ls \
> +    -- lsp-add ls vm1
> +
> +check ovn-nbctl pg-add pg ls_lr \
> +    -- acl-add pg from-lport 1 'inport == @pg && ip4.dst == 42.42.42.42'
drop
> +
> +check ovs-vsctl add-port br-int vm1 \
> +    -- set interface vm1 external_ids:iface-id=vm1
> +
> +wait_for_ports_up
> +check ovn-nbctl --wait=hv sync
> +
> +dp_key=$(fetch_column Datapath_Binding tunnel_key external_ids:name=ls)
> +rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=ls_lr)
> +
> +# Check that ovn-controller adds a flow to drop packets with dest IP
> +# 42.42.42.42 coming from the router port.
> +AT_CHECK([ovs-ofctl dump-flows br-int table=17 | grep
"reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42
actions=drop" -c], [0], [dnl
> +1
> +])
> +
> +OVN_CLEANUP([hv1])
> +AT_CLEANUP
> +])
> +
>  OVN_FOR_EACH_NORTHD([
>  AT_SETUP([ovn -- Static route with discard nexthop])
>  ovn_start
> --
> 2.27.0
>

Thanks Dumitru!
Acked-by: Han Zhou <hzhou@ovn.org>

Not sure if Numan would like to take a second look as well, so let's wait
for one or two days before merging.
Numan Siddique July 1, 2021, 12:53 p.m. UTC | #2
On Wed, Jun 30, 2021 at 7:04 PM Han Zhou <hzhou@ovn.org> wrote:
>
> On Wed, Jun 30, 2021 at 7:01 AM Dumitru Ceara <dceara@redhat.com> wrote:
> >
> > It's valid that port_groups contain non-vif ports, they can actually
> > contain any type of logical_switch_port.
> >
> > Also, there's no need to allocate a new sset containing the local ports'
> > names every time the I-P engine processes a change.  We were already
> > maintaining a set of "local_lport_ids".  These correspond to port
> > bindings that are relevant locally (including non-vif ports).  Extend
> > it to include the locally relevant lport names too and rename the
> > structure an its helper functions to related_lport*.
> >
> > Reported-at: https://github.com/ovn-org/ovn/pull/61#issuecomment-865094163
> > Reported-by: Antonio Ojea <aojea@redhat.com>
> > Fixes: 0cfeba6b55e3 ("ovn-controller: Fix port group conjunction flow
> explosion problem.")
> > Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> > ---
> > v2:
> > - Addressed Numan's and Han's comments:
> >   - add struct related_lports
> >   - add test case.
> > ---
> >  controller/binding.c        | 79 ++++++++++++++++++-------------------
> >  controller/binding.h        | 31 ++++++++-------
> >  controller/lflow.c          |  2 +-
> >  controller/lflow.h          |  2 +-
> >  controller/ovn-controller.c | 48 +++++++++-------------
> >  tests/ovn.at                | 44 +++++++++++++++++++++
> >  6 files changed, 120 insertions(+), 86 deletions(-)
> >
> > diff --git a/controller/binding.c b/controller/binding.c
> > index 7fde0fdbb..594babc98 100644
> > --- a/controller/binding.c
> > +++ b/controller/binding.c
> > @@ -531,38 +531,41 @@ remove_local_lports(const char *iface_id, struct
> binding_ctx_out *b_ctx)
> >      }
> >  }
> >
> > -/* Add a port binding ID (of the form "dp-key"_"port-key") to the set of
> local
> > - * lport IDs. Also track if the set has changed.
> > +/* Add a port binding to the set of locally relevant lports.
> > + * Also track if the set has changed.
> >   */
> >  static void
> > -update_local_lport_ids(const struct sbrec_port_binding *pb,
> > -                       struct binding_ctx_out *b_ctx)
> > +update_related_lport(const struct sbrec_port_binding *pb,
> > +                     struct binding_ctx_out *b_ctx)
> >  {
> >      char buf[16];
> >      get_unique_lport_key(pb->datapath->tunnel_key, pb->tunnel_key,
> >                           buf, sizeof(buf));
> > -    if (sset_add(b_ctx->local_lport_ids, buf) != NULL) {
> > -        b_ctx->local_lport_ids_changed = true;
> > +    if (sset_add(&b_ctx->related_lports->lport_ids, buf) != NULL) {
> > +        b_ctx->related_lports_changed = true;
> >
> >          if (b_ctx->tracked_dp_bindings) {
> >              /* Add the 'pb' to the tracked_datapaths. */
> >              tracked_binding_datapath_lport_add(pb,
> b_ctx->tracked_dp_bindings);
> >          }
> >      }
> > +    sset_add(&b_ctx->related_lports->lport_names, pb->logical_port);
> >  }
> >
> > -/* Remove a port binding id from the set of local lport IDs. Also track
> if
> > - * the set has changed.
> > +/* Remove a port binding id from the set of locally relevant lports.
> > + * Also track if the set has changed.
> >   */
> >  static void
> > -remove_local_lport_ids(const struct sbrec_port_binding *pb,
> > -                       struct binding_ctx_out *b_ctx)
> > +remove_related_lport(const struct sbrec_port_binding *pb,
> > +                     struct binding_ctx_out *b_ctx)
> >  {
> >      char buf[16];
> >      get_unique_lport_key(pb->datapath->tunnel_key, pb->tunnel_key,
> >                           buf, sizeof(buf));
> > -    if (sset_find_and_delete(b_ctx->local_lport_ids, buf)) {
> > -        b_ctx->local_lport_ids_changed = true;
> > +    sset_find_and_delete(&b_ctx->related_lports->lport_names,
> > +                         pb->logical_port);
> > +    if (sset_find_and_delete(&b_ctx->related_lports->lport_ids, buf)) {
> > +        b_ctx->related_lports_changed = true;
> >
> >          if (b_ctx->tracked_dp_bindings) {
> >              /* Add the 'pb' to the tracked_datapaths. */
> > @@ -678,6 +681,20 @@ static struct binding_lport
> *binding_lport_check_and_cleanup(
> >
> >  static char *get_lport_type_str(enum en_lport_type lport_type);
> >
> > +void
> > +related_lports_init(struct related_lports *rp)
> > +{
> > +    sset_init(&rp->lport_names);
> > +    sset_init(&rp->lport_ids);
> > +}
> > +
> > +void
> > +related_lports_destroy(struct related_lports *rp)
> > +{
> > +    sset_destroy(&rp->lport_names);
> > +    sset_destroy(&rp->lport_ids);
> > +}
> > +
> >  void
> >  local_binding_data_init(struct local_binding_data *lbinding_data)
> >  {
> > @@ -1172,7 +1189,7 @@ release_binding_lport(const struct sbrec_chassis
> *chassis_rec,
> >                        struct binding_ctx_out *b_ctx_out)
> >  {
> >      if (is_binding_lport_this_chassis(b_lport, chassis_rec)) {
> > -        remove_local_lport_ids(b_lport->pb, b_ctx_out);
> > +        remove_related_lport(b_lport->pb, b_ctx_out);
> >          if (!release_lport(b_lport->pb, sb_readonly,
> >                             b_ctx_out->tracked_dp_bindings,
> >                             b_ctx_out->if_mgr)) {
> > @@ -1214,7 +1231,7 @@ consider_vif_lport_(const struct sbrec_port_binding
> *pb,
> >                                 pb->datapath, false,
> >                                 b_ctx_out->local_datapaths,
> >                                 b_ctx_out->tracked_dp_bindings);
> > -            update_local_lport_ids(pb, b_ctx_out);
> > +            update_related_lport(pb, b_ctx_out);
> >              update_local_lports(pb->logical_port, b_ctx_out);
> >              if (b_lport->lbinding->iface && qos_map &&
> b_ctx_in->ovs_idl_txn) {
> >                  get_qos_params(pb, qos_map);
> > @@ -1405,7 +1422,7 @@ consider_virtual_lport(const struct
> sbrec_port_binding *pb,
> >       * its entry from the local_lport_ids if present.  This is required
> >       * when a virtual port moves from one chassis to other.*/
> >      if (!virtual_b_lport) {
> > -        remove_local_lport_ids(pb, b_ctx_out);
> > +        remove_related_lport(pb, b_ctx_out);
> >      }
> >
> >      return true;
> > @@ -1430,7 +1447,7 @@ consider_nonvif_lport_(const struct
> sbrec_port_binding *pb,
> >                             b_ctx_out->local_datapaths,
> >                             b_ctx_out->tracked_dp_bindings);
> >
> > -        update_local_lport_ids(pb, b_ctx_out);
> > +        update_related_lport(pb, b_ctx_out);
> >          return claim_lport(pb, NULL, b_ctx_in->chassis_rec, NULL,
> >                             !b_ctx_in->ovnsb_idl_txn, false,
> >                             b_ctx_out->tracked_dp_bindings,
> > @@ -1482,7 +1499,7 @@ consider_localnet_lport(const struct
> sbrec_port_binding *pb,
> >          get_qos_params(pb, qos_map);
> >      }
> >
> > -    update_local_lport_ids(pb, b_ctx_out);
> > +    update_related_lport(pb, b_ctx_out);
> >  }
> >
> >  static bool
> > @@ -1512,7 +1529,7 @@ consider_ha_lport(const struct sbrec_port_binding
> *pb,
> >                             pb->datapath, false,
> >                             b_ctx_out->local_datapaths,
> >                             b_ctx_out->tracked_dp_bindings);
> > -        update_local_lport_ids(pb, b_ctx_out);
> > +        update_related_lport(pb, b_ctx_out);
> >      }
> >
> >      return consider_nonvif_lport_(pb, our_chassis, false, b_ctx_in,
> b_ctx_out);
> > @@ -1634,7 +1651,7 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct
> binding_ctx_out *b_ctx_out)
> >          case LP_PATCH:
> >          case LP_LOCALPORT:
> >          case LP_VTEP:
> > -            update_local_lport_ids(pb, b_ctx_out);
> > +            update_related_lport(pb, b_ctx_out);
> >              break;
> >
> >          case LP_VIF:
> > @@ -1895,7 +1912,7 @@ remove_pb_from_local_datapath(const struct
> sbrec_port_binding *pb,
> >                                struct binding_ctx_out *b_ctx_out,
> >                                struct local_datapath *ld)
> >  {
> > -    remove_local_lport_ids(pb, b_ctx_out);
> > +    remove_related_lport(pb, b_ctx_out);
> >      if (!strcmp(pb->type, "patch") ||
> >          !strcmp(pb->type, "l3gateway")) {
> >          remove_local_datapath_peer_port(pb, ld,
> b_ctx_out->local_datapaths);
> > @@ -2502,7 +2519,7 @@ delete_done:
> >          case LP_PATCH:
> >          case LP_LOCALPORT:
> >          case LP_VTEP:
> > -            update_local_lport_ids(pb, b_ctx_out);
> > +            update_related_lport(pb, b_ctx_out);
> >              if (lport_type ==  LP_PATCH) {
> >                  if (!ld) {
> >                      /* If 'ld' for this lport is not present, then check
> if
> > @@ -2926,23 +2943,3 @@ cleanup:
> >
> >      return b_lport;
> >  }
> > -
> > -struct sset *
> > -binding_collect_local_binding_lports(struct local_binding_data
> *lbinding_data)
> > -{
> > -    struct sset *lports = xzalloc(sizeof *lports);
> > -    sset_init(lports);
> > -    struct shash_node *shash_node;
> > -    SHASH_FOR_EACH (shash_node, &lbinding_data->lports) {
> > -        struct binding_lport *b_lport = shash_node->data;
> > -        sset_add(lports, b_lport->name);
> > -    }
> > -    return lports;
> > -}
> > -
> > -void
> > -binding_destroy_local_binding_lports(struct sset *lports)
> > -{
> > -    sset_destroy(lports);
> > -    free(lports);
> > -}
> > diff --git a/controller/binding.h b/controller/binding.h
> > index 8f3289476..a08011ae2 100644
> > --- a/controller/binding.h
> > +++ b/controller/binding.h
> > @@ -22,6 +22,7 @@
> >  #include "openvswitch/hmap.h"
> >  #include "openvswitch/uuid.h"
> >  #include "openvswitch/list.h"
> > +#include "sset.h"
> >
> >  struct hmap;
> >  struct ovsdb_idl;
> > @@ -56,6 +57,19 @@ struct binding_ctx_in {
> >      const struct ovsrec_interface_table *iface_table;
> >  };
> >
> > +/* Locally relevant port bindings, e.g., VIFs that might be bound
> locally,
> > + * patch ports.
> > + */
> > +struct related_lports {
> > +    struct sset lport_names; /* Set of port names. */
> > +    struct sset lport_ids;   /* Set of
> <datapath-tunnel-key>_<port-tunnel-key>
> > +                              * IDs for fast lookup.
> > +                              */
> > +};
> > +
> > +void related_lports_init(struct related_lports *);
> > +void related_lports_destroy(struct related_lports *);
> > +
> >  struct binding_ctx_out {
> >      struct hmap *local_datapaths;
> >      struct local_binding_data *lbinding_data;
> > @@ -65,11 +79,9 @@ struct binding_ctx_out {
> >      /* Track if local_lports have been updated. */
> >      bool local_lports_changed;
> >
> > -    /* sset of local lport ids in the format
> > -     * <datapath-tunnel-key>_<port-tunnel-key>. */
> > -    struct sset *local_lport_ids;
> > -    /* Track if local_lport_ids has been updated. */
> > -    bool local_lport_ids_changed;
> > +    /* Port bindings that are relevant to the local chassis. */
> > +    struct related_lports *related_lports;
> > +    bool related_lports_changed;
> >
> >      /* Track if non-vif port bindings (e.g., patch, external) have been
> >       * added/deleted.
> > @@ -133,13 +145,4 @@ bool binding_handle_port_binding_changes(struct
> binding_ctx_in *,
> >  void binding_tracked_dp_destroy(struct hmap *tracked_datapaths);
> >
> >  void binding_dump_local_bindings(struct local_binding_data *, struct ds
> *);
> > -
> > -/* Generates a sset of lport names from local_binding_data.
> > - * Note: the caller is responsible for destroying and freeing the
> returned
> > - * sset, by calling binding_detroy_local_binding_lports(). */
> > -struct sset *binding_collect_local_binding_lports(struct
> local_binding_data *);
> > -
> > -/* Destroy and free the lports sset returned by
> > - * binding_collect_local_binding_lports(). */
> > -void binding_destroy_local_binding_lports(struct sset *lports);
> >  #endif /* controller/binding.h */
> > diff --git a/controller/lflow.c b/controller/lflow.c
> > index 34eca135a..abb01f0ce 100644
> > --- a/controller/lflow.c
> > +++ b/controller/lflow.c
> > @@ -625,7 +625,7 @@ add_matches_to_flow_table(const struct
> sbrec_logical_flow *lflow,
> >                  get_unique_lport_key(dp_id, port_id, buf, sizeof(buf));
> >                  lflow_resource_add(l_ctx_out->lfrr,
> REF_TYPE_PORTBINDING, buf,
> >                                     &lflow->header_.uuid);
> > -                if (!sset_contains(l_ctx_in->local_lport_ids, buf)) {
> > +                if (!sset_contains(l_ctx_in->related_lport_ids, buf)) {
> >                      VLOG_DBG("lflow "UUID_FMT
> >                               " port %s in match is not local, skip",
> >                               UUID_ARGS(&lflow->header_.uuid),
> > diff --git a/controller/lflow.h b/controller/lflow.h
> > index e98edf81d..699f9c2d5 100644
> > --- a/controller/lflow.h
> > +++ b/controller/lflow.h
> > @@ -144,7 +144,7 @@ struct lflow_ctx_in {
> >      const struct shash *addr_sets;
> >      const struct shash *port_groups;
> >      const struct sset *active_tunnels;
> > -    const struct sset *local_lport_ids;
> > +    const struct sset *related_lport_ids;
> >  };
> >
> >  struct lflow_ctx_out {
> > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> > index b6afb8fb9..3bb8b22eb 100644
> > --- a/controller/ovn-controller.c
> > +++ b/controller/ovn-controller.c
> > @@ -1014,9 +1014,10 @@ struct ed_type_runtime_data {
> >       * local hypervisor, and localnet ports. */
> >      struct sset local_lports;
> >
> > -    /* Contains the same ports as local_lports, but in the format:
> > -     * <datapath-tunnel-key>_<port-tunnel-key> */
> > -    struct sset local_lport_ids;
> > +    /* Port bindings that are relevant to the local chassis (VIFs bound
> > +     * localy, patch ports).
> > +     */
> > +    struct related_lports related_lports;
> >      struct sset active_tunnels;
> >
> >      /* runtime data engine private data. */
> > @@ -1109,7 +1110,7 @@ en_runtime_data_init(struct engine_node *node
> OVS_UNUSED,
> >
> >      hmap_init(&data->local_datapaths);
> >      sset_init(&data->local_lports);
> > -    sset_init(&data->local_lport_ids);
> > +    related_lports_init(&data->related_lports);
> >      sset_init(&data->active_tunnels);
> >      sset_init(&data->egress_ifaces);
> >      smap_init(&data->local_iface_ids);
> > @@ -1127,7 +1128,7 @@ en_runtime_data_cleanup(void *data)
> >      struct ed_type_runtime_data *rt_data = data;
> >
> >      sset_destroy(&rt_data->local_lports);
> > -    sset_destroy(&rt_data->local_lport_ids);
> > +    related_lports_destroy(&rt_data->related_lports);
> >      sset_destroy(&rt_data->active_tunnels);
> >      sset_destroy(&rt_data->egress_ifaces);
> >      smap_destroy(&rt_data->local_iface_ids);
> > @@ -1219,8 +1220,8 @@ init_binding_ctx(struct engine_node *node,
> >      b_ctx_out->local_datapaths = &rt_data->local_datapaths;
> >      b_ctx_out->local_lports = &rt_data->local_lports;
> >      b_ctx_out->local_lports_changed = false;
> > -    b_ctx_out->local_lport_ids = &rt_data->local_lport_ids;
> > -    b_ctx_out->local_lport_ids_changed = false;
> > +    b_ctx_out->related_lports = &rt_data->related_lports;
> > +    b_ctx_out->related_lports_changed = false;
> >      b_ctx_out->non_vif_ports_changed = false;
> >      b_ctx_out->egress_ifaces = &rt_data->egress_ifaces;
> >      b_ctx_out->lbinding_data = &rt_data->lbinding_data;
> > @@ -1235,7 +1236,6 @@ en_runtime_data_run(struct engine_node *node, void
> *data)
> >      struct ed_type_runtime_data *rt_data = data;
> >      struct hmap *local_datapaths = &rt_data->local_datapaths;
> >      struct sset *local_lports = &rt_data->local_lports;
> > -    struct sset *local_lport_ids = &rt_data->local_lport_ids;
> >      struct sset *active_tunnels = &rt_data->active_tunnels;
> >
> >      static bool first_run = true;
> > @@ -1252,12 +1252,12 @@ en_runtime_data_run(struct engine_node *node,
> void *data)
> >          hmap_clear(local_datapaths);
> >          local_binding_data_destroy(&rt_data->lbinding_data);
> >          sset_destroy(local_lports);
> > -        sset_destroy(local_lport_ids);
> > +        related_lports_destroy(&rt_data->related_lports);
> >          sset_destroy(active_tunnels);
> >          sset_destroy(&rt_data->egress_ifaces);
> >          smap_destroy(&rt_data->local_iface_ids);
> >          sset_init(local_lports);
> > -        sset_init(local_lport_ids);
> > +        related_lports_init(&rt_data->related_lports);
> >          sset_init(active_tunnels);
> >          sset_init(&rt_data->egress_ifaces);
> >          smap_init(&rt_data->local_iface_ids);
> > @@ -1327,7 +1327,7 @@ runtime_data_sb_port_binding_handler(struct
> engine_node *node, void *data)
> >      }
> >
> >      rt_data->local_lports_changed = b_ctx_out.local_lports_changed;
> > -    if (b_ctx_out.local_lport_ids_changed ||
> > +    if (b_ctx_out.related_lports_changed ||
> >              b_ctx_out.non_vif_ports_changed ||
> >              b_ctx_out.local_lports_changed ||
> >              !hmap_is_empty(b_ctx_out.tracked_dp_bindings)) {
> > @@ -1638,11 +1638,8 @@ en_port_groups_run(struct engine_node *node, void
> *data)
> >      struct ed_type_runtime_data *rt_data =
> >          engine_get_input_data("runtime_data", node);
> >
> > -    struct sset *local_b_lports = binding_collect_local_binding_lports(
> > -        &rt_data->lbinding_data);
> > -    port_groups_init(pg_table, local_b_lports, &pg->port_group_ssets,
> > -                     &pg->port_groups_cs_local);
> > -    binding_destroy_local_binding_lports(local_b_lports);
> > +    port_groups_init(pg_table, &rt_data->related_lports.lport_names,
> > +                     &pg->port_group_ssets, &pg->port_groups_cs_local);
> >
> >      engine_set_node_state(node, EN_UPDATED);
> >  }
> > @@ -1659,12 +1656,9 @@ port_groups_sb_port_group_handler(struct
> engine_node *node, void *data)
> >      struct ed_type_runtime_data *rt_data =
> >          engine_get_input_data("runtime_data", node);
> >
> > -    struct sset *local_b_lports = binding_collect_local_binding_lports(
> > -        &rt_data->lbinding_data);
> > -    port_groups_update(pg_table, local_b_lports, &pg->port_group_ssets,
> > -                       &pg->port_groups_cs_local, &pg->new, &pg->deleted,
> > -                       &pg->updated);
> > -    binding_destroy_local_binding_lports(local_b_lports);
> > +    port_groups_update(pg_table, &rt_data->related_lports.lport_names,
> > +                       &pg->port_group_ssets, &pg->port_groups_cs_local,
> > +                       &pg->new, &pg->deleted, &pg->updated);
> >
> >      if (!sset_is_empty(&pg->new) || !sset_is_empty(&pg->deleted) ||
> >              !sset_is_empty(&pg->updated)) {
> > @@ -1697,9 +1691,6 @@ port_groups_runtime_data_handler(struct engine_node
> *node, void *data)
> >          goto out;
> >      }
> >
> > -    struct sset *local_b_lports = binding_collect_local_binding_lports(
> > -        &rt_data->lbinding_data);
> > -
> >      const struct sbrec_port_group *pg_sb;
> >      SBREC_PORT_GROUP_TABLE_FOR_EACH (pg_sb, pg_table) {
> >          struct sset *pg_lports = shash_find_data(&pg->port_group_ssets,
> > @@ -1726,13 +1717,12 @@ port_groups_runtime_data_handler(struct
> engine_node *node, void *data)
> >          if (need_update) {
> >              expr_const_sets_add_strings(&pg->port_groups_cs_local,
> pg_sb->name,
> >                                          (const char *const *)
> pg_sb->ports,
> > -                                        pg_sb->n_ports, local_b_lports);
> > +                                        pg_sb->n_ports,
> > +
>  &rt_data->related_lports.lport_names);
> >              sset_add(&pg->updated, pg_sb->name);
> >          }
> >      }
> >
> > -    binding_destroy_local_binding_lports(local_b_lports);
> > -
> >  out:
> >      if (!sset_is_empty(&pg->new) || !sset_is_empty(&pg->deleted) ||
> >              !sset_is_empty(&pg->updated)) {
> > @@ -2042,7 +2032,7 @@ init_lflow_ctx(struct engine_node *node,
> >      l_ctx_in->addr_sets = addr_sets;
> >      l_ctx_in->port_groups = port_groups;
> >      l_ctx_in->active_tunnels = &rt_data->active_tunnels;
> > -    l_ctx_in->local_lport_ids = &rt_data->local_lport_ids;
> > +    l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids;
> >
> >      l_ctx_out->flow_table = &fo->flow_table;
> >      l_ctx_out->group_table = &fo->group_table;
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index db1a0a35c..7a718d4b6 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -26805,6 +26805,50 @@ OVN_CLEANUP([hv1])
> >  AT_CLEANUP
> >  ])
> >
> > +# Tests that ACLs referencing port groups that include ports connected to
> > +# logical routers are correctly applied.
> > +OVN_FOR_EACH_NORTHD([
> > +AT_SETUP([ovn -- ACL with Port Group including router ports])
> > +ovn_start
> > +net_add n1
> > +
> > +sim_add hv1
> > +as hv1
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.1
> > +
> > +check ovn-nbctl \
> > +    -- lr-add lr \
> > +    -- ls-add ls \
> > +    -- lrp-add lr lrp_ls 00:00:00:00:00:01 42.42.42.1/24 \
> > +    -- lsp-add ls ls_lr \
> > +    -- lsp-set-addresses ls_lr router \
> > +    -- lsp-set-type ls_lr router \
> > +    -- lsp-set-options ls_lr router-port=lr_ls \
> > +    -- lsp-add ls vm1
> > +
> > +check ovn-nbctl pg-add pg ls_lr \
> > +    -- acl-add pg from-lport 1 'inport == @pg && ip4.dst == 42.42.42.42'
> drop
> > +
> > +check ovs-vsctl add-port br-int vm1 \
> > +    -- set interface vm1 external_ids:iface-id=vm1
> > +
> > +wait_for_ports_up
> > +check ovn-nbctl --wait=hv sync
> > +
> > +dp_key=$(fetch_column Datapath_Binding tunnel_key external_ids:name=ls)
> > +rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=ls_lr)
> > +
> > +# Check that ovn-controller adds a flow to drop packets with dest IP
> > +# 42.42.42.42 coming from the router port.
> > +AT_CHECK([ovs-ofctl dump-flows br-int table=17 | grep
> "reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42
> actions=drop" -c], [0], [dnl
> > +1
> > +])
> > +
> > +OVN_CLEANUP([hv1])
> > +AT_CLEANUP
> > +])
> > +
> >  OVN_FOR_EACH_NORTHD([
> >  AT_SETUP([ovn -- Static route with discard nexthop])
> >  ovn_start
> > --
> > 2.27.0
> >
>
> Thanks Dumitru!
> Acked-by: Han Zhou <hzhou@ovn.org>
>
> Not sure if Numan would like to take a second look as well, so let's wait
> for one or two days before merging.

Thanks Dumitru and Han.

I looked at it and LGTM.  I applied the patch to the main branch.

Numan

> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Dumitru Ceara July 1, 2021, 1:05 p.m. UTC | #3
On 7/1/21 2:53 PM, Numan Siddique wrote:
>> Thanks Dumitru!
>> Acked-by: Han Zhou <hzhou@ovn.org>
>>
>> Not sure if Numan would like to take a second look as well, so let's wait
>> for one or two days before merging.
> Thanks Dumitru and Han.
> 
> I looked at it and LGTM.  I applied the patch to the main branch.
> 
> Numan
> 

Thanks!
Han Zhou July 1, 2021, 4:39 p.m. UTC | #4
On Thu, Jul 1, 2021 at 6:05 AM Dumitru Ceara <dceara@redhat.com> wrote:
>
> On 7/1/21 2:53 PM, Numan Siddique wrote:
> >> Thanks Dumitru!
> >> Acked-by: Han Zhou <hzhou@ovn.org>
> >>
> >> Not sure if Numan would like to take a second look as well, so let's
wait
> >> for one or two days before merging.
> > Thanks Dumitru and Han.
> >
> > I looked at it and LGTM.  I applied the patch to the main branch.
> >
> > Numan
> >
>
> Thanks!
>

Do we need this in branch-21.06 and 21.03?
Dumitru Ceara July 1, 2021, 5:17 p.m. UTC | #5
On 7/1/21 6:39 PM, Han Zhou wrote:
> On Thu, Jul 1, 2021 at 6:05 AM Dumitru Ceara <dceara@redhat.com> wrote:
>>
>> On 7/1/21 2:53 PM, Numan Siddique wrote:
>>>> Thanks Dumitru!
>>>> Acked-by: Han Zhou <hzhou@ovn.org>
>>>>
>>>> Not sure if Numan would like to take a second look as well, so let's
> wait
>>>> for one or two days before merging.
>>> Thanks Dumitru and Han.
>>>
>>> I looked at it and LGTM.  I applied the patch to the main branch.
>>>
>>> Numan
>>>
>>
>> Thanks!
>>
> 
> Do we need this in branch-21.06 and 21.03?
> 

Right, that would be great, thanks!
Han Zhou July 1, 2021, 7:31 p.m. UTC | #6
On Thu, Jul 1, 2021 at 10:18 AM Dumitru Ceara <dceara@redhat.com> wrote:
>
> On 7/1/21 6:39 PM, Han Zhou wrote:
> > On Thu, Jul 1, 2021 at 6:05 AM Dumitru Ceara <dceara@redhat.com> wrote:
> >>
> >> On 7/1/21 2:53 PM, Numan Siddique wrote:
> >>>> Thanks Dumitru!
> >>>> Acked-by: Han Zhou <hzhou@ovn.org>
> >>>>
> >>>> Not sure if Numan would like to take a second look as well, so let's
> > wait
> >>>> for one or two days before merging.
> >>> Thanks Dumitru and Han.
> >>>
> >>> I looked at it and LGTM.  I applied the patch to the main branch.
> >>>
> >>> Numan
> >>>
> >>
> >> Thanks!
> >>
> >
> > Do we need this in branch-21.06 and 21.03?
> >
>
> Right, that would be great, thanks!
>
Ok, I rebased and pushed to 21.06 and 21.03.

Thanks,
Han
diff mbox series

Patch

diff --git a/controller/binding.c b/controller/binding.c
index 7fde0fdbb..594babc98 100644
--- a/controller/binding.c
+++ b/controller/binding.c
@@ -531,38 +531,41 @@  remove_local_lports(const char *iface_id, struct binding_ctx_out *b_ctx)
     }
 }
 
-/* Add a port binding ID (of the form "dp-key"_"port-key") to the set of local
- * lport IDs. Also track if the set has changed.
+/* Add a port binding to the set of locally relevant lports.
+ * Also track if the set has changed.
  */
 static void
-update_local_lport_ids(const struct sbrec_port_binding *pb,
-                       struct binding_ctx_out *b_ctx)
+update_related_lport(const struct sbrec_port_binding *pb,
+                     struct binding_ctx_out *b_ctx)
 {
     char buf[16];
     get_unique_lport_key(pb->datapath->tunnel_key, pb->tunnel_key,
                          buf, sizeof(buf));
-    if (sset_add(b_ctx->local_lport_ids, buf) != NULL) {
-        b_ctx->local_lport_ids_changed = true;
+    if (sset_add(&b_ctx->related_lports->lport_ids, buf) != NULL) {
+        b_ctx->related_lports_changed = true;
 
         if (b_ctx->tracked_dp_bindings) {
             /* Add the 'pb' to the tracked_datapaths. */
             tracked_binding_datapath_lport_add(pb, b_ctx->tracked_dp_bindings);
         }
     }
+    sset_add(&b_ctx->related_lports->lport_names, pb->logical_port);
 }
 
-/* Remove a port binding id from the set of local lport IDs. Also track if
- * the set has changed.
+/* Remove a port binding id from the set of locally relevant lports.
+ * Also track if the set has changed.
  */
 static void
-remove_local_lport_ids(const struct sbrec_port_binding *pb,
-                       struct binding_ctx_out *b_ctx)
+remove_related_lport(const struct sbrec_port_binding *pb,
+                     struct binding_ctx_out *b_ctx)
 {
     char buf[16];
     get_unique_lport_key(pb->datapath->tunnel_key, pb->tunnel_key,
                          buf, sizeof(buf));
-    if (sset_find_and_delete(b_ctx->local_lport_ids, buf)) {
-        b_ctx->local_lport_ids_changed = true;
+    sset_find_and_delete(&b_ctx->related_lports->lport_names,
+                         pb->logical_port);
+    if (sset_find_and_delete(&b_ctx->related_lports->lport_ids, buf)) {
+        b_ctx->related_lports_changed = true;
 
         if (b_ctx->tracked_dp_bindings) {
             /* Add the 'pb' to the tracked_datapaths. */
@@ -678,6 +681,20 @@  static struct binding_lport *binding_lport_check_and_cleanup(
 
 static char *get_lport_type_str(enum en_lport_type lport_type);
 
+void
+related_lports_init(struct related_lports *rp)
+{
+    sset_init(&rp->lport_names);
+    sset_init(&rp->lport_ids);
+}
+
+void
+related_lports_destroy(struct related_lports *rp)
+{
+    sset_destroy(&rp->lport_names);
+    sset_destroy(&rp->lport_ids);
+}
+
 void
 local_binding_data_init(struct local_binding_data *lbinding_data)
 {
@@ -1172,7 +1189,7 @@  release_binding_lport(const struct sbrec_chassis *chassis_rec,
                       struct binding_ctx_out *b_ctx_out)
 {
     if (is_binding_lport_this_chassis(b_lport, chassis_rec)) {
-        remove_local_lport_ids(b_lport->pb, b_ctx_out);
+        remove_related_lport(b_lport->pb, b_ctx_out);
         if (!release_lport(b_lport->pb, sb_readonly,
                            b_ctx_out->tracked_dp_bindings,
                            b_ctx_out->if_mgr)) {
@@ -1214,7 +1231,7 @@  consider_vif_lport_(const struct sbrec_port_binding *pb,
                                pb->datapath, false,
                                b_ctx_out->local_datapaths,
                                b_ctx_out->tracked_dp_bindings);
-            update_local_lport_ids(pb, b_ctx_out);
+            update_related_lport(pb, b_ctx_out);
             update_local_lports(pb->logical_port, b_ctx_out);
             if (b_lport->lbinding->iface && qos_map && b_ctx_in->ovs_idl_txn) {
                 get_qos_params(pb, qos_map);
@@ -1405,7 +1422,7 @@  consider_virtual_lport(const struct sbrec_port_binding *pb,
      * its entry from the local_lport_ids if present.  This is required
      * when a virtual port moves from one chassis to other.*/
     if (!virtual_b_lport) {
-        remove_local_lport_ids(pb, b_ctx_out);
+        remove_related_lport(pb, b_ctx_out);
     }
 
     return true;
@@ -1430,7 +1447,7 @@  consider_nonvif_lport_(const struct sbrec_port_binding *pb,
                            b_ctx_out->local_datapaths,
                            b_ctx_out->tracked_dp_bindings);
 
-        update_local_lport_ids(pb, b_ctx_out);
+        update_related_lport(pb, b_ctx_out);
         return claim_lport(pb, NULL, b_ctx_in->chassis_rec, NULL,
                            !b_ctx_in->ovnsb_idl_txn, false,
                            b_ctx_out->tracked_dp_bindings,
@@ -1482,7 +1499,7 @@  consider_localnet_lport(const struct sbrec_port_binding *pb,
         get_qos_params(pb, qos_map);
     }
 
-    update_local_lport_ids(pb, b_ctx_out);
+    update_related_lport(pb, b_ctx_out);
 }
 
 static bool
@@ -1512,7 +1529,7 @@  consider_ha_lport(const struct sbrec_port_binding *pb,
                            pb->datapath, false,
                            b_ctx_out->local_datapaths,
                            b_ctx_out->tracked_dp_bindings);
-        update_local_lport_ids(pb, b_ctx_out);
+        update_related_lport(pb, b_ctx_out);
     }
 
     return consider_nonvif_lport_(pb, our_chassis, false, b_ctx_in, b_ctx_out);
@@ -1634,7 +1651,7 @@  binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out)
         case LP_PATCH:
         case LP_LOCALPORT:
         case LP_VTEP:
-            update_local_lport_ids(pb, b_ctx_out);
+            update_related_lport(pb, b_ctx_out);
             break;
 
         case LP_VIF:
@@ -1895,7 +1912,7 @@  remove_pb_from_local_datapath(const struct sbrec_port_binding *pb,
                               struct binding_ctx_out *b_ctx_out,
                               struct local_datapath *ld)
 {
-    remove_local_lport_ids(pb, b_ctx_out);
+    remove_related_lport(pb, b_ctx_out);
     if (!strcmp(pb->type, "patch") ||
         !strcmp(pb->type, "l3gateway")) {
         remove_local_datapath_peer_port(pb, ld, b_ctx_out->local_datapaths);
@@ -2502,7 +2519,7 @@  delete_done:
         case LP_PATCH:
         case LP_LOCALPORT:
         case LP_VTEP:
-            update_local_lport_ids(pb, b_ctx_out);
+            update_related_lport(pb, b_ctx_out);
             if (lport_type ==  LP_PATCH) {
                 if (!ld) {
                     /* If 'ld' for this lport is not present, then check if
@@ -2926,23 +2943,3 @@  cleanup:
 
     return b_lport;
 }
-
-struct sset *
-binding_collect_local_binding_lports(struct local_binding_data *lbinding_data)
-{
-    struct sset *lports = xzalloc(sizeof *lports);
-    sset_init(lports);
-    struct shash_node *shash_node;
-    SHASH_FOR_EACH (shash_node, &lbinding_data->lports) {
-        struct binding_lport *b_lport = shash_node->data;
-        sset_add(lports, b_lport->name);
-    }
-    return lports;
-}
-
-void
-binding_destroy_local_binding_lports(struct sset *lports)
-{
-    sset_destroy(lports);
-    free(lports);
-}
diff --git a/controller/binding.h b/controller/binding.h
index 8f3289476..a08011ae2 100644
--- a/controller/binding.h
+++ b/controller/binding.h
@@ -22,6 +22,7 @@ 
 #include "openvswitch/hmap.h"
 #include "openvswitch/uuid.h"
 #include "openvswitch/list.h"
+#include "sset.h"
 
 struct hmap;
 struct ovsdb_idl;
@@ -56,6 +57,19 @@  struct binding_ctx_in {
     const struct ovsrec_interface_table *iface_table;
 };
 
+/* Locally relevant port bindings, e.g., VIFs that might be bound locally,
+ * patch ports.
+ */
+struct related_lports {
+    struct sset lport_names; /* Set of port names. */
+    struct sset lport_ids;   /* Set of <datapath-tunnel-key>_<port-tunnel-key>
+                              * IDs for fast lookup.
+                              */
+};
+
+void related_lports_init(struct related_lports *);
+void related_lports_destroy(struct related_lports *);
+
 struct binding_ctx_out {
     struct hmap *local_datapaths;
     struct local_binding_data *lbinding_data;
@@ -65,11 +79,9 @@  struct binding_ctx_out {
     /* Track if local_lports have been updated. */
     bool local_lports_changed;
 
-    /* sset of local lport ids in the format
-     * <datapath-tunnel-key>_<port-tunnel-key>. */
-    struct sset *local_lport_ids;
-    /* Track if local_lport_ids has been updated. */
-    bool local_lport_ids_changed;
+    /* Port bindings that are relevant to the local chassis. */
+    struct related_lports *related_lports;
+    bool related_lports_changed;
 
     /* Track if non-vif port bindings (e.g., patch, external) have been
      * added/deleted.
@@ -133,13 +145,4 @@  bool binding_handle_port_binding_changes(struct binding_ctx_in *,
 void binding_tracked_dp_destroy(struct hmap *tracked_datapaths);
 
 void binding_dump_local_bindings(struct local_binding_data *, struct ds *);
-
-/* Generates a sset of lport names from local_binding_data.
- * Note: the caller is responsible for destroying and freeing the returned
- * sset, by calling binding_detroy_local_binding_lports(). */
-struct sset *binding_collect_local_binding_lports(struct local_binding_data *);
-
-/* Destroy and free the lports sset returned by
- * binding_collect_local_binding_lports(). */
-void binding_destroy_local_binding_lports(struct sset *lports);
 #endif /* controller/binding.h */
diff --git a/controller/lflow.c b/controller/lflow.c
index 34eca135a..abb01f0ce 100644
--- a/controller/lflow.c
+++ b/controller/lflow.c
@@ -625,7 +625,7 @@  add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
                 get_unique_lport_key(dp_id, port_id, buf, sizeof(buf));
                 lflow_resource_add(l_ctx_out->lfrr, REF_TYPE_PORTBINDING, buf,
                                    &lflow->header_.uuid);
-                if (!sset_contains(l_ctx_in->local_lport_ids, buf)) {
+                if (!sset_contains(l_ctx_in->related_lport_ids, buf)) {
                     VLOG_DBG("lflow "UUID_FMT
                              " port %s in match is not local, skip",
                              UUID_ARGS(&lflow->header_.uuid),
diff --git a/controller/lflow.h b/controller/lflow.h
index e98edf81d..699f9c2d5 100644
--- a/controller/lflow.h
+++ b/controller/lflow.h
@@ -144,7 +144,7 @@  struct lflow_ctx_in {
     const struct shash *addr_sets;
     const struct shash *port_groups;
     const struct sset *active_tunnels;
-    const struct sset *local_lport_ids;
+    const struct sset *related_lport_ids;
 };
 
 struct lflow_ctx_out {
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index b6afb8fb9..3bb8b22eb 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -1014,9 +1014,10 @@  struct ed_type_runtime_data {
      * local hypervisor, and localnet ports. */
     struct sset local_lports;
 
-    /* Contains the same ports as local_lports, but in the format:
-     * <datapath-tunnel-key>_<port-tunnel-key> */
-    struct sset local_lport_ids;
+    /* Port bindings that are relevant to the local chassis (VIFs bound
+     * localy, patch ports).
+     */
+    struct related_lports related_lports;
     struct sset active_tunnels;
 
     /* runtime data engine private data. */
@@ -1109,7 +1110,7 @@  en_runtime_data_init(struct engine_node *node OVS_UNUSED,
 
     hmap_init(&data->local_datapaths);
     sset_init(&data->local_lports);
-    sset_init(&data->local_lport_ids);
+    related_lports_init(&data->related_lports);
     sset_init(&data->active_tunnels);
     sset_init(&data->egress_ifaces);
     smap_init(&data->local_iface_ids);
@@ -1127,7 +1128,7 @@  en_runtime_data_cleanup(void *data)
     struct ed_type_runtime_data *rt_data = data;
 
     sset_destroy(&rt_data->local_lports);
-    sset_destroy(&rt_data->local_lport_ids);
+    related_lports_destroy(&rt_data->related_lports);
     sset_destroy(&rt_data->active_tunnels);
     sset_destroy(&rt_data->egress_ifaces);
     smap_destroy(&rt_data->local_iface_ids);
@@ -1219,8 +1220,8 @@  init_binding_ctx(struct engine_node *node,
     b_ctx_out->local_datapaths = &rt_data->local_datapaths;
     b_ctx_out->local_lports = &rt_data->local_lports;
     b_ctx_out->local_lports_changed = false;
-    b_ctx_out->local_lport_ids = &rt_data->local_lport_ids;
-    b_ctx_out->local_lport_ids_changed = false;
+    b_ctx_out->related_lports = &rt_data->related_lports;
+    b_ctx_out->related_lports_changed = false;
     b_ctx_out->non_vif_ports_changed = false;
     b_ctx_out->egress_ifaces = &rt_data->egress_ifaces;
     b_ctx_out->lbinding_data = &rt_data->lbinding_data;
@@ -1235,7 +1236,6 @@  en_runtime_data_run(struct engine_node *node, void *data)
     struct ed_type_runtime_data *rt_data = data;
     struct hmap *local_datapaths = &rt_data->local_datapaths;
     struct sset *local_lports = &rt_data->local_lports;
-    struct sset *local_lport_ids = &rt_data->local_lport_ids;
     struct sset *active_tunnels = &rt_data->active_tunnels;
 
     static bool first_run = true;
@@ -1252,12 +1252,12 @@  en_runtime_data_run(struct engine_node *node, void *data)
         hmap_clear(local_datapaths);
         local_binding_data_destroy(&rt_data->lbinding_data);
         sset_destroy(local_lports);
-        sset_destroy(local_lport_ids);
+        related_lports_destroy(&rt_data->related_lports);
         sset_destroy(active_tunnels);
         sset_destroy(&rt_data->egress_ifaces);
         smap_destroy(&rt_data->local_iface_ids);
         sset_init(local_lports);
-        sset_init(local_lport_ids);
+        related_lports_init(&rt_data->related_lports);
         sset_init(active_tunnels);
         sset_init(&rt_data->egress_ifaces);
         smap_init(&rt_data->local_iface_ids);
@@ -1327,7 +1327,7 @@  runtime_data_sb_port_binding_handler(struct engine_node *node, void *data)
     }
 
     rt_data->local_lports_changed = b_ctx_out.local_lports_changed;
-    if (b_ctx_out.local_lport_ids_changed ||
+    if (b_ctx_out.related_lports_changed ||
             b_ctx_out.non_vif_ports_changed ||
             b_ctx_out.local_lports_changed ||
             !hmap_is_empty(b_ctx_out.tracked_dp_bindings)) {
@@ -1638,11 +1638,8 @@  en_port_groups_run(struct engine_node *node, void *data)
     struct ed_type_runtime_data *rt_data =
         engine_get_input_data("runtime_data", node);
 
-    struct sset *local_b_lports = binding_collect_local_binding_lports(
-        &rt_data->lbinding_data);
-    port_groups_init(pg_table, local_b_lports, &pg->port_group_ssets,
-                     &pg->port_groups_cs_local);
-    binding_destroy_local_binding_lports(local_b_lports);
+    port_groups_init(pg_table, &rt_data->related_lports.lport_names,
+                     &pg->port_group_ssets, &pg->port_groups_cs_local);
 
     engine_set_node_state(node, EN_UPDATED);
 }
@@ -1659,12 +1656,9 @@  port_groups_sb_port_group_handler(struct engine_node *node, void *data)
     struct ed_type_runtime_data *rt_data =
         engine_get_input_data("runtime_data", node);
 
-    struct sset *local_b_lports = binding_collect_local_binding_lports(
-        &rt_data->lbinding_data);
-    port_groups_update(pg_table, local_b_lports, &pg->port_group_ssets,
-                       &pg->port_groups_cs_local, &pg->new, &pg->deleted,
-                       &pg->updated);
-    binding_destroy_local_binding_lports(local_b_lports);
+    port_groups_update(pg_table, &rt_data->related_lports.lport_names,
+                       &pg->port_group_ssets, &pg->port_groups_cs_local,
+                       &pg->new, &pg->deleted, &pg->updated);
 
     if (!sset_is_empty(&pg->new) || !sset_is_empty(&pg->deleted) ||
             !sset_is_empty(&pg->updated)) {
@@ -1697,9 +1691,6 @@  port_groups_runtime_data_handler(struct engine_node *node, void *data)
         goto out;
     }
 
-    struct sset *local_b_lports = binding_collect_local_binding_lports(
-        &rt_data->lbinding_data);
-
     const struct sbrec_port_group *pg_sb;
     SBREC_PORT_GROUP_TABLE_FOR_EACH (pg_sb, pg_table) {
         struct sset *pg_lports = shash_find_data(&pg->port_group_ssets,
@@ -1726,13 +1717,12 @@  port_groups_runtime_data_handler(struct engine_node *node, void *data)
         if (need_update) {
             expr_const_sets_add_strings(&pg->port_groups_cs_local, pg_sb->name,
                                         (const char *const *) pg_sb->ports,
-                                        pg_sb->n_ports, local_b_lports);
+                                        pg_sb->n_ports,
+                                        &rt_data->related_lports.lport_names);
             sset_add(&pg->updated, pg_sb->name);
         }
     }
 
-    binding_destroy_local_binding_lports(local_b_lports);
-
 out:
     if (!sset_is_empty(&pg->new) || !sset_is_empty(&pg->deleted) ||
             !sset_is_empty(&pg->updated)) {
@@ -2042,7 +2032,7 @@  init_lflow_ctx(struct engine_node *node,
     l_ctx_in->addr_sets = addr_sets;
     l_ctx_in->port_groups = port_groups;
     l_ctx_in->active_tunnels = &rt_data->active_tunnels;
-    l_ctx_in->local_lport_ids = &rt_data->local_lport_ids;
+    l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids;
 
     l_ctx_out->flow_table = &fo->flow_table;
     l_ctx_out->group_table = &fo->group_table;
diff --git a/tests/ovn.at b/tests/ovn.at
index db1a0a35c..7a718d4b6 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -26805,6 +26805,50 @@  OVN_CLEANUP([hv1])
 AT_CLEANUP
 ])
 
+# Tests that ACLs referencing port groups that include ports connected to
+# logical routers are correctly applied.
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn -- ACL with Port Group including router ports])
+ovn_start
+net_add n1
+
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+
+check ovn-nbctl \
+    -- lr-add lr \
+    -- ls-add ls \
+    -- lrp-add lr lrp_ls 00:00:00:00:00:01 42.42.42.1/24 \
+    -- lsp-add ls ls_lr \
+    -- lsp-set-addresses ls_lr router \
+    -- lsp-set-type ls_lr router \
+    -- lsp-set-options ls_lr router-port=lr_ls \
+    -- lsp-add ls vm1
+
+check ovn-nbctl pg-add pg ls_lr \
+    -- acl-add pg from-lport 1 'inport == @pg && ip4.dst == 42.42.42.42' drop
+
+check ovs-vsctl add-port br-int vm1 \
+    -- set interface vm1 external_ids:iface-id=vm1
+
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+dp_key=$(fetch_column Datapath_Binding tunnel_key external_ids:name=ls)
+rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=ls_lr)
+
+# Check that ovn-controller adds a flow to drop packets with dest IP
+# 42.42.42.42 coming from the router port.
+AT_CHECK([ovs-ofctl dump-flows br-int table=17 | grep "reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42 actions=drop" -c], [0], [dnl
+1
+])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
 OVN_FOR_EACH_NORTHD([
 AT_SETUP([ovn -- Static route with discard nexthop])
 ovn_start