Introduce ipv6_src and ipv6_dst to selection_fields column in Load_Balancer Logical_Router_Static_Route tables in order to properly load-balance IPv6 traffic if these fields are selected in group hash algorithm.
Reported-at: https://issues.redhat.com/browse/FDP-1032 Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com> --- Changes in v4: - improve test case - fix documentation and comments Changes in v3: - improve documentation - improve self-tests Changes in v2: - add new load-balancer Dual stack system test --- ovn-nb.ovsschema | 9 +- ovn-nb.xml | 10 +- tests/ovn.at | 6 +- tests/system-ovn.at | 256 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 269 insertions(+), 12 deletions(-) diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index e7aa6b2b1..b03d22333 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "7.9.0", - "cksum": "2414335430 38682", + "version": "7.10.0", + "cksum": "963912051 38764", "tables": { "NB_Global": { "columns": { @@ -247,7 +247,7 @@ "type": {"key": {"type": "string", "enum": ["set", ["eth_src", "eth_dst", "ip_src", "ip_dst", - "tp_src", "tp_dst"]]}, + "ipv6_src", "ipv6_dst", "tp_src", "tp_dst"]]}, "min": 0, "max": "unlimited"}}, "options": { "type": {"key": "string", @@ -510,7 +510,8 @@ "type": {"key": {"type": "string", "enum": ["set", ["eth_src", "eth_dst", "ip_proto", "ip_src", - "ip_dst", "tp_src", "tp_dst"]]}, + "ip_dst", "ipv6_src", "ipv6_dst", "tp_src", + "tp_dst"]]}, "min": 0, "max": "unlimited"}}, "options": { "type": {"key": "string", "value": "string", diff --git a/ovn-nb.xml b/ovn-nb.xml index d82f9872b..558b63ce4 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -2175,6 +2175,13 @@ specified fields in generating the hash. </p> + <p> + Example: <code>{ip_proto,ip_src,ip_dst}</code> for a 3-tuple match. + Example: <code>{ip_proto,ipv6_src,ipv6_dst}</code> for an IPv6 match. + Example: <code>{ip_proto,ip_src,ip_dst,tp_src,tp_dst}</code> + Example: <code>{ip_src,ip_dst,ipv6_src,ipv6_dst,tp_src,tp_dst}</code> + </p> + <p> <code>dp_hash</code> selection method uses the assistance of datapath to calculate the hash and it is expected to be @@ -3845,8 +3852,9 @@ or </p> <p> Example: <code>{ip_proto,ip_src,ip_dst}</code> for a 3-tuple match. + Example: <code>{ip_proto,ipv6_src,ipv6_dst}</code> for an IPv6 match. Example: <code>{ip_proto,ip_src,ip_dst,tp_src,tp_dst}</code> - for a 5-tuple match. + Example: <code>{ip_src,ip_dst,ipv6_src,ipv6_dst,tp_src,tp_dst}</code> </p> </column> diff --git a/tests/ovn.at b/tests/ovn.at index 8ecf1f6bf..db4351c7d 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -25733,7 +25733,7 @@ check ovn-nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 check ovn-nbctl lb-add lb1 [[2001::a]]:80 [[2001::3]]:80,[[2002::3]]:80 OVN_LB_ID=$(ovn-nbctl --bare --column _uuid find load_balancer name=lb1) -check ovn-nbctl set load_balancer ${OVN_LB_ID} selection_fields="ip_dst,ip_src,tp_dst,tp_src" +check ovn-nbctl set load_balancer ${OVN_LB_ID} selection_fields="ipv6_dst,ipv6_src,tp_dst,tp_src" # check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:\"[[2001::3]]\"=\"sw0-p1:[[2001::2]]\" check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:\"[[2002::3]]\"=\"sw1-p1:[[2002::2]]\" @@ -25776,14 +25776,14 @@ OVS_WAIT_FOR_OUTPUT( ovn-sbctl dump-flows sw0 | grep ct_lb_mark | grep priority=120 | sed 's/table=..//'], 0, [dnl (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6.dst == 2001::a && tcp.dst == 80), action=(xxreg1 = 2001::a; reg2[[0..15]] = 80; ct_lb_mark;) - (ls_in_lb ), priority=120 , match=(ct.new && ip6.dst == 2001::a && tcp.dst == 80), action=(xxreg1 = 2001::a; reg2[[0..15]] = 80; ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) + (ls_in_lb ), priority=120 , match=(ct.new && ip6.dst == 2001::a && tcp.dst == 80), action=(xxreg1 = 2001::a; reg2[[0..15]] = 80; ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80; hash_fields="ipv6_dst,ipv6_src,tcp_dst,tcp_src");) ]) AT_CAPTURE_FILE([sbflows2]) OVS_WAIT_FOR_OUTPUT( [ovn-sbctl dump-flows > sbflows2 ovn-sbctl dump-flows lr0 | grep ct_lb_mark | grep priority=120 | sed 's/table=..//'], 0, - [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && ip6.dst == 2001::a && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) + [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && ip6.dst == 2001::a && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80; hash_fields="ipv6_dst,ipv6_src,tcp_dst,tcp_src");) ]) # get the svc monitor mac. diff --git a/tests/system-ovn.at b/tests/system-ovn.at index c7379bedb..6159cdf28 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -1755,10 +1755,10 @@ tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd ]) # Configure selection_fields. -check ovn-nbctl set load_balancer $lb2_uuid selection_fields="ip_src,ip_dst,tp_src,tp_dst" +check ovn-nbctl set load_balancer $lb2_uuid selection_fields="ipv6_src,ipv6_dst,tp_src,tp_dst" OVS_WAIT_UNTIL([ test $(ovs-ofctl dump-groups br-int | \ - grep "selection_method=hash,fields(ip_src,ip_dst,tcp_src,tcp_dst)" -c) -eq 2 + grep "selection_method=hash,fields(ipv6_src,ipv6_dst,tcp_src,tcp_dst)" -c) -eq 2 ]) AT_CHECK([ovs-appctl dpctl/flush-conntrack]) @@ -1789,10 +1789,10 @@ done # there should be only one conntrack entry. AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep fd03::2 -c) -eq 1]) -check ovn-nbctl set load_balancer $lb2_uuid selection_fields="eth_src,ip_src" +check ovn-nbctl set load_balancer $lb2_uuid selection_fields="eth_src,ipv6_src" OVS_WAIT_UNTIL([ test $(ovs-ofctl dump-groups br-int | \ - grep "selection_method=hash,fields(eth_src,ip_src)" -c) -eq 2 + grep "selection_method=hash,fields(eth_src,ipv6_src)" -c) -eq 2 ]) AT_CHECK([ovs-appctl dpctl/flush-conntrack]) @@ -1847,6 +1847,254 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d"]) AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD([ +AT_SETUP([load-balancing - Dual Stack]) +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 + +check_uuid ovn-nbctl create Logical_Router name=R1 +check ovn-nbctl ls-add foo +check ovn-nbctl ls-add bar + +# Connect foo to R1. +check ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24 fd01::1/64 +check 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. +check ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 172.16.1.1/24 fd02::1/64 +check 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, "192.168.1.2/24", "f0:00:00:01:02:03", \ + "192.168.1.1") +NS_EXEC([foo1],[ip addr add fd01::2/64 dev foo1 nodad]) +NS_EXEC([foo1],[ip -6 route add default via fd01::1]) +check ovn-nbctl lsp-add foo foo1 \ +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2 fd01::2" + +# Create logical ports 'bar1', 'bar2', 'bar3', 'bar6', 'bar7', 'bar8' in +# switch 'bar'. +ADD_NAMESPACES(bar1) +ADD_VETH(bar1, bar1, br-int, "172.16.1.2/24", "f0:00:0f:01:02:03", \ + "172.16.1.1") +check ovn-nbctl lsp-add bar bar1 \ +-- lsp-set-addresses bar1 "f0:00:0f:01:02:03 172.16.1.2" + +ADD_NAMESPACES(bar2) +ADD_VETH(bar2, bar2, br-int, "172.16.1.3/24", "f0:00:0f:01:02:04", \ + "172.16.1.1") +check ovn-nbctl lsp-add bar bar2 \ +-- lsp-set-addresses bar2 "f0:00:0f:01:02:04 172.16.1.3" + +ADD_NAMESPACES(bar3) +ADD_VETH(bar3, bar3, br-int, "172.16.1.4/24", "f0:00:0f:01:02:05", \ + "172.16.1.1") +check ovn-nbctl lsp-add bar bar3 \ +-- lsp-set-addresses bar3 "f0:00:0f:01:02:05 172.16.1.4" + +ADD_NAMESPACES(bar6) +ADD_VETH(bar6, bar6, br-int, "fd02::2/64", "f0:00:0f:02:02:03", \ + "fd02::1", "nodad") +check ovn-nbctl lsp-add bar bar6 \ +-- lsp-set-addresses bar6 "f0:00:0f:02:02:03 fd02::2" + +ADD_NAMESPACES(bar7) +ADD_VETH(bar7, bar7, br-int, "fd02::3/64", "f0:00:0f:02:02:04", \ + "fd02::1", "nodad") +check ovn-nbctl lsp-add bar bar7 \ +-- lsp-set-addresses bar7 "f0:00:0f:02:02:04 fd02::3" + +ADD_NAMESPACES(bar8) +ADD_VETH(bar8, bar8, br-int, "fd02::4/64", "f0:00:0f:02:02:05", \ + "fd02::1", "nodad") +check ovn-nbctl lsp-add bar bar8 \ +-- lsp-set-addresses bar8 "f0:00:0f:02:02:05 fd02::4" + +# Config OVN load-balancer with a VIP. +check ovn-nbctl lb-add lb1 30.0.0.1:8080 "172.16.1.2:80,172.16.1.3:80,172.16.1.4:80" +lb1_uuid=$(fetch_column nb:load_balancer _uuid name="lb1") +check ovn-nbctl set load_balancer $lb1_uuid vips:'"[[fd03::2]]:8090"'='"@<:@fd02::2@:>@:80,@<:@fd02::3@:>@:80,@<:@fd02::4@:>@:80"' + +check ovn-nbctl ls-lb-add foo lb1 + +# Wait for ovn-controller to catch up. +check ovn-nbctl --wait=hv sync + +OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \ +grep 'nat(dst=172.16.1.4:80)']) + +# Start webservers in 'bar1', 'bar2' and 'bar3' for IPv4 connections. +OVS_START_L7([bar1], [http]) +OVS_START_L7([bar2], [http]) +OVS_START_L7([bar3], [http]) +# Start webservers in 'bar6', 'bar7' and 'bar8' for IPv6 connections. +OVS_START_L7([bar6], [http6]) +OVS_START_L7([bar7], [http6]) +OVS_START_L7([bar8], [http6]) + +AT_CHECK([ovs-appctl dpctl/flush-conntrack]) + +dnl Test load-balancing that includes L4 ports in NAT. +dnl Each server should have at least one connection. +OVS_WAIT_FOR_OUTPUT([ + for i in $(seq 1 20); do + NS_EXEC([foo1], [wget 30.0.0.1:8080 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) + done + ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ + sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl +tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>) +tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>) +tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>) +]) + +OVS_WAIT_FOR_OUTPUT([ +dnl Test load-balancing that includes L4 ports in NAT. +for i in $(seq 1 10); do + NS_EXEC([foo1], [wget http://[[fd03::2]]:8090 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) +done +dnl Each server should have at least one connection. +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>,mark=2,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>,mark=2,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>,mark=2,protoinfo=(state=<cleared>) +]) + +# Configure selection_fields. +check ovn-nbctl set load_balancer $lb1_uuid selection_fields="ip_src,ip_dst,ipv6_src,ipv6_dst,tp_src,tp_dst" +OVS_WAIT_UNTIL([ + test $(ovs-ofctl dump-groups br-int | \ + grep "selection_method=hash,fields(ip_src,ip_dst,ipv6_src,ipv6_dst,tcp_src,tcp_dst)" -c) -eq 2 +]) + +AT_CHECK([ovs-appctl dpctl/flush-conntrack]) + +# dnl Test load-balancing that includes L4 ports in NAT. +# dnl Each server should have at least one connection. +OVS_WAIT_FOR_OUTPUT([ + for i in $(seq 1 20); do + NS_EXEC([foo1], [wget 30.0.0.1:8080 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) + done + ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ + sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl +tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>) +tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>) +tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>) +]) + +OVS_WAIT_FOR_OUTPUT([ +dnl Test load-balancing that includes L4 ports in NAT. +for i in $(seq 1 10); do + NS_EXEC([foo1], [wget http://[[fd03::2]]:8090 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) +done +dnl Each server should have at least one connection. +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>,mark=2,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>,mark=2,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>,mark=2,protoinfo=(state=<cleared>) +]) + +AT_CHECK([ovs-appctl dpctl/flush-conntrack]) + +echo "foo" > foo +for i in $(seq 1 20); do + echo Request $i + NS_EXEC([foo1], [nc -p 30000 30.0.0.1 8080 < foo]) +done + +# dnl Only one backend should be chosen. +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=192.168.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>) +]) + +for i in $(seq 1 20); do + echo Request $i + NS_EXEC([foo1], [nc -6 -p 30000 fd03::2 8090 < foo]) +done + +# dnl Only one backend should be chosen. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | \ +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>,mark=2,protoinfo=(state=<cleared>) +]) + +# Test oad-balancing that using IP src and IP dst +check ovn-nbctl set load_balancer $lb1_uuid selection_fields="ip_src,ip_dst,ipv6_src,ipv6_dst" +OVS_WAIT_UNTIL([ + test $(ovs-ofctl dump-groups br-int | \ + grep "selection_method=hash,fields(ip_src,ip_dst,ipv6_src,ipv6_dst)" -c) -eq 2 +]) + +for p in $(seq 3 20); do + h=$(printf '%02x' $p) + NS_EXEC([foo1],[ip addr add 192.168.1.$p/24 dev foo1]) + NS_EXEC([foo1],[ip addr add fd01::$h/64 dev foo1 nodad]) + NS_EXEC([foo1],[ip -6 route add default via fd01::1]) +done + +AT_CHECK([ovs-appctl dpctl/flush-conntrack]) +for p in $(seq 3 20); do + NS_EXEC([foo1], [nc -s 192.168.1.$p 30.0.0.1 8080 < foo]) +done + +bar1_ct=$(ovs-appctl dpctl/dump-conntrack | grep 172.16.1.2 -c) +bar2_ct=$(ovs-appctl dpctl/dump-conntrack | grep 172.16.1.3 -c) +bar3_ct=$(ovs-appctl dpctl/dump-conntrack | grep 172.16.1.4 -c) + +AT_CHECK([test $bar1_ct -gt 0]) +AT_CHECK([test $bar2_ct -gt 0]) +AT_CHECK([test $bar3_ct -gt 0]) + +for p in $(seq 3 20); do + h=$(printf '%02x' $p) + NS_EXEC([foo1], [nc -6 -s fd01::$h fd03::2 8090 < foo]) +done + +bar1_ct=$(ovs-appctl dpctl/dump-conntrack | grep fd02::2 -c) +bar2_ct=$(ovs-appctl dpctl/dump-conntrack | grep fd02::3 -c) +bar3_ct=$(ovs-appctl dpctl/dump-conntrack | grep fd02::4 -c) + +AT_CHECK([test $bar1_ct -gt 0]) +AT_CHECK([test $bar2_ct -gt 0]) +AT_CHECK([test $bar3_ct -gt 0]) + +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 +]) + OVN_FOR_EACH_NORTHD([ AT_SETUP([load-balancing - same subnet.]) AT_KEYWORDS([ovnlb]) -- 2.48.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev