ip6_fib.c 61.2 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
L
Linus Torvalds 已提交
2
/*
3
 *	Linux INET6 implementation
L
Linus Torvalds 已提交
4 5 6
 *	Forwarding Information Database
 *
 *	Authors:
7
 *	Pedro Roque		<roque@di.fc.ul.pt>
L
Linus Torvalds 已提交
8
 *
9 10 11 12 13
 *	Changes:
 *	Yuji SEKIYA @USAGI:	Support default route on router node;
 *				remove ip6_null_entry from the top of
 *				routing table.
 *	Ville Nuorvala:		Fixed routing subtrees.
L
Linus Torvalds 已提交
14
 */
15 16 17

#define pr_fmt(fmt) "IPv6: " fmt

L
Linus Torvalds 已提交
18 19 20 21 22 23 24
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/net.h>
#include <linux/route.h>
#include <linux/netdevice.h>
#include <linux/in6.h>
#include <linux/init.h>
T
Thomas Graf 已提交
25
#include <linux/list.h>
26
#include <linux/slab.h>
L
Linus Torvalds 已提交
27

28
#include <net/ip.h>
L
Linus Torvalds 已提交
29 30 31
#include <net/ipv6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
32
#include <net/lwtunnel.h>
33
#include <net/fib_notifier.h>
L
Linus Torvalds 已提交
34 35 36 37

#include <net/ip6_fib.h>
#include <net/ip6_route.h>

38
static struct kmem_cache *fib6_node_kmem __read_mostly;
L
Linus Torvalds 已提交
39

40 41
struct fib6_cleaner {
	struct fib6_walker w;
42
	struct net *net;
43
	int (*func)(struct fib6_info *, void *arg);
44
	int sernum;
L
Linus Torvalds 已提交
45
	void *arg;
46
	bool skip_notify;
L
Linus Torvalds 已提交
47 48 49 50 51 52 53 54
};

#ifdef CONFIG_IPV6_SUBTREES
#define FWS_INIT FWS_S
#else
#define FWS_INIT FWS_L
#endif

55
static struct fib6_info *fib6_find_prefix(struct net *net,
56 57 58 59 60
					 struct fib6_table *table,
					 struct fib6_node *fn);
static struct fib6_node *fib6_repair_tree(struct net *net,
					  struct fib6_table *table,
					  struct fib6_node *fn);
M
Michal Kubeček 已提交
61
static int fib6_walk(struct net *net, struct fib6_walker *w);
62
static int fib6_walk_continue(struct fib6_walker *w);
L
Linus Torvalds 已提交
63 64 65 66 67 68 69 70

/*
 *	A routing update causes an increase of the serial number on the
 *	affected subtree. This allows for cached routes to be asynchronously
 *	tested when modifications are made to the destination cache as a
 *	result of redirects, path MTU changes, etc.
 */

71
static void fib6_gc_timer_cb(struct timer_list *t);
72

M
Michal Kubeček 已提交
73 74
#define FOR_WALKERS(net, w) \
	list_for_each_entry(w, &(net)->ipv6.fib6_walkers, lh)
L
Linus Torvalds 已提交
75

M
Michal Kubeček 已提交
76
static void fib6_walker_link(struct net *net, struct fib6_walker *w)
A
Adrian Bunk 已提交
77
{
M
Michal Kubeček 已提交
78 79 80
	write_lock_bh(&net->ipv6.fib6_walker_lock);
	list_add(&w->lh, &net->ipv6.fib6_walkers);
	write_unlock_bh(&net->ipv6.fib6_walker_lock);
A
Adrian Bunk 已提交
81 82
}

M
Michal Kubeček 已提交
83
static void fib6_walker_unlink(struct net *net, struct fib6_walker *w)
A
Adrian Bunk 已提交
84
{
M
Michal Kubeček 已提交
85
	write_lock_bh(&net->ipv6.fib6_walker_lock);
86
	list_del(&w->lh);
M
Michal Kubeček 已提交
87
	write_unlock_bh(&net->ipv6.fib6_walker_lock);
A
Adrian Bunk 已提交
88
}
89

90
static int fib6_new_sernum(struct net *net)
L
Linus Torvalds 已提交
91
{
92 93 94
	int new, old;

	do {
95
		old = atomic_read(&net->ipv6.fib6_sernum);
96
		new = old < INT_MAX ? old + 1 : 1;
97 98
	} while (atomic_cmpxchg(&net->ipv6.fib6_sernum,
				old, new) != old);
99
	return new;
L
Linus Torvalds 已提交
100 101
}

102 103 104 105
enum {
	FIB6_NO_SERNUM_CHANGE = 0,
};

106
void fib6_update_sernum(struct net *net, struct fib6_info *f6i)
107 108 109
{
	struct fib6_node *fn;

110 111
	fn = rcu_dereference_protected(f6i->fib6_node,
			lockdep_is_held(&f6i->fib6_table->tb6_lock));
112 113 114 115
	if (fn)
		fn->fn_sernum = fib6_new_sernum(net);
}

L
Linus Torvalds 已提交
116 117 118
/*
 *	Auxiliary address test functions for the radix tree.
 *
119
 *	These assume a 32bit processor (although it will work on
L
Linus Torvalds 已提交
120 121 122 123 124 125
 *	64bit processors)
 */

/*
 *	test bit
 */
126 127 128 129 130
#if defined(__LITTLE_ENDIAN)
# define BITOP_BE32_SWIZZLE	(0x1F & ~7)
#else
# define BITOP_BE32_SWIZZLE	0
#endif
L
Linus Torvalds 已提交
131

132
static __be32 addr_bit_set(const void *token, int fn_bit)
L
Linus Torvalds 已提交
133
{
134
	const __be32 *addr = token;
135 136
	/*
	 * Here,
137
	 *	1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)
138 139 140 141
	 * is optimized version of
	 *	htonl(1 << ((~fn_bit)&0x1F))
	 * See include/asm-generic/bitops/le.h.
	 */
142 143
	return (__force __be32)(1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)) &
	       addr[fn_bit >> 5];
L
Linus Torvalds 已提交
144 145
}

146
struct fib6_info *fib6_info_alloc(gfp_t gfp_flags, bool with_fib6_nh)
147
{
148
	struct fib6_info *f6i;
149
	size_t sz = sizeof(*f6i);
150

151 152 153 154
	if (with_fib6_nh)
		sz += sizeof(struct fib6_nh);

	f6i = kzalloc(sz, gfp_flags);
155 156 157
	if (!f6i)
		return NULL;

158
	/* fib6_siblings is a union with nh_list, so this initializes both */
159
	INIT_LIST_HEAD(&f6i->fib6_siblings);
160
	refcount_set(&f6i->fib6_ref, 1);
161 162 163 164

	return f6i;
}

165
void fib6_info_destroy_rcu(struct rcu_head *head)
166
{
167
	struct fib6_info *f6i = container_of(head, struct fib6_info, rcu);
168

169
	WARN_ON(f6i->fib6_node);
170

171 172 173 174 175
	if (f6i->nh)
		nexthop_put(f6i->nh);
	else
		fib6_nh_release(f6i->fib6_nh);

176
	ip_fib_metrics_put(f6i->fib6_metrics);
177 178
	kfree(f6i);
}
179
EXPORT_SYMBOL_GPL(fib6_info_destroy_rcu);
180

W
Wei Wang 已提交
181
static struct fib6_node *node_alloc(struct net *net)
L
Linus Torvalds 已提交
182 183 184
{
	struct fib6_node *fn;

185
	fn = kmem_cache_zalloc(fib6_node_kmem, GFP_ATOMIC);
W
Wei Wang 已提交
186 187
	if (fn)
		net->ipv6.rt6_stats->fib_nodes++;
L
Linus Torvalds 已提交
188 189 190 191

	return fn;
}

W
Wei Wang 已提交
192
static void node_free_immediate(struct net *net, struct fib6_node *fn)
193 194
{
	kmem_cache_free(fib6_node_kmem, fn);
W
Wei Wang 已提交
195
	net->ipv6.rt6_stats->fib_nodes--;
196 197 198
}

static void node_free_rcu(struct rcu_head *head)
L
Linus Torvalds 已提交
199
{
200 201
	struct fib6_node *fn = container_of(head, struct fib6_node, rcu);

L
Linus Torvalds 已提交
202 203 204
	kmem_cache_free(fib6_node_kmem, fn);
}

W
Wei Wang 已提交
205
static void node_free(struct net *net, struct fib6_node *fn)
206 207
{
	call_rcu(&fn->rcu, node_free_rcu);
W
Wei Wang 已提交
208
	net->ipv6.rt6_stats->fib_nodes--;
209 210
}

211 212 213 214 215 216
static void fib6_free_table(struct fib6_table *table)
{
	inetpeer_invalidate_tree(&table->tb6_peers);
	kfree(table);
}

217
static void fib6_link_table(struct net *net, struct fib6_table *tb)
218 219 220
{
	unsigned int h;

221 222 223 224
	/*
	 * Initialize table lock at a single place to give lockdep a key,
	 * tables aren't visible prior to being linked to the list.
	 */
225
	spin_lock_init(&tb->tb6_lock);
226
	h = tb->tb6_id & (FIB6_TABLE_HASHSZ - 1);
227 228 229 230 231

	/*
	 * No protection necessary, this is the only list mutatation
	 * operation, tables never disappear once they exist.
	 */
232
	hlist_add_head_rcu(&tb->tb6_hlist, &net->ipv6.fib_table_hash[h]);
233
}
T
Thomas Graf 已提交
234

235
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
236

237
static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
T
Thomas Graf 已提交
238 239 240 241
{
	struct fib6_table *table;

	table = kzalloc(sizeof(*table), GFP_ATOMIC);
242
	if (table) {
T
Thomas Graf 已提交
243
		table->tb6_id = id;
244
		rcu_assign_pointer(table->tb6_root.leaf,
D
David Ahern 已提交
245
				   net->ipv6.fib6_null_entry);
T
Thomas Graf 已提交
246
		table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
247
		inet_peer_base_init(&table->tb6_peers);
T
Thomas Graf 已提交
248 249 250 251 252
	}

	return table;
}

253
struct fib6_table *fib6_new_table(struct net *net, u32 id)
T
Thomas Graf 已提交
254 255 256 257 258
{
	struct fib6_table *tb;

	if (id == 0)
		id = RT6_TABLE_MAIN;
259
	tb = fib6_get_table(net, id);
T
Thomas Graf 已提交
260 261 262
	if (tb)
		return tb;

263
	tb = fib6_alloc_table(net, id);
264
	if (tb)
265
		fib6_link_table(net, tb);
T
Thomas Graf 已提交
266 267 268

	return tb;
}
269
EXPORT_SYMBOL_GPL(fib6_new_table);
T
Thomas Graf 已提交
270

271
struct fib6_table *fib6_get_table(struct net *net, u32 id)
T
Thomas Graf 已提交
272 273
{
	struct fib6_table *tb;
274
	struct hlist_head *head;
T
Thomas Graf 已提交
275 276 277 278
	unsigned int h;

	if (id == 0)
		id = RT6_TABLE_MAIN;
279
	h = id & (FIB6_TABLE_HASHSZ - 1);
T
Thomas Graf 已提交
280
	rcu_read_lock();
281
	head = &net->ipv6.fib_table_hash[h];
282
	hlist_for_each_entry_rcu(tb, head, tb6_hlist) {
T
Thomas Graf 已提交
283 284 285 286 287 288 289 290 291
		if (tb->tb6_id == id) {
			rcu_read_unlock();
			return tb;
		}
	}
	rcu_read_unlock();

	return NULL;
}
292
EXPORT_SYMBOL_GPL(fib6_get_table);
T
Thomas Graf 已提交
293

294
static void __net_init fib6_tables_init(struct net *net)
T
Thomas Graf 已提交
295
{
296 297
	fib6_link_table(net, net->ipv6.fib6_main_tbl);
	fib6_link_table(net, net->ipv6.fib6_local_tbl);
T
Thomas Graf 已提交
298 299 300
}
#else

301
struct fib6_table *fib6_new_table(struct net *net, u32 id)
T
Thomas Graf 已提交
302
{
303
	return fib6_get_table(net, id);
T
Thomas Graf 已提交
304 305
}

306
struct fib6_table *fib6_get_table(struct net *net, u32 id)
T
Thomas Graf 已提交
307
{
308
	  return net->ipv6.fib6_main_tbl;
T
Thomas Graf 已提交
309 310
}

311
struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
D
David Ahern 已提交
312
				   const struct sk_buff *skb,
313
				   int flags, pol_lookup_t lookup)
T
Thomas Graf 已提交
314
{
315 316
	struct rt6_info *rt;

D
David Ahern 已提交
317
	rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, skb, flags);
318
	if (rt->dst.error == -EAGAIN) {
319
		ip6_rt_put_flags(rt, flags);
320
		rt = net->ipv6.ip6_null_entry;
321
		if (!(flags & RT6_LOOKUP_F_DST_NOREF))
322
			dst_hold(&rt->dst);
323 324 325
	}

	return &rt->dst;
T
Thomas Graf 已提交
326 327
}

D
David Ahern 已提交
328
/* called with rcu lock held; no reference taken on fib6_info */
329 330
int fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
		struct fib6_result *res, int flags)
