On Fri, Jul 13, 2018 at 06:45 PM GMT, Mark Michelson wrote: > OVN offers a method of IP address management that allows for an IPv4 subnet or > IPv6 prefix to be specified on a logical switch. Then by specifying a > switch port's address as "dynamic" or "<mac address> dynamic", OVN will > automatically assign addresses to the switch port. > > While this works great for initial assignment of addresses, addresses do > not automatically adjust when changes are made to the switch's > configuration. For instance: > * If the subnet, ipv6_prefix, or exclude_ips for a logical switch > changes, the affected switch ports are not updated. > * If a switch port with a static IP address is added to the switch, and > that address conflicts with a dynamically assigned IP address, the > dynamic address is not updated. > * If a MAC address switched from being statically assigned to > dynamically assigned, the MAC address would not be updated. > * If a statically assigned MAC address changed, then the IPv6 address > would not be updated. > > This patch solves all of the above issues by changing the algorithm for > IPAM assignment. There are essentially three steps. > 1) While joining logical ports, all statically-assigned addresses (i.e. > any ports without "dynamic" addresses) have their addresses registered > to IPAM. This gives them top priority. > 2) All logical ports with dynamic addresses are inspected. Any changes > that must be made to the addresses are collected to be made later. Any > addresses that do not require change are registered to IPAM. This allows > for previously assigned dynamic addresses to be kept. > 3) All gathered changes are enacted. > > The change contains new tests that ensure that dynamic addresses are > updated when appropriate. > > This patch also alters some existing IPAM tests. Those tests assumed > that dynamic addresses would not be updated automatically, so those > tests either had to be altered or removed. > > Signed-off-by: Mark Michelson <mmich...@redhat.com>
I've come up with a couple suggestions (see in-line) but otherwise LGTM: Acked-by: Jakub Sitnicki <j...@redhat.com> > --- > v3->v4: > Print warning when multiple dynamic addresses are configured on a > switch port. Ensure that dynamic addresses beyond the first on a switch > port are ignored. Found by Ben Pfaff. > > v2->v3: > Fixed a checkpatch problem (line too long) > > v1->v2: > Rebased > --- > ovn/northd/ovn-northd.c | 385 > ++++++++++++++++++++++++++++++++++-------------- > tests/ovn.at | 97 +++++++++--- > 2 files changed, 350 insertions(+), 132 deletions(-) > > diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c > index 04a072ba8..b75febb44 100644 > --- a/ovn/northd/ovn-northd.c > +++ b/ovn/northd/ovn-northd.c > @@ -985,9 +985,6 @@ ipam_add_port_addresses(struct ovn_datapath *od, struct > ovn_port *op) > for (size_t i = 0; i < op->nbsp->n_addresses; i++) { > ipam_insert_lsp_addresses(od, op, op->nbsp->addresses[i]); > } > - if (op->nbsp->dynamic_addresses) { > - ipam_insert_lsp_addresses(od, op, op->nbsp->dynamic_addresses); > - } > } else if (op->nbrp) { > struct lport_addresses lrp_networks; > if (!extract_lrp_networks(op->nbrp, &lrp_networks)) { > @@ -1060,64 +1057,255 @@ ipam_get_unused_ip(struct ovn_datapath *od) > return od->ipam_info.start_ipv4 + new_ip_index; > } > > +enum dynamic_update_type { > + NONE, /* No change to the address */ > + REMOVE, /* Address is no longer dynamic */ > + STATIC, /* Use static address (MAC only) */ > + DYNAMIC, /* Assign a new dynamic address */ > +}; > + > +struct dynamic_address_update { > + struct ovs_list node; /* In build_ipam()'s list of updates. */ > + > + struct ovn_port *op; > + > + struct lport_addresses current_addresses; > + struct eth_addr static_mac; > + enum dynamic_update_type mac; > + enum dynamic_update_type ipv4; > + enum dynamic_update_type ipv6; > +}; > + > +static enum dynamic_update_type > +dynamic_mac_changed(const char *lsp_addresses, > + struct dynamic_address_update *update) > +{ > + struct eth_addr ea; > + > + if (ovs_scan(lsp_addresses, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) { > + if (eth_addr_equals(ea, update->current_addresses.ea)) { > + return NONE; > + } else { > + /* MAC is still static, but it has changed */ > + update->static_mac = ea; > + return STATIC; > + } > + } > + > + uint64_t mac64 = eth_addr_to_uint64(update->current_addresses.ea); > + if ((mac64 ^ MAC_ADDR_PREFIX) >> 24) { > + return DYNAMIC; > + } else { > + return NONE; > + } > +} > + > +static enum dynamic_update_type > +dynamic_ip4_changed(struct dynamic_address_update *update) > +{ > + bool dynamic_ip4 = update->op->od->ipam_info.allocated_ipv4s != NULL; > + > + if (!dynamic_ip4) { > + if (update->current_addresses.n_ipv4_addrs) { > + return REMOVE; > + } else { > + return NONE; > + } > + } > + > + if (!update->current_addresses.n_ipv4_addrs) { > + /* IPv4 was previously static but now is dynamic */ > + return DYNAMIC; > + } > + > + uint32_t ip4 = ntohl(update->current_addresses.ipv4_addrs[0].addr); > + if (ip4 < update->op->od->ipam_info.start_ipv4) { > + return DYNAMIC; > + } > + > + uint32_t index = ip4 - update->op->od->ipam_info.start_ipv4; > + if (index > update->op->od->ipam_info.total_ipv4s || > + bitmap_is_set(update->op->od->ipam_info.allocated_ipv4s, index)) { > + /* Previously assigned dynamic IPv4 address can no longer be used. > + * It's either outside the subnet, conflicts with an excluded IP, > + * or conflicts with a statically-assigned address on the switch > + */ > + return DYNAMIC; > + } else { > + return NONE; > + } > +} Looks like you could improve readability a bit with a local pointer to update->op->od->ipam_info, and maybe even also another one to update->current_addresses. > + > +static enum dynamic_update_type > +dynamic_ip6_changed(struct dynamic_address_update *update) > +{ > + bool dynamic_ip6 = update->op->od->ipam_info.ipv6_prefix_set; > + > + if (!dynamic_ip6) { > + if (update->current_addresses.n_ipv6_addrs) { > + /* IPv6 was dynamic but now is not */ > + return REMOVE; > + } else { > + /* IPv6 has never been dynamic */ > + return NONE; > + } > + } > + > + if (update->mac != NONE) { > + /* IPv6 address is based on MAC, so if MAC has been updated, > + * then we have to update IPv6 address too. > + */ > + return DYNAMIC; > + } > + > + if (!update->current_addresses.n_ipv6_addrs) { > + /* IPv6 was previously static but now is dynamic */ > + return DYNAMIC; > + } > + > + struct in6_addr masked = ipv6_addr_bitand( > + &update->current_addresses.ipv6_addrs[0].addr, > + &update->op->od->ipam_info.ipv6_prefix); > + if (!IN6_ARE_ADDR_EQUAL(&masked, > &update->op->od->ipam_info.ipv6_prefix)) { > + return DYNAMIC; > + } > + > + return NONE; > +} > + > +/* Check previously assigned dynamic addresses for validity. This will > + * check if the assigned addresses need to change. For addresses that > + * do not need to be updated, go ahead and insert them into IPAM. This > + * way, their addresses will be claimed and cannot be assigned elsewhere > + * later. > + * > + * Returns true if any changes to dynamic addresses are required > + */ > static bool > -ipam_allocate_addresses(struct ovn_datapath *od, struct ovn_port *op, > - const char *addrspec) > +dynamic_addresses_check_for_updates(const char *lsp_addrs, > + struct dynamic_address_update *update) > { > - if (!op->nbsp) { > + update->mac = dynamic_mac_changed(lsp_addrs, update); > + update->ipv4 = dynamic_ip4_changed(update); > + update->ipv6 = dynamic_ip6_changed(update); > + if (update->mac == NONE) { > + ipam_insert_mac(&update->current_addresses.ea, false); > + } > + if (update->ipv4 == NONE && update->current_addresses.n_ipv4_addrs) { > + ipam_insert_ip(update->op->od, > + ntohl(update->current_addresses.ipv4_addrs[0].addr)); > + } > + if (update->mac == NONE && > + update->ipv4 == NONE && > + update->ipv6 == NONE) { > return false; > + } else { > + return true; > } > +} The side effect of reserving unchanged addresses might be surprising. Have you considered splitting it into two steps: any_changed = dynamic_addresses_check_for_updates(addresses, update); ipam_insert_unchanged_addresses(update); if (any_changed) { /* Queue update */ } else { /* No changes */ } > + > +static void > +set_lsp_dynamic_addresses(const char *dynamic_addresses, struct ovn_port *op) > +{ > + extract_lsp_addresses(dynamic_addresses, > &op->lsp_addrs[op->n_lsp_addrs]); > + op->n_lsp_addrs++; > +} > > - /* Get or generate MAC address. */ > +/* Determines which components (MAC, IPv4, and IPv6) of dynamic > + * addresses need to be assigned. This is used exclusively for > + * ports that do not have dynamic addresses already assigned. > + */ > +static void > +set_dynamic_updates(const char *addrspec, > + struct dynamic_address_update *update) > +{ > struct eth_addr mac; > - bool dynamic_mac; > int n = 0; > if (ovs_scan(addrspec, ETH_ADDR_SCAN_FMT" dynamic%n", > ETH_ADDR_SCAN_ARGS(mac), &n) > && addrspec[n] == '\0') { > - dynamic_mac = false; > + update->mac = STATIC; > + update->static_mac = mac; > } else { > - uint64_t mac64 = ipam_get_unused_mac(); > - if (!mac64) { > - return false; > - } > - eth_addr_from_uint64(mac64, &mac); > - dynamic_mac = true; > + update->mac = DYNAMIC; > } > - > - /* Generate IPv4 address, if desirable. */ > - bool dynamic_ip4 = od->ipam_info.allocated_ipv4s != NULL; > - uint32_t ip4 = dynamic_ip4 ? ipam_get_unused_ip(od) : 0; > - > - /* Generate IPv6 address, if desirable. */ > - bool dynamic_ip6 = od->ipam_info.ipv6_prefix_set; > - struct in6_addr ip6; > - if (dynamic_ip6) { > - in6_generate_eui64(mac, &od->ipam_info.ipv6_prefix, &ip6); > + if (update->op->od->ipam_info.allocated_ipv4s) { > + update->ipv4 = DYNAMIC; > + } else { > + update->ipv4 = NONE; > + } > + if (update->op->od->ipam_info.ipv6_prefix_set) { > + update->ipv6 = DYNAMIC; > + } else { > + update->ipv6 = NONE; > } > +} > > - /* If we didn't generate anything, bail out. */ > - if (!dynamic_ip4 && !dynamic_ip6) { > - return false; > +static void > +update_dynamic_addresses(struct ovn_datapath *od, > + struct dynamic_address_update *update) > +{ > + struct eth_addr mac; > + switch (update->mac) { > + case NONE: > + mac = update->current_addresses.ea; > + break; > + case REMOVE: > + ovs_assert(0); I think OVS_NOT_REACHED() is what we're using for impossible branches. Can't find any ovs_assert(0) in the codebase. > + case STATIC: > + mac = update->static_mac; > + break; > + case DYNAMIC: > + eth_addr_from_uint64(ipam_get_unused_mac(), &mac); > + break; > + } > + > + ovs_be32 ip4 = 0; > + switch (update->ipv4) { > + case NONE: > + if (update->current_addresses.n_ipv4_addrs) { > + ip4 = update->current_addresses.ipv4_addrs[0].addr; > + } > + break; > + case REMOVE: > + break; > + case STATIC: > + ovs_assert(0); > + case DYNAMIC: > + ip4 = htonl(ipam_get_unused_ip(od)); > + } > + > + struct in6_addr ip6 = in6addr_any; > + switch (update->ipv6) { > + case NONE: > + if (update->current_addresses.n_ipv6_addrs) { > + ip6 = update->current_addresses.ipv6_addrs[0].addr; > + } > + break; > + case REMOVE: > + break; > + case STATIC: > + ovs_assert(0); > + case DYNAMIC: > + in6_generate_eui64(mac, &od->ipam_info.ipv6_prefix, &ip6); > + break; > } > > - /* Save the dynamic addresses. */ > struct ds new_addr = DS_EMPTY_INITIALIZER; > ds_put_format(&new_addr, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); > - if (dynamic_ip4 && ip4) { > - ipam_insert_ip(od, ip4); > - ds_put_format(&new_addr, " "IP_FMT, IP_ARGS(htonl(ip4))); > + if (ip4) { > + ipam_insert_ip(od, ntohl(ip4)); > + ds_put_format(&new_addr, " "IP_FMT, IP_ARGS(ip4)); > } > - if (dynamic_ip6) { > + if (!IN6_ARE_ADDR_EQUAL(&ip6, &in6addr_any)) { > char ip6_s[INET6_ADDRSTRLEN + 1]; > ipv6_string_mapped(ip6_s, &ip6); > ds_put_format(&new_addr, " %s", ip6_s); > } > - ipam_insert_mac(&mac, !dynamic_mac); > - nbrec_logical_switch_port_set_dynamic_addresses(op->nbsp, > + nbrec_logical_switch_port_set_dynamic_addresses(update->op->nbsp, > ds_cstr(&new_addr)); > + set_lsp_dynamic_addresses(ds_cstr(&new_addr), update->op); > ds_destroy(&new_addr); > - return true; > } > > static void > @@ -1133,48 +1321,80 @@ 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.allocated_ipv4s && > - !od->ipam_info.ipv6_prefix_set)) { > + if (!od->nbs) { > continue; > } > > - struct ovn_port *op; > + struct ovs_list updates; > + ovs_list_init(&updates); > for (size_t i = 0; i < od->nbs->n_ports; i++) { > - const struct nbrec_logical_switch_port *nbsp = > - od->nbs->ports[i]; > + const struct nbrec_logical_switch_port *nbsp = od->nbs->ports[i]; > > - if (!nbsp) { > + if (!od->ipam_info.allocated_ipv4s && > + !od->ipam_info.ipv6_prefix_set) { > + if (nbsp->dynamic_addresses) { > + nbrec_logical_switch_port_set_dynamic_addresses(nbsp, > + NULL); > + } > continue; > } > > - op = ovn_port_find(ports, nbsp->name); > - if (!op || (op->nbsp && op->peer)) { > + struct ovn_port *op = ovn_port_find(ports, nbsp->name); > + if (!op || op->nbsp != nbsp || op->peer) { > /* Do not allocate addresses for logical switch ports that > * have a peer. */ > continue; > } > > + int num_dynamic_addresses = 0; > for (size_t j = 0; j < nbsp->n_addresses; j++) { > - if (is_dynamic_lsp_address(nbsp->addresses[j]) > - && !nbsp->dynamic_addresses) { > - if (!ipam_allocate_addresses(od, op, nbsp->addresses[j]) > - || !extract_lsp_addresses(nbsp->dynamic_addresses, > - &op->lsp_addrs[op->n_lsp_addrs])) { > - static struct vlog_rate_limit rl > - = VLOG_RATE_LIMIT_INIT(1, 1); > - VLOG_INFO_RL(&rl, "Failed to allocate address."); > + if (!is_dynamic_lsp_address(nbsp->addresses[j])) { > + continue; > + } > + if (num_dynamic_addresses) { > + static struct vlog_rate_limit rl > + = VLOG_RATE_LIMIT_INIT(1, 1); > + VLOG_WARN_RL(&rl, "More than one dynamic address " > + "configured for logical switch port '%s'", > + nbsp->name); > + continue; > + } > + num_dynamic_addresses++; > + struct dynamic_address_update *update > + = xzalloc(sizeof *update); > + update->op = op; > + if (nbsp->dynamic_addresses) { > + extract_lsp_addresses(nbsp->dynamic_addresses, > + &update->current_addresses); > + if > (dynamic_addresses_check_for_updates(nbsp->addresses[j], > + update)) { > + ovs_list_push_back(&updates, &update->node); > } else { > - op->n_lsp_addrs++; > + /* No changes to dynamic addresses */ > + set_lsp_dynamic_addresses(nbsp->dynamic_addresses, > op); > + destroy_lport_addresses(&update->current_addresses); > + free(update); > } > - break; > + } else { > + set_dynamic_updates(nbsp->addresses[j], update); > + ovs_list_push_back(&updates, &update->node); > } > } > > if (!nbsp->n_addresses && nbsp->dynamic_addresses) { > - nbrec_logical_switch_port_set_dynamic_addresses(op->nbsp, > - NULL); > + nbrec_logical_switch_port_set_dynamic_addresses(nbsp, NULL); > } > } > + > + /* After retaining all unchanged dynamic addresses, now assign > + * new ones. > + */ > + struct dynamic_address_update *update; > + LIST_FOR_EACH_POP (update, node, &updates) { > + update_dynamic_addresses(od, update); > + destroy_lport_addresses(&update->current_addresses); > + free(update); > + } > } > } > > @@ -1277,41 +1497,6 @@ tag_alloc_create_new_tag(struct hmap *tag_alloc_table, > } > > > -/* > - * This function checks if the MAC in "address" parameter (if present) is > - * different from the one stored in Logical_Switch_Port.dynamic_addresses > - * and updates it. > - */ > -static void > -check_and_update_mac_in_dynamic_addresses( > - const char *address, > - const struct nbrec_logical_switch_port *nbsp) > -{ > - if (!nbsp->dynamic_addresses) { > - return; > - } > - int buf_index = 0; > - struct eth_addr ea; > - if (!ovs_scan_len(address, &buf_index, > - ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) { > - return; > - } > - > - struct eth_addr present_ea; > - buf_index = 0; > - if (ovs_scan_len(nbsp->dynamic_addresses, &buf_index, > - ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(present_ea)) > - && !eth_addr_equals(ea, present_ea)) { > - /* MAC address has changed. Update it */ > - char *new_addr = xasprintf( > - ETH_ADDR_FMT"%s", ETH_ADDR_ARGS(ea), > -  ->dynamic_addresses[buf_index]); > - nbrec_logical_switch_port_set_dynamic_addresses( > - nbsp, new_addr); > - free(new_addr); > - } > -} > - > static void > join_logical_ports(struct northd_context *ctx, > struct hmap *datapaths, struct hmap *ports, > @@ -1379,23 +1564,7 @@ join_logical_ports(struct northd_context *ctx, > continue; > } > if (is_dynamic_lsp_address(nbsp->addresses[j])) { > - if (nbsp->dynamic_addresses) { > - check_and_update_mac_in_dynamic_addresses( > - nbsp->addresses[j], nbsp); > - if > (!extract_lsp_addresses(nbsp->dynamic_addresses, > - > &op->lsp_addrs[op->n_lsp_addrs])) { > - static struct vlog_rate_limit rl > - = VLOG_RATE_LIMIT_INIT(1, 1); > - VLOG_INFO_RL(&rl, "invalid syntax '%s' in " > - "logical switch port " > - "dynamic_addresses. No " > - "MAC address found", > - > op->nbsp->dynamic_addresses); > - continue; > - } > - } else { > - continue; > - } > + continue; > } else if (!extract_lsp_addresses(nbsp->addresses[j], > &op->lsp_addrs[op->n_lsp_addrs])) > { > static struct vlog_rate_limit rl > diff --git a/tests/ovn.at b/tests/ovn.at > index d1a8967dd..e80c965a3 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -5140,7 +5140,7 @@ AT_CHECK([ovn-nbctl get Logical-Switch-Port p19 > dynamic_addresses], [0], > > # Change a port's address to test for multiple ip's for a single address > entry > # and addresses set by the user. > -ovn-nbctl lsp-set-addresses p0 "0a:00:00:00:00:15 192.168.1.12 192.168.1.14" > +ovn-nbctl lsp-set-addresses p0 "0a:00:00:00:00:15 192.168.1.2 192.168.1.12 > 192.168.1.14" > ovn-nbctl --wait=sb lsp-add sw0 p20 -- lsp-set-addresses p20 dynamic > AT_CHECK([ovn-nbctl get Logical-Switch-Port p20 dynamic_addresses], [0], > ["0a:00:00:00:00:16 192.168.1.13" > @@ -5208,7 +5208,6 @@ AT_CHECK([ovn-nbctl get Logical-Switch-Port p31 > dynamic_addresses], [0], > # Update the static MAC address with dynamically allocated IP and check > # if the MAC address is updated in 'Logical_Switch_Port.dynamic_adddresses' > ovn-nbctl --wait=sb lsp-set-addresses p31 "fe:dc:ba:98:76:55 dynamic" > -ovn-nbctl get Logical-Switch-Port p31 dynamic_addresses > > AT_CHECK([ovn-nbctl get Logical-Switch-Port p31 dynamic_addresses], [0], > ["fe:dc:ba:98:76:55 192.168.1.18" > @@ -5216,7 +5215,7 @@ AT_CHECK([ovn-nbctl get Logical-Switch-Port p31 > dynamic_addresses], [0], > > ovn-nbctl --wait=sb lsp-set-addresses p31 "dynamic" > AT_CHECK([ovn-nbctl get Logical-Switch-Port p31 dynamic_addresses], [0], > - ["fe:dc:ba:98:76:55 192.168.1.18" > + ["0a:00:00:00:00:21 192.168.1.18" > ]) > > ovn-nbctl --wait=sb lsp-set-addresses p31 "fe:dc:ba:98:76:56 dynamic" > @@ -5233,21 +5232,21 @@ ovn-nbctl --wait=sb lsp-add sw0 p32 -- > lsp-set-addresses p32 \ > "dynamic" > # 192.168.1.20 should be assigned as 192.168.1.19 is excluded. > AT_CHECK([ovn-nbctl get Logical-Switch-Port p32 dynamic_addresses], [0], > - ["0a:00:00:00:00:21 192.168.1.20" > + ["0a:00:00:00:00:22 192.168.1.20" > ]) > > ovn-nbctl --wait=sb lsp-add sw0 p33 -- lsp-set-addresses p33 \ > "dynamic" > # 192.168.1.22 should be assigned as 192.168.1.21 is excluded. > AT_CHECK([ovn-nbctl get Logical-Switch-Port p33 dynamic_addresses], [0], > - ["0a:00:00:00:00:22 192.168.1.22" > + ["0a:00:00:00:00:23 192.168.1.22" > ]) > > ovn-nbctl --wait=sb lsp-add sw0 p34 -- lsp-set-addresses p34 \ > "dynamic" > # 192.168.1.51 should be assigned as 192.168.1.23-192.168.1.50 is excluded. > AT_CHECK([ovn-nbctl get Logical-Switch-Port p34 dynamic_addresses], [0], > - ["0a:00:00:00:00:23 192.168.1.51" > + ["0a:00:00:00:00:24 192.168.1.51" > ]) > > # Now clear the exclude_ips list. 192.168.1.19 should be assigned. > @@ -5255,7 +5254,7 @@ ovn-nbctl --wait=sb set Logical-switch sw0 > other_config:exclude_ips="invalid" > ovn-nbctl --wait=sb lsp-add sw0 p35 -- lsp-set-addresses p35 \ > "dynamic" > AT_CHECK([ovn-nbctl get Logical-Switch-Port p35 dynamic_addresses], [0], > - ["0a:00:00:00:00:24 192.168.1.19" > + ["0a:00:00:00:00:25 192.168.1.19" > ]) > > # Set invalid data in exclude_ips list. It should be ignored. > @@ -5264,7 +5263,7 @@ ovn-nbctl --wait=sb lsp-add sw0 p36 -- > lsp-set-addresses p36 \ > "dynamic" > # 192.168.1.21 should be assigned as that's the next free one. > AT_CHECK([ovn-nbctl get Logical-Switch-Port p36 dynamic_addresses], [0], > - ["0a:00:00:00:00:25 192.168.1.21" > + ["0a:00:00:00:00:26 192.168.1.21" > ]) > > # Clear the dynamic addresses assignment request. > @@ -5281,16 +5280,17 @@ ovn-nbctl --wait=sb lsp-add sw0 p37 -- > lsp-set-addresses p37 \ > # 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.21 aef0::800:ff:fe00:26" > + ["0a:00:00:00:00:27 192.168.1.21 aef0::800:ff:fe00:27" > ]) > > ovn-nbctl --wait=sb ls-add sw4 > -ovn-nbctl --wait=sb set Logical-switch sw4 other_config:ipv6_prefix="bef0::" > +ovn-nbctl --wait=sb set Logical-switch sw4 other_config:ipv6_prefix="bef0::" > \ > +-- set Logical-switch sw4 other_config:subnet=192.168.2.0/30 > 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" > + ["0a:00:00:00:00:28 192.168.2.2 bef0::800:ff:fe00:28" > ]) > > ovn-nbctl --wait=sb lsp-add sw4 p39 -- lsp-set-addresses p39 \ > @@ -5300,29 +5300,78 @@ 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 > +# Test the case where IPv4 addresses are exhausted and IPv6 prefix is set > +# p40 should not have an IPv4 address since the pool is exhausted > 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], > + ["0a:00:00:00:00:29 bef0::800:ff:fe00:29" > +]) > + > +# Test dynamic changes on switch ports. > +# > +ovn-nbctl --wait=sb ls-add sw5 > +ovn-nbctl --wait=sb lsp-add sw5 p41 -- lsp-set-addresses p41 \ > +"dynamic" > +# p41 will start with nothing > +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 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::" > +# Set a subnet. Now p41 should have an ipv4 address, too > +ovn-nbctl --wait=sb add Logical-Switch sw5 other_config subnet=192.168.1.0/24 > +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], > + ["0a:00:00:00:00:2a 192.168.1.2" > +]) > > -# 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" > +# Clear the other_config. The IPv4 address should be gone > +ovn-nbctl --wait=sb clear Logical-Switch sw5 other_config > +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], > + [[[]] > ]) > > -ovn-nbctl --wait=sb lsp-add sw4 p41 -- lsp-set-addresses p41 \ > -"dynamic" > -# p41 should not have IPv4 address (as the pool is exhausted). > +# Set an IPv6 prefix. Now p41 should have an IPv6 address. > +ovn-nbctl --wait=sb set Logical-Switch sw5 other_config:ipv6_prefix="aef0::" > AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], > - ["0a:00:00:00:00:29 bef0::800:ff:fe00:29" > + ["0a:00:00:00:00:2b aef0::800:ff:fe00:2b" > +]) > + > +# Change the MAC address to a static one. The IPv6 address should update. > +ovn-nbctl --wait=sb lsp-set-addresses p41 "f0:00:00:00:10:2b dynamic" > +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], > + ["f0:00:00:00:10:2b aef0::f200:ff:fe00:102b" > +]) > + > +# Change the IPv6 prefix. The IPv6 address should update. > +ovn-nbctl --wait=sb set Logical-Switch sw5 other_config:ipv6_prefix="bef0::" > +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], > + ["f0:00:00:00:10:2b bef0::f200:ff:fe00:102b" > +]) > + > +# Clear the other_config. The IPv6 address should be gone > +ovn-nbctl --wait=sb clear Logical-Switch sw5 other_config > +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], > + [[[]] > +]) > + > +# Set the subnet again. Now p41 should get the IPv4 address again. > +ovn-nbctl --wait=sb add Logical-Switch sw5 other_config subnet=192.168.1.0/24 > +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], > + ["f0:00:00:00:10:2b 192.168.1.2" > +]) > + > +# Add another port with a conflicting static IPv4 address. p41 should update. > +ovn-nbctl --wait=sb lsp-add sw5 p42 -- lsp-set-addresses p42 \ > +"f0:00:00:00:10:2c 192.168.1.2" > +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], > + ["f0:00:00:00:10:2b 192.168.1.3" > +]) > + > +# Add an excluded IP address that conflicts with p41. p41 should update. > +ovn-nbctl --wait=sb add Logical-Switch sw5 other_config \ > +exclude_ips="192.168.1.3" > +AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0], > + ["f0:00:00:00:10:2b 192.168.1.4" > ]) > > as ovn-sb _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev