]>
Commit | Line | Data |
---|---|---|
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 | |
22 | VLOG_DEFINE_THIS_MODULE(ovn_util); | |
23 | ||
4685e523 JP |
24 | static void |
25 | add_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 | ||
45 | static void | |
46 | add_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 | */ |
80 | bool | |
81 | is_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 |
94 | static bool |
95 | parse_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(). */ | |
159 | bool | |
160 | extract_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(). */ | |
174 | bool | |
175 | extract_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(). */ | |
197 | bool | |
198 | extract_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(). */ | |
218 | bool | |
219 | extract_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 |
269 | void |
270 | destroy_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. */ | |
280 | char * | |
85423044 | 281 | alloc_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 | |
286 | const char * | |
287 | default_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 | ||
299 | const char * | |
300 | default_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 | */ | |
316 | static const char *OVN_NB_LSP_TYPES[] = { | |
317 | "l2gateway", | |
318 | "localnet", | |
319 | "localport", | |
320 | "router", | |
321 | "vtep", | |
322 | }; | |
323 | ||
324 | bool | |
325 | ovn_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 |
342 | uint32_t | |
343 | sbrec_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 | ||
355 | uint32_t | |
356 | ovn_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 | } |