D
David Ahern 已提交
331
{
332 333
	return fib6_table_lookup(net, net->ipv6.fib6_main_tbl, oif, fl6,
				 res, flags);
D
David Ahern 已提交
334 335
}

336
static void __net_init fib6_tables_init(struct net *net)
T
Thomas Graf 已提交
337
{
338
	fib6_link_table(net, net->ipv6.fib6_main_tbl);
T
Thomas Graf 已提交
339 340 341 342
}

#endif

343 344 345 346 347 348 349 350 351
unsigned int fib6_tables_seq_read(struct net *net)
{
	unsigned int h, fib_seq = 0;

	rcu_read_lock();
	for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
		struct hlist_head *head = &net->ipv6.fib_table_hash[h];
		struct fib6_table *tb;

352
		hlist_for_each_entry_rcu(tb, head, tb6_hlist)
353 354 355 356 357 358 359
			fib_seq += tb->fib_seq;
	}
	rcu_read_unlock();

	return fib_seq;
}

360
static int call_fib6_entry_notifier(struct notifier_block *nb,
361
				    enum fib_event_type event_type,
362 363
				    struct fib6_info *rt,
				    struct netlink_ext_ack *extack)
364 365
{
	struct fib6_entry_notifier_info info = {
366
		.info.extack = extack,
367 368 369
		.rt = rt,
	};

370
	return call_fib6_notifier(nb, event_type, &info.info);
371 372
}

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
static int call_fib6_multipath_entry_notifier(struct notifier_block *nb,
					      enum fib_event_type event_type,
					      struct fib6_info *rt,
					      unsigned int nsiblings,
					      struct netlink_ext_ack *extack)
{
	struct fib6_entry_notifier_info info = {
		.info.extack = extack,
		.rt = rt,
		.nsiblings = nsiblings,
	};

	return call_fib6_notifier(nb, event_type, &info.info);
}

388 389 390 391
int call_fib6_entry_notifiers(struct net *net,
			      enum fib_event_type event_type,
			      struct fib6_info *rt,
			      struct netlink_ext_ack *extack)
392 393
{
	struct fib6_entry_notifier_info info = {
D
David Ahern 已提交
394
		.info.extack = extack,
395 396 397
		.rt = rt,
	};

398
	rt->fib6_table->fib_seq++;
399 400 401
	return call_fib6_notifiers(net, event_type, &info.info);
}

402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
int call_fib6_multipath_entry_notifiers(struct net *net,
					enum fib_event_type event_type,
					struct fib6_info *rt,
					unsigned int nsiblings,
					struct netlink_ext_ack *extack)
{
	struct fib6_entry_notifier_info info = {
		.info.extack = extack,
		.rt = rt,
		.nsiblings = nsiblings,
	};

	rt->fib6_table->fib_seq++;
	return call_fib6_notifiers(net, event_type, &info.info);
}

418 419 420 421 422 423 424 425
int call_fib6_entry_notifiers_replace(struct net *net, struct fib6_info *rt)
{
	struct fib6_entry_notifier_info info = {
		.rt = rt,
		.nsiblings = rt->fib6_nsiblings,
	};

	rt->fib6_table->fib_seq++;
426
	return call_fib6_notifiers(net, FIB_EVENT_ENTRY_REPLACE, &info.info);
427 428
}

429 430 431
struct fib6_dump_arg {
	struct net *net;
	struct notifier_block *nb;
432
	struct netlink_ext_ack *extack;
433 434
};

435
static int fib6_rt_dump(struct fib6_info *rt, struct fib6_dump_arg *arg)
436
{
437
	enum fib_event_type fib_event = FIB_EVENT_ENTRY_REPLACE;
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
	int err;

	if (!rt || rt == arg->net->ipv6.fib6_null_entry)
		return 0;

	if (rt->fib6_nsiblings)
		err = call_fib6_multipath_entry_notifier(arg->nb, fib_event,
							 rt,
							 rt->fib6_nsiblings,
							 arg->extack);
	else
		err = call_fib6_entry_notifier(arg->nb, fib_event, rt,
					       arg->extack);

	return err;
}

455 456
static int fib6_node_dump(struct fib6_walker *w)
{
457
	int err;
458

459
	err = fib6_rt_dump(w->leaf, w->args);
460
	w->leaf = NULL;
461
	return err;
462 463
}

464 465
static int fib6_table_dump(struct net *net, struct fib6_table *tb,
			   struct fib6_walker *w)
466
{
467 468
	int err;

469
	w->root = &tb->tb6_root;
470
	spin_lock_bh(&tb->tb6_lock);
471
	err = fib6_walk(net, w);
472
	spin_unlock_bh(&tb->tb6_lock);
473
	return err;
474 475 476
}

/* Called with rcu_read_lock() */
477 478
int fib6_tables_dump(struct net *net, struct notifier_block *nb,
		     struct netlink_ext_ack *extack)
479 480 481 482
{
	struct fib6_dump_arg arg;
	struct fib6_walker *w;
	unsigned int h;
483
	int err = 0;
484 485 486 487 488 489 490 491

	w = kzalloc(sizeof(*w), GFP_ATOMIC);
	if (!w)
		return -ENOMEM;

	w->func = fib6_node_dump;
	arg.net = net;
	arg.nb = nb;
492
	arg.extack = extack;
493 494 495 496 497 498
	w->args = &arg;

	for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
		struct hlist_head *head = &net->ipv6.fib_table_hash[h];
		struct fib6_table *tb;

499 500 501 502 503
		hlist_for_each_entry_rcu(tb, head, tb6_hlist) {
			err = fib6_table_dump(net, tb, w);
			if (err < 0)
				goto out;
		}
504 505
	}

506
out:
507 508
	kfree(w);

509
	return err;
510 511
}

512
static int fib6_dump_node(struct fib6_walker *w)
513 514
{
	int res;
515
	struct fib6_info *rt;
516

517
	for_each_fib6_walker_rt(w) {
518
		res = rt6_dump_route(rt, w->args, w->skip_in_node);
519
		if (res >= 0) {
520 521
			/* Frame is full, suspend walking */
			w->leaf = rt;
522 523 524 525 526 527

			/* We'll restart from this node, so if some routes were
			 * already dumped, skip them next time.
			 */
			w->skip_in_node += res;

528 529
			return 1;
		}
530
		w->skip_in_node = 0;
531 532 533 534 535 536

		/* Multipath routes are dumped in one route with the
		 * RTA_MULTIPATH attribute. Jump 'rt' to point to the
		 * last sibling of this route (no need to dump the
		 * sibling routes again)
		 */
537 538
		if (rt->fib6_nsiblings)
			rt = list_last_entry(&rt->fib6_siblings,
539
					     struct fib6_info,
540
					     fib6_siblings);
541 542 543 544 545 546 547
	}
	w->leaf = NULL;
	return 0;
}

static void fib6_dump_end(struct netlink_callback *cb)
{
M
Michal Kubeček 已提交
548
	struct net *net = sock_net(cb->skb->sk);
549
	struct fib6_walker *w = (void *)cb->args[2];
550 551

	if (w) {
552 553
		if (cb->args[4]) {
			cb->args[4] = 0;
M
Michal Kubeček 已提交
554
			fib6_walker_unlink(net, w);
555
		}
556 557 558
		cb->args[2] = 0;
		kfree(w);
	}
559
	cb->done = (void *)cb->args[3];
560 561 562 563 564 565 566 567 568 569 570 571
	cb->args[1] = 3;
}

static int fib6_dump_done(struct netlink_callback *cb)
{
	fib6_dump_end(cb);
	return cb->done ? cb->done(cb) : 0;
}

static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
			   struct netlink_callback *cb)
{
M
Michal Kubeček 已提交
572
	struct net *net = sock_net(skb->sk);
573
	struct fib6_walker *w;
574 575 576 577 578 579
	int res;

	w = (void *)cb->args[2];
	w->root = &table->tb6_root;

	if (cb->args[4] == 0) {
580 581
		w->count = 0;
		w->skip = 0;
582
		w->skip_in_node = 0;
583

584
		spin_lock_bh(&table->tb6_lock);
M
Michal Kubeček 已提交
585
		res = fib6_walk(net, w);
586
		spin_unlock_bh(&table->tb6_lock);
587
		if (res > 0) {
588
			cb->args[4] = 1;
589 590
			cb->args[5] = w->root->fn_sernum;
		}
591
	} else {
592 593 594 595 596 597
		if (cb->args[5] != w->root->fn_sernum) {
			/* Begin at the root if the tree changed */
			cb->args[5] = w->root->fn_sernum;
			w->state = FWS_INIT;
			w->node = w->root;
			w->skip = w->count;
598
			w->skip_in_node = 0;
599 600 601
		} else
			w->skip = 0;

602
		spin_lock_bh(&table->tb6_lock);
603
		res = fib6_walk_continue(w);
604
		spin_unlock_bh(&table->tb6_lock);
605
		if (res <= 0) {
M
Michal Kubeček 已提交
606
			fib6_walker_unlink(net, w);
607
			cb->args[4] = 0;
608 609
		}
	}
610

611 612 613
	return res;
}

614
static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
615
{
616 617
	struct rt6_rtnl_dump_arg arg = { .filter.dump_exceptions = true,
					 .filter.dump_routes = true };
618
	const struct nlmsghdr *nlh = cb->nlh;
619
	struct net *net = sock_net(skb->sk);
620 621
	unsigned int h, s_h;
	unsigned int e = 0, s_e;
622
	struct fib6_walker *w;
623
	struct fib6_table *tb;
624
	struct hlist_head *head;
625 626
	int res = 0;

627
	if (cb->strict_check) {
D
David Ahern 已提交
628
		int err;
629

630
		err = ip_valid_fib_dump_req(net, nlh, &arg.filter, cb);
631 632
		if (err < 0)
			return err;
633 634
	} else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) {
		struct rtmsg *rtm = nlmsg_data(nlh);
635

636 637
		if (rtm->rtm_flags & RTM_F_PREFIX)
			arg.filter.flags = RTM_F_PREFIX;
638
	}
639 640

	w = (void *)cb->args[2];
641
	if (!w) {
642 643 644 645 646 647 648 649 650 651 652
		/* New dump:
		 *
		 * 1. hook callback destructor.
		 */
		cb->args[3] = (long)cb->done;
		cb->done = fib6_dump_done;

		/*
		 * 2. allocate and initialize walker.
		 */
		w = kzalloc(sizeof(*w), GFP_ATOMIC);
653
		if (!w)
654 655 656 657 658 659 660
			return -ENOMEM;
		w->func = fib6_dump_node;
		cb->args[2] = (long)w;
	}

	arg.skb = skb;
	arg.cb = cb;
661
	arg.net = net;
662 663
	w->args = &arg;

664 665 666
	if (arg.filter.table_id) {
		tb = fib6_get_table(net, arg.filter.table_id);
		if (!tb) {
667
			if (arg.filter.dump_all_families)
668
				goto out;
669

670 671 672 673
			NL_SET_ERR_MSG_MOD(cb->extack, "FIB table does not exist");
			return -ENOENT;
		}

674 675 676 677 678
		if (!cb->args[0]) {
			res = fib6_dump_table(tb, skb, cb);
			if (!res)
				cb->args[0] = 1;
		}
679 680 681 682 683 684
		goto out;
	}

	s_h = cb->args[0];
	s_e = cb->args[1];

685
	rcu_read_lock();
686
	for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) {
687
		e = 0;
688
		head = &net->ipv6.fib_table_hash[h];
689
		hlist_for_each_entry_rcu(tb, head, tb6_hlist) {
690 691 692 693
			if (e < s_e)
				goto next;
			res = fib6_dump_table(tb, skb, cb);
			if (res != 0)
694
				goto out_unlock;
695 696 697 698
next:
			e++;
		}
	}
699
out_unlock:
700
	rcu_read_unlock();
701 702
	cb->args[1] = e;
	cb->args[0] = h;
703
out:
704 705 706 707 708
	res = res < 0 ? res : skb->len;
	if (res <= 0)
		fib6_dump_end(cb);
	return res;
}
L
Linus Torvalds 已提交
709

710
void fib6_metric_set(struct fib6_info *f6i, int metric, u32 val)
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
{
	if (!f6i)
		return;

	if (f6i->fib6_metrics == &dst_default_metrics) {
		struct dst_metrics *p = kzalloc(sizeof(*p), GFP_ATOMIC);

		if (!p)
			return;

		refcount_set(&p->refcnt, 1);
		f6i->fib6_metrics = p;
	}

	f6i->fib6_metrics->metrics[metric - 1] = val;
}

L
Linus Torvalds 已提交
728 729 730 731 732 733 734 735
/*
 *	Routing Table
 *
 *	return the appropriate node for a routing tree "add" operation
 *	by either creating and inserting or by returning an existing
 *	node.
 */

W
Wei Wang 已提交
736 737
static struct fib6_node *fib6_add_1(struct net *net,
				    struct fib6_table *table,
738 739 740 741 742
				    struct fib6_node *root,
				    struct in6_addr *addr, int plen,
				    int offset, int allow_create,
				    int replace_required,
				    struct netlink_ext_ack *extack)
