]> git.proxmox.com Git - mirror_ovs.git/blame - ovn/lib/ovn-util.c
OVN: add static IP support to IPAM
[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"
8bf33222 20#include "ovn/lib/ovn-sb-idl.h"
218351dd
RR
21
22VLOG_DEFINE_THIS_MODULE(ovn_util);
23
4685e523
JP
24static void
25add_ipv4_netaddr(struct lport_addresses *laddrs, ovs_be32 addr,
26 unsigned int plen)
27{
28 laddrs->n_ipv4_addrs++;
29 laddrs->ipv4_addrs = xrealloc(laddrs->ipv4_addrs,
30 laddrs->n_ipv4_addrs * sizeof *laddrs->ipv4_addrs);
31
32 struct ipv4_netaddr *na = &laddrs->ipv4_addrs[laddrs->n_ipv4_addrs - 1];
33
34 na->addr = addr;
35 na->mask = be32_prefix_mask(plen);
36 na->network = addr & na->mask;
37 na->plen = plen;
38
c3179d6f
JP
39 ovs_be32 bcast = addr | ~na->mask;
40 inet_ntop(AF_INET, &addr, na->addr_s, sizeof na->addr_s);
41 inet_ntop(AF_INET, &na->network, na->network_s, sizeof na->network_s);
42 inet_ntop(AF_INET, &bcast, na->bcast_s, sizeof na->bcast_s);
4685e523
JP
43}
44
45static void
46add_ipv6_netaddr(struct lport_addresses *laddrs, struct in6_addr addr,
47 unsigned int plen)
48{
49 laddrs->n_ipv6_addrs++;
50 laddrs->ipv6_addrs = xrealloc(laddrs->ipv6_addrs,
51 laddrs->n_ipv6_addrs * sizeof *laddrs->ipv6_addrs);
52
53 struct ipv6_netaddr *na = &laddrs->ipv6_addrs[laddrs->n_ipv6_addrs - 1];
54
55 memcpy(&na->addr, &addr, sizeof na->addr);
56 na->mask = ipv6_create_mask(plen);
57 na->network = ipv6_addr_bitand(&addr, &na->mask);
58 na->plen = plen;
fbd9b767 59 in6_addr_solicited_node(&na->sn_addr, &addr);
4685e523 60
c3179d6f
JP
61 inet_ntop(AF_INET6, &addr, na->addr_s, sizeof na->addr_s);
62 inet_ntop(AF_INET6, &na->sn_addr, na->sn_addr_s, sizeof na->sn_addr_s);
63 inet_ntop(AF_INET6, &na->network, na->network_s, sizeof na->network_s);
4685e523
JP
64}
65
6374d518
LR
66/* Returns true if specified address specifies a dynamic address,
67 * supporting the following formats:
68 *
69 * "dynamic":
70 * Both MAC and IP are to be allocated dynamically.
71 *
72 * "xx:xx:xx:xx:xx:xx dynamic":
73 * Use specified MAC address, but allocate an IP address
74 * dynamically.
e46b7020
LB
75 *
76 * "dynamic x.x.x.x":
77 * Use specified IP address, but allocate a MAC address
78 * dynamically.
6374d518
LR
79 */
80bool
81is_dynamic_lsp_address(const char *address)
82{
83 struct eth_addr ea;
e46b7020 84 ovs_be32 ip;
6374d518
LR
85 int n;
86 return (!strcmp(address, "dynamic")
e46b7020
LB
87 || (ovs_scan(address, "dynamic "IP_SCAN_FMT"%n",
88 IP_SCAN_ARGS(&ip), &n)
89 && address[n] == '\0')
6374d518
LR
90 || (ovs_scan(address, ETH_ADDR_SCAN_FMT" dynamic%n",
91 ETH_ADDR_SCAN_ARGS(ea), &n) && address[n] == '\0'));
92}
93
f7c5e0db
NS
94static bool
95parse_and_store_addresses(const char *address, struct lport_addresses *laddrs,
96 int *ofs, bool extract_eth_addr)
218351dd 97{
f2a715b5
JP
98 memset(laddrs, 0, sizeof *laddrs);
99
8439c2eb 100 const char *buf = address;
26b9e08d 101 const char *const start = buf;
218351dd 102 int buf_index = 0;
8439c2eb 103 const char *buf_end = buf + strlen(address);
218351dd 104
f7c5e0db
NS
105 if (extract_eth_addr) {
106 if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT,
107 ETH_ADDR_SCAN_ARGS(laddrs->ea))) {
108 laddrs->ea = eth_addr_zero;
109 *ofs = 0;
110 return false;
111 }
112
113 snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT,
114 ETH_ADDR_ARGS(laddrs->ea));
115 }
f2a715b5 116
218351dd
RR
117 ovs_be32 ip4;
118 struct in6_addr ip6;
119 unsigned int plen;
120 char *error;
121
218351dd
RR
122 /* Loop through the buffer and extract the IPv4/IPv6 addresses
123 * and store in the 'laddrs'. Break the loop if invalid data is found.
124 */
125 buf += buf_index;
126 while (buf < buf_end) {
127 buf_index = 0;
128 error = ip_parse_cidr_len(buf, &buf_index, &ip4, &plen);
129 if (!error) {
4685e523 130 add_ipv4_netaddr(laddrs, ip4, plen);
218351dd
RR
131 buf += buf_index;
132 continue;
133 }
134 free(error);
135 error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen);
5942a98d 136 if (!error) {
4685e523
JP
137 add_ipv6_netaddr(laddrs, ip6, plen);
138 } else {
218351dd
RR
139 free(error);
140 break;
141 }
142 buf += buf_index;
143 }
144
26b9e08d 145 *ofs = buf - start;
218351dd
RR
146 return true;
147}
3bd4ae23 148
f7c5e0db
NS
149/* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which
150 * should be of the format "MAC [IP1 IP2 ..] .." where IPn should be a
151 * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and
152 * 'ipv6_addrs' fields of 'laddrs'. There may be additional content in
153 * 'address' after "MAC [IP1 IP2 .. ]". The value of 'ofs' that is
154 * returned indicates the offset where that additional content begins.
155 *
156 * Returns true if at least 'MAC' is found in 'address', false otherwise.
157 *
158 * The caller must call destroy_lport_addresses(). */
159bool
160extract_addresses(const char *address, struct lport_addresses *laddrs,
161 int *ofs)
162{
163 return parse_and_store_addresses(address, laddrs, ofs, true);
164}
165
26b9e08d
MS
166/* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which
167 * should be of the format 'MAC [IP1 IP2 ..]" where IPn should be a
168 * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and
169 * 'ipv6_addrs' fields of 'laddrs'.
170 *
171 * Return true if at least 'MAC' is found in 'address', false otherwise.
172 *
173 * The caller must call destroy_lport_addresses(). */
174bool
175extract_lsp_addresses(const char *address, struct lport_addresses *laddrs)
176{
177 int ofs;
178 bool success = extract_addresses(address, laddrs, &ofs);
179
180 if (success && ofs < strlen(address)) {
181 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
182 VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", address);
183 }
184
185 return success;
186}
187
f7c5e0db
NS
188/* Extracts the IPv4 and IPv6 addresses from * 'address' which
189 * should be of the format 'IP1 IP2 .." where IPn should be a
190 * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and
191 * 'ipv6_addrs' fields of 'laddrs'.
192 *
193 * Return true if at least one IP address is found in 'address',
194 * false otherwise.
195 *
196 * The caller must call destroy_lport_addresses(). */
197bool
198extract_ip_addresses(const char *address, struct lport_addresses *laddrs)
199{
200 int ofs;
201 if (parse_and_store_addresses(address, laddrs, &ofs, false)) {
202 return (laddrs->n_ipv4_addrs || laddrs->n_ipv6_addrs);
203 }
204
205 return false;
206}
207
4685e523
JP
208/* Extracts the mac, IPv4 and IPv6 addresses from the
209 * "nbrec_logical_router_port" parameter 'lrp'. Stores the IPv4 and
210 * IPv6 addresses in the 'ipv4_addrs' and 'ipv6_addrs' fields of
a63f7235
JP
211 * 'laddrs', respectively. In addition, a link local IPv6 address
212 * based on the 'mac' member of 'lrp' is added to the 'ipv6_addrs'
213 * field.
4685e523 214 *
a63f7235 215 * Return true if a valid 'mac' address is found in 'lrp', false otherwise.
4685e523
JP
216 *
217 * The caller must call destroy_lport_addresses(). */
218bool
219extract_lrp_networks(const struct nbrec_logical_router_port *lrp,
220 struct lport_addresses *laddrs)
221{
222 memset(laddrs, 0, sizeof *laddrs);
223
224 if (!eth_addr_from_string(lrp->mac, &laddrs->ea)) {
225 laddrs->ea = eth_addr_zero;
226 return false;
227 }
c3179d6f
JP
228 snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT,
229 ETH_ADDR_ARGS(laddrs->ea));
4685e523
JP
230
231 for (int i = 0; i < lrp->n_networks; i++) {
232 ovs_be32 ip4;
233 struct in6_addr ip6;
234 unsigned int plen;
235 char *error;
236
237 error = ip_parse_cidr(lrp->networks[i], &ip4, &plen);
238 if (!error) {
6b785fd8 239 if (!ip4) {
4685e523
JP
240 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
241 VLOG_WARN_RL(&rl, "bad 'networks' %s", lrp->networks[i]);
242 continue;
243 }
244
245 add_ipv4_netaddr(laddrs, ip4, plen);
246 continue;
247 }
248 free(error);
249
250 error = ipv6_parse_cidr(lrp->networks[i], &ip6, &plen);
251 if (!error) {
4685e523
JP
252 add_ipv6_netaddr(laddrs, ip6, plen);
253 } else {
254 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
255 VLOG_INFO_RL(&rl, "invalid syntax '%s' in networks",
256 lrp->networks[i]);
257 free(error);
258 }
259 }
260
a63f7235
JP
261 /* Always add the IPv6 link local address. */
262 struct in6_addr lla;
263 in6_generate_lla(laddrs->ea, &lla);
264 add_ipv6_netaddr(laddrs, lla, 64);
265
4685e523
JP
266 return true;
267}
268
f2a715b5
JP
269void
270destroy_lport_addresses(struct lport_addresses *laddrs)
271{
f2a715b5 272 free(laddrs->ipv4_addrs);
f2a715b5
JP
273 free(laddrs->ipv6_addrs);
274}
275
3bd4ae23 276/* Allocates a key for NAT conntrack zone allocation for a provided
34114cf8 277 * 'key' record and a 'type'.
3bd4ae23
GS
278 *
279 * It is the caller's responsibility to free the allocated memory. */
280char *
85423044 281alloc_nat_zone_key(const struct uuid *key, const char *type)
3bd4ae23 282{
85423044 283 return xasprintf(UUID_FMT"_%s", UUID_ARGS(key), type);
3bd4ae23 284}
8ad609c0
BP
285
286const char *
287default_nb_db(void)
288{
289 static char *def;
290 if (!def) {
291 def = getenv("OVN_NB_DB");
292 if (!def) {
293 def = xasprintf("unix:%s/ovnnb_db.sock", ovs_rundir());
294 }
295 }
296 return def;
297}
298
299const char *
300default_sb_db(void)
301{
302 static char *def;
303 if (!def) {
304 def = getenv("OVN_SB_DB");
305 if (!def) {
306 def = xasprintf("unix:%s/ovnsb_db.sock", ovs_rundir());
307 }
308 }
309 return def;
310}
173acc1c
MM
311
312/* l3gateway, chassisredirect, and patch
313 * are not in this list since they are
314 * only set in the SB DB by northd
315 */
316static const char *OVN_NB_LSP_TYPES[] = {
317 "l2gateway",
318 "localnet",
319 "localport",
320 "router",
321 "vtep",
322};
323
324bool
325ovn_is_known_nb_lsp_type(const char *type)
326{
327 int i;
328
329 if (!type || !type[0]) {
330 return true;
331 }
332
333 for (i = 0; i < ARRAY_SIZE(OVN_NB_LSP_TYPES); ++i) {
334 if (!strcmp(OVN_NB_LSP_TYPES[i], type)) {
335 return true;
336 }
337 }
338
339 return false;
340}
8bf33222
BP
341\f
342uint32_t
343sbrec_logical_flow_hash(const struct sbrec_logical_flow *lf)
344{
345 const struct sbrec_datapath_binding *ld = lf->logical_datapath;
346 if (!ld) {
347 return 0;
348 }
349
350 return ovn_logical_flow_hash(&ld->header_.uuid,
351 lf->table_id, lf->pipeline,
352 lf->priority, lf->match, lf->actions);
353}
354
355uint32_t
356ovn_logical_flow_hash(const struct uuid *logical_datapath,
357 uint8_t table_id, const char *pipeline,
358 uint16_t priority,
359 const char *match, const char *actions)
360{
361 size_t hash = uuid_hash(logical_datapath);
362 hash = hash_2words((table_id << 16) | priority, hash);
363 hash = hash_string(pipeline, hash);
364 hash = hash_string(match, hash);
365 return hash_string(actions, hash);
366}