dpif-netlink: add GENEVE creation support
[cascardo/ovs.git] / lib / ovs-router.c
1 /*
2  * Copyright (c) 2014, 2015, 2016 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include "ovs-router.h"
20
21 #include <arpa/inet.h>
22 #include <errno.h>
23 #include <inttypes.h>
24 #include <sys/socket.h>
25 #include <net/if.h>
26 #include <netinet/in.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include "classifier.h"
33 #include "command-line.h"
34 #include "compiler.h"
35 #include "dpif.h"
36 #include "openvswitch/dynamic-string.h"
37 #include "netdev.h"
38 #include "packets.h"
39 #include "seq.h"
40 #include "ovs-thread.h"
41 #include "route-table.h"
42 #include "tnl-ports.h"
43 #include "unixctl.h"
44 #include "util.h"
45 #include "unaligned.h"
46 #include "unixctl.h"
47 #include "util.h"
48
49 static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
50 static struct classifier cls;
51
52 struct ovs_router_entry {
53     struct cls_rule cr;
54     char output_bridge[IFNAMSIZ];
55     struct in6_addr gw;
56     struct in6_addr nw_addr;
57     struct in6_addr src_addr;
58     uint8_t plen;
59     uint8_t priority;
60 };
61
62 static struct ovs_router_entry *
63 ovs_router_entry_cast(const struct cls_rule *cr)
64 {
65     if (offsetof(struct ovs_router_entry, cr) == 0) {
66         return CONTAINER_OF(cr, struct ovs_router_entry, cr);
67     } else {
68         return cr ? CONTAINER_OF(cr, struct ovs_router_entry, cr) : NULL;
69     }
70 }
71
72 static bool
73 ovs_router_lookup_fallback(const struct in6_addr *ip6_dst, char output_bridge[],
74                            struct in6_addr *src6, struct in6_addr *gw6)
75 {
76     ovs_be32 src;
77
78     if (!route_table_fallback_lookup(ip6_dst, output_bridge, gw6)) {
79         return false;
80     }
81     if (netdev_get_in4_by_name(output_bridge, (struct in_addr *)&src)) {
82         return false;
83     }
84     if (src6) {
85         in6_addr_set_mapped_ipv4(src6, src);
86     }
87     return true;
88 }
89
90 bool
91 ovs_router_lookup(const struct in6_addr *ip6_dst, char output_bridge[],
92                   struct in6_addr *src, struct in6_addr *gw)
93 {
94     const struct cls_rule *cr;
95     struct flow flow = {.ipv6_dst = *ip6_dst};
96
97     cr = classifier_lookup(&cls, CLS_MAX_VERSION, &flow, NULL);
98     if (cr) {
99         struct ovs_router_entry *p = ovs_router_entry_cast(cr);
100
101         ovs_strlcpy(output_bridge, p->output_bridge, IFNAMSIZ);
102         *gw = p->gw;
103         if (src) {
104             *src = p->src_addr;
105         }
106         return true;
107     }
108     return ovs_router_lookup_fallback(ip6_dst, output_bridge, src, gw);
109 }
110
111 static void
112 rt_entry_free(struct ovs_router_entry *p)
113 {
114     cls_rule_destroy(&p->cr);
115     free(p);
116 }
117
118 static void rt_init_match(struct match *match, const struct in6_addr *ip6_dst,
119                           uint8_t plen)
120 {
121     struct in6_addr dst;
122     struct in6_addr mask;
123
124     mask = ipv6_create_mask(plen);
125
126     dst = ipv6_addr_bitand(ip6_dst, &mask);
127     memset(match, 0, sizeof *match);
128     match->flow.ipv6_dst = dst;
129     match->wc.masks.ipv6_dst = mask;
130 }
131
132 static int
133 get_src_addr(const struct in6_addr *ip6_dst,
134              const char output_bridge[], struct in6_addr *psrc)
135 {
136     struct in6_addr *mask, *addr6;
137     int err, n_in6, i, max_plen = -1;
138     struct netdev *dev;
139
140     err = netdev_open(output_bridge, NULL, &dev);
141     if (err) {
142         return err;
143     }
144
145     err = netdev_get_addr_list(dev, &addr6, &mask, &n_in6);
146     if (err) {
147         goto out;
148     }
149
150     for (i = 0; i < n_in6; i++) {
151         struct in6_addr a1, a2;
152         int mask_bits;
153
154         a1 = ipv6_addr_bitand(ip6_dst, &mask[i]);
155         a2 = ipv6_addr_bitand(&addr6[i], &mask[i]);
156         mask_bits = bitmap_count1(ALIGNED_CAST(const unsigned long *, &mask[i]), 128);
157
158         if (!memcmp(&a1, &a2, sizeof (a1)) && mask_bits > max_plen) {
159             *psrc = addr6[i];
160             max_plen = mask_bits;
161         }
162     }
163     if (max_plen == -1) {
164         err = ENOENT;
165     }
166 out:
167     free(addr6);
168     free(mask);
169     netdev_close(dev);
170     return err;
171 }
172
173 static int
174 ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
175                     uint8_t plen, const char output_bridge[],
176                     const struct in6_addr *gw)
177 {
178     const struct cls_rule *cr;
179     struct ovs_router_entry *p;
180     struct match match;
181     int err;
182
183     rt_init_match(&match, ip6_dst, plen);
184
185     p = xzalloc(sizeof *p);
186     ovs_strlcpy(p->output_bridge, output_bridge, sizeof p->output_bridge);
187     if (ipv6_addr_is_set(gw)) {
188         p->gw = *gw;
189     }
190     p->nw_addr = match.flow.ipv6_dst;
191     p->plen = plen;
192     p->priority = priority;
193     err = get_src_addr(ip6_dst, output_bridge, &p->src_addr);
194     if (err) {
195         free(p);
196         return err;
197     }
198     /* Longest prefix matches first. */
199     cls_rule_init(&p->cr, &match, priority);
200
201     ovs_mutex_lock(&mutex);
202     cr = classifier_replace(&cls, &p->cr, CLS_MIN_VERSION, NULL, 0);
203     ovs_mutex_unlock(&mutex);
204
205     if (cr) {
206         /* An old rule with the same match was displaced. */
207         ovsrcu_postpone(rt_entry_free, ovs_router_entry_cast(cr));
208     }
209     tnl_port_map_insert_ipdev(output_bridge);
210     seq_change(tnl_conf_seq);
211     return 0;
212 }
213
214 void
215 ovs_router_insert(const struct in6_addr *ip_dst, uint8_t plen,
216                   const char output_bridge[], const struct in6_addr *gw)
217 {
218     ovs_router_insert__(plen, ip_dst, plen, output_bridge, gw);
219 }
220
221
222 static bool
223 __rt_entry_delete(const struct cls_rule *cr)
224 {
225     struct ovs_router_entry *p = ovs_router_entry_cast(cr);
226
227     tnl_port_map_delete_ipdev(p->output_bridge);
228     /* Remove it. */
229     cr = classifier_remove(&cls, cr);
230     if (cr) {
231         ovsrcu_postpone(rt_entry_free, ovs_router_entry_cast(cr));
232         return true;
233     }
234     return false;
235 }
236
237 static bool
238 rt_entry_delete(uint8_t priority, const struct in6_addr *ip6_dst, uint8_t plen)
239 {
240     const struct cls_rule *cr;
241     struct cls_rule rule;
242     struct match match;
243     bool res = false;
244
245     rt_init_match(&match, ip6_dst, plen);
246
247     cls_rule_init(&rule, &match, priority);
248
249     /* Find the exact rule. */
250     cr = classifier_find_rule_exactly(&cls, &rule, CLS_MAX_VERSION);
251     if (cr) {
252         ovs_mutex_lock(&mutex);
253         res = __rt_entry_delete(cr);
254         ovs_mutex_unlock(&mutex);
255     }
256     return res;
257 }
258
259 static bool
260 scan_ipv6_route(const char *s, struct in6_addr *addr, unsigned int *plen)
261 {
262     char *error = ipv6_parse_cidr(s, addr, plen);
263     if (error) {
264         free(error);
265         return false;
266     }
267     return true;
268 }
269
270 static bool
271 scan_ipv4_route(const char *s, ovs_be32 *addr, unsigned int *plen)
272 {
273     char *error = ip_parse_cidr(s, addr, plen);
274     if (error) {
275         free(error);
276         return false;
277     }
278     return true;
279 }
280
281 static void
282 ovs_router_add(struct unixctl_conn *conn, int argc,
283               const char *argv[], void *aux OVS_UNUSED)
284 {
285     ovs_be32 ip;
286     unsigned int plen;
287     struct in6_addr ip6;
288     struct in6_addr gw6;
289     int err;
290
291     if (scan_ipv4_route(argv[1], &ip, &plen)) {
292         ovs_be32 gw = 0;
293         if (argc > 3 && !ip_parse(argv[3], &gw)) {
294             unixctl_command_reply_error(conn, "Invalid gateway");
295             return;
296         }
297         in6_addr_set_mapped_ipv4(&ip6, ip);
298         in6_addr_set_mapped_ipv4(&gw6, gw);
299         plen += 96;
300     } else if (scan_ipv6_route(argv[1], &ip6, &plen)) {
301         gw6 = in6addr_any;
302         if (argc > 3 && !ipv6_parse(argv[3], &gw6)) {
303             unixctl_command_reply_error(conn, "Invalid IPv6 gateway");
304             return;
305         }
306     } else {
307         unixctl_command_reply_error(conn, "Invalid parameters");
308         return;
309     }
310     err = ovs_router_insert__(plen + 32, &ip6, plen, argv[2], &gw6);
311     if (err) {
312         unixctl_command_reply(conn, "Error while inserting route.");
313     } else {
314         unixctl_command_reply(conn, "OK");
315     }
316 }
317
318 static void
319 ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED,
320               const char *argv[], void *aux OVS_UNUSED)
321 {
322     ovs_be32 ip;
323     unsigned int plen;
324     struct in6_addr ip6;
325
326     if (scan_ipv4_route(argv[1], &ip, &plen)) {
327         in6_addr_set_mapped_ipv4(&ip6, ip);
328         plen += 96;
329     } else if (!scan_ipv6_route(argv[1], &ip6, &plen)) {
330         unixctl_command_reply_error(conn, "Invalid parameters");
331         return;
332     }
333     if (rt_entry_delete(plen + 32, &ip6, plen)) {
334         unixctl_command_reply(conn, "OK");
335         seq_change(tnl_conf_seq);
336     } else {
337         unixctl_command_reply_error(conn, "Not found");
338     }
339 }
340
341 static void
342 ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
343                const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
344 {
345     struct ovs_router_entry *rt;
346     struct ds ds = DS_EMPTY_INITIALIZER;
347
348     ds_put_format(&ds, "Route Table:\n");
349     CLS_FOR_EACH(rt, cr, &cls) {
350         uint8_t plen;
351         if (rt->priority == rt->plen) {
352             ds_put_format(&ds, "Cached: ");
353         } else {
354             ds_put_format(&ds, "User: ");
355         }
356         ipv6_format_mapped(&rt->nw_addr, &ds);
357         plen = rt->plen;
358         if (IN6_IS_ADDR_V4MAPPED(&rt->nw_addr)) {
359             plen -= 96;
360         }
361         ds_put_format(&ds, "/%"PRIu16" dev %s", plen, rt->output_bridge);
362         if (ipv6_addr_is_set(&rt->gw)) {
363             ds_put_format(&ds, " GW ");
364             ipv6_format_mapped(&rt->gw, &ds);
365         }
366         ds_put_format(&ds, " SRC ");
367         ipv6_format_mapped(&rt->src_addr, &ds);
368         ds_put_format(&ds, "\n");
369     }
370     unixctl_command_reply(conn, ds_cstr(&ds));
371     ds_destroy(&ds);
372 }
373
374 static void
375 ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED,
376                       const char *argv[], void *aux OVS_UNUSED)
377 {
378     ovs_be32 ip;
379     struct in6_addr ip6;
380     unsigned int plen;
381     char iface[IFNAMSIZ];
382     struct in6_addr gw, src;
383
384     if (scan_ipv4_route(argv[1], &ip, &plen) && plen == 32) {
385         in6_addr_set_mapped_ipv4(&ip6, ip);
386     } else if (!(scan_ipv6_route(argv[1], &ip6, &plen) && plen == 128)) {
387         unixctl_command_reply_error(conn, "Invalid parameters");
388         return;
389     }
390
391     if (ovs_router_lookup(&ip6, iface, &src, &gw)) {
392         struct ds ds = DS_EMPTY_INITIALIZER;
393         ds_put_format(&ds, "src ");
394         ipv6_format_mapped(&src, &ds);
395         ds_put_format(&ds, "gateway ");
396         ipv6_format_mapped(&gw, &ds);
397         ds_put_format(&ds, "\ndev %s\n", iface);
398         unixctl_command_reply(conn, ds_cstr(&ds));
399         ds_destroy(&ds);
400     } else {
401         unixctl_command_reply_error(conn, "Not found");
402     }
403 }
404
405 void
406 ovs_router_flush(void)
407 {
408     struct ovs_router_entry *rt;
409
410     ovs_mutex_lock(&mutex);
411     classifier_defer(&cls);
412     CLS_FOR_EACH(rt, cr, &cls) {
413         if (rt->priority == rt->plen) {
414             __rt_entry_delete(&rt->cr);
415         }
416     }
417     classifier_publish(&cls);
418     ovs_mutex_unlock(&mutex);
419     seq_change(tnl_conf_seq);
420 }
421
422 /* May not be called more than once. */
423 void
424 ovs_router_init(void)
425 {
426     classifier_init(&cls, NULL);
427     unixctl_command_register("ovs/route/add", "ip_addr/prefix_len out_br_name gw", 2, 3,
428                              ovs_router_add, NULL);
429     unixctl_command_register("ovs/route/show", "", 0, 0, ovs_router_show, NULL);
430     unixctl_command_register("ovs/route/del", "ip_addr/prefix_len", 1, 1, ovs_router_del,
431                              NULL);
432     unixctl_command_register("ovs/route/lookup", "ip_addr", 1, 1,
433                              ovs_router_lookup_cmd, NULL);
434 }