L
Linus Torvalds 已提交
743 744 745 746 747
{
	struct fib6_node *fn, *in, *ln;
	struct fib6_node *pn = NULL;
	struct rt6key *key;
	int	bit;
748
	__be32	dir = 0;
L
Linus Torvalds 已提交
749 750 751 752 753 754 755 756

	RT6_TRACE("fib6_add_1\n");

	/* insert node in tree */

	fn = root;

	do {
757
		struct fib6_info *leaf = rcu_dereference_protected(fn->leaf,
758 759
					    lockdep_is_held(&table->tb6_lock));
		key = (struct rt6key *)((u8 *)leaf + offset);
L
Linus Torvalds 已提交
760 761 762 763 764

		/*
		 *	Prefix match
		 */
		if (plen < fn->fn_bit ||
765
		    !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit)) {
766 767
			if (!allow_create) {
				if (replace_required) {
768 769
					NL_SET_ERR_MSG(extack,
						       "Can not replace route - no match found");
770
					pr_warn("Can't replace route, no match found\n");
771 772
					return ERR_PTR(-ENOENT);
				}
773
				pr_warn("NLM_F_CREATE should be set when creating new route\n");
774
			}
L
Linus Torvalds 已提交
775
			goto insert_above;
776
		}
777

L
Linus Torvalds 已提交
778 779 780
		/*
		 *	Exact match ?
		 */
781

L
Linus Torvalds 已提交
782 783
		if (plen == fn->fn_bit) {
			/* clean up an intermediate node */
784
			if (!(fn->fn_flags & RTN_RTINFO)) {
785
				RCU_INIT_POINTER(fn->leaf, NULL);
786
				fib6_info_release(leaf);
787 788 789
			/* remove null_entry in the root node */
			} else if (fn->fn_flags & RTN_TL_ROOT &&
				   rcu_access_pointer(fn->leaf) ==
D
David Ahern 已提交
790
				   net->ipv6.fib6_null_entry) {
791
				RCU_INIT_POINTER(fn->leaf, NULL);
L
Linus Torvalds 已提交
792
			}
793

L
Linus Torvalds 已提交
794 795 796 797 798 799
			return fn;
		}

		/*
		 *	We have more bits to go
		 */
800

L
Linus Torvalds 已提交
801 802 803
		/* Try to walk down on tree. */
		dir = addr_bit_set(addr, fn->fn_bit);
		pn = fn;
804 805 806 807 808
		fn = dir ?
		     rcu_dereference_protected(fn->right,
					lockdep_is_held(&table->tb6_lock)) :
		     rcu_dereference_protected(fn->left,
					lockdep_is_held(&table->tb6_lock));
L
Linus Torvalds 已提交
809 810
	} while (fn);

811
	if (!allow_create) {
812 813 814 815 816 817 818 819 820
		/* We should not create new node because
		 * NLM_F_REPLACE was specified without NLM_F_CREATE
		 * I assume it is safe to require NLM_F_CREATE when
		 * REPLACE flag is used! Later we may want to remove the
		 * check for replace_required, because according
		 * to netlink specification, NLM_F_CREATE
		 * MUST be specified if new route is created.
		 * That would keep IPv6 consistent with IPv4
		 */
821
		if (replace_required) {
822 823
			NL_SET_ERR_MSG(extack,
				       "Can not replace route - no match found");
824
			pr_warn("Can't replace route, no match found\n");
825 826
			return ERR_PTR(-ENOENT);
		}
827
		pr_warn("NLM_F_CREATE should be set when creating new route\n");
828
	}
L
Linus Torvalds 已提交
829 830 831 832 833
	/*
	 *	We walked to the bottom of tree.
	 *	Create new leaf node without children.
	 */

W
Wei Wang 已提交
834
	ln = node_alloc(net);
L
Linus Torvalds 已提交
835

836
	if (!ln)
837
		return ERR_PTR(-ENOMEM);
L
Linus Torvalds 已提交
838
	ln->fn_bit = plen;
839
	RCU_INIT_POINTER(ln->parent, pn);
L
Linus Torvalds 已提交
840 841

	if (dir)
842
		rcu_assign_pointer(pn->right, ln);
L
Linus Torvalds 已提交
843
	else
844
		rcu_assign_pointer(pn->left, ln);
L
Linus Torvalds 已提交
845 846 847 848 849 850

	return ln;


insert_above:
	/*
851
	 * split since we don't have a common prefix anymore or
L
Linus Torvalds 已提交
852 853 854 855 856 857
	 * we have a less significant route.
	 * we've to insert an intermediate node on the list
	 * this new node will point to the one we need to create
	 * and the current
	 */

858 859
	pn = rcu_dereference_protected(fn->parent,
				       lockdep_is_held(&table->tb6_lock));
L
Linus Torvalds 已提交
860 861 862

	/* find 1st bit in difference between the 2 addrs.

863
	   See comment in __ipv6_addr_diff: bit may be an invalid value,
L
Linus Torvalds 已提交
864 865
	   but if it is >= plen, the value is ignored in any case.
	 */
866

867
	bit = __ipv6_addr_diff(addr, &key->addr, sizeof(*addr));
L
Linus Torvalds 已提交
868

869 870
	/*
	 *		(intermediate)[in]
L
Linus Torvalds 已提交
871 872 873 874
	 *	          /	   \
	 *	(new leaf node)[ln] (old node)[fn]
	 */
	if (plen > bit) {
W
Wei Wang 已提交
875 876
		in = node_alloc(net);
		ln = node_alloc(net);
877

878
		if (!in || !ln) {
L
Linus Torvalds 已提交
879
			if (in)
W
Wei Wang 已提交
880
				node_free_immediate(net, in);
L
Linus Torvalds 已提交
881
			if (ln)
W
Wei Wang 已提交
882
				node_free_immediate(net, ln);
883
			return ERR_PTR(-ENOMEM);
L
Linus Torvalds 已提交
884 885
		}

886 887
		/*
		 * new intermediate node.
L
Linus Torvalds 已提交
888 889 890 891 892 893 894 895
		 * RTN_RTINFO will
		 * be off since that an address that chooses one of
		 * the branches would not match less specific routes
		 * in the other branch
		 */

		in->fn_bit = bit;

896
		RCU_INIT_POINTER(in->parent, pn);
L
Linus Torvalds 已提交
897
		in->leaf = fn->leaf;
898 899
		fib6_info_hold(rcu_dereference_protected(in->leaf,
				lockdep_is_held(&table->tb6_lock)));
L
Linus Torvalds 已提交
900 901 902

		/* update parent pointer */
		if (dir)
903
			rcu_assign_pointer(pn->right, in);
L
Linus Torvalds 已提交
904
		else
905
			rcu_assign_pointer(pn->left, in);
L
Linus Torvalds 已提交
906 907 908

		ln->fn_bit = plen;

909 910
		RCU_INIT_POINTER(ln->parent, in);
		rcu_assign_pointer(fn->parent, in);
L
Linus Torvalds 已提交
911 912

		if (addr_bit_set(addr, bit)) {
913 914
			rcu_assign_pointer(in->right, ln);
			rcu_assign_pointer(in->left, fn);
L
Linus Torvalds 已提交
915
		} else {
916 917
			rcu_assign_pointer(in->left, ln);
			rcu_assign_pointer(in->right, fn);
L
Linus Torvalds 已提交
918 919 920
		}
	} else { /* plen <= bit */

921
		/*
L
Linus Torvalds 已提交
922 923 924 925 926
		 *		(new leaf node)[ln]
		 *	          /	   \
		 *	     (old node)[fn] NULL
		 */

W
Wei Wang 已提交
927
		ln = node_alloc(net);
L
Linus Torvalds 已提交
928

929
		if (!ln)
930
			return ERR_PTR(-ENOMEM);
L
Linus Torvalds 已提交
931 932 933

		ln->fn_bit = plen;

934
		RCU_INIT_POINTER(ln->parent, pn);
L
Linus Torvalds 已提交
935 936

		if (addr_bit_set(&key->addr, plen))
937
			RCU_INIT_POINTER(ln->right, fn);
L
Linus Torvalds 已提交
938
		else
939 940 941
			RCU_INIT_POINTER(ln->left, fn);

		rcu_assign_pointer(fn->parent, ln);
L
Linus Torvalds 已提交
942

943 944 945 946
		if (dir)
			rcu_assign_pointer(pn->right, ln);
		else
			rcu_assign_pointer(pn->left, ln);
L
Linus Torvalds 已提交
947 948 949 950
	}
	return ln;
}

D
David Ahern 已提交
951 952 953
static void __fib6_drop_pcpu_from(struct fib6_nh *fib6_nh,
				  const struct fib6_info *match,
				  const struct fib6_table *table)
954
{
955
	int cpu;
956

957 958 959
	if (!fib6_nh->rt6i_pcpu)
		return;

960 961 962 963 964 965
	/* release the reference to this fib entry from
	 * all of its cached pcpu routes
	 */
	for_each_possible_cpu(cpu) {
		struct rt6_info **ppcpu_rt;
		struct rt6_info *pcpu_rt;
966

967
		ppcpu_rt = per_cpu_ptr(fib6_nh->rt6i_pcpu, cpu);
968
		pcpu_rt = *ppcpu_rt;
D
David Ahern 已提交
969 970 971 972 973 974 975

		/* only dropping the 'from' reference if the cached route
		 * is using 'match'. The cached pcpu_rt->from only changes
		 * from a fib6_info to NULL (ip6_dst_destroy); it can never
		 * change from one fib6_info reference to another
		 */
		if (pcpu_rt && rcu_access_pointer(pcpu_rt->from) == match) {
976
			struct fib6_info *from;
977

978
			from = xchg((__force struct fib6_info **)&pcpu_rt->from, NULL);
979
			fib6_info_release(from);
980
		}
981 982 983
	}
}

984 985 986 987 988 989 990 991 992 993 994 995 996
struct fib6_nh_pcpu_arg {
	struct fib6_info	*from;
	const struct fib6_table *table;
};

static int fib6_nh_drop_pcpu_from(struct fib6_nh *nh, void *_arg)
{
	struct fib6_nh_pcpu_arg *arg = _arg;

	__fib6_drop_pcpu_from(nh, arg->from, arg->table);
	return 0;
}

D
David Ahern 已提交
997 998 999 1000 1001 1002 1003 1004 1005
static void fib6_drop_pcpu_from(struct fib6_info *f6i,
				const struct fib6_table *table)
{
	/* Make sure rt6_make_pcpu_route() wont add other percpu routes
	 * while we are cleaning them here.
	 */
	f6i->fib6_destroying = 1;
	mb(); /* paired with the cmpxchg() in rt6_make_pcpu_route() */

1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
	if (f6i->nh) {
		struct fib6_nh_pcpu_arg arg = {
			.from = f6i,
			.table = table
		};

		nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_drop_pcpu_from,
					 &arg);
	} else {
		struct fib6_nh *fib6_nh;

		fib6_nh = f6i->fib6_nh;
		__fib6_drop_pcpu_from(fib6_nh, f6i, table);
	}
D
David Ahern 已提交
1020 1021
}

1022
static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn,
1023 1024
			  struct net *net)
{
1025
	struct fib6_table *table = rt->fib6_table;
1026

1027
	fib6_drop_pcpu_from(rt, table);
E
Eric Dumazet 已提交
1028

1029 1030 1031
	if (rt->nh && !list_empty(&rt->nh_list))
		list_del_init(&rt->nh_list);

1032
	if (refcount_read(&rt->fib6_ref) != 1) {
1033 1034 1035 1036 1037 1038 1039
		/* This route is used as dummy address holder in some split
		 * nodes. It is not leaked, but it still holds other resources,
		 * which must be released in time. So, scan ascendant nodes
		 * and replace dummy references to this route with references
		 * to still alive ones.
		 */
		while (fn) {
1040
			struct fib6_info *leaf = rcu_dereference_protected(fn->leaf,
1041
					    lockdep_is_held(&table->tb6_lock));
1042
			struct fib6_info *new_leaf;
1043 1044
			if (!(fn->fn_flags & RTN_RTINFO) && leaf == rt) {
				new_leaf = fib6_find_prefix(net, table, fn);
1045
				fib6_info_hold(new_leaf);
1046

1047
				rcu_assign_pointer(fn->leaf, new_leaf);
1048
				fib6_info_release(rt);
1049
			}
1050 1051
			fn = rcu_dereference_protected(fn->parent,
				    lockdep_is_held(&table->tb6_lock));
1052 1053 1054 1055
		}
	}
}

L
Linus Torvalds 已提交
1056 1057 1058 1059
/*
 *	Insert routing information in a node.
 */

1060
static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
1061
			    struct nl_info *info,
D
David Ahern 已提交
1062
			    struct netlink_ext_ack *extack)
