On Wed, Jun 12, 2024 at 2:50 AM Felix Huettner via dev
<ovs-dev@openvswitch.org> wrote:
>
> Previously we could only generate ARP requests from IPv4 packets
> and NS requests from IPv6 packets. This was the case because we rely on
> information in the packet to generate the ARP/NS requests.
>
> However in case of ARP/NS requests originating from the Logical_Router
> pipeline for nexthop lookups we overwrite the affected fields
> afterwards. This overwrite is done by the userdata openflow actions.
> Because of this we actually do not rely on any information of the IPv4/6
> packets in these cases.
>
> Unfortunately we can not easily determine if we are actually later
> overwriting the affected fields. The approach now is to use the fields
> from the IP header if we have a matching IP version and default to some
> values otherwise. In case we overwrite this data afterwards we are
> generally good. If we do not overwrite this data because of some bug we
> will send out invalid ARP/NS requests. They will hopefully be dropped by
> the rest of the network.
>
> The alternative would have been to introduce new arp/nd_ns actions where
> we guarantee this overwrite. This would not suffer from the above
> limitations, but would require a coordination on upgrades between all
> ovn-controllers and northd.
>
> Signed-off-by: Felix Huettner <felix.huettner@mail.schwarz>

Hi Felix,

Thanks for the patch series and sorry for the delay in reviews.

Looks like this patch series requires another rebase.

I tested this patch series using the ovn-fake-mutlinode - [1] .

After starting it,  I added the below static route

ovn-nbctl lr-route-add lr1 172.15.0.0/24 3001::b

And in the 'ovn-chassis-1' container I ran this command

[root@ovn-chassis-1 ~]# ip netns exec sw01p1 ping 172.15.0.50

Since we don't know the next hop,  the below logical flow is hit
(which is as expected)

  table=24(lr_in_arp_request  ), priority=200  , match=(eth.dst ==
00:00:00:00:00:00 && reg9[9] == 0 && xxreg0 == 3001::4), action=(nd_ns
{ eth.dst = 33:33:ff:00:00:04; ip6.dst = ff02::1:ff00:4; nd.target =
3001::b; output; }; output;)

And If I look into the ovn-controller logs (after enabling vconn:dbg)
I see that ovn-controller receives the icmp ping packet and it
generates IPv6 NS packet which is also as expected

----
2024-06-28T21:39:06.303Z|00020|vconn(ovn_pinctrl0)|DBG|unix:/var/run/openvswitch/br-int.mgmt:
received: NXT_PACKET_IN2 (OF1.5) (xid=0x0): cookie=0x77e2d8b
total_len=98 
reg0=0x30010000,reg1=0xac10016e,reg3=0xb,reg4=0x30010000,reg7=0xa,reg9=0x4,reg10=0x1,reg11=0x1,reg12=0x3,reg14=0x1,reg15=0x3,metadata=0x3,in_port=5
(via action) data_len=98 (unbuffered)
 
userdata=00.00.00.09.00.00.00.00.00.1c.00.18.00.80.00.00.00.00.00.00.00.01.de.10.80.00.3e.10.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.25.00.00.00
 continuation.bridge=b72b4e65-0756-4215-bfbf-c3db3652e8ee
 continuation.actions=unroll_xlate(table=0, cookie=0),resubmit(,37)
 continuation.odp_port=5
