diff mbox series

[ovs-dev,RFC,2/3] northd: Do some of the more complex match dynamic string alterations.

Message ID 20210616175611.597915-3-mmichels@redhat.com
State Rejected
Headers show
Series Thread-local storage for logical flow matches. | expand

Commit Message

Mark Michelson June 16, 2021, 5:56 p.m. UTC
Signed-off-by: Mark Michelson <mmichels@redhat.com>
---
 northd/ovn-northd.c | 223 ++++++++++++++++++++++----------------------
 1 file changed, 111 insertions(+), 112 deletions(-)
diff mbox series

Patch

diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 6b51d12de..59e3c5f84 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -4441,21 +4441,20 @@  build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op,
             continue;
         }
 
+        struct ds *match = match_get_clear();
         if (ps->n_ipv4_addrs) {
-            struct ds *match = match_get_clear();
             if (pipeline == P_IN) {
                 /* Permit use of the unspecified address for DHCP discovery */
-                struct ds dhcp_match = DS_EMPTY_INITIALIZER;
-                ds_put_format(&dhcp_match, "inport == %s"
+                ds_put_format(match, "inport == %s"
                               " && eth.src == %s"
                               " && ip4.src == 0.0.0.0"
                               " && ip4.dst == 255.255.255.255"
                               " && udp.src == 68 && udp.dst == 67",
                               op->json_key, ps->ea_s);
                 ovn_lflow_add_with_hint(lflows, op->od, stage, 90,
-                                        ds_cstr(&dhcp_match), "next;",
+                                        ds_cstr(match), "next;",
                                         stage_hint);
-                ds_destroy(&dhcp_match);
+                ds_clear(match);
                 ds_put_format(match, "inport == %s && eth.src == %s"
                               " && ip4.src == {", op->json_key,
                               ps->ea_s);
@@ -4498,22 +4497,21 @@  build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op,
                                     stage_hint);
         }
 
+        ds_clear(match);
         if (ps->n_ipv6_addrs) {
-            struct ds *match = match_get_clear();
             if (pipeline == P_IN) {
                 /* Permit use of unspecified address for duplicate address
                  * detection */
-                struct ds dad_match = DS_EMPTY_INITIALIZER;
-                ds_put_format(&dad_match, "inport == %s"
+                ds_put_format(match, "inport == %s"
                               " && eth.src == %s"
                               " && ip6.src == ::"
                               " && ip6.dst == ff02::/16"
                               " && icmp6.type == {131, 135, 143}", op->json_key,
                               ps->ea_s);
                 ovn_lflow_add_with_hint(lflows, op->od, stage, 90,
-                                        ds_cstr(&dad_match), "next;",
+                                        ds_cstr(match), "next;",
                                         stage_hint);
-                ds_destroy(&dad_match);
+                ds_clear(match);
             }
             ds_put_format(match, "%s == %s && %s == %s",
                           port_direction, op->json_key,
@@ -4525,13 +4523,13 @@  build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op,
                                     stage_hint);
         }
 
-        char *match = xasprintf("%s == %s && %s == %s && ip",
-                                port_direction, op->json_key,
-                                pipeline == P_IN ? "eth.src" : "eth.dst",
-                                ps->ea_s);
-        ovn_lflow_add_with_hint(lflows, op->od, stage, 80, match, "drop;",
-                                stage_hint);
-        free(match);
+        ds_clear(match);
+        ds_put_format(match, "%s == %s && %s == %s && ip",
+                      port_direction, op->json_key,
+                      pipeline == P_IN ? "eth.src" : "eth.dst",
+                      ps->ea_s);
+        ovn_lflow_add_with_hint(lflows, op->od, stage, 80, ds_cstr(match),
+                                "drop;", stage_hint);
     }
 
 }
@@ -4981,20 +4979,17 @@  skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op,
      * know about the connection, as the icmp request went through the logical
      * router on hostA, not hostB. This would only work with distributed
      * conntrack state across all chassis. */
-    struct ds match_in = DS_EMPTY_INITIALIZER;
-    struct ds match_out = DS_EMPTY_INITIALIZER;
+    struct ds *match = match_get_clear();
 