L
Linus Torvalds 已提交
1063
{
1064
	struct fib6_info *leaf = rcu_dereference_protected(fn->leaf,
1065
				    lockdep_is_held(&rt->fib6_table->tb6_lock));
1066
	struct fib6_info *iter = NULL;
1067
	struct fib6_info __rcu **ins;
1068
	struct fib6_info __rcu **fallback_ins = NULL;
1069 1070 1071 1072
	int replace = (info->nlh &&
		       (info->nlh->nlmsg_flags & NLM_F_REPLACE));
	int add = (!info->nlh ||
		   (info->nlh->nlmsg_flags & NLM_F_CREATE));
1073
	int found = 0;
1074
	bool rt_can_ecmp = rt6_qualify_for_ecmp(rt);
1075
	bool notify_sibling_rt = false;
1076
	u16 nlflags = NLM_F_EXCL;
1077
	int err;
L
Linus Torvalds 已提交
1078

1079
	if (info->nlh && (info->nlh->nlmsg_flags & NLM_F_APPEND))
1080 1081
		nlflags |= NLM_F_APPEND;

L
Linus Torvalds 已提交
1082 1083
	ins = &fn->leaf;

1084
	for (iter = leaf; iter;
1085
	     iter = rcu_dereference_protected(iter->fib6_next,
1086
				lockdep_is_held(&rt->fib6_table->tb6_lock))) {
L
Linus Torvalds 已提交
1087 1088 1089 1090
		/*
		 *	Search for duplicates
		 */

1091
		if (iter->fib6_metric == rt->fib6_metric) {
L
Linus Torvalds 已提交
1092 1093 1094
			/*
			 *	Same priority level
			 */
1095 1096
			if (info->nlh &&
			    (info->nlh->nlmsg_flags & NLM_F_EXCL))
1097
				return -EEXIST;
1098 1099

			nlflags &= ~NLM_F_EXCL;
1100
			if (replace) {
1101 1102 1103 1104
				if (rt_can_ecmp == rt6_qualify_for_ecmp(iter)) {
					found++;
					break;
				}
1105
				fallback_ins = fallback_ins ?: ins;
1106
				goto next_iter;
1107
			}
L
Linus Torvalds 已提交
1108

1109
			if (rt6_duplicate_nexthop(iter, rt)) {
1110 1111 1112
				if (rt->fib6_nsiblings)
					rt->fib6_nsiblings = 0;
				if (!(iter->fib6_flags & RTF_EXPIRES))
L
Linus Torvalds 已提交
1113
					return -EEXIST;
1114
				if (!(rt->fib6_flags & RTF_EXPIRES))
1115
					fib6_clean_expires(iter);
1116
				else
1117
					fib6_set_expires(iter, rt->expires);
1118 1119 1120 1121

				if (rt->fib6_pmtu)
					fib6_metric_set(iter, RTAX_MTU,
							rt->fib6_pmtu);
L
Linus Torvalds 已提交
1122 1123
				return -EEXIST;
			}
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
			/* If we have the same destination and the same metric,
			 * but not the same gateway, then the route we try to
			 * add is sibling to this route, increment our counter
			 * of siblings, and later we will add our route to the
			 * list.
			 * Only static routes (which don't have flag
			 * RTF_EXPIRES) are used for ECMPv6.
			 *
			 * To avoid long list, we only had siblings if the
			 * route have a gateway.
			 */
			if (rt_can_ecmp &&
			    rt6_qualify_for_ecmp(iter))
				rt->fib6_nsiblings++;
L
Linus Torvalds 已提交
1138 1139
		}

1140
		if (iter->fib6_metric > rt->fib6_metric)
L
Linus Torvalds 已提交
1141 1142
			break;

1143
next_iter:
1144
		ins = &iter->fib6_next;
1145 1146
	}

1147
	if (fallback_ins && !found) {
1148 1149 1150
		/* No matching route with same ecmp-able-ness found, replace
		 * first matching route
		 */
1151 1152 1153 1154 1155 1156
		ins = fallback_ins;
		iter = rcu_dereference_protected(*ins,
				    lockdep_is_held(&rt->fib6_table->tb6_lock));
		found++;
	}

1157 1158 1159 1160
	/* Reset round-robin state, if necessary */
	if (ins == &fn->leaf)
		fn->rr_ptr = NULL;

1161
	/* Link this route to others same route. */
1162 1163
	if (rt->fib6_nsiblings) {
		unsigned int fib6_nsiblings;
1164
		struct fib6_info *sibling, *temp_sibling;
1165

1166 1167
		/* Find the first route that have the same metric */
		sibling = leaf;
1168
		notify_sibling_rt = true;
1169 1170 1171 1172 1173 1174 1175 1176 1177
		while (sibling) {
			if (sibling->fib6_metric == rt->fib6_metric &&
			    rt6_qualify_for_ecmp(sibling)) {
				list_add_tail(&rt->fib6_siblings,
					      &sibling->fib6_siblings);
				break;
			}
			sibling = rcu_dereference_protected(sibling->fib6_next,
				    lockdep_is_held(&rt->fib6_table->tb6_lock));
1178
			notify_sibling_rt = false;
1179 1180 1181 1182 1183
		}
		/* For each sibling in the list, increment the counter of
		 * siblings. BUG() if counters does not match, list of siblings
		 * is broken!
		 */
1184
		fib6_nsiblings = 0;
1185
		list_for_each_entry_safe(sibling, temp_sibling,
1186
					 &rt->fib6_siblings, fib6_siblings) {
1187
			sibling->fib6_nsiblings++;
1188 1189
			BUG_ON(sibling->fib6_nsiblings != rt->fib6_nsiblings);
			fib6_nsiblings++;
1190
		}
1191 1192
		BUG_ON(fib6_nsiblings != rt->fib6_nsiblings);
		rt6_multipath_rebalance(temp_sibling);
1193 1194
	}

L
Linus Torvalds 已提交
1195 1196 1197
	/*
	 *	insert node
	 */
1198 1199
	if (!replace) {
		if (!add)
1200
			pr_warn("NLM_F_CREATE should be set when creating new route\n");
1201 1202

add:
1203
		nlflags |= NLM_F_CREATE;
1204

1205 1206 1207 1208 1209 1210
		/* The route should only be notified if it is the first
		 * route in the node or if it is added as a sibling
		 * route to the first route in the node.
		 */
		if (!info->skip_notify_kernel &&
		    (notify_sibling_rt || ins == &fn->leaf)) {
1211 1212 1213 1214 1215
			enum fib_event_type fib_event;

			if (notify_sibling_rt)
				fib_event = FIB_EVENT_ENTRY_APPEND;
			else
1216
				fib_event = FIB_EVENT_ENTRY_REPLACE;
1217
			err = call_fib6_entry_notifiers(info->nl_net,
1218 1219
							fib_event, rt,
							extack);
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
			if (err) {
				struct fib6_info *sibling, *next_sibling;

				/* If the route has siblings, then it first
				 * needs to be unlinked from them.
				 */
				if (!rt->fib6_nsiblings)
					return err;

				list_for_each_entry_safe(sibling, next_sibling,
							 &rt->fib6_siblings,
							 fib6_siblings)
					sibling->fib6_nsiblings--;
				rt->fib6_nsiblings = 0;
				list_del_init(&rt->fib6_siblings);
				rt6_multipath_rebalance(next_sibling);
1236
				return err;
1237
			}
1238
		}
1239

1240
		rcu_assign_pointer(rt->fib6_next, iter);
1241
		fib6_info_hold(rt);
1242
		rcu_assign_pointer(rt->fib6_node, fn);
1243
		rcu_assign_pointer(*ins, rt);
1244 1245
		if (!info->skip_notify)
			inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
1246 1247
		info->nl_net->ipv6.rt6_stats->fib_rt_entries++;

1248
		if (!(fn->fn_flags & RTN_RTINFO)) {
1249 1250 1251
			info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
			fn->fn_flags |= RTN_RTINFO;
		}
L
Linus Torvalds 已提交
1252

1253
	} else {
1254
		int nsiblings;
1255

1256 1257 1258
		if (!found) {
			if (add)
				goto add;
1259
			pr_warn("NLM_F_REPLACE set, but no existing node found!\n");
1260 1261
			return -ENOENT;
		}
1262

1263
		if (!info->skip_notify_kernel && ins == &fn->leaf) {
1264 1265 1266 1267 1268 1269
			err = call_fib6_entry_notifiers(info->nl_net,
							FIB_EVENT_ENTRY_REPLACE,
							rt, extack);
			if (err)
				return err;
		}
1270

1271
		fib6_info_hold(rt);
1272
		rcu_assign_pointer(rt->fib6_node, fn);
1273
		rt->fib6_next = iter->fib6_next;
1274
		rcu_assign_pointer(*ins, rt);
1275 1276
		if (!info->skip_notify)
			inet6_rt_notify(RTM_NEWROUTE, rt, info, NLM_F_REPLACE);
1277
		if (!(fn->fn_flags & RTN_RTINFO)) {
1278 1279 1280
			info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
			fn->fn_flags |= RTN_RTINFO;
		}
1281 1282 1283 1284 1285 1286
		nsiblings = iter->fib6_nsiblings;
		iter->fib6_node = NULL;
		fib6_purge_rt(iter, fn, info->nl_net);
		if (rcu_access_pointer(fn->rr_ptr) == iter)
			fn->rr_ptr = NULL;
		fib6_info_release(iter);
1287

1288
		if (nsiblings) {
1289
			/* Replacing an ECMP route, remove all siblings */
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
			ins = &rt->fib6_next;
			iter = rcu_dereference_protected(*ins,
				    lockdep_is_held(&rt->fib6_table->tb6_lock));
			while (iter) {
				if (iter->fib6_metric > rt->fib6_metric)
					break;
				if (rt6_qualify_for_ecmp(iter)) {
					*ins = iter->fib6_next;
					iter->fib6_node = NULL;
					fib6_purge_rt(iter, fn, info->nl_net);
					if (rcu_access_pointer(fn->rr_ptr) == iter)
						fn->rr_ptr = NULL;
					fib6_info_release(iter);
					nsiblings--;
					info->nl_net->ipv6.rt6_stats->fib_rt_entries--;
				} else {
					ins = &iter->fib6_next;
				}
				iter = rcu_dereference_protected(*ins,
					lockdep_is_held(&rt->fib6_table->tb6_lock));
1310
			}
1311
			WARN_ON(nsiblings != 0);
1312
		}
L
Linus Torvalds 已提交
1313 1314 1315 1316 1317
	}

	return 0;
}

1318
static void fib6_start_gc(struct net *net, struct fib6_info *rt)
L
Linus Torvalds 已提交
1319
{
1320
	if (!timer_pending(&net->ipv6.ip6_fib_timer) &&
1321
	    (rt->fib6_flags & RTF_EXPIRES))
1322
		mod_timer(&net->ipv6.ip6_fib_timer,
S
Stephen Hemminger 已提交
1323
			  jiffies + net->ipv6.sysctl.ip6_rt_gc_interval);
L
Linus Torvalds 已提交
1324 1325
}

1326
void fib6_force_start_gc(struct net *net)
L
Linus Torvalds 已提交
1327
{
1328 1329
	if (!timer_pending(&net->ipv6.ip6_fib_timer))
		mod_timer(&net->ipv6.ip6_fib_timer,
S
Stephen Hemminger 已提交
1330
			  jiffies + net->ipv6.sysctl.ip6_rt_gc_interval);
L
Linus Torvalds 已提交
1331 1332
}

1333
static void __fib6_update_sernum_upto_root(struct fib6_info *rt,
1334
					   int sernum)
1335
{
1336 1337
	struct fib6_node *fn = rcu_dereference_protected(rt->fib6_node,
				lockdep_is_held(&rt->fib6_table->tb6_lock));
1338 1339 1340 1341 1342

	/* paired with smp_rmb() in rt6_get_cookie_safe() */
	smp_wmb();
	while (fn) {
		fn->fn_sernum = sernum;
1343
		fn = rcu_dereference_protected(fn->parent,
1344
				lockdep_is_held(&rt->fib6_table->tb6_lock));
1345 1346 1347
	}
}

1348
void fib6_update_sernum_upto_root(struct net *net, struct fib6_info *rt)
1349 1350 1351 1352
{
	__fib6_update_sernum_upto_root(rt, fib6_new_sernum(net));
}

1353 1354 1355 1356 1357 1358 1359 1360
/* allow ipv4 to update sernum via ipv6_stub */
void fib6_update_sernum_stub(struct net *net, struct fib6_info *f6i)
{
	spin_lock_bh(&f6i->fib6_table->tb6_lock);
	fib6_update_sernum_upto_root(net, f6i);
	spin_unlock_bh(&f6i->fib6_table->tb6_lock);
}

L
Linus Torvalds 已提交
1361 1362 1363 1364
/*
 *	Add routing information to the routing tree.
 *	<destination addr>/<source addr>
 *	with source addr info in sub-trees
1365
 *	Need to own table->tb6_lock
L
Linus Torvalds 已提交
1366 1367
 */

1368
int fib6_add(struct fib6_node *root, struct fib6_info *rt,
1369
	     struct nl_info *info, struct netlink_ext_ack *extack)
