From patchwork Tue Mar 7 01:49:45 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 736022 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3vcfjl3tc9z9sNd for ; Tue, 7 Mar 2017 12:50:03 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 5437CC77; Tue, 7 Mar 2017 01:49:59 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 62DFDC4B for ; Tue, 7 Mar 2017 01:49:58 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id EA2FB1BD for ; Tue, 7 Mar 2017 01:49:55 +0000 (UTC) Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 697AC63E29 for ; Tue, 7 Mar 2017 01:49:56 +0000 (UTC) Received: from nusiddiq.blr.redhat.com (ovpn-116-35.sin2.redhat.com [10.67.116.35]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v271npXo006606; Mon, 6 Mar 2017 20:49:53 -0500 From: nusiddiq@redhat.com To: dev@openvswitch.org Date: Tue, 7 Mar 2017 07:19:45 +0530 Message-Id: <20170307014945.2513-1-nusiddiq@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 07 Mar 2017 01:49:56 +0000 (UTC) X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 2/2] ovn-northd ipam: Support IPv6 dynamic assignment X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org From: Numan Siddique OVN will generate the IPv6 address for a logical port if requested using the IPv6 prefix and the MAC address (as IEEE EUI64 identifier). To generate the IPv6 address, CMS should define the IPv6 prefix in the 'Logical_switch.other_config:ipv6_prefix' column. Signed-off-by: Numan Siddique --- lib/packets.h | 20 +++++++++++++++ ovn/northd/ovn-northd.c | 66 ++++++++++++++++++++++++++++++++++++++----------- ovn/ovn-nb.xml | 23 +++++++++++++++++ tests/ovn.at | 54 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 15 deletions(-) diff --git a/lib/packets.h b/lib/packets.h index c4d3799..ce1e1c0 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -990,6 +990,26 @@ in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6) } /* + * Generates ipv6 EUI64 address from the given eth addr + * and prefix and stores it in 'lla' + */ +static inline void +in6_generate_eui64(struct eth_addr ea, struct in6_addr *prefix, + struct in6_addr *lla) +{ + union ovs_16aligned_in6_addr *taddr = (void *) lla; + union ovs_16aligned_in6_addr *prefix_taddr = (void *) prefix; + taddr->be16[0] = prefix_taddr->be16[0]; + taddr->be16[1] = prefix_taddr->be16[1]; + taddr->be16[2] = prefix_taddr->be16[2]; + taddr->be16[3] = prefix_taddr->be16[3]; + taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]); + taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff); + taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]); + taddr->be16[7] = ea.be16[2]; +} + +/* * Generates ipv6 link local address from the given eth addr * with prefix 'fe80::/64' and stores it in 'lla' */ diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 5b471e1..9ad47d8 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -377,6 +377,8 @@ struct ipam_info { uint32_t start_ipv4; size_t total_ipv4s; unsigned long *allocated_ipv4s; /* A bitmap of allocated IPv4s */ + bool ipv6_prefix_set; + struct in6_addr ipv6_prefix; }; /* The 'key' comes from nbs->header_.uuid or nbr->header_.uuid or @@ -509,6 +511,14 @@ init_ipam_info_for_datapath(struct ovn_datapath *od) } const char *subnet_str = smap_get(&od->nbs->other_config, "subnet"); + const char *ipv6_prefix = smap_get(&od->nbs->other_config, "ipv6_prefix"); + + if (ipv6_prefix) { + od->ipam_info = xzalloc(sizeof *od->ipam_info); + od->ipam_info->ipv6_prefix_set = ipv6_parse( + ipv6_prefix, &od->ipam_info->ipv6_prefix); + } + if (!subnet_str) { return; } @@ -523,7 +533,9 @@ init_ipam_info_for_datapath(struct ovn_datapath *od) return; } - od->ipam_info = xzalloc(sizeof *od->ipam_info); + if (!od->ipam_info) { + od->ipam_info = xzalloc(sizeof *od->ipam_info); + } od->ipam_info->start_ipv4 = ntohl(subnet) + 1; od->ipam_info->total_ipv4s = ~ntohl(mask); od->ipam_info->allocated_ipv4s = @@ -1023,13 +1035,21 @@ static bool ipam_allocate_addresses(struct ovn_datapath *od, struct ovn_port *op, const char *addrspec) { - if (!od || !op || !op->nbsp) { + if (!od || !op || !op->nbsp || !od->ipam_info || + (!od->ipam_info->allocated_ipv4s && !od->ipam_info->ipv6_prefix_set)) { return false; } - uint32_t ip = ipam_get_unused_ip(od); - if (!ip) { - return false; + uint32_t ip = 0; + + if (od->ipam_info->allocated_ipv4s) { + ip = ipam_get_unused_ip(od); + if (!ip && !od->ipam_info->ipv6_prefix_set) { + /* We dont want to return false for cases where IPv4 addresses + * are exhausted and IPv6 prefix is set. + */ + return false; + } } struct eth_addr mac; @@ -1049,17 +1069,33 @@ ipam_allocate_addresses(struct ovn_datapath *od, struct ovn_port *op, check_mac = false; } - /* Add MAC to MACAM and IP to IPAM bitmap if both addresses were allocated - * successfully. */ - ipam_insert_ip(od, ip); - ipam_insert_mac(&mac, check_mac); + bool retval = false; + struct ds new_addr = DS_EMPTY_INITIALIZER; + ds_put_format(&new_addr, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); + if (ip) { + ipam_insert_ip(od, ip); + ds_put_format(&new_addr, " "IP_FMT, IP_ARGS(htonl(ip))); + } - char *new_addr = xasprintf(ETH_ADDR_FMT" "IP_FMT, - ETH_ADDR_ARGS(mac), IP_ARGS(htonl(ip))); - nbrec_logical_switch_port_set_dynamic_addresses(op->nbsp, new_addr); - free(new_addr); + if (od->ipam_info->ipv6_prefix_set) { + struct in6_addr ipv6_addr; + in6_generate_eui64(mac, &od->ipam_info->ipv6_prefix, &ipv6_addr); + char ipv6_addr_s[INET6_ADDRSTRLEN + 1]; + ipv6_string_mapped(ipv6_addr_s, &ipv6_addr); + ds_put_format(&new_addr, " %s", ipv6_addr_s); + } - return true; + if (ip || od->ipam_info->ipv6_prefix_set) { + /* Add MAC to MACAM only if IPv4/IPv6 address(es) were allocated + * successfully. */ + ipam_insert_mac(&mac, check_mac); + nbrec_logical_switch_port_set_dynamic_addresses(op->nbsp, + ds_cstr(&new_addr)); + retval = true; + } + + ds_destroy(&new_addr); + return retval; } static void @@ -1075,7 +1111,7 @@ build_ipam(struct hmap *datapaths, struct hmap *ports) * ports that have the "dynamic" keyword in their addresses column. */ struct ovn_datapath *od; HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs || !od->ipam_info || !od->ipam_info->allocated_ipv4s) { + if (!od->nbs || !od->ipam_info) { continue; } diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index f759ee9..0be338e 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -169,6 +169,29 @@
192.168.0.110-192.168.0.120 192.168.0.25-192.168.0.30 192.168.0.144
+ + + Set this to an IPv6 prefix to enable ovn-northd to + automatically assign IPv6 addresses using this prefix. Use the + dynamic keyword in the + table's column to + request dynamic address assignment for a particular port. The assigned + IPv6 address will be generated using the IPv6 prefix and the + MAC address (as IEEE EUI64 identifier) of the port. + The IPv6 prefix defined here should be a valid IPv6 address ending with + "::". +

+ Examples: +

+
+
aef0::
+
+
bef0:1234:a890:5678::
+
+
8230:5678::
+
+
+
diff --git a/tests/ovn.at b/tests/ovn.at index 0834f03..8509c5b 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -4955,6 +4955,60 @@ AT_CHECK([ovn-nbctl get Logical-Switch-Port p36 dynamic_addresses], [0], ["0a:00:00:00:00:25 192.168.1.21" ]) +# Set IPv6 prefix +ovn-nbctl --wait=sb set Logical-switch sw0 other_config:ipv6_prefix="aef0::" +ovn-nbctl --wait=sb lsp-add sw0 p37 -- lsp-set-addresses p37 \ +"dynamic" + +# With prefix aef0 and mac 0a:00:00:00:00:26, the dynamic IPv6 should be +# - aef0::800:ff:fe00:26 (EUI64) +AT_CHECK([ovn-nbctl get Logical-Switch-Port p37 dynamic_addresses], [0], + ["0a:00:00:00:00:26 192.168.1.23 aef0::800:ff:fe00:26" +]) + +ovn-nbctl --wait=sb ls-add sw4 +ovn-nbctl --wait=sb set Logical-switch sw4 other_config:ipv6_prefix="bef0::" +ovn-nbctl --wait=sb lsp-add sw4 p38 -- lsp-set-addresses p38 \ +"dynamic" + +AT_CHECK([ovn-nbctl get Logical-Switch-Port p38 dynamic_addresses], [0], + ["0a:00:00:00:00:27 bef0::800:ff:fe00:27" +]) + +ovn-nbctl --wait=sb lsp-add sw4 p39 -- lsp-set-addresses p39 \ +"f0:00:00:00:10:12 dynamic" + +AT_CHECK([ovn-nbctl get Logical-Switch-Port p39 dynamic_addresses], [0], + ["f0:00:00:00:10:12 bef0::f200:ff:fe00:1012" +]) + +# Clear the other_config for sw4. No dynamic ip should be assigned. +ovn-nbctl --wait=sb clear Logical-switch sw4 other_config +ovn-nbctl --wait=sb lsp-add sw4 p40 -- lsp-set-addresses p40 \ +"dynamic" + +AT_CHECK([ovn-nbctl get Logical-Switch-Port p40 dynamic_addresses], [0], + [[[]] +]) + +# Test the case where IPv4 addresses are exhausted and IPv6 prefix is set +ovn-nbctl --wait=sb set Logical-switch sw4 other_config:subnet=192.168.2.0/30 \ +-- set Logical-switch sw4 other_config:ipv6_prefix="bef0::" + +sleep 1 +# Now p40 should be assigned with dynamic addresses. +AT_CHECK([ovn-nbctl get Logical-Switch-Port p40 dynamic_addresses], [0], + ["0a:00:00:00:00:28 192.168.2.2 bef0::800:ff:fe00:28" +]) + + +ovn-nbctl --wait=sb lsp-add sw4 p41 -- lsp-set-addresses p41 \ +"dynamic" +# p41 should not have IPv4 address (as the pool is exhausted). +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], + ["0a:00:00:00:00:29 bef0::800:ff:fe00:29" +]) + as ovn-sb OVS_APP_EXIT_AND_WAIT([ovsdb-server])