-    ds_put_format(&match_in, "ip && inport == %s", op->json_key);
-    ds_put_format(&match_out, "ip && outport == %s", op->json_key);
+    ds_put_format(match, "ip && inport == %s", op->json_key);
     ovn_lflow_add_with_hint(lflows, od, in_stage, priority,
-                            ds_cstr(&match_in), "next;",
+                            ds_cstr(match), "next;",
                             &op->nbsp->header_);
+    ds_clear(match);
+    ds_put_format(match, "ip && outport == %s", op->json_key);
     ovn_lflow_add_with_hint(lflows, od, out_stage, priority,
-                            ds_cstr(&match_out), "next;",
+                            ds_cstr(match), "next;",
                             &op->nbsp->header_);
-
-    ds_destroy(&match_in);
-    ds_destroy(&match_out);
 }
 
 static void
@@ -5494,11 +5489,10 @@  build_acl_log(struct ds *actions, const struct nbrec_acl *acl,
 static void
 build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
                        enum ovn_stage stage, struct nbrec_acl *acl,
-                       struct ds *extra_match, struct ds *extra_actions,
+                       struct ds *match, struct ds *extra_actions,
                        const struct ovsdb_idl_row *stage_hint,
                        const struct shash *meter_groups)
 {
-    struct ds match = DS_EMPTY_INITIALIZER;
     struct ds actions = DS_EMPTY_INITIALIZER;
     bool ingress = (stage == S_SWITCH_IN_ACL);
 
@@ -5509,10 +5503,10 @@  build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
                           : ovn_stage_get_table(S_SWITCH_IN_L2_LKUP));
 
     build_acl_log(&actions, acl, meter_groups);
-    if (extra_match->length > 0) {
-        ds_put_format(&match, "(%s) && ", extra_match->string);
+    if (match->length > 0) {
+        ds_put_cstr(match, " && ");
     }
-    ds_put_cstr(&match, acl->match);
+    ds_put_cstr(match, acl->match);
 
     if (extra_actions->length > 0) {
         ds_put_format(&actions, "%s ", extra_actions->string);
@@ -5524,10 +5518,9 @@  build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
                   "outport <-> inport; %s };", next_action);
     ovn_lflow_add_with_hint(lflows, od, stage,
                             acl->priority + OVN_ACL_PRI_OFFSET,
-                            ds_cstr(&match), ds_cstr(&actions), stage_hint);
+                            ds_cstr(match), ds_cstr(&actions), stage_hint);
 
     free(next_action);
-    ds_destroy(&match);
     ds_destroy(&actions);
 }
 