L
Linus Torvalds 已提交
1370
{
1371
	struct fib6_table *table = rt->fib6_table;
1372
	struct fib6_node *fn, *pn = NULL;
L
Linus Torvalds 已提交
1373
	int err = -ENOMEM;
1374 1375
	int allow_create = 1;
	int replace_required = 0;
1376
	int sernum = fib6_new_sernum(info->nl_net);
1377 1378 1379

	if (info->nlh) {
		if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
1380
			allow_create = 0;
1381
		if (info->nlh->nlmsg_flags & NLM_F_REPLACE)
1382 1383 1384
			replace_required = 1;
	}
	if (!allow_create && !replace_required)
1385
		pr_warn("RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");
L
Linus Torvalds 已提交
1386

W
Wei Wang 已提交
1387
	fn = fib6_add_1(info->nl_net, table, root,
1388 1389
			&rt->fib6_dst.addr, rt->fib6_dst.plen,
			offsetof(struct fib6_info, fib6_dst), allow_create,
1390
			replace_required, extack);
1391 1392
	if (IS_ERR(fn)) {
		err = PTR_ERR(fn);
1393
		fn = NULL;
L
Linus Torvalds 已提交
1394
		goto out;
1395
	}
L
Linus Torvalds 已提交
1396

1397 1398
	pn = fn;

L
Linus Torvalds 已提交
1399
#ifdef CONFIG_IPV6_SUBTREES
1400
	if (rt->fib6_src.plen) {
L
Linus Torvalds 已提交
1401 1402
		struct fib6_node *sn;

1403
		if (!rcu_access_pointer(fn->subtree)) {
L
Linus Torvalds 已提交
1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
			struct fib6_node *sfn;

			/*
			 * Create subtree.
			 *
			 *		fn[main tree]
			 *		|
			 *		sfn[subtree root]
			 *		   \
			 *		    sn[new leaf node]
			 */

			/* Create subtree root node */
W
Wei Wang 已提交
1417
			sfn = node_alloc(info->nl_net);
1418
			if (!sfn)
1419
				goto failure;
L
Linus Torvalds 已提交
1420

1421
			fib6_info_hold(info->nl_net->ipv6.fib6_null_entry);
1422
			rcu_assign_pointer(sfn->leaf,
D
David Ahern 已提交
1423
					   info->nl_net->ipv6.fib6_null_entry);
L
Linus Torvalds 已提交
1424 1425 1426 1427
			sfn->fn_flags = RTN_ROOT;

			/* Now add the first leaf node to new subtree */

W
Wei Wang 已提交
1428
			sn = fib6_add_1(info->nl_net, table, sfn,
1429 1430
					&rt->fib6_src.addr, rt->fib6_src.plen,
					offsetof(struct fib6_info, fib6_src),
1431
					allow_create, replace_required, extack);
L
Linus Torvalds 已提交
1432

1433
			if (IS_ERR(sn)) {
L
Linus Torvalds 已提交
1434
				/* If it is failed, discard just allocated
1435
				   root, and then (in failure) stale node
L
Linus Torvalds 已提交
1436 1437
				   in main tree.
				 */
W
Wei Wang 已提交
1438
				node_free_immediate(info->nl_net, sfn);
1439
				err = PTR_ERR(sn);
1440
				goto failure;
L
Linus Torvalds 已提交
1441 1442 1443
			}

			/* Now link new subtree to main tree */
1444 1445
			rcu_assign_pointer(sfn->parent, fn);
			rcu_assign_pointer(fn->subtree, sfn);
L
Linus Torvalds 已提交
1446
		} else {
W
Wei Wang 已提交
1447
			sn = fib6_add_1(info->nl_net, table, FIB6_SUBTREE(fn),
1448 1449
					&rt->fib6_src.addr, rt->fib6_src.plen,
					offsetof(struct fib6_info, fib6_src),
1450
					allow_create, replace_required, extack);
L
Linus Torvalds 已提交
1451

1452 1453
			if (IS_ERR(sn)) {
				err = PTR_ERR(sn);
1454
				goto failure;
1455
			}
L
Linus Torvalds 已提交
1456 1457
		}

1458
		if (!rcu_access_pointer(fn->leaf)) {
1459 1460 1461
			if (fn->fn_flags & RTN_TL_ROOT) {
				/* put back null_entry for root node */
				rcu_assign_pointer(fn->leaf,
D
David Ahern 已提交
1462
					    info->nl_net->ipv6.fib6_null_entry);
1463
			} else {
1464
				fib6_info_hold(rt);
1465 1466
				rcu_assign_pointer(fn->leaf, rt);
			}
1467
		}
L
Linus Torvalds 已提交
1468 1469 1470 1471
		fn = sn;
	}
#endif

1472
	err = fib6_add_rt2node(fn, rt, info, extack);
1473
	if (!err) {
1474 1475
		if (rt->nh)
			list_add(&rt->nh_list, &rt->nh->f6i_list);
1476
		__fib6_update_sernum_upto_root(rt, sernum);
1477
		fib6_start_gc(info->nl_net, rt);
1478
	}
L
Linus Torvalds 已提交
1479 1480

out:
1481 1482 1483 1484 1485 1486
	if (err) {
#ifdef CONFIG_IPV6_SUBTREES
		/*
		 * If fib6_add_1 has cleared the old leaf pointer in the
		 * super-tree leaf node we have to find a new one for it.
		 */
1487
		if (pn != fn) {
1488
			struct fib6_info *pn_leaf =
1489 1490 1491 1492 1493
				rcu_dereference_protected(pn->leaf,
				    lockdep_is_held(&table->tb6_lock));
			if (pn_leaf == rt) {
				pn_leaf = NULL;
				RCU_INIT_POINTER(pn->leaf, NULL);
1494
				fib6_info_release(rt);
1495
			}
1496 1497 1498 1499 1500 1501 1502
			if (!pn_leaf && !(pn->fn_flags & RTN_RTINFO)) {
				pn_leaf = fib6_find_prefix(info->nl_net, table,
							   pn);
#if RT6_DEBUG >= 2
				if (!pn_leaf) {
					WARN_ON(!pn_leaf);
					pn_leaf =
D
David Ahern 已提交
1503
					    info->nl_net->ipv6.fib6_null_entry;
1504
				}
1505
#endif
1506
				fib6_info_hold(pn_leaf);
1507 1508
				rcu_assign_pointer(pn->leaf, pn_leaf);
			}
1509 1510
		}
#endif
1511
		goto failure;
P
Paolo Abeni 已提交
1512 1513
	} else if (fib6_requires_src(rt)) {
		fib6_routes_require_src_inc(info->nl_net);
1514
	}
L
Linus Torvalds 已提交
1515 1516
	return err;

1517
failure:
1518 1519 1520 1521 1522 1523
	/* fn->leaf could be NULL and fib6_repair_tree() needs to be called if:
	 * 1. fn is an intermediate node and we failed to add the new
	 * route to it in both subtree creation failure and fib6_add_rt2node()
	 * failure case.
	 * 2. fn is the root node in the table and we fail to add the first
	 * default route to it.
L
Linus Torvalds 已提交
1524
	 */
1525 1526 1527 1528
	if (fn &&
	    (!(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)) ||
	     (fn->fn_flags & RTN_TL_ROOT &&
	      !rcu_access_pointer(fn->leaf))))
1529
		fib6_repair_tree(info->nl_net, table, fn);
L
Linus Torvalds 已提交
1530 1531 1532 1533 1534 1535 1536 1537 1538
	return err;
}

/*
 *	Routing tree lookup
 *
 */

struct lookup_args {
1539
	int			offset;		/* key offset on fib6_info */
1540
	const struct in6_addr	*addr;		/* search key			*/
L
Linus Torvalds 已提交
1541 1542
};

1543 1544
static struct fib6_node *fib6_node_lookup_1(struct fib6_node *root,
					    struct lookup_args *args)
L
Linus Torvalds 已提交
1545 1546
{
	struct fib6_node *fn;
A
Al Viro 已提交
1547
	__be32 dir;
L
Linus Torvalds 已提交
1548

1549 1550 1551
	if (unlikely(args->offset == 0))
		return NULL;

L
Linus Torvalds 已提交
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
	/*
	 *	Descend on a tree
	 */

	fn = root;

	for (;;) {
		struct fib6_node *next;

		dir = addr_bit_set(args->addr, fn->fn_bit);

1563 1564
		next = dir ? rcu_dereference(fn->right) :
			     rcu_dereference(fn->left);
L
Linus Torvalds 已提交
1565 1566 1567 1568 1569 1570 1571 1572

		if (next) {
			fn = next;
			continue;
		}
		break;
	}

1573
	while (fn) {
1574 1575 1576
		struct fib6_node *subtree = FIB6_SUBTREE(fn);

		if (subtree || fn->fn_flags & RTN_RTINFO) {
1577
			struct fib6_info *leaf = rcu_dereference(fn->leaf);
L
Linus Torvalds 已提交
1578 1579
			struct rt6key *key;

W
Wei Wang 已提交
1580 1581 1582 1583
			if (!leaf)
				goto backtrack;

			key = (struct rt6key *) ((u8 *)leaf + args->offset);
L
Linus Torvalds 已提交
1584

1585 1586
			if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) {
#ifdef CONFIG_IPV6_SUBTREES
1587
				if (subtree) {
1588
					struct fib6_node *sfn;
1589 1590
					sfn = fib6_node_lookup_1(subtree,
								 args + 1);
1591 1592 1593 1594
					if (!sfn)
						goto backtrack;
					fn = sfn;
				}
1595
#endif
1596
				if (fn->fn_flags & RTN_RTINFO)
1597 1598
					return fn;
			}
L
Linus Torvalds 已提交
1599
		}
1600
backtrack:
1601 1602 1603
		if (fn->fn_flags & RTN_ROOT)
			break;

1604
		fn = rcu_dereference(fn->parent);
L
Linus Torvalds 已提交
1605 1606 1607 1608 1609
	}

	return NULL;
}

1610 1611
/* called with rcu_read_lock() held
 */
1612 1613 1614
struct fib6_node *fib6_node_lookup(struct fib6_node *root,
				   const struct in6_addr *daddr,
				   const struct in6_addr *saddr)
L
Linus Torvalds 已提交
1615 1616
{
	struct fib6_node *fn;
1617 1618
	struct lookup_args args[] = {
		{
1619
			.offset = offsetof(struct fib6_info, fib6_dst),
1620 1621
			.addr = daddr,
		},
L
Linus Torvalds 已提交
1622
#ifdef CONFIG_IPV6_SUBTREES
1623
		{
1624
			.offset = offsetof(struct fib6_info, fib6_src),
1625 1626
			.addr = saddr,
		},
L
Linus Torvalds 已提交
1627
#endif
1628 1629 1630 1631
		{
			.offset = 0,	/* sentinel */
		}
	};
L
Linus Torvalds 已提交
1632

1633
	fn = fib6_node_lookup_1(root, daddr ? args : args + 1);
1634
	if (!fn || fn->fn_flags & RTN_TL_ROOT)
L
Linus Torvalds 已提交
1635 1636 1637 1638 1639 1640 1641 1642
		fn = root;

	return fn;
}

/*
 *	Get node with specified destination prefix (and source prefix,
 *	if subtrees are used)
1643 1644 1645 1646 1647 1648
 *	exact_match == true means we try to find fn with exact match of
 *	the passed in prefix addr
 *	exact_match == false means we try to find fn with longest prefix
 *	match of the passed in prefix addr. This is useful for finding fn
 *	for cached route as it will be stored in the exception table under
 *	the node with longest prefix length.
L
Linus Torvalds 已提交
1649 1650 1651
 */


1652 1653
static struct fib6_node *fib6_locate_1(struct fib6_node *root,
				       const struct in6_addr *addr,
1654 1655
				       int plen, int offset,
				       bool exact_match)
L
Linus Torvalds 已提交
1656
{
1657
	struct fib6_node *fn, *prev = NULL;
L
Linus Torvalds 已提交
1658 1659

	for (fn = root; fn ; ) {
1660
		struct fib6_info *leaf = rcu_dereference(fn->leaf);
W
Wei Wang 已提交
1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671
		struct rt6key *key;

		/* This node is being deleted */
		if (!leaf) {
			if (plen <= fn->fn_bit)
				goto out;
			else
				goto next;
		}

		key = (struct rt6key *)((u8 *)leaf + offset);
L
Linus Torvalds 已提交
1672 1673 1674 1675 1676 1677

		/*
		 *	Prefix match
		 */
		if (plen < fn->fn_bit ||
		    !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit))
1678
			goto out;
L
Linus Torvalds 已提交
1679 1680 1681 1682

		if (plen == fn->fn_bit)
			return fn;

1683 1684
		if (fn->fn_flags & RTN_RTINFO)
			prev = fn;
1685

W
Wei Wang 已提交
1686
next:
L
Linus Torvalds 已提交
1687 1688 1689 1690
		/*
		 *	We have more bits to go
		 */
		if (addr_bit_set(addr, fn->fn_bit))
1691
			fn = rcu_dereference(fn->right);
L
Linus Torvalds 已提交
1692
		else
1693
			fn = rcu_dereference(fn->left);
L
Linus Torvalds 已提交
1694
	}
1695 1696 1697 1698 1699
out:
	if (exact_match)
		return NULL;
	else
		return prev;
L
Linus Torvalds 已提交
1700 1701
}

1702 1703
struct fib6_node *fib6_locate(struct fib6_node *root,
			      const struct in6_addr *daddr, int dst_len,
1704 1705
			      const struct in6_addr *saddr, int src_len,
			      bool exact_match)
L
Linus Torvalds 已提交
1706 1707 1708 1709
{
	struct fib6_node *fn;

	fn = fib6_locate_1(root, daddr, dst_len,
1710
			   offsetof(struct fib6_info, fib6_dst),
1711
			   exact_match);
L
Linus Torvalds 已提交
1712 1713 1714

#ifdef CONFIG_IPV6_SUBTREES
	if (src_len) {
1715
		WARN_ON(saddr == NULL);
1716 1717 1718 1719 1720
		if (fn) {
			struct fib6_node *subtree = FIB6_SUBTREE(fn);

			if (subtree) {
				fn = fib6_locate_1(subtree, saddr, src_len,
1721
					   offsetof(struct fib6_info, fib6_src),
1722
					   exact_match);
1723 1724
			}
		}
L
Linus Torvalds 已提交
1725 1726 1727
	}
#endif

1728
	if (fn && fn->fn_flags & RTN_RTINFO)
L
Linus Torvalds 已提交
1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739
		return fn;

	return NULL;
}


/*
 *	Deletion
 *
 */

1740
static struct fib6_info *fib6_find_prefix(struct net *net,
1741 1742
					 struct fib6_table *table,
					 struct fib6_node *fn)
L
Linus Torvalds 已提交
1743
{
1744 1745
	struct fib6_node *child_left, *child_right;

1746
	if (fn->fn_flags & RTN_ROOT)
D
David Ahern 已提交
1747
		return net->ipv6.fib6_null_entry;
L
Linus Torvalds 已提交
1748

1749
	while (fn) {
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759
		child_left = rcu_dereference_protected(fn->left,
				    lockdep_is_held(&table->tb6_lock));
		child_right = rcu_dereference_protected(fn->right,
				    lockdep_is_held(&table->tb6_lock));
		if (child_left)
			return rcu_dereference_protected(child_left->leaf,
					lockdep_is_held(&table->tb6_lock));
		if (child_right)
			return rcu_dereference_protected(child_right->leaf,
					lockdep_is_held(&table->tb6_lock));
L
Linus Torvalds 已提交
1760

1761
		fn = FIB6_SUBTREE(fn);
L
Linus Torvalds 已提交
1762 1763 1764 1765 1766 1767 1768
	}
	return NULL;
}

/*
 *	Called to trim the tree of intermediate nodes when possible. "fn"
 *	is the node we want to try and remove.
1769
 *	Need to own table->tb6_lock
L
Linus Torvalds 已提交
1770 1771
 */

1772
static struct fib6_node *fib6_repair_tree(struct net *net,
1773 1774
					  struct fib6_table *table,
					  struct fib6_node *fn)
L
Linus Torvalds 已提交
1775 1776 1777
{
	int children;
	int nstate;
1778
	struct fib6_node *child;
1779
	struct fib6_walker *w;
L
Linus Torvalds 已提交
1780 1781
	int iter = 0;

1782 1783
	/* Set fn->leaf to null_entry for root node. */
	if (fn->fn_flags & RTN_TL_ROOT) {
D
David Ahern 已提交
1784
		rcu_assign_pointer(fn->leaf, net->ipv6.fib6_null_entry);
1785 1786 1787
		return fn;
	}

L
Linus Torvalds 已提交
1788
	for (;;) {
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798
		struct fib6_node *fn_r = rcu_dereference_protected(fn->right,
					    lockdep_is_held(&table->tb6_lock));
		struct fib6_node *fn_l = rcu_dereference_protected(fn->left,
					    lockdep_is_held(&table->tb6_lock));
		struct fib6_node *pn = rcu_dereference_protected(fn->parent,
					    lockdep_is_held(&table->tb6_lock));
		struct fib6_node *pn_r = rcu_dereference_protected(pn->right,
					    lockdep_is_held(&table->tb6_lock));
		struct fib6_node *pn_l = rcu_dereference_protected(pn->left,
					    lockdep_is_held(&table->tb6_lock));
1799
		struct fib6_info *fn_leaf = rcu_dereference_protected(fn->leaf,
1800
					    lockdep_is_held(&table->tb6_lock));
1801
		struct fib6_info *pn_leaf = rcu_dereference_protected(pn->leaf,
1802
					    lockdep_is_held(&table->tb6_lock));
1803
		struct fib6_info *new_fn_leaf;
1804

L
Linus Torvalds 已提交
1805 1806 1807
		RT6_TRACE("fixing tree: plen=%d iter=%d\n", fn->fn_bit, iter);
		iter++;

1808 1809
		WARN_ON(fn->fn_flags & RTN_RTINFO);
		WARN_ON(fn->fn_flags & RTN_TL_ROOT);
1810
		WARN_ON(fn_leaf);
L
Linus Torvalds 已提交
1811 1812 1813

		children = 0;
		child = NULL;
1814 1815 1816 1817
		if (fn_r)
			child = fn_r, children |= 1;
		if (fn_l)
			child = fn_l, children |= 2;
L
Linus Torvalds 已提交
1818

1819
		if (children == 3 || FIB6_SUBTREE(fn)
L
Linus Torvalds 已提交
1820 1821
#ifdef CONFIG_IPV6_SUBTREES
		    /* Subtree root (i.e. fn) may have one child */
1822
		    || (children && fn->fn_flags & RTN_ROOT)
L
Linus Torvalds 已提交
1823 1824
#endif
		    ) {
1825
			new_fn_leaf = fib6_find_prefix(net, table, fn);
L
Linus Torvalds 已提交
1826
#if RT6_DEBUG >= 2
1827 1828
			if (!new_fn_leaf) {
				WARN_ON(!new_fn_leaf);
D
David Ahern 已提交
1829
				new_fn_leaf = net->ipv6.fib6_null_entry;
L
Linus Torvalds 已提交
1830 1831
			}
#endif
1832
			fib6_info_hold(new_fn_leaf);
1833 1834
			rcu_assign_pointer(fn->leaf, new_fn_leaf);
			return pn;
L
Linus Torvalds 已提交
1835 1836 1837
		}

#ifdef CONFIG_IPV6_SUBTREES
1838
		if (FIB6_SUBTREE(pn) == fn) {
1839
			WARN_ON(!(fn->fn_flags & RTN_ROOT));
1840
			RCU_INIT_POINTER(pn->subtree, NULL);
L
Linus Torvalds 已提交
1841 1842
			nstate = FWS_L;
		} else {
1843
			WARN_ON(fn->fn_flags & RTN_ROOT);
L
Linus Torvalds 已提交
1844
#endif
1845 1846 1847 1848
			if (pn_r == fn)
				rcu_assign_pointer(pn->right, child);
			else if (pn_l == fn)
				rcu_assign_pointer(pn->left, child);
L
Linus Torvalds 已提交
1849
#if RT6_DEBUG >= 2
1850 1851
			else
				WARN_ON(1);
L
Linus Torvalds 已提交
1852 1853
#endif
			if (child)
1854
				rcu_assign_pointer(child->parent, pn);
L
Linus Torvalds 已提交
1855 1856 1857 1858 1859
			nstate = FWS_R;
#ifdef CONFIG_IPV6_SUBTREES
		}
#endif

M
Michal Kubeček 已提交
1860 1861
		read_lock(&net->ipv6.fib6_walker_lock);
		FOR_WALKERS(net, w) {
1862
			if (!child) {
1863
				if (w->node == fn) {
L
Linus Torvalds 已提交
1864 1865 1866 1867 1868 1869 1870 1871 1872
					RT6_TRACE("W %p adjusted by delnode 1, s=%d/%d\n", w, w->state, nstate);
					w->node = pn;
					w->state = nstate;
				}
			} else {
				if (w->node == fn) {
					w->node = child;
					if (children&2) {
						RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state);
1873
						w->state = w->state >= FWS_R ? FWS_U : FWS_INIT;
L
Linus Torvalds 已提交
1874 1875
					} else {
						RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state);
1876
						w->state = w->state >= FWS_C ? FWS_U : FWS_INIT;
L
Linus Torvalds 已提交
1877 1878 1879 1880
					}
				}
			}
		}
M
Michal Kubeček 已提交
1881
		read_unlock(&net->ipv6.fib6_walker_lock);
L
Linus Torvalds 已提交
1882

W
Wei Wang 已提交
1883
		node_free(net, fn);
1884
		if (pn->fn_flags & RTN_RTINFO || FIB6_SUBTREE(pn))
L
Linus Torvalds 已提交
1885 1886
			return pn;

1887
		RCU_INIT_POINTER(pn->leaf, NULL);
1888
		fib6_info_release(pn_leaf);
L
Linus Torvalds 已提交
1889 1890 1891 1892
		fn = pn;
	}
}

1893
static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
1894
			   struct fib6_info __rcu **rtp, struct nl_info *info)
L
Linus Torvalds 已提交
1895
{
1896
	struct fib6_info *leaf, *replace_rt = NULL;
1897
	struct fib6_walker *w;
1898
	struct fib6_info *rt = rcu_dereference_protected(*rtp,
1899
				    lockdep_is_held(&table->tb6_lock));
1900
	struct net *net = info->nl_net;
1901
	bool notify_del = false;
L
Linus Torvalds 已提交
1902 1903 1904

	RT6_TRACE("fib6_del_route\n");

1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918
	/* If the deleted route is the first in the node and it is not part of
	 * a multipath route, then we need to replace it with the next route
	 * in the node, if exists.
	 */
	leaf = rcu_dereference_protected(fn->leaf,
					 lockdep_is_held(&table->tb6_lock));
	if (leaf == rt && !rt->fib6_nsiblings) {
		if (rcu_access_pointer(rt->fib6_next))
			replace_rt = rcu_dereference_protected(rt->fib6_next,
					    lockdep_is_held(&table->tb6_lock));
		else
			notify_del = true;
	}

L
Linus Torvalds 已提交
1919
	/* Unlink it */
1920
	*rtp = rt->fib6_next;
1921
	rt->fib6_node = NULL;
1922 1923
	net->ipv6.rt6_stats->fib_rt_entries--;
	net->ipv6.rt6_stats->fib_discarded_routes++;
L
Linus Torvalds 已提交
1924

1925 1926 1927
	/* Flush all cached dst in exception table */
	rt6_flush_exceptions(rt);

1928
	/* Reset round-robin state, if necessary */
1929
	if (rcu_access_pointer(fn->rr_ptr) == rt)
1930 1931
		fn->rr_ptr = NULL;

1932
	/* Remove this entry from other siblings */
1933
	if (rt->fib6_nsiblings) {
1934
		struct fib6_info *sibling, *next_sibling;
1935

1936 1937 1938 1939 1940 1941 1942 1943
		/* The route is deleted from a multipath route. If this
		 * multipath route is the first route in the node, then we need
		 * to emit a delete notification. Otherwise, we need to skip
		 * the notification.
		 */
		if (rt->fib6_metric == leaf->fib6_metric &&
		    rt6_qualify_for_ecmp(leaf))
			notify_del = true;
1944
		list_for_each_entry_safe(sibling, next_sibling,
1945 1946 1947 1948
					 &rt->fib6_siblings, fib6_siblings)
			sibling->fib6_nsiblings--;
		rt->fib6_nsiblings = 0;
		list_del_init(&rt->fib6_siblings);
1949
		rt6_multipath_rebalance(next_sibling);
1950 1951
	}

L
Linus Torvalds 已提交
1952
	/* Adjust walkers */
M
Michal Kubeček 已提交
1953 1954
	read_lock(&net->ipv6.fib6_walker_lock);
	FOR_WALKERS(net, w) {
L
Linus Torvalds 已提交
1955 1956
		if (w->state == FWS_C && w->leaf == rt) {
			RT6_TRACE("walker %p adjusted by delroute\n", w);
1957
			w->leaf = rcu_dereference_protected(rt->fib6_next,
1958
					    lockdep_is_held(&table->tb6_lock));
1959
			if (!w->leaf)
L
Linus Torvalds 已提交
1960 1961 1962
				w->state = FWS_U;
		}
	}
M
Michal Kubeček 已提交
1963
	read_unlock(&net->ipv6.fib6_walker_lock);
L
Linus Torvalds 已提交
1964

1965 1966 1967 1968
	/* If it was last route, call fib6_repair_tree() to:
	 * 1. For root node, put back null_entry as how the table was created.
	 * 2. For other nodes, expunge its radix tree node.
	 */
1969
	if (!rcu_access_pointer(fn->leaf)) {
1970 1971 1972 1973
		if (!(fn->fn_flags & RTN_TL_ROOT)) {
			fn->fn_flags &= ~RTN_RTINFO;
			net->ipv6.rt6_stats->fib_route_nodes--;
		}
1974
		fn = fib6_repair_tree(net, table, fn);
L
Linus Torvalds 已提交
1975 1976
	}

1977
	fib6_purge_rt(rt, fn, net);
L
Linus Torvalds 已提交
1978

1979 1980
	if (!info->skip_notify_kernel) {
		if (notify_del)
1981
			call_fib6_entry_notifiers(net, FIB_EVENT_ENTRY_DEL,
1982 1983 1984 1985
						  rt, NULL);
		else if (replace_rt)
			call_fib6_entry_notifiers_replace(net, replace_rt);
	}
1986 1987
	if (!info->skip_notify)
		inet6_rt_notify(RTM_DELROUTE, rt, info, 0);
1988

1989
	fib6_info_release(rt);
L
Linus Torvalds 已提交
1990 1991
}

