ovn-util: Add string representations to 'lport_addresses'.
[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-sb-idl.h"
19
20 VLOG_DEFINE_THIS_MODULE(ovn_util);
21
22 /*
23  * Extracts the mac, ipv4 and ipv6 addresses from the input param 'address'
24  * which should be of the format 'MAC [IP1 IP2 ..]" where IPn should be
25  * a valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and
26  * 'ipv6_addrs' fields of input param 'laddrs'.  If input param
27  * 'store_ipv6' is true only then extracted ipv6 addresses are stored in
28  * 'ipv6_addrs' fields.
29  *
30  * Return true if at least 'MAC' is found in 'address', false otherwise.
31  *
32  * The caller must call destroy_lport_addresses().
33  *
34  * Eg 1.
35  * If 'address' = '00:00:00:00:00:01 10.0.0.4 fe80::ea2a:eaff:fe28:3390/64
36  *                 30.0.0.3/23' and 'store_ipv6' = true
37  * then returns true with laddrs->n_ipv4_addrs = 2, naddrs->n_ipv6_addrs = 1.
38  *
39  * Eg. 2
40  * If 'address' = '00:00:00:00:00:01 10.0.0.4 fe80::ea2a:eaff:fe28:3390/64
41  *                 30.0.0.3/23' and 'store_ipv6' = false
42  * then returns true with laddrs->n_ipv4_addrs = 2, naddrs->n_ipv6_addrs = 0.
43  *
44  * Eg 3. If 'address' = '00:00:00:00:00:01 10.0.0.4 addr 30.0.0.4', then
45  * returns true with laddrs->n_ipv4_addrs = 1 and laddrs->n_ipv6_addrs = 0.
46  */
47 bool
48 extract_lsp_addresses(char *address, struct lport_addresses *laddrs,
49                       bool store_ipv6)
50 {
51     memset(laddrs, 0, sizeof *laddrs);
52
53     char *buf = address;
54     int buf_index = 0;
55     char *buf_end = buf + strlen(address);
56     if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT,
57                       ETH_ADDR_SCAN_ARGS(laddrs->ea))) {
58         laddrs->ea = eth_addr_zero;
59         return false;
60     }
61
62     laddrs->ea_s = xasprintf(ETH_ADDR_FMT, ETH_ADDR_ARGS(laddrs->ea));
63
64     ovs_be32 ip4;
65     struct in6_addr ip6;
66     unsigned int plen;
67     char *error;
68
69     /* Loop through the buffer and extract the IPv4/IPv6 addresses
70      * and store in the 'laddrs'. Break the loop if invalid data is found.
71      */
72     buf += buf_index;
73     while (buf < buf_end) {
74         buf_index = 0;
75         error = ip_parse_cidr_len(buf, &buf_index, &ip4, &plen);
76         if (!error) {
77             laddrs->n_ipv4_addrs++;
78             laddrs->ipv4_addrs = xrealloc(laddrs->ipv4_addrs,
79                 sizeof (struct ipv4_netaddr) * laddrs->n_ipv4_addrs);
80
81             struct ipv4_netaddr *na
82                 = &laddrs->ipv4_addrs[laddrs->n_ipv4_addrs - 1];
83
84             na->addr = ip4;
85             na->mask = be32_prefix_mask(plen);
86             na->network = ip4 & na->mask;
87             na->plen = plen;
88
89             na->addr_s = xasprintf(IP_FMT, IP_ARGS(ip4));
90             na->network_s = xasprintf(IP_FMT, IP_ARGS(na->network));
91             na->bcast_s = xasprintf(IP_FMT, IP_ARGS(ip4 | ~na->mask));
92
93             buf += buf_index;
94             continue;
95         }
96         free(error);
97         error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen);
98         if (!error && store_ipv6) {
99             laddrs->n_ipv6_addrs++;
100             laddrs->ipv6_addrs = xrealloc(
101                 laddrs->ipv6_addrs,
102                 sizeof(struct ipv6_netaddr) * laddrs->n_ipv6_addrs);
103
104             struct ipv6_netaddr *na
105                 = &laddrs->ipv6_addrs[laddrs->n_ipv6_addrs - 1];
106
107             memcpy(&na->addr, &ip6, sizeof(struct in6_addr));
108             na->mask = ipv6_create_mask(plen);
109             na->network = ipv6_addr_bitand(&ip6, &na->mask);
110             na->plen = plen;
111
112             na->addr_s = xmalloc(INET6_ADDRSTRLEN);
113             inet_ntop(AF_INET6, &ip6, na->addr_s, INET6_ADDRSTRLEN);
114             na->network_s = xmalloc(INET6_ADDRSTRLEN);
115             inet_ntop(AF_INET6, &na->network, na->network_s, INET6_ADDRSTRLEN);
116         }
117
118         if (error) {
119             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
120             VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", address);
121             free(error);
122             break;
123         }
124         buf += buf_index;
125     }
126
127     return true;
128 }
129
130 void
131 destroy_lport_addresses(struct lport_addresses *laddrs)
132 {
133     free(laddrs->ea_s);
134
135     for (int i = 0; i < laddrs->n_ipv4_addrs; i++) {
136         free(laddrs->ipv4_addrs[i].addr_s);
137         free(laddrs->ipv4_addrs[i].network_s);
138         free(laddrs->ipv4_addrs[i].bcast_s);
139     }
140     free(laddrs->ipv4_addrs);
141
142     for (int i = 0; i < laddrs->n_ipv6_addrs; i++) {
143         free(laddrs->ipv6_addrs[i].addr_s);
144         free(laddrs->ipv6_addrs[i].network_s);
145     }
146     free(laddrs->ipv6_addrs);
147 }
148
149 /* Allocates a key for NAT conntrack zone allocation for a provided
150  * 'key' record and a 'type'.
151  *
152  * It is the caller's responsibility to free the allocated memory. */
153 char *
154 alloc_nat_zone_key(const char *key, const char *type)
155 {
156     return xasprintf("%s_%s", key, type);
157 }