]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ovs-router.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / ovs-router.c
CommitLineData
d9b4ebc5 1/*
fd13c6b5 2 * Copyright (c) 2014, 2015, 2016, 2017 Nicira, Inc.
d9b4ebc5
PS
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>
1f9575ca
TLSC
18
19#include "ovs-router.h"
20
b2befd5b
BP
21#include <sys/types.h>
22#include <netinet/in.h>
d9b4ebc5
PS
23#include <arpa/inet.h>
24#include <errno.h>
25#include <inttypes.h>
26#include <sys/socket.h>
27#include <net/if.h>
d9b4ebc5
PS
28#include <stdarg.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "classifier.h"
34#include "command-line.h"
35#include "compiler.h"
36#include "dpif.h"
74fd3cdb 37#include "fatal-signal.h"
3e8a2ad1 38#include "openvswitch/dynamic-string.h"
d9b4ebc5
PS
39#include "netdev.h"
40#include "packets.h"
a36de779 41#include "seq.h"
fccd7c09 42#include "ovs-thread.h"
88ffdc93 43#include "route-table.h"
7f9b8504 44#include "tnl-ports.h"
d9b4ebc5
PS
45#include "unixctl.h"
46#include "util.h"
a8704b50 47#include "unaligned.h"
ed52ca57
PS
48#include "openvswitch/vlog.h"
49
50VLOG_DEFINE_THIS_MODULE(ovs_router);
51
52static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
d9b4ebc5 53
fccd7c09 54static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
d9b4ebc5
PS
55static struct classifier cls;
56
898d7b05
BP
57/* By default, use the system routing table. For system-independent testing,
58 * the unit tests disable using the system routing table. */
59static bool use_system_routing_table = true;
60
d9b4ebc5
PS
61struct ovs_router_entry {
62 struct cls_rule cr;
63 char output_bridge[IFNAMSIZ];
0b8da9ae
TLSC
64 struct in6_addr gw;
65 struct in6_addr nw_addr;
a8704b50 66 struct in6_addr src_addr;
d9b4ebc5
PS
67 uint8_t plen;
68 uint8_t priority;
8e4e4588 69 bool local;
ed52ca57 70 uint32_t mark;
d9b4ebc5
PS
71};
72
73static struct ovs_router_entry *
74ovs_router_entry_cast(const struct cls_rule *cr)
75{
53d416af 76 return cr ? CONTAINER_OF(cr, struct ovs_router_entry, cr) : NULL;
d9b4ebc5
PS
77}
78
898d7b05
BP
79/* Disables obtaining routes from the system routing table, for testing
80 * purposes. */
81void
82ovs_router_disable_system_routing_table(void)
83{
84 use_system_routing_table = false;
85}
86
ec6c5379
PS
87static bool
88ovs_router_lookup_fallback(const struct in6_addr *ip6_dst, char output_bridge[],
89 struct in6_addr *src6, struct in6_addr *gw6)
90{
91 ovs_be32 src;
92
898d7b05
BP
93 if (!use_system_routing_table
94 || !route_table_fallback_lookup(ip6_dst, output_bridge, gw6)) {
ec6c5379
PS
95 return false;
96 }
97 if (netdev_get_in4_by_name(output_bridge, (struct in_addr *)&src)) {
98 return false;
99 }
100 if (src6) {
101 in6_addr_set_mapped_ipv4(src6, src);
102 }
103 return true;
104}
105
d9b4ebc5 106bool
ed52ca57
PS
107ovs_router_lookup(uint32_t mark, const struct in6_addr *ip6_dst,
108 char output_bridge[],
a8704b50 109 struct in6_addr *src, struct in6_addr *gw)
d9b4ebc5
PS
110{
111 const struct cls_rule *cr;
ed52ca57 112 struct flow flow = {.ipv6_dst = *ip6_dst, .pkt_mark = mark};
d9b4ebc5 113
8e4e4588 114 if (src && ipv6_addr_is_set(src)) {
115 const struct cls_rule *cr_src;
116 struct flow flow_src = {.ipv6_dst = *src, .pkt_mark = mark};
117
118 cr_src = classifier_lookup(&cls, OVS_VERSION_MAX, &flow_src, NULL);
119 if (cr_src) {
120 struct ovs_router_entry *p_src = ovs_router_entry_cast(cr_src);
121 if (!p_src->local) {
122 return false;
123 }
124 } else {
125 return false;
126 }
127 }
128
44e0c35d 129 cr = classifier_lookup(&cls, OVS_VERSION_MAX, &flow, NULL);
d9b4ebc5
PS
130 if (cr) {
131 struct ovs_router_entry *p = ovs_router_entry_cast(cr);
132
8742957c 133 ovs_strlcpy(output_bridge, p->output_bridge, IFNAMSIZ);
d9b4ebc5 134 *gw = p->gw;
8e4e4588 135 if (src && !ipv6_addr_is_set(src)) {
a8704b50
PS
136 *src = p->src_addr;
137 }
d9b4ebc5
PS
138 return true;
139 }
ec6c5379 140 return ovs_router_lookup_fallback(ip6_dst, output_bridge, src, gw);
d9b4ebc5
PS
141}
142
143static void
144rt_entry_free(struct ovs_router_entry *p)
145{
146 cls_rule_destroy(&p->cr);
147 free(p);
148}
149
ed52ca57
PS
150static void rt_init_match(struct match *match, uint32_t mark,
151 const struct in6_addr *ip6_dst,
0b8da9ae 152 uint8_t plen)
d9b4ebc5 153{
0b8da9ae
TLSC
154 struct in6_addr dst;
155 struct in6_addr mask;
d9b4ebc5 156
0b8da9ae 157 mask = ipv6_create_mask(plen);
d9b4ebc5 158
0b8da9ae 159 dst = ipv6_addr_bitand(ip6_dst, &mask);
d9b4ebc5 160 memset(match, 0, sizeof *match);
0b8da9ae
TLSC
161 match->flow.ipv6_dst = dst;
162 match->wc.masks.ipv6_dst = mask;
ed52ca57
PS
163 match->wc.masks.pkt_mark = UINT32_MAX;
164 match->flow.pkt_mark = mark;
d9b4ebc5
PS
165}
166
a8704b50
PS
167static int
168get_src_addr(const struct in6_addr *ip6_dst,
169 const char output_bridge[], struct in6_addr *psrc)
170{
171 struct in6_addr *mask, *addr6;
172 int err, n_in6, i, max_plen = -1;
173 struct netdev *dev;
20dcdc7f 174 bool is_ipv4;
a8704b50
PS
175
176 err = netdev_open(output_bridge, NULL, &dev);
177 if (err) {
178 return err;
179 }
180
181 err = netdev_get_addr_list(dev, &addr6, &mask, &n_in6);
182 if (err) {
183 goto out;
184 }
185
20dcdc7f
TLSC
186 is_ipv4 = IN6_IS_ADDR_V4MAPPED(ip6_dst);
187
a8704b50
PS
188 for (i = 0; i < n_in6; i++) {
189 struct in6_addr a1, a2;
190 int mask_bits;
191
20dcdc7f
TLSC
192 if (is_ipv4 && !IN6_IS_ADDR_V4MAPPED(&addr6[i])) {
193 continue;
194 }
195
a8704b50
PS
196 a1 = ipv6_addr_bitand(ip6_dst, &mask[i]);
197 a2 = ipv6_addr_bitand(&addr6[i], &mask[i]);
198 mask_bits = bitmap_count1(ALIGNED_CAST(const unsigned long *, &mask[i]), 128);
199
200 if (!memcmp(&a1, &a2, sizeof (a1)) && mask_bits > max_plen) {
201 *psrc = addr6[i];
202 max_plen = mask_bits;
203 }
204 }
205 if (max_plen == -1) {
206 err = ENOENT;
207 }
208out:
209 free(addr6);
210 free(mask);
211 netdev_close(dev);
212 return err;
213}
214
215static int
8e4e4588 216ovs_router_insert__(uint32_t mark, uint8_t priority, bool local,
ed52ca57 217 const struct in6_addr *ip6_dst,
0b8da9ae
TLSC
218 uint8_t plen, const char output_bridge[],
219 const struct in6_addr *gw)
d9b4ebc5
PS
220{
221 const struct cls_rule *cr;
222 struct ovs_router_entry *p;
223 struct match match;
a8704b50 224 int err;
d9b4ebc5 225
ed52ca57 226 rt_init_match(&match, mark, ip6_dst, plen);
d9b4ebc5
PS
227
228 p = xzalloc(sizeof *p);
8742957c 229 ovs_strlcpy(p->output_bridge, output_bridge, sizeof p->output_bridge);
0b8da9ae
TLSC
230 if (ipv6_addr_is_set(gw)) {
231 p->gw = *gw;
232 }
ed52ca57 233 p->mark = mark;
0b8da9ae 234 p->nw_addr = match.flow.ipv6_dst;
d9b4ebc5 235 p->plen = plen;
8e4e4588 236 p->local = local;
d9b4ebc5 237 p->priority = priority;
a8704b50 238 err = get_src_addr(ip6_dst, output_bridge, &p->src_addr);
4e08f54b
AW
239 if (err && ipv6_addr_is_set(gw)) {
240 err = get_src_addr(gw, output_bridge, &p->src_addr);
241 }
a8704b50 242 if (err) {
ed52ca57
PS
243 struct ds ds = DS_EMPTY_INITIALIZER;
244
245 ipv6_format_mapped(ip6_dst, &ds);
246 VLOG_DBG_RL(&rl, "src addr not available for route %s", ds_cstr(&ds));
7209202e 247 free(p);
ed52ca57 248 ds_destroy(&ds);
a8704b50
PS
249 return err;
250 }
2b7b1427 251 /* Longest prefix matches first. */
bd53aa17 252 cls_rule_init(&p->cr, &match, priority);
d9b4ebc5 253
fccd7c09 254 ovs_mutex_lock(&mutex);
44e0c35d 255 cr = classifier_replace(&cls, &p->cr, OVS_VERSION_MIN, NULL, 0);
fccd7c09
JR
256 ovs_mutex_unlock(&mutex);
257
d9b4ebc5
PS
258 if (cr) {
259 /* An old rule with the same match was displaced. */
260 ovsrcu_postpone(rt_entry_free, ovs_router_entry_cast(cr));
261 }
7f9b8504 262 tnl_port_map_insert_ipdev(output_bridge);
a36de779 263 seq_change(tnl_conf_seq);
a8704b50 264 return 0;
d9b4ebc5
PS
265}
266
267void
ed52ca57 268ovs_router_insert(uint32_t mark, const struct in6_addr *ip_dst, uint8_t plen,
8e4e4588 269 bool local, const char output_bridge[],
270 const struct in6_addr *gw)
d9b4ebc5 271{
898d7b05 272 if (use_system_routing_table) {
8e4e4588 273 uint8_t priority = local ? plen + 64 : plen;
274 ovs_router_insert__(mark, priority, local, ip_dst, plen, output_bridge, gw);
898d7b05 275 }
d9b4ebc5
PS
276}
277
46ab60bf
BP
278static void
279rt_entry_delete__(const struct cls_rule *cr)
7f9b8504
PS
280{
281 struct ovs_router_entry *p = ovs_router_entry_cast(cr);
282
283 tnl_port_map_delete_ipdev(p->output_bridge);
46ab60bf
BP
284 classifier_remove_assert(&cls, cr);
285 ovsrcu_postpone(rt_entry_free, ovs_router_entry_cast(cr));
7f9b8504
PS
286}
287
d9b4ebc5 288static bool
ed52ca57
PS
289rt_entry_delete(uint32_t mark, uint8_t priority,
290 const struct in6_addr *ip6_dst, uint8_t plen)
d9b4ebc5 291{
dfea28b3 292 const struct cls_rule *cr;
d9b4ebc5
PS
293 struct cls_rule rule;
294 struct match match;
7f9b8504 295 bool res = false;
d9b4ebc5 296
ed52ca57 297 rt_init_match(&match, mark, ip6_dst, plen);
d9b4ebc5 298
bd53aa17 299 cls_rule_init(&rule, &match, priority);
d9b4ebc5
PS
300
301 /* Find the exact rule. */
44e0c35d 302 cr = classifier_find_rule_exactly(&cls, &rule, OVS_VERSION_MAX);
d9b4ebc5 303 if (cr) {
fccd7c09 304 ovs_mutex_lock(&mutex);
46ab60bf 305 rt_entry_delete__(cr);
fccd7c09 306 ovs_mutex_unlock(&mutex);
46ab60bf
BP
307
308 res = true;
d9b4ebc5 309 }
d3328b16
WT
310
311 cls_rule_destroy(&rule);
7f9b8504 312 return res;
d9b4ebc5
PS
313}
314
0b8da9ae
TLSC
315static bool
316scan_ipv6_route(const char *s, struct in6_addr *addr, unsigned int *plen)
317{
e7695092 318 char *error = ipv6_parse_cidr(s, addr, plen);
184dfff0
JP
319 if (error) {
320 free(error);
321 return false;
0b8da9ae 322 }
184dfff0 323 return true;
0b8da9ae
TLSC
324}
325
d9b4ebc5
PS
326static bool
327scan_ipv4_route(const char *s, ovs_be32 *addr, unsigned int *plen)
328{
e7695092
BP
329 char *error = ip_parse_cidr(s, addr, plen);
330 if (error) {
331 free(error);
d9b4ebc5
PS
332 return false;
333 }
e7695092 334 return true;
d9b4ebc5
PS
335}
336
337static void
338ovs_router_add(struct unixctl_conn *conn, int argc,
339 const char *argv[], void *aux OVS_UNUSED)
340{
ed52ca57 341 struct in6_addr gw6 = in6addr_any;
0b8da9ae 342 struct in6_addr ip6;
ed52ca57
PS
343 uint32_t mark = 0;
344 unsigned int plen;
345 ovs_be32 ip;
a8704b50 346 int err;
d9b4ebc5
PS
347
348 if (scan_ipv4_route(argv[1], &ip, &plen)) {
e7695092 349 ovs_be32 gw = 0;
ed52ca57
PS
350
351 if (argc > 3) {
352 if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) &&
353 !ip_parse(argv[3], &gw)) {
354 unixctl_command_reply_error(conn, "Invalid pkt_mark or gateway");
355 return;
356 }
d9b4ebc5 357 }
0b8da9ae 358 in6_addr_set_mapped_ipv4(&ip6, ip);
ed52ca57
PS
359 if (gw) {
360 in6_addr_set_mapped_ipv4(&gw6, gw);
361 }
0b8da9ae
TLSC
362 plen += 96;
363 } else if (scan_ipv6_route(argv[1], &ip6, &plen)) {
ed52ca57
PS
364 if (argc > 3) {
365 if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) &&
366 !ipv6_parse(argv[3], &gw6)) {
367 unixctl_command_reply_error(conn, "Invalid pkt_mark or IPv6 gateway");
368 return;
369 }
0b8da9ae 370 }
d9b4ebc5 371 } else {
f2e06274
BP
372 unixctl_command_reply_error(conn, "Invalid parameters");
373 return;
d9b4ebc5 374 }
ed52ca57
PS
375 if (argc > 4) {
376 if (!ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) {
377 unixctl_command_reply_error(conn, "Invalid pkt_mark");
378 return;
379 }
380 }
381
8e4e4588 382 err = ovs_router_insert__(mark, plen + 32, false, &ip6, plen, argv[2], &gw6);
a8704b50 383 if (err) {
9104895e 384 unixctl_command_reply_error(conn, "Error while inserting route.");
a8704b50
PS
385 } else {
386 unixctl_command_reply(conn, "OK");
387 }
d9b4ebc5
PS
388}
389
390static void
391ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED,
392 const char *argv[], void *aux OVS_UNUSED)
393{
0b8da9ae 394 struct in6_addr ip6;
ed52ca57
PS
395 uint32_t mark = 0;
396 unsigned int plen;
397 ovs_be32 ip;
d9b4ebc5
PS
398
399 if (scan_ipv4_route(argv[1], &ip, &plen)) {
0b8da9ae
TLSC
400 in6_addr_set_mapped_ipv4(&ip6, ip);
401 plen += 96;
402 } else if (!scan_ipv6_route(argv[1], &ip6, &plen)) {
f2e06274
BP
403 unixctl_command_reply_error(conn, "Invalid parameters");
404 return;
d9b4ebc5 405 }
ed52ca57
PS
406 if (argc > 2) {
407 if (!ovs_scan(argv[2], "pkt_mark=%"SCNi32, &mark)) {
408 unixctl_command_reply_error(conn, "Invalid pkt_mark");
409 return;
410 }
411 }
412
413 if (rt_entry_delete(mark, plen + 32, &ip6, plen)) {
0b8da9ae
TLSC
414 unixctl_command_reply(conn, "OK");
415 seq_change(tnl_conf_seq);
416 } else {
f2e06274 417 unixctl_command_reply_error(conn, "Not found");
0b8da9ae 418 }
d9b4ebc5
PS
419}
420
421static void
422ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
423 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
424{
425 struct ovs_router_entry *rt;
426 struct ds ds = DS_EMPTY_INITIALIZER;
427
428 ds_put_format(&ds, "Route Table:\n");
429 CLS_FOR_EACH(rt, cr, &cls) {
0b8da9ae 430 uint8_t plen;
8e4e4588 431 if (rt->priority == rt->plen || rt->local) {
d9b4ebc5
PS
432 ds_put_format(&ds, "Cached: ");
433 } else {
434 ds_put_format(&ds, "User: ");
435 }
ac6d120f 436 ipv6_format_mapped(&rt->nw_addr, &ds);
0b8da9ae
TLSC
437 plen = rt->plen;
438 if (IN6_IS_ADDR_V4MAPPED(&rt->nw_addr)) {
439 plen -= 96;
440 }
fd13c6b5 441 ds_put_format(&ds, "/%"PRIu8, plen);
ed52ca57
PS
442 if (rt->mark) {
443 ds_put_format(&ds, " MARK %"PRIu32, rt->mark);
444 }
445
446 ds_put_format(&ds, " dev %s", rt->output_bridge);
0b8da9ae
TLSC
447 if (ipv6_addr_is_set(&rt->gw)) {
448 ds_put_format(&ds, " GW ");
ac6d120f 449 ipv6_format_mapped(&rt->gw, &ds);
d9b4ebc5 450 }
a8704b50
PS
451 ds_put_format(&ds, " SRC ");
452 ipv6_format_mapped(&rt->src_addr, &ds);
8e4e4588 453 if (rt->local) {
454 ds_put_format(&ds, " local");
455 }
d9b4ebc5
PS
456 ds_put_format(&ds, "\n");
457 }
458 unixctl_command_reply(conn, ds_cstr(&ds));
459 ds_destroy(&ds);
460}
461
bc786797 462static void
ed52ca57 463ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc,
bc786797
YT
464 const char *argv[], void *aux OVS_UNUSED)
465{
8e4e4588 466 struct in6_addr gw, src = in6addr_any;
ed52ca57 467 char iface[IFNAMSIZ];
0b8da9ae 468 struct in6_addr ip6;
bc786797 469 unsigned int plen;
ed52ca57
PS
470 uint32_t mark = 0;
471 ovs_be32 ip;
bc786797
YT
472
473 if (scan_ipv4_route(argv[1], &ip, &plen) && plen == 32) {
0b8da9ae
TLSC
474 in6_addr_set_mapped_ipv4(&ip6, ip);
475 } else if (!(scan_ipv6_route(argv[1], &ip6, &plen) && plen == 128)) {
f2e06274
BP
476 unixctl_command_reply_error(conn, "Invalid parameters");
477 return;
0b8da9ae 478 }
ed52ca57
PS
479 if (argc > 2) {
480 if (!ovs_scan(argv[2], "pkt_mark=%"SCNi32, &mark)) {
481 unixctl_command_reply_error(conn, "Invalid pkt_mark");
482 return;
483 }
484 }
485 if (ovs_router_lookup(mark, &ip6, iface, &src, &gw)) {
0b8da9ae 486 struct ds ds = DS_EMPTY_INITIALIZER;
ed52ca57 487
a8704b50
PS
488 ds_put_format(&ds, "src ");
489 ipv6_format_mapped(&src, &ds);
2ddf1bca 490 ds_put_format(&ds, "\ngateway ");
a8704b50 491 ipv6_format_mapped(&gw, &ds);
0b8da9ae
TLSC
492 ds_put_format(&ds, "\ndev %s\n", iface);
493 unixctl_command_reply(conn, ds_cstr(&ds));
494 ds_destroy(&ds);
bc786797 495 } else {
f2e06274 496 unixctl_command_reply_error(conn, "Not found");
bc786797
YT
497 }
498}
499
d9b4ebc5
PS
500void
501ovs_router_flush(void)
502{
503 struct ovs_router_entry *rt;
504
802f84ff
JR
505 ovs_mutex_lock(&mutex);
506 classifier_defer(&cls);
de4ad4a2 507 CLS_FOR_EACH(rt, cr, &cls) {
9e11517e 508 if (rt->priority == rt->plen || rt->local) {
46ab60bf 509 rt_entry_delete__(&rt->cr);
d9b4ebc5
PS
510 }
511 }
802f84ff
JR
512 classifier_publish(&cls);
513 ovs_mutex_unlock(&mutex);
a36de779 514 seq_change(tnl_conf_seq);
d9b4ebc5
PS
515}
516
74fd3cdb
FL
517static void
518ovs_router_flush_handler(void *aux OVS_UNUSED)
519{
520 ovs_router_flush();
521}
522
d9b4ebc5 523void
1bc50ef3 524ovs_router_init(void)
d9b4ebc5 525{
74fd3cdb
FL
526 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
527
528 if (ovsthread_once_start(&once)) {
529 fatal_signal_add_hook(ovs_router_flush_handler, NULL, NULL, true);
530 classifier_init(&cls, NULL);
531 unixctl_command_register("ovs/route/add",
532 "ip_addr/prefix_len out_br_name [gw] "
533 "[pkt_mark=mark]",
534 2, 4, ovs_router_add, NULL);
535 unixctl_command_register("ovs/route/show", "", 0, 0,
536 ovs_router_show, NULL);
537 unixctl_command_register("ovs/route/del", "ip_addr/prefix_len "
538 "[pkt_mark=mark]", 1, 2, ovs_router_del,
539 NULL);
540 unixctl_command_register("ovs/route/lookup", "ip_addr "
541 "[pkt_mark=mark]", 1, 2,
542 ovs_router_lookup_cmd, NULL);
543 ovsthread_once_done(&once);
544 }
d9b4ebc5 545}