1992
/* Need to own table->tb6_lock */
1993
int fib6_del(struct fib6_info *rt, struct nl_info *info)
L
Linus Torvalds 已提交
1994
{
1995 1996 1997
	struct fib6_node *fn = rcu_dereference_protected(rt->fib6_node,
				    lockdep_is_held(&rt->fib6_table->tb6_lock));
	struct fib6_table *table = rt->fib6_table;
1998
	struct net *net = info->nl_net;
1999 2000
	struct fib6_info __rcu **rtp;
	struct fib6_info __rcu **rtp_next;
L
Linus Torvalds 已提交
2001

D
David Ahern 已提交
2002
	if (!fn || rt == net->ipv6.fib6_null_entry)
L
Linus Torvalds 已提交
2003 2004
		return -ENOENT;

2005
	WARN_ON(!(fn->fn_flags & RTN_RTINFO));
L
Linus Torvalds 已提交
2006 2007 2008 2009 2010

	/*
	 *	Walk the leaf entries looking for ourself
	 */

2011
	for (rtp = &fn->leaf; *rtp; rtp = rtp_next) {
2012
		struct fib6_info *cur = rcu_dereference_protected(*rtp,
2013 2014
					lockdep_is_held(&table->tb6_lock));
		if (rt == cur) {
P
Paolo Abeni 已提交
2015 2016
			if (fib6_requires_src(cur))
				fib6_routes_require_src_dec(info->nl_net);
2017
			fib6_del_route(table, fn, rtp, info);
L
Linus Torvalds 已提交
2018 2019
			return 0;
		}
2020
		rtp_next = &cur->fib6_next;
L
Linus Torvalds 已提交
2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031
	}
	return -ENOENT;
}

/*
 *	Tree traversal function.
 *
 *	Certainly, it is not interrupt safe.
 *	However, it is internally reenterable wrt itself and fib6_add/fib6_del.
 *	It means, that we can modify tree during walking
 *	and use this function for garbage collection, clone pruning,
2032
 *	cleaning tree when a device goes down etc. etc.
L
Linus Torvalds 已提交
2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046
 *
 *	It guarantees that every node will be traversed,
 *	and that it will be traversed only once.
 *
 *	Callback function w->func may return:
 *	0 -> continue walking.
 *	positive value -> walking is suspended (used by tree dumps,
 *	and probably by gc, if it will be split to several slices)
 *	negative value -> terminate walking.
 *
 *	The function itself returns:
 *	0   -> walk is complete.
 *	>0  -> walk is incomplete (i.e. suspended)
 *	<0  -> walk is terminated by an error.
2047 2048
 *
 *	This function is called with tb6_lock held.
L
Linus Torvalds 已提交
2049 2050
 */

2051
static int fib6_walk_continue(struct fib6_walker *w)
L
Linus Torvalds 已提交
2052
{
2053
	struct fib6_node *fn, *pn, *left, *right;
L
Linus Torvalds 已提交
2054

2055 2056 2057
	/* w->root should always be table->tb6_root */
	WARN_ON_ONCE(!(w->root->fn_flags & RTN_TL_ROOT));

L
Linus Torvalds 已提交
2058 2059
	for (;;) {
		fn = w->node;
2060
		if (!fn)
L
Linus Torvalds 已提交
2061 2062 2063 2064 2065
			return 0;

		switch (w->state) {
#ifdef CONFIG_IPV6_SUBTREES
		case FWS_S:
2066 2067
			if (FIB6_SUBTREE(fn)) {
				w->node = FIB6_SUBTREE(fn);
L
Linus Torvalds 已提交
2068 2069 2070
				continue;
			}
			w->state = FWS_L;
J
Joe Perches 已提交
2071
			fallthrough;
2072
#endif
L
Linus Torvalds 已提交
2073
		case FWS_L:
2074 2075 2076
			left = rcu_dereference_protected(fn->left, 1);
			if (left) {
				w->node = left;
L
Linus Torvalds 已提交
2077 2078 2079 2080
				w->state = FWS_INIT;
				continue;
			}
			w->state = FWS_R;
J
Joe Perches 已提交
2081
			fallthrough;
L
Linus Torvalds 已提交
2082
		case FWS_R:
2083 2084 2085
			right = rcu_dereference_protected(fn->right, 1);
			if (right) {
				w->node = right;
L
Linus Torvalds 已提交
2086 2087 2088 2089
				w->state = FWS_INIT;
				continue;
			}
			w->state = FWS_C;
2090
			w->leaf = rcu_dereference_protected(fn->leaf, 1);
J
Joe Perches 已提交
2091
			fallthrough;
L
Linus Torvalds 已提交
2092
		case FWS_C:
2093
			if (w->leaf && fn->fn_flags & RTN_RTINFO) {
2094 2095
				int err;

E
Eric Dumazet 已提交
2096 2097
				if (w->skip) {
					w->skip--;
2098
					goto skip;
2099 2100 2101
				}

				err = w->func(w);
L
Linus Torvalds 已提交
2102 2103
				if (err)
					return err;
2104 2105

				w->count++;
L
Linus Torvalds 已提交
2106 2107
				continue;
			}
2108
skip:
L
Linus Torvalds 已提交
2109
			w->state = FWS_U;
J
Joe Perches 已提交
2110
			fallthrough;
L
Linus Torvalds 已提交
2111 2112 2113
		case FWS_U:
			if (fn == w->root)
				return 0;
2114 2115 2116
			pn = rcu_dereference_protected(fn->parent, 1);
			left = rcu_dereference_protected(pn->left, 1);
			right = rcu_dereference_protected(pn->right, 1);
L
Linus Torvalds 已提交
2117 2118
			w->node = pn;
#ifdef CONFIG_IPV6_SUBTREES
2119
			if (FIB6_SUBTREE(pn) == fn) {
2120
				WARN_ON(!(fn->fn_flags & RTN_ROOT));
L
Linus Torvalds 已提交
2121 2122 2123 2124
				w->state = FWS_L;
				continue;
			}
#endif
2125
			if (left == fn) {
L
Linus Torvalds 已提交
2126 2127 2128
				w->state = FWS_R;
				continue;
			}
2129
			if (right == fn) {
L
Linus Torvalds 已提交
2130
				w->state = FWS_C;
2131
				w->leaf = rcu_dereference_protected(w->node->leaf, 1);
L
Linus Torvalds 已提交
2132 2133 2134
				continue;
			}
#if RT6_DEBUG >= 2
2135
			WARN_ON(1);
L
Linus Torvalds 已提交
2136 2137 2138 2139 2140
#endif
		}
	}
}

M
Michal Kubeček 已提交
2141
static int fib6_walk(struct net *net, struct fib6_walker *w)
L
Linus Torvalds 已提交
2142 2143 2144 2145 2146 2147
{
	int res;

	w->state = FWS_INIT;
	w->node = w->root;

M
Michal Kubeček 已提交
2148
	fib6_walker_link(net, w);
L
Linus Torvalds 已提交
2149 2150
	res = fib6_walk_continue(w);
	if (res <= 0)
M
Michal Kubeček 已提交
2151
		fib6_walker_unlink(net, w);
L
Linus Torvalds 已提交
2152 2153 2154
	return res;
}

2155
static int fib6_clean_node(struct fib6_walker *w)
L
Linus Torvalds 已提交
2156 2157
{
	int res;
2158
	struct fib6_info *rt;
2159
	struct fib6_cleaner *c = container_of(w, struct fib6_cleaner, w);
2160 2161
	struct nl_info info = {
		.nl_net = c->net,
2162
		.skip_notify = c->skip_notify,
2163
	};
L
Linus Torvalds 已提交
2164

2165 2166 2167 2168 2169 2170 2171 2172 2173 2174
	if (c->sernum != FIB6_NO_SERNUM_CHANGE &&
	    w->node->fn_sernum != c->sernum)
		w->node->fn_sernum = c->sernum;

	if (!c->func) {
		WARN_ON_ONCE(c->sernum == FIB6_NO_SERNUM_CHANGE);
		w->leaf = NULL;
		return 0;
	}

2175
	for_each_fib6_walker_rt(w) {
L
Linus Torvalds 已提交
2176
		res = c->func(rt, c->arg);
2177
		if (res == -1) {
L
Linus Torvalds 已提交
2178
			w->leaf = rt;
2179
			res = fib6_del(rt, &info);
L
Linus Torvalds 已提交
2180 2181
			if (res) {
#if RT6_DEBUG >= 2
2182
				pr_debug("%s: del failed: rt=%p@%p err=%d\n",
W
Wei Wang 已提交
2183
					 __func__, rt,
2184
					 rcu_access_pointer(rt->fib6_node),
W
Wei Wang 已提交
2185
					 res);
L
Linus Torvalds 已提交
2186 2187 2188 2189
#endif
				continue;
			}
			return 0;
2190
		} else if (res == -2) {
2191
			if (WARN_ON(!rt->fib6_nsiblings))
2192
				continue;
2193 2194
			rt = list_last_entry(&rt->fib6_siblings,
					     struct fib6_info, fib6_siblings);
2195
			continue;
L
Linus Torvalds 已提交
2196
		}
2197
		WARN_ON(res != 0);
L
Linus Torvalds 已提交
2198 2199 2200 2201 2202 2203 2204
	}
	w->leaf = rt;
	return 0;
}

/*
 *	Convenient frontend to tree walker.
2205
 *
L
Linus Torvalds 已提交
2206
 *	func is called on each route.
2207 2208
 *		It may return -2 -> skip multipath route.
 *			      -1 -> delete this route.
L
Linus Torvalds 已提交
2209 2210 2211
 *		              0  -> continue walking
 */

2212
static void fib6_clean_tree(struct net *net, struct fib6_node *root,
2213
			    int (*func)(struct fib6_info *, void *arg),
2214
			    int sernum, void *arg, bool skip_notify)
L
Linus Torvalds 已提交
2215
{
2216
	struct fib6_cleaner c;
L
Linus Torvalds 已提交
2217 2218 2219

	c.w.root = root;
	c.w.func = fib6_clean_node;
2220 2221
	c.w.count = 0;
	c.w.skip = 0;
2222
	c.w.skip_in_node = 0;
L
Linus Torvalds 已提交
2223
	c.func = func;
2224
	c.sernum = sernum;
L
Linus Torvalds 已提交
2225
	c.arg = arg;
2226
	c.net = net;
2227
	c.skip_notify = skip_notify;
L
Linus Torvalds 已提交
2228

M
Michal Kubeček 已提交
2229
	fib6_walk(net, &c.w);
L
Linus Torvalds 已提交
2230 2231
}

2232
static void __fib6_clean_all(struct net *net,
2233
			     int (*func)(struct fib6_info *, void *),
2234
			     int sernum, void *arg, bool skip_notify)
T
Thomas Graf 已提交
2235 2236
{
	struct fib6_table *table;
2237
	struct hlist_head *head;
2238
	unsigned int h;
T
Thomas Graf 已提交
2239

2240
	rcu_read_lock();
2241
	for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
2242
		head = &net->ipv6.fib_table_hash[h];
2243
		hlist_for_each_entry_rcu(table, head, tb6_hlist) {
2244
			spin_lock_bh(&table->tb6_lock);
2245
			fib6_clean_tree(net, &table->tb6_root,
2246
					func, sernum, arg, skip_notify);
2247
			spin_unlock_bh(&table->tb6_lock);
T
Thomas Graf 已提交
2248 2249
		}
	}
2250
	rcu_read_unlock();
T
Thomas Graf 已提交
2251 2252
}

2253
void fib6_clean_all(struct net *net, int (*func)(struct fib6_info *, void *),
2254 2255
		    void *arg)
{
2256 2257 2258 2259 2260 2261 2262 2263
	__fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg, false);
}

void fib6_clean_all_skip_notify(struct net *net,
				int (*func)(struct fib6_info *, void *),
				void *arg)
{
	__fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg, true);
2264 2265
}

H
Hannes Frederic Sowa 已提交
2266 2267
static void fib6_flush_trees(struct net *net)
{
2268
	int new_sernum = fib6_new_sernum(net);
H
Hannes Frederic Sowa 已提交
2269

2270
	__fib6_clean_all(net, NULL, new_sernum, NULL, false);
H
Hannes Frederic Sowa 已提交
2271 2272
}

L
Linus Torvalds 已提交
2273 2274 2275 2276
/*
 *	Garbage collection
 */

2277
static int fib6_age(struct fib6_info *rt, void *arg)
L
Linus Torvalds 已提交
2278
{
2279
	struct fib6_gc_args *gc_args = arg;
L
Linus Torvalds 已提交
2280 2281 2282 2283 2284 2285 2286
	unsigned long now = jiffies;

	/*
	 *	check addrconf expiration here.
	 *	Routes are expired even if they are in use.
	 */

2287
	if (rt->fib6_flags & RTF_EXPIRES && rt->expires) {
2288
		if (time_after(now, rt->expires)) {
L
Linus Torvalds 已提交
2289 2290 2291
			RT6_TRACE("expiring %p\n", rt);
			return -1;
		}
2292
		gc_args->more++;
L
Linus Torvalds 已提交
2293 2294
	}

2295 2296 2297 2298 2299 2300
	/*	Also age clones in the exception table.
	 *	Note, that clones are aged out
	 *	only if they are not in use now.
	 */
	rt6_age_exceptions(rt, gc_args, now);

L
Linus Torvalds 已提交
2301 2302 2303
	return 0;
}

