[ovs-dev,ovn,v2] system-ovn.at: Create IPv6 load balancing tests
diff mbox series

Message ID 20191106012628.395130-1-russell@ovn.org
State New
Headers show
Series
  • [ovs-dev,ovn,v2] system-ovn.at: Create IPv6 load balancing tests
Related show

Commit Message

Russell Bryant Nov. 6, 2019, 1:26 a.m. UTC
Duplicate all of the IPv4 load balancing test cases for IPv6.
All of these are passing without any changes needed in OVN code, but
this will help ensure that we do not have any IPv6 load balancing
regressions in the future.

Signed-off-by: Russell Bryant <russell@ovn.org>
---
 tests/system-ovn.at | 876 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 799 insertions(+), 77 deletions(-)

v1 -> v2:
 - Use [[ and ]] instead of quadigraphs to enhance readability,
   as suggested by Ben Pfaff

Comments

0-day Robot Nov. 6, 2019, 1:57 a.m. UTC | #1
Bleep bloop.  Greetings Russell Bryant, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


checkpatch:
WARNING: Line is 184 characters long (recommended limit is 79)
#746 FILE: p-set-addresses:1987:
tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 184 characters long (recommended limit is 79)
#747 FILE: p-set-addresses:1988:
tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 185 characters long (recommended limit is 79)
#763 FILE: p-set-addresses:1995:
tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 185 characters long (recommended limit is 79)
#764 FILE: p-set-addresses:1996:
tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 101 characters long (recommended limit is 79)
#920 FILE: p-set-addresses:2156:
    NS_CHECK_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])

