@@ -2653,6 +2653,8 @@ ovn_port_update_sbrec(struct northd_context *ctx,
struct sset *active_ha_chassis_grps)
{
sbrec_port_binding_set_datapath(op->sb, op->od->sb);
+ const char *ipv6_pd_list = NULL;
+
if (op->nbrp) {
/* If the router is for l3 gateway, it resides on a chassis
* and its port type is "l3gateway". */
@@ -2775,6 +2777,12 @@ ovn_port_update_sbrec(struct northd_context *ctx,
smap_add(&new, "l3gateway-chassis", chassis_name);
}
}
+
+ ipv6_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
+ if (ipv6_pd_list) {
+ smap_add(&new, "ipv6_ra_pd_list", ipv6_pd_list);
+ }
+
sbrec_port_binding_set_options(op->sb, &new);
smap_destroy(&new);
@@ -2824,6 +2832,12 @@ ovn_port_update_sbrec(struct northd_context *ctx,
smap_add_format(&options,
"qdisc_queue_id", "%d", queue_id);
}
+
+ ipv6_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
+ if (ipv6_pd_list) {
+ smap_add(&options, "ipv6_ra_pd_list", ipv6_pd_list);
+ }
+
sbrec_port_binding_set_options(op->sb, &options);
smap_destroy(&options);
if (ovn_is_known_nb_lsp_type(op->nbsp->type)) {
@@ -2873,6 +2887,12 @@ ovn_port_update_sbrec(struct northd_context *ctx,
if (chassis) {
smap_add(&new, "l3gateway-chassis", chassis);
}
+
+ ipv6_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
+ if (ipv6_pd_list) {
+ smap_add(&new, "ipv6_ra_pd_list", ipv6_pd_list);
+ }
+
sbrec_port_binding_set_options(op->sb, &new);
smap_destroy(&new);
} else {
@@ -7129,6 +7149,11 @@ copy_ra_to_sb(struct ovn_port *op, const char *address_mode)
}
ds_put_format(&s, "%s/%u ", addrs->network_s, addrs->plen);
}
+
+ const char *ra_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
+ if (ra_pd_list) {
+ ds_put_cstr(&s, ra_pd_list);
+ }
/* Remove trailing space */
ds_chomp(&s, ' ');
smap_add(&options, "ipv6_ra_prefixes", ds_cstr(&s));
@@ -7843,7 +7868,36 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
free(snat_ips);
}
- /* Logical router ingress table 3: IP Input for IPv6. */
+ /* DHCPv6 reply handling */
+ HMAP_FOR_EACH (op, key_node, ports) {
+ if (!op->nbrp) {
+ continue;
+ }
+
+ if (op->derived) {
+ continue;
+ }
+
+ struct lport_addresses lrp_networks;
+ if (!extract_lrp_networks(op->nbrp, &lrp_networks)) {
+ continue;
+ }
+
+ for (size_t i = 0; i < lrp_networks.n_ipv6_addrs; i++) {
+ ds_clear(&actions);
+ ds_clear(&match);
+ ds_put_format(&match, "ip6.dst == %s && udp.src == 547 &&"
+ " udp.dst == 546",
+ lrp_networks.ipv6_addrs[i].addr_s);
+ ds_put_format(&actions, "reg0 = 0; handle_dhcpv6_reply { "
+ "eth.dst <-> eth.src; ip6.dst <-> ip6.src; "
+ "outport <-> inport; output; };");
+ ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
+ ds_cstr(&match), ds_cstr(&actions));
+ }
+ }
+
+ /* Logical router ingress table 1: IP Input for IPv6. */
HMAP_FOR_EACH (op, key_node, ports) {
if (!op->nbrp) {
continue;
@@ -8644,6 +8698,24 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
continue;
}
+ struct smap options;
+ /* enable IPv6 prefix delegation */
+ bool prefix_delegation = smap_get_bool(&op->nbrp->options,
+ "prefix_delegation", false);
+ if (prefix_delegation) {
+ smap_clone(&options, &op->sb->options);
+ smap_add(&options, "ipv6_prefix_delegation", "true");
+ sbrec_port_binding_set_options(op->sb, &options);
+ smap_destroy(&options);
+ }
+
+ if (smap_get_bool(&op->nbrp->options, "prefix", false)) {
+ smap_clone(&options, &op->sb->options);
+ smap_add(&options, "ipv6_prefix", "true");
+ sbrec_port_binding_set_options(op->sb, &options);
+ smap_destroy(&options);
+ }
+
const char *address_mode = smap_get(
&op->nbrp->ipv6_ra_configs, "address_mode");
@@ -2142,6 +2142,23 @@
to <code>true</code>.
</p>
</column>
+
+ <column name="options" key="prefix_delegation"
+ type='{"type": "boolean"}'>
+ <p>
+ If set to <code>true</code>, enable IPv6 prefix delegation state
+ machine on this logical router port (RFC3633). IPv6 prefix
+ delegation is available just on a gateway router or on a gateway
+ router port.
+ </p>
+ </column>
+
+ <column name="options" key="prefix" type='{"type": "boolean"}'>
+ <p>
+ If set to <code>true</code>, this interface will receive an IPv6
+ prefix according to RFC3663
+ </p>
+ </column>
</group>
<group title="Attachment">
@@ -157,7 +157,7 @@ find_command()
{
which $1 > /dev/null 2>&1
status=$?
- var=HAVE_`echo "$1" | tr '[a-z]' '[A-Z]'`
+ var=HAVE_`echo "$1" | tr '-' '_' | tr '[a-z]' '[A-Z]'`
if test "$status" = "0"; then
eval ${var}="yes"
else
@@ -192,6 +192,9 @@ else
DIFF_SUPPORTS_NORMAL_FORMAT=no
fi
+# Set HAVE_DIBBLER-SERVER
+find_command dibbler-server
+
# Turn off proxies.
unset http_proxy
unset https_proxy
@@ -3426,3 +3426,130 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
/connection dropped.*/d"])
AT_CLEANUP
+
+AT_SETUP([ovn -- IPv6 prefix delegation])
+AT_SKIP_IF([test $HAVE_DIBBLER_SERVER = no])
+AT_KEYWORDS([ovn-ipv6-prefix_d])
+
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+
+ADD_BR([br-int])
+ADD_BR([br-ext])
+
+ovs-ofctl add-flow br-ext action=normal
+# 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
+
+ovn-nbctl lr-add R1
+
+ovn-nbctl ls-add sw0
+ovn-nbctl ls-add sw1
+ovn-nbctl ls-add public
+
+ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24
+ovn-nbctl lrp-add R1 rp-sw1 00:00:03:01:02:03 192.168.2.1/24
+ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 2001:db8:3333::1/64 \
+ -- set Logical_Router_Port rp-public options:redirect-chassis=hv1
+
+ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \
+ type=router options:router-port=rp-sw0 \
+ -- lsp-set-addresses sw0-rp router
+ovn-nbctl lsp-add sw1 sw1-rp -- set Logical_Switch_Port sw1-rp \
+ type=router options:router-port=rp-sw1 \
+ -- lsp-set-addresses sw1-rp router
+
+ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \
+ type=router options:router-port=rp-public \
+ -- lsp-set-addresses public-rp router
+
+ADD_NAMESPACES(sw01)
+ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
+ "192.168.1.1")
+ovn-nbctl lsp-add sw0 sw01 \
+ -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2"
+
+ADD_NAMESPACES(sw11)
+ADD_VETH(sw11, sw11, br-int, "192.168.2.2/24", "f0:00:00:02:02:03", \
+ "192.168.2.1")
+ovn-nbctl lsp-add sw1 sw11 \
+ -- lsp-set-addresses sw11 "f0:00:00:02:02:03 192.168.2.2"
+
+ADD_NAMESPACES(server)
+ADD_VETH(s1, server, br-ext, "2001:db8:3333::2/64", "f0:00:00:01:02:05", \
+ "2001:db8:3333::1")
+
+OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep 2001:db8:3333::2 | grep tentative)" = ""])
+OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep fe80 | grep tentative)" = ""])
+
+AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext])
+ovn-nbctl lsp-add public public1 \
+ -- lsp-set-addresses public1 unknown \
+ -- lsp-set-type public1 localnet \
+ -- lsp-set-options public1 network_name=phynet
+
+ovn-nbctl set logical_router_port rp-public options:prefix_delegation=true
+ovn-nbctl set logical_router_port rp-public options:prefix=true
+ovn-nbctl set logical_router_port rp-sw0 options:prefix=true
+ovn-nbctl set logical_router_port rp-sw1 options:prefix=true
+
+# reset dibbler state
+sed s/eth0/s1/g -i /etc/dibbler/server.conf
+cat > /var/lib/dibbler/server-AddrMgr.xml <<EOF
+<AddrMgr>
+ <timestamp>1575481348</timestamp>
+ <replayDetection>0</replayDetection>
+</AddrMgr>
+EOF
+cat > /var/lib/dibbler/server-CfgMgr.xml <<EOF
+<SrvCfgMgr>
+ <workDir>/var/lib/dibbler</workDir>
+ <LogName>Server</LogName>
+ <LogLevel>8</LogLevel>
+ <InactiveMode>0</InactiveMode>
+ <GuessMode>0</GuessMode>
+</SrvCfgMgr>
+EOF
+
+NS_CHECK_EXEC([server], [dibbler-server run > dibbler.log &])
+ovn-nbctl --wait=hv sync
+
+sleep 10
+kill $(pidof dibbler-server)
+
+OVS_WAIT_UNTIL([ovn-sbctl list port_binding rp-public | grep ipv6_ra_pd_list])
+OVS_WAIT_UNTIL([ovn-sbctl list port_binding rp-sw0 | grep ipv6_ra_pd_list])
+OVS_WAIT_UNTIL([ovn-sbctl list port_binding rp-sw1 | grep ipv6_ra_pd_list])
+AT_CHECK([ovn-sbctl get port_binding rp-public options:ipv6_ra_pd_list], [0], [dnl
+"2001:db8:3333::6a2f:0:0/96"
+])
+AT_CHECK([ovn-sbctl get port_binding rp-sw0 options:ipv6_ra_pd_list], [0], [dnl
+"2001:db8:3333::5b81:0:0/96"
+])
+AT_CHECK([ovn-sbctl get port_binding rp-sw1 options:ipv6_ra_pd_list], [0], [dnl
+"2001:db8:3333::42f1:0:0/96"
+])
+
+kill $(pidof 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(["/.*error receiving.*/d
+/.*terminating with signal 15.*/d"])
+AT_CLEANUP
Introduce logical flows in ovn router pipeline in order to parse dhcpv6 advertise/reply from IPv6 prefix delegation router. Do not overwrite ipv6_ra_pd_list info in options column of SB port_binding table written by ovn-controller Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com> --- northd/ovn-northd.c | 74 +++++++++++++++++++++++++- ovn-nb.xml | 17 ++++++ tests/atlocal.in | 5 +- tests/system-ovn.at | 127 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 2 deletions(-)