2304
void fib6_run_gc(unsigned long expires, struct net *net, bool force)
L
Linus Torvalds 已提交
2305
{
2306
	struct fib6_gc_args gc_args;
2307 2308
	unsigned long now;

2309
	if (force) {
2310 2311
		spin_lock_bh(&net->ipv6.fib6_gc_lock);
	} else if (!spin_trylock_bh(&net->ipv6.fib6_gc_lock)) {
2312 2313
		mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
		return;
L
Linus Torvalds 已提交
2314
	}
2315 2316
	gc_args.timeout = expires ? (int)expires :
			  net->ipv6.sysctl.ip6_rt_gc_interval;
2317
	gc_args.more = 0;
2318

2319
	fib6_clean_all(net, fib6_age, &gc_args);
2320 2321
	now = jiffies;
	net->ipv6.ip6_rt_last_gc = now;
L
Linus Torvalds 已提交
2322 2323

	if (gc_args.more)
S
Stephen Hemminger 已提交
2324
		mod_timer(&net->ipv6.ip6_fib_timer,
2325
			  round_jiffies(now
S
Stephen Hemminger 已提交
2326
					+ net->ipv6.sysctl.ip6_rt_gc_interval));
2327 2328
	else
		del_timer(&net->ipv6.ip6_fib_timer);
2329
	spin_unlock_bh(&net->ipv6.fib6_gc_lock);
L
Linus Torvalds 已提交
2330 2331
}

2332
static void fib6_gc_timer_cb(struct timer_list *t)
2333
{
2334 2335 2336
	struct net *arg = from_timer(arg, t, ipv6.ip6_fib_timer);

	fib6_run_gc(0, arg, true);
2337 2338
}

2339
static int __net_init fib6_net_init(struct net *net)
L
Linus Torvalds 已提交
2340
{
2341
	size_t size = sizeof(struct hlist_head) * FIB6_TABLE_HASHSZ;
2342 2343 2344 2345 2346
	int err;

	err = fib6_notifier_init(net);
	if (err)
		return err;
2347

2348
	spin_lock_init(&net->ipv6.fib6_gc_lock);
M
Michal Kubeček 已提交
2349 2350
	rwlock_init(&net->ipv6.fib6_walker_lock);
	INIT_LIST_HEAD(&net->ipv6.fib6_walkers);
2351
	timer_setup(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, 0);
2352

2353 2354 2355 2356
	net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
	if (!net->ipv6.rt6_stats)
		goto out_timer;

2357 2358 2359 2360
	/* Avoid false sharing : Use at least a full cache line */
	size = max_t(size_t, size, L1_CACHE_BYTES);

	net->ipv6.fib_table_hash = kzalloc(size, GFP_KERNEL);
2361
	if (!net->ipv6.fib_table_hash)
2362
		goto out_rt6_stats;
2363

2364 2365 2366
	net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
					  GFP_KERNEL);
	if (!net->ipv6.fib6_main_tbl)
2367 2368
		goto out_fib_table_hash;

2369
	net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
2370
	rcu_assign_pointer(net->ipv6.fib6_main_tbl->tb6_root.leaf,
D
David Ahern 已提交
2371
			   net->ipv6.fib6_null_entry);
2372 2373
	net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
		RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
2374
	inet_peer_base_init(&net->ipv6.fib6_main_tbl->tb6_peers);
2375 2376

#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2377 2378 2379
	net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl),
					   GFP_KERNEL);
	if (!net->ipv6.fib6_local_tbl)
2380
		goto out_fib6_main_tbl;
2381
	net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
2382
	rcu_assign_pointer(net->ipv6.fib6_local_tbl->tb6_root.leaf,
D
David Ahern 已提交
2383
			   net->ipv6.fib6_null_entry);
2384 2385
	net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
		RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
2386
	inet_peer_base_init(&net->ipv6.fib6_local_tbl->tb6_peers);
2387
#endif
2388
	fib6_tables_init(net);
2389

2390
	return 0;
2391

2392 2393
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
out_fib6_main_tbl:
2394
	kfree(net->ipv6.fib6_main_tbl);
2395 2396
#endif
out_fib_table_hash:
2397
	kfree(net->ipv6.fib_table_hash);
2398 2399
out_rt6_stats:
	kfree(net->ipv6.rt6_stats);
2400
out_timer:
2401
	fib6_notifier_exit(net);
2402
	return -ENOMEM;
2403
}
2404 2405 2406

static void fib6_net_exit(struct net *net)
{
2407 2408
	unsigned int i;

2409 2410
	del_timer_sync(&net->ipv6.ip6_fib_timer);

E
Eric Dumazet 已提交
2411
	for (i = 0; i < FIB6_TABLE_HASHSZ; i++) {
2412 2413 2414 2415 2416 2417 2418 2419 2420 2421
		struct hlist_head *head = &net->ipv6.fib_table_hash[i];
		struct hlist_node *tmp;
		struct fib6_table *tb;

		hlist_for_each_entry_safe(tb, tmp, head, tb6_hlist) {
			hlist_del(&tb->tb6_hlist);
			fib6_free_table(tb);
		}
	}

2422
	kfree(net->ipv6.fib_table_hash);
2423
	kfree(net->ipv6.rt6_stats);
2424
	fib6_notifier_exit(net);
2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
}

static struct pernet_operations fib6_net_ops = {
	.init = fib6_net_init,
	.exit = fib6_net_exit,
};

int __init fib6_init(void)
{
	int ret = -ENOMEM;
2435

2436 2437 2438 2439 2440 2441 2442 2443 2444
	fib6_node_kmem = kmem_cache_create("fib6_nodes",
					   sizeof(struct fib6_node),
					   0, SLAB_HWCACHE_ALIGN,
					   NULL);
	if (!fib6_node_kmem)
		goto out;

	ret = register_pernet_subsys(&fib6_net_ops);
	if (ret)
2445
		goto out_kmem_cache_create;
2446

2447 2448
	ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE, NULL,
				   inet6_dump_fib, 0);
2449 2450
	if (ret)
		goto out_unregister_subsys;
H
Hannes Frederic Sowa 已提交
2451 2452

	__fib6_flush_trees = fib6_flush_trees;
2453 2454 2455
out:
	return ret;

2456 2457
out_unregister_subsys:
	unregister_pernet_subsys(&fib6_net_ops);
2458 2459 2460
out_kmem_cache_create:
	kmem_cache_destroy(fib6_node_kmem);
	goto out;
L
Linus Torvalds 已提交
2461 2462 2463 2464
}

void fib6_gc_cleanup(void)
{
2465
	unregister_pernet_subsys(&fib6_net_ops);
L
Linus Torvalds 已提交
2466 2467
	kmem_cache_destroy(fib6_node_kmem);
}
2468 2469 2470 2471

#ifdef CONFIG_PROC_FS
static int ipv6_route_seq_show(struct seq_file *seq, void *v)
{
2472
	struct fib6_info *rt = v;
2473
	struct ipv6_route_iter *iter = seq->private;
2474
	struct fib6_nh *fib6_nh = rt->fib6_nh;
2475
	unsigned int flags = rt->fib6_flags;
2476
	const struct net_device *dev;
2477

2478 2479 2480
	if (rt->nh)
		fib6_nh = nexthop_fib6_nh(rt->nh);

2481
	seq_printf(seq, "%pi6 %02x ", &rt->fib6_dst.addr, rt->fib6_dst.plen);
2482 2483

#ifdef CONFIG_IPV6_SUBTREES
2484
	seq_printf(seq, "%pi6 %02x ", &rt->fib6_src.addr, rt->fib6_src.plen);
2485 2486 2487
#else
	seq_puts(seq, "00000000000000000000000000000000 00 ");
#endif
2488
	if (fib6_nh->fib_nh_gw_family) {
2489
		flags |= RTF_GATEWAY;
2490
		seq_printf(seq, "%pi6", &fib6_nh->fib_nh_gw6);
2491
	} else {
2492
		seq_puts(seq, "00000000000000000000000000000000");
2493
	}
2494

2495
	dev = fib6_nh->fib_nh_dev;
2496
	seq_printf(seq, " %08x %08x %08x %08x %8s\n",
2497
		   rt->fib6_metric, refcount_read(&rt->fib6_ref), 0,
2498
		   flags, dev ? dev->name : "");
2499 2500 2501 2502
	iter->w.leaf = NULL;
	return 0;
}

2503
static int ipv6_route_yield(struct fib6_walker *w)
2504 2505 2506 2507 2508 2509 2510
{
	struct ipv6_route_iter *iter = w->args;

	if (!iter->skip)
		return 1;

	do {
2511
		iter->w.leaf = rcu_dereference_protected(
2512
				iter->w.leaf->fib6_next,
2513
				lockdep_is_held(&iter->tbl->tb6_lock));
2514 2515 2516 2517 2518 2519 2520 2521
		iter->skip--;
		if (!iter->skip && iter->w.leaf)
			return 1;
	} while (iter->w.leaf);

	return 0;
}

M
Michal Kubeček 已提交
2522 2523
static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter,
				      struct net *net)
2524 2525 2526 2527 2528 2529 2530
{
	memset(&iter->w, 0, sizeof(iter->w));
	iter->w.func = ipv6_route_yield;
	iter->w.root = &iter->tbl->tb6_root;
	iter->w.state = FWS_INIT;
	iter->w.node = iter->w.root;
	iter->w.args = iter;
2531
	iter->sernum = iter->w.root->fn_sernum;
2532
	INIT_LIST_HEAD(&iter->w.lh);
M
Michal Kubeček 已提交
2533
	fib6_walker_link(net, &iter->w);
2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556
}

static struct fib6_table *ipv6_route_seq_next_table(struct fib6_table *tbl,
						    struct net *net)
{
	unsigned int h;
	struct hlist_node *node;

	if (tbl) {
		h = (tbl->tb6_id & (FIB6_TABLE_HASHSZ - 1)) + 1;
		node = rcu_dereference_bh(hlist_next_rcu(&tbl->tb6_hlist));
	} else {
		h = 0;
		node = NULL;
	}

	while (!node && h < FIB6_TABLE_HASHSZ) {
		node = rcu_dereference_bh(
			hlist_first_rcu(&net->ipv6.fib_table_hash[h++]));
	}
	return hlist_entry_safe(node, struct fib6_table, tb6_hlist);
}

2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567
static void ipv6_route_check_sernum(struct ipv6_route_iter *iter)
{
	if (iter->sernum != iter->w.root->fn_sernum) {
		iter->sernum = iter->w.root->fn_sernum;
		iter->w.state = FWS_INIT;
		iter->w.node = iter->w.root;
		WARN_ON(iter->w.skip);
		iter->w.skip = iter->w.count;
	}
}

2568 2569 2570
static void *ipv6_route_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
	int r;
2571
	struct fib6_info *n;
2572 2573 2574
	struct net *net = seq_file_net(seq);
	struct ipv6_route_iter *iter = seq->private;

2575
	++(*pos);
2576 2577 2578
	if (!v)
		goto iter_table;

2579
	n = rcu_dereference_bh(((struct fib6_info *)v)->fib6_next);
2580
	if (n)
2581 2582 2583
		return n;

iter_table:
2584
	ipv6_route_check_sernum(iter);
2585
	spin_lock_bh(&iter->tbl->tb6_lock);
2586
	r = fib6_walk_continue(&iter->w);
2587
	spin_unlock_bh(&iter->tbl->tb6_lock);
2588 2589 2590
	if (r > 0) {
		return iter->w.leaf;
	} else if (r < 0) {
M
Michal Kubeček 已提交
2591
		fib6_walker_unlink(net, &iter->w);
2592 2593
		return NULL;
	}
M
Michal Kubeček 已提交
2594
	fib6_walker_unlink(net, &iter->w);
2595 2596 2597 2598 2599

	iter->tbl = ipv6_route_seq_next_table(iter->tbl, net);
	if (!iter->tbl)
		return NULL;

M
Michal Kubeček 已提交
2600
	ipv6_route_seq_setup_walk(iter, net);
2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614
	goto iter_table;
}

static void *ipv6_route_seq_start(struct seq_file *seq, loff_t *pos)
	__acquires(RCU_BH)
{
	struct net *net = seq_file_net(seq);
	struct ipv6_route_iter *iter = seq->private;

	rcu_read_lock_bh();
	iter->tbl = ipv6_route_seq_next_table(NULL, net);
	iter->skip = *pos;

	if (iter->tbl) {
M
Michal Kubeček 已提交
2615
		ipv6_route_seq_setup_walk(iter, net);
2616 2617 2618 2619 2620 2621 2622 2623
		return ipv6_route_seq_next(seq, NULL, pos);
	} else {
		return NULL;
	}
}

static bool ipv6_route_iter_active(struct ipv6_route_iter *iter)
{
2624
	struct fib6_walker *w = &iter->w;
2625 2626 2627 2628 2629 2630
	return w->node && !(w->state == FWS_U && w->node == w->root);
}

static void ipv6_route_seq_stop(struct seq_file *seq, void *v)
	__releases(RCU_BH)
{
M
Michal Kubeček 已提交
2631
	struct net *net = seq_file_net(seq);
2632 2633 2634
	struct ipv6_route_iter *iter = seq->private;

	if (ipv6_route_iter_active(iter))
M
Michal Kubeček 已提交
2635
		fib6_walker_unlink(net, &iter->w);
2636 2637 2638 2639

	rcu_read_unlock_bh();
}

2640
const struct seq_operations ipv6_route_seq_ops = {
2641 2642 2643 2644 2645 2646
	.start	= ipv6_route_seq_start,
	.next	= ipv6_route_seq_next,
	.stop	= ipv6_route_seq_stop,
	.show	= ipv6_route_seq_show
};
#endif /* CONFIG_PROC_FS */