WARNING: Line is 173 characters long (recommended limit is 79)
#929 FILE: p-set-addresses:2162:
tcp,orig=(src=fd72::3,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 173 characters long (recommended limit is 79)
#930 FILE: p-set-addresses:2163:
tcp,orig=(src=fd72::3,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 173 characters long (recommended limit is 79)
#939 FILE: p-set-addresses:2169:
tcp,orig=(src=fd72::3,dst=fd11::2,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 173 characters long (recommended limit is 79)
#940 FILE: p-set-addresses:2170:
tcp,orig=(src=fd72::3,dst=fd12::2,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 89 characters long (recommended limit is 79)
#960 FILE: p-set-addresses:2337:
        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \

WARNING: Line is 102 characters long (recommended limit is 79)
#1036 FILE: p-set-addresses:2413:
ovn-nbctl set load_balancer $uuid vips:'"[[fd72::11]]:8000"'='"@<:@fd01::2@:>@:80,@<:@fd02::2@:>@:80"'

WARNING: Line is 102 characters long (recommended limit is 79)
#1050 FILE: p-set-addresses:2427:
    NS_CHECK_EXEC([alice1], [wget http://[[fd72::10]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])

WARNING: Line is 80 characters long (recommended limit is 79)
#1054 FILE: p-set-addresses:2431:
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::10) | grep -v fe80 |

WARNING: Line is 174 characters long (recommended limit is 79)
#1056 FILE: p-set-addresses:2433:
tcp,orig=(src=fd72::2,dst=fd72::10,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 174 characters long (recommended limit is 79)
#1057 FILE: p-set-addresses:2434:
tcp,orig=(src=fd72::2,dst=fd72::10,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 107 characters long (recommended limit is 79)
#1063 FILE: p-set-addresses:2440:
    NS_CHECK_EXEC([alice1], [wget http://[[fd72::11]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])

WARNING: Line is 80 characters long (recommended limit is 79)
#1067 FILE: p-set-addresses:2444:
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::11) | grep -v fe80 |

WARNING: Line is 174 characters long (recommended limit is 79)
#1069 FILE: p-set-addresses:2446:
tcp,orig=(src=fd72::2,dst=fd72::11,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

WARNING: Line is 174 characters long (recommended limit is 79)
#1070 FILE: p-set-addresses:2447:
tcp,orig=(src=fd72::2,dst=fd72::11,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)

Lines checked: 1094, Warnings: 19, Errors: 0


Please check this out.  If you feel there has been an error, please email aconole@redhat.com

Thanks,
0-day Robot
Numan Siddique Nov. 6, 2019, 1:12 p.m. UTC | #2
On Wed, Nov 6, 2019 at 6:57 AM Russell Bryant <russell@ovn.org> wrote:
>
> Duplicate all of the IPv4 load balancing test cases for IPv6.
> All of these are passing without any changes needed in OVN code, but
> this will help ensure that we do not have any IPv6 load balancing
> regressions in the future.
>
> Signed-off-by: Russell Bryant <russell@ovn.org>

Acked-by: Numan Siddique <numans@ovn.org>

Numan

> ---
>  tests/system-ovn.at | 876 ++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 799 insertions(+), 77 deletions(-)
>
> v1 -> v2:
>  - Use [[ and ]] instead of quadigraphs to enhance readability,
>    as suggested by Ben Pfaff
>
>
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index b3f90aae2..5885df58e 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -1158,6 +1158,153 @@ tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(s
>  ])
>
>
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- load-balancing - IPv6])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# 2 logical switches "foo" (fd01::/64) and "bar" (fd02::/64)
> +# connected to a router R1.
> +# foo has foo1 to act as a client.
> +# bar has bar1, bar2, bar3 to act as servers.
> +#
> +# Loadbalancer VIPs in fd03::/64 network.
> +
> +ovn-nbctl create Logical_Router name=R1
> +ovn-nbctl ls-add foo
> +ovn-nbctl ls-add bar
> +
> +# Connect foo to R1
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd01::1/64
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
> +
> +# Connect bar to R1
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd02::1/64
> +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
> +    type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
> +
> +# Create logical port 'foo1' in switch 'foo'.
> +ADD_NAMESPACES(foo1)
> +ADD_VETH(foo1, foo1, br-int, "fd01::2/64", "f0:00:00:01:02:03", \
> +         "fd01::1")
> +ovn-nbctl lsp-add foo foo1 \
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd01::2"
> +
> +# Create logical ports 'bar1', 'bar2', 'bar3' in switch 'bar'.
> +ADD_NAMESPACES(bar1)
> +ADD_VETH(bar1, bar1, br-int, "fd02::2/64", "f0:00:0f:01:02:03", \
> +         "fd02::1")
> +ovn-nbctl lsp-add bar bar1 \
> +-- lsp-set-addresses bar1 "f0:00:0f:01:02:03 fd02::2"
> +
> +ADD_NAMESPACES(bar2)
> +ADD_VETH(bar2, bar2, br-int, "fd02::3/64", "f0:00:0f:01:02:04", \
> +         "fd02::1")
> +ovn-nbctl lsp-add bar bar2 \
> +-- lsp-set-addresses bar2 "f0:00:0f:01:02:04 fd02::3"
> +
> +ADD_NAMESPACES(bar3)
> +ADD_VETH(bar3, bar3, br-int, "fd02::4/64", "f0:00:0f:01:02:05", \
> +         "fd02::1")
> +ovn-nbctl lsp-add bar bar3 \
> +-- lsp-set-addresses bar3 "f0:00:0f:01:02:05 fd02::4"
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:\"fd03::1\"=\"fd02::2,fd02::3,fd02::4\"`
> +ovn-nbctl set logical_switch foo load_balancer=$uuid
> +
> +# Create another load-balancer with another VIP.
> +uuid=`ovn-nbctl create load_balancer vips:\"fd03::3\"=\"fd02::2,fd02::3,fd02::4\"`
> +ovn-nbctl add logical_switch foo load_balancer $uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd02::2@:>@:80,@<:@fd02::3@:>@:80,@<:@fd02::4@:>@:80"'
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=\[[fd02::4\]]:80)'])
> +
> +# Start webservers in 'bar1', 'bar2' and 'bar3'.
> +OVS_START_L7([bar1], [http6])
> +OVS_START_L7([bar2], [http6])
> +OVS_START_L7([bar3], [http6])
> +
> +dnl Should work with the virtual IP fd03::1 address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log || (ovs-ofctl -O OpenFlow13 dump-flows br-int && false)])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Should work with the virtual IP fd03::3 address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::3]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::3) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::3,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::3,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::3,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +
>  OVS_APP_EXIT_AND_WAIT([ovn-controller])
>
>  as ovn-sb
> @@ -1253,18 +1400,431 @@ tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(s
>  dnl Test load-balancing that includes L4 ports in NAT.
>  for i in `seq 1 20`; do
>      echo Request $i
> -    NS_CHECK_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +    NS_CHECK_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.5,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- load-balancing - same subnet. - IPv6])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# 1 logical switch "foo" (fd01::/64) connected to router R1.
> +# foo has foo1, foo2, foo3, foo4 as logical ports.
> +#
> +# Loadbalancer VIPs in fd03::/64 network. Router is needed for default
> +# gateway. We will test load-balancing with foo1 as a client and foo2, foo3 and
> +# foo4 as servers.
> +
> +ovn-nbctl create Logical_Router name=R1
> +ovn-nbctl ls-add foo
> +
> +# Connect foo to R1
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd01::1/64
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
> +
> +# Create logical port 'foo1', 'foo2', 'foo3' and 'foo4' in switch 'foo'.
> +ADD_NAMESPACES(foo1, foo2, foo3, foo4)
> +for i in `seq 1 4`; do
> +    j=`expr $i + 1`
> +    ADD_VETH(foo$i, foo$i, br-int, "fd01::$j/64", "f0:00:00:01:02:0$j", \
> +             "fd01::1")
> +    ovn-nbctl lsp-add foo foo$i \
> +        -- lsp-set-addresses foo$i "f0:00:00:01:02:0$j fd01::$j"
> +done
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:\"fd03::1\"=\"fd01::3,fd01::4,fd01::5\"`
> +ovn-nbctl set logical_switch foo load_balancer=$uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd01::3@:>@:80,@<:@fd01::4@:>@:80,@<:@fd01::5@:>@:80"'
> +
> +ovn-nbctl list load_balancer
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=\[[fd01::5\]]:80)'])
> +
> +# Start webservers in 'foo2', 'foo3' and 'foo4'.
> +OVS_START_L7([foo2], [http6])
> +OVS_START_L7([foo3], [http6])
> +OVS_START_L7([foo4], [http6])
> +
> +dnl Should work with the virtual IP address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd01::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd01::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd01::5,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::5,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- load balancing in gateway router])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# Two LRs - R1 and R2 that are connected to each other via LS "join"
> +# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and
> +# bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected
> +# to it.  R2 is a gateway router on which we add load-balancing rules.
> +#
> +#    foo -- R1 -- join - R2 -- alice
> +#           |
> +#    bar ----
> +
> +ovn-nbctl create Logical_Router name=R1
> +ovn-nbctl create Logical_Router name=R2 options:chassis=hv1
> +
> +ovn-nbctl ls-add foo
> +ovn-nbctl ls-add bar
> +ovn-nbctl ls-add alice
> +ovn-nbctl ls-add join
> +
> +# Connect foo to R1
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
> +
> +# Connect bar to R1
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24
> +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
> +    type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
> +
> +# Connect alice to R2
> +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24
> +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
> +    type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
> +
> +# Connect R1 to join
> +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24
> +ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
> +    type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"'
> +
> +# Connect R2 to join
> +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24
> +ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
> +    type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
> +
> +# Static routes.
> +ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2
> +ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1
> +
> +# Logical port 'foo1' in switch 'foo'.
> +ADD_NAMESPACES(foo1)
> +ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
> +         "192.168.1.1")
> +ovn-nbctl lsp-add foo foo1 \
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
> +
> +# Logical port 'alice1' in switch 'alice'.
> +ADD_NAMESPACES(alice1)
> +ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:04", \
> +         "172.16.1.1")
> +ovn-nbctl lsp-add alice alice1 \
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2"
> +
> +# Logical port 'bar1' in switch 'bar'.
> +ADD_NAMESPACES(bar1)
> +ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \
> +"192.168.2.1")
> +ovn-nbctl lsp-add bar bar1 \
> +-- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2"
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
> +ovn-nbctl set logical_router R2 load_balancer=$uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.168.2.2:80"'
> +
> +# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule.
> +ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \
> +    external_ip=30.0.0.2 -- add logical_router R2 nat @nat
> +
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=192.168.2.2:80)'])
> +
> +# Start webservers in 'foo1', 'bar1'.
> +OVS_START_L7([foo1], [http])
> +OVS_START_L7([bar1], [http])
> +
> +dnl Should work with the virtual IP address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/connection dropped.*/d"])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- load balancing in gateway router - IPv6])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# Two LRs - R1 and R2 that are connected to each other via LS "join"
> +# in fd20::/64 network. R1 has switchess foo (fd11::/64) and
> +# bar (fd12::/64) connected to it. R2 has alice (fd72::/64) connected
> +# to it.  R2 is a gateway router on which we add load-balancing rules.
> +#
> +#    foo -- R1 -- join - R2 -- alice
> +#           |
> +#    bar ----
> +
> +ovn-nbctl create Logical_Router name=R1
> +ovn-nbctl create Logical_Router name=R2 options:chassis=hv1
> +
> +ovn-nbctl ls-add foo
> +ovn-nbctl ls-add bar
> +ovn-nbctl ls-add alice
> +ovn-nbctl ls-add join
> +
> +# Connect foo to R1
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
> +
> +# Connect bar to R1
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64
> +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
> +    type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
> +
> +# Connect alice to R2
> +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 fd72::1/64
> +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
> +    type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
> +
> +# Connect R1 to join
> +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 fd20::1/64
> +ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
> +    type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"'
> +
> +# Connect R2 to join
> +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 fd20::2/64
> +ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
> +    type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
> +
> +# Static routes.
> +ovn-nbctl lr-route-add R1 fd72::/64 fd20::2
> +ovn-nbctl lr-route-add R2 fd11::/64 fd20::1
> +ovn-nbctl lr-route-add R2 fd12::/64 fd20::1
> +
> +# Logical port 'foo1' in switch 'foo'.
> +ADD_NAMESPACES(foo1)
> +ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \
> +         "fd11::1")
> +ovn-nbctl lsp-add foo foo1 \
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2"
> +
> +# Logical port 'alice1' in switch 'alice'.
> +ADD_NAMESPACES(alice1)
> +ADD_VETH(alice1, alice1, br-int, "fd72::2/64", "f0:00:00:01:02:04", \
> +         "fd72::1")
> +ovn-nbctl lsp-add alice alice1 \
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd72::2"
> +
> +# Logical port 'bar1' in switch 'bar'.
> +ADD_NAMESPACES(bar1)
> +ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \
> +"fd12::1")
> +ovn-nbctl lsp-add bar bar1 \
> +-- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2"
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:\"fd30::1\"=\"fd11::2,fd12::2\"`
> +ovn-nbctl set logical_router R2 load_balancer=$uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"[[fd30::2]]:8000"'='"@<:@fd11::2@:>@:80,@<:@fd12::2@:>@:80"'
> +
> +ovn-nbctl list load_balancer
> +
> +# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule.
> +ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=\"fd12::2\" \
> +    external_ip=\"fd30::2\" -- add logical_router R2 nat @nat
> +
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=\[[fd12::2\]]:80)'])
> +
> +# Start webservers in 'foo1', 'bar1'.
> +OVS_START_L7([foo1], [http6])
> +OVS_START_L7([bar1], [http6])
> +
> +dnl Should work with the virtual IP address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd72::2,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd30::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
>  done
>
>  dnl Each server should have at least one connection.
> -AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::2) | grep -v fe80 |
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.5,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd30::2,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd30::2,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>  ])
>
> -
>  OVS_APP_EXIT_AND_WAIT([ovn-controller])
>
>  as ovn-sb
> @@ -1277,10 +1837,11 @@ as northd
>  OVS_APP_EXIT_AND_WAIT([ovn-northd])
>
>  as
> -OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/connection dropped.*/d"])
>  AT_CLEANUP
>
> -AT_SETUP([ovn -- load balancing in gateway router])
> +AT_SETUP([ovn -- multiple gateway routers, load-balancing])
>  AT_KEYWORDS([ovnlb])
>
>  CHECK_CONNTRACK()
> @@ -1301,21 +1862,27 @@ ovs-vsctl \
>  start_daemon ovn-controller
>
>  # Logical network:
> -# Two LRs - R1 and R2 that are connected to each other via LS "join"
> +# Three LRs - R1, R2 and R3 that are connected to each other via LS "join"
>  # in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and
>  # bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected
> -# to it.  R2 is a gateway router on which we add load-balancing rules.
> +# to it.  R3 has bob (172.16.1.0/24) connected to it. Note how both alice and
> +# bob have the same subnet behind it.  We are trying to simulate external
> +# network via those 2 switches. In real world the switch ports of these
> +# switches will have addresses set as "unknown" to make them learning switches.
> +# Or those switches will be "localnet" ones.
>  #
>  #    foo -- R1 -- join - R2 -- alice
> -#           |
> -#    bar ----
> +#           |          |
> +#    bar ----          - R3 --- bob
>
>  ovn-nbctl create Logical_Router name=R1
>  ovn-nbctl create Logical_Router name=R2 options:chassis=hv1
> +ovn-nbctl create Logical_Router name=R3 options:chassis=hv1
>
>  ovn-nbctl ls-add foo
>  ovn-nbctl ls-add bar
>  ovn-nbctl ls-add alice
> +ovn-nbctl ls-add bob
>  ovn-nbctl ls-add join
>
>  # Connect foo to R1
> @@ -1333,6 +1900,11 @@ ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24
>  ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
>      type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
>
> +# Connect bob to R3
> +ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 172.16.1.2/24
> +ovn-nbctl lsp-add bob rp-bob -- set Logical_Switch_Port rp-bob \
> +    type=router options:router-port=bob addresses=\"00:00:03:01:02:03\"
> +
>  # Connect R1 to join
>  ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24
>  ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
> @@ -1343,9 +1915,23 @@ ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24
>  ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
>      type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
>
> +# Connect R3 to join
> +ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 20.0.0.3/24
> +ovn-nbctl lsp-add join r3-join -- set Logical_Switch_Port r3-join \
> +    type=router options:router-port=R3_join addresses='"00:00:04:01:02:05"'
> +
> +# Install static routes with source ip address as the policy for routing.
> +# We want traffic from 'foo' to go via R2 and traffic of 'bar' to go via R3.
> +ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.1.0/24 20.0.0.2
> +ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.2.0/24 20.0.0.3
> +
>  # Static routes.
> -ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2
>  ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1
> +ovn-nbctl lr-route-add R3 192.168.0.0/16 20.0.0.1
> +
> +# For gateway routers R2 and R3, set a force SNAT rule.
> +ovn-nbctl set logical_router R2 options:lb_force_snat_ip=20.0.0.2
> +ovn-nbctl set logical_router R3 options:lb_force_snat_ip=20.0.0.3
>
>  # Logical port 'foo1' in switch 'foo'.
>  ADD_NAMESPACES(foo1)
> @@ -1356,10 +1942,10 @@ ovn-nbctl lsp-add foo foo1 \
>
>  # Logical port 'alice1' in switch 'alice'.
>  ADD_NAMESPACES(alice1)
> -ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:04", \
> +ADD_VETH(alice1, alice1, br-int, "172.16.1.3/24", "f0:00:00:01:02:04", \
>           "172.16.1.1")
>  ovn-nbctl lsp-add alice alice1 \
> --- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2"
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.3"
>
>  # Logical port 'bar1' in switch 'bar'.
>  ADD_NAMESPACES(bar1)
> @@ -1368,22 +1954,22 @@ ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \
>  ovn-nbctl lsp-add bar bar1 \
>  -- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2"
>
> +# Logical port 'bob1' in switch 'bob'.
> +ADD_NAMESPACES(bob1)
> +ADD_VETH(bob1, bob1, br-int, "172.16.1.4/24", "f0:00:00:01:02:06", \
> +         "172.16.1.2")
> +ovn-nbctl lsp-add bob bob1 \
> +-- lsp-set-addresses bob1 "f0:00:00:01:02:06 172.16.1.4"
> +
>  # Config OVN load-balancer with a VIP.
>  uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
>  ovn-nbctl set logical_router R2 load_balancer=$uuid
> -
> -# Config OVN load-balancer with another VIP (this time with ports).
> -ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.168.2.2:80"'
> -
> -# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule.
> -ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \
> -    external_ip=30.0.0.2 -- add logical_router R2 nat @nat
> -
> +ovn-nbctl set logical_router R3 load_balancer=$uuid
>
>  # Wait for ovn-controller to catch up.
>  ovn-nbctl --wait=hv sync
>  OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> -grep 'nat(dst=192.168.2.2:80)'])
> +grep 'nat(dst=192.168.2.2)'])
>
>  # Start webservers in 'foo1', 'bar1'.
>  OVS_START_L7([foo1], [http])
> @@ -1398,23 +1984,16 @@ done
>  dnl Each server should have at least one connection.
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) |
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>  ])
>
> -dnl Test load-balancing that includes L4 ports in NAT.
> -for i in `seq 1 20`; do
> -    echo Request $i
> -    NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> -done
> -
> -dnl Each server should have at least one connection.
> -AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) |
> +dnl Force SNAT should have worked.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) |
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>  ])
> -
>  OVS_APP_EXIT_AND_WAIT([ovn-controller])
>
>  as ovn-sb
> @@ -1431,7 +2010,7 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
>  /connection dropped.*/d"])
>  AT_CLEANUP
>
> -AT_SETUP([ovn -- multiple gateway routers, load-balancing])
> +AT_SETUP([ovn -- multiple gateway routers, load-balancing - IPv6])
>  AT_KEYWORDS([ovnlb])
>
>  CHECK_CONNTRACK()
> @@ -1453,9 +2032,9 @@ start_daemon ovn-controller
>
>  # Logical network:
>  # Three LRs - R1, R2 and R3 that are connected to each other via LS "join"
> -# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and
> -# bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected
> -# to it.  R3 has bob (172.16.1.0/24) connected to it. Note how both alice and
> +# in fd20::/64 network. R1 has switchess foo (fd11::/64) and
> +# bar (fd12::/64) connected to it. R2 has alice (fd72::/64) connected
> +# to it.  R3 has bob (fd72::/64) connected to it. Note how both alice and
>  # bob have the same subnet behind it.  We are trying to simulate external
>  # network via those 2 switches. In real world the switch ports of these
>  # switches will have addresses set as "unknown" to make them learning switches.
> @@ -1476,113 +2055,115 @@ ovn-nbctl ls-add bob
>  ovn-nbctl ls-add join
>
>  # Connect foo to R1
> -ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64
>  ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
>      type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
>
>  # Connect bar to R1
> -ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64
>  ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
>      type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
>
>  # Connect alice to R2
> -ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24
> +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 fd72::1/64
>  ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
>      type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
>
>  # Connect bob to R3
> -ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 172.16.1.2/24
> +ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 fd72::2/64
>  ovn-nbctl lsp-add bob rp-bob -- set Logical_Switch_Port rp-bob \
>      type=router options:router-port=bob addresses=\"00:00:03:01:02:03\"
>
>  # Connect R1 to join
> -ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24
> +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 fd20::1/64
>  ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
>      type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"'
>
>  # Connect R2 to join
> -ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24
> +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 fd20::2/64
>  ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
>      type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
>
>  # Connect R3 to join
> -ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 20.0.0.3/24
> +ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 fd20::3/64
>  ovn-nbctl lsp-add join r3-join -- set Logical_Switch_Port r3-join \
>      type=router options:router-port=R3_join addresses='"00:00:04:01:02:05"'
>
>  # Install static routes with source ip address as the policy for routing.
>  # We want traffic from 'foo' to go via R2 and traffic of 'bar' to go via R3.
> -ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.1.0/24 20.0.0.2
> -ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.2.0/24 20.0.0.3
> +ovn-nbctl --policy="src-ip" lr-route-add R1 fd11::/64 fd20::2
> +ovn-nbctl --policy="src-ip" lr-route-add R1 fd12::/64 fd20::3
>
>  # Static routes.
> -ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1
> -ovn-nbctl lr-route-add R3 192.168.0.0/16 20.0.0.1
> +ovn-nbctl lr-route-add R2 fd11::/64 fd20::1
> +ovn-nbctl lr-route-add R2 fd12::/64 fd20::1
> +ovn-nbctl lr-route-add R3 fd11::/64 fd20::1
> +ovn-nbctl lr-route-add R3 fd12::/64 fd20::1
>
>  # For gateway routers R2 and R3, set a force SNAT rule.
> -ovn-nbctl set logical_router R2 options:lb_force_snat_ip=20.0.0.2
> -ovn-nbctl set logical_router R3 options:lb_force_snat_ip=20.0.0.3
> +ovn-nbctl set logical_router R2 options:lb_force_snat_ip=fd20::2
> +ovn-nbctl set logical_router R3 options:lb_force_snat_ip=fd20::3
>
>  # Logical port 'foo1' in switch 'foo'.
>  ADD_NAMESPACES(foo1)
> -ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
> -         "192.168.1.1")
> +ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \
> +         "fd11::1")
>  ovn-nbctl lsp-add foo foo1 \
> --- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2"
>
>  # Logical port 'alice1' in switch 'alice'.
>  ADD_NAMESPACES(alice1)
> -ADD_VETH(alice1, alice1, br-int, "172.16.1.3/24", "f0:00:00:01:02:04", \
> -         "172.16.1.1")
> +ADD_VETH(alice1, alice1, br-int, "fd72::3/64", "f0:00:00:01:02:04", \
> +         "fd72::1")
>  ovn-nbctl lsp-add alice alice1 \
> --- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.3"
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd72::3"
>
>  # Logical port 'bar1' in switch 'bar'.
>  ADD_NAMESPACES(bar1)
> -ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \
> -"192.168.2.1")
> +ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \
> +"fd12::1")
>  ovn-nbctl lsp-add bar bar1 \
> --- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2"
> +-- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2"
>
>  # Logical port 'bob1' in switch 'bob'.
>  ADD_NAMESPACES(bob1)
> -ADD_VETH(bob1, bob1, br-int, "172.16.1.4/24", "f0:00:00:01:02:06", \
> -         "172.16.1.2")
> +ADD_VETH(bob1, bob1, br-int, "fd72::4/64", "f0:00:00:01:02:06", \
> +         "fd72::2")
>  ovn-nbctl lsp-add bob bob1 \
> --- lsp-set-addresses bob1 "f0:00:00:01:02:06 172.16.1.4"
> +-- lsp-set-addresses bob1 "f0:00:00:01:02:06 fd72::4"
>
>  # Config OVN load-balancer with a VIP.
> -uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
> +uuid=`ovn-nbctl create load_balancer vips:\"fd30::1\"=\"fd11::2,fd12::2\"`
>  ovn-nbctl set logical_router R2 load_balancer=$uuid
>  ovn-nbctl set logical_router R3 load_balancer=$uuid
>
>  # Wait for ovn-controller to catch up.
>  ovn-nbctl --wait=hv sync
>  OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> -grep 'nat(dst=192.168.2.2)'])
> +grep 'nat(dst=fd12::2)'])
>
>  # Start webservers in 'foo1', 'bar1'.
> -OVS_START_L7([foo1], [http])
> -OVS_START_L7([bar1], [http])
> +OVS_START_L7([foo1], [http6])
> +OVS_START_L7([bar1], [http6])
>
>  dnl Should work with the virtual IP address through NAT
>  for i in `seq 1 20`; do
>      echo Request $i
> -    NS_CHECK_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
>  done
>
>  dnl Each server should have at least one connection.
> -AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) |
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 |
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::3,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::3,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>  ])
>
>  dnl Force SNAT should have worked.
> -AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) |
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::2) | grep -v fe80 |
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::3,dst=fd11::2,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::3,dst=fd12::2,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>  ])
>  OVS_APP_EXIT_AND_WAIT([ovn-controller])
>
> @@ -1741,6 +2322,147 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
>  /connection dropped.*/d"])
>  AT_CLEANUP
>
> +AT_SETUP([ovn -- load balancing in router with gateway router port - IPv6])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# One LR R1 with switches foo (fd01::/64), bar (fd02::/64),
> +# and alice (fd72::/64) connected to it.  The port between R1 and
> +# alice is the router gateway port where the R1 LB rules are applied.
> +#
> +#    foo -- R1 -- bar
> +#           |
> +#    alice ----
> +
> +ovn-nbctl lr-add R1
> +
> +ovn-nbctl ls-add foo
> +ovn-nbctl ls-add bar
> +ovn-nbctl ls-add alice
> +
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd01::1/64
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd02::1/64
> +ovn-nbctl lrp-add R1 alice 00:00:02:01:02:03 fd72::1/64 \
> +    -- set Logical_Router_Port alice options:redirect-chassis=hv1
> +
> +# Connect foo to R1
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo \
> +    -- lsp-set-addresses rp-foo router
> +
> +# Connect bar to R1
> +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
> +    type=router options:router-port=bar \
> +    -- lsp-set-addresses rp-bar router
> +
> +# Connect alice to R1
> +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
> +    type=router options:router-port=alice \
> +    -- lsp-set-addresses rp-alice router
> +
> +# Logical port 'foo1' in switch 'foo'.
> +ADD_NAMESPACES(foo1)
> +ADD_VETH(foo1, foo1, br-int, "fd01::2/64", "f0:00:00:01:02:03", \
> +         "fd01::1")
> +ovn-nbctl lsp-add foo foo1 \
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd01::2"
> +
> +# Logical port 'foo2' in switch 'foo'.
> +ADD_NAMESPACES(foo2)
> +ADD_VETH(foo2, foo2, br-int, "fd01::3/64", "f0:00:00:01:02:06", \
> +         "fd01::1")
> +ovn-nbctl lsp-add foo foo2 \
> +-- lsp-set-addresses foo2 "f0:00:00:01:02:06 fd01::3"
> +
> +# Logical port 'bar1' in switch 'bar'.
> +ADD_NAMESPACES(bar1)
> +ADD_VETH(bar1, bar1, br-int, "fd02::2/64", "f0:00:00:01:02:04", \
> +         "fd02::1")
> +ovn-nbctl lsp-add bar bar1 \
> +-- lsp-set-addresses bar1 "f0:00:00:01:02:04 fd02::2"
> +
> +# Logical port 'alice1' in switch 'alice'.
> +ADD_NAMESPACES(alice1)
> +ADD_VETH(alice1, alice1, br-int, "fd72::2/64", "f0:00:00:01:02:05", \
> +         "fd72::1")
> +ovn-nbctl lsp-add alice alice1 \
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:05 fd72::2"
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:\"fd72::10\"=\"fd01::2,fd02::2\"`
> +ovn-nbctl set logical_router R1 load_balancer=$uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"[[fd72::11]]:8000"'='"@<:@fd01::2@:>@:80,@<:@fd02::2@:>@:80"'
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=\[[fd02::2\]]:80)'])
> +
> +# Start webservers in 'foo1', 'bar1'.
> +OVS_START_L7([foo1], [http6])
> +OVS_START_L7([bar1], [http6])
> +
> +dnl Should work with the virtual IP address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd72::10]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::10) | grep -v fe80 |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd72::2,dst=fd72::10,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd72::10,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd72::11]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::11) | grep -v fe80 |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd72::2,dst=fd72::11,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd72::11,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/connection dropped.*/d"])
> +AT_CLEANUP
> +
>  AT_SETUP([ovn -- DNAT and SNAT on distributed router - N/S])
>  AT_KEYWORDS([ovnnat])
>
> --
> 2.23.0
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Mark Michelson Nov. 6, 2019, 6:46 p.m. UTC | #3
I pushed this to master. Thanks!