@@ -5623,7 +5616,7 @@  consider_acl(struct hmap *lflows, struct ovn_datapath *od,
         if (has_stateful) {
             /* If the packet is not tracked or not part of an established
              * connection, then we can simply reject/drop it. */
-            ds_put_cstr(match, REGBIT_ACL_HINT_DROP " == 1");
+            ds_put_cstr(match, "(" REGBIT_ACL_HINT_DROP " == 1)");
             if (!strcmp(acl->action, "reject")) {
                 build_reject_acl_rules(od, lflows, stage, acl, match,
                                        &actions, &acl->header_, meter_groups);
@@ -5649,7 +5642,7 @@  consider_acl(struct hmap *lflows, struct ovn_datapath *od,
              */
             ds_clear(match);
             ds_clear(&actions);
-            ds_put_cstr(match, REGBIT_ACL_HINT_BLOCK " == 1");
+            ds_put_cstr(match, "(" REGBIT_ACL_HINT_BLOCK " == 1)");
             ds_put_cstr(&actions, "ct_commit { ct_label.blocked = 1; }; ");
             if (!strcmp(acl->action, "reject")) {
                 build_reject_acl_rules(od, lflows, stage, acl, match,
@@ -8690,8 +8683,8 @@  static void
 add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
                    struct ds *match, struct ds *actions, int priority,
                    enum lb_snat_type snat_type, struct ovn_lb_vip *lb_vip,
-                   const char *proto, struct nbrec_load_balancer *lb,
-                   struct shash *meter_groups, struct sset *nat_entries)
+                   struct nbrec_load_balancer *lb,
+                   struct shash *meter_groups)
 {
     build_empty_lb_event_flow(od, lflows, lb_vip, lb, S_ROUTER_IN_DNAT,
                               meter_groups);
@@ -8725,7 +8718,15 @@  add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
 
     free(new_match);
     free(est_match);
+}
 
+static void
+add_router_lb_undnat_unsnat_flows(struct hmap *lflows, struct ovn_datapath *od,
+                               enum lb_snat_type snat_type,
+                               struct ovn_lb_vip *lb_vip, const char *proto,
+                               struct nbrec_load_balancer *lb,
+                               struct sset *nat_entries)
+{
     const char *ip_match = NULL;
     if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
         ip_match = "ip4";
@@ -8733,6 +8734,8 @@  add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
         ip_match = "ip6";
     }
 
+    struct ds *match = match_get_clear();
+   
     if (sset_contains(nat_entries, lb_vip->vip_str)) {
         /* The load balancer vip is also present in the NAT entries.
          * So add a high priority lflow to advance the the packet
@@ -8745,18 +8748,15 @@  add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
          * unsnat stage, the conntrack flags are not set properly, and
          * it doesn't hit the established state flows in
          * S_ROUTER_IN_DNAT stage. */
-        struct ds unsnat_match = DS_EMPTY_INITIALIZER;
-        ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s",
+        ds_put_format(match, "%s && %s.dst == %s && %s",
                       ip_match, ip_match, lb_vip->vip_str, proto);
         if (lb_vip->vip_port) {
-            ds_put_format(&unsnat_match, " && %s.dst == %d", proto,
+            ds_put_format(match, " && %s.dst == %d", proto,
                           lb_vip->vip_port);
         }
 
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120,
-                                ds_cstr(&unsnat_match), "next;", &lb->header_);
-
-        ds_destroy(&unsnat_match);
+                                ds_cstr(match), "next;", &lb->header_);
     }
 
     if (!od->l3dgw_port || !od->l3redirect_port || !lb_vip->n_backends) {
@@ -8767,43 +8767,41 @@  add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
      * the router egress pipleine stage - S_ROUTER_OUT_UNDNAT if the logical
      * router has a gateway router port associated.
      */
-    struct ds undnat_match = DS_EMPTY_INITIALIZER;
-    ds_put_format(&undnat_match, "%s && (", ip_match);
+    ds_clear(match);
+    ds_put_format(match, "%s && (", ip_match);
 
     for (size_t i = 0; i < lb_vip->n_backends; i++) {
         struct ovn_lb_backend *backend = &lb_vip->backends[i];
-        ds_put_format(&undnat_match, "(%s.src == %s", ip_match,
+        ds_put_format(match, "(%s.src == %s", ip_match,
                       backend->ip_str);
 
         if (backend->port) {
-            ds_put_format(&undnat_match, " && %s.src == %d) || ",
+            ds_put_format(match, " && %s.src == %d) || ",
                           proto, backend->port);
         } else {
-            ds_put_cstr(&undnat_match, ") || ");
+            ds_put_cstr(match, ") || ");
         }
     }
 
-    ds_chomp(&undnat_match, ' ');
-    ds_chomp(&undnat_match, '|');
-    ds_chomp(&undnat_match, '|');
-    ds_chomp(&undnat_match, ' ');
-    ds_put_format(&undnat_match, ") && outport == %s && "
+    ds_chomp(match, ' ');
+    ds_chomp(match, '|');
+    ds_chomp(match, '|');
+    ds_chomp(match, ' ');
+    ds_put_format(match, ") && outport == %s && "
                  "is_chassis_resident(%s)", od->l3dgw_port->json_key,
                  od->l3redirect_port->json_key);
     if (snat_type == FORCE_SNAT || snat_type == SKIP_SNAT) {
         char *action = xasprintf("flags.%s_snat_for_lb = 1; ct_dnat;",
                                  snat_type == SKIP_SNAT ? "skip" : "force");
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120,
-                                ds_cstr(&undnat_match), action,
+                                ds_cstr(match), action,
                                 &lb->header_);
         free(action);
     } else {
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120,
-                                ds_cstr(&undnat_match), "ct_dnat;",
+                                ds_cstr(match), "ct_dnat;",
                                 &lb->header_);
     }
-
-    ds_destroy(&undnat_match);
 }
 
 static void
@@ -8898,8 +8896,10 @@  build_lrouter_lb_flows(struct hmap *lflows, struct ovn_datapath *od,
                 snat_type = FORCE_SNAT;
             }
             add_router_lb_flow(lflows, od, match, actions, prio,
-                               snat_type, lb_vip, proto, nb_lb,
-                               meter_groups, nat_entries);
+                               snat_type, lb_vip, nb_lb,
+                               meter_groups);
+            add_router_lb_undnat_unsnat_flows(lflows, od, snat_type, lb_vip,
+                                              proto, nb_lb, nat_entries);
         }
     }
     sset_destroy(&all_ips);
@@ -9274,9 +9274,10 @@  build_lrouter_drop_own_dest(struct ovn_port *op, enum ovn_stage stage,
                             uint16_t priority, bool drop_snat_ip,
                             struct hmap *lflows)
 {
-    struct ds match_ips = DS_EMPTY_INITIALIZER;
+    struct ds *match_ips = match_get_clear();
 
     if (op->lrp_networks.n_ipv4_addrs) {
+        ds_put_cstr(match_ips, "ip4.dst == {");
         for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
             const char *ip = op->lrp_networks.ipv4_addrs[i].addr_s;
 
@@ -9284,24 +9285,25 @@  build_lrouter_drop_own_dest(struct ovn_port *op, enum ovn_stage stage,
             bool drop_router_ip = (drop_snat_ip == router_ip_in_snat_ips);
 
             if (drop_router_ip) {
-                ds_put_format(&match_ips, "%s, ", ip);
+                ds_put_format(match_ips, "%s, ", ip);
             }
         }
 
-        if (ds_last(&match_ips) != EOF) {
-            ds_chomp(&match_ips, ' ');
-            ds_chomp(&match_ips, ',');
+        if (ds_last(match_ips) != EOF) {
+            ds_chomp(match_ips, ' ');
+            ds_chomp(match_ips, ',');
 
-            char *match = xasprintf("ip4.dst == {%s}", ds_cstr(&match_ips));
+            ds_put_cstr(match_ips, "}");
             ovn_lflow_add_with_hint(lflows, op->od, stage, priority,
-                                    match, "drop;",
+                                    ds_cstr(match_ips), "drop;",
                                     &op->nbrp->header_);
-            free(match);
         }
     }
 
     if (op->lrp_networks.n_ipv6_addrs) {
-        ds_clear(&match_ips);
+        ds_clear(match_ips);
+
+        ds_put_cstr(match_ips, "ip6.dst == {");
 
         for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
             const char *ip = op->lrp_networks.ipv6_addrs[i].addr_s;
@@ -9310,22 +9312,20 @@  build_lrouter_drop_own_dest(struct ovn_port *op, enum ovn_stage stage,
             bool drop_router_ip = (drop_snat_ip == router_ip_in_snat_ips);
 
             if (drop_router_ip) {
-                ds_put_format(&match_ips, "%s, ", ip);
+                ds_put_format(match_ips, "%s, ", ip);
             }
         }
 
-        if (ds_last(&match_ips) != EOF) {
-            ds_chomp(&match_ips, ' ');
-            ds_chomp(&match_ips, ',');
+        if (ds_last(match_ips) != EOF) {
+            ds_chomp(match_ips, ' ');
+            ds_chomp(match_ips, ',');
 
-            char *match = xasprintf("ip6.dst == {%s}", ds_cstr(&match_ips));
+            ds_put_cstr(match_ips, "}");
             ovn_lflow_add_with_hint(lflows, op->od, stage, priority,
-                                    match, "drop;",
+                                    ds_cstr(match_ips), "drop;",
                                     &op->nbrp->header_);
-            free(match);
         }
     }
-    ds_destroy(&match_ips);
 }
 
 static void
@@ -11872,7 +11872,6 @@  struct lswitch_flow_build_info {
     struct hmap *lbs;
     struct hmap *bfd_connections;
     char *svc_check_match;
-    struct ds match;
     struct ds actions;
 };
 
@@ -11885,7 +11884,8 @@  struct lswitch_flow_build_info {
 
 static void
 build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od,
-                                        struct lswitch_flow_build_info *lsi)
+                                        struct lswitch_flow_build_info *lsi,
+                                        struct ds *match)
 {
     /* Build Logical Switch Flows. */
     build_lswitch_lflows_pre_acl_and_acl(od, lsi->port_groups, lsi->lflows,
@@ -11903,69 +11903,70 @@  build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od,
 
     /* Build Logical Router Flows. */
     build_adm_ctrl_flows_for_lrouter(od, lsi->lflows);
-    build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match,
+    build_neigh_learning_flows_for_lrouter(od, lsi->lflows, match,
                                            &lsi->actions);
     build_ND_RA_flows_for_lrouter(od, lsi->lflows);
     build_static_route_flows_for_lrouter(od, lsi->lflows, lsi->ports,
                                          lsi->bfd_connections);
-    build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match,
+    build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, match,
                                          &lsi->actions);
     build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->ports);
     build_arp_resolve_flows_for_lrouter(od, lsi->lflows);
     build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->ports,
-                                          &lsi->match, &lsi->actions);
-    build_gateway_redirect_flows_for_lrouter(od, lsi->lflows, &lsi->match,
+                                          match, &lsi->actions);
+    build_gateway_redirect_flows_for_lrouter(od, lsi->lflows, match,
                                              &lsi->actions);
-    build_arp_request_flows_for_lrouter(od, lsi->lflows, &lsi->match,
+    build_arp_request_flows_for_lrouter(od, lsi->lflows, match,
                                         &lsi->actions);
     build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows);
     build_lrouter_arp_nd_for_datapath(od, lsi->lflows);
     build_lrouter_nat_defrag_and_lb(od, lsi->lflows, lsi->meter_groups,
-                                    lsi->lbs, &lsi->match, &lsi->actions);
+                                    lsi->lbs, match, &lsi->actions);
 }
 
 /* Helper function to combine all lflow generation which is iterated by port.
  */
 static void
 build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op,
