On 7/3/20 7:46 AM, Han Zhou wrote:
> Thanks Dumitru. I have 2 comments below.
>
> On Thu, Jul 2, 2020 at 7:53 AM Dumitru Ceara <[email protected]
> <mailto:[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] <mailto:[email protected]>>
>> Reported-by: Girish Moodalbail <[email protected]
> <mailto:[email protected]>>
>> Reported-at:
> https://mail.openvswitch.org/pipermail/ovs-discuss/2020-June/050186.html
>> Signed-off-by: Dumitru Ceara <[email protected]
> <mailto:[email protected]>>
>> ---
>> northd/ovn-northd.8.xml | 16 +++-
>> northd/ovn-northd.c | 203
> ++++++++++++++++++++++++++++++++---------------
>> tests/ovn-northd.at <http://ovn-northd.at> | 65 +++++++++------
>> tests/ovn.at <http://ovn.at> | 8 +-
>> 4 files changed, 190 insertions(+), 102 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 a1ba56f..10fc8cf 100644
>> --- a/northd/ovn-northd.c
>> +++ b/northd/ovn-northd.c
>> @@ -8048,7 +8048,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;
>> @@ -8063,20 +8063,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);
>> @@ -8095,7 +8099,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)
>> {
>> @@ -8117,21 +8121,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);
>> @@ -8321,7 +8329,41 @@ build_lrouter_flows(struct hmap *datapaths,
> struct hmap *ports,
>> "ip4.dst == 0.0.0.0/8 <http://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.
>> @@ -8471,8 +8513,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. */
>> @@ -8490,7 +8532,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) {
>> @@ -8502,7 +8544,7 @@ 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);
>> @@ -8555,53 +8597,84 @@ build_lrouter_flows(struct hmap *datapaths,
> struct hmap *ports,
>> /* Mac address to use when replying to ARP/NS. */
>> const char *mac_s = REG_INPORT_ETH_ADDR;
>>
>> + /* 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) {
>
> This check should instead be put before the for loop, since this
> condition is the same for the whole loop.
>
Hi Han,
Thanks for the review. I don't think that would work because we also
build snat_ips in the same loop, regardless of op->od->l3dgw_port.
It might be cleaner to run the loop twice, once for SNAT and once for
DNAT (if op == op->od->l3dgw_port).
What do you think?
>> + continue;
>> + }
>> +
>> /* 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 ds match_cr_port = DS_EMPTY_INITIALIZER;
>> + struct ds match_non_cr_port = DS_EMPTY_INITIALIZER;
>> +
>> + 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_cr_port,
>> + "is_chassis_resident(\"%s\")",
>> + nat->logical_port);
>> + ds_put_format(&match_non_cr_port,
>> + "!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_cr_port,
>> + "is_chassis_resident(\"%s\")",
>> + op->od->l3redirect_port->json_key);
>> + ds_put_format(&match_non_cr_port,
>> + "!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, 90,
>> + mac_s, &match_cr_port, 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, &match_non_cr_port,
> true, 91,
>> lflows, &nat->header_);
>
> I think "match_non_cr_port" is not needed. If the priority-92 flow (with
> "match_cr_port") doesn't match, then it can just let the priority-91
> flow to drop the packet. Alternatively, if "match_non_cr_port" is added,
> then the two lflows can use the same priority.
>
You're right, we don't need match_non_cr_port, I'll remove it.
Thanks,
Dumitru
>> } else {
>> build_lrouter_arp_flow(op->od, op,
>> ext_addrs->ipv4_addrs[0].addr_s,
>> - mac_s, &match, 90,
>> + mac_s, &match_cr_port, false, 92,
>> + lflows, &nat->header_);
>> + build_lrouter_arp_flow(op->od, op,
>> + ext_addrs->ipv4_addrs[0].addr_s,
>> + mac_s, &match_non_cr_port,
> true, 91,
>> lflows, &nat->header_);
>> }
>> + ds_destroy(&match_cr_port);
>> + ds_destroy(&match_non_cr_port);
>> }
>>
>> if (!smap_get(&op->od->nbr->options, "chassis")
>> @@ -8787,8 +8860,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 <http://ovn-northd.at>
> b/tests/ovn-northd.at <http://ovn-northd.at>
>> index a3fb7ef..4a13456 100644
>> --- a/tests/ovn-northd.at <http://ovn-northd.at>
>> +++ b/tests/ovn-northd.at <http://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 <http://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 <http://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 <http://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 <http://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 <http://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 <http://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
> && !is_chassis_resident(""cr-lrp-public"")), 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
> && !is_chassis_resident(""cr-lrp-public"")), 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
> && !is_chassis_resident("ls-vm")), 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 <http://ovn.at> b/tests/ovn.at <http://ovn.at>
>> index 1a1cfbf..9522b55 100644
>> --- a/tests/ovn.at <http://ovn.at>
>> +++ b/tests/ovn.at <http://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