icmp,vlan_tci=0x0000,dl_src=30:51:00:00:00:03,dl_dst=00:00:00:00:00:00,nw_src=11.0.0.3,nw_dst=172.15.0.50,nw_tos=0,nw_ecn=0,nw_ttl=63,nw_frag=no,icmp_type=8,icmp_code=0
icmp_csum:cf9b
2024-06-28T21:39:06.304Z|00021|vconn(ovn_pinctrl0)|DBG|unix:/var/run/openvswitch/br-int.mgmt:
sent (Success): OFPT_PACKET_OUT (OF1.5) (xid=0x413):
in_port=CONTROLLER
actions=set_field:0x30010000->reg0,set_field:0xac10016e->reg1,set_field:0xb->reg3,set_field:0x30010000->reg4,set_field:0xa->reg7,set_field:0x4->reg9,set_field:0x1->reg10,set_field:0x1->reg11,set_field:0x3->reg12,set_field:0x1->reg14,set_field:0x3->reg15,set_field:0x3->metadata,move:NXM_NX_XXREG0[]->NXM_NX_ND_TARGET[],resubmit(,37)
data_len=86
icmp6,vlan_tci=0x0000,dl_src=30:51:00:00:00:03,dl_dst=33:33:ff:ff:ff:ff,ipv6_src=fe80::3251:ff:fe00:3,ipv6_dst=ff02::1:ffff:ffff,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,nw_frag=no,icmp_type=135,icmp_code=0,nd_target=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,nd_sll=30:51:00:00:00:03,nd_tll=00:00:00:00:00:00
icmp6_csum:1877
------

But strangely when this packet leaves the physical interface 'eth2' on
ovn-chassis-1,  the nd_target is wrongly populated

tcpdump on the physical interface (connected to br-ex)
---
17:37:40.289881 30:51:00:00:00:03 > 33:33:ff:ff:ff:ff, ethertype IPv6
(0x86dd), length 86: (hlim 255, next-header ICMPv6 (58) payload
length: 32) fe80::3251:ff:fe00:3 > ff02::1:ffff:ffff: [icmp6 sum ok]
ICMP6, neighbor solicitation, length 32, who has 3001:0:ac10:16e::b
  source link-address option (1), length 8 (1): 30:51:00:00:00:03

---

You can see that the nd_target is '3001:0:ac10:16e::b  and not
'3001::b', which is strange.  The inner action of "nd_ns" clearly sets
nd.target = 3001::b.

Can you please verify in your end if that is the case ?  You can
perhaps use ovn-fake-multinode if you can't  reproduce in your setup.

Thanks
Numan




