From 643d4be1b3f40c3075af584d0cbc83e34a5e51ca Mon Sep 17 00:00:00 2001 Message-Id: <643d4be1b3f40c3075af584d0cbc83e34a5e51ca.1586727203.git.lorenzo.bianconi@redhat.com> In-Reply-To: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com> References: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com> From: Lorenzo Bianconi Date: Wed, 1 Apr 2020 18:37:31 +0200 Subject: [PATCH 3/3] northd: Add logical flows for dhcpv6 pfd parsing 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 Introduce ipv6_prefix column in NB Logical_router_port table to report IPv6 prefix received from delegation router to the CMS Change-Id: Ibc1bd83bf3d9d4671f70610df5635e6266580a18 Signed-off-by: Lorenzo Bianconi Signed-off-by: Numan Siddique --- NEWS | 1 + northd/ovn-northd.8.xml | 8 +++ northd/ovn-northd.c | 95 ++++++++++++++++++++++++-- ovn-nb.ovsschema | 7 +- ovn-nb.xml | 21 ++++++ tests/atlocal.in | 5 +- tests/system-ovn.at | 143 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 272 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 9b36bfd17..21c80f0dc 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ OVN v20.03.0 - 28 Feb 2020 - Added Forwarding Group support in OVN. - Added support for MLD Snooping and MLD Querier. - Added support for ECMP routes in OVN router. + - Added IPv6 Prefix Delegation support in OVN. - OVN Interconnection: * Support for L3 interconnection of multiple OVN deployments with tunnels diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index b5e4d6d84..82c86f636 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -1660,6 +1660,14 @@ next; +
  • + A priority-100 flow parses DHCPv6 replies from IPv6 prefix + delegation routers (udp.src == 547 && + udp.dst == 546). The handle_dhcpv6_reply + is used to send IPv6 prefix delegation messages to the delegation + router. +
  • +
  • A priority-87 flow explicitly allows IPv6 multicast traffic that is diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index bb68b8fe9..fd1be5b27 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -2688,6 +2688,33 @@ op_get_name(const struct ovn_port *op) return name; } +static void +ovn_update_ipv6_prefix(struct hmap *ports) +{ + const struct ovn_port *op; + HMAP_FOR_EACH (op, key_node, ports) { + if (!op->nbrp) { + continue; + } + + char prefix[IPV6_SCAN_LEN + 6]; + unsigned aid; + const char *ipv6_pd_list = smap_get(&op->sb->options, + "ipv6_ra_pd_list"); + if (!ipv6_pd_list || + !ovs_scan(ipv6_pd_list, "%u:%s", &aid, prefix)) { + continue; + } + + struct sset ipv6_prefix_set = SSET_INITIALIZER(&ipv6_prefix_set); + sset_add(&ipv6_prefix_set, prefix); + nbrec_logical_router_port_set_ipv6_prefix(op->nbrp, + sset_array(&ipv6_prefix_set), + sset_count(&ipv6_prefix_set)); + sset_destroy(&ipv6_prefix_set); + } +} + static void ovn_port_update_sbrec(struct northd_context *ctx, struct ovsdb_idl_index *sbrec_chassis_by_name, @@ -2818,6 +2845,13 @@ ovn_port_update_sbrec(struct northd_context *ctx, smap_add(&new, "l3gateway-chassis", chassis_name); } } + + const char *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); @@ -4683,12 +4717,12 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) * unreachable packets. */ ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, "nd || nd_rs || nd_ra || icmp4.type == 3 || " - "icmp6.type == 1 || (tcp && tcp.flags == 20)", - "next;"); + "icmp6.type == 1 || (tcp && tcp.flags == 20) || " + "(udp && udp.src == 546 && udp.dst == 547)", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, "nd || nd_rs || nd_ra || icmp4.type == 3 || " - "icmp6.type == 1 || (tcp && tcp.flags == 20)", - "next;"); + "icmp6.type == 1 || (tcp && tcp.flags == 20) ||" + "(udp && udp.src == 546 && udp.dst == 547)", "next;"); /* Ingress and Egress Pre-ACL Table (Priority 100). * @@ -7744,6 +7778,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)); @@ -8488,7 +8527,34 @@ 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;"); + 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; @@ -9250,6 +9316,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"); @@ -10941,6 +11025,7 @@ ovnnb_db_run(struct northd_context *ctx, build_meter_groups(ctx, &meter_groups); build_lflows(ctx, datapaths, ports, &port_groups, &mcast_groups, &igmp_groups, &meter_groups, &lbs); + ovn_update_ipv6_prefix(ports); sync_address_sets(ctx); sync_port_groups(ctx); diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index ea6f4e354..949f6258b 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.20.1", - "cksum": "721375950 25251", + "version": "5.22.0", + "cksum": "170077561 25417", "tables": { "NB_Global": { "columns": { @@ -342,6 +342,9 @@ "ipv6_ra_configs": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}, + "ipv6_prefix": {"type": {"key": "string", + "min": 0, + "max": "unlimited"}}, "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, diff --git a/ovn-nb.xml b/ovn-nb.xml index f7ba9c334..045c63fb0 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -2065,6 +2065,11 @@ port has all ingress and egress traffic dropped. + + This column contains IPv6 prefix obtained by prefix delegation + router according to RFC 3633 + +

    This column defines the IPv6 ND RA address mode and ND MTU Option to be @@ -2320,6 +2325,22 @@ ovn-northd honors the configured value. + +

    + If set to true, 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. +

    + + + +

    + If set to true, this interface will receive an IPv6 + prefix according to RFC3663 +

    +
    diff --git a/tests/atlocal.in b/tests/atlocal.in index 5f14c3da0..8f3ff03b9 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -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 diff --git a/tests/system-ovn.at b/tests/system-ovn.at index f1ae69b20..000b3f13b 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -3793,3 +3793,146 @@ 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_SKIP_IF([test $HAVE_TCPDUMP = 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 \ + -- 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:1db8:3333::2/64", "f0:00:00:01:02:05", \ + "2001:1db8:3333::1") + +OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep 2001:1db8: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/^iface.*/"iface \"s1\" {"/g -i /etc/dibbler/server.conf +sed s/pd-pool.*/"pd-pool 2001:1db8:3333::\/80"/g -i /etc/dibbler/server.conf +sed s/t1.*/"t1 10"/g -i /etc/dibbler/server.conf +sed s/t2.*/"t2 15"/g -i /etc/dibbler/server.conf +cat > /var/lib/dibbler/server-AddrMgr.xml < + 1575481348 + 0 + +EOF +cat > /var/lib/dibbler/server-CfgMgr.xml < + /var/lib/dibbler + Server + 8 + 0 + 0 + +EOF + +NS_CHECK_EXEC([server], [dibbler-server run > dibbler.log &]) +ovn-nbctl --wait=hv sync + +OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c4-15)" = ""]) +OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c4-15)" = ""]) +OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c4-15)" = ""]) + +AT_CHECK([ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c3-16], [0], [dnl +[2001:1db8:3333] +]) +AT_CHECK([ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16], [0], [dnl +[2001:1db8:3333] +]) +AT_CHECK([ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c3-16], [0], [dnl +[2001:1db8:3333] +]) + +kill $(pidof dibbler-server) + +prefix=$(ovn-nbctl list logical_router_port rp-public | awk -F/ '/ipv6_prefix/{print substr($1,25,9)}' | sed 's/://g') +ovn-nbctl set logical_router_port rp-sw0 options:prefix=false +ovn-nbctl set logical_router_port rp-sw1 options:prefix=false + +NS_CHECK_EXEC([server], [tcpdump -c 1 -nni s1 ip6[[95:4]]=0x${prefix} > public.pcap &]) + +OVS_WAIT_UNTIL([ + total_pkts=$(cat public.pcap | wc -l) + test "${total_pkts}" = "1" +]) + +kill $(pidof tcpdump) +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 -- 2.25.2