On 11/5/19 8:26 PM, Russell Bryant wrote:
> Duplicate all of the IPv4 load balancing test cases for IPv6.
> All of these are passing without any changes needed in OVN code, but
> this will help ensure that we do not have any IPv6 load balancing
> regressions in the future.
> 
> Signed-off-by: Russell Bryant <russell@ovn.org>
> ---
>   tests/system-ovn.at | 876 ++++++++++++++++++++++++++++++++++++++++----
>   1 file changed, 799 insertions(+), 77 deletions(-)
> 
> v1 -> v2:
>   - Use [[ and ]] instead of quadigraphs to enhance readability,
>     as suggested by Ben Pfaff
> 
> 
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index b3f90aae2..5885df58e 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -1158,6 +1158,153 @@ tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(s
>   ])
>   
>   
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- load-balancing - IPv6])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# 2 logical switches "foo" (fd01::/64) and "bar" (fd02::/64)
> +# connected to a router R1.
> +# foo has foo1 to act as a client.
> +# bar has bar1, bar2, bar3 to act as servers.
> +#
> +# Loadbalancer VIPs in fd03::/64 network.
> +
> +ovn-nbctl create Logical_Router name=R1
> +ovn-nbctl ls-add foo
> +ovn-nbctl ls-add bar
> +
> +# Connect foo to R1
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd01::1/64
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
> +
> +# Connect bar to R1
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd02::1/64
> +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
> +    type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
> +
> +# Create logical port 'foo1' in switch 'foo'.
> +ADD_NAMESPACES(foo1)
> +ADD_VETH(foo1, foo1, br-int, "fd01::2/64", "f0:00:00:01:02:03", \
> +         "fd01::1")
> +ovn-nbctl lsp-add foo foo1 \
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd01::2"
> +
> +# Create logical ports 'bar1', 'bar2', 'bar3' in switch 'bar'.
> +ADD_NAMESPACES(bar1)
> +ADD_VETH(bar1, bar1, br-int, "fd02::2/64", "f0:00:0f:01:02:03", \
> +         "fd02::1")
> +ovn-nbctl lsp-add bar bar1 \
> +-- lsp-set-addresses bar1 "f0:00:0f:01:02:03 fd02::2"
> +
> +ADD_NAMESPACES(bar2)
> +ADD_VETH(bar2, bar2, br-int, "fd02::3/64", "f0:00:0f:01:02:04", \
> +         "fd02::1")
> +ovn-nbctl lsp-add bar bar2 \
> +-- lsp-set-addresses bar2 "f0:00:0f:01:02:04 fd02::3"
> +
> +ADD_NAMESPACES(bar3)
> +ADD_VETH(bar3, bar3, br-int, "fd02::4/64", "f0:00:0f:01:02:05", \
> +         "fd02::1")
> +ovn-nbctl lsp-add bar bar3 \
> +-- lsp-set-addresses bar3 "f0:00:0f:01:02:05 fd02::4"
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:\"fd03::1\"=\"fd02::2,fd02::3,fd02::4\"`
> +ovn-nbctl set logical_switch foo load_balancer=$uuid
> +
> +# Create another load-balancer with another VIP.
> +uuid=`ovn-nbctl create load_balancer vips:\"fd03::3\"=\"fd02::2,fd02::3,fd02::4\"`
> +ovn-nbctl add logical_switch foo load_balancer $uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd02::2@:>@:80,@<:@fd02::3@:>@:80,@<:@fd02::4@:>@:80"'
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=\[[fd02::4\]]:80)'])
> +
> +# Start webservers in 'bar1', 'bar2' and 'bar3'.
> +OVS_START_L7([bar1], [http6])
> +OVS_START_L7([bar2], [http6])
> +OVS_START_L7([bar3], [http6])
> +
> +dnl Should work with the virtual IP fd03::1 address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log || (ovs-ofctl -O OpenFlow13 dump-flows br-int && false)])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Should work with the virtual IP fd03::3 address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::3]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::3) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::3,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::3,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::3,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +
>   OVS_APP_EXIT_AND_WAIT([ovn-controller])
>   
>   as ovn-sb
> @@ -1253,18 +1400,431 @@ tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(s
>   dnl Test load-balancing that includes L4 ports in NAT.
>   for i in `seq 1 20`; do
>       echo Request $i
> -    NS_CHECK_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +    NS_CHECK_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.5,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- load-balancing - same subnet. - IPv6])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# 1 logical switch "foo" (fd01::/64) connected to router R1.
> +# foo has foo1, foo2, foo3, foo4 as logical ports.
> +#
> +# Loadbalancer VIPs in fd03::/64 network. Router is needed for default
> +# gateway. We will test load-balancing with foo1 as a client and foo2, foo3 and
> +# foo4 as servers.
> +
> +ovn-nbctl create Logical_Router name=R1
> +ovn-nbctl ls-add foo
> +
> +# Connect foo to R1
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd01::1/64
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
> +
> +# Create logical port 'foo1', 'foo2', 'foo3' and 'foo4' in switch 'foo'.
> +ADD_NAMESPACES(foo1, foo2, foo3, foo4)
> +for i in `seq 1 4`; do
> +    j=`expr $i + 1`
> +    ADD_VETH(foo$i, foo$i, br-int, "fd01::$j/64", "f0:00:00:01:02:0$j", \
> +             "fd01::1")
> +    ovn-nbctl lsp-add foo foo$i \
> +        -- lsp-set-addresses foo$i "f0:00:00:01:02:0$j fd01::$j"
> +done
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:\"fd03::1\"=\"fd01::3,fd01::4,fd01::5\"`
> +ovn-nbctl set logical_switch foo load_balancer=$uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd01::3@:>@:80,@<:@fd01::4@:>@:80,@<:@fd01::5@:>@:80"'
> +
> +ovn-nbctl list load_balancer
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=\[[fd01::5\]]:80)'])
> +
> +# Start webservers in 'foo2', 'foo3' and 'foo4'.
> +OVS_START_L7([foo2], [http6])
> +OVS_START_L7([foo3], [http6])
> +OVS_START_L7([foo4], [http6])
> +
> +dnl Should work with the virtual IP address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd01::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd01::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd01::5,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::5,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- load balancing in gateway router])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# Two LRs - R1 and R2 that are connected to each other via LS "join"
> +# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and
> +# bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected
> +# to it.  R2 is a gateway router on which we add load-balancing rules.
> +#
> +#    foo -- R1 -- join - R2 -- alice
> +#           |
> +#    bar ----
> +
> +ovn-nbctl create Logical_Router name=R1
> +ovn-nbctl create Logical_Router name=R2 options:chassis=hv1
> +
> +ovn-nbctl ls-add foo
> +ovn-nbctl ls-add bar
> +ovn-nbctl ls-add alice
> +ovn-nbctl ls-add join
> +
> +# Connect foo to R1
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
> +
> +# Connect bar to R1
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24
> +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
> +    type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
> +
> +# Connect alice to R2
> +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24
> +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
> +    type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
> +
> +# Connect R1 to join
> +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24
> +ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
> +    type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"'
> +
> +# Connect R2 to join
> +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24
> +ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
> +    type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
> +
> +# Static routes.
> +ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2
> +ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1
> +
> +# Logical port 'foo1' in switch 'foo'.
> +ADD_NAMESPACES(foo1)
> +ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
> +         "192.168.1.1")
> +ovn-nbctl lsp-add foo foo1 \
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
> +
> +# Logical port 'alice1' in switch 'alice'.
> +ADD_NAMESPACES(alice1)
> +ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:04", \
> +         "172.16.1.1")
> +ovn-nbctl lsp-add alice alice1 \
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2"
> +
> +# Logical port 'bar1' in switch 'bar'.
> +ADD_NAMESPACES(bar1)
> +ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \
> +"192.168.2.1")
> +ovn-nbctl lsp-add bar bar1 \
> +-- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2"
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
> +ovn-nbctl set logical_router R2 load_balancer=$uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.168.2.2:80"'
> +
> +# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule.
> +ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \
> +    external_ip=30.0.0.2 -- add logical_router R2 nat @nat
> +
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=192.168.2.2:80)'])
> +
> +# Start webservers in 'foo1', 'bar1'.
> +OVS_START_L7([foo1], [http])
> +OVS_START_L7([bar1], [http])
> +
> +dnl Should work with the virtual IP address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/connection dropped.*/d"])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- load balancing in gateway router - IPv6])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# Two LRs - R1 and R2 that are connected to each other via LS "join"
> +# in fd20::/64 network. R1 has switchess foo (fd11::/64) and
> +# bar (fd12::/64) connected to it. R2 has alice (fd72::/64) connected
> +# to it.  R2 is a gateway router on which we add load-balancing rules.
> +#
> +#    foo -- R1 -- join - R2 -- alice
> +#           |
> +#    bar ----
> +
> +ovn-nbctl create Logical_Router name=R1
> +ovn-nbctl create Logical_Router name=R2 options:chassis=hv1
> +
> +ovn-nbctl ls-add foo
> +ovn-nbctl ls-add bar
> +ovn-nbctl ls-add alice
> +ovn-nbctl ls-add join
> +
> +# Connect foo to R1
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
> +
> +# Connect bar to R1
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64
> +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
> +    type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
> +
> +# Connect alice to R2
> +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 fd72::1/64
> +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
> +    type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
> +
> +# Connect R1 to join
> +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 fd20::1/64
> +ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
> +    type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"'
> +
> +# Connect R2 to join
> +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 fd20::2/64
> +ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
> +    type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
> +
> +# Static routes.
> +ovn-nbctl lr-route-add R1 fd72::/64 fd20::2
> +ovn-nbctl lr-route-add R2 fd11::/64 fd20::1
> +ovn-nbctl lr-route-add R2 fd12::/64 fd20::1
> +
> +# Logical port 'foo1' in switch 'foo'.
> +ADD_NAMESPACES(foo1)
> +ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \
> +         "fd11::1")
> +ovn-nbctl lsp-add foo foo1 \
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2"
> +
> +# Logical port 'alice1' in switch 'alice'.
> +ADD_NAMESPACES(alice1)
> +ADD_VETH(alice1, alice1, br-int, "fd72::2/64", "f0:00:00:01:02:04", \
> +         "fd72::1")
> +ovn-nbctl lsp-add alice alice1 \
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd72::2"
> +
> +# Logical port 'bar1' in switch 'bar'.
> +ADD_NAMESPACES(bar1)
> +ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \
> +"fd12::1")
> +ovn-nbctl lsp-add bar bar1 \
> +-- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2"
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:\"fd30::1\"=\"fd11::2,fd12::2\"`
> +ovn-nbctl set logical_router R2 load_balancer=$uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"[[fd30::2]]:8000"'='"@<:@fd11::2@:>@:80,@<:@fd12::2@:>@:80"'
> +
> +ovn-nbctl list load_balancer
> +
> +# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule.
> +ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=\"fd12::2\" \
> +    external_ip=\"fd30::2\" -- add logical_router R2 nat @nat
> +
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=\[[fd12::2\]]:80)'])
> +
> +# Start webservers in 'foo1', 'bar1'.
> +OVS_START_L7([foo1], [http6])
> +OVS_START_L7([bar1], [http6])
> +
> +dnl Should work with the virtual IP address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd72::2,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd30::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
>   done
>   
>   dnl Each server should have at least one connection.
> -AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::2) | grep -v fe80 |
>   sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.5,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd30::2,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd30::2,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>   ])
>   
> -
>   OVS_APP_EXIT_AND_WAIT([ovn-controller])
>   
>   as ovn-sb
> @@ -1277,10 +1837,11 @@ as northd
>   OVS_APP_EXIT_AND_WAIT([ovn-northd])
>   
>   as
> -OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/connection dropped.*/d"])
>   AT_CLEANUP
>   
> -AT_SETUP([ovn -- load balancing in gateway router])
> +AT_SETUP([ovn -- multiple gateway routers, load-balancing])
>   AT_KEYWORDS([ovnlb])
>   
>   CHECK_CONNTRACK()
> @@ -1301,21 +1862,27 @@ ovs-vsctl \
>   start_daemon ovn-controller
>   
>   # Logical network:
> -# Two LRs - R1 and R2 that are connected to each other via LS "join"
> +# Three LRs - R1, R2 and R3 that are connected to each other via LS "join"
>   # in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and
>   # bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected
> -# to it.  R2 is a gateway router on which we add load-balancing rules.
> +# to it.  R3 has bob (172.16.1.0/24) connected to it. Note how both alice and
> +# bob have the same subnet behind it.  We are trying to simulate external
> +# network via those 2 switches. In real world the switch ports of these
> +# switches will have addresses set as "unknown" to make them learning switches.
> +# Or those switches will be "localnet" ones.
>   #
>   #    foo -- R1 -- join - R2 -- alice
> -#           |
> -#    bar ----
> +#           |          |
> +#    bar ----          - R3 --- bob
>   
>   ovn-nbctl create Logical_Router name=R1
>   ovn-nbctl create Logical_Router name=R2 options:chassis=hv1
> +ovn-nbctl create Logical_Router name=R3 options:chassis=hv1
>   
>   ovn-nbctl ls-add foo
>   ovn-nbctl ls-add bar
>   ovn-nbctl ls-add alice
> +ovn-nbctl ls-add bob
>   ovn-nbctl ls-add join
>   
>   # Connect foo to R1
> @@ -1333,6 +1900,11 @@ ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24
>   ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
>       type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
>   
> +# Connect bob to R3
> +ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 172.16.1.2/24
> +ovn-nbctl lsp-add bob rp-bob -- set Logical_Switch_Port rp-bob \
> +    type=router options:router-port=bob addresses=\"00:00:03:01:02:03\"
> +
>   # Connect R1 to join
>   ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24
>   ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
> @@ -1343,9 +1915,23 @@ ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24
>   ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
>       type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
>   
> +# Connect R3 to join
> +ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 20.0.0.3/24
> +ovn-nbctl lsp-add join r3-join -- set Logical_Switch_Port r3-join \
> +    type=router options:router-port=R3_join addresses='"00:00:04:01:02:05"'
> +
> +# Install static routes with source ip address as the policy for routing.
> +# We want traffic from 'foo' to go via R2 and traffic of 'bar' to go via R3.
> +ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.1.0/24 20.0.0.2
> +ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.2.0/24 20.0.0.3
> +
>   # Static routes.
> -ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2
>   ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1
> +ovn-nbctl lr-route-add R3 192.168.0.0/16 20.0.0.1
> +
> +# For gateway routers R2 and R3, set a force SNAT rule.
> +ovn-nbctl set logical_router R2 options:lb_force_snat_ip=20.0.0.2
> +ovn-nbctl set logical_router R3 options:lb_force_snat_ip=20.0.0.3
>   
>   # Logical port 'foo1' in switch 'foo'.
>   ADD_NAMESPACES(foo1)
> @@ -1356,10 +1942,10 @@ ovn-nbctl lsp-add foo foo1 \
>   
>   # Logical port 'alice1' in switch 'alice'.
>   ADD_NAMESPACES(alice1)
> -ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:04", \
> +ADD_VETH(alice1, alice1, br-int, "172.16.1.3/24", "f0:00:00:01:02:04", \
>            "172.16.1.1")
>   ovn-nbctl lsp-add alice alice1 \
> --- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2"
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.3"
>   
>   # Logical port 'bar1' in switch 'bar'.
>   ADD_NAMESPACES(bar1)
> @@ -1368,22 +1954,22 @@ ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \
>   ovn-nbctl lsp-add bar bar1 \
>   -- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2"
>   
> +# Logical port 'bob1' in switch 'bob'.
> +ADD_NAMESPACES(bob1)
> +ADD_VETH(bob1, bob1, br-int, "172.16.1.4/24", "f0:00:00:01:02:06", \
> +         "172.16.1.2")
> +ovn-nbctl lsp-add bob bob1 \
> +-- lsp-set-addresses bob1 "f0:00:00:01:02:06 172.16.1.4"
> +
>   # Config OVN load-balancer with a VIP.
>   uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
>   ovn-nbctl set logical_router R2 load_balancer=$uuid
> -
> -# Config OVN load-balancer with another VIP (this time with ports).
> -ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.168.2.2:80"'
> -
> -# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule.
> -ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \
> -    external_ip=30.0.0.2 -- add logical_router R2 nat @nat
> -
> +ovn-nbctl set logical_router R3 load_balancer=$uuid
>   
>   # Wait for ovn-controller to catch up.
>   ovn-nbctl --wait=hv sync
>   OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> -grep 'nat(dst=192.168.2.2:80)'])
> +grep 'nat(dst=192.168.2.2)'])
>   
>   # Start webservers in 'foo1', 'bar1'.
>   OVS_START_L7([foo1], [http])
> @@ -1398,23 +1984,16 @@ done
>   dnl Each server should have at least one connection.
>   AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) |
>   sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>   ])
>   
> -dnl Test load-balancing that includes L4 ports in NAT.
> -for i in `seq 1 20`; do
> -    echo Request $i
> -    NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> -done
> -
> -dnl Each server should have at least one connection.
> -AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) |
> +dnl Force SNAT should have worked.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) |
>   sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>   ])
> -
>   OVS_APP_EXIT_AND_WAIT([ovn-controller])
>   
>   as ovn-sb
> @@ -1431,7 +2010,7 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
>   /connection dropped.*/d"])
>   AT_CLEANUP
>   
> -AT_SETUP([ovn -- multiple gateway routers, load-balancing])
> +AT_SETUP([ovn -- multiple gateway routers, load-balancing - IPv6])
>   AT_KEYWORDS([ovnlb])
>   
>   CHECK_CONNTRACK()
> @@ -1453,9 +2032,9 @@ start_daemon ovn-controller
>   
>   # Logical network:
>   # Three LRs - R1, R2 and R3 that are connected to each other via LS "join"
> -# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and
> -# bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected
> -# to it.  R3 has bob (172.16.1.0/24) connected to it. Note how both alice and
> +# in fd20::/64 network. R1 has switchess foo (fd11::/64) and
> +# bar (fd12::/64) connected to it. R2 has alice (fd72::/64) connected
> +# to it.  R3 has bob (fd72::/64) connected to it. Note how both alice and
>   # bob have the same subnet behind it.  We are trying to simulate external
>   # network via those 2 switches. In real world the switch ports of these
>   # switches will have addresses set as "unknown" to make them learning switches.
> @@ -1476,113 +2055,115 @@ ovn-nbctl ls-add bob
>   ovn-nbctl ls-add join
>   
>   # Connect foo to R1
> -ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64
>   ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
>       type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
>   
>   # Connect bar to R1
> -ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64
>   ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
>       type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
>   
>   # Connect alice to R2
> -ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24
> +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 fd72::1/64
>   ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
>       type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
>   
>   # Connect bob to R3
> -ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 172.16.1.2/24
> +ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 fd72::2/64
>   ovn-nbctl lsp-add bob rp-bob -- set Logical_Switch_Port rp-bob \
>       type=router options:router-port=bob addresses=\"00:00:03:01:02:03\"
>   
>   # Connect R1 to join
> -ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24
> +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 fd20::1/64
>   ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
>       type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"'
>   
>   # Connect R2 to join
> -ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24
> +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 fd20::2/64
>   ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
>       type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
>   
>   # Connect R3 to join
> -ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 20.0.0.3/24
> +ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 fd20::3/64
>   ovn-nbctl lsp-add join r3-join -- set Logical_Switch_Port r3-join \
>       type=router options:router-port=R3_join addresses='"00:00:04:01:02:05"'
>   
>   # Install static routes with source ip address as the policy for routing.
>   # We want traffic from 'foo' to go via R2 and traffic of 'bar' to go via R3.
> -ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.1.0/24 20.0.0.2
> -ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.2.0/24 20.0.0.3
> +ovn-nbctl --policy="src-ip" lr-route-add R1 fd11::/64 fd20::2
> +ovn-nbctl --policy="src-ip" lr-route-add R1 fd12::/64 fd20::3
>   
>   # Static routes.
> -ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1
> -ovn-nbctl lr-route-add R3 192.168.0.0/16 20.0.0.1
> +ovn-nbctl lr-route-add R2 fd11::/64 fd20::1
> +ovn-nbctl lr-route-add R2 fd12::/64 fd20::1
> +ovn-nbctl lr-route-add R3 fd11::/64 fd20::1
> +ovn-nbctl lr-route-add R3 fd12::/64 fd20::1
>   
>   # For gateway routers R2 and R3, set a force SNAT rule.
> -ovn-nbctl set logical_router R2 options:lb_force_snat_ip=20.0.0.2
> -ovn-nbctl set logical_router R3 options:lb_force_snat_ip=20.0.0.3
> +ovn-nbctl set logical_router R2 options:lb_force_snat_ip=fd20::2
> +ovn-nbctl set logical_router R3 options:lb_force_snat_ip=fd20::3
>   
>   # Logical port 'foo1' in switch 'foo'.
>   ADD_NAMESPACES(foo1)
> -ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
> -         "192.168.1.1")
> +ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \
> +         "fd11::1")
>   ovn-nbctl lsp-add foo foo1 \
> --- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2"
>   
>   # Logical port 'alice1' in switch 'alice'.
>   ADD_NAMESPACES(alice1)
> -ADD_VETH(alice1, alice1, br-int, "172.16.1.3/24", "f0:00:00:01:02:04", \
> -         "172.16.1.1")
> +ADD_VETH(alice1, alice1, br-int, "fd72::3/64", "f0:00:00:01:02:04", \
> +         "fd72::1")
>   ovn-nbctl lsp-add alice alice1 \
> --- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.3"
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd72::3"
>   
>   # Logical port 'bar1' in switch 'bar'.
>   ADD_NAMESPACES(bar1)
> -ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \
> -"192.168.2.1")
> +ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \
> +"fd12::1")
>   ovn-nbctl lsp-add bar bar1 \
> --- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2"
> +-- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2"
>   
>   # Logical port 'bob1' in switch 'bob'.
>   ADD_NAMESPACES(bob1)
> -ADD_VETH(bob1, bob1, br-int, "172.16.1.4/24", "f0:00:00:01:02:06", \
> -         "172.16.1.2")
> +ADD_VETH(bob1, bob1, br-int, "fd72::4/64", "f0:00:00:01:02:06", \
> +         "fd72::2")
>   ovn-nbctl lsp-add bob bob1 \
> --- lsp-set-addresses bob1 "f0:00:00:01:02:06 172.16.1.4"
> +-- lsp-set-addresses bob1 "f0:00:00:01:02:06 fd72::4"
>   
>   # Config OVN load-balancer with a VIP.
> -uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
> +uuid=`ovn-nbctl create load_balancer vips:\"fd30::1\"=\"fd11::2,fd12::2\"`
>   ovn-nbctl set logical_router R2 load_balancer=$uuid
>   ovn-nbctl set logical_router R3 load_balancer=$uuid
>   
>   # Wait for ovn-controller to catch up.
>   ovn-nbctl --wait=hv sync
>   OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> -grep 'nat(dst=192.168.2.2)'])
> +grep 'nat(dst=fd12::2)'])
>   
>   # Start webservers in 'foo1', 'bar1'.
> -OVS_START_L7([foo1], [http])
> -OVS_START_L7([bar1], [http])
> +OVS_START_L7([foo1], [http6])
> +OVS_START_L7([bar1], [http6])
>   
>   dnl Should work with the virtual IP address through NAT
>   for i in `seq 1 20`; do
>       echo Request $i
> -    NS_CHECK_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
>   done
>   
>   dnl Each server should have at least one connection.
> -AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) |
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 |
>   sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::3,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::3,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>   ])
>   
>   dnl Force SNAT should have worked.
> -AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) |
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::2) | grep -v fe80 |
>   sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> -tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> -tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::3,dst=fd11::2,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::3,dst=fd12::2,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>   ])
>   OVS_APP_EXIT_AND_WAIT([ovn-controller])
>   
> @@ -1741,6 +2322,147 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
>   /connection dropped.*/d"])
>   AT_CLEANUP
>   
> +AT_SETUP([ovn -- load balancing in router with gateway router port - IPv6])
> +AT_KEYWORDS([ovnlb])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# One LR R1 with switches foo (fd01::/64), bar (fd02::/64),
> +# and alice (fd72::/64) connected to it.  The port between R1 and
> +# alice is the router gateway port where the R1 LB rules are applied.
> +#
> +#    foo -- R1 -- bar
> +#           |
> +#    alice ----
> +
> +ovn-nbctl lr-add R1
> +
> +ovn-nbctl ls-add foo
> +ovn-nbctl ls-add bar
> +ovn-nbctl ls-add alice
> +
> +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd01::1/64
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd02::1/64
> +ovn-nbctl lrp-add R1 alice 00:00:02:01:02:03 fd72::1/64 \
> +    -- set Logical_Router_Port alice options:redirect-chassis=hv1
> +
> +# Connect foo to R1
> +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> +    type=router options:router-port=foo \
> +    -- lsp-set-addresses rp-foo router
> +
> +# Connect bar to R1
> +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
> +    type=router options:router-port=bar \
> +    -- lsp-set-addresses rp-bar router
> +
> +# Connect alice to R1
> +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
> +    type=router options:router-port=alice \
> +    -- lsp-set-addresses rp-alice router
> +
> +# Logical port 'foo1' in switch 'foo'.
> +ADD_NAMESPACES(foo1)
> +ADD_VETH(foo1, foo1, br-int, "fd01::2/64", "f0:00:00:01:02:03", \
> +         "fd01::1")
> +ovn-nbctl lsp-add foo foo1 \
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd01::2"
> +
> +# Logical port 'foo2' in switch 'foo'.
> +ADD_NAMESPACES(foo2)
> +ADD_VETH(foo2, foo2, br-int, "fd01::3/64", "f0:00:00:01:02:06", \
> +         "fd01::1")
> +ovn-nbctl lsp-add foo foo2 \
> +-- lsp-set-addresses foo2 "f0:00:00:01:02:06 fd01::3"
> +
> +# Logical port 'bar1' in switch 'bar'.
> +ADD_NAMESPACES(bar1)
> +ADD_VETH(bar1, bar1, br-int, "fd02::2/64", "f0:00:00:01:02:04", \
> +         "fd02::1")
> +ovn-nbctl lsp-add bar bar1 \
> +-- lsp-set-addresses bar1 "f0:00:00:01:02:04 fd02::2"
> +
> +# Logical port 'alice1' in switch 'alice'.
> +ADD_NAMESPACES(alice1)
> +ADD_VETH(alice1, alice1, br-int, "fd72::2/64", "f0:00:00:01:02:05", \
> +         "fd72::1")
> +ovn-nbctl lsp-add alice alice1 \
> +-- lsp-set-addresses alice1 "f0:00:00:01:02:05 fd72::2"
> +
> +# Config OVN load-balancer with a VIP.
> +uuid=`ovn-nbctl  create load_balancer vips:\"fd72::10\"=\"fd01::2,fd02::2\"`
> +ovn-nbctl set logical_router R1 load_balancer=$uuid
> +
> +# Config OVN load-balancer with another VIP (this time with ports).
> +ovn-nbctl set load_balancer $uuid vips:'"[[fd72::11]]:8000"'='"@<:@fd01::2@:>@:80,@<:@fd02::2@:>@:80"'
> +
> +# Wait for ovn-controller to catch up.
> +ovn-nbctl --wait=hv sync
> +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
> +grep 'nat(dst=\[[fd02::2\]]:80)'])
> +
> +# Start webservers in 'foo1', 'bar1'.
> +OVS_START_L7([foo1], [http6])
> +OVS_START_L7([bar1], [http6])
> +
> +dnl Should work with the virtual IP address through NAT
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd72::10]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::10) | grep -v fe80 |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd72::2,dst=fd72::10,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd72::10,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test load-balancing that includes L4 ports in NAT.
> +for i in `seq 1 20`; do
> +    echo Request $i
> +    NS_CHECK_EXEC([alice1], [wget http://[[fd72::11]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
> +done
> +
> +dnl Each server should have at least one connection.
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::11) | grep -v fe80 |
> +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
> +tcp,orig=(src=fd72::2,dst=fd72::11,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +tcp,orig=(src=fd72::2,dst=fd72::11,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
> +])
> +
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/connection dropped.*/d"])
> +AT_CLEANUP
> +
>   AT_SETUP([ovn -- DNAT and SNAT on distributed router - N/S])
>   AT_KEYWORDS([ovnnat])
>   
>

Patch
diff mbox series

diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index b3f90aae2..5885df58e 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -1158,6 +1158,153 @@  tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(s
 ])
 
 
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+as ovn-sb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as ovn-nb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as northd
+OVS_APP_EXIT_AND_WAIT([ovn-northd])
+
+as
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
+AT_CLEANUP
+
+AT_SETUP([ovn -- load-balancing - IPv6])
+AT_KEYWORDS([ovnlb])
+
+CHECK_CONNTRACK()
+CHECK_CONNTRACK_NAT()
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+
+# Set external-ids in br-int needed for ovn-controller
+ovs-vsctl \
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
+
+# Start ovn-controller
+start_daemon ovn-controller
+
+# Logical network:
+# 2 logical switches "foo" (fd01::/64) and "bar" (fd02::/64)
+# connected to a router R1.
+# foo has foo1 to act as a client.
+# bar has bar1, bar2, bar3 to act as servers.
+#
+# Loadbalancer VIPs in fd03::/64 network.
+
+ovn-nbctl create Logical_Router name=R1
+ovn-nbctl ls-add foo
+ovn-nbctl ls-add bar
+
+# Connect foo to R1
+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd01::1/64
+ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
+    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
+
+# Connect bar to R1
+ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd02::1/64
+ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
+    type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
+
+# Create logical port 'foo1' in switch 'foo'.
+ADD_NAMESPACES(foo1)
+ADD_VETH(foo1, foo1, br-int, "fd01::2/64", "f0:00:00:01:02:03", \
+         "fd01::1")
+ovn-nbctl lsp-add foo foo1 \
+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd01::2"
+
+# Create logical ports 'bar1', 'bar2', 'bar3' in switch 'bar'.
+ADD_NAMESPACES(bar1)
+ADD_VETH(bar1, bar1, br-int, "fd02::2/64", "f0:00:0f:01:02:03", \
+         "fd02::1")
+ovn-nbctl lsp-add bar bar1 \
+-- lsp-set-addresses bar1 "f0:00:0f:01:02:03 fd02::2"
+
+ADD_NAMESPACES(bar2)
+ADD_VETH(bar2, bar2, br-int, "fd02::3/64", "f0:00:0f:01:02:04", \
+         "fd02::1")
+ovn-nbctl lsp-add bar bar2 \
+-- lsp-set-addresses bar2 "f0:00:0f:01:02:04 fd02::3"
+
+ADD_NAMESPACES(bar3)
+ADD_VETH(bar3, bar3, br-int, "fd02::4/64", "f0:00:0f:01:02:05", \
+         "fd02::1")
+ovn-nbctl lsp-add bar bar3 \
+-- lsp-set-addresses bar3 "f0:00:0f:01:02:05 fd02::4"
+
+# Config OVN load-balancer with a VIP.
+uuid=`ovn-nbctl  create load_balancer vips:\"fd03::1\"=\"fd02::2,fd02::3,fd02::4\"`
+ovn-nbctl set logical_switch foo load_balancer=$uuid
+
+# Create another load-balancer with another VIP.
+uuid=`ovn-nbctl create load_balancer vips:\"fd03::3\"=\"fd02::2,fd02::3,fd02::4\"`
+ovn-nbctl add logical_switch foo load_balancer $uuid
+
+# Config OVN load-balancer with another VIP (this time with ports).
+ovn-nbctl set load_balancer $uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd02::2@:>@:80,@<:@fd02::3@:>@:80,@<:@fd02::4@:>@:80"'
+
+# Wait for ovn-controller to catch up.
+ovn-nbctl --wait=hv sync
+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
+grep 'nat(dst=\[[fd02::4\]]:80)'])
+
+# Start webservers in 'bar1', 'bar2' and 'bar3'.
+OVS_START_L7([bar1], [http6])
+OVS_START_L7([bar2], [http6])
+OVS_START_L7([bar3], [http6])
+
+dnl Should work with the virtual IP fd03::1 address through NAT
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log || (ovs-ofctl -O OpenFlow13 dump-flows br-int && false)])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+dnl Should work with the virtual IP fd03::3 address through NAT
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([foo1], [wget http://[[fd03::3]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::3) | grep -v fe80 | \
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=fd01::2,dst=fd03::3,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::3,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::3,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+dnl Test load-balancing that includes L4 ports in NAT.
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+
 OVS_APP_EXIT_AND_WAIT([ovn-controller])
 
 as ovn-sb
@@ -1253,18 +1400,431 @@  tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(s
 dnl Test load-balancing that includes L4 ports in NAT.
 for i in `seq 1 20`; do
     echo Request $i
-    NS_CHECK_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+    NS_CHECK_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.5,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+as ovn-sb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as ovn-nb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as northd
+OVS_APP_EXIT_AND_WAIT([ovn-northd])
+
+as
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
+AT_CLEANUP
+
+AT_SETUP([ovn -- load-balancing - same subnet. - IPv6])
+AT_KEYWORDS([ovnlb])
+
+CHECK_CONNTRACK()
+CHECK_CONNTRACK_NAT()
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+
+# Set external-ids in br-int needed for ovn-controller
+ovs-vsctl \
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
+
+# Start ovn-controller
+start_daemon ovn-controller
+
+# Logical network:
+# 1 logical switch "foo" (fd01::/64) connected to router R1.
+# foo has foo1, foo2, foo3, foo4 as logical ports.
+#
+# Loadbalancer VIPs in fd03::/64 network. Router is needed for default
+# gateway. We will test load-balancing with foo1 as a client and foo2, foo3 and
+# foo4 as servers.
+
+ovn-nbctl create Logical_Router name=R1
+ovn-nbctl ls-add foo
+
+# Connect foo to R1
+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd01::1/64
+ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
+    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
+
+# Create logical port 'foo1', 'foo2', 'foo3' and 'foo4' in switch 'foo'.
+ADD_NAMESPACES(foo1, foo2, foo3, foo4)
+for i in `seq 1 4`; do
+    j=`expr $i + 1`
+    ADD_VETH(foo$i, foo$i, br-int, "fd01::$j/64", "f0:00:00:01:02:0$j", \
+             "fd01::1")
+    ovn-nbctl lsp-add foo foo$i \
+        -- lsp-set-addresses foo$i "f0:00:00:01:02:0$j fd01::$j"
+done
+
+# Config OVN load-balancer with a VIP.
+uuid=`ovn-nbctl  create load_balancer vips:\"fd03::1\"=\"fd01::3,fd01::4,fd01::5\"`
+ovn-nbctl set logical_switch foo load_balancer=$uuid
+
+# Config OVN load-balancer with another VIP (this time with ports).
+ovn-nbctl set load_balancer $uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd01::3@:>@:80,@<:@fd01::4@:>@:80,@<:@fd01::5@:>@:80"'
+
+ovn-nbctl list load_balancer
+
+# Wait for ovn-controller to catch up.
+ovn-nbctl --wait=hv sync
+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
+grep 'nat(dst=\[[fd01::5\]]:80)'])
+
+# Start webservers in 'foo2', 'foo3' and 'foo4'.
+OVS_START_L7([foo2], [http6])
+OVS_START_L7([foo3], [http6])
+OVS_START_L7([foo4], [http6])
+
+dnl Should work with the virtual IP address through NAT
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd01::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd01::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::1,sport=<cleared>,dport=<cleared>),reply=(src=fd01::5,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+dnl Test load-balancing that includes L4 ports in NAT.
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::5,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+as ovn-sb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as ovn-nb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as northd
+OVS_APP_EXIT_AND_WAIT([ovn-northd])
+
+as
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
+AT_CLEANUP
+
+AT_SETUP([ovn -- load balancing in gateway router])
+AT_KEYWORDS([ovnlb])
+
+CHECK_CONNTRACK()
+CHECK_CONNTRACK_NAT()
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+
+# Set external-ids in br-int needed for ovn-controller
+ovs-vsctl \
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
+
+# Start ovn-controller
+start_daemon ovn-controller
+
+# Logical network:
+# Two LRs - R1 and R2 that are connected to each other via LS "join"
+# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and
+# bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected
+# to it.  R2 is a gateway router on which we add load-balancing rules.
+#
+#    foo -- R1 -- join - R2 -- alice
+#           |
+#    bar ----
+
+ovn-nbctl create Logical_Router name=R1
+ovn-nbctl create Logical_Router name=R2 options:chassis=hv1
+
+ovn-nbctl ls-add foo
+ovn-nbctl ls-add bar
+ovn-nbctl ls-add alice
+ovn-nbctl ls-add join
+
+# Connect foo to R1
+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
+ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
+    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
+
+# Connect bar to R1
+ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24
+ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
+    type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
+
+# Connect alice to R2
+ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24
+ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
+    type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
+
+# Connect R1 to join
+ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24
+ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
+    type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"'
+
+# Connect R2 to join
+ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24
+ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
+    type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
+
+# Static routes.
+ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2
+ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1
+
+# Logical port 'foo1' in switch 'foo'.
+ADD_NAMESPACES(foo1)
+ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
+         "192.168.1.1")
+ovn-nbctl lsp-add foo foo1 \
+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
+
+# Logical port 'alice1' in switch 'alice'.
+ADD_NAMESPACES(alice1)
+ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:04", \
+         "172.16.1.1")
+ovn-nbctl lsp-add alice alice1 \
+-- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2"
+
+# Logical port 'bar1' in switch 'bar'.
+ADD_NAMESPACES(bar1)
+ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \
+"192.168.2.1")
+ovn-nbctl lsp-add bar bar1 \
+-- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2"
+
+# Config OVN load-balancer with a VIP.
+uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
+ovn-nbctl set logical_router R2 load_balancer=$uuid
+
+# Config OVN load-balancer with another VIP (this time with ports).
+ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.168.2.2:80"'
+
+# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule.
+ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \
+    external_ip=30.0.0.2 -- add logical_router R2 nat @nat
+
+
+# Wait for ovn-controller to catch up.
+ovn-nbctl --wait=hv sync
+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
+grep 'nat(dst=192.168.2.2:80)'])
+
+# Start webservers in 'foo1', 'bar1'.
+OVS_START_L7([foo1], [http])
+OVS_START_L7([bar1], [http])
+
+dnl Should work with the virtual IP address through NAT
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) |
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+dnl Test load-balancing that includes L4 ports in NAT.
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) |
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+as ovn-sb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as ovn-nb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as northd
+OVS_APP_EXIT_AND_WAIT([ovn-northd])
+
+as
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+/connection dropped.*/d"])
+AT_CLEANUP
+
+AT_SETUP([ovn -- load balancing in gateway router - IPv6])
+AT_KEYWORDS([ovnlb])
+
+CHECK_CONNTRACK()
+CHECK_CONNTRACK_NAT()
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+
+# Set external-ids in br-int needed for ovn-controller
+ovs-vsctl \
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
+
+# Start ovn-controller
+start_daemon ovn-controller
+
+# Logical network:
+# Two LRs - R1 and R2 that are connected to each other via LS "join"
+# in fd20::/64 network. R1 has switchess foo (fd11::/64) and
+# bar (fd12::/64) connected to it. R2 has alice (fd72::/64) connected
+# to it.  R2 is a gateway router on which we add load-balancing rules.
+#
+#    foo -- R1 -- join - R2 -- alice
+#           |
+#    bar ----
+
+ovn-nbctl create Logical_Router name=R1
+ovn-nbctl create Logical_Router name=R2 options:chassis=hv1
+
+ovn-nbctl ls-add foo
+ovn-nbctl ls-add bar
+ovn-nbctl ls-add alice
+ovn-nbctl ls-add join
+
+# Connect foo to R1
+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64
+ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
+    type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
+
+# Connect bar to R1
+ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64
+ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
+    type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
+
+# Connect alice to R2
+ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 fd72::1/64
+ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
+    type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
+
+# Connect R1 to join
+ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 fd20::1/64
+ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
+    type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"'
+
+# Connect R2 to join
+ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 fd20::2/64
+ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
+    type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
+
+# Static routes.
+ovn-nbctl lr-route-add R1 fd72::/64 fd20::2
+ovn-nbctl lr-route-add R2 fd11::/64 fd20::1
+ovn-nbctl lr-route-add R2 fd12::/64 fd20::1
+
+# Logical port 'foo1' in switch 'foo'.
+ADD_NAMESPACES(foo1)
+ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \
+         "fd11::1")
+ovn-nbctl lsp-add foo foo1 \
+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2"
+
+# Logical port 'alice1' in switch 'alice'.
+ADD_NAMESPACES(alice1)
+ADD_VETH(alice1, alice1, br-int, "fd72::2/64", "f0:00:00:01:02:04", \
+         "fd72::1")
+ovn-nbctl lsp-add alice alice1 \
+-- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd72::2"
+
+# Logical port 'bar1' in switch 'bar'.
+ADD_NAMESPACES(bar1)
+ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \
+"fd12::1")
+ovn-nbctl lsp-add bar bar1 \
+-- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2"
+
+# Config OVN load-balancer with a VIP.
+uuid=`ovn-nbctl  create load_balancer vips:\"fd30::1\"=\"fd11::2,fd12::2\"`
+ovn-nbctl set logical_router R2 load_balancer=$uuid
+
+# Config OVN load-balancer with another VIP (this time with ports).
+ovn-nbctl set load_balancer $uuid vips:'"[[fd30::2]]:8000"'='"@<:@fd11::2@:>@:80,@<:@fd12::2@:>@:80"'
+
+ovn-nbctl list load_balancer
+
+# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule.
+ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=\"fd12::2\" \
+    external_ip=\"fd30::2\" -- add logical_router R2 nat @nat
+
+
+# Wait for ovn-controller to catch up.
+ovn-nbctl --wait=hv sync
+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
+grep 'nat(dst=\[[fd12::2\]]:80)'])
+
+# Start webservers in 'foo1', 'bar1'.
+OVS_START_L7([foo1], [http6])
+OVS_START_L7([bar1], [http6])
+
+dnl Should work with the virtual IP address through NAT
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 |
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=fd72::2,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd72::2,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+dnl Test load-balancing that includes L4 ports in NAT.
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([alice1], [wget http://[[fd30::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
 done
 
 dnl Each server should have at least one connection.
-AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::2) | grep -v fe80 |
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.5,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd72::2,dst=fd30::2,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd72::2,dst=fd30::2,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
 ])
 