> ---
> v4->v5: rebase
> v4: newly added
>
>  controller/pinctrl.c |  52 +++++++--
>  lib/actions.c        |   4 +-
>  northd/northd.c      |   9 +-
>  tests/ovn-northd.at  |   8 +-
>  tests/ovn.at         | 268 ++++++++++++++++++++++++++++++++++++++++++-
>  5 files changed, 320 insertions(+), 21 deletions(-)
>
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index f2e382a44..4c520bd5e 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -1574,9 +1574,11 @@ pinctrl_handle_arp(struct rconn *swconn, const struct 
> flow *ip_flow,
>                     const struct ofputil_packet_in *pin,
>                     struct ofpbuf *userdata, const struct ofpbuf 
> *continuation)
>  {
> -    /* This action only works for IP packets, and the switch should only send
> -     * us IP packets this way, but check here just to be sure. */
> -    if (ip_flow->dl_type != htons(ETH_TYPE_IP)) {
> +    uint16_t dl_type = ntohs(ip_flow->dl_type);
> +
> +    /* This action only works for IPv4 or IPv6 packets, and the switch should
> +     * only send us IP packets this way, but check here just to be sure. */
> +    if (dl_type != ETH_TYPE_IP && dl_type != ETH_TYPE_IPV6) {
>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>          VLOG_WARN_RL(&rl, "ARP action on non-IP packet (Ethertype 
> %"PRIx16")",
>                       ntohs(ip_flow->dl_type));
> @@ -1600,9 +1602,25 @@ pinctrl_handle_arp(struct rconn *swconn, const struct 
> flow *ip_flow,
>      struct arp_eth_header *arp = dp_packet_l3(&packet);
>      arp->ar_op = htons(ARP_OP_REQUEST);
>      arp->ar_sha = ip_flow->dl_src;
> -    put_16aligned_be32(&arp->ar_spa, ip_flow->nw_src);
>      arp->ar_tha = eth_addr_zero;
> -    put_16aligned_be32(&arp->ar_tpa, ip_flow->nw_dst);
> +
> +    /* We might be here without actually currently handling an IPv4 packet.
> +     * This can happen in the case where we route IPv6 packets over an IPv4
> +     * link.
> +     * In these cases we have no destination IPv4 address from the packet 
> that
> +     * we can reuse. But we receive the actual destination IPv4 address via
> +     * userdata anyway, so what we set for now is irrelevant.
> +     * This is just a hope since we do not parse the userdata. If we land 
> here
> +     * for whatever reason without being an IPv4 packet and without userdata 
> we
> +     * will send out a wrong packet.
> +     */
> +    if (ip_flow->dl_type == htons(ETH_TYPE_IP)) {
> +        put_16aligned_be32(&arp->ar_spa, ip_flow->nw_src);
> +        put_16aligned_be32(&arp->ar_tpa, ip_flow->nw_dst);
> +    } else {
> +        put_16aligned_be32(&arp->ar_spa, 0);
> +        put_16aligned_be32(&arp->ar_tpa, 0);
> +    }
>
>      if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) {
>          eth_push_vlan(&packet, htons(ETH_TYPE_VLAN_8021Q),
> @@ -6741,8 +6759,11 @@ pinctrl_handle_nd_ns(struct rconn *swconn, const 
> struct flow *ip_flow,
>                       struct ofpbuf *userdata,
>                       const struct ofpbuf *continuation)
>  {
> -    /* This action only works for IPv6 packets. */
> -    if (get_dl_type(ip_flow) != htons(ETH_TYPE_IPV6)) {
> +    uint16_t dl_type = ntohs(ip_flow->dl_type);
> +
> +    /* This action only works for IPv4 or IPv6 packets, and the switch should
> +     * only send us IP packets this way, but check here just to be sure. */
> +    if (dl_type != ETH_TYPE_IP && dl_type != ETH_TYPE_IPV6) {
>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>          VLOG_WARN_RL(&rl, "NS action on non-IPv6 packet");
>          return;
> @@ -6758,8 +6779,23 @@ pinctrl_handle_nd_ns(struct rconn *swconn, const 
> struct flow *ip_flow,
>      dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
>
>      in6_generate_lla(ip_flow->dl_src, &ipv6_src);
> +
> +    /* We might be here without actually currently handling an IPv6 packet.
> +     * This can happen in the case where we route IPv4 packets over an IPv6
> +     * link.
> +     * In these cases we have no destination IPv6 address from the packet 
> that
> +     * we can reuse. But we receive the actual destination IPv6 address via
> +     * userdata anyway, so what we pass to compose_nd_ns is irrelevant.
> +     * This is just a hope since we do not parse the userdata. If we land 
> here
> +     * for whatever reason without being an IPv6 packet and without userdata 
> we
> +     * will send out a wrong packet.
> +     */
> +    struct in6_addr ipv6_dst = IN6ADDR_EXACT_INIT;
> +    if (get_dl_type(ip_flow) == htons(ETH_TYPE_IPV6)) {
> +        ipv6_dst = ip_flow->ipv6_dst;
> +    }
>      compose_nd_ns(&packet, ip_flow->dl_src, &ipv6_src,
> -                  &ip_flow->ipv6_dst);
> +                  &ipv6_dst);
>
>      /* Reload previous packet metadata and set actions from userdata. */
>      set_actions_and_enqueue_msg(swconn, &packet,
> diff --git a/lib/actions.c b/lib/actions.c
> index e8cc0994d..c7c83a34c 100644
> --- a/lib/actions.c
> +++ b/lib/actions.c
> @@ -1718,7 +1718,7 @@ parse_nested_action(struct action_context *ctx, enum 
> ovnact_type type,
>  static void
>  parse_ARP(struct action_context *ctx)
>  {
> -    parse_nested_action(ctx, OVNACT_ARP, "ip4", ctx->scope);
> +    parse_nested_action(ctx, OVNACT_ARP, "ip", ctx->scope);
>  }
>
>  static void
> @@ -1772,7 +1772,7 @@ parse_ND_NA_ROUTER(struct action_context *ctx)
>  static void
>  parse_ND_NS(struct action_context *ctx)
>  {
> -    parse_nested_action(ctx, OVNACT_ND_NS, "ip6", ctx->scope);
> +    parse_nested_action(ctx, OVNACT_ND_NS, "ip", ctx->scope);
>  }
>
>  static void
> diff --git a/northd/northd.c b/northd/northd.c
> index e697973ce..970cdca6e 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -13549,7 +13549,8 @@ build_arp_request_flows_for_lrouter(
>
>          ds_clear(match);
>          ds_put_format(match, "eth.dst == 00:00:00:00:00:00 && "
> -                      "ip6 && " REG_NEXT_HOP_IPV6 " == %s",
> +                      REGBIT_NEXTHOP_IS_IPV4" == 0 && "
> +                      REG_NEXT_HOP_IPV6 " == %s",
>                        route->nexthop);
>          struct in6_addr sn_addr;
>          struct eth_addr eth_dst;
> @@ -13579,7 +13580,8 @@ build_arp_request_flows_for_lrouter(
>      }
>
>      ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
> -                      "eth.dst == 00:00:00:00:00:00 && ip4",
> +                      "eth.dst == 00:00:00:00:00:00 && "
> +                      REGBIT_NEXTHOP_IS_IPV4" == 1",
>                        "arp { "
>                        "eth.dst = ff:ff:ff:ff:ff:ff; "
>                        "arp.spa = " REG_SRC_IPV4 "; "
> @@ -13591,7 +13593,8 @@ build_arp_request_flows_for_lrouter(
>                                       meter_groups),
>                        lflow_ref);
>      ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
> -                      "eth.dst == 00:00:00:00:00:00 && ip6",
> +                      "eth.dst == 00:00:00:00:00:00 && "
> +                      REGBIT_NEXTHOP_IS_IPV4" == 0",
>                        "nd_ns { "
>                        "nd.target = " REG_NEXT_HOP_IPV6 "; "
>                        "output; "
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 41761ba96..a6aa66a0c 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -6796,10 +6796,10 @@ AT_CHECK([grep -e "lr_in_arp_resolve" lr0flows | 
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep -e "lr_in_arp_request" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_arp_request  ), priority=0    , match=(1), action=(output;)
> -  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 
> 00:00:00:00:00:00 && ip4), action=(arp { eth.dst = ff:ff:ff:ff:ff:ff; arp.spa 
> = reg1; arp.tpa = reg0; arp.op = 1; output; }; output;)
> -  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 
> 00:00:00:00:00:00 && ip6), action=(nd_ns { nd.target = xxreg0; output; }; 
> output;)
> -  table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst == 
> 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::10), action=(nd_ns { eth.dst 
> = 33:33:ff:00:00:10; ip6.dst = ff02::1:ff00:10; nd.target = 2001:db8::10; 
> output; }; output;)
> -  table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst == 
> 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::20), action=(nd_ns { eth.dst 
> = 33:33:ff:00:00:20; ip6.dst = ff02::1:ff00:20; nd.target = 2001:db8::20; 
> output; }; output;)
> +  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 
> 00:00:00:00:00:00 && reg9[[9]] == 0), action=(nd_ns { nd.target = xxreg0; 
> output; }; output;)
> +  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 
> 00:00:00:00:00:00 && reg9[[9]] == 1), action=(arp { eth.dst = 
> ff:ff:ff:ff:ff:ff; arp.spa = reg1; arp.tpa = reg0; arp.op = 1; output; }; 
> output;)
> +  table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst == 
> 00:00:00:00:00:00 && reg9[[9]] == 0 && xxreg0 == 2001:db8::10), action=(nd_ns 
> { eth.dst = 33:33:ff:00:00:10; ip6.dst = ff02::1:ff00:10; nd.target = 
> 2001:db8::10; output; }; output;)
> +  table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst == 
> 00:00:00:00:00:00 && reg9[[9]] == 0 && xxreg0 == 2001:db8::20), action=(nd_ns 
> { eth.dst = 33:33:ff:00:00:20; ip6.dst = ff02::1:ff00:20; nd.target = 
> 2001:db8::20; output; }; output;)
>  ])
>
>  AT_CLEANUP
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 1f1a7963d..6894947d1 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -1541,11 +1541,11 @@ clone { ip4.dst = 255.255.255.255; output; }; next;
>  # arp
>  arp { eth.dst = ff:ff:ff:ff:ff:ff; output; }; output;
>      encodes as 
> controller(userdata=00.00.00.00.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.OFTABLE_SAVE_INPORT_HEX.00.00.00,pause),resubmit(,OFTABLE_SAVE_INPORT)
> -    has prereqs ip4
> +    has prereqs ip
>  arp { };
>      formats as arp { drop; };
>      encodes as controller(userdata=00.00.00.00.00.00.00.00,pause)
> -    has prereqs ip4
> +    has prereqs ip
>
>  # get_arp
>  get_arp(outport, ip4.dst);
> @@ -1709,12 +1709,12 @@ reg9[[8]] = dhcp_relay_resp_chk(192.168.1, 
> 172.16.1.1);
>  # nd_ns
>  nd_ns { nd.target = xxreg0; output; };
>      encodes as 
> controller(userdata=00.00.00.09.00.00.00.00.00.1c.00.18.00.80.00.00.00.00.00.00.00.01.de.10.80.00.3e.10.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.OFTABLE_SAVE_INPORT_HEX.00.00.00,pause)
> -    has prereqs ip6
> +    has prereqs ip
>
>  nd_ns { };
>      formats as nd_ns { drop; };
>      encodes as controller(userdata=00.00.00.09.00.00.00.00,pause)
> -    has prereqs ip6
> +    has prereqs ip
>
>  # nd_na
>  nd_na { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = 
> inport; inport = ""; /* Allow sending out inport. */ output; };
> @@ -38706,6 +38706,266 @@ OVN_CLEANUP([hv1],[hv2])
>  AT_CLEANUP
>  ])
>
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over IPv6, 
> dynamic])
> +AT_SKIP_IF([test $HAVE_SCAPY = no])
> +ovn_start
> +
> +# Logical network:
> +# Two LRs - R1 and R2 that are connected to ls-transfer in 2001:db8::/64
> +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it.
> +# R2 has ls2 (172.16.1.0/24) connected to it.
> +
> +ls1_lp1_mac="f0:00:00:01:02:03"
> +rp_ls1_mac="00:00:00:01:02:03"
> +rp_ls2_mac="00:00:00:01:02:04"
> +ls2_lp1_mac="f0:00:00:01:02:04"
> +
> +ls1_lp1_ip="192.168.1.2"
> +ls2_lp1_ip="172.16.1.2"
> +
> +check ovn-nbctl lr-add R1
> +check ovn-nbctl lr-add R2
> +
> +check ovn-nbctl ls-add ls1
> +check ovn-nbctl ls-add ls2
> +check ovn-nbctl ls-add ls-transfer
> +
> +# Connect ls1 to R1
> +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24
> +check ovn-nbctl set Logical_Router R1 options:dynamic_neigh_routers=true
> +
> +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 
> type=router \
> +  options:router-port=ls1 addresses=\"$rp_ls1_mac\"
> +
> +# Connect ls2 to R2
> +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24
> +check ovn-nbctl set Logical_Router R2 options:dynamic_neigh_routers=true
> +
> +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 
> type=router \
> +  options:router-port=ls2 addresses=\"$rp_ls2_mac\"
> +
> +# Connect R1 to R2
> +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 2001:db8::1/64
> +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 2001:db8::2/64
> +
> +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \
> +  set Logical_Switch_Port ls-transfer_r1 type=router \
> +  options:router-port=R1_ls-transfer addresses=\"router\"
> +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \
> +  set Logical_Switch_Port ls-transfer_r2 type=router \
> +  options:router-port=R2_ls-transfer addresses=\"router\"
> +
> +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2])
> +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1])
> +
> +# Create logical port ls1-lp1 in ls1
> +check ovn-nbctl lsp-add ls1 ls1-lp1 \
> +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip"
> +
> +# Create logical port ls2-lp1 in ls2
> +check ovn-nbctl lsp-add ls2 ls2-lp1 \
> +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip"
> +
> +# Create two hypervisor and create OVS ports corresponding to logical ports.
> +net_add n1
> +
> +sim_add hv1
> +as hv1
> +check ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.1
> +check ovs-vsctl -- add-port br-int hv1-vif1 -- \
> +    set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \
> +    options:tx_pcap=hv1/vif1-tx.pcap \
> +    options:rxq_pcap=hv1/vif1-rx.pcap \
> +    ofport-request=1
> +
> +sim_add hv2
> +as hv2
> +check ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.2
> +check ovs-vsctl -- add-port br-int hv2-vif1 -- \
> +    set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \
> +    options:tx_pcap=hv2/vif1-tx.pcap \
> +    options:rxq_pcap=hv2/vif1-rx.pcap \
> +    ofport-request=1
> +
> +
> +# Pre-populate the hypervisors' ARP tables so that we don't lose any
> +# packets for ARP resolution (native tunneling doesn't queue packets
> +# for ARP resolution).
> +OVN_POPULATE_ARP
> +
> +# Allow some time for ovn-northd and ovn-controller to catch up.
> +wait_for_ports_up
> +check ovn-nbctl --wait=hv sync
> +
> +# Packet to send.
> +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \
> +                        IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', 
> ttl=64)/ \
> +                        UDP(sport=53, dport=4369)")
> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet"
> +
> +# Packet to Expect
> +# The TTL should be decremented by 2.
> +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \
> +                        IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', 
> ttl=62)/ \
> +                        UDP(sport=53, dport=4369)")
> +echo ${expected} > expected
> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
> +
> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \
> +grep "reg0 == 172.16.1.2" | wc -l], [0], [1
> +])
> +
> +# Disable the ls2-lp1 port.
> +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false
> +
> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \
> +grep "reg0 == 172.16.1.2" | wc -l], [0], [0
> +])
> +
> +# Send the same packet again and it should not be delivered
> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet"
> +
> +# The 2nd packet sent shound not be received.
> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
> +
> +OVN_CLEANUP([hv1],[hv2])
> +
> +AT_CLEANUP
> +])
> +
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv6 over IPv4, 
> dynamic])
> +AT_SKIP_IF([test $HAVE_SCAPY = no])
> +ovn_start
> +
> +# Logical network:
> +# Two LRs - R1 and R2 that are connected to ls-transfer in 10.0.0.0/24
> +# network. R1 has a switchs ls1 (2001:db8:1::/64) connected to it.
> +# R2 has ls2 (2001:db8:2::/64) connected to it.
> +
> +ls1_lp1_mac="f0:00:00:01:02:03"
> +rp_ls1_mac="00:00:00:01:02:03"
> +rp_ls2_mac="00:00:00:01:02:04"
> +ls2_lp1_mac="f0:00:00:01:02:04"
> +
> +ls1_lp1_ip="2001:db8:1::2"
> +ls2_lp1_ip="2001:db8:2::2"
> +
> +check ovn-nbctl lr-add R1
> +check ovn-nbctl lr-add R2
> +
> +check ovn-nbctl ls-add ls1
> +check ovn-nbctl ls-add ls2
> +check ovn-nbctl ls-add ls-transfer
> +
> +# Connect ls1 to R1
> +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 2001:db8:1::1/64
> +check ovn-nbctl set Logical_Router R1 options:dynamic_neigh_routers=true
> +
> +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 
> type=router \
> +  options:router-port=ls1 addresses=\"$rp_ls1_mac\"
> +
> +# Connect ls2 to R2
> +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 2001:db8:2::1/64
> +check ovn-nbctl set Logical_Router R2 options:dynamic_neigh_routers=true
> +
> +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 
> type=router \
> +  options:router-port=ls2 addresses=\"$rp_ls2_mac\"
> +
> +# Connect R1 to R2
> +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 10.0.0.1/24
> +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 10.0.0.2/24
> +
> +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \
> +  set Logical_Switch_Port ls-transfer_r1 type=router \
> +  options:router-port=R1_ls-transfer addresses=\"router\"
> +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \
> +  set Logical_Switch_Port ls-transfer_r2 type=router \
> +  options:router-port=R2_ls-transfer addresses=\"router\"
> +
> +AT_CHECK([ovn-nbctl lr-route-add R1 "::/0" 10.0.0.2])
> +AT_CHECK([ovn-nbctl lr-route-add R2 "::/0" 10.0.0.1])
> +
> +# Create logical port ls1-lp1 in ls1
> +check ovn-nbctl lsp-add ls1 ls1-lp1 \
> +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip"
> +
> +# Create logical port ls2-lp1 in ls2
> +check ovn-nbctl lsp-add ls2 ls2-lp1 \
> +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip"
> +
> +# Create two hypervisor and create OVS ports corresponding to logical ports.
> +net_add n1
> +
> +sim_add hv1
> +as hv1
> +check ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.1
> +check ovs-vsctl -- add-port br-int hv1-vif1 -- \
> +    set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \
> +    options:tx_pcap=hv1/vif1-tx.pcap \
> +    options:rxq_pcap=hv1/vif1-rx.pcap \
> +    ofport-request=1
> +
> +sim_add hv2
> +as hv2
> +check ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.2
> +check ovs-vsctl -- add-port br-int hv2-vif1 -- \
> +    set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \
> +    options:tx_pcap=hv2/vif1-tx.pcap \
> +    options:rxq_pcap=hv2/vif1-rx.pcap \
> +    ofport-request=1
> +
> +
> +# Pre-populate the hypervisors' ARP tables so that we don't lose any
> +# packets for ARP resolution (native tunneling doesn't queue packets
> +# for ARP resolution).
> +OVN_POPULATE_ARP
> +
> +# Allow some time for ovn-northd and ovn-controller to catch up.
> +wait_for_ports_up
> +check ovn-nbctl --wait=hv sync
> +
> +# Packet to send.
> +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \
> +                        IPv6(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', 
> hlim=64)/ \
> +                        UDP(sport=53, dport=4369)")
> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet"
> +
> +# Packet to Expect
> +# The TTL should be decremented by 2.
> +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \
> +                        IPv6(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', 
> hlim=62)/ \
> +                        UDP(sport=53, dport=4369)")
> +echo ${expected} > expected
> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
> +
> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \
> +grep "reg0 == 2001:db8:2::2" | wc -l], [0], [1
> +])
> +
> +# Disable the ls2-lp1 port.
> +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false
> +
> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \
> +grep "reg0 == 2001:db8:2::2" | wc -l], [0], [0
> +])
> +
> +# Send the same packet again and it should not be delivered
> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet"
> +
> +# The 2nd packet sent shound not be received.
> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
> +
> +OVN_CLEANUP([hv1],[hv2])
> +
> +AT_CLEANUP
> +])
> +
>  OVN_FOR_EACH_NORTHD([
>  AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over IPv6, 
> ECMP])
>  AT_SKIP_IF([test $HAVE_SCAPY = no])
> --
> 2.45.2
>
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to