-                                        struct lswitch_flow_build_info *lsi)
+                                        struct lswitch_flow_build_info *lsi,
+                                        struct ds *match)
 {
     /* Build Logical Switch Flows. */
     build_lswitch_input_port_sec_op(op, lsi->lflows, &lsi->actions,
-                                    &lsi->match);
+                                    match);
     build_lswitch_learn_fdb_op(op, lsi->lflows, &lsi->actions,
-                               &lsi->match);
+                               match);
     build_lswitch_arp_nd_responder_skip_local(op, lsi->lflows,
-                                              &lsi->match);
+                                              match);
     build_lswitch_arp_nd_responder_known_ips(op, lsi->lflows,
                                              lsi->ports,
                                              &lsi->actions,
-                                             &lsi->match);
+                                             match);
     build_lswitch_dhcp_options_and_response(op, lsi->lflows);
     build_lswitch_external_port(op, lsi->lflows);
     build_lswitch_ip_unicast_lookup(op, lsi->lflows, lsi->mcgroups,
-                                    &lsi->actions, &lsi->match);
+                                    &lsi->actions, match);
     build_lswitch_output_port_sec_op(op, lsi->lflows,
-                                     &lsi->actions, &lsi->match);
+                                     &lsi->actions, match);
 
     /* Build Logical Router Flows. */
