2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-30 13:58:14 +00:00

ovn-northd: support IPAM with externally specified MAC

The current IPAM implementation allocates both a MAC address and
an IPv4 address when dynamic address allocation is requested. This
patch adds the ability to specify a fixed MAC address for use with
dynamic IPv4 address allocation.

Example:
   ovn-nbctl lsp-set-addresses p1 "00:01:02:03:04:05 dynamic"

Acked-by: Ben Pfaff <blp@ovn.org>
Acked-by: Russell Bryant <russell@ovn.org>
Signed-off-by: Lance Richardson <lrichard@redhat.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Lance Richardson
2016-10-06 15:58:51 -04:00
committed by Ben Pfaff
parent 13c0048ecb
commit 6374d5185d
6 changed files with 83 additions and 15 deletions

1
NEWS
View File

@@ -3,6 +3,7 @@ Post-v2.6.0
- OVN: - OVN:
* QoS is now implemented via egress shaping rather than ingress policing. * QoS is now implemented via egress shaping rather than ingress policing.
* DSCP marking is now supported, via the new northbound QoS table. * DSCP marking is now supported, via the new northbound QoS table.
* IPAM now supports fixed MAC addresses.
- Fixed regression in table stats maintenance introduced in OVS - Fixed regression in table stats maintenance introduced in OVS
2.3.0, wherein the number of OpenFlow table hits and misses was 2.3.0, wherein the number of OpenFlow table hits and misses was
not accurate. not accurate.

View File