-
 OVS_APP_EXIT_AND_WAIT([ovn-controller])
 
 as ovn-sb
@@ -1277,10 +1837,11 @@  as northd
 OVS_APP_EXIT_AND_WAIT([ovn-northd])
 
 as
-OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"])
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+/connection dropped.*/d"])
 AT_CLEANUP
 
-AT_SETUP([ovn -- load balancing in gateway router])
+AT_SETUP([ovn -- multiple gateway routers, load-balancing])
 AT_KEYWORDS([ovnlb])
 
 CHECK_CONNTRACK()
@@ -1301,21 +1862,27 @@  ovs-vsctl \
 start_daemon ovn-controller
 
 # Logical network:
-# Two LRs - R1 and R2 that are connected to each other via LS "join"
+# Three LRs - R1, R2 and R3 that are connected to each other via LS "join"
 # in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and
 # bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected
-# to it.  R2 is a gateway router on which we add load-balancing rules.
+# to it.  R3 has bob (172.16.1.0/24) connected to it. Note how both alice and
+# bob have the same subnet behind it.  We are trying to simulate external
+# network via those 2 switches. In real world the switch ports of these
+# switches will have addresses set as "unknown" to make them learning switches.
+# Or those switches will be "localnet" ones.
 #
 #    foo -- R1 -- join - R2 -- alice