-    build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
+    build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, match,
                                           &lsi->actions);
-    build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
+    build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, match,
                                                 &lsi->actions);
     build_ip_routing_flows_for_lrouter_port(op, lsi->lflows);
-    build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
+    build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, match,
                                        &lsi->actions);
     build_arp_resolve_flows_for_lrouter_port(op, lsi->lflows, lsi->ports,
-                                             &lsi->match, &lsi->actions);
-    build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
+                                             match, &lsi->actions);
+    build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, match,
                                                  &lsi->actions);
-    build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match);
+    build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, match);
     build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows,
-                                            &lsi->match, &lsi->actions);
+                                            match, &lsi->actions);
     build_lrouter_ipv4_ip_input(op, lsi->lflows,
-                                &lsi->match, &lsi->actions);
-    build_lrouter_force_snat_flows_op(op, lsi->lflows, &lsi->match,
+                                match, &lsi->actions);
+    build_lrouter_force_snat_flows_op(op, lsi->lflows, match,
                                       &lsi->actions);
 }
 
@@ -11994,6 +11995,7 @@  build_lflows_thread(void *arg)
         if (stop_parallel_processing()) {
             return NULL;
         }
+        struct ds *match = match_get_clear();
         if (lsi && workload) {
             /* Iterate over bucket ThreadID, ThreadID+size, ... */
             for (bnum = control->id;
@@ -12004,7 +12006,7 @@  build_lflows_thread(void *arg)
                     if (stop_parallel_processing()) {
                         return NULL;
                     }
-                    build_lswitch_and_lrouter_iterate_by_od(od, lsi);
+                    build_lswitch_and_lrouter_iterate_by_od(od, lsi, match);
                 }
             }
             for (bnum = control->id;
@@ -12015,7 +12017,7 @@  build_lflows_thread(void *arg)
                     if (stop_parallel_processing()) {
                         return NULL;
                     }
-                    build_lswitch_and_lrouter_iterate_by_op(op, lsi);
+                    build_lswitch_and_lrouter_iterate_by_op(op, lsi, match);
                 }
             }
             for (bnum = control->id;
@@ -12027,7 +12029,7 @@  build_lflows_thread(void *arg)
                         return NULL;
                     }
                     build_lswitch_arp_nd_service_monitor(lb, lsi->lflows,
-                                                         &lsi->match,
+                                                         match,
                                                          &lsi->actions);
                 }
             }