@@ -62,6 +62,26 @@ add_ipv6_netaddr(struct lport_addresses *laddrs, struct in6_addr addr,
inet_ntop(AF_INET6, &na->network, na->network_s, sizeof na->network_s); inet_ntop(AF_INET6, &na->network, na->network_s, sizeof na->network_s);
} }
/* Returns true if specified address specifies a dynamic address,
* supporting the following formats:
*
* "dynamic":
* Both MAC and IP are to be allocated dynamically.
*
* "xx:xx:xx:xx:xx:xx dynamic":
* Use specified MAC address, but allocate an IP address
* dynamically.
*/
bool
is_dynamic_lsp_address(const char *address)
{
struct eth_addr ea;
int n;
return (!strcmp(address, "dynamic")
|| (ovs_scan(address, ETH_ADDR_SCAN_FMT" dynamic%n",
ETH_ADDR_SCAN_ARGS(ea), &n) && address[n] == '\0'));
}
/* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which /* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which
* should be of the format 'MAC [IP1 IP2 ..]" where IPn should be a * should be of the format 'MAC [IP1 IP2 ..]" where IPn should be a
* valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and

View File

@@ -53,7 +53,7 @@ struct lport_addresses {
struct ipv6_netaddr *ipv6_addrs; struct ipv6_netaddr *ipv6_addrs;
}; };
bool is_dynamic_lsp_address(const char *address);
bool extract_lsp_addresses(const char *address, struct lport_addresses *); bool extract_lsp_addresses(const char *address, struct lport_addresses *);
bool extract_lrp_networks(const struct nbrec_logical_router_port *, bool extract_lrp_networks(const struct nbrec_logical_router_port *,
struct lport_addresses *); struct lport_addresses *);

View File

@@ -815,7 +815,7 @@ ipam_insert_lsp_addresses(struct ovn_datapath *od, struct ovn_port *op,
char *address) char *address)
{ {
if (!od || !op || !address || !strcmp(address, "unknown") if (!od || !op || !address || !strcmp(address, "unknown")
|| !strcmp(address, "dynamic")) { || is_dynamic_lsp_address(address)) {
return; return;
} }
@@ -940,7 +940,7 @@ ipam_get_unused_ip(struct ovn_datapath *od, uint32_t subnet, uint32_t mask)
static bool static bool
ipam_allocate_addresses(struct ovn_datapath *od, struct ovn_port *op, ipam_allocate_addresses(struct ovn_datapath *od, struct ovn_port *op,
ovs_be32 subnet, ovs_be32 mask) const char *addrspec, ovs_be32 subnet, ovs_be32 mask)
{ {
if (!od || !op || !op->nbsp) { if (!od || !op || !op->nbsp) {
return false; return false;
@@ -952,16 +952,26 @@ ipam_allocate_addresses(struct ovn_datapath *od, struct ovn_port *op,
} }
struct eth_addr mac; struct eth_addr mac;
bool check_mac;
int n = 0;
if (ovs_scan(addrspec, ETH_ADDR_SCAN_FMT" dynamic%n",
ETH_ADDR_SCAN_ARGS(mac), &n)
&& addrspec[n] == '\0') {
check_mac = true;
} else {
uint64_t mac64 = ipam_get_unused_mac(); uint64_t mac64 = ipam_get_unused_mac();
if (!mac64) { if (!mac64) {
return false; return false;
} }
eth_addr_from_uint64(mac64, &mac); eth_addr_from_uint64(mac64, &mac);
check_mac = false;
}
/* Add MAC/IP to MACAM/IPAM hmaps if both addresses were allocated /* Add MAC/IP to MACAM/IPAM hmaps if both addresses were allocated
* successfully. */ * successfully. */
ipam_insert_ip(od, ip, false); ipam_insert_ip(od, ip, false);
ipam_insert_mac(&mac, false); ipam_insert_mac(&mac, check_mac);
char *new_addr = xasprintf(ETH_ADDR_FMT" "IP_FMT, char *new_addr = xasprintf(ETH_ADDR_FMT" "IP_FMT,
ETH_ADDR_ARGS(mac), IP_ARGS(htonl(ip))); ETH_ADDR_ARGS(mac), IP_ARGS(htonl(ip)));
@@ -1018,9 +1028,10 @@ build_ipam(struct hmap *datapaths, struct hmap *ports)
} }
for (size_t j = 0; j < nbsp->n_addresses; j++) { for (size_t j = 0; j < nbsp->n_addresses; j++) {
if (!strcmp(nbsp->addresses[j], "dynamic") if (is_dynamic_lsp_address(nbsp->addresses[j])
&& !nbsp->dynamic_addresses) { && !nbsp->dynamic_addresses) {
if (!ipam_allocate_addresses(od, op, subnet, mask) if (!ipam_allocate_addresses(od, op,
nbsp->addresses[j], subnet, mask)
|| !extract_lsp_addresses(nbsp->dynamic_addresses, || !extract_lsp_addresses(nbsp->dynamic_addresses,
&op->lsp_addrs[op->n_lsp_addrs])) { &op->lsp_addrs[op->n_lsp_addrs])) {
static struct vlog_rate_limit rl static struct vlog_rate_limit rl
@@ -1197,7 +1208,7 @@ join_logical_ports(struct northd_context *ctx,
if (!strcmp(nbsp->addresses[j], "unknown")) { if (!strcmp(nbsp->addresses[j], "unknown")) {
continue; continue;
} }
if (!strcmp(nbsp->addresses[j], "dynamic")) { if (is_dynamic_lsp_address(nbsp->addresses[j])) {
if (nbsp->dynamic_addresses) { if (nbsp->dynamic_addresses) {
if (!extract_lsp_addresses(nbsp->dynamic_addresses, if (!extract_lsp_addresses(nbsp->dynamic_addresses,
&op->lsp_addrs[op->n_lsp_addrs])) { &op->lsp_addrs[op->n_lsp_addrs])) {
@@ -3078,7 +3089,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
ovn_multicast_add(mcgroups, &mc_unknown, op); ovn_multicast_add(mcgroups, &mc_unknown, op);
op->od->has_unknown = true; op->od->has_unknown = true;
} }
} else if (!strcmp(op->nbsp->addresses[i], "dynamic")) { } else if (is_dynamic_lsp_address(op->nbsp->addresses[i])) {
if (!op->nbsp->dynamic_addresses if (!op->nbsp->dynamic_addresses
|| !ovs_scan(op->nbsp->dynamic_addresses, || !ovs_scan(op->nbsp->dynamic_addresses,
ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) { ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {

View File

@@ -479,6 +479,35 @@
column="other_config" key="subnet"/> in the port's <ref column="other_config" key="subnet"/> in the port's <ref
table="Logical_Switch"/>. table="Logical_Switch"/>.
</dd> </dd>
<dt><code>Ethernet address followed by keyword "dynamic"</code></dt>
<dd>
<p>
The keyword <code>dynamic</code> after the MAC address indicates
that <code>ovn-northd</code> should choose an unused IPv4 address
from the logical port's subnet and store it with the specified
MAC in the port's <ref column="dynamic_addresses"/> column.
<code>ovn-northd</code> will use the subnet specified in <ref
table="Logical_Switch" column="other_config" key="subnet"/> in
the port's <ref table="Logical_Switch"/> table.
</p>
<p>
Examples:
</p>
<dl>
<dt><code>80:fa:5b:06:72:b7 dynamic</code></dt>
<dd>
This indicates that the logical port owns the specified
MAC address and <code>ovn-northd</code> should allocate an
unused IPv4 address for the logical port from the corresponding
logical switch subnet.
</dd>
</dl>
</dd>
</dl> </dl>
</column> </column>
@@ -487,9 +516,9 @@
Addresses assigned to the logical port by <code>ovn-northd</code>, if Addresses assigned to the logical port by <code>ovn-northd</code>, if
<code>dynamic</code> is specified in <ref column="addresses"/>. <code>dynamic</code> is specified in <ref column="addresses"/>.
Addresses will be of the same format as those that populate the <ref Addresses will be of the same format as those that populate the <ref
column="addresses"/> column. Note that these addresses are column="addresses"/> column. Note that dynamically assigned
constructed and managed locally in ovn-northd, so they cannot be addresses are constructed and managed locally in ovn-northd, so they
reconstructed in the event that the database is lost. cannot be reconstructed in the event that the database is lost.
</p> </p>
</column> </column>

View File

@@ -4689,6 +4689,13 @@ AT_CHECK([ovn-nbctl get Logical-Switch-Port p30 dynamic_addresses], [0],
["0a:00:00:00:00:20 192.168.1.17" ["0a:00:00:00:00:20 192.168.1.17"
]) ])
# Test static MAC address with dynamically allocated IP
ovn-nbctl --wait=sb lsp-add sw0 p31 -- lsp-set-addresses p31 \
"fe:dc:ba:98:76:54 dynamic"
AT_CHECK([ovn-nbctl get Logical-Switch-Port p31 dynamic_addresses], [0],
["fe:dc:ba:98:76:54 192.168.1.18"
])
as ovn-sb as ovn-sb
OVS_APP_EXIT_AND_WAIT([ovsdb-server]) OVS_APP_EXIT_AND_WAIT([ovsdb-server])