-#           |
-#    bar ----
+#           |          |
+#    bar ----          - R3 --- bob
 
 ovn-nbctl create Logical_Router name=R1
 ovn-nbctl create Logical_Router name=R2 options:chassis=hv1
+ovn-nbctl create Logical_Router name=R3 options:chassis=hv1
 
 ovn-nbctl ls-add foo
 ovn-nbctl ls-add bar
 ovn-nbctl ls-add alice
+ovn-nbctl ls-add bob
 ovn-nbctl ls-add join
 
 # Connect foo to R1
@@ -1333,6 +1900,11 @@  ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24
 ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
     type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
 
+# Connect bob to R3
+ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 172.16.1.2/24
+ovn-nbctl lsp-add bob rp-bob -- set Logical_Switch_Port rp-bob \
+    type=router options:router-port=bob addresses=\"00:00:03:01:02:03\"
+
 # Connect R1 to join
 ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24
 ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
@@ -1343,9 +1915,23 @@  ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24
 ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
     type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
 
+# Connect R3 to join
+ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 20.0.0.3/24
+ovn-nbctl lsp-add join r3-join -- set Logical_Switch_Port r3-join \
+    type=router options:router-port=R3_join addresses='"00:00:04:01:02:05"'
+
+# Install static routes with source ip address as the policy for routing.
+# We want traffic from 'foo' to go via R2 and traffic of 'bar' to go via R3.
+ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.1.0/24 20.0.0.2
+ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.2.0/24 20.0.0.3
+
 # Static routes.
-ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2
 ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1
+ovn-nbctl lr-route-add R3 192.168.0.0/16 20.0.0.1
+
+# For gateway routers R2 and R3, set a force SNAT rule.
+ovn-nbctl set logical_router R2 options:lb_force_snat_ip=20.0.0.2
+ovn-nbctl set logical_router R3 options:lb_force_snat_ip=20.0.0.3
 
 # Logical port 'foo1' in switch 'foo'.
 ADD_NAMESPACES(foo1)
@@ -1356,10 +1942,10 @@  ovn-nbctl lsp-add foo foo1 \
 
 # Logical port 'alice1' in switch 'alice'.
 ADD_NAMESPACES(alice1)
-ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:04", \
+ADD_VETH(alice1, alice1, br-int, "172.16.1.3/24", "f0:00:00:01:02:04", \
          "172.16.1.1")
 ovn-nbctl lsp-add alice alice1 \
--- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2"
+-- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.3"
 
 # Logical port 'bar1' in switch 'bar'.
 ADD_NAMESPACES(bar1)
@@ -1368,22 +1954,22 @@  ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \
 ovn-nbctl lsp-add bar bar1 \
 -- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2"
 
+# Logical port 'bob1' in switch 'bob'.
+ADD_NAMESPACES(bob1)
+ADD_VETH(bob1, bob1, br-int, "172.16.1.4/24", "f0:00:00:01:02:06", \
+         "172.16.1.2")
+ovn-nbctl lsp-add bob bob1 \
+-- lsp-set-addresses bob1 "f0:00:00:01:02:06 172.16.1.4"
+
 # Config OVN load-balancer with a VIP.
 uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
 ovn-nbctl set logical_router R2 load_balancer=$uuid
