@@ -392,6 +392,106 @@ lflow_handle_changed_flows(struct ovn_desired_flow_table *flow_table,
return ret;
}
+bool
+lflow_handle_changed_ref(struct ovn_desired_flow_table *flow_table,
+ struct lflow_resource_ref *lfrr,
+ enum ref_type ref_type,
+ const char *ref_name,
+ struct controller_ctx *ctx,
+ const struct sbrec_chassis *chassis,
+ const struct chassis_index *chassis_index,
+ const struct hmap *local_datapaths,
+ struct ovn_extend_table *group_table,
+ struct ovn_extend_table *meter_table,
+ const struct shash *addr_sets,
+ const struct shash *port_groups,
+ struct sset *active_tunnels,
+ struct sset *local_lport_ids,
+ uint32_t *conj_id_ofs,
+ bool *changed)
+{
+ struct ref_lflow_node *rlfn = ref_lflow_lookup(&lfrr->ref_lflow_table,
+ ref_type, ref_name);
+ if (!rlfn) {
+ *changed = false;
+ return true;
+ }
+ VLOG_DBG("Handle changed lflow reference for resource type: %d,"
+ " name: %s.", ref_type, ref_name);
+ *changed = false;
+ bool ret = true;
+
+ hmap_remove(&lfrr->ref_lflow_table, &rlfn->node);
+
+ struct lflow_ref_list_node *lrln, *next;
+ /* Detach the rlfn->ref_lflow_head nodes from the lfrr table and clean
+ * up all other nodes related to the lflows that uses the resource,
+ * so that the old nodes won't interfere with updating the lfrr table
+ * when reparsing the lflows. */
+ LIST_FOR_EACH (lrln, ref_list, &rlfn->ref_lflow_head) {
+ ovs_list_remove(&lrln->lflow_list);
+ lflow_resource_destroy_lflow(lfrr, &lrln->lflow_uuid);
+ }
+
+ struct hmap dhcp_opts = HMAP_INITIALIZER(&dhcp_opts);
+ struct hmap dhcpv6_opts = HMAP_INITIALIZER(&dhcpv6_opts);
+ const struct sbrec_dhcp_options *dhcp_opt_row;
+ SBREC_DHCP_OPTIONS_FOR_EACH (dhcp_opt_row, ctx->ovnsb_idl) {
+ dhcp_opt_add(&dhcp_opts, dhcp_opt_row->name, dhcp_opt_row->code,
+ dhcp_opt_row->type);
+ }
+
+
+ const struct sbrec_dhcpv6_options *dhcpv6_opt_row;
+ SBREC_DHCPV6_OPTIONS_FOR_EACH(dhcpv6_opt_row, ctx->ovnsb_idl) {
+ dhcp_opt_add(&dhcpv6_opts, dhcpv6_opt_row->name, dhcpv6_opt_row->code,
+ dhcpv6_opt_row->type);
+ }
+
+ struct hmap nd_ra_opts = HMAP_INITIALIZER(&nd_ra_opts);
+ nd_ra_opts_init(&nd_ra_opts);
+
+ /* Re-parse the related lflows. */
+ LIST_FOR_EACH (lrln, ref_list, &rlfn->ref_lflow_head) {
+ const struct sbrec_logical_flow *lflow =
+ sbrec_logical_flow_get_for_uuid(ctx->ovnsb_idl,
+ &lrln->lflow_uuid);
+ if (!lflow) {
+ VLOG_DBG("Reprocess lflow "UUID_FMT" for resource type: %d,"
+ " name: %s - not found.",
+ UUID_ARGS(&lrln->lflow_uuid),
+ ref_type, ref_name);
+ continue;
+ }
+ VLOG_DBG("Reprocess lflow "UUID_FMT" for resource type: %d,"
+ " name: %s.",
+ UUID_ARGS(&lrln->lflow_uuid),
+ ref_type, ref_name);
+ ofctrl_remove_flows(flow_table, &lrln->lflow_uuid);
+ if (!consider_logical_flow(flow_table, lfrr, ctx, chassis_index,
+ lflow, local_datapaths,
+ group_table, meter_table, chassis,
+ &dhcp_opts, &dhcpv6_opts, &nd_ra_opts,
+ conj_id_ofs, addr_sets, port_groups,
+ active_tunnels, local_lport_ids)) {
+ ret = false;
+ break;
+ }
+ *changed = true;
+ }
+
+ LIST_FOR_EACH_SAFE (lrln, next, ref_list, &rlfn->ref_lflow_head) {
+ ovs_list_remove(&lrln->ref_list);
+ free(lrln);
+ }
+ free(rlfn);
+
+ dhcp_opts_destroy(&dhcp_opts);
+ dhcp_opts_destroy(&dhcpv6_opts);
+ nd_ra_opts_destroy(&nd_ra_opts);
+ return ret;
+}
+
static bool
update_conj_id_ofs(uint32_t *conj_id_ofs, uint32_t n_conjs)
{
@@ -139,6 +139,22 @@ bool lflow_handle_changed_flows(struct ovn_desired_flow_table *,
struct sset *active_tunnels,
struct sset *local_lport_ids,
uint32_t *conj_id_ofs);
+bool lflow_handle_changed_ref(struct ovn_desired_flow_table *,
+ struct lflow_resource_ref *,
+ enum ref_type,
+ const char *ref_name,
+ struct controller_ctx *ctx,
+ const struct sbrec_chassis *chassis,
+ const struct chassis_index *chassis_index,
+ const struct hmap *local_datapaths,
+ struct ovn_extend_table *group_table,
+ struct ovn_extend_table *meter_table,
+ const struct shash *addr_sets,
+ const struct shash *port_groups,
+ struct sset *active_tunnels,
+ struct sset *local_lport_ids,
+ uint32_t *conj_id_ofs,
+ bool *changed);
void lflow_destroy(void);
#endif /* ovn/lflow.h */
@@ -1075,6 +1075,76 @@ flow_output_sb_multicast_group_handler(struct engine_node *node)
}
+static bool
+flow_output_addr_sets_handler(struct engine_node *node)
+{
+ struct controller_ctx *ctx = (struct controller_ctx *)node->context;
+ struct ed_type_runtime_data *data =
+ (struct ed_type_runtime_data *)engine_get_input(
+ "runtime_data", node)->data;
+ struct hmap *local_datapaths = &data->local_datapaths;
+ struct sset *local_lport_ids = &data->local_lport_ids;
+ struct sset *active_tunnels = &data->active_tunnels;
+ struct chassis_index *chassis_index = &data->chassis_index;
+ struct shash *port_groups = &data->port_groups;
+ struct ed_type_addr_sets *as_data =
+ (struct ed_type_addr_sets *)engine_get_input("addr_sets", node)->data;
+ struct shash *addr_sets = &as_data->addr_sets;
+ const struct ovsrec_bridge *br_int = get_br_int(ctx);
+ const char *chassis_id = get_chassis_id(ctx->ovs_idl);
+
+ const struct sbrec_chassis *chassis = NULL;
+ if (chassis_id) {
+ chassis = get_chassis(ctx->ovnsb_idl, chassis_id);
+ }
+
+ ovs_assert(br_int && chassis);
+
+ struct ed_type_flow_output *fo =
+ (struct ed_type_flow_output *)node->data;
+ struct ovn_desired_flow_table *flow_table = &fo->flow_table;
+ struct ovn_extend_table *group_table = &fo->group_table;
+ struct ovn_extend_table *meter_table = &fo->meter_table;
+ uint32_t *conj_id_ofs = &fo->conj_id_ofs;
+ struct lflow_resource_ref *lfrr = &fo->lflow_resource_ref;
+
+ bool changed;
+ const char *as;
+
+ SSET_FOR_EACH (as, &as_data->deleted) {
+ if (!lflow_handle_changed_ref(flow_table, lfrr, REF_TYPE_ADDRSET,
+ as, ctx, chassis, chassis_index, local_datapaths,
+ group_table, meter_table, addr_sets, port_groups,
+ active_tunnels, local_lport_ids, conj_id_ofs,
+ &changed)) {
+ return false;
+ }
+ node->changed = changed || node->changed;
+ }
+ SSET_FOR_EACH (as, &as_data->updated) {
+ if (!lflow_handle_changed_ref(flow_table, lfrr, REF_TYPE_ADDRSET,
+ as, ctx, chassis, chassis_index, local_datapaths,
+ group_table, meter_table, addr_sets, port_groups,
+ active_tunnels, local_lport_ids, conj_id_ofs,
+ &changed)) {
+ return false;
+ }
+ node->changed = changed || node->changed;
+ }
+ SSET_FOR_EACH (as, &as_data->new) {
+ if (!lflow_handle_changed_ref(flow_table, lfrr, REF_TYPE_ADDRSET,
+ as, ctx, chassis, chassis_index, local_datapaths,
+ group_table, meter_table, addr_sets, port_groups,
+ active_tunnels, local_lport_ids, conj_id_ofs,
+ &changed)) {
+ return false;
+ }
+ node->changed = changed || node->changed;
+ }
+
+ return true;
+}
+
int
main(int argc, char *argv[])
{
@@ -1156,7 +1226,7 @@ main(int argc, char *argv[])
engine_add_input(&en_addr_sets, &en_sb_address_set, NULL);
- engine_add_input(&en_flow_output, &en_addr_sets, NULL);
+ engine_add_input(&en_flow_output, &en_addr_sets, flow_output_addr_sets_handler);
engine_add_input(&en_flow_output, &en_runtime_data, NULL);
engine_add_input(&en_flow_output, &en_ovs_port, NULL);
@@ -10267,3 +10267,74 @@ $PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
AT_CHECK([cat 2.packets], [0], [])
AT_CLEANUP
+
+AT_SETUP([ovn -- Address Set Incremental Processing])
+AT_KEYWORDS([ovn_as_inc])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.10
+
+ovn-nbctl ls-add ls1
+for i in 1 2; do
+ ovn-nbctl lsp-add ls1 lp$i \
+ -- lsp-set-addresses lp$i "f0:00:00:00:00:0$i 192.168.1.$i"
+ as hv1 ovs-vsctl \
+ -- add-port br-int vif$i \
+ -- set Interface vif$i \
+ external-ids:iface-id=lp$i
+done
+
+for i in 1 2 3; do
+ as1_uuid=`ovn-nbctl --wait=hv create addr name=as1`
+ as2_uuid=`ovn-nbctl --wait=hv create addr name=as2`
+ ovn-nbctl --wait=hv acl-add ls1 to-lport 200 \
+ 'outport=="lp1" && ip4 && ip4.src == {$as1, $as2}' allow-related
+ ovn-nbctl --wait=hv set addr as1 addresses="10.1.2.10"
+ AT_CHECK([ovs-ofctl dump-flows br-int | grep "10.1.2.10"], [0], [ignore])
+
+ # Update address set as1
+ ovn-nbctl --wait=hv set addr as1 addresses="10.1.2.10 10.1.2.11"
+ AT_CHECK([ovs-ofctl dump-flows br-int | grep "10.1.2.11"], [0], [ignore])
+
+ # Update address set as2
+ ovn-nbctl --wait=hv set addr as2 addresses="10.1.2.12 10.1.2.13"
+ AT_CHECK([ovs-ofctl dump-flows br-int | grep "10.1.2.12"], [0], [ignore])
+
+ # Add another ACL referencing as1
+ n_flows_before=`ovs-ofctl dump-flows br-int | grep "10.1.2.10" | wc -l`
+ ovn-nbctl --wait=hv acl-add ls1 to-lport 200 \
+ 'outport=="lp2" && ip4 && ip4.src == $as1' allow-related
+ n_flows_after=`ovs-ofctl dump-flows br-int | grep "10.1.2.10" | wc -l`
+ AT_CHECK([test $(expr $n_flows_before \* 2) = $n_flows_after], [0], [ignore])
+
+ # Remove an ACL
+ ovn-nbctl --wait=hv acl-del ls1 to-lport 200 \
+ 'outport=="lp2" && ip4 && ip4.src == $as1'
+ n_flows_after=`ovs-ofctl dump-flows br-int | grep "10.1.2.10" | wc -l`
+ AT_CHECK([test $n_flows_before = $n_flows_after], [0], [ignore])
+
+ # Remove as1 while it is still used by an ACL, the lflows should be reparsed and
+ # parsing should fail.
+ ovn-nbctl --wait=hv destroy addr $as1_uuid
+ AT_CHECK([ovs-ofctl dump-flows br-int | grep "10.1.2.10"], [1], [ignore])
+ AT_CHECK([ovs-ofctl dump-flows br-int | grep "10.1.2.12"], [1], [ignore])
+
+ # Recreate as1
+ as1_uuid=`ovn-nbctl --wait=hv create addr name=as1`
+ AT_CHECK([ovs-ofctl dump-flows br-int | grep "10.1.2.12"], [0], [ignore])
+
+ # Remove ACLs and address sets
+ ovn-nbctl --wait=hv destroy addr $as1_uuid -- destroy addr $as2_uuid
+ AT_CHECK([ovs-ofctl dump-flows br-int | grep "10.1.2.12"], [1], [ignore])
+
+ ovn-nbctl --wait=hv acl-del ls1
+done
+
+# Gracefully terminate daemons
+OVN_CLEANUP([hv1])
+AT_CLEANUP
Signed-off-by: Han Zhou <hzhou8@ebay.com> --- ovn/controller/lflow.c | 100 ++++++++++++++++++++++++++++++++++++++++ ovn/controller/lflow.h | 16 +++++++ ovn/controller/ovn-controller.c | 72 ++++++++++++++++++++++++++++- tests/ovn.at | 71 ++++++++++++++++++++++++++++ 4 files changed, 258 insertions(+), 1 deletion(-)