]> git.proxmox.com Git - mirror_ovs.git/blame - ovn/lib/ovn-util.c
ovn-northd: support IPAM with externally specified MAC
[mirror_ovs.git] / ovn / lib / ovn-util.c
CommitLineData
218351dd
RR
1/*
2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at:
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15#include <config.h>
16#include "ovn-util.h"
8ad609c0 17#include "dirs.h"
218351dd 18#include "openvswitch/vlog.h"
4685e523 19#include "ovn/lib/ovn-nb-idl.h"
218351dd
RR
20
21VLOG_DEFINE_THIS_MODULE(ovn_util);
22
4685e523
JP
23static void
24add_ipv4_netaddr(struct lport_addresses *laddrs, ovs_be32 addr,
25 unsigned int plen)
26{
27 laddrs->n_ipv4_addrs++;
28 laddrs->ipv4_addrs = xrealloc(laddrs->ipv4_addrs,
29 laddrs->n_ipv4_addrs * sizeof *laddrs->ipv4_addrs);
30
31 struct ipv4_netaddr *na = &laddrs->ipv4_addrs[laddrs->n_ipv4_addrs - 1];
32
33 na->addr = addr;
34 na->mask = be32_prefix_mask(plen);
35 na->network = addr & na->mask;
36 na->plen = plen;
37
c3179d6f
JP
38 ovs_be32 bcast = addr | ~na->mask;
39 inet_ntop(AF_INET, &addr, na->addr_s, sizeof na->addr_s);
40 inet_ntop(AF_INET, &na->network, na->network_s, sizeof na->network_s);
41 inet_ntop(AF_INET, &bcast, na->bcast_s, sizeof na->bcast_s);
4685e523
JP
42}
43
44static void
45add_ipv6_netaddr(struct lport_addresses *laddrs, struct in6_addr addr,
46 unsigned int plen)
47{
48 laddrs->n_ipv6_addrs++;
49 laddrs->ipv6_addrs = xrealloc(laddrs->ipv6_addrs,
50 laddrs->n_ipv6_addrs * sizeof *laddrs->ipv6_addrs);
51
52 struct ipv6_netaddr *na = &laddrs->ipv6_addrs[laddrs->n_ipv6_addrs - 1];
53
54 memcpy(&na->addr, &addr, sizeof na->addr);
55 na->mask = ipv6_create_mask(plen);
56 na->network = ipv6_addr_bitand(&addr, &na->mask);
57 na->plen = plen;
fbd9b767 58 in6_addr_solicited_node(&na->sn_addr, &addr);
4685e523 59
c3179d6f
JP
60 inet_ntop(AF_INET6, &addr, na->addr_s, sizeof na->addr_s);
61 inet_ntop(AF_INET6, &na->sn_addr, na->sn_addr_s, sizeof na->sn_addr_s);
62 inet_ntop(AF_INET6, &na->network, na->network_s, sizeof na->network_s);
4685e523
JP
63}
64
6374d518
LR
65/* Returns true if specified address specifies a dynamic address,
66 * supporting the following formats:
67 *
68 * "dynamic":
69 * Both MAC and IP are to be allocated dynamically.
70 *
71 * "xx:xx:xx:xx:xx:xx dynamic":
72 * Use specified MAC address, but allocate an IP address
73 * dynamically.
74 */
75bool
76is_dynamic_lsp_address(const char *address)
77{
78 struct eth_addr ea;
79 int n;
80 return (!strcmp(address, "dynamic")
81 || (ovs_scan(address, ETH_ADDR_SCAN_FMT" dynamic%n",
82 ETH_ADDR_SCAN_ARGS(ea), &n) && address[n] == '\0'));
83}
84
4685e523
JP
85/* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which
86 * should be of the format 'MAC [IP1 IP2 ..]" where IPn should be a
87 * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and
88 * 'ipv6_addrs' fields of 'laddrs'.
f2a715b5 89 *
218351dd 90 * Return true if at least 'MAC' is found in 'address', false otherwise.
f2a715b5 91 *
4685e523 92 * The caller must call destroy_lport_addresses(). */
218351dd 93bool
8439c2eb 94extract_lsp_addresses(const char *address, struct lport_addresses *laddrs)
218351dd 95{
f2a715b5
JP
96 memset(laddrs, 0, sizeof *laddrs);
97
8439c2eb 98 const char *buf = address;
218351dd 99 int buf_index = 0;
8439c2eb 100 const char *buf_end = buf + strlen(address);
218351dd
RR
101 if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT,
102 ETH_ADDR_SCAN_ARGS(laddrs->ea))) {
f2a715b5 103 laddrs->ea = eth_addr_zero;
218351dd
RR
104 return false;
105 }
106
c3179d6f
JP
107 snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT,
108 ETH_ADDR_ARGS(laddrs->ea));
f2a715b5 109
218351dd
RR
110 ovs_be32 ip4;
111 struct in6_addr ip6;
112 unsigned int plen;
113 char *error;
114
218351dd
RR
115 /* Loop through the buffer and extract the IPv4/IPv6 addresses
116 * and store in the 'laddrs'. Break the loop if invalid data is found.
117 */
118 buf += buf_index;
119 while (buf < buf_end) {
120 buf_index = 0;
121 error = ip_parse_cidr_len(buf, &buf_index, &ip4, &plen);
122 if (!error) {
4685e523 123 add_ipv4_netaddr(laddrs, ip4, plen);
218351dd
RR
124 buf += buf_index;
125 continue;
126 }
127 free(error);
128 error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen);
5942a98d 129 if (!error) {
4685e523
JP
130 add_ipv6_netaddr(laddrs, ip6, plen);
131 } else {
218351dd
RR
132 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
133 VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", address);
134 free(error);
135 break;
136 }
137 buf += buf_index;
138 }
139
140 return true;
141}
3bd4ae23 142
4685e523
JP
143/* Extracts the mac, IPv4 and IPv6 addresses from the
144 * "nbrec_logical_router_port" parameter 'lrp'. Stores the IPv4 and
145 * IPv6 addresses in the 'ipv4_addrs' and 'ipv6_addrs' fields of
a63f7235
JP
146 * 'laddrs', respectively. In addition, a link local IPv6 address
147 * based on the 'mac' member of 'lrp' is added to the 'ipv6_addrs'
148 * field.
4685e523 149 *
a63f7235 150 * Return true if a valid 'mac' address is found in 'lrp', false otherwise.
4685e523
JP
151 *
152 * The caller must call destroy_lport_addresses(). */
153bool
154extract_lrp_networks(const struct nbrec_logical_router_port *lrp,
155 struct lport_addresses *laddrs)
156{
157 memset(laddrs, 0, sizeof *laddrs);
158
159 if (!eth_addr_from_string(lrp->mac, &laddrs->ea)) {
160 laddrs->ea = eth_addr_zero;
161 return false;
162 }
c3179d6f
JP
163 snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT,
164 ETH_ADDR_ARGS(laddrs->ea));
4685e523
JP
165
166 for (int i = 0; i < lrp->n_networks; i++) {
167 ovs_be32 ip4;
168 struct in6_addr ip6;
169 unsigned int plen;
170 char *error;
171
172 error = ip_parse_cidr(lrp->networks[i], &ip4, &plen);
173 if (!error) {
174 if (!ip4 || plen == 32) {
175 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
176 VLOG_WARN_RL(&rl, "bad 'networks' %s", lrp->networks[i]);
177 continue;
178 }
179
180 add_ipv4_netaddr(laddrs, ip4, plen);
181 continue;
182 }
183 free(error);
184
185 error = ipv6_parse_cidr(lrp->networks[i], &ip6, &plen);
186 if (!error) {
187 if (plen == 128) {
188 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
189 VLOG_WARN_RL(&rl, "bad 'networks' %s", lrp->networks[i]);
190 continue;
191 }
192 add_ipv6_netaddr(laddrs, ip6, plen);
193 } else {
194 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
195 VLOG_INFO_RL(&rl, "invalid syntax '%s' in networks",
196 lrp->networks[i]);
197 free(error);
198 }
199 }
200
a63f7235
JP
201 /* Always add the IPv6 link local address. */
202 struct in6_addr lla;
203 in6_generate_lla(laddrs->ea, &lla);
204 add_ipv6_netaddr(laddrs, lla, 64);
205
4685e523
JP
206 return true;
207}
208
f2a715b5
JP
209void
210destroy_lport_addresses(struct lport_addresses *laddrs)
211{
f2a715b5 212 free(laddrs->ipv4_addrs);
f2a715b5
JP
213 free(laddrs->ipv6_addrs);
214}
215
3bd4ae23 216/* Allocates a key for NAT conntrack zone allocation for a provided
34114cf8 217 * 'key' record and a 'type'.
3bd4ae23
GS
218 *
219 * It is the caller's responsibility to free the allocated memory. */
220char *
85423044 221alloc_nat_zone_key(const struct uuid *key, const char *type)
3bd4ae23 222{
85423044 223 return xasprintf(UUID_FMT"_%s", UUID_ARGS(key), type);
3bd4ae23 224}
8ad609c0
BP
225
226const char *
227default_nb_db(void)
228{
229 static char *def;
230 if (!def) {
231 def = getenv("OVN_NB_DB");
232 if (!def) {
233 def = xasprintf("unix:%s/ovnnb_db.sock", ovs_rundir());
234 }
235 }
236 return def;
237}
238
239const char *
240default_sb_db(void)
241{
242 static char *def;
243 if (!def) {
244 def = getenv("OVN_SB_DB");
245 if (!def) {
246 def = xasprintf("unix:%s/ovnsb_db.sock", ovs_rundir());
247 }
248 }
249 return def;
250}