40299176151e1e01c95347361caef481b3b6d1b8
[cascardo/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 "openvswitch/vlog.h"
18 #include "ovn/lib/ovn-nb-idl.h"
19
20 VLOG_DEFINE_THIS_MODULE(ovn_util);
21
22 static void
23 add_ipv4_netaddr(struct lport_addresses *laddrs, ovs_be32 addr,
24                  unsigned int plen)
25 {
26     laddrs->n_ipv4_addrs++;
27     laddrs->ipv4_addrs = xrealloc(laddrs->ipv4_addrs,
28         laddrs->n_ipv4_addrs * sizeof *laddrs->ipv4_addrs);
29
30     struct ipv4_netaddr *na = &laddrs->ipv4_addrs[laddrs->n_ipv4_addrs - 1];
31
32     na->addr = addr;
33     na->mask = be32_prefix_mask(plen);
34     na->network = addr & na->mask;
35     na->plen = plen;
36
37     na->addr_s = xasprintf(IP_FMT, IP_ARGS(addr));
38     na->network_s = xasprintf(IP_FMT, IP_ARGS(na->network));
39     na->bcast_s = xasprintf(IP_FMT, IP_ARGS(addr | ~na->mask));
40 }
41
42 static void
43 add_ipv6_netaddr(struct lport_addresses *laddrs, struct in6_addr addr,
44                  unsigned int plen)
45 {
46     laddrs->n_ipv6_addrs++;
47     laddrs->ipv6_addrs = xrealloc(laddrs->ipv6_addrs,
48         laddrs->n_ipv6_addrs * sizeof *laddrs->ipv6_addrs);
49
50     struct ipv6_netaddr *na = &laddrs->ipv6_addrs[laddrs->n_ipv6_addrs - 1];
51
52     memcpy(&na->addr, &addr, sizeof na->addr);
53     na->mask = ipv6_create_mask(plen);
54     na->network = ipv6_addr_bitand(&addr, &na->mask);
55     na->plen = plen;
56
57     na->addr_s = xmalloc(INET6_ADDRSTRLEN);
58     inet_ntop(AF_INET6, &addr, na->addr_s, INET6_ADDRSTRLEN);
59     na->network_s = xmalloc(INET6_ADDRSTRLEN);
60     inet_ntop(AF_INET6, &na->network, na->network_s, INET6_ADDRSTRLEN);
61 }
62
63 /* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which
64  * should be of the format 'MAC [IP1 IP2 ..]" where IPn should be a
65  * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and
66  * 'ipv6_addrs' fields of 'laddrs'.
67  *
68  * Return true if at least 'MAC' is found in 'address', false otherwise.
69  *
70  * The caller must call destroy_lport_addresses(). */
71 bool
72 extract_lsp_addresses(char *address, struct lport_addresses *laddrs)
73 {
74     memset(laddrs, 0, sizeof *laddrs);
75
76     char *buf = address;
77     int buf_index = 0;
78     char *buf_end = buf + strlen(address);
79     if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT,
80                       ETH_ADDR_SCAN_ARGS(laddrs->ea))) {
81         laddrs->ea = eth_addr_zero;
82         return false;
83     }
84
85     laddrs->ea_s = xasprintf(ETH_ADDR_FMT, ETH_ADDR_ARGS(laddrs->ea));
86
87     ovs_be32 ip4;
88     struct in6_addr ip6;
89     unsigned int plen;
90     char *error;
91
92     /* Loop through the buffer and extract the IPv4/IPv6 addresses
93      * and store in the 'laddrs'. Break the loop if invalid data is found.
94      */
95     buf += buf_index;
96     while (buf < buf_end) {
97         buf_index = 0;
98         error = ip_parse_cidr_len(buf, &buf_index, &ip4, &plen);
99         if (!error) {
100             add_ipv4_netaddr(laddrs, ip4, plen);
101             buf += buf_index;
102             continue;
103         }
104         free(error);
105         error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen);
106         if (!error) {
107             add_ipv6_netaddr(laddrs, ip6, plen);
108         } else {
109             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
110             VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", address);
111             free(error);
112             break;
113         }
114         buf += buf_index;
115     }
116
117     return true;
118 }
119
120 /* Extracts the mac, IPv4 and IPv6 addresses from the
121  * "nbrec_logical_router_port" parameter 'lrp'.  Stores the IPv4 and
122  * IPv6 addresses in the 'ipv4_addrs' and 'ipv6_addrs' fields of
123  * 'laddrs', respectively.
124  *
125  * Return true if at least 'MAC' is found in 'lrp', false otherwise.
126  *
127  * The caller must call destroy_lport_addresses(). */
128 bool
129 extract_lrp_networks(const struct nbrec_logical_router_port *lrp,
130                      struct lport_addresses *laddrs)
131 {
132     memset(laddrs, 0, sizeof *laddrs);
133
134     if (!eth_addr_from_string(lrp->mac, &laddrs->ea)) {
135         laddrs->ea = eth_addr_zero;
136         return false;
137     }
138     laddrs->ea_s = xasprintf(ETH_ADDR_FMT, ETH_ADDR_ARGS(laddrs->ea));
139
140     for (int i = 0; i < lrp->n_networks; i++) {
141         ovs_be32 ip4;
142         struct in6_addr ip6;
143         unsigned int plen;
144         char *error;
145
146         error = ip_parse_cidr(lrp->networks[i], &ip4, &plen);
147         if (!error) {
148             if (!ip4 || plen == 32) {
149                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
150                 VLOG_WARN_RL(&rl, "bad 'networks' %s", lrp->networks[i]);
151                 continue;
152             }
153
154             add_ipv4_netaddr(laddrs, ip4, plen);
155             continue;
156         }
157         free(error);
158
159         error = ipv6_parse_cidr(lrp->networks[i], &ip6, &plen);
160         if (!error) {
161             if (plen == 128) {
162                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
163                 VLOG_WARN_RL(&rl, "bad 'networks' %s", lrp->networks[i]);
164                 continue;
165             }
166             add_ipv6_netaddr(laddrs, ip6, plen);
167         } else {
168             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
169             VLOG_INFO_RL(&rl, "invalid syntax '%s' in networks",
170                          lrp->networks[i]);
171             free(error);
172         }
173     }
174
175     return true;
176 }
177
178 void
179 destroy_lport_addresses(struct lport_addresses *laddrs)
180 {
181     free(laddrs->ea_s);
182
183     for (int i = 0; i < laddrs->n_ipv4_addrs; i++) {
184         free(laddrs->ipv4_addrs[i].addr_s);
185         free(laddrs->ipv4_addrs[i].network_s);
186         free(laddrs->ipv4_addrs[i].bcast_s);
187     }
188     free(laddrs->ipv4_addrs);
189
190     for (int i = 0; i < laddrs->n_ipv6_addrs; i++) {
191         free(laddrs->ipv6_addrs[i].addr_s);
192         free(laddrs->ipv6_addrs[i].network_s);
193     }
194     free(laddrs->ipv6_addrs);
195 }
196
197 /* Allocates a key for NAT conntrack zone allocation for a provided
198  * 'key' record and a 'type'.
199  *
200  * It is the caller's responsibility to free the allocated memory. */
201 char *
202 alloc_nat_zone_key(const char *key, const char *type)
203 {
204     return xasprintf("%s_%s", key, type);
205 }