]> git.proxmox.com Git - mirror_ovs.git/blob - ovn/lib/ovn-util.c
ovn-northd: support IPAM with externally specified MAC
[mirror_ovs.git] / ovn / lib / ovn-util.c
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"
17 #include "dirs.h"
18 #include "openvswitch/vlog.h"
19 #include "ovn/lib/ovn-nb-idl.h"
20
21 VLOG_DEFINE_THIS_MODULE(ovn_util);
22
23 static void
24 add_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
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);
42 }
43
44 static void
45 add_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;
58 in6_addr_solicited_node(&na->sn_addr, &addr);
59
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);
63 }
64
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 */
75 bool
76 is_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
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'.
89 *
90 * Return true if at least 'MAC' is found in 'address', false otherwise.
91 *
92 * The caller must call destroy_lport_addresses(). */
93 bool
94 extract_lsp_addresses(const char *address, struct lport_addresses *laddrs)
95 {
96 memset(laddrs, 0, sizeof *laddrs);
97
98 const char *buf = address;
99 int buf_index = 0;
100 const char *buf_end = buf + strlen(address);
101 if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT,
102 ETH_ADDR_SCAN_ARGS(laddrs->ea))) {
103 laddrs->ea = eth_addr_zero;
104 return false;
105 }
106
107 snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT,
108 ETH_ADDR_ARGS(laddrs->ea));
109
110 ovs_be32 ip4;
111 struct in6_addr ip6;
112 unsigned int plen;
113 char *error;
114
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) {
123 add_ipv4_netaddr(laddrs, ip4, plen);
124 buf += buf_index;
125 continue;
126 }
127 free(error);
128 error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen);
129 if (!error) {
130 add_ipv6_netaddr(laddrs, ip6, plen);
131 } else {
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 }
142
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
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.
149 *
150 * Return true if a valid 'mac' address is found in 'lrp', false otherwise.
151 *
152 * The caller must call destroy_lport_addresses(). */
153 bool
154 extract_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 }
163 snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT,
164 ETH_ADDR_ARGS(laddrs->ea));
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
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
206 return true;
207 }
208
209 void
210 destroy_lport_addresses(struct lport_addresses *laddrs)
211 {
212 free(laddrs->ipv4_addrs);
213 free(laddrs->ipv6_addrs);
214 }
215
216 /* Allocates a key for NAT conntrack zone allocation for a provided
217 * 'key' record and a 'type'.
218 *
219 * It is the caller's responsibility to free the allocated memory. */
220 char *
221 alloc_nat_zone_key(const struct uuid *key, const char *type)
222 {
223 return xasprintf(UUID_FMT"_%s", UUID_ARGS(key), type);
224 }
225
226 const char *
227 default_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
239 const char *
240 default_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 }