-
-# Config OVN load-balancer with another VIP (this time with ports).
-ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.168.2.2:80"'
-
-# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule.
-ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \
-    external_ip=30.0.0.2 -- add logical_router R2 nat @nat
-
+ovn-nbctl set logical_router R3 load_balancer=$uuid
 
 # Wait for ovn-controller to catch up.
 ovn-nbctl --wait=hv sync
 OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
-grep 'nat(dst=192.168.2.2:80)'])
+grep 'nat(dst=192.168.2.2)'])
 
 # Start webservers in 'foo1', 'bar1'.
 OVS_START_L7([foo1], [http])
@@ -1398,23 +1984,16 @@  done
 dnl Each server should have at least one connection.
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) |
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
-tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
-tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
 ])
 
-dnl Test load-balancing that includes L4 ports in NAT.
-for i in `seq 1 20`; do
-    echo Request $i
-    NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
-done
-
-dnl Each server should have at least one connection.
-AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) |
+dnl Force SNAT should have worked.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) |
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
-tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
-tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
 ])
-
 OVS_APP_EXIT_AND_WAIT([ovn-controller])
 
 as ovn-sb
@@ -1431,7 +2010,7 @@  OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
 /connection dropped.*/d"])
 AT_CLEANUP
 
-AT_SETUP([ovn -- multiple gateway routers, load-balancing])
+AT_SETUP([ovn -- multiple gateway routers, load-balancing - IPv6])
 AT_KEYWORDS([ovnlb])
 
 CHECK_CONNTRACK()