@@ -12041,7 +12043,7 @@  build_lflows_thread(void *arg)
                         return NULL;
                     }
                     build_lswitch_ip_mcast_igmp_mld(igmp_group, lsi->lflows,
-                                                    &lsi->match,
+                                                    match,
                                                     &lsi->actions);
                 }
             }
@@ -12140,7 +12142,6 @@  build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
             lsiv[index].lbs = lbs;
             lsiv[index].bfd_connections = bfd_connections;
             lsiv[index].svc_check_match = svc_check_match;
-            ds_init(&lsiv[index].match);
             ds_init(&lsiv[index].actions);
 
             build_lflows_pool->pool->controls[index].data = &lsiv[index];
@@ -12154,7 +12155,6 @@  build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
         }
 
         for (index = 0; index < build_lflows_pool->pool->size; index++) {
-            ds_destroy(&lsiv[index].match);
             ds_destroy(&lsiv[index].actions);
         }
         free(lflow_segs);
@@ -12175,32 +12175,31 @@  build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
             .lbs = lbs,
             .bfd_connections = bfd_connections,
             .svc_check_match = svc_check_match,
-            .match = DS_EMPTY_INITIALIZER,
             .actions = DS_EMPTY_INITIALIZER,
         };
 
+        struct ds *match = match_get_clear();
         /* Combined build - all lflow generation from lswitch and lrouter
          * will move here and will be reogranized by iterator type.
          */
         HMAP_FOR_EACH (od, key_node, datapaths) {
-            build_lswitch_and_lrouter_iterate_by_od(od, &lsi);
+            build_lswitch_and_lrouter_iterate_by_od(od, &lsi, match);
         }
         HMAP_FOR_EACH (op, key_node, ports) {
-            build_lswitch_and_lrouter_iterate_by_op(op, &lsi);
+            build_lswitch_and_lrouter_iterate_by_op(op, &lsi, match);
         }
         HMAP_FOR_EACH (lb, hmap_node, lbs) {
             build_lswitch_arp_nd_service_monitor(lb, lsi.lflows,
                                                  &lsi.actions,
-                                                 &lsi.match);
+                                                 match);
         }
         HMAP_FOR_EACH (igmp_group, hmap_node, igmp_groups) {
             build_lswitch_ip_mcast_igmp_mld(igmp_group,
                                             lsi.lflows,
                                             &lsi.actions,
-                                            &lsi.match);
+                                            match);
         }
 
-        ds_destroy(&lsi.match);
         ds_destroy(&lsi.actions);
     }