Message ID | 1579275884-16018-1-git-send-email-dceara@redhat.com |
---|---|
State | Superseded |
Headers | show |
Series | [ovs-dev,ovn] ovn-northd: Set stage-hint for all applicable flows. | expand |
Hi Dumitru, It appears that some of the stage hints correspond to DHCPv4_Options and DHCPv6_Options, but these are not handled in ovn-detrace. On 1/17/20 10:44 AM, Dumitru Ceara wrote: > Until now the 'stage-hint' external-id was set only for logical flows > installed for ACLs. In order to simplify troubleshooting, extend the > approach and apply whenever possible. Set stage-hint for logical flows > generated by the following NB tables too: > - Logical_Switch_Port > - Logical_Router_Port > - Load_Balancer > - NAT > > Also update ovn-detrace such that whenever stage-hints are available, > all the tables mentioned above are queried and if the stage-hint matches > a NB uuid, relevant information is dumped. > > Signed-off-by: Dumitru Ceara <dceara@redhat.com> > --- > northd/ovn-northd.c | 721 +++++++++++++++++++++++++++++------------------ > utilities/ovn-detrace.in | 93 ++++-- > 2 files changed, 524 insertions(+), 290 deletions(-) > > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c > index b6dc809..20b8429 100644 > --- a/northd/ovn-northd.c > +++ b/northd/ovn-northd.c > @@ -3714,6 +3714,15 @@ ovn_lflow_hash(const struct ovn_lflow *lflow) > lflow->actions); > } > > +static char * > +ovn_lflow_hint(const struct ovsdb_idl_row *row) > +{ > + if (!row) { > + return NULL; > + } > + return xasprintf("%08x", row->uuid.parts[0]); > +} > + > static bool > ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b) > { > @@ -3744,14 +3753,14 @@ static void > ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, > enum ovn_stage stage, uint16_t priority, > const char *match, const char *actions, > - const char *stage_hint, const char *where) > + const struct ovsdb_idl_row *stage_hint, const char *where) > { > ovs_assert(ovn_stage_to_datapath_type(stage) == ovn_datapath_get_type(od)); > > struct ovn_lflow *lflow = xmalloc(sizeof *lflow); > ovn_lflow_init(lflow, od, stage, priority, > xstrdup(match), xstrdup(actions), > - nullable_xstrdup(stage_hint), where); > + ovn_lflow_hint(stage_hint), where); > hmap_insert(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow)); > } > > @@ -3902,7 +3911,8 @@ build_port_security_ipv6_flow( > * - Priority 80 flow to drop ARP and IPv6 ND packets. > */ > static void > -build_port_security_nd(struct ovn_port *op, struct hmap *lflows) > +build_port_security_nd(struct ovn_port *op, struct hmap *lflows, > + const struct ovsdb_idl_row *stage_hint) > { > struct ds match = DS_EMPTY_INITIALIZER; > > @@ -3938,8 +3948,8 @@ build_port_security_nd(struct ovn_port *op, struct hmap *lflows) > ds_chomp(&match, ','); > ds_put_cstr(&match, "}"); > } > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, > + 90, ds_cstr(&match), "next;", stage_hint); > } > > if (ps->n_ipv6_addrs || no_ip) { > @@ -3948,15 +3958,15 @@ build_port_security_nd(struct ovn_port *op, struct hmap *lflows) > op->json_key, ps->ea_s); > build_port_security_ipv6_nd_flow(&match, ps->ea, ps->ipv6_addrs, > ps->n_ipv6_addrs); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, > + 90, ds_cstr(&match), "next;", stage_hint); > } > } > > ds_clear(&match); > ds_put_format(&match, "inport == %s && (arp || nd)", op->json_key); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 80, > - ds_cstr(&match), "drop;"); > + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 80, > + ds_cstr(&match), "drop;", stage_hint); > ds_destroy(&match); > } > > @@ -3977,7 +3987,8 @@ build_port_security_nd(struct ovn_port *op, struct hmap *lflows) > */ > static void > build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, > - struct hmap *lflows) > + struct hmap *lflows, > + const struct ovsdb_idl_row *stage_hint) > { > char *port_direction; > enum ovn_stage stage; > @@ -4007,8 +4018,9 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, > " && ip4.dst == 255.255.255.255" > " && udp.src == 68 && udp.dst == 67", > op->json_key, ps->ea_s); > - ovn_lflow_add(lflows, op->od, stage, 90, > - ds_cstr(&dhcp_match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, stage, 90, > + ds_cstr(&dhcp_match), "next;", > + stage_hint); > ds_destroy(&dhcp_match); > ds_put_format(&match, "inport == %s && eth.src == %s" > " && ip4.src == {", op->json_key, > @@ -4047,7 +4059,9 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, > ds_chomp(&match, ' '); > ds_chomp(&match, ','); > ds_put_cstr(&match, "}"); > - ovn_lflow_add(lflows, op->od, stage, 90, ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, stage, 90, > + ds_cstr(&match), "next;", > + stage_hint); > ds_destroy(&match); > } > > @@ -4063,8 +4077,9 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, > " && ip6.dst == ff02::/16" > " && icmp6.type == {131, 135, 143}", op->json_key, > ps->ea_s); > - ovn_lflow_add(lflows, op->od, stage, 90, > - ds_cstr(&dad_match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, stage, 90, > + ds_cstr(&dad_match), "next;", > + stage_hint); > ds_destroy(&dad_match); > } > ds_put_format(&match, "%s == %s && %s == %s", > @@ -4072,8 +4087,9 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, > pipeline == P_IN ? "eth.src" : "eth.dst", ps->ea_s); > build_port_security_ipv6_flow(pipeline, &match, ps->ea, > ps->ipv6_addrs, ps->n_ipv6_addrs); > - ovn_lflow_add(lflows, op->od, stage, 90, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, stage, 90, > + ds_cstr(&match), "next;", > + stage_hint); > ds_destroy(&match); > } > > @@ -4081,7 +4097,8 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, > port_direction, op->json_key, > pipeline == P_IN ? "eth.src" : "eth.dst", > ps->ea_s); > - ovn_lflow_add(lflows, op->od, stage, 80, match, "drop;"); > + ovn_lflow_add_with_hint(lflows, op->od, stage, 80, match, "drop;", > + stage_hint); > free(match); > } > > @@ -4371,12 +4388,13 @@ build_lswitch_input_port_sec(struct hmap *ports, struct hmap *datapaths, > ds_put_format(&actions, "set_queue(%s); ", queue_id); > } > ds_put_cstr(&actions, "next;"); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbsp->header_); > > if (op->nbsp->n_port_security) { > - build_port_security_ip(P_IN, op, lflows); > - build_port_security_nd(op, lflows); > + build_port_security_ip(P_IN, op, lflows, &op->nbsp->header_); > + build_port_security_nd(op, lflows, &op->nbsp->header_); > } > } > > @@ -4436,15 +4454,17 @@ build_lswitch_output_port_sec(struct hmap *ports, struct hmap *datapaths, > } > } > ds_put_cstr(&actions, "output;"); > - ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, > + 50, ds_cstr(&match), ds_cstr(&actions), > + &op->nbsp->header_); > } else { > - ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 150, > - ds_cstr(&match), "drop;"); > + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, > + 150, ds_cstr(&match), "drop;", > + &op->nbsp->header_); > } > > if (op->nbsp->n_port_security) { > - build_port_security_ip(P_OUT, op, lflows); > + build_port_security_ip(P_OUT, op, lflows, &op->nbsp->header_); > } > } > > @@ -4499,10 +4519,12 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) > > ds_put_format(&match_in, "ip && inport == %s", op->json_key); > ds_put_format(&match_out, "ip && outport == %s", op->json_key); > - ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, > - ds_cstr(&match_in), "next;"); > - ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, > - ds_cstr(&match_out), "next;"); > + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_ACL, 110, > + ds_cstr(&match_in), "next;", > + &op->nbsp->header_); > + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, > + ds_cstr(&match_out), "next;", > + &op->nbsp->header_); > > ds_destroy(&match_in); > ds_destroy(&match_out); > @@ -4515,10 +4537,12 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) > od->localnet_port->json_key); > ds_put_format(&match_out, "ip && outport == %s", > od->localnet_port->json_key); > - ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, > - ds_cstr(&match_in), "next;"); > - ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, > - ds_cstr(&match_out), "next;"); > + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_ACL, 110, > + ds_cstr(&match_in), "next;", > + &od->localnet_port->nbsp->header_); > + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, > + ds_cstr(&match_out), "next;", > + &od->localnet_port->nbsp->header_); > > ds_destroy(&match_in); > ds_destroy(&match_out); > @@ -4596,7 +4620,8 @@ static void > build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, > struct smap_node *node, char *ip_address, > struct nbrec_load_balancer *lb, uint16_t port, > - int addr_family, int pl, struct shash *meter_groups) > + int addr_family, int pl, struct shash *meter_groups, > + const struct ovsdb_idl_row *stage_hint) > { > if (!controller_event_en || node->value[0]) { > return; > @@ -4627,7 +4652,8 @@ build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, > event_to_string(OVN_EVENT_EMPTY_LB_BACKENDS), > meter, node->key, lb->protocol, > UUID_ARGS(&lb->header_.uuid)); > - ovn_lflow_add(lflows, od, pl, 130, ds_cstr(&match), action); > + ovn_lflow_add_with_hint(lflows, od, pl, 130, ds_cstr(&match), action, > + stage_hint); > ds_destroy(&match); > free(action); > } > @@ -4680,7 +4706,7 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows, > > build_empty_lb_event_flow(od, lflows, node, ip_address, lb, > port, addr_family, S_SWITCH_IN_PRE_LB, > - meter_groups); > + meter_groups, &lb->header_); > > free(ip_address); > > @@ -4772,7 +4798,8 @@ 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 *extra_match, struct ds *extra_actions, > + const struct ovsdb_idl_row *stage_hint) > { > struct ds match = DS_EMPTY_INITIALIZER; > struct ds actions = DS_EMPTY_INITIALIZER; > @@ -4788,8 +4815,9 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, > "eth.dst <-> eth.src; ip4.dst <-> ip4.src; " > "tcp_reset { outport <-> inport; %s };", > ingress ? "output;" : "next(pipeline=ingress,table=0);"); > - ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET + 10, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, stage, > + acl->priority + OVN_ACL_PRI_OFFSET + 10, > + ds_cstr(&match), ds_cstr(&actions), stage_hint); > ds_clear(&match); > ds_clear(&actions); > build_acl_log(&actions, acl); > @@ -4801,8 +4829,9 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, > "eth.dst <-> eth.src; ip6.dst <-> ip6.src; " > "tcp_reset { outport <-> inport; %s };", > ingress ? "output;" : "next(pipeline=ingress,table=0);"); > - ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET + 10, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, stage, > + acl->priority + OVN_ACL_PRI_OFFSET + 10, > + ds_cstr(&match), ds_cstr(&actions), stage_hint); > > /* IP traffic */ > ds_clear(&match); > @@ -4819,8 +4848,9 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, > "eth.dst <-> eth.src; ip4.dst <-> ip4.src; " > "icmp4 { outport <-> inport; %s };", > ingress ? "output;" : "next(pipeline=ingress,table=0);"); > - ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, stage, > + acl->priority + OVN_ACL_PRI_OFFSET, > + ds_cstr(&match), ds_cstr(&actions), stage_hint); > ds_clear(&match); > ds_clear(&actions); > build_acl_log(&actions, acl); > @@ -4835,8 +4865,9 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, > "eth.dst <-> eth.src; ip6.dst <-> ip6.src; " > "outport <-> inport; %s };", > ingress ? "output;" : "next(pipeline=ingress,table=0);"); > - ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, stage, > + acl->priority + OVN_ACL_PRI_OFFSET, > + ds_cstr(&match), ds_cstr(&actions), stage_hint); > > ds_destroy(&match); > ds_destroy(&actions); > @@ -4849,7 +4880,6 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > bool ingress = !strcmp(acl->direction, "from-lport") ? true :false; > enum ovn_stage stage = ingress ? S_SWITCH_IN_ACL : S_SWITCH_OUT_ACL; > > - char *stage_hint = xasprintf("%08x", acl->header_.uuid.parts[0]); > if (!strcmp(acl->action, "allow") > || !strcmp(acl->action, "allow-related")) { > /* If there are any stateful flows, we must even commit "allow" > @@ -4864,7 +4894,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > ovn_lflow_add_with_hint(lflows, od, stage, > acl->priority + OVN_ACL_PRI_OFFSET, > acl->match, ds_cstr(&actions), > - stage_hint); > + &acl->header_); > ds_destroy(&actions); > } else { > struct ds match = DS_EMPTY_INITIALIZER; > @@ -4893,7 +4923,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > acl->priority + OVN_ACL_PRI_OFFSET, > ds_cstr(&match), > ds_cstr(&actions), > - stage_hint); > + &acl->header_); > > /* Match on traffic in the request direction for an established > * connection tracking entry that has not been marked for > @@ -4913,7 +4943,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > ovn_lflow_add_with_hint(lflows, od, stage, > acl->priority + OVN_ACL_PRI_OFFSET, > ds_cstr(&match), ds_cstr(&actions), > - stage_hint); > + &acl->header_); > > ds_destroy(&match); > ds_destroy(&actions); > @@ -4935,14 +4965,15 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > " || (ct.est && ct_label.blocked == 1))"); > if (!strcmp(acl->action, "reject")) { > build_reject_acl_rules(od, lflows, stage, acl, &match, > - &actions); > + &actions, &acl->header_); > } else { > ds_put_format(&match, " && (%s)", acl->match); > build_acl_log(&actions, acl); > ds_put_cstr(&actions, "/* drop */"); > - ovn_lflow_add(lflows, od, stage, > - acl->priority + OVN_ACL_PRI_OFFSET, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, stage, > + acl->priority + OVN_ACL_PRI_OFFSET, > + ds_cstr(&match), ds_cstr(&actions), > + &acl->header_); > } > /* For an existing connection without ct_label set, we've > * encountered a policy change. ACLs previously allowed > @@ -4961,14 +4992,15 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > ds_put_cstr(&actions, "ct_commit(ct_label=1/1); "); > if (!strcmp(acl->action, "reject")) { > build_reject_acl_rules(od, lflows, stage, acl, &match, > - &actions); > + &actions, &acl->header_); > } else { > ds_put_format(&match, " && (%s)", acl->match); > build_acl_log(&actions, acl); > ds_put_cstr(&actions, "/* drop */"); > - ovn_lflow_add(lflows, od, stage, > - acl->priority + OVN_ACL_PRI_OFFSET, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, stage, > + acl->priority + OVN_ACL_PRI_OFFSET, > + ds_cstr(&match), ds_cstr(&actions), > + &acl->header_); > } > } else { > /* There are no stateful ACLs in use on this datapath, > @@ -4976,19 +5008,19 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > * logical flow action in all cases. */ > if (!strcmp(acl->action, "reject")) { > build_reject_acl_rules(od, lflows, stage, acl, &match, > - &actions); > + &actions, &acl->header_); > } else { > build_acl_log(&actions, acl); > ds_put_cstr(&actions, "/* drop */"); > - ovn_lflow_add(lflows, od, stage, > - acl->priority + OVN_ACL_PRI_OFFSET, > - acl->match, ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, stage, > + acl->priority + OVN_ACL_PRI_OFFSET, > + acl->match, ds_cstr(&actions), > + &acl->header_); > } > } > ds_destroy(&match); > ds_destroy(&actions); > } > - free(stage_hint); > } > > static struct ovn_port_group * > @@ -5191,9 +5223,9 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, > "&& ip4.src == %s && udp && udp.src == 67 " > "&& udp.dst == 68", od->nbs->ports[i]->name, > server_mac, server_id); > - ovn_lflow_add( > + ovn_lflow_add_with_hint( > lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match), > - actions); > + actions, &od->nbs->ports[i]->dhcpv4_options->header_); > ds_destroy(&match); > } > } > @@ -5218,9 +5250,9 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, > "&& ip6.src == %s && udp && udp.src == 547 " > "&& udp.dst == 546", od->nbs->ports[i]->name, > server_mac, server_ip); > - ovn_lflow_add( > + ovn_lflow_add_with_hint( > lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match), > - actions); > + actions, &od->nbs->ports[i]->dhcpv6_options->header_); > ds_destroy(&match); > } > } > @@ -5257,9 +5289,10 @@ build_qos(struct ovn_datapath *od, struct hmap *lflows) { > > ds_put_format(&dscp_action, "ip.dscp = %"PRId64"; next;", > qos->value_action[j]); > - ovn_lflow_add(lflows, od, stage, > - qos->priority, > - qos->match, ds_cstr(&dscp_action)); > + ovn_lflow_add_with_hint(lflows, od, stage, > + qos->priority, > + qos->match, ds_cstr(&dscp_action), > + &qos->header_); > ds_destroy(&dscp_action); > } > } > @@ -5288,9 +5321,10 @@ build_qos(struct ovn_datapath *od, struct hmap *lflows) { > * > * We limit the bandwidth of this flow by adding a meter table. > */ > - ovn_lflow_add(lflows, od, stage, > - qos->priority, > - qos->match, ds_cstr(&meter_action)); > + ovn_lflow_add_with_hint(lflows, od, stage, > + qos->priority, > + qos->match, ds_cstr(&meter_action), > + &qos->header_); > ds_destroy(&meter_action); > } > } > @@ -5405,11 +5439,13 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows, struct hmap *lbs) > ds_put_format(&match, " && tcp.dst == %d", > lb_vip->vip_port); > } > - ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, > - 120, ds_cstr(&match), ds_cstr(&action)); > + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_STATEFUL, 120, > + ds_cstr(&match), ds_cstr(&action), > + &lb->nlb->header_); > } else { > - ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, > - 110, ds_cstr(&match), ds_cstr(&action)); > + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_STATEFUL, 110, > + ds_cstr(&match), ds_cstr(&action), > + &lb->nlb->header_); > } > > ds_destroy(&match); > @@ -5574,7 +5610,8 @@ build_lswitch_rport_arp_req_flow_for_ip(struct sset *ips, > struct ovn_port *patch_op, > struct ovn_datapath *od, > uint32_t priority, > - struct hmap *lflows) > + struct hmap *lflows, > + const struct ovsdb_idl_row *stage_hint) > { > struct ds match = DS_EMPTY_INITIALIZER; > struct ds actions = DS_EMPTY_INITIALIZER; > @@ -5605,8 +5642,8 @@ build_lswitch_rport_arp_req_flow_for_ip(struct sset *ips, > * in the broadcast domain. > */ > ds_put_format(&actions, "outport = %s; output;", patch_op->json_key); > - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, priority, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, priority, > + ds_cstr(&match), ds_cstr(&actions), stage_hint); > > ds_destroy(&match); > ds_destroy(&actions); > @@ -5623,7 +5660,8 @@ static void > build_lswitch_rport_arp_req_flows(struct ovn_port *op, > struct ovn_datapath *sw_od, > struct ovn_port *sw_op, > - struct hmap *lflows) > + struct hmap *lflows, > + const struct ovsdb_idl_row *stage_hint) > { > if (!op || !op->nbrp) { > return; > @@ -5677,11 +5715,13 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > > if (!sset_is_empty(&all_ips_v4)) { > build_lswitch_rport_arp_req_flow_for_ip(&all_ips_v4, AF_INET, sw_op, > - sw_od, 75, lflows); > + sw_od, 75, lflows, > + stage_hint); > } > if (!sset_is_empty(&all_ips_v6)) { > build_lswitch_rport_arp_req_flow_for_ip(&all_ips_v6, AF_INET6, sw_op, > - sw_od, 75, lflows); > + sw_od, 75, lflows, > + stage_hint); > } > > sset_destroy(&all_ips_v4); > @@ -5752,8 +5792,9 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > (!strcmp(op->nbsp->type, "vtep"))) { > ds_clear(&match); > ds_put_format(&match, "inport == %s", op->json_key); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, > + 100, ds_cstr(&match), "next;", > + &op->nbsp->header_); > } > } > > @@ -5806,8 +5847,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > "bind_vport(%s, inport); " > "next;", > op->json_key); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_ARP_ND_RSP, 100, > + ds_cstr(&match), ds_cstr(&actions), > + &vp->nbsp->header_); > } > > free(tokstr); > @@ -5846,8 +5889,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > "output;", > op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s, > op->lsp_addrs[i].ipv4_addrs[j].addr_s); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_ARP_ND_RSP, 50, > + ds_cstr(&match), > + ds_cstr(&actions), > + &op->nbsp->header_); > > /* Do not reply to an ARP request from the port that owns > * the address (otherwise a DHCP client that ARPs to check > @@ -5862,8 +5908,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > * network is not working as configured, so dropping the > * request would frustrate that intent.) */ > ds_put_format(&match, " && inport == %s", op->json_key); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_ARP_ND_RSP, 100, > + ds_cstr(&match), "next;", > + &op->nbsp->header_); > } > > /* For ND solicitations, we need to listen for both the > @@ -5894,14 +5942,19 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > op->lsp_addrs[i].ipv6_addrs[j].addr_s, > op->lsp_addrs[i].ipv6_addrs[j].addr_s, > op->lsp_addrs[i].ea_s); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_ARP_ND_RSP, 50, > + ds_cstr(&match), > + ds_cstr(&actions), > + &op->nbsp->header_); > > /* Do not reply to a solicitation from the port that owns > * the address (otherwise DAD detection will fail). */ > ds_put_format(&match, " && inport == %s", op->json_key); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_ARP_ND_RSP, 100, > + ds_cstr(&match), "next;", > + &op->nbsp->header_); > } > } > } > @@ -5949,9 +6002,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > "output;", > svc_monitor_mac, svc_monitor_mac, > lb->vips[i].backends[j].svc_mon_src_ip); > - ovn_lflow_add(lflows, lb->vips[i].backends[j].op->od, > - S_SWITCH_IN_ARP_ND_RSP, 110, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, > + lb->vips[i].backends[j].op->od, > + S_SWITCH_IN_ARP_ND_RSP, 110, > + ds_cstr(&match), ds_cstr(&actions), > + &lb->nlb->header_); > } > } > } > @@ -5985,6 +6040,14 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > } > > for (size_t i = 0; i < op->n_lsp_addrs; i++) { > + struct ovsdb_idl_row *stage_hint; > + > + if (op->nbsp->dhcpv4_options) { > + stage_hint = &op->nbsp->dhcpv4_options->header_; > + } else { > + stage_hint = NULL; > + } > + > for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) { > struct ds options_action = DS_EMPTY_INITIALIZER; > struct ds response_action = DS_EMPTY_INITIALIZER; > @@ -6006,9 +6069,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > op->json_key); > } > > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_OPTIONS, > - 100, ds_cstr(&match), > - ds_cstr(&options_action)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_DHCP_OPTIONS, 100, > + ds_cstr(&match), > + ds_cstr(&options_action), > + stage_hint); > ds_clear(&match); > /* Allow ip4.src = OFFER_IP and > * ip4.dst = {SERVER_IP, 255.255.255.255} for the below > @@ -6030,9 +6095,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > op->json_key); > } > > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_OPTIONS, > - 100, ds_cstr(&match), > - ds_cstr(&options_action)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_DHCP_OPTIONS, 100, > + ds_cstr(&match), > + ds_cstr(&options_action), > + stage_hint); > ds_clear(&match); > > /* If REGBIT_DHCP_OPTS_RESULT is set, it means the > @@ -6050,9 +6117,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > op->json_key); > } > > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, > - 100, ds_cstr(&match), > - ds_cstr(&response_action)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_DHCP_RESPONSE, 100, > + ds_cstr(&match), > + ds_cstr(&response_action), > + stage_hint); > ds_destroy(&options_action); > ds_destroy(&response_action); > ds_destroy(&ipv4_addr_match); > @@ -6060,6 +6129,12 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > } > } > > + if (op->nbsp->dhcpv6_options) { > + stage_hint = &op->nbsp->dhcpv6_options->header_; > + } else { > + stage_hint = NULL; > + } > + > for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) { > struct ds options_action = DS_EMPTY_INITIALIZER; > struct ds response_action = DS_EMPTY_INITIALIZER; > @@ -6080,14 +6155,20 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > op->json_key); > } > > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_OPTIONS, 100, > - ds_cstr(&match), ds_cstr(&options_action)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_DHCP_OPTIONS, 100, > + ds_cstr(&match), > + ds_cstr(&options_action), > + stage_hint); > > /* If REGBIT_DHCP_OPTS_RESULT is set to 1, it means the > * put_dhcpv6_opts action is successful */ > ds_put_cstr(&match, " && "REGBIT_DHCP_OPTS_RESULT); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, 100, > - ds_cstr(&match), ds_cstr(&response_action)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_DHCP_RESPONSE, 100, > + ds_cstr(&match), > + ds_cstr(&response_action), > + stage_hint); > ds_destroy(&options_action); > ds_destroy(&response_action); > break; > @@ -6172,9 +6253,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > op->od->localnet_port->json_key, > op->lsp_addrs[i].ea_s, op->json_key, > rp->lsp_addrs[k].ipv4_addrs[l].addr_s); > - ovn_lflow_add(lflows, op->od, > - S_SWITCH_IN_EXTERNAL_PORT, 100, > - ds_cstr(&match), "drop;"); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_EXTERNAL_PORT, > + 100, ds_cstr(&match), "drop;", > + &op->nbsp->header_); > } > for (size_t l = 0; l < rp->lsp_addrs[k].n_ipv6_addrs; > l++) { > @@ -6189,9 +6271,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > rp->lsp_addrs[k].ipv6_addrs[l].addr_s, > rp->lsp_addrs[k].ipv6_addrs[l].sn_addr_s, > rp->lsp_addrs[k].ipv6_addrs[l].addr_s); > - ovn_lflow_add(lflows, op->od, > - S_SWITCH_IN_EXTERNAL_PORT, 100, > - ds_cstr(&match), "drop;"); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_EXTERNAL_PORT, 100, > + ds_cstr(&match), "drop;", > + &op->nbsp->header_); > } > } > } > @@ -6326,7 +6409,8 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > * requests only to the router port that owns the IP address. > */ > if (!strcmp(op->nbsp->type, "router")) { > - build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lflows); > + build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lflows, > + &op->nbsp->header_); > } > > for (size_t i = 0; i < op->nbsp->n_addresses; i++) { > @@ -6342,8 +6426,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > > ds_clear(&actions); > ds_put_format(&actions, "outport = %s; output;", op->json_key); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_L2_LKUP, > + 50, ds_cstr(&match), > + ds_cstr(&actions), > + &op->nbsp->header_); > } else if (!strcmp(op->nbsp->addresses[i], "unknown")) { > if (lsp_is_enabled(op->nbsp)) { > ovn_multicast_add(mcgroups, &mc_unknown, op); > @@ -6361,8 +6447,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > > ds_clear(&actions); > ds_put_format(&actions, "outport = %s; output;", op->json_key); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_L2_LKUP, > + 50, ds_cstr(&match), > + ds_cstr(&actions), > + &op->nbsp->header_); > } else if (!strcmp(op->nbsp->addresses[i], "router")) { > if (!op->peer || !op->peer->nbrp > || !ovs_scan(op->peer->nbrp->mac, > @@ -6403,8 +6491,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > > ds_clear(&actions); > ds_put_format(&actions, "outport = %s; output;", op->json_key); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_L2_LKUP, 50, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbsp->header_); > > /* Add ethernet addresses specified in NAT rules on > * distributed logical routers. */ > @@ -6426,9 +6516,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > ds_clear(&actions); > ds_put_format(&actions, "outport = %s; output;", > op->json_key); > - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, > - 50, ds_cstr(&match), > - ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_SWITCH_IN_L2_LKUP, 50, > + ds_cstr(&match), > + ds_cstr(&actions), > + &op->nbsp->header_); > } > } > } > @@ -6544,7 +6636,8 @@ get_outport_for_routing_policy_nexthop(struct ovn_datapath *od, > static void > build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od, > struct hmap *ports, > - const struct nbrec_logical_router_policy *rule) > + const struct nbrec_logical_router_policy *rule, > + const struct ovsdb_idl_row *stage_hint) > { > struct ds match = DS_EMPTY_INITIALIZER; > struct ds actions = DS_EMPTY_INITIALIZER; > @@ -6584,8 +6677,9 @@ build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od, > ds_put_cstr(&actions, "next;"); > } > ds_put_format(&match, "%s", rule->match); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, rule->priority, > - ds_cstr(&match), ds_cstr(&actions)); > + > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY, rule->priority, > + ds_cstr(&match), ds_cstr(&actions), stage_hint); > ds_destroy(&match); > ds_destroy(&actions); > } > @@ -6654,8 +6748,9 @@ add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op) > REGBIT_NAT_REDIRECT" = 0; next;", > op->od->l3dgw_port->json_key, > nat->external_mac); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, > + ds_cstr(&match), ds_cstr(&actions), > + &nat->header_); > ds_clear(&match); > ds_clear(&actions); > > @@ -6702,8 +6797,9 @@ add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op) > family == AF_INET ? "4" : "6", > family == AF_INET ? "" : "xx", > nat->external_ip); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_ROUTING, > + 400, ds_cstr(&match), ds_cstr(&actions), > + &nat2->header_); > ds_clear(&match); > ds_clear(&actions); > } > @@ -6715,7 +6811,8 @@ add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op) > static void > add_route(struct hmap *lflows, const struct ovn_port *op, > const char *lrp_addr_s, const char *network_s, int plen, > - const char *gateway, const char *policy) > + const char *gateway, const char *policy, > + const struct ovsdb_idl_row *stage_hint) > { > bool is_ipv4 = strchr(network_s, '.') ? true : false; > struct ds match = DS_EMPTY_INITIALIZER; > @@ -6762,8 +6859,8 @@ add_route(struct hmap *lflows, const struct ovn_port *op, > > /* The priority here is calculated to implement longest-prefix-match > * routing. */ > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, priority, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_ROUTING, priority, > + ds_cstr(&match), ds_cstr(&actions), stage_hint); > ds_destroy(&match); > ds_destroy(&actions); > } > @@ -6771,7 +6868,8 @@ add_route(struct hmap *lflows, const struct ovn_port *op, > static void > build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, > struct hmap *ports, > - const struct nbrec_logical_router_static_route *route) > + const struct nbrec_logical_router_static_route *route, > + const struct ovsdb_idl_row *stage_hint) > { > ovs_be32 nexthop; > const char *lrp_addr_s = NULL; > @@ -6894,7 +6992,7 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, > > char *policy = route->policy ? route->policy : "dst-ip"; > add_route(lflows, out_port, lrp_addr_s, prefix_s, plen, route->nexthop, > - policy); > + policy, stage_hint); > > free_prefix_s: > free(prefix_s); > @@ -6977,35 +7075,38 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, > const char *lb_force_snat_ip, struct smap_node *lb_info, > bool is_udp, int addr_family, char *ip_addr, > uint16_t l4_port, struct nbrec_load_balancer *lb, > - struct shash *meter_groups) > + struct shash *meter_groups, > + const struct ovsdb_idl_row *stage_hint) > { > char *backend_ips = lb_info->value; > > build_empty_lb_event_flow(od, lflows, lb_info, ip_addr, lb, > l4_port, addr_family, S_ROUTER_IN_DNAT, > - meter_groups); > + meter_groups, stage_hint); > > /* A match and actions for new connections. */ > char *new_match = xasprintf("ct.new && %s", ds_cstr(match)); > if (lb_force_snat_ip) { > char *new_actions = xasprintf("flags.force_snat_for_lb = 1; %s", > ds_cstr(actions)); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, new_match, > - new_actions); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, > + new_match, new_actions, stage_hint); > free(new_actions); > } else { > - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, new_match, > - ds_cstr(actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, > + new_match, ds_cstr(actions), stage_hint); > } > > /* A match and actions for established connections. */ > char *est_match = xasprintf("ct.est && %s", ds_cstr(match)); > if (lb_force_snat_ip) { > - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, est_match, > - "flags.force_snat_for_lb = 1; ct_dnat;"); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, > + est_match, > + "flags.force_snat_for_lb = 1; ct_dnat;", > + stage_hint); > } else { > - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, est_match, > - "ct_dnat;"); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, > + est_match, "ct_dnat;", stage_hint); > } > > free(new_match); > @@ -7068,12 +7169,14 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, > "is_chassis_resident(%s)", od->l3dgw_port->json_key, > od->l3redirect_port->json_key); > if (lb_force_snat_ip) { > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 120, > - ds_cstr(&undnat_match), > - "flags.force_snat_for_lb = 1; ct_dnat;"); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120, > + ds_cstr(&undnat_match), > + "flags.force_snat_for_lb = 1; ct_dnat;", > + stage_hint); > } else { > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 120, > - ds_cstr(&undnat_match), "ct_dnat;"); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120, > + ds_cstr(&undnat_match), "ct_dnat;", > + stage_hint); > } > > ds_destroy(&undnat_match); > @@ -7219,8 +7322,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > > ds_clear(&match); > ds_put_format(&match, "eth.mcast && inport == %s", op->json_key); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, > + ds_cstr(&match), "next;", &op->nbrp->header_); > > ds_clear(&match); > ds_put_format(&match, "eth.dst == %s && inport == %s", > @@ -7232,8 +7335,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_format(&match, " && is_chassis_resident(%s)", > op->od->l3redirect_port->json_key); > } > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, > + ds_cstr(&match), "next;", &op->nbrp->header_); > } > > /* Logical router ingress table 1: LOOKUP_NEIGHBOR and > @@ -7318,10 +7421,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_format(&match, " && is_chassis_resident(%s)", > op->od->l3redirect_port->json_key); > } > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, > - ds_cstr(&match), > - REGBIT_LOOKUP_NEIGHBOR_RESULT" = " > - "lookup_arp(inport, arp.spa, arp.sha); next;"); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, > + ds_cstr(&match), > + REGBIT_LOOKUP_NEIGHBOR_RESULT" = " > + "lookup_arp(inport, arp.spa, arp.sha); " > + "next;", &op->nbrp->header_); > } > } > > @@ -7391,8 +7496,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_cstr(&match, "ip4.src == "); > op_put_v4_networks(&match, op, true); > ds_put_cstr(&match, " && "REGBIT_EGRESS_LOOPBACK" == 0"); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, > - ds_cstr(&match), "drop;"); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, > + ds_cstr(&match), "drop;", > + &op->nbrp->header_); > > /* ICMP echo reply. These flows reply to ICMP echo requests > * received for the router's IP address. Since packets only > @@ -7411,8 +7517,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "icmp4.type = 0; " > "flags.loopback = 1; " > "next; "); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > > /* ICMP time exceeded */ > @@ -7433,8 +7540,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "ip.ttl = 255; " > "next; };", > op->lrp_networks.ipv4_addrs[i].addr_s); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > > /* ARP reply. These flows reply to ARP requests for the router's own > @@ -7495,8 +7603,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > op->lrp_networks.ea_s, > op->lrp_networks.ipv4_addrs[i].addr_s, > op->json_key); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > > /* A set to hold all load-balancer vips that need ARP responses. */ > @@ -7740,8 +7849,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > IP_ARGS(ip), > op->json_key); > } > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > - ds_cstr(&match), ds_cstr(&actions)); > + > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > + ds_cstr(&match), ds_cstr(&actions), > + &nat->header_); > } > > if (!smap_get(&op->od->nbr->options, "chassis") > @@ -7759,8 +7870,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "icmp4.type = 3; " > "icmp4.code = 3; " > "next; };"; > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, > - ds_cstr(&match), action); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, > + 80, ds_cstr(&match), action, > + &op->nbrp->header_); > > ds_clear(&match); > ds_put_format(&match, > @@ -7770,8 +7882,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "eth.dst <-> eth.src; " > "ip4.dst <-> ip4.src; " > "next; };"; > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, > - ds_cstr(&match), action); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, > + 80, ds_cstr(&match), action, > + &op->nbrp->header_); > > ds_clear(&match); > ds_put_format(&match, > @@ -7784,8 +7897,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "icmp4.type = 3; " > "icmp4.code = 2; " > "next; };"; > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 70, > - ds_cstr(&match), action); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, > + 70, ds_cstr(&match), action, > + &op->nbrp->header_); > } > } > > @@ -7844,8 +7958,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > > if (has_drop_ips) { > /* Drop IP traffic to this router. */ > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 60, > - ds_cstr(&match), "drop;"); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 60, > + ds_cstr(&match), "drop;", > + &op->nbrp->header_); > } > > free(snat_ips); > @@ -7878,8 +7993,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "icmp6.type = 129; " > "flags.loopback = 1; " > "next; "); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > > /* ND reply. These flows reply to ND solicitations for the > @@ -7919,8 +8035,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > op->lrp_networks.ipv6_addrs[i].addr_s, > op->lrp_networks.ipv6_addrs[i].addr_s, > op->lrp_networks.ea_s); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > > /* UDP/TCP port unreachable */ > @@ -7935,8 +8052,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "eth.dst <-> eth.src; " > "ip6.dst <-> ip6.src; " > "next; };"; > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, > - ds_cstr(&match), action); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, > + 80, ds_cstr(&match), action, > + &op->nbrp->header_); > > ds_clear(&match); > ds_put_format(&match, > @@ -7949,8 +8067,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "icmp6.type = 1; " > "icmp6.code = 4; " > "next; };"; > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, > - ds_cstr(&match), action); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, > + 80, ds_cstr(&match), action, > + &op->nbrp->header_); > > ds_clear(&match); > ds_put_format(&match, > @@ -7963,8 +8082,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "icmp6.type = 1; " > "icmp6.code = 3; " > "next; };"; > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 70, > - ds_cstr(&match), action); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, > + 70, ds_cstr(&match), action, > + &op->nbrp->header_); > } > } > > @@ -7995,8 +8115,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "icmp6.code = 0; /* TTL exceeded in transit */ " > "next; };", > op->lrp_networks.ipv6_addrs[i].addr_s); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > } > > @@ -8135,8 +8256,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_cstr(&actions, "ct_snat;"); > } > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 90, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, > + 90, ds_cstr(&match), > + ds_cstr(&actions), > + &nat->header_); > } else { > /* Distributed router. */ > > @@ -8162,8 +8285,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_cstr(&actions, "ct_snat;"); > } > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, > + 100, ds_cstr(&match), > + ds_cstr(&actions), > + &nat->header_); > > /* Traffic received on other router ports must be > * redirected to the central instance of the l3dgw_port > @@ -8172,9 +8297,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_format(&match, "ip && ip%s.dst == %s", > is_v6 ? "6" : "4", > nat->external_ip); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 50, > - ds_cstr(&match), > - REGBIT_NAT_REDIRECT" = 1; next;"); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, > + 50, ds_cstr(&match), > + REGBIT_NAT_REDIRECT" = 1; next;", > + &nat->header_); > } > } > > @@ -8210,8 +8336,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "ct_dnat(%s);", nat->logical_ip); > } > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 100, > + ds_cstr(&match), ds_cstr(&actions), > + &nat->header_); > } else { > /* Distributed router. */ > > @@ -8238,8 +8365,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > nat->logical_ip); > } > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 100, > + ds_cstr(&match), ds_cstr(&actions), > + &nat->header_); > > /* Traffic received on other router ports must be > * redirected to the central instance of the l3dgw_port > @@ -8248,9 +8376,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_format(&match, "ip && ip%s.dst == %s", > is_v6 ? "6" : "4", > nat->external_ip); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, > - ds_cstr(&match), > - REGBIT_NAT_REDIRECT" = 1; next;"); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 50, > + ds_cstr(&match), > + REGBIT_NAT_REDIRECT" = 1; next;", > + &nat->header_); > } > } > > @@ -8289,8 +8418,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_format(&actions, "ct_dnat;"); > } > > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 100, > + ds_cstr(&match), ds_cstr(&actions), > + &nat->header_); > } > > /* Egress SNAT table: Packets enter the egress pipeline with > @@ -8317,9 +8447,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > /* The priority here is calculated such that the > * nat->logical_ip with the longest mask gets a higher > * priority. */ > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, > - count_1bits(ntohl(mask)) + 1, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT, > + count_1bits(ntohl(mask)) + 1, > + ds_cstr(&match), ds_cstr(&actions), > + &nat->header_); > } else { > uint16_t priority = count_1bits(ntohl(mask)) + 1; > > @@ -8354,9 +8485,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > /* The priority here is calculated such that the > * nat->logical_ip with the longest mask gets a higher > * priority. */ > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, > - priority, ds_cstr(&match), > - ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT, > + priority, ds_cstr(&match), > + ds_cstr(&actions), > + &nat->header_); > } > } > > @@ -8373,8 +8505,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ETH_ADDR_ARGS(mac), > od->l3dgw_port->json_key, > nat->logical_port); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 50, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ADMISSION, 50, > + ds_cstr(&match), "next;", > + &nat->header_); > } > > /* Ingress Gateway Redirect Table: For NAT on a distributed > @@ -8387,8 +8520,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > is_v6 ? "6" : "4", > nat->logical_ip, > od->l3dgw_port->json_key); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 100, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, > + 100, ds_cstr(&match), "next;", > + &nat->header_); > } > > /* Egress Loopback table: For NAT on a distributed router. > @@ -8422,16 +8556,21 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "flags = 0; flags.loopback = 1; " > REGBIT_EGRESS_LOOPBACK" = 1; " > "next(pipeline=ingress, table=0); "); > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 300, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, > + S_ROUTER_OUT_EGR_LOOP, 300, > + ds_cstr(&match), > + ds_cstr(&actions), > + &nat2->header_); > > ds_clear(&match); > ds_put_format(&match, > "ip%s.src == %s && ip%s.dst == %s", > is_v6 ? "6" : "4", nat2->external_ip, > is_v6 ? "6" : "4", nat->external_ip); > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 200, > - ds_cstr(&match), "next;"); > + ovn_lflow_add_with_hint(lflows, od, > + S_ROUTER_OUT_EGR_LOOP, 200, > + ds_cstr(&match), "next;", > + &nat2->header_); > ds_clear(&match); > } > } > @@ -8451,8 +8590,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > } > ds_put_format(&actions, REGBIT_EGRESS_LOOPBACK" = 1; " > "next(pipeline=ingress, table=0); };"); > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_EGR_LOOP, 100, > + ds_cstr(&match), ds_cstr(&actions), > + &nat->header_); > } > } > > @@ -8591,8 +8731,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_format(&match, "ip && ip6.dst == %s", > ip_address); > } > - ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, > - 100, ds_cstr(&match), "ct_next;"); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, > + 100, ds_cstr(&match), "ct_next;", > + &lb->header_); > } > > /* Higher priority rules are added for load-balancing in DNAT > @@ -8633,7 +8774,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > add_router_lb_flow(lflows, od, &match, &actions, prio, > lb_force_snat_ip, node, is_udp, > addr_family, ip_address, port, lb, > - meter_groups); > + meter_groups, > + &lb->header_); > > free(ip_address); > } > @@ -8706,8 +8848,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > > if (add_rs_response_flow) { > ds_put_cstr(&actions, "); next;"); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS, > + 50, ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > ds_clear(&actions); > ds_clear(&match); > ds_put_format(&match, "inport == %s && ip6.dst == ff02::2 && " > @@ -8723,8 +8866,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "outport = inport; flags.loopback = 1; " > "output;", > op->lrp_networks.ea_s, ip6_str); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ND_RA_RESPONSE, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->od, > + S_ROUTER_IN_ND_RA_RESPONSE, 50, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > } > > @@ -8758,13 +8903,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > add_route(lflows, op, op->lrp_networks.ipv4_addrs[i].addr_s, > op->lrp_networks.ipv4_addrs[i].network_s, > - op->lrp_networks.ipv4_addrs[i].plen, NULL, NULL); > + op->lrp_networks.ipv4_addrs[i].plen, NULL, NULL, > + &op->nbrp->header_); > } > > for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { > add_route(lflows, op, op->lrp_networks.ipv6_addrs[i].addr_s, > op->lrp_networks.ipv6_addrs[i].network_s, > - op->lrp_networks.ipv6_addrs[i].plen, NULL, NULL); > + op->lrp_networks.ipv6_addrs[i].plen, NULL, NULL, > + &op->nbrp->header_); > } > } > > @@ -8778,7 +8925,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > const struct nbrec_logical_router_static_route *route; > > route = od->nbr->static_routes[i]; > - build_static_route_flow(lflows, od, ports, route); > + build_static_route_flow(lflows, od, ports, route, &route->header_); > } > } > > @@ -8849,7 +8996,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > for (int i = 0; i < od->nbr->n_policies; i++) { > const struct nbrec_logical_router_policy *rule > = od->nbr->policies[i]; > - build_routing_policy_flow(lflows, od, ports, rule); > + build_routing_policy_flow(lflows, od, ports, rule, &rule->header_); > } > } > > @@ -8900,8 +9047,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_clear(&actions); > ds_put_format(&actions, "eth.dst = %s; next;", > op->lrp_networks.ea_s); > - ovn_lflow_add(lflows, op->peer->od, S_ROUTER_IN_ARP_RESOLVE, > - 100, ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->peer->od, > + S_ROUTER_IN_ARP_RESOLVE, 100, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > > if (op->lrp_networks.n_ipv6_addrs) { > @@ -8913,8 +9062,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_clear(&actions); > ds_put_format(&actions, "eth.dst = %s; next;", > op->lrp_networks.ea_s); > - ovn_lflow_add(lflows, op->peer->od, S_ROUTER_IN_ARP_RESOLVE, > - 100, ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, op->peer->od, > + S_ROUTER_IN_ARP_RESOLVE, 100, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > } > > @@ -8935,8 +9086,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_clear(&actions); > ds_put_format(&actions, "eth.dst = %s; next;", > op->lrp_networks.ea_s); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ARP_RESOLVE, > - 50, ds_cstr(&match), ds_cstr(&actions)); > + > + ovn_lflow_add_with_hint(lflows, op->od, > + S_ROUTER_IN_ARP_RESOLVE, 50, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbrp->header_); > } > } > } else if (op->od->n_router_ports && strcmp(op->nbsp->type, "router") > @@ -8977,9 +9131,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > > ds_clear(&actions); > ds_put_format(&actions, "eth.dst = %s; next;", ea_s); > - ovn_lflow_add(lflows, peer->od, > - S_ROUTER_IN_ARP_RESOLVE, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, peer->od, > + S_ROUTER_IN_ARP_RESOLVE, 100, > + ds_cstr(&match), > + ds_cstr(&actions), > + &op->nbsp->header_); > } > } > > @@ -9011,9 +9167,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > > ds_clear(&actions); > ds_put_format(&actions, "eth.dst = %s; next;", ea_s); > - ovn_lflow_add(lflows, peer->od, > - S_ROUTER_IN_ARP_RESOLVE, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, peer->od, > + S_ROUTER_IN_ARP_RESOLVE, 100, > + ds_cstr(&match), > + ds_cstr(&actions), > + &op->nbsp->header_); > } > } > } > @@ -9061,9 +9219,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_clear(&actions); > ds_put_format(&actions, > "eth.dst = 00:00:00:00:00:00; next;"); > - ovn_lflow_add(lflows, peer->od, > - S_ROUTER_IN_ARP_RESOLVE, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, peer->od, > + S_ROUTER_IN_ARP_RESOLVE, 100, > + ds_cstr(&match), > + ds_cstr(&actions), > + &op->nbsp->header_); > break; > } > } > @@ -9104,9 +9264,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > > ds_clear(&actions); > ds_put_format(&actions, "eth.dst = %s; next;", ea_s); > - ovn_lflow_add(lflows, peer->od, > - S_ROUTER_IN_ARP_RESOLVE, 100, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, peer->od, > + S_ROUTER_IN_ARP_RESOLVE, 100, > + ds_cstr(&match), > + ds_cstr(&actions), > + &op->nbsp->header_); > found_vip_network = true; > break; > } > @@ -9159,8 +9321,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_clear(&actions); > ds_put_format(&actions, "eth.dst = %s; next;", > router_port->lrp_networks.ea_s); > - ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, > - 100, ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, peer->od, > + S_ROUTER_IN_ARP_RESOLVE, 100, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbsp->header_); > } > > if (router_port->lrp_networks.n_ipv6_addrs) { > @@ -9172,8 +9336,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_clear(&actions); > ds_put_format(&actions, "eth.dst = %s; next;", > router_port->lrp_networks.ea_s); > - ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, > - 100, ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, peer->od, > + S_ROUTER_IN_ARP_RESOLVE, 100, > + ds_cstr(&match), ds_cstr(&actions), > + &op->nbsp->header_); > } > } > } > @@ -9234,8 +9400,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_format(&actions, > REGBIT_PKT_LARGER" = check_pkt_larger(%d);" > " next;", gw_mtu); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 50, > + ds_cstr(&match), ds_cstr(&actions), > + &od->l3dgw_port->nbrp->header_); > > for (size_t i = 0; i < od->nbr->n_ports; i++) { > struct ovn_port *rp = ovn_port_find(ports, > @@ -9266,8 +9433,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > rp->lrp_networks.ea_s, > rp->lrp_networks.ipv4_addrs[0].addr_s, > gw_mtu - 18); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_LARGER_PKTS, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_LARGER_PKTS, > + 50, ds_cstr(&match), ds_cstr(&actions), > + &rp->nbrp->header_); > } > } > } > @@ -9284,8 +9452,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > continue; > } > if (od->l3dgw_port && od->l3redirect_port) { > - ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 300, > - REGBIT_DISTRIBUTED_NAT" == 1", "next;"); > + const struct ovsdb_idl_row *stage_hint = NULL; > + > + if (od->l3dgw_port->nbrp) { > + stage_hint = &od->l3dgw_port->nbrp->header_; > + } > + > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 300, > + REGBIT_DISTRIBUTED_NAT" == 1", "next;", > + stage_hint); > > /* For traffic with outport == l3dgw_port, if the > * packet did not match any higher priority redirect > @@ -9297,8 +9472,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_clear(&actions); > ds_put_format(&actions, "outport = %s; next;", > od->l3redirect_port->json_key); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50, > + ds_cstr(&match), ds_cstr(&actions), > + stage_hint); > > /* If the Ethernet destination has not been resolved, > * redirect to the central instance of the l3dgw_port. > @@ -9307,8 +9483,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > * table, before being redirected to the central instance. > */ > ds_put_format(&match, " && eth.dst == 00:00:00:00:00:00"); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 150, > - ds_cstr(&match), ds_cstr(&actions)); > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 150, > + ds_cstr(&match), ds_cstr(&actions), > + stage_hint); > } > > /* Packets are allowed by default. */ > @@ -9357,8 +9534,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "output; " > "};", ETH_ADDR_ARGS(eth_dst), sn_addr_s, > route->nexthop); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, > - ds_cstr(&match), ds_cstr(&actions)); > + > + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, > + ds_cstr(&match), ds_cstr(&actions), > + &route->header_); > } > > ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, > @@ -9416,7 +9595,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_put_format(&actions, "eth.src = %s; output;", > op->lrp_networks.ea_s); > ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 110, > - ds_cstr(&match), ds_cstr(&actions)); > + ds_cstr(&match), ds_cstr(&actions)); > } > > ds_clear(&match); > diff --git a/utilities/ovn-detrace.in b/utilities/ovn-detrace.in > index 3bfb720..e9c3736 100755 > --- a/utilities/ovn-detrace.in > +++ b/utilities/ovn-detrace.in > @@ -135,9 +135,74 @@ class CookieHandlerByUUUID(CookieHandler): > cookie = cookie.zfill(8) > return self._db.find_rows_by_partial_uuid(self._table, cookie) > > +class ACLHintHandler(CookieHandlerByUUUID): > + def __init__(self, ovnnb_db): > + super(ACLHintHandler, self).__init__(ovnnb_db, 'ACL') > + > + def print_record(self, acl): > + output = 'ACL: %s, priority=%s, ' \ > + 'match=(%s), %s' % (acl.direction, > + acl.priority, > + acl.match.strip('"'), > + acl.action) > + if acl.log: > + output += ' (log)' > + print_h(output) > + > +class LSPHintHandler(CookieHandlerByUUUID): > + def __init__(self, ovnnb_db): > + super(LSPHintHandler, self).__init__(ovnnb_db, 'Logical_Switch_Port') > + > + def print_record(self, lsp): > + print_h('Logical Switch Port: %s type %s (addresses %s, dynamic addresses %s, security %s' % ( > + lsp.name, lsp.type, lsp.addresses, lsp.dynamic_addresses, > + lsp.port_security)) > + > +class LRPHintHandler(CookieHandlerByUUUID): > + def __init__(self, ovnnb_db): > + super(LRPHintHandler, self).__init__(ovnnb_db, 'Logical_Router_Port') > + > + def print_record(self, lrp): > + print_h('Logical Router Port: %s mac %s networks %s ipv6_ra_configs %s' % ( > + lrp.name, lrp.mac, lrp.networks, lrp.ipv6_ra_configs)) > + > +class LoadBalancerHintHandler(CookieHandlerByUUUID): > + def __init__(self, ovnnb_db): > + super(LoadBalancerHintHandler, self).__init__(ovnnb_db, 'Load_Balancer') > + > + def print_record(self, lb): > + print_h('Load Balancer: %s protocol %s vips %s ip_port_mappings %s' % ( > + lb.name, lb.protocol, lb.vips, lb.ip_port_mappings)) > + > +class NATHintHandler(CookieHandlerByUUUID): > + def __init__(self, ovnnb_db): > + super(NATHintHandler, self).__init__(ovnnb_db, 'NAT') > + > + def print_record(self, nat): > + print_h('NAT: external IP %s external_mac %s logical_ip %s logical_port %s type %s' % ( > + nat.external_ip, nat.external_mac, nat.logical_ip, > + nat.logical_port, nat.type)) > + > +class StaticRouteHintHandler(CookieHandlerByUUUID): > + def __init__(self, ovnnb_db): > + super(StaticRouteHintHandler, self).__init__(ovnnb_db, > + 'Logical_Router_Static_Route') > + > + def print_record(self, route): > + print_h('Route: %s via %s (port %s), policy=%s' % ( > + route.ip_prefix, route.nexthop, route.output_port, > + route.policy)) > + > class LogicalFlowHandler(CookieHandlerByUUUID): > - def __init__(self, ovnsb_db): > + def __init__(self, ovnnb_db, ovnsb_db): > super(LogicalFlowHandler, self).__init__(ovnsb_db, 'Logical_Flow') > + self._hint_handlers = [ > + ACLHintHandler(ovnnb_db), > + LSPHintHandler(ovnnb_db), > + LRPHintHandler(ovnnb_db), > + LoadBalancerHintHandler(ovnnb_db), > + NATHintHandler(ovnnb_db) > + ] > > def print_record(self, lflow): > print_p('Logical datapath: %s [%s]' % > @@ -151,24 +216,14 @@ class LogicalFlowHandler(CookieHandlerByUUUID): > > def print_hint(self, lflow, ovnnb_db): > external_ids = lflow.external_ids > - if external_ids.get('stage-name') in ['ls_in_acl', > - 'ls_out_acl']: > - acl_hint = external_ids.get('stage-hint') > - if not acl_hint: > - return > - for i, acl in enumerate( > - ovnnb_db.find_rows_by_partial_uuid('ACL', acl_hint)): > + hint = external_ids.get('stage-hint') > + if not hint: > + return > + for handler in self._hint_handlers: > + for i, record in enumerate(handler.get_records(hint)): > if i > 0: > - print_h('[Duplicate uuid ACL hint]') > - > - output = 'ACL: %s, priority=%s, ' \ > - 'match=(%s), %s' % (acl.direction, > - acl.priority, > - acl.match.strip('"'), > - acl.action) > - if acl.log: > - output += ' (log)' > - print_h(output) > + print_h('[Duplicate uuid hint]') > + handler.print_record(record) > > class PortBindingHandler(CookieHandlerByUUUID): > def __init__(self, ovnsb_db): > @@ -283,7 +338,7 @@ def main(): > ovsdb_ovnnb = OVSDB(ovnnb_db, 'OVN_Northbound') > > cookie_handlers = [ > - LogicalFlowHandler(ovsdb_ovnsb), > + LogicalFlowHandler(ovsdb_ovnnb, ovsdb_ovnsb), > PortBindingHandler(ovsdb_ovnsb), > MacBindingHandler(ovsdb_ovnsb), > MulticastGroupHandler(ovsdb_ovnsb), >
On 1/21/20 10:41 PM, Mark Michelson wrote: > Hi Dumitru, > > It appears that some of the stage hints correspond to DHCPv4_Options and > DHCPv6_Options, but these are not handled in ovn-detrace. Hi Mark, Thanks for reviewing this. My bad, I had missed a few tables indeed (QoS and Logical_Router_Policy too). I just sent a v2 rebased on current master where I updated ovn-detrace to handle these tables too. I also updated some more ovn_lflow_add() calls which were introduced in the meantime in ovn-northd so that they properly set the hint. https://patchwork.ozlabs.org/patch/1231858/ Regards, Dumitru > > On 1/17/20 10:44 AM, Dumitru Ceara wrote: >> Until now the 'stage-hint' external-id was set only for logical flows >> installed for ACLs. In order to simplify troubleshooting, extend the >> approach and apply whenever possible. Set stage-hint for logical flows >> generated by the following NB tables too: >> - Logical_Switch_Port >> - Logical_Router_Port >> - Load_Balancer >> - NAT >> >> Also update ovn-detrace such that whenever stage-hints are available, >> all the tables mentioned above are queried and if the stage-hint matches >> a NB uuid, relevant information is dumped. >> >> Signed-off-by: Dumitru Ceara <dceara@redhat.com> >> --- >>  northd/ovn-northd.c     | 721 >> +++++++++++++++++++++++++++++------------------ >>  utilities/ovn-detrace.in | 93 ++++-- >>  2 files changed, 524 insertions(+), 290 deletions(-) >> >> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c >> index b6dc809..20b8429 100644 >> --- a/northd/ovn-northd.c >> +++ b/northd/ovn-northd.c >> @@ -3714,6 +3714,15 @@ ovn_lflow_hash(const struct ovn_lflow *lflow) >>                                   lflow->actions); >>  } >>  +static char * >> +ovn_lflow_hint(const struct ovsdb_idl_row *row) >> +{ >> +   if (!row) { >> +       return NULL; >> +   } >> +   return xasprintf("%08x", row->uuid.parts[0]); >> +} >> + >>  static bool >>  ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b) >>  { >> @@ -3744,14 +3753,14 @@ static void >>  ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, >>                   enum ovn_stage stage, uint16_t priority, >>                   const char *match, const char *actions, >> -                const char *stage_hint, const char *where) >> +                const struct ovsdb_idl_row *stage_hint, const char >> *where) >>  { >>      ovs_assert(ovn_stage_to_datapath_type(stage) == >> ovn_datapath_get_type(od)); >>       struct ovn_lflow *lflow = xmalloc(sizeof *lflow); >>      ovn_lflow_init(lflow, od, stage, priority, >>                     xstrdup(match), xstrdup(actions), >> -                  nullable_xstrdup(stage_hint), where); >> +                  ovn_lflow_hint(stage_hint), where); >>      hmap_insert(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow)); >>  } >>  @@ -3902,7 +3911,8 @@ build_port_security_ipv6_flow( >>   *  - Priority 80 flow to drop ARP and IPv6 ND packets. >>   */ >>  static void >> -build_port_security_nd(struct ovn_port *op, struct hmap *lflows) >> +build_port_security_nd(struct ovn_port *op, struct hmap *lflows, >> +                      const struct ovsdb_idl_row *stage_hint) >>  { >>      struct ds match = DS_EMPTY_INITIALIZER; >>  @@ -3938,8 +3948,8 @@ build_port_security_nd(struct ovn_port *op, >> struct hmap *lflows) >>                  ds_chomp(&match, ','); >>                  ds_put_cstr(&match, "}"); >>              } >> -           ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90, >> -                         ds_cstr(&match), "next;"); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_SWITCH_IN_PORT_SEC_ND, >> +                                   90, ds_cstr(&match), "next;", >> stage_hint); >>          } >>           if (ps->n_ipv6_addrs || no_ip) { >> @@ -3948,15 +3958,15 @@ build_port_security_nd(struct ovn_port *op, >> struct hmap *lflows) >>                            op->json_key, ps->ea_s); >>              build_port_security_ipv6_nd_flow(&match, ps->ea, >> ps->ipv6_addrs, >>                                               ps->n_ipv6_addrs); >> -           ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90, >> -                         ds_cstr(&match), "next;"); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_SWITCH_IN_PORT_SEC_ND, >> +                                   90, ds_cstr(&match), "next;", >> stage_hint); >>          } >>      } >>       ds_clear(&match); >>      ds_put_format(&match, "inport == %s && (arp || nd)", op->json_key); >> -   ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 80, >> -                 ds_cstr(&match), "drop;"); >> +   ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 80, >> +                           ds_cstr(&match), "drop;", stage_hint); >>      ds_destroy(&match); >>  } >>  @@ -3977,7 +3987,8 @@ build_port_security_nd(struct ovn_port *op, >> struct hmap *lflows) >>   */ >>  static void >>  build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, >> -                      struct hmap *lflows) >> +                      struct hmap *lflows, >> +                      const struct ovsdb_idl_row *stage_hint) >>  { >>      char *port_direction; >>      enum ovn_stage stage; >> @@ -4007,8 +4018,9 @@ build_port_security_ip(enum ovn_pipeline >> pipeline, struct ovn_port *op, >>                                " && ip4.dst == 255.255.255.255" >>                                " && udp.src == 68 && udp.dst == 67", >>                                op->json_key, ps->ea_s); >> -               ovn_lflow_add(lflows, op->od, stage, 90, >> -                             ds_cstr(&dhcp_match), "next;"); >> +               ovn_lflow_add_with_hint(lflows, op->od, stage, 90, >> +                                       ds_cstr(&dhcp_match), "next;", >> +                                       stage_hint); >>                  ds_destroy(&dhcp_match); >>                  ds_put_format(&match, "inport == %s && eth.src == %s" >>                                " && ip4.src == {", op->json_key, >> @@ -4047,7 +4059,9 @@ build_port_security_ip(enum ovn_pipeline >> pipeline, struct ovn_port *op, >>              ds_chomp(&match, ' '); >>              ds_chomp(&match, ','); >>              ds_put_cstr(&match, "}"); >> -           ovn_lflow_add(lflows, op->od, stage, 90, ds_cstr(&match), >> "next;"); >> +           ovn_lflow_add_with_hint(lflows, op->od, stage, 90, >> +                                   ds_cstr(&match), "next;", >> +                                   stage_hint); >>              ds_destroy(&match); >>          } >>  @@ -4063,8 +4077,9 @@ build_port_security_ip(enum ovn_pipeline >> pipeline, struct ovn_port *op, >>                                " && ip6.dst == ff02::/16" >>                                " && icmp6.type == {131, 135, 143}", >> op->json_key, >>                                ps->ea_s); >> -               ovn_lflow_add(lflows, op->od, stage, 90, >> -                             ds_cstr(&dad_match), "next;"); >> +               ovn_lflow_add_with_hint(lflows, op->od, stage, 90, >> +                                       ds_cstr(&dad_match), "next;", >> +                                       stage_hint); >>                  ds_destroy(&dad_match); >>              } >>              ds_put_format(&match, "%s == %s && %s == %s", >> @@ -4072,8 +4087,9 @@ build_port_security_ip(enum ovn_pipeline >> pipeline, struct ovn_port *op, >>                            pipeline == P_IN ? "eth.src" : "eth.dst", >> ps->ea_s); >>              build_port_security_ipv6_flow(pipeline, &match, ps->ea, >>                                            ps->ipv6_addrs, >> ps->n_ipv6_addrs); >> -           ovn_lflow_add(lflows, op->od, stage, 90, >> -                         ds_cstr(&match), "next;"); >> +           ovn_lflow_add_with_hint(lflows, op->od, stage, 90, >> +                                   ds_cstr(&match), "next;", >> +                                   stage_hint); >>              ds_destroy(&match); >>          } >>  @@ -4081,7 +4097,8 @@ build_port_security_ip(enum ovn_pipeline >> pipeline, struct ovn_port *op, >>                                  port_direction, op->json_key, >>                                  pipeline == P_IN ? "eth.src" : >> "eth.dst", >>                                  ps->ea_s); >> -       ovn_lflow_add(lflows, op->od, stage, 80, match, "drop;"); >> +       ovn_lflow_add_with_hint(lflows, op->od, stage, 80, match, >> "drop;", >> +                               stage_hint); >>          free(match); >>      } >>  @@ -4371,12 +4388,13 @@ build_lswitch_input_port_sec(struct hmap >> *ports, struct hmap *datapaths, >>              ds_put_format(&actions, "set_queue(%s); ", queue_id); >>          } >>          ds_put_cstr(&actions, "next;"); >> -       ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50, >> -                     ds_cstr(&match), ds_cstr(&actions)); >> +       ovn_lflow_add_with_hint(lflows, op->od, >> S_SWITCH_IN_PORT_SEC_L2, 50, >> +                               ds_cstr(&match), ds_cstr(&actions), >> +                               &op->nbsp->header_); >>           if (op->nbsp->n_port_security) { >> -           build_port_security_ip(P_IN, op, lflows); >> -           build_port_security_nd(op, lflows); >> +           build_port_security_ip(P_IN, op, lflows, >> &op->nbsp->header_); >> +           build_port_security_nd(op, lflows, &op->nbsp->header_); >>          } >>      } >>  @@ -4436,15 +4454,17 @@ build_lswitch_output_port_sec(struct hmap >> *ports, struct hmap *datapaths, >>                  } >>              } >>              ds_put_cstr(&actions, "output;"); >> -           ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 50, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_SWITCH_OUT_PORT_SEC_L2, >> +                                   50, ds_cstr(&match), >> ds_cstr(&actions), >> +                                   &op->nbsp->header_); >>          } else { >> -           ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 150, >> -                         ds_cstr(&match), "drop;"); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_SWITCH_OUT_PORT_SEC_L2, >> +                                   150, ds_cstr(&match), "drop;", >> +                                   &op->nbsp->header_); >>          } >>           if (op->nbsp->n_port_security) { >> -           build_port_security_ip(P_OUT, op, lflows); >> +           build_port_security_ip(P_OUT, op, lflows, >> &op->nbsp->header_); >>          } >>      } >>  @@ -4499,10 +4519,12 @@ build_pre_acls(struct ovn_datapath *od, >> struct hmap *lflows) >>               ds_put_format(&match_in, "ip && inport == %s", >> op->json_key); >>              ds_put_format(&match_out, "ip && outport == %s", >> op->json_key); >> -           ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, >> -                         ds_cstr(&match_in), "next;"); >> -           ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, >> -                         ds_cstr(&match_out), "next;"); >> +           ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_ACL, >> 110, >> +                                   ds_cstr(&match_in), "next;", >> +                                   &op->nbsp->header_); >> +           ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL, >> 110, >> +                                   ds_cstr(&match_out), "next;", >> +                                   &op->nbsp->header_); >>               ds_destroy(&match_in); >>              ds_destroy(&match_out); >> @@ -4515,10 +4537,12 @@ build_pre_acls(struct ovn_datapath *od, struct >> hmap *lflows) >>                            od->localnet_port->json_key); >>              ds_put_format(&match_out, "ip && outport == %s", >>                            od->localnet_port->json_key); >> -           ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, >> -                         ds_cstr(&match_in), "next;"); >> -           ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, >> -                         ds_cstr(&match_out), "next;"); >> +           ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_ACL, >> 110, >> +                                   ds_cstr(&match_in), "next;", >> +                                   &od->localnet_port->nbsp->header_); >> +           ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL, >> 110, >> +                                   ds_cstr(&match_out), "next;", >> +                                   &od->localnet_port->nbsp->header_); >>               ds_destroy(&match_in); >>              ds_destroy(&match_out); >> @@ -4596,7 +4620,8 @@ static void >>  build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, >>                            struct smap_node *node, char *ip_address, >>                            struct nbrec_load_balancer *lb, uint16_t >> port, >> -                         int addr_family, int pl, struct shash >> *meter_groups) >> +                         int addr_family, int pl, struct shash >> *meter_groups, >> +                         const struct ovsdb_idl_row *stage_hint) >>  { >>      if (!controller_event_en || node->value[0]) { >>          return; >> @@ -4627,7 +4652,8 @@ build_empty_lb_event_flow(struct ovn_datapath >> *od, struct hmap *lflows, >>                         event_to_string(OVN_EVENT_EMPTY_LB_BACKENDS), >>                         meter, node->key, lb->protocol, >>                         UUID_ARGS(&lb->header_.uuid)); >> -   ovn_lflow_add(lflows, od, pl, 130, ds_cstr(&match), action); >> +   ovn_lflow_add_with_hint(lflows, od, pl, 130, ds_cstr(&match), >> action, >> +                           stage_hint); >>      ds_destroy(&match); >>      free(action); >>  } >> @@ -4680,7 +4706,7 @@ build_pre_lb(struct ovn_datapath *od, struct >> hmap *lflows, >>               build_empty_lb_event_flow(od, lflows, node, >> ip_address, lb, >>                                        port, addr_family, >> S_SWITCH_IN_PRE_LB, >> -                                     meter_groups); >> +                                     meter_groups, &lb->header_); >>               free(ip_address); >>  @@ -4772,7 +4798,8 @@ 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 *extra_match, struct ds *extra_actions, >> +                      const struct ovsdb_idl_row *stage_hint) >>  { >>      struct ds match = DS_EMPTY_INITIALIZER; >>      struct ds actions = DS_EMPTY_INITIALIZER; >> @@ -4788,8 +4815,9 @@ build_reject_acl_rules(struct ovn_datapath *od, >> struct hmap *lflows, >>                    "eth.dst <-> eth.src; ip4.dst <-> ip4.src; " >>                    "tcp_reset { outport <-> inport; %s };", >>                    ingress ? "output;" : >> "next(pipeline=ingress,table=0);"); >> -   ovn_lflow_add(lflows, od, stage, acl->priority + >> OVN_ACL_PRI_OFFSET + 10, >> -                 ds_cstr(&match), ds_cstr(&actions)); >> +   ovn_lflow_add_with_hint(lflows, od, stage, >> +                           acl->priority + OVN_ACL_PRI_OFFSET + 10, >> +                           ds_cstr(&match), ds_cstr(&actions), >> stage_hint); >>      ds_clear(&match); >>      ds_clear(&actions); >>      build_acl_log(&actions, acl); >> @@ -4801,8 +4829,9 @@ build_reject_acl_rules(struct ovn_datapath *od, >> struct hmap *lflows, >>                    "eth.dst <-> eth.src; ip6.dst <-> ip6.src; " >>                    "tcp_reset { outport <-> inport; %s };", >>                    ingress ? "output;" : >> "next(pipeline=ingress,table=0);"); >> -   ovn_lflow_add(lflows, od, stage, acl->priority + >> OVN_ACL_PRI_OFFSET + 10, >> -                 ds_cstr(&match), ds_cstr(&actions)); >> +   ovn_lflow_add_with_hint(lflows, od, stage, >> +                           acl->priority + OVN_ACL_PRI_OFFSET + 10, >> +                           ds_cstr(&match), ds_cstr(&actions), >> stage_hint); >>       /* IP traffic */ >>      ds_clear(&match); >> @@ -4819,8 +4848,9 @@ build_reject_acl_rules(struct ovn_datapath *od, >> struct hmap *lflows, >>                    "eth.dst <-> eth.src; ip4.dst <-> ip4.src; " >>                    "icmp4 { outport <-> inport; %s };", >>                    ingress ? "output;" : >> "next(pipeline=ingress,table=0);"); >> -   ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, >> -                 ds_cstr(&match), ds_cstr(&actions)); >> +   ovn_lflow_add_with_hint(lflows, od, stage, >> +                           acl->priority + OVN_ACL_PRI_OFFSET, >> +                           ds_cstr(&match), ds_cstr(&actions), >> stage_hint); >>      ds_clear(&match); >>      ds_clear(&actions); >>      build_acl_log(&actions, acl); >> @@ -4835,8 +4865,9 @@ build_reject_acl_rules(struct ovn_datapath *od, >> struct hmap *lflows, >>                    "eth.dst <-> eth.src; ip6.dst <-> ip6.src; " >>                    "outport <-> inport; %s };", >>                    ingress ? "output;" : >> "next(pipeline=ingress,table=0);"); >> -   ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, >> -                 ds_cstr(&match), ds_cstr(&actions)); >> +   ovn_lflow_add_with_hint(lflows, od, stage, >> +                           acl->priority + OVN_ACL_PRI_OFFSET, >> +                           ds_cstr(&match), ds_cstr(&actions), >> stage_hint); >>       ds_destroy(&match); >>      ds_destroy(&actions); >> @@ -4849,7 +4880,6 @@ consider_acl(struct hmap *lflows, struct >> ovn_datapath *od, >>      bool ingress = !strcmp(acl->direction, "from-lport") ? true :false; >>      enum ovn_stage stage = ingress ? S_SWITCH_IN_ACL : >> S_SWITCH_OUT_ACL; >>  -   char *stage_hint = xasprintf("%08x", acl->header_.uuid.parts[0]); >>      if (!strcmp(acl->action, "allow") >>          || !strcmp(acl->action, "allow-related")) { >>          /* If there are any stateful flows, we must even commit "allow" >> @@ -4864,7 +4894,7 @@ consider_acl(struct hmap *lflows, struct >> ovn_datapath *od, >>              ovn_lflow_add_with_hint(lflows, od, stage, >>                                      acl->priority + OVN_ACL_PRI_OFFSET, >>                                      acl->match, ds_cstr(&actions), >> -                                   stage_hint); >> +                                   &acl->header_); >>              ds_destroy(&actions); >>          } else { >>              struct ds match = DS_EMPTY_INITIALIZER; >> @@ -4893,7 +4923,7 @@ consider_acl(struct hmap *lflows, struct >> ovn_datapath *od, >>                                      acl->priority + OVN_ACL_PRI_OFFSET, >>                                      ds_cstr(&match), >>                                      ds_cstr(&actions), >> -                                   stage_hint); >> +                                   &acl->header_); >>               /* Match on traffic in the request direction for an >> established >>               * connection tracking entry that has not been marked for >> @@ -4913,7 +4943,7 @@ consider_acl(struct hmap *lflows, struct >> ovn_datapath *od, >>              ovn_lflow_add_with_hint(lflows, od, stage, >>                                      acl->priority + OVN_ACL_PRI_OFFSET, >>                                      ds_cstr(&match), ds_cstr(&actions), >> -                                   stage_hint); >> +                                   &acl->header_); >>               ds_destroy(&match); >>              ds_destroy(&actions); >> @@ -4935,14 +4965,15 @@ consider_acl(struct hmap *lflows, struct >> ovn_datapath *od, >>                          " || (ct.est && ct_label.blocked == 1))"); >>              if (!strcmp(acl->action, "reject")) { >>                  build_reject_acl_rules(od, lflows, stage, acl, &match, >> -                                      &actions); >> +                                      &actions, &acl->header_); >>              } else { >>                  ds_put_format(&match, " && (%s)", acl->match); >>                  build_acl_log(&actions, acl); >>                  ds_put_cstr(&actions, "/* drop */"); >> -               ovn_lflow_add(lflows, od, stage, >> -                             acl->priority + OVN_ACL_PRI_OFFSET, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, od, stage, >> +                                       acl->priority + >> OVN_ACL_PRI_OFFSET, >> +                                       ds_cstr(&match), >> ds_cstr(&actions), >> +                                       &acl->header_); >>              } >>              /* For an existing connection without ct_label set, we've >>               * encountered a policy change. ACLs previously allowed >> @@ -4961,14 +4992,15 @@ consider_acl(struct hmap *lflows, struct >> ovn_datapath *od, >>              ds_put_cstr(&actions, "ct_commit(ct_label=1/1); "); >>              if (!strcmp(acl->action, "reject")) { >>                  build_reject_acl_rules(od, lflows, stage, acl, &match, >> -                                      &actions); >> +                                      &actions, &acl->header_); >>              } else { >>                  ds_put_format(&match, " && (%s)", acl->match); >>                  build_acl_log(&actions, acl); >>                  ds_put_cstr(&actions, "/* drop */"); >> -               ovn_lflow_add(lflows, od, stage, >> -                             acl->priority + OVN_ACL_PRI_OFFSET, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, od, stage, >> +                                       acl->priority + >> OVN_ACL_PRI_OFFSET, >> +                                       ds_cstr(&match), >> ds_cstr(&actions), >> +                                       &acl->header_); >>              } >>          } else { >>              /* There are no stateful ACLs in use on this datapath, >> @@ -4976,19 +5008,19 @@ consider_acl(struct hmap *lflows, struct >> ovn_datapath *od, >>               * logical flow action in all cases. */ >>              if (!strcmp(acl->action, "reject")) { >>                  build_reject_acl_rules(od, lflows, stage, acl, &match, >> -                                      &actions); >> +                                      &actions, &acl->header_); >>              } else { >>                  build_acl_log(&actions, acl); >>                  ds_put_cstr(&actions, "/* drop */"); >> -               ovn_lflow_add(lflows, od, stage, >> -                             acl->priority + OVN_ACL_PRI_OFFSET, >> -                             acl->match, ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, od, stage, >> +                                       acl->priority + >> OVN_ACL_PRI_OFFSET, >> +                                       acl->match, ds_cstr(&actions), >> +                                       &acl->header_); >>              } >>          } >>          ds_destroy(&match); >>          ds_destroy(&actions); >>      } >> -   free(stage_hint); >>  } >>   static struct ovn_port_group * >> @@ -5191,9 +5223,9 @@ build_acls(struct ovn_datapath *od, struct hmap >> *lflows, >>                                "&& ip4.src == %s && udp && udp.src == >> 67 " >>                                "&& udp.dst == 68", >> od->nbs->ports[i]->name, >>                                server_mac, server_id); >> -               ovn_lflow_add( >> +               ovn_lflow_add_with_hint( >>                      lflows, od, S_SWITCH_OUT_ACL, 34000, >> ds_cstr(&match), >> -                   actions); >> +                   actions, >> &od->nbs->ports[i]->dhcpv4_options->header_); >>                  ds_destroy(&match); >>              } >>          } >> @@ -5218,9 +5250,9 @@ build_acls(struct ovn_datapath *od, struct hmap >> *lflows, >>                                "&& ip6.src == %s && udp && udp.src == >> 547 " >>                                "&& udp.dst == 546", >> od->nbs->ports[i]->name, >>                                server_mac, server_ip); >> -               ovn_lflow_add( >> +               ovn_lflow_add_with_hint( >>                      lflows, od, S_SWITCH_OUT_ACL, 34000, >> ds_cstr(&match), >> -                   actions); >> +                   actions, >> &od->nbs->ports[i]->dhcpv6_options->header_); >>                  ds_destroy(&match); >>              } >>          } >> @@ -5257,9 +5289,10 @@ build_qos(struct ovn_datapath *od, struct hmap >> *lflows) { >>                   ds_put_format(&dscp_action, "ip.dscp = %"PRId64"; >> next;", >>                                qos->value_action[j]); >> -               ovn_lflow_add(lflows, od, stage, >> -                             qos->priority, >> -                             qos->match, ds_cstr(&dscp_action)); >> +               ovn_lflow_add_with_hint(lflows, od, stage, >> +                                       qos->priority, >> +                                       qos->match, >> ds_cstr(&dscp_action), >> +                                       &qos->header_); >>                  ds_destroy(&dscp_action); >>              } >>          } >> @@ -5288,9 +5321,10 @@ build_qos(struct ovn_datapath *od, struct hmap >> *lflows) { >>               * >>               * We limit the bandwidth of this flow by adding a meter >> table. >>               */ >> -           ovn_lflow_add(lflows, od, stage, >> -                         qos->priority, >> -                         qos->match, ds_cstr(&meter_action)); >> +           ovn_lflow_add_with_hint(lflows, od, stage, >> +                                   qos->priority, >> +                                   qos->match, ds_cstr(&meter_action), >> +                                   &qos->header_); >>              ds_destroy(&meter_action); >>          } >>      } >> @@ -5405,11 +5439,13 @@ build_stateful(struct ovn_datapath *od, struct >> hmap *lflows, struct hmap *lbs) >>                      ds_put_format(&match, " && tcp.dst == %d", >>                                    lb_vip->vip_port); >>                  } >> -               ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, >> -                             120, ds_cstr(&match), ds_cstr(&action)); >> +               ovn_lflow_add_with_hint(lflows, od, >> S_SWITCH_IN_STATEFUL, 120, >> +                                       ds_cstr(&match), >> ds_cstr(&action), >> +                                       &lb->nlb->header_); >>              } else { >> -               ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, >> -                             110, ds_cstr(&match), ds_cstr(&action)); >> +               ovn_lflow_add_with_hint(lflows, od, >> S_SWITCH_IN_STATEFUL, 110, >> +                                       ds_cstr(&match), >> ds_cstr(&action), >> +                                       &lb->nlb->header_); >>              } >>               ds_destroy(&match); >> @@ -5574,7 +5610,8 @@ build_lswitch_rport_arp_req_flow_for_ip(struct >> sset *ips, >>                                          struct ovn_port *patch_op, >>                                          struct ovn_datapath *od, >>                                          uint32_t priority, >> -                                       struct hmap *lflows) >> +                                       struct hmap *lflows, >> +                                       const struct ovsdb_idl_row >> *stage_hint) >>  { >>      struct ds match  = DS_EMPTY_INITIALIZER; >>      struct ds actions = DS_EMPTY_INITIALIZER; >> @@ -5605,8 +5642,8 @@ build_lswitch_rport_arp_req_flow_for_ip(struct >> sset *ips, >>       * in the broadcast domain. >>       */ >>      ds_put_format(&actions, "outport = %s; output;", >> patch_op->json_key); >> -   ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, priority, >> -                 ds_cstr(&match), ds_cstr(&actions)); >> +   ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, priority, >> +                           ds_cstr(&match), ds_cstr(&actions), >> stage_hint); >>       ds_destroy(&match); >>      ds_destroy(&actions); >> @@ -5623,7 +5660,8 @@ static void >>  build_lswitch_rport_arp_req_flows(struct ovn_port *op, >>                                    struct ovn_datapath *sw_od, >>                                    struct ovn_port *sw_op, >> -                                 struct hmap *lflows) >> +                                 struct hmap *lflows, >> +                                 const struct ovsdb_idl_row >> *stage_hint) >>  { >>      if (!op || !op->nbrp) { >>          return; >> @@ -5677,11 +5715,13 @@ build_lswitch_rport_arp_req_flows(struct >> ovn_port *op, >>       if (!sset_is_empty(&all_ips_v4)) { >>          build_lswitch_rport_arp_req_flow_for_ip(&all_ips_v4, >> AF_INET, sw_op, >> -                                               sw_od, 75, lflows); >> +                                               sw_od, 75, lflows, >> +                                               stage_hint); >>      } >>      if (!sset_is_empty(&all_ips_v6)) { >>          build_lswitch_rport_arp_req_flow_for_ip(&all_ips_v6, >> AF_INET6, sw_op, >> -                                               sw_od, 75, lflows); >> +                                               sw_od, 75, lflows, >> +                                               stage_hint); >>      } >>       sset_destroy(&all_ips_v4); >> @@ -5752,8 +5792,9 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>              (!strcmp(op->nbsp->type, "vtep"))) { >>              ds_clear(&match); >>              ds_put_format(&match, "inport == %s", op->json_key); >> -           ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, >> -                         ds_cstr(&match), "next;"); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_SWITCH_IN_ARP_ND_RSP, >> +                                   100, ds_cstr(&match), "next;", >> +                                   &op->nbsp->header_); >>          } >>      } >>  @@ -5806,8 +5847,10 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      "bind_vport(%s, inport); " >>                      "next;", >>                      op->json_key); >> -               ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, >> 100, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> +                                       S_SWITCH_IN_ARP_ND_RSP, 100, >> +                                       ds_cstr(&match), >> ds_cstr(&actions), >> +                                       &vp->nbsp->header_); >>              } >>               free(tokstr); >> @@ -5846,8 +5889,11 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                          "output;", >>                          op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s, >>                          op->lsp_addrs[i].ipv4_addrs[j].addr_s); >> -                   ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_ARP_ND_RSP, 50, >> -                               ds_cstr(&match), ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           S_SWITCH_IN_ARP_ND_RSP, 50, >> +                                           ds_cstr(&match), >> +                                           ds_cstr(&actions), >> +                                           &op->nbsp->header_); >>                       /* Do not reply to an ARP request from the >> port that owns >>                       * the address (otherwise a DHCP client that >> ARPs to check >> @@ -5862,8 +5908,10 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                       * network is not working as configured, so >> dropping the >>                       * request would frustrate that intent.) */ >>                      ds_put_format(&match, " && inport == %s", >> op->json_key); >> -                   ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_ARP_ND_RSP, 100, >> -                               ds_cstr(&match), "next;"); >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           S_SWITCH_IN_ARP_ND_RSP, 100, >> +                                           ds_cstr(&match), "next;", >> +                                           &op->nbsp->header_); >>                  } >>                   /* For ND solicitations, we need to listen for >> both the >> @@ -5894,14 +5942,19 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                              op->lsp_addrs[i].ipv6_addrs[j].addr_s, >>                              op->lsp_addrs[i].ipv6_addrs[j].addr_s, >>                              op->lsp_addrs[i].ea_s); >> -                   ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_ARP_ND_RSP, 50, >> -                               ds_cstr(&match), ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           S_SWITCH_IN_ARP_ND_RSP, 50, >> +                                           ds_cstr(&match), >> +                                           ds_cstr(&actions), >> +                                           &op->nbsp->header_); >>                       /* Do not reply to a solicitation from the >> port that owns >>                       * the address (otherwise DAD detection will >> fail). */ >>                      ds_put_format(&match, " && inport == %s", >> op->json_key); >> -                   ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_ARP_ND_RSP, 100, >> -                               ds_cstr(&match), "next;"); >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           S_SWITCH_IN_ARP_ND_RSP, 100, >> +                                           ds_cstr(&match), "next;", >> +                                           &op->nbsp->header_); >>                  } >>              } >>          } >> @@ -5949,9 +6002,11 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      "output;", >>                      svc_monitor_mac, svc_monitor_mac, >>                      lb->vips[i].backends[j].svc_mon_src_ip); >> -               ovn_lflow_add(lflows, lb->vips[i].backends[j].op->od, >> -                             S_SWITCH_IN_ARP_ND_RSP, 110, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, >> +                                       lb->vips[i].backends[j].op->od, >> +                                       S_SWITCH_IN_ARP_ND_RSP, 110, >> +                                       ds_cstr(&match), >> ds_cstr(&actions), >> +                                       &lb->nlb->header_); >>              } >>          } >>      } >> @@ -5985,6 +6040,14 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>          } >>           for (size_t i = 0; i < op->n_lsp_addrs; i++) { >> +           struct ovsdb_idl_row *stage_hint; >> + >> +           if (op->nbsp->dhcpv4_options) { >> +               stage_hint = &op->nbsp->dhcpv4_options->header_; >> +           } else { >> +               stage_hint = NULL; >> +           } >> + >>              for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; >> j++) { >>                  struct ds options_action = DS_EMPTY_INITIALIZER; >>                  struct ds response_action = DS_EMPTY_INITIALIZER; >> @@ -6006,9 +6069,11 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                        op->json_key); >>                      } >>  -                   ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_DHCP_OPTIONS, >> -                                 100, ds_cstr(&match), >> -                                 ds_cstr(&options_action)); >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           S_SWITCH_IN_DHCP_OPTIONS, >> 100, >> +                                           ds_cstr(&match), >> +                                           ds_cstr(&options_action), >> +                                           stage_hint); >>                      ds_clear(&match); >>                      /* Allow ip4.src = OFFER_IP and >>                       * ip4.dst = {SERVER_IP, 255.255.255.255} for >> the below >> @@ -6030,9 +6095,11 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                        op->json_key); >>                      } >>  -                   ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_DHCP_OPTIONS, >> -                                 100, ds_cstr(&match), >> -                                 ds_cstr(&options_action)); >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           S_SWITCH_IN_DHCP_OPTIONS, >> 100, >> +                                           ds_cstr(&match), >> +                                           ds_cstr(&options_action), >> +                                           stage_hint); >>                      ds_clear(&match); >>                       /* If REGBIT_DHCP_OPTS_RESULT is set, it means >> the >> @@ -6050,9 +6117,11 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                        op->json_key); >>                      } >>  -                   ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_DHCP_RESPONSE, >> -                                 100, ds_cstr(&match), >> -                                 ds_cstr(&response_action)); >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           >> S_SWITCH_IN_DHCP_RESPONSE, 100, >> +                                           ds_cstr(&match), >> +                                           ds_cstr(&response_action), >> +                                           stage_hint); >>                      ds_destroy(&options_action); >>                      ds_destroy(&response_action); >>                      ds_destroy(&ipv4_addr_match); >> @@ -6060,6 +6129,12 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                  } >>              } >>  +           if (op->nbsp->dhcpv6_options) { >> +               stage_hint = &op->nbsp->dhcpv6_options->header_; >> +           } else { >> +               stage_hint = NULL; >> +           } >> + >>              for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; >> j++) { >>                  struct ds options_action = DS_EMPTY_INITIALIZER; >>                  struct ds response_action = DS_EMPTY_INITIALIZER; >> @@ -6080,14 +6155,20 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                        op->json_key); >>                      } >>  -                   ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_DHCP_OPTIONS, 100, >> -                                 ds_cstr(&match), >> ds_cstr(&options_action)); >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           S_SWITCH_IN_DHCP_OPTIONS, >> 100, >> +                                           ds_cstr(&match), >> +                                           ds_cstr(&options_action), >> +                                           stage_hint); >>                       /* If REGBIT_DHCP_OPTS_RESULT is set to 1, it >> means the >>                       * put_dhcpv6_opts action is successful */ >>                      ds_put_cstr(&match, " && "REGBIT_DHCP_OPTS_RESULT); >> -                   ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_DHCP_RESPONSE, 100, >> -                                 ds_cstr(&match), >> ds_cstr(&response_action)); >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           >> S_SWITCH_IN_DHCP_RESPONSE, 100, >> +                                           ds_cstr(&match), >> +                                           ds_cstr(&response_action), >> +                                           stage_hint); >>                      ds_destroy(&options_action); >>                      ds_destroy(&response_action); >>                      break; >> @@ -6172,9 +6253,10 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                              op->od->localnet_port->json_key, >>                              op->lsp_addrs[i].ea_s, op->json_key, >>                              rp->lsp_addrs[k].ipv4_addrs[l].addr_s); >> -                       ovn_lflow_add(lflows, op->od, >> -                                     S_SWITCH_IN_EXTERNAL_PORT, 100, >> -                                     ds_cstr(&match), "drop;"); >> +                       ovn_lflow_add_with_hint(lflows, op->od, >> +                                               >> S_SWITCH_IN_EXTERNAL_PORT, >> +                                               100, ds_cstr(&match), >> "drop;", >> +                                               &op->nbsp->header_); >>                      } >>                      for (size_t l = 0; l < >> rp->lsp_addrs[k].n_ipv6_addrs; >>                           l++) { >> @@ -6189,9 +6271,10 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                              rp->lsp_addrs[k].ipv6_addrs[l].addr_s, >>                              rp->lsp_addrs[k].ipv6_addrs[l].sn_addr_s, >>                              rp->lsp_addrs[k].ipv6_addrs[l].addr_s); >> -                       ovn_lflow_add(lflows, op->od, >> -                                     S_SWITCH_IN_EXTERNAL_PORT, 100, >> -                                     ds_cstr(&match), "drop;"); >> +                       ovn_lflow_add_with_hint(lflows, op->od, >> +                                               >> S_SWITCH_IN_EXTERNAL_PORT, 100, >> +                                               ds_cstr(&match), >> "drop;", >> +                                               &op->nbsp->header_); >>                      } >>                  } >>              } >> @@ -6326,7 +6409,8 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>           * requests only to the router port that owns the IP address. >>           */ >>          if (!strcmp(op->nbsp->type, "router")) { >> -           build_lswitch_rport_arp_req_flows(op->peer, op->od, op, >> lflows); >> +           build_lswitch_rport_arp_req_flows(op->peer, op->od, op, >> lflows, >> +                                             &op->nbsp->header_); >>          } >>           for (size_t i = 0; i < op->nbsp->n_addresses; i++) { >> @@ -6342,8 +6426,10 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                   ds_clear(&actions); >>                  ds_put_format(&actions, "outport = %s; output;", >> op->json_key); >> -               ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> S_SWITCH_IN_L2_LKUP, >> +                                       50, ds_cstr(&match), >> +                                       ds_cstr(&actions), >> +                                       &op->nbsp->header_); >>              } else if (!strcmp(op->nbsp->addresses[i], "unknown")) { >>                  if (lsp_is_enabled(op->nbsp)) { >>                      ovn_multicast_add(mcgroups, &mc_unknown, op); >> @@ -6361,8 +6447,10 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                   ds_clear(&actions); >>                  ds_put_format(&actions, "outport = %s; output;", >> op->json_key); >> -               ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> S_SWITCH_IN_L2_LKUP, >> +                                       50, ds_cstr(&match), >> +                                       ds_cstr(&actions), >> +                                       &op->nbsp->header_); >>              } else if (!strcmp(op->nbsp->addresses[i], "router")) { >>                  if (!op->peer || !op->peer->nbrp >>                      || !ovs_scan(op->peer->nbrp->mac, >> @@ -6403,8 +6491,10 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                   ds_clear(&actions); >>                  ds_put_format(&actions, "outport = %s; output;", >> op->json_key); >> -               ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> +                                       S_SWITCH_IN_L2_LKUP, 50, >> +                                       ds_cstr(&match), >> ds_cstr(&actions), >> +                                       &op->nbsp->header_); >>                   /* Add ethernet addresses specified in NAT rules on >>                   * distributed logical routers. */ >> @@ -6426,9 +6516,11 @@ build_lswitch_flows(struct hmap *datapaths, >> struct hmap *ports, >>                              ds_clear(&actions); >>                              ds_put_format(&actions, "outport = %s; >> output;", >>                                            op->json_key); >> -                           ovn_lflow_add(lflows, op->od, >> S_SWITCH_IN_L2_LKUP, >> -                                         50, ds_cstr(&match), >> -                                         ds_cstr(&actions)); >> +                           ovn_lflow_add_with_hint(lflows, op->od, >> +                                                   >> S_SWITCH_IN_L2_LKUP, 50, >> +                                                   ds_cstr(&match), >> +                                                   ds_cstr(&actions), >> +                                                   &op->nbsp->header_); >>                          } >>                      } >>                  } >> @@ -6544,7 +6636,8 @@ get_outport_for_routing_policy_nexthop(struct >> ovn_datapath *od, >>  static void >>  build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od, >>                            struct hmap *ports, >> -                         const struct nbrec_logical_router_policy >> *rule) >> +                         const struct nbrec_logical_router_policy >> *rule, >> +                         const struct ovsdb_idl_row *stage_hint) >>  { >>      struct ds match = DS_EMPTY_INITIALIZER; >>      struct ds actions = DS_EMPTY_INITIALIZER; >> @@ -6584,8 +6677,9 @@ build_routing_policy_flow(struct hmap *lflows, >> struct ovn_datapath *od, >>          ds_put_cstr(&actions, "next;"); >>      } >>      ds_put_format(&match, "%s", rule->match); >> -   ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, rule->priority, >> -                 ds_cstr(&match), ds_cstr(&actions)); >> + >> +   ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY, >> rule->priority, >> +                           ds_cstr(&match), ds_cstr(&actions), >> stage_hint); >>      ds_destroy(&match); >>      ds_destroy(&actions); >>  } >> @@ -6654,8 +6748,9 @@ add_distributed_nat_routes(struct hmap *lflows, >> const struct ovn_port *op) >>                        REGBIT_NAT_REDIRECT" = 0; next;", >>                        op->od->l3dgw_port->json_key, >>                        nat->external_mac); >> -       ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, >> -                     ds_cstr(&match), ds_cstr(&actions)); >> +       ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_ROUTING, 400, >> +                               ds_cstr(&match), ds_cstr(&actions), >> +                               &nat->header_); >>          ds_clear(&match); >>          ds_clear(&actions); >>  @@ -6702,8 +6797,9 @@ add_distributed_nat_routes(struct hmap >> *lflows, const struct ovn_port *op) >>                            family == AF_INET ? "4" : "6", >>                            family == AF_INET ? "" : "xx", >>                            nat->external_ip); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_ROUTING, >> +                                   400, ds_cstr(&match), >> ds_cstr(&actions), >> +                                   &nat2->header_); >>              ds_clear(&match); >>              ds_clear(&actions); >>          } >> @@ -6715,7 +6811,8 @@ add_distributed_nat_routes(struct hmap *lflows, >> const struct ovn_port *op) >>  static void >>  add_route(struct hmap *lflows, const struct ovn_port *op, >>            const char *lrp_addr_s, const char *network_s, int plen, >> -         const char *gateway, const char *policy) >> +         const char *gateway, const char *policy, >> +         const struct ovsdb_idl_row *stage_hint) >>  { >>      bool is_ipv4 = strchr(network_s, '.') ? true : false; >>      struct ds match = DS_EMPTY_INITIALIZER; >> @@ -6762,8 +6859,8 @@ add_route(struct hmap *lflows, const struct >> ovn_port *op, >>       /* The priority here is calculated to implement >> longest-prefix-match >>       * routing. */ >> -   ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, priority, >> -                 ds_cstr(&match), ds_cstr(&actions)); >> +   ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_ROUTING, >> priority, >> +                           ds_cstr(&match), ds_cstr(&actions), >> stage_hint); >>      ds_destroy(&match); >>      ds_destroy(&actions); >>  } >> @@ -6771,7 +6868,8 @@ add_route(struct hmap *lflows, const struct >> ovn_port *op, >>  static void >>  build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, >>                          struct hmap *ports, >> -                       const struct >> nbrec_logical_router_static_route *route) >> +                       const struct >> nbrec_logical_router_static_route *route, >> +                       const struct ovsdb_idl_row *stage_hint) >>  { >>      ovs_be32 nexthop; >>      const char *lrp_addr_s = NULL; >> @@ -6894,7 +6992,7 @@ build_static_route_flow(struct hmap *lflows, >> struct ovn_datapath *od, >>       char *policy = route->policy ? route->policy : "dst-ip"; >>      add_route(lflows, out_port, lrp_addr_s, prefix_s, plen, >> route->nexthop, >> -             policy); >> +             policy, stage_hint); >>   free_prefix_s: >>      free(prefix_s); >> @@ -6977,35 +7075,38 @@ add_router_lb_flow(struct hmap *lflows, struct >> ovn_datapath *od, >>                     const char *lb_force_snat_ip, struct smap_node >> *lb_info, >>                     bool is_udp, int addr_family, char *ip_addr, >>                     uint16_t l4_port, struct nbrec_load_balancer *lb, >> -                  struct shash *meter_groups) >> +                  struct shash *meter_groups, >> +                  const struct ovsdb_idl_row *stage_hint) >>  { >>      char *backend_ips = lb_info->value; >>       build_empty_lb_event_flow(od, lflows, lb_info, ip_addr, lb, >>                                l4_port, addr_family, S_ROUTER_IN_DNAT, >> -                             meter_groups); >> +                             meter_groups, stage_hint); >>       /* A match and actions for new connections. */ >>      char *new_match = xasprintf("ct.new && %s", ds_cstr(match)); >>      if (lb_force_snat_ip) { >>          char *new_actions = xasprintf("flags.force_snat_for_lb = 1; >> %s", >>                                        ds_cstr(actions)); >> -       ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, new_match, >> -                     new_actions); >> +       ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, >> +                               new_match, new_actions, stage_hint); >>          free(new_actions); >>      } else { >> -       ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, new_match, >> -                     ds_cstr(actions)); >> +       ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, >> +                               new_match, ds_cstr(actions), >> stage_hint); >>      } >>       /* A match and actions for established connections. */ >>      char *est_match = xasprintf("ct.est && %s", ds_cstr(match)); >>      if (lb_force_snat_ip) { >> -       ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, est_match, >> -                     "flags.force_snat_for_lb = 1; ct_dnat;"); >> +       ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, >> +                               est_match, >> +                               "flags.force_snat_for_lb = 1; ct_dnat;", >> +                               stage_hint); >>      } else { >> -       ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, est_match, >> -                     "ct_dnat;"); >> +       ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, >> +                               est_match, "ct_dnat;", stage_hint); >>      } >>       free(new_match); >> @@ -7068,12 +7169,14 @@ add_router_lb_flow(struct hmap *lflows, struct >> ovn_datapath *od, >>                   "is_chassis_resident(%s)", od->l3dgw_port->json_key, >>                   od->l3redirect_port->json_key); >>      if (lb_force_snat_ip) { >> -       ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 120, >> -                     ds_cstr(&undnat_match), >> -                     "flags.force_snat_for_lb = 1; ct_dnat;"); >> +       ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120, >> +                               ds_cstr(&undnat_match), >> +                               "flags.force_snat_for_lb = 1; ct_dnat;", >> +                               stage_hint); >>      } else { >> -       ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 120, >> -                     ds_cstr(&undnat_match), "ct_dnat;"); >> +       ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120, >> +                               ds_cstr(&undnat_match), "ct_dnat;", >> +                               stage_hint); >>      } >>       ds_destroy(&undnat_match); >> @@ -7219,8 +7322,8 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>           ds_clear(&match); >>          ds_put_format(&match, "eth.mcast && inport == %s", >> op->json_key); >> -       ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, >> -                     ds_cstr(&match), "next;"); >> +       ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_ADMISSION, 50, >> +                               ds_cstr(&match), "next;", >> &op->nbrp->header_); >>           ds_clear(&match); >>          ds_put_format(&match, "eth.dst == %s && inport == %s", >> @@ -7232,8 +7335,8 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>              ds_put_format(&match, " && is_chassis_resident(%s)", >>                            op->od->l3redirect_port->json_key); >>          } >> -       ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, >> -                     ds_cstr(&match), "next;"); >> +       ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_ADMISSION, 50, >> +                               ds_cstr(&match), "next;", >> &op->nbrp->header_); >>      } >>       /* Logical router ingress table 1: LOOKUP_NEIGHBOR and >> @@ -7318,10 +7421,12 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                  ds_put_format(&match, " && is_chassis_resident(%s)", >>                                op->od->l3redirect_port->json_key); >>              } >> -           ovn_lflow_add(lflows, op->od, >> S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, >> -                         ds_cstr(&match), >> -                         REGBIT_LOOKUP_NEIGHBOR_RESULT" = " >> -                         "lookup_arp(inport, arp.spa, arp.sha); >> next;"); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> +                                   S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, >> +                                   ds_cstr(&match), >> +                                   REGBIT_LOOKUP_NEIGHBOR_RESULT" = " >> +                                   "lookup_arp(inport, arp.spa, >> arp.sha); " >> +                                   "next;", &op->nbrp->header_); >>          } >>      } >>  @@ -7391,8 +7496,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>              ds_put_cstr(&match, "ip4.src == "); >>              op_put_v4_networks(&match, op, true); >>              ds_put_cstr(&match, " && "REGBIT_EGRESS_LOOPBACK" == 0"); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, >> -                         ds_cstr(&match), "drop;"); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, 100, >> +                                   ds_cstr(&match), "drop;", >> +                                   &op->nbrp->header_); >>               /* ICMP echo reply. These flows reply to ICMP echo >> requests >>               * received for the router's IP address. Since packets only >> @@ -7411,8 +7517,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                  "icmp4.type = 0; " >>                  "flags.loopback = 1; " >>                  "next; "); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, 90, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &op->nbrp->header_); >>          } >>           /* ICMP time exceeded */ >> @@ -7433,8 +7540,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                            "ip.ttl = 255; " >>                            "next; };", >>                            op->lrp_networks.ipv4_addrs[i].addr_s); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, 40, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &op->nbrp->header_); >>          } >>           /* ARP reply. These flows reply to ARP requests for the >> router's own >> @@ -7495,8 +7603,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                  op->lrp_networks.ea_s, >>                  op->lrp_networks.ipv4_addrs[i].addr_s, >>                  op->json_key); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, 90, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &op->nbrp->header_); >>          } >>           /* A set to hold all load-balancer vips that need ARP >> responses. */ >> @@ -7740,8 +7849,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      IP_ARGS(ip), >>                      op->json_key); >>              } >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> + >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, 90, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &nat->header_); >>          } >>           if (!smap_get(&op->od->nbr->options, "chassis") >> @@ -7759,8 +7870,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                       "icmp4.type = 3; " >>                                       "icmp4.code = 3; " >>                                       "next; };"; >> -               ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, >> -                             ds_cstr(&match), action); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, >> +                                       80, ds_cstr(&match), action, >> +                                       &op->nbrp->header_); >>                   ds_clear(&match); >>                  ds_put_format(&match, >> @@ -7770,8 +7882,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                           "eth.dst <-> eth.src; " >>                           "ip4.dst <-> ip4.src; " >>                           "next; };"; >> -               ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, >> -                             ds_cstr(&match), action); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, >> +                                       80, ds_cstr(&match), action, >> +                                       &op->nbrp->header_); >>                   ds_clear(&match); >>                  ds_put_format(&match, >> @@ -7784,8 +7897,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                           "icmp4.type = 3; " >>                           "icmp4.code = 2; " >>                           "next; };"; >> -               ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 70, >> -                             ds_cstr(&match), action); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, >> +                                       70, ds_cstr(&match), action, >> +                                       &op->nbrp->header_); >>              } >>          } >>  @@ -7844,8 +7958,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>           if (has_drop_ips) { >>              /* Drop IP traffic to this router. */ >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 60, >> -                         ds_cstr(&match), "drop;"); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, 60, >> +                                   ds_cstr(&match), "drop;", >> +                                   &op->nbrp->header_); >>          } >>           free(snat_ips); >> @@ -7878,8 +7993,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                          "icmp6.type = 129; " >>                          "flags.loopback = 1; " >>                          "next; "); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, 90, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &op->nbrp->header_); >>          } >>           /* ND reply. These flows reply to ND solicitations for the >> @@ -7919,8 +8035,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                            op->lrp_networks.ipv6_addrs[i].addr_s, >>                            op->lrp_networks.ipv6_addrs[i].addr_s, >>                            op->lrp_networks.ea_s); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, 90, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &op->nbrp->header_); >>          } >>           /* UDP/TCP port unreachable */ >> @@ -7935,8 +8052,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                       "eth.dst <-> eth.src; " >>                                       "ip6.dst <-> ip6.src; " >>                                       "next; };"; >> -               ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, >> -                         ds_cstr(&match), action); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, >> +                                       80, ds_cstr(&match), action, >> +                                       &op->nbrp->header_); >>                   ds_clear(&match); >>                  ds_put_format(&match, >> @@ -7949,8 +8067,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                           "icmp6.type = 1; " >>                           "icmp6.code = 4; " >>                           "next; };"; >> -               ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, >> -                             ds_cstr(&match), action); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, >> +                                       80, ds_cstr(&match), action, >> +                                       &op->nbrp->header_); >>                   ds_clear(&match); >>                  ds_put_format(&match, >> @@ -7963,8 +8082,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                           "icmp6.type = 1; " >>                           "icmp6.code = 3; " >>                           "next; };"; >> -               ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 70, >> -                             ds_cstr(&match), action); >> +               ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, >> +                                       70, ds_cstr(&match), action, >> +                                       &op->nbrp->header_); >>              } >>          } >>  @@ -7995,8 +8115,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                            "icmp6.code = 0; /* TTL exceeded in >> transit */ " >>                            "next; };", >>                            op->lrp_networks.ipv6_addrs[i].addr_s); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_IP_INPUT, 40, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &op->nbrp->header_); >>          } >>      } >>  @@ -8135,8 +8256,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                         ds_put_cstr(&actions, "ct_snat;"); >>                      } >>  -                   ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 90, >> -                                 ds_cstr(&match), ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_UNSNAT, >> +                                           90, ds_cstr(&match), >> +                                           ds_cstr(&actions), >> +                                           &nat->header_); >>                  } else { >>                      /* Distributed router. */ >>  @@ -8162,8 +8285,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                          ds_put_cstr(&actions, "ct_snat;"); >>                      } >>  -                   ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 100, >> -                                 ds_cstr(&match), ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_UNSNAT, >> +                                           100, ds_cstr(&match), >> +                                           ds_cstr(&actions), >> +                                           &nat->header_); >>                       /* Traffic received on other router ports must be >>                       * redirected to the central instance of the >> l3dgw_port >> @@ -8172,9 +8297,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      ds_put_format(&match, "ip && ip%s.dst == %s", >>                                    is_v6 ? "6" : "4", >>                                    nat->external_ip); >> -                   ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 50, >> -                                 ds_cstr(&match), >> -                                 REGBIT_NAT_REDIRECT" = 1; next;"); >> +                   ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_UNSNAT, >> +                                           50, ds_cstr(&match), >> +                                           REGBIT_NAT_REDIRECT" = 1; >> next;", >> +                                           &nat->header_); >>                  } >>              } >>  @@ -8210,8 +8336,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                        "ct_dnat(%s);", nat->logical_ip); >>                      } >>  -                   ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100, >> -                                 ds_cstr(&match), ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_DNAT, 100, >> +                                           ds_cstr(&match), >> ds_cstr(&actions), >> +                                           &nat->header_); >>                  } else { >>                      /* Distributed router. */ >>  @@ -8238,8 +8365,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                        nat->logical_ip); >>                      } >>  -                   ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100, >> -                                 ds_cstr(&match), ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_DNAT, 100, >> +                                           ds_cstr(&match), >> ds_cstr(&actions), >> +                                           &nat->header_); >>                       /* Traffic received on other router ports must be >>                       * redirected to the central instance of the >> l3dgw_port >> @@ -8248,9 +8376,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      ds_put_format(&match, "ip && ip%s.dst == %s", >>                                    is_v6 ? "6" : "4", >>                                    nat->external_ip); >> -                   ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, >> -                                 ds_cstr(&match), >> -                                 REGBIT_NAT_REDIRECT" = 1; next;"); >> +                   ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_DNAT, 50, >> +                                           ds_cstr(&match), >> +                                           REGBIT_NAT_REDIRECT" = 1; >> next;", >> +                                           &nat->header_); >>                  } >>              } >>  @@ -8289,8 +8418,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      ds_put_format(&actions, "ct_dnat;"); >>                  } >>  -               ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_OUT_UNDNAT, 100, >> +                                       ds_cstr(&match), >> ds_cstr(&actions), >> +                                       &nat->header_); >>              } >>               /* Egress SNAT table: Packets enter the egress >> pipeline with >> @@ -8317,9 +8447,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      /* The priority here is calculated such that the >>                       * nat->logical_ip with the longest mask gets a >> higher >>                       * priority. */ >> -                   ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, >> -                                 count_1bits(ntohl(mask)) + 1, >> -                                 ds_cstr(&match), ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_OUT_SNAT, >> +                                           count_1bits(ntohl(mask)) >> + 1, >> +                                           ds_cstr(&match), >> ds_cstr(&actions), >> +                                           &nat->header_); >>                  } else { >>                      uint16_t priority = count_1bits(ntohl(mask)) + 1; >>  @@ -8354,9 +8485,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      /* The priority here is calculated such that the >>                       * nat->logical_ip with the longest mask gets a >> higher >>                       * priority. */ >> -                   ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, >> -                                 priority, ds_cstr(&match), >> -                                 ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_OUT_SNAT, >> +                                           priority, ds_cstr(&match), >> +                                           ds_cstr(&actions), >> +                                           &nat->header_); >>                  } >>              } >>  @@ -8373,8 +8505,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                ETH_ADDR_ARGS(mac), >>                                od->l3dgw_port->json_key, >>                                nat->logical_port); >> -               ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 50, >> -                             ds_cstr(&match), "next;"); >> +               ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_ADMISSION, 50, >> +                                       ds_cstr(&match), "next;", >> +                                       &nat->header_); >>              } >>               /* Ingress Gateway Redirect Table: For NAT on a >> distributed >> @@ -8387,8 +8520,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                is_v6 ? "6" : "4", >>                                nat->logical_ip, >>                                od->l3dgw_port->json_key); >> -               ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 100, >> -                             ds_cstr(&match), "next;"); >> +               ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_GW_REDIRECT, >> +                                       100, ds_cstr(&match), "next;", >> +                                       &nat->header_); >>              } >>               /* Egress Loopback table: For NAT on a distributed >> router. >> @@ -8422,16 +8556,21 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                                        "flags = 0; flags.loopback = 1; " >>                                        REGBIT_EGRESS_LOOPBACK" = 1; " >>                                        "next(pipeline=ingress, >> table=0); "); >> -                       ovn_lflow_add(lflows, od, >> S_ROUTER_OUT_EGR_LOOP, 300, >> -                                     ds_cstr(&match), >> ds_cstr(&actions)); >> +                       ovn_lflow_add_with_hint(lflows, od, >> +                                               >> S_ROUTER_OUT_EGR_LOOP, 300, >> +                                               ds_cstr(&match), >> +                                               ds_cstr(&actions), >> +                                               &nat2->header_); >>                           ds_clear(&match); >>                          ds_put_format(&match, >>                                        "ip%s.src == %s && ip%s.dst == >> %s", >>                                        is_v6 ? "6" : "4", >> nat2->external_ip, >>                                        is_v6 ? "6" : "4", >> nat->external_ip); >> -                       ovn_lflow_add(lflows, od, >> S_ROUTER_OUT_EGR_LOOP, 200, >> -                                     ds_cstr(&match), "next;"); >> +                       ovn_lflow_add_with_hint(lflows, od, >> +                                               >> S_ROUTER_OUT_EGR_LOOP, 200, >> +                                               ds_cstr(&match), >> "next;", >> +                                               &nat2->header_); >>                          ds_clear(&match); >>                      } >>                  } >> @@ -8451,8 +8590,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                  } >>                  ds_put_format(&actions, REGBIT_EGRESS_LOOPBACK" = 1; " >>                                "next(pipeline=ingress, table=0); };"); >> -               ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 100, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_OUT_EGR_LOOP, 100, >> +                                       ds_cstr(&match), >> ds_cstr(&actions), >> +                                       &nat->header_); >>              } >>          } >>  @@ -8591,8 +8731,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                          ds_put_format(&match, "ip && ip6.dst == %s", >>                                        ip_address); >>                      } >> -                   ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, >> -                                 100, ds_cstr(&match), "ct_next;"); >> +                   ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_DEFRAG, >> +                                           100, ds_cstr(&match), >> "ct_next;", >> +                                           &lb->header_); >>                  } >>                   /* Higher priority rules are added for >> load-balancing in DNAT >> @@ -8633,7 +8774,8 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                  add_router_lb_flow(lflows, od, &match, &actions, prio, >>                                     lb_force_snat_ip, node, is_udp, >>                                     addr_family, ip_address, port, lb, >> -                                  meter_groups); >> +                                  meter_groups, >> +                                  &lb->header_); >>                   free(ip_address); >>              } >> @@ -8706,8 +8848,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>           if (add_rs_response_flow) { >>              ds_put_cstr(&actions, "); next;"); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS, 50, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> S_ROUTER_IN_ND_RA_OPTIONS, >> +                                   50, ds_cstr(&match), >> ds_cstr(&actions), >> +                                   &op->nbrp->header_); >>              ds_clear(&actions); >>              ds_clear(&match); >>              ds_put_format(&match, "inport == %s && ip6.dst == >> ff02::2 && " >> @@ -8723,8 +8866,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                            "outport = inport; flags.loopback = 1; " >>                            "output;", >>                            op->lrp_networks.ea_s, ip6_str); >> -           ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ND_RA_RESPONSE, >> 50, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, op->od, >> +                                   S_ROUTER_IN_ND_RA_RESPONSE, 50, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &op->nbrp->header_); >>          } >>      } >>  @@ -8758,13 +8903,15 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>          for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { >>              add_route(lflows, op, >> op->lrp_networks.ipv4_addrs[i].addr_s, >>                        op->lrp_networks.ipv4_addrs[i].network_s, >> -                     op->lrp_networks.ipv4_addrs[i].plen, NULL, NULL); >> +                     op->lrp_networks.ipv4_addrs[i].plen, NULL, NULL, >> +                     &op->nbrp->header_); >>          } >>           for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { >>              add_route(lflows, op, >> op->lrp_networks.ipv6_addrs[i].addr_s, >>                        op->lrp_networks.ipv6_addrs[i].network_s, >> -                     op->lrp_networks.ipv6_addrs[i].plen, NULL, NULL); >> +                     op->lrp_networks.ipv6_addrs[i].plen, NULL, NULL, >> +                     &op->nbrp->header_); >>          } >>      } >>  @@ -8778,7 +8925,7 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>              const struct nbrec_logical_router_static_route *route; >>               route = od->nbr->static_routes[i]; >> -           build_static_route_flow(lflows, od, ports, route); >> +           build_static_route_flow(lflows, od, ports, route, >> &route->header_); >>          } >>      } >>  @@ -8849,7 +8996,7 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>          for (int i = 0; i < od->nbr->n_policies; i++) { >>              const struct nbrec_logical_router_policy *rule >>                  = od->nbr->policies[i]; >> -           build_routing_policy_flow(lflows, od, ports, rule); >> +           build_routing_policy_flow(lflows, od, ports, rule, >> &rule->header_); >>          } >>      } >>  @@ -8900,8 +9047,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      ds_clear(&actions); >>                      ds_put_format(&actions, "eth.dst = %s; next;", >>                                    op->lrp_networks.ea_s); >> -                   ovn_lflow_add(lflows, op->peer->od, >> S_ROUTER_IN_ARP_RESOLVE, >> -                                 100, ds_cstr(&match), >> ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, op->peer->od, >> +                                           S_ROUTER_IN_ARP_RESOLVE, >> 100, >> +                                           ds_cstr(&match), >> ds_cstr(&actions), >> +                                           &op->nbrp->header_); >>                  } >>                   if (op->lrp_networks.n_ipv6_addrs) { >> @@ -8913,8 +9062,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      ds_clear(&actions); >>                      ds_put_format(&actions, "eth.dst = %s; next;", >>                                    op->lrp_networks.ea_s); >> -                   ovn_lflow_add(lflows, op->peer->od, >> S_ROUTER_IN_ARP_RESOLVE, >> -                                 100, ds_cstr(&match), >> ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, op->peer->od, >> +                                           S_ROUTER_IN_ARP_RESOLVE, >> 100, >> +                                           ds_cstr(&match), >> ds_cstr(&actions), >> +                                           &op->nbrp->header_); >>                  } >>              } >>  @@ -8935,8 +9086,11 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      ds_clear(&actions); >>                      ds_put_format(&actions, "eth.dst = %s; next;", >>                                    op->lrp_networks.ea_s); >> -                   ovn_lflow_add(lflows, op->od, >> S_ROUTER_IN_ARP_RESOLVE, >> -                                 50, ds_cstr(&match), >> ds_cstr(&actions)); >> + >> +                   ovn_lflow_add_with_hint(lflows, op->od, >> +                                           S_ROUTER_IN_ARP_RESOLVE, 50, >> +                                           ds_cstr(&match), >> ds_cstr(&actions), >> +                                           &op->nbrp->header_); >>                  } >>              } >>          } else if (op->od->n_router_ports && strcmp(op->nbsp->type, >> "router") >> @@ -8977,9 +9131,11 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                           ds_clear(&actions); >>                          ds_put_format(&actions, "eth.dst = %s; >> next;", ea_s); >> -                       ovn_lflow_add(lflows, peer->od, >> -                                     S_ROUTER_IN_ARP_RESOLVE, 100, >> -                                     ds_cstr(&match), >> ds_cstr(&actions)); >> +                       ovn_lflow_add_with_hint(lflows, peer->od, >> +                                               >> S_ROUTER_IN_ARP_RESOLVE, 100, >> +                                               ds_cstr(&match), >> +                                               ds_cstr(&actions), >> +                                               &op->nbsp->header_); >>                      } >>                  } >>  @@ -9011,9 +9167,11 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                           ds_clear(&actions); >>                          ds_put_format(&actions, "eth.dst = %s; >> next;", ea_s); >> -                       ovn_lflow_add(lflows, peer->od, >> -                                     S_ROUTER_IN_ARP_RESOLVE, 100, >> -                                     ds_cstr(&match), >> ds_cstr(&actions)); >> +                       ovn_lflow_add_with_hint(lflows, peer->od, >> +                                               >> S_ROUTER_IN_ARP_RESOLVE, 100, >> +                                               ds_cstr(&match), >> +                                               ds_cstr(&actions), >> +                                               &op->nbsp->header_); >>                      } >>                  } >>              } >> @@ -9061,9 +9219,11 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                          ds_clear(&actions); >>                          ds_put_format(&actions, >>                                        "eth.dst = 00:00:00:00:00:00; >> next;"); >> -                       ovn_lflow_add(lflows, peer->od, >> -                                       S_ROUTER_IN_ARP_RESOLVE, 100, >> -                                       ds_cstr(&match), >> ds_cstr(&actions)); >> +                       ovn_lflow_add_with_hint(lflows, peer->od, >> +                                               >> S_ROUTER_IN_ARP_RESOLVE, 100, >> +                                               ds_cstr(&match), >> +                                               ds_cstr(&actions), >> +                                               &op->nbsp->header_); >>                          break; >>                      } >>                  } >> @@ -9104,9 +9264,11 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                           ds_clear(&actions); >>                          ds_put_format(&actions, "eth.dst = %s; >> next;", ea_s); >> -                       ovn_lflow_add(lflows, peer->od, >> -                                       S_ROUTER_IN_ARP_RESOLVE, 100, >> -                                       ds_cstr(&match), >> ds_cstr(&actions)); >> +                       ovn_lflow_add_with_hint(lflows, peer->od, >> +                                               >> S_ROUTER_IN_ARP_RESOLVE, 100, >> +                                               ds_cstr(&match), >> +                                               ds_cstr(&actions), >> +                                               &op->nbsp->header_); >>                          found_vip_network = true; >>                          break; >>                      } >> @@ -9159,8 +9321,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      ds_clear(&actions); >>                      ds_put_format(&actions, "eth.dst = %s; next;", >>                                                >> router_port->lrp_networks.ea_s); >> -                   ovn_lflow_add(lflows, peer->od, >> S_ROUTER_IN_ARP_RESOLVE, >> -                                 100, ds_cstr(&match), >> ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, peer->od, >> +                                           S_ROUTER_IN_ARP_RESOLVE, >> 100, >> +                                           ds_cstr(&match), >> ds_cstr(&actions), >> +                                           &op->nbsp->header_); >>                  } >>                   if (router_port->lrp_networks.n_ipv6_addrs) { >> @@ -9172,8 +9336,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      ds_clear(&actions); >>                      ds_put_format(&actions, "eth.dst = %s; next;", >>                                    router_port->lrp_networks.ea_s); >> -                   ovn_lflow_add(lflows, peer->od, >> S_ROUTER_IN_ARP_RESOLVE, >> -                                 100, ds_cstr(&match), >> ds_cstr(&actions)); >> +                   ovn_lflow_add_with_hint(lflows, peer->od, >> +                                           S_ROUTER_IN_ARP_RESOLVE, >> 100, >> +                                           ds_cstr(&match), >> ds_cstr(&actions), >> +                                           &op->nbsp->header_); >>                  } >>              } >>          } >> @@ -9234,8 +9400,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>              ds_put_format(&actions, >>                            REGBIT_PKT_LARGER" = check_pkt_larger(%d);" >>                            " next;", gw_mtu); >> -           ovn_lflow_add(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 50, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_CHK_PKT_LEN, 50, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &od->l3dgw_port->nbrp->header_); >>               for (size_t i = 0; i < od->nbr->n_ports; i++) { >>                  struct ovn_port *rp = ovn_port_find(ports, >> @@ -9266,8 +9433,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                      rp->lrp_networks.ea_s, >>                      rp->lrp_networks.ipv4_addrs[0].addr_s, >>                      gw_mtu - 18); >> -               ovn_lflow_add(lflows, od, S_ROUTER_IN_LARGER_PKTS, 50, >> -                             ds_cstr(&match), ds_cstr(&actions)); >> +               ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_LARGER_PKTS, >> +                                       50, ds_cstr(&match), >> ds_cstr(&actions), >> +                                       &rp->nbrp->header_); >>              } >>          } >>      } >> @@ -9284,8 +9452,15 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>              continue; >>          } >>          if (od->l3dgw_port && od->l3redirect_port) { >> -           ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 300, >> -                         REGBIT_DISTRIBUTED_NAT" == 1", "next;"); >> +           const struct ovsdb_idl_row *stage_hint = NULL; >> + >> +           if (od->l3dgw_port->nbrp) { >> +               stage_hint = &od->l3dgw_port->nbrp->header_; >> +           } >> + >> +           ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_GW_REDIRECT, 300, >> +                                   REGBIT_DISTRIBUTED_NAT" == 1", >> "next;", >> +                                   stage_hint); >>               /* For traffic with outport == l3dgw_port, if the >>               * packet did not match any higher priority redirect >> @@ -9297,8 +9472,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>              ds_clear(&actions); >>              ds_put_format(&actions, "outport = %s; next;", >>                            od->l3redirect_port->json_key); >> -           ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_GW_REDIRECT, 50, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   stage_hint); >>               /* If the Ethernet destination has not been resolved, >>               * redirect to the central instance of the l3dgw_port. >> @@ -9307,8 +9483,9 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>               * table, before being redirected to the central instance. >>               */ >>              ds_put_format(&match, " && eth.dst == 00:00:00:00:00:00"); >> -           ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 150, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> +           ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_GW_REDIRECT, 150, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   stage_hint); >>          } >>           /* Packets are allowed by default. */ >> @@ -9357,8 +9534,10 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>                            "output; " >>                            "};", ETH_ADDR_ARGS(eth_dst), sn_addr_s, >>                            route->nexthop); >> -           ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, >> -                         ds_cstr(&match), ds_cstr(&actions)); >> + >> +           ovn_lflow_add_with_hint(lflows, od, >> S_ROUTER_IN_ARP_REQUEST, 200, >> +                                   ds_cstr(&match), ds_cstr(&actions), >> +                                   &route->header_); >>          } >>           ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, >> @@ -9416,7 +9595,7 @@ build_lrouter_flows(struct hmap *datapaths, >> struct hmap *ports, >>              ds_put_format(&actions, "eth.src = %s; output;", >>                            op->lrp_networks.ea_s); >>              ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 110, >> -                       ds_cstr(&match), ds_cstr(&actions)); >> +                         ds_cstr(&match), ds_cstr(&actions)); >>          } >>           ds_clear(&match); >> diff --git a/utilities/ovn-detrace.in b/utilities/ovn-detrace.in >> index 3bfb720..e9c3736 100755 >> --- a/utilities/ovn-detrace.in >> +++ b/utilities/ovn-detrace.in >> @@ -135,9 +135,74 @@ class CookieHandlerByUUUID(CookieHandler): >>          cookie = cookie.zfill(8) >>          return self._db.find_rows_by_partial_uuid(self._table, cookie) >>  +class ACLHintHandler(CookieHandlerByUUUID): >> +   def __init__(self, ovnnb_db): >> +       super(ACLHintHandler, self).__init__(ovnnb_db, 'ACL') >> + >> +   def print_record(self, acl): >> +       output = 'ACL: %s, priority=%s, ' \ >> +                'match=(%s), %s' % (acl.direction, >> +                                    acl.priority, >> +                                    acl.match.strip('"'), >> +                                    acl.action) >> +       if acl.log: >> +           output += ' (log)' >> +       print_h(output) >> + >> +class LSPHintHandler(CookieHandlerByUUUID): >> +   def __init__(self, ovnnb_db): >> +       super(LSPHintHandler, self).__init__(ovnnb_db, >> 'Logical_Switch_Port') >> + >> +   def print_record(self, lsp): >> +       print_h('Logical Switch Port: %s type %s (addresses %s, >> dynamic addresses %s, security %s' % ( >> +                   lsp.name, lsp.type, lsp.addresses, >> lsp.dynamic_addresses, >> +                   lsp.port_security)) >> + >> +class LRPHintHandler(CookieHandlerByUUUID): >> +   def __init__(self, ovnnb_db): >> +       super(LRPHintHandler, self).__init__(ovnnb_db, >> 'Logical_Router_Port') >> + >> +   def print_record(self, lrp): >> +       print_h('Logical Router Port: %s mac %s networks %s >> ipv6_ra_configs %s' % ( >> +                   lrp.name, lrp.mac, lrp.networks, >> lrp.ipv6_ra_configs)) >> + >> +class LoadBalancerHintHandler(CookieHandlerByUUUID): >> +   def __init__(self, ovnnb_db): >> +       super(LoadBalancerHintHandler, self).__init__(ovnnb_db, >> 'Load_Balancer') >> + >> +   def print_record(self, lb): >> +       print_h('Load Balancer: %s protocol %s vips %s >> ip_port_mappings %s' % ( >> +                   lb.name, lb.protocol, lb.vips, lb.ip_port_mappings)) >> + >> +class NATHintHandler(CookieHandlerByUUUID): >> +   def __init__(self, ovnnb_db): >> +       super(NATHintHandler, self).__init__(ovnnb_db, 'NAT') >> + >> +   def print_record(self, nat): >> +       print_h('NAT: external IP %s external_mac %s logical_ip %s >> logical_port %s type %s' % ( >> +                   nat.external_ip, nat.external_mac, nat.logical_ip, >> +                   nat.logical_port, nat.type)) >> + >> +class StaticRouteHintHandler(CookieHandlerByUUUID): >> +   def __init__(self, ovnnb_db): >> +       super(StaticRouteHintHandler, self).__init__(ovnnb_db, >> +                                                    >> 'Logical_Router_Static_Route') >> + >> +   def print_record(self, route): >> +       print_h('Route: %s via %s (port %s), policy=%s' % ( >> +                   route.ip_prefix, route.nexthop, route.output_port, >> +                   route.policy)) >> + >>  class LogicalFlowHandler(CookieHandlerByUUUID): >> -   def __init__(self, ovnsb_db): >> +   def __init__(self, ovnnb_db, ovnsb_db): >>          super(LogicalFlowHandler, self).__init__(ovnsb_db, >> 'Logical_Flow') >> +       self._hint_handlers = [ >> +           ACLHintHandler(ovnnb_db), >> +           LSPHintHandler(ovnnb_db), >> +           LRPHintHandler(ovnnb_db), >> +           LoadBalancerHintHandler(ovnnb_db), >> +           NATHintHandler(ovnnb_db) >> +       ] >>       def print_record(self, lflow): >>          print_p('Logical datapath: %s [%s]' % >> @@ -151,24 +216,14 @@ class LogicalFlowHandler(CookieHandlerByUUUID): >>       def print_hint(self, lflow, ovnnb_db): >>          external_ids = lflow.external_ids >> -       if external_ids.get('stage-name') in ['ls_in_acl', >> -                                             'ls_out_acl']: >> -           acl_hint = external_ids.get('stage-hint') >> -           if not acl_hint: >> -               return >> -           for i, acl in enumerate( >> -                   ovnnb_db.find_rows_by_partial_uuid('ACL', >> acl_hint)): >> +       hint = external_ids.get('stage-hint') >> +       if not hint: >> +           return >> +       for handler in self._hint_handlers: >> +           for i, record in enumerate(handler.get_records(hint)): >>                  if i > 0: >> -                   print_h('[Duplicate uuid ACL hint]') >> - >> -               output = 'ACL: %s, priority=%s, ' \ >> -                       'match=(%s), %s' % (acl.direction, >> -                                           acl.priority, >> -                                           acl.match.strip('"'), >> -                                           acl.action) >> -               if acl.log: >> -                   output += ' (log)' >> -               print_h(output) >> +                   print_h('[Duplicate uuid hint]') >> +               handler.print_record(record) >>   class PortBindingHandler(CookieHandlerByUUUID): >>      def __init__(self, ovnsb_db): >> @@ -283,7 +338,7 @@ def main(): >>      ovsdb_ovnnb = OVSDB(ovnnb_db, 'OVN_Northbound') >>       cookie_handlers = [ >> -       LogicalFlowHandler(ovsdb_ovnsb), >> +       LogicalFlowHandler(ovsdb_ovnnb, ovsdb_ovnsb), >>          PortBindingHandler(ovsdb_ovnsb), >>          MacBindingHandler(ovsdb_ovnsb), >>          MulticastGroupHandler(ovsdb_ovnsb), >> >
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index b6dc809..20b8429 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -3714,6 +3714,15 @@ ovn_lflow_hash(const struct ovn_lflow *lflow) lflow->actions); } +static char * +ovn_lflow_hint(const struct ovsdb_idl_row *row) +{ + if (!row) { + return NULL; + } + return xasprintf("%08x", row->uuid.parts[0]); +} + static bool ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b) { @@ -3744,14 +3753,14 @@ static void ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, enum ovn_stage stage, uint16_t priority, const char *match, const char *actions, - const char *stage_hint, const char *where) + const struct ovsdb_idl_row *stage_hint, const char *where) { ovs_assert(ovn_stage_to_datapath_type(stage) == ovn_datapath_get_type(od)); struct ovn_lflow *lflow = xmalloc(sizeof *lflow); ovn_lflow_init(lflow, od, stage, priority, xstrdup(match), xstrdup(actions), - nullable_xstrdup(stage_hint), where); + ovn_lflow_hint(stage_hint), where); hmap_insert(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow)); } @@ -3902,7 +3911,8 @@ build_port_security_ipv6_flow( * - Priority 80 flow to drop ARP and IPv6 ND packets. */ static void -build_port_security_nd(struct ovn_port *op, struct hmap *lflows) +build_port_security_nd(struct ovn_port *op, struct hmap *lflows, + const struct ovsdb_idl_row *stage_hint) { struct ds match = DS_EMPTY_INITIALIZER; @@ -3938,8 +3948,8 @@ build_port_security_nd(struct ovn_port *op, struct hmap *lflows) ds_chomp(&match, ','); ds_put_cstr(&match, "}"); } - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, + 90, ds_cstr(&match), "next;", stage_hint); } if (ps->n_ipv6_addrs || no_ip) { @@ -3948,15 +3958,15 @@ build_port_security_nd(struct ovn_port *op, struct hmap *lflows) op->json_key, ps->ea_s); build_port_security_ipv6_nd_flow(&match, ps->ea, ps->ipv6_addrs, ps->n_ipv6_addrs); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, + 90, ds_cstr(&match), "next;", stage_hint); } } ds_clear(&match); ds_put_format(&match, "inport == %s && (arp || nd)", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 80, - ds_cstr(&match), "drop;"); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 80, + ds_cstr(&match), "drop;", stage_hint); ds_destroy(&match); } @@ -3977,7 +3987,8 @@ build_port_security_nd(struct ovn_port *op, struct hmap *lflows) */ static void build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, - struct hmap *lflows) + struct hmap *lflows, + const struct ovsdb_idl_row *stage_hint) { char *port_direction; enum ovn_stage stage; @@ -4007,8 +4018,9 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, " && ip4.dst == 255.255.255.255" " && udp.src == 68 && udp.dst == 67", op->json_key, ps->ea_s); - ovn_lflow_add(lflows, op->od, stage, 90, - ds_cstr(&dhcp_match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, stage, 90, + ds_cstr(&dhcp_match), "next;", + stage_hint); ds_destroy(&dhcp_match); ds_put_format(&match, "inport == %s && eth.src == %s" " && ip4.src == {", op->json_key, @@ -4047,7 +4059,9 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, ds_chomp(&match, ' '); ds_chomp(&match, ','); ds_put_cstr(&match, "}"); - ovn_lflow_add(lflows, op->od, stage, 90, ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, stage, 90, + ds_cstr(&match), "next;", + stage_hint); ds_destroy(&match); } @@ -4063,8 +4077,9 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, " && ip6.dst == ff02::/16" " && icmp6.type == {131, 135, 143}", op->json_key, ps->ea_s); - ovn_lflow_add(lflows, op->od, stage, 90, - ds_cstr(&dad_match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, stage, 90, + ds_cstr(&dad_match), "next;", + stage_hint); ds_destroy(&dad_match); } ds_put_format(&match, "%s == %s && %s == %s", @@ -4072,8 +4087,9 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, pipeline == P_IN ? "eth.src" : "eth.dst", ps->ea_s); build_port_security_ipv6_flow(pipeline, &match, ps->ea, ps->ipv6_addrs, ps->n_ipv6_addrs); - ovn_lflow_add(lflows, op->od, stage, 90, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, stage, 90, + ds_cstr(&match), "next;", + stage_hint); ds_destroy(&match); } @@ -4081,7 +4097,8 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, port_direction, op->json_key, pipeline == P_IN ? "eth.src" : "eth.dst", ps->ea_s); - ovn_lflow_add(lflows, op->od, stage, 80, match, "drop;"); + ovn_lflow_add_with_hint(lflows, op->od, stage, 80, match, "drop;", + stage_hint); free(match); } @@ -4371,12 +4388,13 @@ build_lswitch_input_port_sec(struct hmap *ports, struct hmap *datapaths, ds_put_format(&actions, "set_queue(%s); ", queue_id); } ds_put_cstr(&actions, "next;"); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50, + ds_cstr(&match), ds_cstr(&actions), + &op->nbsp->header_); if (op->nbsp->n_port_security) { - build_port_security_ip(P_IN, op, lflows); - build_port_security_nd(op, lflows); + build_port_security_ip(P_IN, op, lflows, &op->nbsp->header_); + build_port_security_nd(op, lflows, &op->nbsp->header_); } } @@ -4436,15 +4454,17 @@ build_lswitch_output_port_sec(struct hmap *ports, struct hmap *datapaths, } } ds_put_cstr(&actions, "output;"); - ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, + 50, ds_cstr(&match), ds_cstr(&actions), + &op->nbsp->header_); } else { - ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 150, - ds_cstr(&match), "drop;"); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, + 150, ds_cstr(&match), "drop;", + &op->nbsp->header_); } if (op->nbsp->n_port_security) { - build_port_security_ip(P_OUT, op, lflows); + build_port_security_ip(P_OUT, op, lflows, &op->nbsp->header_); } } @@ -4499,10 +4519,12 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) ds_put_format(&match_in, "ip && inport == %s", op->json_key); ds_put_format(&match_out, "ip && outport == %s", op->json_key); - ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, - ds_cstr(&match_in), "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, - ds_cstr(&match_out), "next;"); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_ACL, 110, + ds_cstr(&match_in), "next;", + &op->nbsp->header_); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, + ds_cstr(&match_out), "next;", + &op->nbsp->header_); ds_destroy(&match_in); ds_destroy(&match_out); @@ -4515,10 +4537,12 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) od->localnet_port->json_key); ds_put_format(&match_out, "ip && outport == %s", od->localnet_port->json_key); - ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, - ds_cstr(&match_in), "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, - ds_cstr(&match_out), "next;"); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_ACL, 110, + ds_cstr(&match_in), "next;", + &od->localnet_port->nbsp->header_); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, + ds_cstr(&match_out), "next;", + &od->localnet_port->nbsp->header_); ds_destroy(&match_in); ds_destroy(&match_out); @@ -4596,7 +4620,8 @@ static void build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, struct smap_node *node, char *ip_address, struct nbrec_load_balancer *lb, uint16_t port, - int addr_family, int pl, struct shash *meter_groups) + int addr_family, int pl, struct shash *meter_groups, + const struct ovsdb_idl_row *stage_hint) { if (!controller_event_en || node->value[0]) { return; @@ -4627,7 +4652,8 @@ build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, event_to_string(OVN_EVENT_EMPTY_LB_BACKENDS), meter, node->key, lb->protocol, UUID_ARGS(&lb->header_.uuid)); - ovn_lflow_add(lflows, od, pl, 130, ds_cstr(&match), action); + ovn_lflow_add_with_hint(lflows, od, pl, 130, ds_cstr(&match), action, + stage_hint); ds_destroy(&match); free(action); } @@ -4680,7 +4706,7 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows, build_empty_lb_event_flow(od, lflows, node, ip_address, lb, port, addr_family, S_SWITCH_IN_PRE_LB, - meter_groups); + meter_groups, &lb->header_); free(ip_address); @@ -4772,7 +4798,8 @@ 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 *extra_match, struct ds *extra_actions, + const struct ovsdb_idl_row *stage_hint) { struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; @@ -4788,8 +4815,9 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, "eth.dst <-> eth.src; ip4.dst <-> ip4.src; " "tcp_reset { outport <-> inport; %s };", ingress ? "output;" : "next(pipeline=ingress,table=0);"); - ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET + 10, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET + 10, + ds_cstr(&match), ds_cstr(&actions), stage_hint); ds_clear(&match); ds_clear(&actions); build_acl_log(&actions, acl); @@ -4801,8 +4829,9 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, "eth.dst <-> eth.src; ip6.dst <-> ip6.src; " "tcp_reset { outport <-> inport; %s };", ingress ? "output;" : "next(pipeline=ingress,table=0);"); - ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET + 10, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET + 10, + ds_cstr(&match), ds_cstr(&actions), stage_hint); /* IP traffic */ ds_clear(&match); @@ -4819,8 +4848,9 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, "eth.dst <-> eth.src; ip4.dst <-> ip4.src; " "icmp4 { outport <-> inport; %s };", ingress ? "output;" : "next(pipeline=ingress,table=0);"); - ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET, + ds_cstr(&match), ds_cstr(&actions), stage_hint); ds_clear(&match); ds_clear(&actions); build_acl_log(&actions, acl); @@ -4835,8 +4865,9 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, "eth.dst <-> eth.src; ip6.dst <-> ip6.src; " "outport <-> inport; %s };", ingress ? "output;" : "next(pipeline=ingress,table=0);"); - ovn_lflow_add(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET, + ds_cstr(&match), ds_cstr(&actions), stage_hint); ds_destroy(&match); ds_destroy(&actions); @@ -4849,7 +4880,6 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, bool ingress = !strcmp(acl->direction, "from-lport") ? true :false; enum ovn_stage stage = ingress ? S_SWITCH_IN_ACL : S_SWITCH_OUT_ACL; - char *stage_hint = xasprintf("%08x", acl->header_.uuid.parts[0]); if (!strcmp(acl->action, "allow") || !strcmp(acl->action, "allow-related")) { /* If there are any stateful flows, we must even commit "allow" @@ -4864,7 +4894,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, ovn_lflow_add_with_hint(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, acl->match, ds_cstr(&actions), - stage_hint); + &acl->header_); ds_destroy(&actions); } else { struct ds match = DS_EMPTY_INITIALIZER; @@ -4893,7 +4923,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, acl->priority + OVN_ACL_PRI_OFFSET, ds_cstr(&match), ds_cstr(&actions), - stage_hint); + &acl->header_); /* Match on traffic in the request direction for an established * connection tracking entry that has not been marked for @@ -4913,7 +4943,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, ovn_lflow_add_with_hint(lflows, od, stage, acl->priority + OVN_ACL_PRI_OFFSET, ds_cstr(&match), ds_cstr(&actions), - stage_hint); + &acl->header_); ds_destroy(&match); ds_destroy(&actions); @@ -4935,14 +4965,15 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, " || (ct.est && ct_label.blocked == 1))"); if (!strcmp(acl->action, "reject")) { build_reject_acl_rules(od, lflows, stage, acl, &match, - &actions); + &actions, &acl->header_); } else { ds_put_format(&match, " && (%s)", acl->match); build_acl_log(&actions, acl); ds_put_cstr(&actions, "/* drop */"); - ovn_lflow_add(lflows, od, stage, - acl->priority + OVN_ACL_PRI_OFFSET, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET, + ds_cstr(&match), ds_cstr(&actions), + &acl->header_); } /* For an existing connection without ct_label set, we've * encountered a policy change. ACLs previously allowed @@ -4961,14 +4992,15 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, ds_put_cstr(&actions, "ct_commit(ct_label=1/1); "); if (!strcmp(acl->action, "reject")) { build_reject_acl_rules(od, lflows, stage, acl, &match, - &actions); + &actions, &acl->header_); } else { ds_put_format(&match, " && (%s)", acl->match); build_acl_log(&actions, acl); ds_put_cstr(&actions, "/* drop */"); - ovn_lflow_add(lflows, od, stage, - acl->priority + OVN_ACL_PRI_OFFSET, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET, + ds_cstr(&match), ds_cstr(&actions), + &acl->header_); } } else { /* There are no stateful ACLs in use on this datapath, @@ -4976,19 +5008,19 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, * logical flow action in all cases. */ if (!strcmp(acl->action, "reject")) { build_reject_acl_rules(od, lflows, stage, acl, &match, - &actions); + &actions, &acl->header_); } else { build_acl_log(&actions, acl); ds_put_cstr(&actions, "/* drop */"); - ovn_lflow_add(lflows, od, stage, - acl->priority + OVN_ACL_PRI_OFFSET, - acl->match, ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET, + acl->match, ds_cstr(&actions), + &acl->header_); } } ds_destroy(&match); ds_destroy(&actions); } - free(stage_hint); } static struct ovn_port_group * @@ -5191,9 +5223,9 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, "&& ip4.src == %s && udp && udp.src == 67 " "&& udp.dst == 68", od->nbs->ports[i]->name, server_mac, server_id); - ovn_lflow_add( + ovn_lflow_add_with_hint( lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match), - actions); + actions, &od->nbs->ports[i]->dhcpv4_options->header_); ds_destroy(&match); } } @@ -5218,9 +5250,9 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, "&& ip6.src == %s && udp && udp.src == 547 " "&& udp.dst == 546", od->nbs->ports[i]->name, server_mac, server_ip); - ovn_lflow_add( + ovn_lflow_add_with_hint( lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match), - actions); + actions, &od->nbs->ports[i]->dhcpv6_options->header_); ds_destroy(&match); } } @@ -5257,9 +5289,10 @@ build_qos(struct ovn_datapath *od, struct hmap *lflows) { ds_put_format(&dscp_action, "ip.dscp = %"PRId64"; next;", qos->value_action[j]); - ovn_lflow_add(lflows, od, stage, - qos->priority, - qos->match, ds_cstr(&dscp_action)); + ovn_lflow_add_with_hint(lflows, od, stage, + qos->priority, + qos->match, ds_cstr(&dscp_action), + &qos->header_); ds_destroy(&dscp_action); } } @@ -5288,9 +5321,10 @@ build_qos(struct ovn_datapath *od, struct hmap *lflows) { * * We limit the bandwidth of this flow by adding a meter table. */ - ovn_lflow_add(lflows, od, stage, - qos->priority, - qos->match, ds_cstr(&meter_action)); + ovn_lflow_add_with_hint(lflows, od, stage, + qos->priority, + qos->match, ds_cstr(&meter_action), + &qos->header_); ds_destroy(&meter_action); } } @@ -5405,11 +5439,13 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows, struct hmap *lbs) ds_put_format(&match, " && tcp.dst == %d", lb_vip->vip_port); } - ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, - 120, ds_cstr(&match), ds_cstr(&action)); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_STATEFUL, 120, + ds_cstr(&match), ds_cstr(&action), + &lb->nlb->header_); } else { - ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, - 110, ds_cstr(&match), ds_cstr(&action)); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_STATEFUL, 110, + ds_cstr(&match), ds_cstr(&action), + &lb->nlb->header_); } ds_destroy(&match); @@ -5574,7 +5610,8 @@ build_lswitch_rport_arp_req_flow_for_ip(struct sset *ips, struct ovn_port *patch_op, struct ovn_datapath *od, uint32_t priority, - struct hmap *lflows) + struct hmap *lflows, + const struct ovsdb_idl_row *stage_hint) { struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; @@ -5605,8 +5642,8 @@ build_lswitch_rport_arp_req_flow_for_ip(struct sset *ips, * in the broadcast domain. */ ds_put_format(&actions, "outport = %s; output;", patch_op->json_key); - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, priority, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, priority, + ds_cstr(&match), ds_cstr(&actions), stage_hint); ds_destroy(&match); ds_destroy(&actions); @@ -5623,7 +5660,8 @@ static void build_lswitch_rport_arp_req_flows(struct ovn_port *op, struct ovn_datapath *sw_od, struct ovn_port *sw_op, - struct hmap *lflows) + struct hmap *lflows, + const struct ovsdb_idl_row *stage_hint) { if (!op || !op->nbrp) { return; @@ -5677,11 +5715,13 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, if (!sset_is_empty(&all_ips_v4)) { build_lswitch_rport_arp_req_flow_for_ip(&all_ips_v4, AF_INET, sw_op, - sw_od, 75, lflows); + sw_od, 75, lflows, + stage_hint); } if (!sset_is_empty(&all_ips_v6)) { build_lswitch_rport_arp_req_flow_for_ip(&all_ips_v6, AF_INET6, sw_op, - sw_od, 75, lflows); + sw_od, 75, lflows, + stage_hint); } sset_destroy(&all_ips_v4); @@ -5752,8 +5792,9 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, (!strcmp(op->nbsp->type, "vtep"))) { ds_clear(&match); ds_put_format(&match, "inport == %s", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, + 100, ds_cstr(&match), "next;", + &op->nbsp->header_); } } @@ -5806,8 +5847,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, "bind_vport(%s, inport); " "next;", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 100, + ds_cstr(&match), ds_cstr(&actions), + &vp->nbsp->header_); } free(tokstr); @@ -5846,8 +5889,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, "output;", op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ipv4_addrs[j].addr_s); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(&match), + ds_cstr(&actions), + &op->nbsp->header_); /* Do not reply to an ARP request from the port that owns * the address (otherwise a DHCP client that ARPs to check @@ -5862,8 +5908,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, * network is not working as configured, so dropping the * request would frustrate that intent.) */ ds_put_format(&match, " && inport == %s", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 100, + ds_cstr(&match), "next;", + &op->nbsp->header_); } /* For ND solicitations, we need to listen for both the @@ -5894,14 +5942,19 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, op->lsp_addrs[i].ipv6_addrs[j].addr_s, op->lsp_addrs[i].ipv6_addrs[j].addr_s, op->lsp_addrs[i].ea_s); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(&match), + ds_cstr(&actions), + &op->nbsp->header_); /* Do not reply to a solicitation from the port that owns * the address (otherwise DAD detection will fail). */ ds_put_format(&match, " && inport == %s", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 100, + ds_cstr(&match), "next;", + &op->nbsp->header_); } } } @@ -5949,9 +6002,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, "output;", svc_monitor_mac, svc_monitor_mac, lb->vips[i].backends[j].svc_mon_src_ip); - ovn_lflow_add(lflows, lb->vips[i].backends[j].op->od, - S_SWITCH_IN_ARP_ND_RSP, 110, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, + lb->vips[i].backends[j].op->od, + S_SWITCH_IN_ARP_ND_RSP, 110, + ds_cstr(&match), ds_cstr(&actions), + &lb->nlb->header_); } } } @@ -5985,6 +6040,14 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, } for (size_t i = 0; i < op->n_lsp_addrs; i++) { + struct ovsdb_idl_row *stage_hint; + + if (op->nbsp->dhcpv4_options) { + stage_hint = &op->nbsp->dhcpv4_options->header_; + } else { + stage_hint = NULL; + } + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) { struct ds options_action = DS_EMPTY_INITIALIZER; struct ds response_action = DS_EMPTY_INITIALIZER; @@ -6006,9 +6069,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, op->json_key); } - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_OPTIONS, - 100, ds_cstr(&match), - ds_cstr(&options_action)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_DHCP_OPTIONS, 100, + ds_cstr(&match), + ds_cstr(&options_action), + stage_hint); ds_clear(&match); /* Allow ip4.src = OFFER_IP and * ip4.dst = {SERVER_IP, 255.255.255.255} for the below @@ -6030,9 +6095,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, op->json_key); } - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_OPTIONS, - 100, ds_cstr(&match), - ds_cstr(&options_action)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_DHCP_OPTIONS, 100, + ds_cstr(&match), + ds_cstr(&options_action), + stage_hint); ds_clear(&match); /* If REGBIT_DHCP_OPTS_RESULT is set, it means the @@ -6050,9 +6117,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, op->json_key); } - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, - 100, ds_cstr(&match), - ds_cstr(&response_action)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_DHCP_RESPONSE, 100, + ds_cstr(&match), + ds_cstr(&response_action), + stage_hint); ds_destroy(&options_action); ds_destroy(&response_action); ds_destroy(&ipv4_addr_match); @@ -6060,6 +6129,12 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, } } + if (op->nbsp->dhcpv6_options) { + stage_hint = &op->nbsp->dhcpv6_options->header_; + } else { + stage_hint = NULL; + } + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) { struct ds options_action = DS_EMPTY_INITIALIZER; struct ds response_action = DS_EMPTY_INITIALIZER; @@ -6080,14 +6155,20 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, op->json_key); } - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_OPTIONS, 100, - ds_cstr(&match), ds_cstr(&options_action)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_DHCP_OPTIONS, 100, + ds_cstr(&match), + ds_cstr(&options_action), + stage_hint); /* If REGBIT_DHCP_OPTS_RESULT is set to 1, it means the * put_dhcpv6_opts action is successful */ ds_put_cstr(&match, " && "REGBIT_DHCP_OPTS_RESULT); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, 100, - ds_cstr(&match), ds_cstr(&response_action)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_DHCP_RESPONSE, 100, + ds_cstr(&match), + ds_cstr(&response_action), + stage_hint); ds_destroy(&options_action); ds_destroy(&response_action); break; @@ -6172,9 +6253,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, op->od->localnet_port->json_key, op->lsp_addrs[i].ea_s, op->json_key, rp->lsp_addrs[k].ipv4_addrs[l].addr_s); - ovn_lflow_add(lflows, op->od, - S_SWITCH_IN_EXTERNAL_PORT, 100, - ds_cstr(&match), "drop;"); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_EXTERNAL_PORT, + 100, ds_cstr(&match), "drop;", + &op->nbsp->header_); } for (size_t l = 0; l < rp->lsp_addrs[k].n_ipv6_addrs; l++) { @@ -6189,9 +6271,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, rp->lsp_addrs[k].ipv6_addrs[l].addr_s, rp->lsp_addrs[k].ipv6_addrs[l].sn_addr_s, rp->lsp_addrs[k].ipv6_addrs[l].addr_s); - ovn_lflow_add(lflows, op->od, - S_SWITCH_IN_EXTERNAL_PORT, 100, - ds_cstr(&match), "drop;"); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_EXTERNAL_PORT, 100, + ds_cstr(&match), "drop;", + &op->nbsp->header_); } } } @@ -6326,7 +6409,8 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, * requests only to the router port that owns the IP address. */ if (!strcmp(op->nbsp->type, "router")) { - build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lflows); + build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lflows, + &op->nbsp->header_); } for (size_t i = 0; i < op->nbsp->n_addresses; i++) { @@ -6342,8 +6426,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "outport = %s; output;", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_L2_LKUP, + 50, ds_cstr(&match), + ds_cstr(&actions), + &op->nbsp->header_); } else if (!strcmp(op->nbsp->addresses[i], "unknown")) { if (lsp_is_enabled(op->nbsp)) { ovn_multicast_add(mcgroups, &mc_unknown, op); @@ -6361,8 +6447,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "outport = %s; output;", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_L2_LKUP, + 50, ds_cstr(&match), + ds_cstr(&actions), + &op->nbsp->header_); } else if (!strcmp(op->nbsp->addresses[i], "router")) { if (!op->peer || !op->peer->nbrp || !ovs_scan(op->peer->nbrp->mac, @@ -6403,8 +6491,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "outport = %s; output;", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_L2_LKUP, 50, + ds_cstr(&match), ds_cstr(&actions), + &op->nbsp->header_); /* Add ethernet addresses specified in NAT rules on * distributed logical routers. */ @@ -6426,9 +6516,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "outport = %s; output;", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, - 50, ds_cstr(&match), - ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_L2_LKUP, 50, + ds_cstr(&match), + ds_cstr(&actions), + &op->nbsp->header_); } } } @@ -6544,7 +6636,8 @@ get_outport_for_routing_policy_nexthop(struct ovn_datapath *od, static void build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od, struct hmap *ports, - const struct nbrec_logical_router_policy *rule) + const struct nbrec_logical_router_policy *rule, + const struct ovsdb_idl_row *stage_hint) { struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; @@ -6584,8 +6677,9 @@ build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od, ds_put_cstr(&actions, "next;"); } ds_put_format(&match, "%s", rule->match); - ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, rule->priority, - ds_cstr(&match), ds_cstr(&actions)); + + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY, rule->priority, + ds_cstr(&match), ds_cstr(&actions), stage_hint); ds_destroy(&match); ds_destroy(&actions); } @@ -6654,8 +6748,9 @@ add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op) REGBIT_NAT_REDIRECT" = 0; next;", op->od->l3dgw_port->json_key, nat->external_mac); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, + ds_cstr(&match), ds_cstr(&actions), + &nat->header_); ds_clear(&match); ds_clear(&actions); @@ -6702,8 +6797,9 @@ add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op) family == AF_INET ? "4" : "6", family == AF_INET ? "" : "xx", nat->external_ip); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_ROUTING, + 400, ds_cstr(&match), ds_cstr(&actions), + &nat2->header_); ds_clear(&match); ds_clear(&actions); } @@ -6715,7 +6811,8 @@ add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op) static void add_route(struct hmap *lflows, const struct ovn_port *op, const char *lrp_addr_s, const char *network_s, int plen, - const char *gateway, const char *policy) + const char *gateway, const char *policy, + const struct ovsdb_idl_row *stage_hint) { bool is_ipv4 = strchr(network_s, '.') ? true : false; struct ds match = DS_EMPTY_INITIALIZER; @@ -6762,8 +6859,8 @@ add_route(struct hmap *lflows, const struct ovn_port *op, /* The priority here is calculated to implement longest-prefix-match * routing. */ - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, priority, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_ROUTING, priority, + ds_cstr(&match), ds_cstr(&actions), stage_hint); ds_destroy(&match); ds_destroy(&actions); } @@ -6771,7 +6868,8 @@ add_route(struct hmap *lflows, const struct ovn_port *op, static void build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, struct hmap *ports, - const struct nbrec_logical_router_static_route *route) + const struct nbrec_logical_router_static_route *route, + const struct ovsdb_idl_row *stage_hint) { ovs_be32 nexthop; const char *lrp_addr_s = NULL; @@ -6894,7 +6992,7 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, char *policy = route->policy ? route->policy : "dst-ip"; add_route(lflows, out_port, lrp_addr_s, prefix_s, plen, route->nexthop, - policy); + policy, stage_hint); free_prefix_s: free(prefix_s); @@ -6977,35 +7075,38 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, const char *lb_force_snat_ip, struct smap_node *lb_info, bool is_udp, int addr_family, char *ip_addr, uint16_t l4_port, struct nbrec_load_balancer *lb, - struct shash *meter_groups) + struct shash *meter_groups, + const struct ovsdb_idl_row *stage_hint) { char *backend_ips = lb_info->value; build_empty_lb_event_flow(od, lflows, lb_info, ip_addr, lb, l4_port, addr_family, S_ROUTER_IN_DNAT, - meter_groups); + meter_groups, stage_hint); /* A match and actions for new connections. */ char *new_match = xasprintf("ct.new && %s", ds_cstr(match)); if (lb_force_snat_ip) { char *new_actions = xasprintf("flags.force_snat_for_lb = 1; %s", ds_cstr(actions)); - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, new_match, - new_actions); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, + new_match, new_actions, stage_hint); free(new_actions); } else { - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, new_match, - ds_cstr(actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, + new_match, ds_cstr(actions), stage_hint); } /* A match and actions for established connections. */ char *est_match = xasprintf("ct.est && %s", ds_cstr(match)); if (lb_force_snat_ip) { - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, est_match, - "flags.force_snat_for_lb = 1; ct_dnat;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, + est_match, + "flags.force_snat_for_lb = 1; ct_dnat;", + stage_hint); } else { - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, priority, est_match, - "ct_dnat;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, + est_match, "ct_dnat;", stage_hint); } free(new_match); @@ -7068,12 +7169,14 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, "is_chassis_resident(%s)", od->l3dgw_port->json_key, od->l3redirect_port->json_key); if (lb_force_snat_ip) { - ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 120, - ds_cstr(&undnat_match), - "flags.force_snat_for_lb = 1; ct_dnat;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120, + ds_cstr(&undnat_match), + "flags.force_snat_for_lb = 1; ct_dnat;", + stage_hint); } else { - ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 120, - ds_cstr(&undnat_match), "ct_dnat;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120, + ds_cstr(&undnat_match), "ct_dnat;", + stage_hint); } ds_destroy(&undnat_match); @@ -7219,8 +7322,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&match); ds_put_format(&match, "eth.mcast && inport == %s", op->json_key); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, + ds_cstr(&match), "next;", &op->nbrp->header_); ds_clear(&match); ds_put_format(&match, "eth.dst == %s && inport == %s", @@ -7232,8 +7335,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&match, " && is_chassis_resident(%s)", op->od->l3redirect_port->json_key); } - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ADMISSION, 50, + ds_cstr(&match), "next;", &op->nbrp->header_); } /* Logical router ingress table 1: LOOKUP_NEIGHBOR and @@ -7318,10 +7421,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&match, " && is_chassis_resident(%s)", op->od->l3redirect_port->json_key); } - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, - ds_cstr(&match), - REGBIT_LOOKUP_NEIGHBOR_RESULT" = " - "lookup_arp(inport, arp.spa, arp.sha); next;"); + ovn_lflow_add_with_hint(lflows, op->od, + S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, + ds_cstr(&match), + REGBIT_LOOKUP_NEIGHBOR_RESULT" = " + "lookup_arp(inport, arp.spa, arp.sha); " + "next;", &op->nbrp->header_); } } @@ -7391,8 +7496,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_cstr(&match, "ip4.src == "); op_put_v4_networks(&match, op, true); ds_put_cstr(&match, " && "REGBIT_EGRESS_LOOPBACK" == 0"); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, - ds_cstr(&match), "drop;"); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, + ds_cstr(&match), "drop;", + &op->nbrp->header_); /* ICMP echo reply. These flows reply to ICMP echo requests * received for the router's IP address. Since packets only @@ -7411,8 +7517,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "icmp4.type = 0; " "flags.loopback = 1; " "next; "); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } /* ICMP time exceeded */ @@ -7433,8 +7540,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "ip.ttl = 255; " "next; };", op->lrp_networks.ipv4_addrs[i].addr_s); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } /* ARP reply. These flows reply to ARP requests for the router's own @@ -7495,8 +7603,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, op->lrp_networks.ea_s, op->lrp_networks.ipv4_addrs[i].addr_s, op->json_key); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } /* A set to hold all load-balancer vips that need ARP responses. */ @@ -7740,8 +7849,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, IP_ARGS(ip), op->json_key); } - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, - ds_cstr(&match), ds_cstr(&actions)); + + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), ds_cstr(&actions), + &nat->header_); } if (!smap_get(&op->od->nbr->options, "chassis") @@ -7759,8 +7870,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "icmp4.type = 3; " "icmp4.code = 3; " "next; };"; - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, - ds_cstr(&match), action); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(&match), action, + &op->nbrp->header_); ds_clear(&match); ds_put_format(&match, @@ -7770,8 +7882,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "eth.dst <-> eth.src; " "ip4.dst <-> ip4.src; " "next; };"; - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, - ds_cstr(&match), action); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(&match), action, + &op->nbrp->header_); ds_clear(&match); ds_put_format(&match, @@ -7784,8 +7897,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "icmp4.type = 3; " "icmp4.code = 2; " "next; };"; - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 70, - ds_cstr(&match), action); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 70, ds_cstr(&match), action, + &op->nbrp->header_); } } @@ -7844,8 +7958,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, if (has_drop_ips) { /* Drop IP traffic to this router. */ - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 60, - ds_cstr(&match), "drop;"); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 60, + ds_cstr(&match), "drop;", + &op->nbrp->header_); } free(snat_ips); @@ -7878,8 +7993,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "icmp6.type = 129; " "flags.loopback = 1; " "next; "); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } /* ND reply. These flows reply to ND solicitations for the @@ -7919,8 +8035,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, op->lrp_networks.ipv6_addrs[i].addr_s, op->lrp_networks.ipv6_addrs[i].addr_s, op->lrp_networks.ea_s); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } /* UDP/TCP port unreachable */ @@ -7935,8 +8052,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "eth.dst <-> eth.src; " "ip6.dst <-> ip6.src; " "next; };"; - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, - ds_cstr(&match), action); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(&match), action, + &op->nbrp->header_); ds_clear(&match); ds_put_format(&match, @@ -7949,8 +8067,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "icmp6.type = 1; " "icmp6.code = 4; " "next; };"; - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, - ds_cstr(&match), action); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(&match), action, + &op->nbrp->header_); ds_clear(&match); ds_put_format(&match, @@ -7963,8 +8082,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "icmp6.type = 1; " "icmp6.code = 3; " "next; };"; - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 70, - ds_cstr(&match), action); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 70, ds_cstr(&match), action, + &op->nbrp->header_); } } @@ -7995,8 +8115,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "icmp6.code = 0; /* TTL exceeded in transit */ " "next; };", op->lrp_networks.ipv6_addrs[i].addr_s); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } } @@ -8135,8 +8256,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_cstr(&actions, "ct_snat;"); } - ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 90, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, + 90, ds_cstr(&match), + ds_cstr(&actions), + &nat->header_); } else { /* Distributed router. */ @@ -8162,8 +8285,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_cstr(&actions, "ct_snat;"); } - ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, + 100, ds_cstr(&match), + ds_cstr(&actions), + &nat->header_); /* Traffic received on other router ports must be * redirected to the central instance of the l3dgw_port @@ -8172,9 +8297,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&match, "ip && ip%s.dst == %s", is_v6 ? "6" : "4", nat->external_ip); - ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 50, - ds_cstr(&match), - REGBIT_NAT_REDIRECT" = 1; next;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, + 50, ds_cstr(&match), + REGBIT_NAT_REDIRECT" = 1; next;", + &nat->header_); } } @@ -8210,8 +8336,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "ct_dnat(%s);", nat->logical_ip); } - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 100, + ds_cstr(&match), ds_cstr(&actions), + &nat->header_); } else { /* Distributed router. */ @@ -8238,8 +8365,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, nat->logical_ip); } - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 100, + ds_cstr(&match), ds_cstr(&actions), + &nat->header_); /* Traffic received on other router ports must be * redirected to the central instance of the l3dgw_port @@ -8248,9 +8376,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&match, "ip && ip%s.dst == %s", is_v6 ? "6" : "4", nat->external_ip); - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, - ds_cstr(&match), - REGBIT_NAT_REDIRECT" = 1; next;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 50, + ds_cstr(&match), + REGBIT_NAT_REDIRECT" = 1; next;", + &nat->header_); } } @@ -8289,8 +8418,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&actions, "ct_dnat;"); } - ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 100, + ds_cstr(&match), ds_cstr(&actions), + &nat->header_); } /* Egress SNAT table: Packets enter the egress pipeline with @@ -8317,9 +8447,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* The priority here is calculated such that the * nat->logical_ip with the longest mask gets a higher * priority. */ - ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, - count_1bits(ntohl(mask)) + 1, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT, + count_1bits(ntohl(mask)) + 1, + ds_cstr(&match), ds_cstr(&actions), + &nat->header_); } else { uint16_t priority = count_1bits(ntohl(mask)) + 1; @@ -8354,9 +8485,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* The priority here is calculated such that the * nat->logical_ip with the longest mask gets a higher * priority. */ - ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, - priority, ds_cstr(&match), - ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_SNAT, + priority, ds_cstr(&match), + ds_cstr(&actions), + &nat->header_); } } @@ -8373,8 +8505,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ETH_ADDR_ARGS(mac), od->l3dgw_port->json_key, nat->logical_port); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 50, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ADMISSION, 50, + ds_cstr(&match), "next;", + &nat->header_); } /* Ingress Gateway Redirect Table: For NAT on a distributed @@ -8387,8 +8520,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, is_v6 ? "6" : "4", nat->logical_ip, od->l3dgw_port->json_key); - ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 100, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, + 100, ds_cstr(&match), "next;", + &nat->header_); } /* Egress Loopback table: For NAT on a distributed router. @@ -8422,16 +8556,21 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "flags = 0; flags.loopback = 1; " REGBIT_EGRESS_LOOPBACK" = 1; " "next(pipeline=ingress, table=0); "); - ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 300, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, + S_ROUTER_OUT_EGR_LOOP, 300, + ds_cstr(&match), + ds_cstr(&actions), + &nat2->header_); ds_clear(&match); ds_put_format(&match, "ip%s.src == %s && ip%s.dst == %s", is_v6 ? "6" : "4", nat2->external_ip, is_v6 ? "6" : "4", nat->external_ip); - ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 200, - ds_cstr(&match), "next;"); + ovn_lflow_add_with_hint(lflows, od, + S_ROUTER_OUT_EGR_LOOP, 200, + ds_cstr(&match), "next;", + &nat2->header_); ds_clear(&match); } } @@ -8451,8 +8590,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, } ds_put_format(&actions, REGBIT_EGRESS_LOOPBACK" = 1; " "next(pipeline=ingress, table=0); };"); - ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_EGR_LOOP, 100, + ds_cstr(&match), ds_cstr(&actions), + &nat->header_); } } @@ -8591,8 +8731,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&match, "ip && ip6.dst == %s", ip_address); } - ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, - 100, ds_cstr(&match), "ct_next;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, + 100, ds_cstr(&match), "ct_next;", + &lb->header_); } /* Higher priority rules are added for load-balancing in DNAT @@ -8633,7 +8774,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, add_router_lb_flow(lflows, od, &match, &actions, prio, lb_force_snat_ip, node, is_udp, addr_family, ip_address, port, lb, - meter_groups); + meter_groups, + &lb->header_); free(ip_address); } @@ -8706,8 +8848,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, if (add_rs_response_flow) { ds_put_cstr(&actions, "); next;"); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS, + 50, ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); ds_clear(&actions); ds_clear(&match); ds_put_format(&match, "inport == %s && ip6.dst == ff02::2 && " @@ -8723,8 +8866,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "outport = inport; flags.loopback = 1; " "output;", op->lrp_networks.ea_s, ip6_str); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ND_RA_RESPONSE, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->od, + S_ROUTER_IN_ND_RA_RESPONSE, 50, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } } @@ -8758,13 +8903,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { add_route(lflows, op, op->lrp_networks.ipv4_addrs[i].addr_s, op->lrp_networks.ipv4_addrs[i].network_s, - op->lrp_networks.ipv4_addrs[i].plen, NULL, NULL); + op->lrp_networks.ipv4_addrs[i].plen, NULL, NULL, + &op->nbrp->header_); } for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { add_route(lflows, op, op->lrp_networks.ipv6_addrs[i].addr_s, op->lrp_networks.ipv6_addrs[i].network_s, - op->lrp_networks.ipv6_addrs[i].plen, NULL, NULL); + op->lrp_networks.ipv6_addrs[i].plen, NULL, NULL, + &op->nbrp->header_); } } @@ -8778,7 +8925,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, const struct nbrec_logical_router_static_route *route; route = od->nbr->static_routes[i]; - build_static_route_flow(lflows, od, ports, route); + build_static_route_flow(lflows, od, ports, route, &route->header_); } } @@ -8849,7 +8996,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, for (int i = 0; i < od->nbr->n_policies; i++) { const struct nbrec_logical_router_policy *rule = od->nbr->policies[i]; - build_routing_policy_flow(lflows, od, ports, rule); + build_routing_policy_flow(lflows, od, ports, rule, &rule->header_); } } @@ -8900,8 +9047,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "eth.dst = %s; next;", op->lrp_networks.ea_s); - ovn_lflow_add(lflows, op->peer->od, S_ROUTER_IN_ARP_RESOLVE, - 100, ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->peer->od, + S_ROUTER_IN_ARP_RESOLVE, 100, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } if (op->lrp_networks.n_ipv6_addrs) { @@ -8913,8 +9062,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "eth.dst = %s; next;", op->lrp_networks.ea_s); - ovn_lflow_add(lflows, op->peer->od, S_ROUTER_IN_ARP_RESOLVE, - 100, ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, op->peer->od, + S_ROUTER_IN_ARP_RESOLVE, 100, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } } @@ -8935,8 +9086,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "eth.dst = %s; next;", op->lrp_networks.ea_s); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ARP_RESOLVE, - 50, ds_cstr(&match), ds_cstr(&actions)); + + ovn_lflow_add_with_hint(lflows, op->od, + S_ROUTER_IN_ARP_RESOLVE, 50, + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } } } else if (op->od->n_router_ports && strcmp(op->nbsp->type, "router") @@ -8977,9 +9131,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "eth.dst = %s; next;", ea_s); - ovn_lflow_add(lflows, peer->od, - S_ROUTER_IN_ARP_RESOLVE, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, peer->od, + S_ROUTER_IN_ARP_RESOLVE, 100, + ds_cstr(&match), + ds_cstr(&actions), + &op->nbsp->header_); } } @@ -9011,9 +9167,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "eth.dst = %s; next;", ea_s); - ovn_lflow_add(lflows, peer->od, - S_ROUTER_IN_ARP_RESOLVE, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, peer->od, + S_ROUTER_IN_ARP_RESOLVE, 100, + ds_cstr(&match), + ds_cstr(&actions), + &op->nbsp->header_); } } } @@ -9061,9 +9219,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "eth.dst = 00:00:00:00:00:00; next;"); - ovn_lflow_add(lflows, peer->od, - S_ROUTER_IN_ARP_RESOLVE, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, peer->od, + S_ROUTER_IN_ARP_RESOLVE, 100, + ds_cstr(&match), + ds_cstr(&actions), + &op->nbsp->header_); break; } } @@ -9104,9 +9264,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "eth.dst = %s; next;", ea_s); - ovn_lflow_add(lflows, peer->od, - S_ROUTER_IN_ARP_RESOLVE, 100, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, peer->od, + S_ROUTER_IN_ARP_RESOLVE, 100, + ds_cstr(&match), + ds_cstr(&actions), + &op->nbsp->header_); found_vip_network = true; break; } @@ -9159,8 +9321,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "eth.dst = %s; next;", router_port->lrp_networks.ea_s); - ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, - 100, ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, peer->od, + S_ROUTER_IN_ARP_RESOLVE, 100, + ds_cstr(&match), ds_cstr(&actions), + &op->nbsp->header_); } if (router_port->lrp_networks.n_ipv6_addrs) { @@ -9172,8 +9336,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "eth.dst = %s; next;", router_port->lrp_networks.ea_s); - ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, - 100, ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, peer->od, + S_ROUTER_IN_ARP_RESOLVE, 100, + ds_cstr(&match), ds_cstr(&actions), + &op->nbsp->header_); } } } @@ -9234,8 +9400,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&actions, REGBIT_PKT_LARGER" = check_pkt_larger(%d);" " next;", gw_mtu); - ovn_lflow_add(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 50, + ds_cstr(&match), ds_cstr(&actions), + &od->l3dgw_port->nbrp->header_); for (size_t i = 0; i < od->nbr->n_ports; i++) { struct ovn_port *rp = ovn_port_find(ports, @@ -9266,8 +9433,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, rp->lrp_networks.ea_s, rp->lrp_networks.ipv4_addrs[0].addr_s, gw_mtu - 18); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LARGER_PKTS, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_LARGER_PKTS, + 50, ds_cstr(&match), ds_cstr(&actions), + &rp->nbrp->header_); } } } @@ -9284,8 +9452,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } if (od->l3dgw_port && od->l3redirect_port) { - ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 300, - REGBIT_DISTRIBUTED_NAT" == 1", "next;"); + const struct ovsdb_idl_row *stage_hint = NULL; + + if (od->l3dgw_port->nbrp) { + stage_hint = &od->l3dgw_port->nbrp->header_; + } + + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 300, + REGBIT_DISTRIBUTED_NAT" == 1", "next;", + stage_hint); /* For traffic with outport == l3dgw_port, if the * packet did not match any higher priority redirect @@ -9297,8 +9472,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&actions, "outport = %s; next;", od->l3redirect_port->json_key); - ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50, + ds_cstr(&match), ds_cstr(&actions), + stage_hint); /* If the Ethernet destination has not been resolved, * redirect to the central instance of the l3dgw_port. @@ -9307,8 +9483,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * table, before being redirected to the central instance. */ ds_put_format(&match, " && eth.dst == 00:00:00:00:00:00"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 150, - ds_cstr(&match), ds_cstr(&actions)); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 150, + ds_cstr(&match), ds_cstr(&actions), + stage_hint); } /* Packets are allowed by default. */ @@ -9357,8 +9534,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "output; " "};", ETH_ADDR_ARGS(eth_dst), sn_addr_s, route->nexthop); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, - ds_cstr(&match), ds_cstr(&actions)); + + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, + ds_cstr(&match), ds_cstr(&actions), + &route->header_); } ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, @@ -9416,7 +9595,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&actions, "eth.src = %s; output;", op->lrp_networks.ea_s); ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 110, - ds_cstr(&match), ds_cstr(&actions)); + ds_cstr(&match), ds_cstr(&actions)); } ds_clear(&match); diff --git a/utilities/ovn-detrace.in b/utilities/ovn-detrace.in index 3bfb720..e9c3736 100755 --- a/utilities/ovn-detrace.in +++ b/utilities/ovn-detrace.in @@ -135,9 +135,74 @@ class CookieHandlerByUUUID(CookieHandler): cookie = cookie.zfill(8) return self._db.find_rows_by_partial_uuid(self._table, cookie) +class ACLHintHandler(CookieHandlerByUUUID): + def __init__(self, ovnnb_db): + super(ACLHintHandler, self).__init__(ovnnb_db, 'ACL') + + def print_record(self, acl): + output = 'ACL: %s, priority=%s, ' \ + 'match=(%s), %s' % (acl.direction, + acl.priority, + acl.match.strip('"'), + acl.action) + if acl.log: + output += ' (log)' + print_h(output) + +class LSPHintHandler(CookieHandlerByUUUID): + def __init__(self, ovnnb_db): + super(LSPHintHandler, self).__init__(ovnnb_db, 'Logical_Switch_Port') + + def print_record(self, lsp): + print_h('Logical Switch Port: %s type %s (addresses %s, dynamic addresses %s, security %s' % ( + lsp.name, lsp.type, lsp.addresses, lsp.dynamic_addresses, + lsp.port_security)) + +class LRPHintHandler(CookieHandlerByUUUID): + def __init__(self, ovnnb_db): + super(LRPHintHandler, self).__init__(ovnnb_db, 'Logical_Router_Port') + + def print_record(self, lrp): + print_h('Logical Router Port: %s mac %s networks %s ipv6_ra_configs %s' % ( + lrp.name, lrp.mac, lrp.networks, lrp.ipv6_ra_configs)) + +class LoadBalancerHintHandler(CookieHandlerByUUUID): + def __init__(self, ovnnb_db): + super(LoadBalancerHintHandler, self).__init__(ovnnb_db, 'Load_Balancer') + + def print_record(self, lb): + print_h('Load Balancer: %s protocol %s vips %s ip_port_mappings %s' % ( + lb.name, lb.protocol, lb.vips, lb.ip_port_mappings)) + +class NATHintHandler(CookieHandlerByUUUID): + def __init__(self, ovnnb_db): + super(NATHintHandler, self).__init__(ovnnb_db, 'NAT') + + def print_record(self, nat): + print_h('NAT: external IP %s external_mac %s logical_ip %s logical_port %s type %s' % ( + nat.external_ip, nat.external_mac, nat.logical_ip, + nat.logical_port, nat.type)) + +class StaticRouteHintHandler(CookieHandlerByUUUID): + def __init__(self, ovnnb_db): + super(StaticRouteHintHandler, self).__init__(ovnnb_db, + 'Logical_Router_Static_Route') + + def print_record(self, route): + print_h('Route: %s via %s (port %s), policy=%s' % ( + route.ip_prefix, route.nexthop, route.output_port, + route.policy)) + class LogicalFlowHandler(CookieHandlerByUUUID): - def __init__(self, ovnsb_db): + def __init__(self, ovnnb_db, ovnsb_db): super(LogicalFlowHandler, self).__init__(ovnsb_db, 'Logical_Flow') + self._hint_handlers = [ + ACLHintHandler(ovnnb_db), + LSPHintHandler(ovnnb_db), + LRPHintHandler(ovnnb_db), + LoadBalancerHintHandler(ovnnb_db), + NATHintHandler(ovnnb_db) + ] def print_record(self, lflow): print_p('Logical datapath: %s [%s]' % @@ -151,24 +216,14 @@ class LogicalFlowHandler(CookieHandlerByUUUID): def print_hint(self, lflow, ovnnb_db): external_ids = lflow.external_ids - if external_ids.get('stage-name') in ['ls_in_acl', - 'ls_out_acl']: - acl_hint = external_ids.get('stage-hint') - if not acl_hint: - return - for i, acl in enumerate( - ovnnb_db.find_rows_by_partial_uuid('ACL', acl_hint)): + hint = external_ids.get('stage-hint') + if not hint: + return + for handler in self._hint_handlers: + for i, record in enumerate(handler.get_records(hint)): if i > 0: - print_h('[Duplicate uuid ACL hint]') - - output = 'ACL: %s, priority=%s, ' \ - 'match=(%s), %s' % (acl.direction, - acl.priority, - acl.match.strip('"'), - acl.action) - if acl.log: - output += ' (log)' - print_h(output) + print_h('[Duplicate uuid hint]') + handler.print_record(record) class PortBindingHandler(CookieHandlerByUUUID): def __init__(self, ovnsb_db): @@ -283,7 +338,7 @@ def main(): ovsdb_ovnnb = OVSDB(ovnnb_db, 'OVN_Northbound') cookie_handlers = [ - LogicalFlowHandler(ovsdb_ovnsb), + LogicalFlowHandler(ovsdb_ovnnb, ovsdb_ovnsb), PortBindingHandler(ovsdb_ovnsb), MacBindingHandler(ovsdb_ovnsb), MulticastGroupHandler(ovsdb_ovnsb),
Until now the 'stage-hint' external-id was set only for logical flows installed for ACLs. In order to simplify troubleshooting, extend the approach and apply whenever possible. Set stage-hint for logical flows generated by the following NB tables too: - Logical_Switch_Port - Logical_Router_Port - Load_Balancer - NAT Also update ovn-detrace such that whenever stage-hints are available, all the tables mentioned above are queried and if the stage-hint matches a NB uuid, relevant information is dumped. Signed-off-by: Dumitru Ceara <dceara@redhat.com> --- northd/ovn-northd.c | 721 +++++++++++++++++++++++++++++------------------ utilities/ovn-detrace.in | 93 ++++-- 2 files changed, 524 insertions(+), 290 deletions(-)