@@ -1453,9 +2032,9 @@  start_daemon ovn-controller
 
 # Logical network:
 # Three LRs - R1, R2 and R3 that are connected to each other via LS "join"
-# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and
-# bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected
-# to it.  R3 has bob (172.16.1.0/24) connected to it. Note how both alice and
+# in fd20::/64 network. R1 has switchess foo (fd11::/64) and
+# bar (fd12::/64) connected to it. R2 has alice (fd72::/64) connected
+# to it.  R3 has bob (fd72::/64) connected to it. Note how both alice and
 # bob have the same subnet behind it.  We are trying to simulate external
 # network via those 2 switches. In real world the switch ports of these
 # switches will have addresses set as "unknown" to make them learning switches.
@@ -1476,113 +2055,115 @@  ovn-nbctl ls-add bob
 ovn-nbctl ls-add join
 
 # Connect foo to R1
-ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64
 ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
     type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
 
 # Connect bar to R1
-ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24
+ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64
 ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
     type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
 
 # Connect alice to R2
-ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24
+ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 fd72::1/64
 ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
     type=router options:router-port=alice addresses=\"00:00:02:01:02:03\"
 
 # Connect bob to R3
-ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 172.16.1.2/24
+ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 fd72::2/64
 ovn-nbctl lsp-add bob rp-bob -- set Logical_Switch_Port rp-bob \
     type=router options:router-port=bob addresses=\"00:00:03:01:02:03\"
 
 # Connect R1 to join
-ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24
+ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 fd20::1/64
 ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \
     type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"'
 
 # Connect R2 to join
-ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24
+ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 fd20::2/64
 ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \
     type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"'
 
 # Connect R3 to join
-ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 20.0.0.3/24
+ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 fd20::3/64
 ovn-nbctl lsp-add join r3-join -- set Logical_Switch_Port r3-join \
     type=router options:router-port=R3_join addresses='"00:00:04:01:02:05"'
 
 # Install static routes with source ip address as the policy for routing.
 # We want traffic from 'foo' to go via R2 and traffic of 'bar' to go via R3.
-ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.1.0/24 20.0.0.2
-ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.2.0/24 20.0.0.3
+ovn-nbctl --policy="src-ip" lr-route-add R1 fd11::/64 fd20::2
+ovn-nbctl --policy="src-ip" lr-route-add R1 fd12::/64 fd20::3
 
 # Static routes.
-ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1
-ovn-nbctl lr-route-add R3 192.168.0.0/16 20.0.0.1
+ovn-nbctl lr-route-add R2 fd11::/64 fd20::1
+ovn-nbctl lr-route-add R2 fd12::/64 fd20::1
+ovn-nbctl lr-route-add R3 fd11::/64 fd20::1
+ovn-nbctl lr-route-add R3 fd12::/64 fd20::1
 
 # For gateway routers R2 and R3, set a force SNAT rule.
-ovn-nbctl set logical_router R2 options:lb_force_snat_ip=20.0.0.2
-ovn-nbctl set logical_router R3 options:lb_force_snat_ip=20.0.0.3
+ovn-nbctl set logical_router R2 options:lb_force_snat_ip=fd20::2
+ovn-nbctl set logical_router R3 options:lb_force_snat_ip=fd20::3
 
 # Logical port 'foo1' in switch 'foo'.
 ADD_NAMESPACES(foo1)
-ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
-         "192.168.1.1")
+ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \
+         "fd11::1")
 ovn-nbctl lsp-add foo foo1 \
--- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2"
 
 # Logical port 'alice1' in switch 'alice'.
 ADD_NAMESPACES(alice1)
-ADD_VETH(alice1, alice1, br-int, "172.16.1.3/24", "f0:00:00:01:02:04", \
-         "172.16.1.1")
+ADD_VETH(alice1, alice1, br-int, "fd72::3/64", "f0:00:00:01:02:04", \
+         "fd72::1")
 ovn-nbctl lsp-add alice alice1 \
--- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.3"
+-- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd72::3"
 
 # Logical port 'bar1' in switch 'bar'.
 ADD_NAMESPACES(bar1)
-ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \
-"192.168.2.1")
+ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \
+"fd12::1")
 ovn-nbctl lsp-add bar bar1 \
--- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2"
+-- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2"
 
 # Logical port 'bob1' in switch 'bob'.
 ADD_NAMESPACES(bob1)
-ADD_VETH(bob1, bob1, br-int, "172.16.1.4/24", "f0:00:00:01:02:06", \
-         "172.16.1.2")
+ADD_VETH(bob1, bob1, br-int, "fd72::4/64", "f0:00:00:01:02:06", \
+         "fd72::2")
 ovn-nbctl lsp-add bob bob1 \
--- lsp-set-addresses bob1 "f0:00:00:01:02:06 172.16.1.4"
+-- lsp-set-addresses bob1 "f0:00:00:01:02:06 fd72::4"
 
 # Config OVN load-balancer with a VIP.
-uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
+uuid=`ovn-nbctl create load_balancer vips:\"fd30::1\"=\"fd11::2,fd12::2\"`
 ovn-nbctl set logical_router R2 load_balancer=$uuid
 ovn-nbctl set logical_router R3 load_balancer=$uuid
 
 # Wait for ovn-controller to catch up.
 ovn-nbctl --wait=hv sync
 OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
-grep 'nat(dst=192.168.2.2)'])
+grep 'nat(dst=fd12::2)'])
 
 # Start webservers in 'foo1', 'bar1'.
-OVS_START_L7([foo1], [http])
-OVS_START_L7([bar1], [http])
+OVS_START_L7([foo1], [http6])
+OVS_START_L7([bar1], [http6])
 
 dnl Should work with the virtual IP address through NAT
 for i in `seq 1 20`; do
     echo Request $i
-    NS_CHECK_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+    NS_CHECK_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
 done
 
 dnl Each server should have at least one connection.
-AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) |
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 |
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
-tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
-tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd72::3,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd72::3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd72::3,dst=fd30::1,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd72::3,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
 ])
 
 dnl Force SNAT should have worked.
-AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) |
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::2) | grep -v fe80 |
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
-tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
-tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd72::3,dst=fd11::2,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd72::3,dst=fd12::2,sport=<cleared>,dport=<cleared>),reply=(src=fd12::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
 ])
 OVS_APP_EXIT_AND_WAIT([ovn-controller])
 
@@ -1741,6 +2322,147 @@  OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
 /connection dropped.*/d"])
 AT_CLEANUP
 
+AT_SETUP([ovn -- load balancing in router with gateway router port - IPv6])
+AT_KEYWORDS([ovnlb])
+
+CHECK_CONNTRACK()
+CHECK_CONNTRACK_NAT()
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+
+# Set external-ids in br-int needed for ovn-controller
+ovs-vsctl \
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
+
+# Start ovn-controller
+start_daemon ovn-controller
+
+# Logical network:
+# One LR R1 with switches foo (fd01::/64), bar (fd02::/64),
+# and alice (fd72::/64) connected to it.  The port between R1 and
+# alice is the router gateway port where the R1 LB rules are applied.
+#
+#    foo -- R1 -- bar
+#           |
+#    alice ----
+
+ovn-nbctl lr-add R1
+
+ovn-nbctl ls-add foo
+ovn-nbctl ls-add bar
+ovn-nbctl ls-add alice
+
+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd01::1/64
+ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd02::1/64
+ovn-nbctl lrp-add R1 alice 00:00:02:01:02:03 fd72::1/64 \
+    -- set Logical_Router_Port alice options:redirect-chassis=hv1
+
+# Connect foo to R1
+ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
+    type=router options:router-port=foo \
+    -- lsp-set-addresses rp-foo router
+
+# Connect bar to R1
+ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
+    type=router options:router-port=bar \
+    -- lsp-set-addresses rp-bar router
+
+# Connect alice to R1
+ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
+    type=router options:router-port=alice \
+    -- lsp-set-addresses rp-alice router
+
+# Logical port 'foo1' in switch 'foo'.
+ADD_NAMESPACES(foo1)
+ADD_VETH(foo1, foo1, br-int, "fd01::2/64", "f0:00:00:01:02:03", \
+         "fd01::1")
+ovn-nbctl lsp-add foo foo1 \
+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd01::2"
+
+# Logical port 'foo2' in switch 'foo'.
+ADD_NAMESPACES(foo2)
+ADD_VETH(foo2, foo2, br-int, "fd01::3/64", "f0:00:00:01:02:06", \
+         "fd01::1")
+ovn-nbctl lsp-add foo foo2 \
+-- lsp-set-addresses foo2 "f0:00:00:01:02:06 fd01::3"
+
+# Logical port 'bar1' in switch 'bar'.
+ADD_NAMESPACES(bar1)
+ADD_VETH(bar1, bar1, br-int, "fd02::2/64", "f0:00:00:01:02:04", \
+         "fd02::1")
+ovn-nbctl lsp-add bar bar1 \
+-- lsp-set-addresses bar1 "f0:00:00:01:02:04 fd02::2"
+
+# Logical port 'alice1' in switch 'alice'.
+ADD_NAMESPACES(alice1)
+ADD_VETH(alice1, alice1, br-int, "fd72::2/64", "f0:00:00:01:02:05", \
+         "fd72::1")
+ovn-nbctl lsp-add alice alice1 \
+-- lsp-set-addresses alice1 "f0:00:00:01:02:05 fd72::2"
+
+# Config OVN load-balancer with a VIP.
+uuid=`ovn-nbctl  create load_balancer vips:\"fd72::10\"=\"fd01::2,fd02::2\"`
+ovn-nbctl set logical_router R1 load_balancer=$uuid
+
+# Config OVN load-balancer with another VIP (this time with ports).
+ovn-nbctl set load_balancer $uuid vips:'"[[fd72::11]]:8000"'='"@<:@fd01::2@:>@:80,@<:@fd02::2@:>@:80"'
+
+# Wait for ovn-controller to catch up.
+ovn-nbctl --wait=hv sync
+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
+grep 'nat(dst=\[[fd02::2\]]:80)'])
+
+# Start webservers in 'foo1', 'bar1'.
+OVS_START_L7([foo1], [http6])
+OVS_START_L7([bar1], [http6])
+
+dnl Should work with the virtual IP address through NAT
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([alice1], [wget http://[[fd72::10]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::10) | grep -v fe80 |
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=fd72::2,dst=fd72::10,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd72::2,dst=fd72::10,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+dnl Test load-balancing that includes L4 ports in NAT.
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([alice1], [wget http://[[fd72::11]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::11) | grep -v fe80 |
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=fd72::2,dst=fd72::11,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=fd72::2,dst=fd72::11,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd72::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+as ovn-sb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as ovn-nb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as northd
+OVS_APP_EXIT_AND_WAIT([ovn-northd])
+
+as
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+/connection dropped.*/d"])
+AT_CLEANUP
+
 AT_SETUP([ovn -- DNAT and SNAT on distributed router - N/S])
 AT_KEYWORDS([ovnnat])