On Sat, Jul 4, 2020 at 12:05 AM Dumitru Ceara <[email protected]> wrote:
> Most ARP/NS responder flows can be configured per datapath instead of per > router port. > > The only exception is with distributed gateway router ports which need > special treatment. This patch changes the ARP/NS responder behavior and > adds: > - Priority 92 flows to reply to ARP requests on distributed gateway router > ports, on the chassis where the DNAT entry is bound. > - Priority 91 flows to drop ARP requests on distributed gateway router > ports, > on chassis where the DNAT entry is not bound. > - Priority 90 flows to reply to ARP requests on all other router ports. > This > last type of flows is programmed exactly once per logical router limiting > the total number of required logical flows. > > Suggested-by: Han Zhou <[email protected]> > Reported-by: Girish Moodalbail <[email protected]> > Reported-at: > https://mail.openvswitch.org/pipermail/ovs-discuss/2020-June/050186.html > Signed-off-by: Dumitru Ceara <[email protected]> > Acked-by: Numan Siddique <[email protected]> Thanks Numan > --- > northd/ovn-northd.8.xml | 16 ++ > northd/ovn-northd.c | 342 > +++++++++++++++++++++++++++++------------------ > tests/ovn-northd.at | 65 +++++---- > tests/ovn.at | 8 + > 4 files changed, 260 insertions(+), 171 deletions(-) > > diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml > index 84224ff..11607c0 100644 > --- a/northd/ovn-northd.8.xml > +++ b/northd/ovn-northd.8.xml > @@ -1857,9 +1857,8 @@ nd_na_router { > IPv4: For a configured DNAT IP address or a load balancer > IPv4 VIP <var>A</var>, for each router port <var>P</var> with > Ethernet address <var>E</var>, a priority-90 flow matches > - <code>inport == <var>P</var> && arp.op == 1 && > - arp.tpa == <var>A</var></code> (ARP request) > - with the following actions: > + <code>arp.op == 1 && arp.tpa == <var>A</var></code> > + (ARP request) with the following actions: > </p> > > <pre> > @@ -1876,6 +1875,11 @@ output; > </pre> > > <p> > + IPv4: For a configured load balancer IPv4 VIP, a similar flow is > + added with the additional match <code>inport == > <var>P</var></code>. > + </p> > + > + <p> > If the router port <var>P</var> is a distributed gateway router > port, then the <code>is_chassis_resident(<var>P</var>)</code> is > also added in the match condition for the load balancer IPv4 > @@ -1922,9 +1926,11 @@ nd_na { > <ul> > <li> > If the corresponding NAT rule cannot be handled in a > - distributed manner, then this flow is only programmed on > + distributed manner, then a priority-92 flow is programmed on > the gateway port instance on the > - <code>redirect-chassis</code>. This behavior avoids > + <code>redirect-chassis</code>. A priority-91 drop flow is > + programmed on the other chassis when ARP requests/NS packets > + are received on the gateway port. This behavior avoids > generation of multiple ARP responses from different chassis, > and allows upstream MAC learning to point to the > <code>redirect-chassis</code>. > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c > index 2dc4e20..5643317 100644 > --- a/northd/ovn-northd.c > +++ b/northd/ovn-northd.c > @@ -8054,7 +8054,7 @@ lrouter_nat_is_stateless(const struct nbrec_nat *nat) > static void > build_lrouter_arp_flow(struct ovn_datapath *od, struct ovn_port *op, > const char *ip_address, const char *eth_addr, > - struct ds *extra_match, uint16_t priority, > + struct ds *extra_match, bool drop, uint16_t > priority, > struct hmap *lflows, const struct ovsdb_idl_row > *hint) > { > struct ds match = DS_EMPTY_INITIALIZER; > @@ -8069,20 +8069,24 @@ build_lrouter_arp_flow(struct ovn_datapath *od, > struct ovn_port *op, > if (extra_match && ds_last(extra_match) != EOF) { > ds_put_format(&match, " && %s", ds_cstr(extra_match)); > } > - ds_put_format(&actions, > - "eth.dst = eth.src; " > - "eth.src = %s; " > - "arp.op = 2; /* ARP reply */ " > - "arp.tha = arp.sha; " > - "arp.sha = %s; " > - "arp.tpa = arp.spa; " > - "arp.spa = %s; " > - "outport = inport; " > - "flags.loopback = 1; " > - "output;", > - eth_addr, > - eth_addr, > - ip_address); > + if (drop) { > + ds_put_format(&actions, "drop;"); > + } else { > + ds_put_format(&actions, > + "eth.dst = eth.src; " > + "eth.src = %s; " > + "arp.op = 2; /* ARP reply */ " > + "arp.tha = arp.sha; " > + "arp.sha = %s; " > + "arp.tpa = arp.spa; " > + "arp.spa = %s; " > + "outport = inport; " > + "flags.loopback = 1; " > + "output;", > + eth_addr, > + eth_addr, > + ip_address); > + } > > ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority, > ds_cstr(&match), ds_cstr(&actions), hint); > @@ -8101,7 +8105,7 @@ static void > build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op, > const char *action, const char *ip_address, > const char *sn_ip_address, const char *eth_addr, > - struct ds *extra_match, uint16_t priority, > + struct ds *extra_match, bool drop, uint16_t > priority, > struct hmap *lflows, > const struct ovsdb_idl_row *hint) > { > @@ -8123,21 +8127,25 @@ build_lrouter_nd_flow(struct ovn_datapath *od, > struct ovn_port *op, > ds_put_format(&match, " && %s", ds_cstr(extra_match)); > } > > - ds_put_format(&actions, > - "%s { " > - "eth.src = %s; " > - "ip6.src = %s; " > - "nd.target = %s; " > - "nd.tll = %s; " > - "outport = inport; " > - "flags.loopback = 1; " > - "output; " > - "};", > - action, > - eth_addr, > - ip_address, > - ip_address, > - eth_addr); > + if (drop) { > + ds_put_format(&actions, "drop;"); > + } else { > + ds_put_format(&actions, > + "%s { " > + "eth.src = %s; " > + "ip6.src = %s; " > + "nd.target = %s; " > + "nd.tll = %s; " > + "outport = inport; " > + "flags.loopback = 1; " > + "output; " > + "};", > + action, > + eth_addr, > + ip_address, > + ip_address, > + eth_addr); > + } > > ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority, > ds_cstr(&match), ds_cstr(&actions), hint); > @@ -8327,7 +8335,41 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > "ip4.dst == 0.0.0.0/8", > "drop;"); > > - /* Priority-90 flows reply to ARP requests and ND packets. */ > + /* Priority-90-92 flows handle ARP requests and ND packets. Most > are > + * per logical port but DNAT addresses can be handled per datapath > + * for non gateway router ports. > + */ > + for (int i = 0; i < od->nbr->n_nat; i++) { > + struct ovn_nat *nat_entry = &od->nat_entries[i]; > + const struct nbrec_nat *nat = nat_entry->nb; > + > + /* Skip entries we failed to parse. */ > + if (!nat_entry_is_valid(nat_entry)) { > + continue; > + } > + > + if (!strcmp(nat->type, "snat")) { > + continue; > + } > + > + /* Priority 91 and 92 flows are added for each gateway router > + * port to handle the special cases. In case we get the packet > + * on a regular port, just reply with the port's ETH address. > + */ > + struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; > + if (nat_entry_is_v6(nat_entry)) { > + build_lrouter_nd_flow(od, NULL, "nd_na", > + ext_addrs->ipv6_addrs[0].addr_s, > + ext_addrs->ipv6_addrs[0].sn_addr_s, > + REG_INPORT_ETH_ADDR, NULL, false, > 90, > + lflows, &nat->header_); > + } else { > + build_lrouter_arp_flow(od, NULL, > + ext_addrs->ipv4_addrs[0].addr_s, > + REG_INPORT_ETH_ADDR, NULL, false, > 90, > + lflows, &nat->header_); > + } > + } > > /* Drop ARP packets (priority 85). ARP request packets for > router's own > * IPs are handled with priority-90 flows. > @@ -8477,8 +8519,8 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > > build_lrouter_arp_flow(op->od, op, > op->lrp_networks.ipv4_addrs[i].addr_s, > - REG_INPORT_ETH_ADDR, &match, 90, > lflows, > - &op->nbrp->header_); > + REG_INPORT_ETH_ADDR, &match, false, 90, > + lflows, &op->nbrp->header_); > } > > /* A set to hold all load-balancer vips that need ARP responses. > */ > @@ -8496,7 +8538,7 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > > build_lrouter_arp_flow(op->od, op, > ip_address, REG_INPORT_ETH_ADDR, > - &match, 90, lflows, NULL); > + &match, false, 90, lflows, NULL); > } > > SSET_FOR_EACH (ip_address, &all_ips_v6) { > @@ -8508,108 +8550,12 @@ build_lrouter_flows(struct hmap *datapaths, > struct hmap *ports, > > build_lrouter_nd_flow(op->od, op, "nd_na", > ip_address, NULL, REG_INPORT_ETH_ADDR, > - &match, 90, lflows, NULL); > + &match, false, 90, lflows, NULL); > } > > sset_destroy(&all_ips_v4); > sset_destroy(&all_ips_v6); > > - /* A gateway router can have 2 SNAT IP addresses to force DNATed > and > - * LBed traffic respectively to be SNATed. In addition, there > can be > - * a number of SNAT rules in the NAT table. */ > - struct v46_ip *snat_ips = xmalloc(sizeof *snat_ips > - * (op->od->nbr->n_nat + 2)); > - size_t n_snat_ips = 0; > - > - struct v46_ip snat_ip; > - const char *dnat_force_snat_ip = get_force_snat_ip(op->od, "dnat", > - &snat_ip); > - if (dnat_force_snat_ip) { > - snat_ips[n_snat_ips++] = snat_ip; > - } > - > - const char *lb_force_snat_ip = get_force_snat_ip(op->od, "lb", > - &snat_ip); > - if (lb_force_snat_ip) { > - snat_ips[n_snat_ips++] = snat_ip; > - } > - > - for (size_t i = 0; i < op->od->nbr->n_nat; i++) { > - struct ovn_nat *nat_entry = &op->od->nat_entries[i]; > - const struct nbrec_nat *nat = nat_entry->nb; > - > - /* Skip entries we failed to parse. */ > - if (!nat_entry_is_valid(nat_entry)) { > - continue; > - } > - > - if (!strcmp(nat->type, "snat")) { > - if (nat_entry_is_v6(nat_entry)) { > - struct in6_addr *ipv6 = > - &nat_entry->ext_addrs.ipv6_addrs[0].addr; > - > - snat_ips[n_snat_ips].family = AF_INET6; > - snat_ips[n_snat_ips++].ipv6 = *ipv6; > - } else { > - ovs_be32 ip = nat_entry->ext_addrs.ipv4_addrs[0].addr; > - snat_ips[n_snat_ips].family = AF_INET; > - snat_ips[n_snat_ips++].ipv4 = ip; > - } > - continue; > - } > - > - /* Mac address to use when replying to ARP/NS. */ > - const char *mac_s = REG_INPORT_ETH_ADDR; > - > - /* ARP / ND handling for external IP addresses. > - * > - * DNAT IP addresses are external IP addresses that need ARP > - * handling. */ > - ds_clear(&match); > - > - if (op->od->l3dgw_port && op == op->od->l3dgw_port) { > - struct eth_addr mac; > - if (nat->external_mac && > - eth_addr_from_string(nat->external_mac, &mac) > - && nat->logical_port) { > - /* distributed NAT case, use nat->external_mac */ > - mac_s = nat->external_mac; > - /* Traffic with eth.src = nat->external_mac should > only be > - * sent from the chassis where nat->logical_port is > - * resident, so that upstream MAC learning points to > the > - * correct chassis. Also need to avoid generation of > - * multiple ARP responses from different chassis. */ > - ds_put_format(&match, "is_chassis_resident(\"%s\")", > - nat->logical_port); > - } else { > - mac_s = REG_INPORT_ETH_ADDR; > - /* Traffic with eth.src = > l3dgw_port->lrp_networks.ea_s > - * should only be sent from the "redirect-chassis", > so that > - * upstream MAC learning points to the > "redirect-chassis". > - * Also need to avoid generation of multiple ARP > responses > - * from different chassis. */ > - if (op->od->l3redirect_port) { > - ds_put_format(&match, "is_chassis_resident(%s)", > - op->od->l3redirect_port->json_key); > - } > - } > - } > - > - struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; > - if (nat_entry_is_v6(nat_entry)) { > - build_lrouter_nd_flow(op->od, op, "nd_na", > - ext_addrs->ipv6_addrs[0].addr_s, > - ext_addrs->ipv6_addrs[0].sn_addr_s, > - mac_s, &match, 90, > - lflows, &nat->header_); > - } else { > - build_lrouter_arp_flow(op->od, op, > - ext_addrs->ipv4_addrs[0].addr_s, > - mac_s, &match, 90, > - lflows, &nat->header_); > - } > - } > - > if (!smap_get(&op->od->nbr->options, "chassis") > && !op->od->l3dgw_port) { > /* UDP/TCP port unreachable. */ > @@ -8658,6 +8604,50 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > } > } > > + /* A gateway router can have 2 SNAT IP addresses to force DNATed > and > + * LBed traffic respectively to be SNATed. In addition, there > can be > + * a number of SNAT rules in the NAT table. */ > + struct v46_ip *snat_ips = xmalloc(sizeof *snat_ips > + * (op->od->nbr->n_nat + 2)); > + size_t n_snat_ips = 0; > + > + struct v46_ip snat_ip; > + const char *dnat_force_snat_ip = get_force_snat_ip(op->od, "dnat", > + &snat_ip); > + if (dnat_force_snat_ip) { > + snat_ips[n_snat_ips++] = snat_ip; > + } > + > + const char *lb_force_snat_ip = get_force_snat_ip(op->od, "lb", > + &snat_ip); > + if (lb_force_snat_ip) { > + snat_ips[n_snat_ips++] = snat_ip; > + } > + > + for (size_t i = 0; i < op->od->nbr->n_nat; i++) { > + struct ovn_nat *nat_entry = &op->od->nat_entries[i]; > + const struct nbrec_nat *nat = nat_entry->nb; > + > + /* Skip entries we failed to parse. */ > + if (!nat_entry_is_valid(nat_entry)) { > + continue; > + } > + > + if (!strcmp(nat->type, "snat")) { > + if (nat_entry_is_v6(nat_entry)) { > + struct in6_addr *ipv6 = > + &nat_entry->ext_addrs.ipv6_addrs[0].addr; > + > + snat_ips[n_snat_ips].family = AF_INET6; > + snat_ips[n_snat_ips++].ipv6 = *ipv6; > + } else { > + ovs_be32 ip = nat_entry->ext_addrs.ipv4_addrs[0].addr; > + snat_ips[n_snat_ips].family = AF_INET; > + snat_ips[n_snat_ips++].ipv4 = ip; > + } > + } > + } > + > ds_clear(&match); > ds_put_cstr(&match, "ip4.dst == {"); > bool has_drop_ips = false; > @@ -8719,6 +8709,90 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > } > > free(snat_ips); > + > + /* ARP/NS packets are taken care of per router. The only exception > + * is on the l3dgw_port where we might need to use a different > + * ETH address. > + */ > + if (op != op->od->l3dgw_port) { > + continue; > + } > + > + for (size_t i = 0; i < op->od->nbr->n_nat; i++) { > + struct ovn_nat *nat_entry = &op->od->nat_entries[i]; > + const struct nbrec_nat *nat = nat_entry->nb; > + > + /* Skip entries we failed to parse. */ > + if (!nat_entry_is_valid(nat_entry)) { > + continue; > + } > + > + if (!strcmp(nat->type, "snat")) { > + continue; > + } > + > + /* Mac address to use when replying to ARP/NS. */ > + const char *mac_s = REG_INPORT_ETH_ADDR; > + > + /* ARP / ND handling for external IP addresses. > + * > + * DNAT IP addresses are external IP addresses that need ARP > + * handling. */ > + > + struct eth_addr mac; > + > + ds_clear(&match); > + if (nat->external_mac && > + eth_addr_from_string(nat->external_mac, &mac) > + && nat->logical_port) { > + /* distributed NAT case, use nat->external_mac */ > + mac_s = nat->external_mac; > + /* Traffic with eth.src = nat->external_mac should only be > + * sent from the chassis where nat->logical_port is > + * resident, so that upstream MAC learning points to the > + * correct chassis. Also need to avoid generation of > + * multiple ARP responses from different chassis. */ > + ds_put_format(&match, "is_chassis_resident(\"%s\")", > + nat->logical_port); > + } else { > + mac_s = REG_INPORT_ETH_ADDR; > + /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s > + * should only be sent from the "redirect-chassis", so > that > + * upstream MAC learning points to the "redirect-chassis". > + * Also need to avoid generation of multiple ARP responses > + * from different chassis. */ > + if (op->od->l3redirect_port) { > + ds_put_format(&match, "is_chassis_resident(\"%s\")", > + op->od->l3redirect_port->json_key); > + } > + } > + > + /* Respond to ARP/NS requests on the chassis that binds the gw > + * port. Drop the ARP/NS requests on other chassis. > + */ > + struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; > + if (nat_entry_is_v6(nat_entry)) { > + build_lrouter_nd_flow(op->od, op, "nd_na", > + ext_addrs->ipv6_addrs[0].addr_s, > + ext_addrs->ipv6_addrs[0].sn_addr_s, > + mac_s, &match, false, 92, > + lflows, &nat->header_); > + build_lrouter_nd_flow(op->od, op, "nd_na", > + ext_addrs->ipv6_addrs[0].addr_s, > + ext_addrs->ipv6_addrs[0].sn_addr_s, > + mac_s, NULL, true, 91, > + lflows, &nat->header_); > + } else { > + build_lrouter_arp_flow(op->od, op, > + ext_addrs->ipv4_addrs[0].addr_s, > + mac_s, &match, false, 92, > + lflows, &nat->header_); > + build_lrouter_arp_flow(op->od, op, > + ext_addrs->ipv4_addrs[0].addr_s, > + mac_s, NULL, true, 91, > + lflows, &nat->header_); > + } > + } > } > > /* DHCPv6 reply handling */ > @@ -8793,8 +8867,8 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > build_lrouter_nd_flow(op->od, op, "nd_na_router", > op->lrp_networks.ipv6_addrs[i].addr_s, > > op->lrp_networks.ipv6_addrs[i].sn_addr_s, > - REG_INPORT_ETH_ADDR, &match, 90, lflows, > - &op->nbrp->header_); > + REG_INPORT_ETH_ADDR, &match, false, 90, > + lflows, &op->nbrp->header_); > } > > /* UDP/TCP port unreachable */ > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > index a3fb7ef..5693f84 100644 > --- a/tests/ovn-northd.at > +++ b/tests/ovn-northd.at > @@ -1594,33 +1594,24 @@ action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;) > # Ingress router port ETH address is used for ARP reply/NA in > lr_in_ip_input. > AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" | > grep "arp\|nd" | sort], [0], [dnl > table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa > == 42.42.42.0/24), dnl > -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 42.42.42.1; outport = inport; flags.loopback = 1; output;) > - table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.2), dnl > +match=(arp.op == 1 && arp.tpa == 43.43.43.2), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;) > table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.3), dnl > +match=(arp.op == 1 && arp.tpa == 43.43.43.3), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.3; outport = inport; flags.loopback = 1; output;) > table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.4), dnl > +match=(arp.op == 1 && arp.tpa == 43.43.43.4), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.4; outport = inport; flags.loopback = 1; output;) > table=3 (lr_in_ip_input ), priority=90 , dnl > +match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa > == 42.42.42.0/24), dnl > +action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 42.42.42.1; outport = inport; flags.loopback = 1; output;) > + table=3 (lr_in_ip_input ), priority=90 , dnl > match=(inport == "lrp" && ip6.dst == {fe80::200:ff:fe00:1, > ff02::1:ff00:1} && nd_ns && nd.target == fe80::200:ff:fe00:1), dnl > action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src = > fe80::200:ff:fe00:1; nd.target = fe80::200:ff:fe00:1; nd.tll = > xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };) > table=3 (lr_in_ip_input ), priority=90 , dnl > match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.1 && > arp.spa == 43.43.43.0/24), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.1; outport = inport; flags.loopback = 1; output;) > table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2), > dnl > -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;) > - table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3), > dnl > -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.3; outport = inport; flags.loopback = 1; output;) > - table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.4), > dnl > -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.4; outport = inport; flags.loopback = 1; output;) > - table=3 (lr_in_ip_input ), priority=90 , dnl > match=(inport == "lrp-public" && ip6.dst == {fe80::200:ff:fe00:100, > ff02::1:ff00:100} && nd_ns && nd.target == fe80::200:ff:fe00:100), dnl > action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src = > fe80::200:ff:fe00:100; nd.target = fe80::200:ff:fe00:100; nd.tll = > xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };) > ]) > @@ -1654,37 +1645,55 @@ action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;) > > # Ingress router port is used for ARP reply/NA in lr_in_ip_input. > # xxreg0[0..47] is used unless external_mac is set. > +# Priority 90 flows (per router). > AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" | > grep "arp\|nd" | sort], [0], [dnl > table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa > == 42.42.42.0/24), dnl > -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 42.42.42.1; outport = inport; flags.loopback = 1; output;) > - table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.2), dnl > +match=(arp.op == 1 && arp.tpa == 43.43.43.2), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;) > table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.3), dnl > +match=(arp.op == 1 && arp.tpa == 43.43.43.3), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.3; outport = inport; flags.loopback = 1; output;) > table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.4), dnl > +match=(arp.op == 1 && arp.tpa == 43.43.43.4), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.4; outport = inport; flags.loopback = 1; output;) > table=3 (lr_in_ip_input ), priority=90 , dnl > +match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa > == 42.42.42.0/24), dnl > +action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 42.42.42.1; outport = inport; flags.loopback = 1; output;) > + table=3 (lr_in_ip_input ), priority=90 , dnl > match=(inport == "lrp" && ip6.dst == {fe80::200:ff:fe00:1, > ff02::1:ff00:1} && nd_ns && nd.target == fe80::200:ff:fe00:1), dnl > action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src = > fe80::200:ff:fe00:1; nd.target = fe80::200:ff:fe00:1; nd.tll = > xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };) > table=3 (lr_in_ip_input ), priority=90 , dnl > match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.1 && > arp.spa == 43.43.43.0/24), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.1; outport = inport; flags.loopback = 1; output;) > table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2 && > is_chassis_resident("cr-lrp-public")), dnl > +match=(inport == "lrp-public" && ip6.dst == {fe80::200:ff:fe00:100, > ff02::1:ff00:100} && nd_ns && nd.target == fe80::200:ff:fe00:100 && > is_chassis_resident("cr-lrp-public")), dnl > +action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src = > fe80::200:ff:fe00:100; nd.target = fe80::200:ff:fe00:100; nd.tll = > xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };) > +]) > + > +# Priority 91 drop flows (per distributed gw port), if port is not > resident. > +AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=91" | > grep "arp\|nd" | sort], [0], [dnl > + table=3 (lr_in_ip_input ), priority=91 , dnl > +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2), > dnl > +action=(drop;) > + table=3 (lr_in_ip_input ), priority=91 , dnl > +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3), > dnl > +action=(drop;) > + table=3 (lr_in_ip_input ), priority=91 , dnl > +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.4), > dnl > +action=(drop;) > +]) > + > +# Priority 92 ARP/NS responders (per distributed gw port), if port is > resident. > +AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=92" | > grep "arp\|nd" | sort], [0], [dnl > + table=3 (lr_in_ip_input ), priority=92 , dnl > +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2 && > is_chassis_resident(""cr-lrp-public"")), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;) > - table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3 && > is_chassis_resident("cr-lrp-public")), dnl > + table=3 (lr_in_ip_input ), priority=92 , dnl > +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3 && > is_chassis_resident(""cr-lrp-public"")), dnl > action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP > reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; > arp.spa = 43.43.43.3; outport = inport; flags.loopback = 1; output;) > - table=3 (lr_in_ip_input ), priority=90 , dnl > + table=3 (lr_in_ip_input ), priority=92 , dnl > match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.4 && > is_chassis_resident("ls-vm")), dnl > action=(eth.dst = eth.src; eth.src = 00:00:00:00:00:02; arp.op = 2; /* > ARP reply */ arp.tha = arp.sha; arp.sha = 00:00:00:00:00:02; arp.tpa = > arp.spa; arp.spa = 43.43.43.4; outport = inport; flags.loopback = 1; > output;) > - table=3 (lr_in_ip_input ), priority=90 , dnl > -match=(inport == "lrp-public" && ip6.dst == {fe80::200:ff:fe00:100, > ff02::1:ff00:100} && nd_ns && nd.target == fe80::200:ff:fe00:100 && > is_chassis_resident("cr-lrp-public")), dnl > -action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src = > fe80::200:ff:fe00:100; nd.target = fe80::200:ff:fe00:100; nd.tll = > xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };) > ]) > > # xreg0[0..47] isn't used anywhere else. > diff --git a/tests/ovn.at b/tests/ovn.at > index 1a1cfbf..9522b55 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -19336,7 +19336,7 @@ OVS_WAIT_UNTIL([ > send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 > 0 121) > > # Verify that the ARP request is replied to from hv1 and not hv2. > > -match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.121,arp_op=1" > > +match_arp_req="priority=92.*${match_r1_metadata}.*arp_tpa=10.0.0.121,arp_op=1" > > as hv1 > OVS_WAIT_UNTIL([ > @@ -19356,7 +19356,7 @@ OVS_WAIT_UNTIL([ > send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 > 0 122) > > # Verify that the ARP request is replied to from hv2 and not hv1. > > -match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.122,arp_op=1" > > +match_arp_req="priority=92.*${match_r1_metadata}.*arp_tpa=10.0.0.122,arp_op=1" > > as hv2 > OVS_WAIT_UNTIL([ > @@ -19400,7 +19400,7 @@ dst_ipv6=00100000000000000000000000000121 > send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72dd > > # Verify that the ND_NS is replied to from hv1 and not hv2. > > -match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::121" > > +match_nd_ns="priority=92.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::121" > > as hv1 > OVS_WAIT_UNTIL([ > @@ -19422,7 +19422,7 @@ dst_ipv6=00100000000000000000000000000122 > send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72db > > # Verify that the ND_NS is replied to from hv2 and not hv1. > > -match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::122" > > +match_nd_ns="priority=92.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::122" > > as hv2 > OVS_WAIT_UNTIL([ > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
