[ovs-dev] [PATCH v2 2/2] ovn-northd ipam: Support IPv6 dynamic assignment
nusiddiq at redhat.com
nusiddiq at redhat.com
Tue Mar 7 01:49:45 UTC 2017
From: Numan Siddique <nusiddiq at redhat.com>
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 <nusiddiq at redhat.com>
---
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 @@
<dt><code>192.168.0.110-192.168.0.120 192.168.0.25-192.168.0.30 192.168.0.144</code></dt>
</dl>
</column>
+
+ <column name="other_config" key="ipv6_prefix">
+ Set this to an IPv6 prefix to enable <code>ovn-northd</code> to
+ automatically assign IPv6 addresses using this prefix. Use the
+ <code>dynamic</code> keyword in the <ref table="Logical_Switch_Port"/>
+ table's <ref table="Logical_Switch_Port" column="addresses"/> 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
+ "::".
+ <p>
+ Examples:
+ </p>
+ <dl>
+ <dt><code>aef0::</code></dt>
+ <dd></dd>
+ <dt><code>bef0:1234:a890:5678::</code></dt>
+ <dd></dd>
+ <dt><code>8230:5678::</code></dt>
+ <dd></dd>
+ </dl>
+ </column>
</group>
<group title="Common Columns">
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])
--
2.9.3
More information about the dev
mailing list