fib_trie.c revision 058bd4d2a4ff0aaa4a5381c67e776729d840c785
119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson/* 219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * This program is free software; you can redistribute it and/or 319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * modify it under the terms of the GNU General Public License 419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * as published by the Free Software Foundation; either version 519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 2 of the License, or (at your option) any later version. 619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Robert Olsson <robert.olsson@its.uu.se> Uppsala Universitet 819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * & Swedish University of Agricultural Sciences. 919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 10e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki * Jens Laas <jens.laas@data.slu.se> Swedish University of 1119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Agricultural Sciences. 12e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki * 1319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Hans Liss <hans.liss@its.uu.se> Uppsala Universitet 1419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 1525985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * This work is based on the LPC-trie which is originally described in: 16e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki * 1719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * An experimental study of compression methods for dynamic tries 1819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. 19631dd1a885b6d7e9f6f51b4e5b311c2bb04c323cJustin P. Mattock * http://www.csc.kth.se/~snilsson/software/dyntrie2/ 2019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 2119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 2219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson 2319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999 2419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 2519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 2619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Code from fib_hash has been reused which includes the following header: 2719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 2819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 2919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * INET An implementation of the TCP/IP protocol suite for the LINUX 3019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * operating system. INET is implemented using the BSD Socket 3119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * interface as the means of communication with the user level. 3219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 3319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * IPv4 FIB: lookup engine and maintenance routines. 3419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 3519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 3619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 3719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 3819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * This program is free software; you can redistribute it and/or 3919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * modify it under the terms of the GNU General Public License 4019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * as published by the Free Software Foundation; either version 4119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 2 of the License, or (at your option) any later version. 42fd9662555cc35f8bf9242cd7bba8b44ae168a68bRobert Olsson * 43fd9662555cc35f8bf9242cd7bba8b44ae168a68bRobert Olsson * Substantial contributions to this work comes from: 44fd9662555cc35f8bf9242cd7bba8b44ae168a68bRobert Olsson * 45fd9662555cc35f8bf9242cd7bba8b44ae168a68bRobert Olsson * David S. Miller, <davem@davemloft.net> 46fd9662555cc35f8bf9242cd7bba8b44ae168a68bRobert Olsson * Stephen Hemminger <shemminger@osdl.org> 47fd9662555cc35f8bf9242cd7bba8b44ae168a68bRobert Olsson * Paul E. McKenney <paulmck@us.ibm.com> 48fd9662555cc35f8bf9242cd7bba8b44ae168a68bRobert Olsson * Patrick McHardy <kaber@trash.net> 4919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 5019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 5180b71b80df14d885f7e50e115c1348398f418759Jens Låås#define VERSION "0.409" 5219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 5319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <asm/uaccess.h> 5419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <asm/system.h> 551977f032722c27ee3730284582fd3991ad9ac81bJiri Slaby#include <linux/bitops.h> 5619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/types.h> 5719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/kernel.h> 5819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/mm.h> 5919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/string.h> 6019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/socket.h> 6119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/sockios.h> 6219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/errno.h> 6319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/in.h> 6419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/inet.h> 65cd8787ab04d23f925f440b712b43a6fd5cb31eceStephen Hemminger#include <linux/inetdevice.h> 6619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/netdevice.h> 6719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/if_arp.h> 6819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/proc_fs.h> 692373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson#include <linux/rcupdate.h> 7019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/skbuff.h> 7119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/netlink.h> 7219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/init.h> 7319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <linux/list.h> 745a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 7570c71606190e9115e5f8363bfcd164c582eb314aPaul Gortmaker#include <linux/prefetch.h> 76bc3b2d7fb9b014d75ebb79ba371a763dbab5e8cfPaul Gortmaker#include <linux/export.h> 77457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h> 7819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/ip.h> 7919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/protocol.h> 8019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/route.h> 8119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/tcp.h> 8219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/sock.h> 8319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/ip_fib.h> 8419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include "fib_lookup.h" 8519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8606ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson#define MAX_STAT_DEPTH 32 8719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#define KEYLENGTH (8*sizeof(t_key)) 8919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 9019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssontypedef unsigned int t_key; 9119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 9219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#define T_TNODE 0 9319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#define T_LEAF 1 9419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#define NODE_TYPE_MASK 0x1UL 952373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson#define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK) 962373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 9791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson#define IS_TNODE(n) (!(n->parent & T_LEAF)) 9891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson#define IS_LEAF(n) (n->parent & T_LEAF) 9919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 100b299e4f001cfa16205f9121f4630970049652268David S. Millerstruct rt_trie_node { 10191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson unsigned long parent; 1028d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet t_key key; 10319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 10419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 10519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct leaf { 10691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson unsigned long parent; 1078d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet t_key key; 10819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_head list; 1092373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct rcu_head rcu; 11019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 11119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 11219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct leaf_info { 11319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_node hlist; 11419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int plen; 1155c74501f76360ce6f410730b9b5e5976f38e8504Eric Dumazet u32 mask_plen; /* ntohl(inet_make_mask(plen)) */ 11619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct list_head falh; 1175c74501f76360ce6f410730b9b5e5976f38e8504Eric Dumazet struct rcu_head rcu; 11819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 11919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 12019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct tnode { 12191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson unsigned long parent; 1228d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet t_key key; 123112d8cfcbf4f5ef0cf669cb5864f1206972076d6Eric Dumazet unsigned char pos; /* 2log(KEYLENGTH) bits needed */ 124112d8cfcbf4f5ef0cf669cb5864f1206972076d6Eric Dumazet unsigned char bits; /* 2log(KEYLENGTH) bits needed */ 1258d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet unsigned int full_children; /* KEYLENGTH bits needed */ 1268d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet unsigned int empty_children; /* KEYLENGTH bits needed */ 12715be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger union { 12815be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger struct rcu_head rcu; 12915be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger struct work_struct work; 130e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski struct tnode *tnode_free; 13115be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger }; 1320a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet struct rt_trie_node __rcu *child[0]; 13319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 13419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 13519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 13619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct trie_use_stats { 13719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int gets; 13819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int backtrack; 13919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int semantic_match_passed; 14019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int semantic_match_miss; 14119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int null_node_hit; 1422f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson unsigned int resize_node_skipped; 14319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 14419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 14519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 14619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct trie_stat { 14719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int totdepth; 14819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int maxdepth; 14919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int tnodes; 15019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int leaves; 15119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int nullpointers; 152936722922f6d2366378de606a40c14f96915474dStephen Hemminger unsigned int prefixes; 15306ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson unsigned int nodesizes[MAX_STAT_DEPTH]; 154c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger}; 15519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 15619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct trie { 1570a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet struct rt_trie_node __rcu *trie; 15819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 15919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie_use_stats stats; 16019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 16119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 16219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 163b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic void put_child(struct trie *t, struct tnode *tn, int i, struct rt_trie_node *n); 164b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n, 165a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger int wasfull); 166b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic struct rt_trie_node *resize(struct trie *t, struct tnode *tn); 1672f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonstatic struct tnode *inflate(struct trie *t, struct tnode *tn); 1682f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonstatic struct tnode *halve(struct trie *t, struct tnode *tn); 169e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski/* tnodes to free after resize(); protected by RTNL */ 170e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawskistatic struct tnode *tnode_free_head; 171c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawskistatic size_t tnode_free_size; 172c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski 173c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski/* 174c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski * synchronize_rcu after call_rcu for that many pages; it should be especially 175c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski * useful before resizing the root node with PREEMPT_NONE configs; the value was 176c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski * obtained experimentally, aiming to avoid visible slowdown. 177c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski */ 178c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawskistatic const int sync_pages = 128; 17919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 180e18b890bb0881bbab6f4f1a6cd20d9c60d66b003Christoph Lameterstatic struct kmem_cache *fn_alias_kmem __read_mostly; 181bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemmingerstatic struct kmem_cache *trie_leaf_kmem __read_mostly; 18219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1830a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet/* 1840a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet * caller must hold RTNL 1850a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet */ 1860a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazetstatic inline struct tnode *node_parent(const struct rt_trie_node *node) 1870680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger{ 1880a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet unsigned long parent; 1890a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet 1900a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held()); 1910a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet 1920a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet return (struct tnode *)(parent & ~NODE_TYPE_MASK); 193b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet} 194b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet 1950a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet/* 1960a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet * caller must hold RCU read lock or RTNL 1970a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet */ 1980a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazetstatic inline struct tnode *node_parent_rcu(const struct rt_trie_node *node) 199b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet{ 2000a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet unsigned long parent; 2010a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet 2020a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() || 2030a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet lockdep_rtnl_is_held()); 2040680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger 2050a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet return (struct tnode *)(parent & ~NODE_TYPE_MASK); 2060680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger} 2070680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger 208cf778b00e96df6d64f8e21b8395d1f8a859ecdc7Eric Dumazet/* Same as rcu_assign_pointer 2096440cc9e0f48ade57af7be28008cbfa6a991f287Stephen Hemminger * but that macro() assumes that value is a pointer. 2106440cc9e0f48ade57af7be28008cbfa6a991f287Stephen Hemminger */ 211b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr) 2120680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger{ 2136440cc9e0f48ade57af7be28008cbfa6a991f287Stephen Hemminger smp_wmb(); 2146440cc9e0f48ade57af7be28008cbfa6a991f287Stephen Hemminger node->parent = (unsigned long)ptr | NODE_TYPE(node); 2150680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger} 2162373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 2170a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet/* 2180a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet * caller must hold RTNL 2190a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet */ 2200a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazetstatic inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i) 221b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet{ 222b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet BUG_ON(i >= 1U << tn->bits); 2232373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 2240a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet return rtnl_dereference(tn->child[i]); 225b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet} 226b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet 2270a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet/* 2280a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet * caller must hold RCU read lock or RTNL 2290a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet */ 2300a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazetstatic inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i) 23119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2320a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet BUG_ON(i >= 1U << tn->bits); 23319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2340a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet return rcu_dereference_rtnl(tn->child[i]); 23519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 23619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 237bb435b8d816582064ee0ddb1e2a6fbca67f34108Stephen Hemmingerstatic inline int tnode_child_length(const struct tnode *tn) 23819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 23991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return 1 << tn->bits; 24019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 24119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2423b004569d86d02786ebae496e75dc0b625be3e9aDavid S. Millerstatic inline t_key mask_pfx(t_key k, unsigned int l) 243ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger{ 244ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l); 245ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger} 246ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger 2473b004569d86d02786ebae496e75dc0b625be3e9aDavid S. Millerstatic inline t_key tkey_extract_bits(t_key a, unsigned int offset, unsigned int bits) 24819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 24991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (offset < KEYLENGTH) 25019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return ((t_key)(a << offset)) >> (KEYLENGTH - bits); 25191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson else 25219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 25319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 25419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 25519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic inline int tkey_equals(t_key a, t_key b) 25619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 257c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger return a == b; 25819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 25919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 26019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b) 26119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 262c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (bits == 0 || offset >= KEYLENGTH) 263c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger return 1; 26491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson bits = bits > KEYLENGTH ? KEYLENGTH : bits; 26591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0; 266c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger} 26719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 26819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic inline int tkey_mismatch(t_key a, int offset, t_key b) 26919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 27019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t_key diff = a ^ b; 27119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i = offset; 27219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 273c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!diff) 274c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger return 0; 275c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger while ((diff << i) >> (KEYLENGTH-1) == 0) 27619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson i++; 27719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return i; 27819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 27919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 28019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson/* 281e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki To understand this stuff, an understanding of keys and all their bits is 282e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki necessary. Every node in the trie has a key associated with it, but not 28319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson all of the bits in that key are significant. 28419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 28519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson Consider a node 'n' and its parent 'tp'. 28619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 287e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki If n is a leaf, every bit in its key is significant. Its presence is 288e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki necessitated by path compression, since during a tree traversal (when 289e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki searching for a leaf - unless we are doing an insertion) we will completely 290e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki ignore all skipped bits we encounter. Thus we need to verify, at the end of 291e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki a potentially successful search, that we have indeed been walking the 29219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson correct key path. 29319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 294e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki Note that we can never "miss" the correct key in the tree if present by 295e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki following the wrong path. Path compression ensures that segments of the key 296e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki that are the same for all keys with a given prefix are skipped, but the 297e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki skipped part *is* identical for each node in the subtrie below the skipped 298e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki bit! trie_insert() in this implementation takes care of that - note the 29919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson call to tkey_sub_equals() in trie_insert(). 30019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 301e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if n is an internal node - a 'tnode' here, the various parts of its key 30219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson have many different meanings. 30319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 304e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki Example: 30519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson _________________________________________________________________ 30619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C | 30719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson ----------------------------------------------------------------- 308e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 30919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 31019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson _________________________________________________________________ 31119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u | 31219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson ----------------------------------------------------------------- 31319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 31419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 31519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tp->pos = 7 31619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tp->bits = 3 31719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson n->pos = 15 31891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson n->bits = 4 31919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 320e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki First, let's just ignore the bits that come before the parent tp, that is 321e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki the bits from 0 to (tp->pos-1). They are *known* but at this point we do 32219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson not use them for anything. 32319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 32419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the 325e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki index into the parent's child array. That is, they will be used to find 32619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 'n' among tp's children. 32719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 32819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits 32919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson for the node n. 33019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 331e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki All the bits we have seen so far are significant to the node n. The rest 33219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson of the bits are really not needed or indeed known in n->key. 33319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 334e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into 33519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson n's child array, and will of course be different for each child. 336e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 337c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 33819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson The rest of the bits, from (n->pos + n->bits) onward, are completely unknown 33919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson at this point. 34019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 34119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson*/ 34219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 3430c7770c740156c8802c23d24fc094d06967d997dStephen Hemmingerstatic inline void check_tnode(const struct tnode *tn) 34419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 3450c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger WARN_ON(tn && tn->pos+tn->bits > 32); 34619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 34719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 348f5026fabda54e5ab5d469d8cfac5f46b4d321ce9Denis V. Lunevstatic const int halve_threshold = 25; 349f5026fabda54e5ab5d469d8cfac5f46b4d321ce9Denis V. Lunevstatic const int inflate_threshold = 50; 350345aa031207d02d7438c1aa96ed9315911ecd745Jarek Poplawskistatic const int halve_threshold_root = 15; 35180b71b80df14d885f7e50e115c1348398f418759Jens Lååsstatic const int inflate_threshold_root = 30; 3522373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 3532373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic void __alias_free_mem(struct rcu_head *head) 35419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 3552373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct fib_alias *fa = container_of(head, struct fib_alias, rcu); 3562373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson kmem_cache_free(fn_alias_kmem, fa); 35719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 35819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 3592373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic inline void alias_free_mem_rcu(struct fib_alias *fa) 36019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 3612373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson call_rcu(&fa->rcu, __alias_free_mem); 3622373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 36391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 3642373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic void __leaf_free_rcu(struct rcu_head *head) 3652373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson{ 366bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger struct leaf *l = container_of(head, struct leaf, rcu); 367bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger kmem_cache_free(trie_leaf_kmem, l); 3682373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 36991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 370387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemmingerstatic inline void free_leaf(struct leaf *l) 371387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger{ 372387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger call_rcu_bh(&l->rcu, __leaf_free_rcu); 373387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger} 374387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger 3752373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic inline void free_leaf_info(struct leaf_info *leaf) 37619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 377bceb0f4512d448763fe98c9f37504c98bbebbed6Lai Jiangshan kfree_rcu(leaf, rcu); 37819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 37919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 3808d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazetstatic struct tnode *tnode_alloc(size_t size) 381f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy{ 3822373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (size <= PAGE_SIZE) 3838d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet return kzalloc(size, GFP_KERNEL); 38415be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger else 3857a1c8e5ab120a5f352e78bbc1fa5bb64e6f23639Eric Dumazet return vzalloc(size); 38615be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger} 3872373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 38815be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemmingerstatic void __tnode_vfree(struct work_struct *arg) 38915be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger{ 39015be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger struct tnode *tn = container_of(arg, struct tnode, work); 39115be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger vfree(tn); 392f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy} 393f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy 3942373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic void __tnode_free_rcu(struct rcu_head *head) 395f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy{ 3962373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct tnode *tn = container_of(head, struct tnode, rcu); 3978d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet size_t size = sizeof(struct tnode) + 398b299e4f001cfa16205f9121f4630970049652268David S. Miller (sizeof(struct rt_trie_node *) << tn->bits); 399f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy 400f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy if (size <= PAGE_SIZE) 401f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy kfree(tn); 40215be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger else { 40315be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger INIT_WORK(&tn->work, __tnode_vfree); 40415be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger schedule_work(&tn->work); 40515be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger } 406f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy} 407f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy 4082373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic inline void tnode_free(struct tnode *tn) 4092373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson{ 410387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger if (IS_LEAF(tn)) 411387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger free_leaf((struct leaf *) tn); 412387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger else 413550e29bc96e6f1ced2bca82dace197b009434367Robert Olsson call_rcu(&tn->rcu, __tnode_free_rcu); 4142373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 4152373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 416e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawskistatic void tnode_free_safe(struct tnode *tn) 417e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski{ 418e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski BUG_ON(IS_LEAF(tn)); 4197b85576d15bf2574b0a451108f59f9ad4170dd3fJarek Poplawski tn->tnode_free = tnode_free_head; 4207b85576d15bf2574b0a451108f59f9ad4170dd3fJarek Poplawski tnode_free_head = tn; 421c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski tnode_free_size += sizeof(struct tnode) + 422b299e4f001cfa16205f9121f4630970049652268David S. Miller (sizeof(struct rt_trie_node *) << tn->bits); 423e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski} 424e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski 425e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawskistatic void tnode_free_flush(void) 426e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski{ 427e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski struct tnode *tn; 428e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski 429e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski while ((tn = tnode_free_head)) { 430e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tnode_free_head = tn->tnode_free; 431e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tn->tnode_free = NULL; 432e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tnode_free(tn); 433e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski } 434c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski 435c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski if (tnode_free_size >= PAGE_SIZE * sync_pages) { 436c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski tnode_free_size = 0; 437c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski synchronize_rcu(); 438c3059477fce2d956a0bb3e04357324780c5d8eebJarek Poplawski } 439e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski} 440e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski 4412373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic struct leaf *leaf_new(void) 4422373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson{ 443bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); 4442373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (l) { 4452373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson l->parent = T_LEAF; 4462373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson INIT_HLIST_HEAD(&l->list); 4472373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson } 4482373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson return l; 4492373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 4502373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 4512373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic struct leaf_info *leaf_info_new(int plen) 4522373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson{ 4532373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct leaf_info *li = kmalloc(sizeof(struct leaf_info), GFP_KERNEL); 4542373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (li) { 4552373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson li->plen = plen; 4565c74501f76360ce6f410730b9b5e5976f38e8504Eric Dumazet li->mask_plen = ntohl(inet_make_mask(plen)); 4572373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson INIT_LIST_HEAD(&li->falh); 4582373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson } 4592373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson return li; 4602373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 4612373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 462a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic struct tnode *tnode_new(t_key key, int pos, int bits) 46319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 464b299e4f001cfa16205f9121f4630970049652268David S. Miller size_t sz = sizeof(struct tnode) + (sizeof(struct rt_trie_node *) << bits); 465f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy struct tnode *tn = tnode_alloc(sz); 46619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 46791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (tn) { 4682373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson tn->parent = T_TNODE; 46919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->pos = pos; 47019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->bits = bits; 47119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->key = key; 47219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->full_children = 0; 47319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->empty_children = 1<<bits; 47419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 475c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 476a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode), 477b299e4f001cfa16205f9121f4630970049652268David S. Miller sizeof(struct rt_trie_node) << bits); 47819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return tn; 47919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 48019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 48119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson/* 48219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Check whether a tnode 'n' is "full", i.e. it is an internal node 48319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * and no bits are skipped. See discussion in dyntree paper p. 6 48419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 48519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 486b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic inline int tnode_full(const struct tnode *tn, const struct rt_trie_node *n) 48719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 488c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (n == NULL || IS_LEAF(n)) 48919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 49019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 49119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return ((struct tnode *) n)->pos == tn->pos + tn->bits; 49219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 49319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 494a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic inline void put_child(struct trie *t, struct tnode *tn, int i, 495b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n) 49619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 49719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tnode_put_child_reorg(tn, i, n, -1); 49819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 49919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 500c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger /* 50119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Add a child at position i overwriting the old value. 50219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Update the value of full_children and empty_children. 50319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 50419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 505b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n, 506a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger int wasfull) 50719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 5080a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet struct rt_trie_node *chi = rtnl_dereference(tn->child[i]); 50919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int isfull; 51019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 5110c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger BUG_ON(i >= 1<<tn->bits); 5120c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 51319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* update emptyChildren */ 51419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (n == NULL && chi != NULL) 51519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->empty_children++; 51619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson else if (n != NULL && chi == NULL) 51719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->empty_children--; 518c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 51919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* update fullChildren */ 52091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (wasfull == -1) 52119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson wasfull = tnode_full(tn, chi); 52219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 52319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson isfull = tnode_full(tn, n); 524c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (wasfull && !isfull) 52519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->full_children--; 526c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger else if (!wasfull && isfull) 52719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->full_children++; 52891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 529c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (n) 5300680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger node_set_parent(n, tn); 53119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 532cf778b00e96df6d64f8e21b8395d1f8a859ecdc7Eric Dumazet rcu_assign_pointer(tn->child[i], n); 53319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 53419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 53580b71b80df14d885f7e50e115c1348398f418759Jens Låås#define MAX_WORK 10 536b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic struct rt_trie_node *resize(struct trie *t, struct tnode *tn) 53719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 53819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i; 5392f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson struct tnode *old_tn; 540e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson int inflate_threshold_use; 541e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson int halve_threshold_use; 54280b71b80df14d885f7e50e115c1348398f418759Jens Låås int max_work; 54319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 544e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (!tn) 54519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 54619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 5470c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n", 5480c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger tn, inflate_threshold, halve_threshold); 54919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 55019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* No children */ 55119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (tn->empty_children == tnode_child_length(tn)) { 552e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tnode_free_safe(tn); 55319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 55419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 55519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* One child */ 55619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (tn->empty_children == tnode_child_length(tn) - 1) 55780b71b80df14d885f7e50e115c1348398f418759Jens Låås goto one_child; 558c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger /* 55919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Double as long as the resulting node has a number of 56019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * nonempty nodes that are above the threshold. 56119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 56219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 56319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 564c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * From "Implementing a dynamic compressed trie" by Stefan Nilsson of 565c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * the Helsinki University of Technology and Matti Tikkanen of Nokia 56619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Telecommunications, page 6: 567c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * "A node is doubled if the ratio of non-empty children to all 56819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * children in the *doubled* node is at least 'high'." 56919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 570c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 'high' in this instance is the variable 'inflate_threshold'. It 571c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * is expressed as a percentage, so we multiply it with 572c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * tnode_child_length() and instead of multiplying by 2 (since the 573c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * child array will be doubled by inflate()) and multiplying 574c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * the left-hand side by 100 (to handle the percentage thing) we 57519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * multiply the left-hand side by 50. 576c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 577c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * The left-hand side may look a bit weird: tnode_child_length(tn) 578c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * - tn->empty_children is of course the number of non-null children 579c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * in the current node. tn->full_children is the number of "full" 58019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * children, that is non-null tnodes with a skip value of 0. 581c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * All of those will be doubled in the resulting inflated tnode, so 58219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * we just count them one extra time here. 583c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 58419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * A clearer way to write this would be: 585c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 58619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * to_be_doubled = tn->full_children; 587c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children - 58819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * tn->full_children; 58919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 59019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * new_child_length = tnode_child_length(tn) * 2; 59119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 592c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) / 59319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * new_child_length; 59419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * if (new_fill_factor >= inflate_threshold) 595c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 596c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * ...and so on, tho it would mess up the while () loop. 597c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 59819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * anyway, 59919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >= 60019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * inflate_threshold 601c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 60219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * avoid a division: 60319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 100 * (not_to_be_doubled + 2*to_be_doubled) >= 60419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * inflate_threshold * new_child_length 605c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 60619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * expand not_to_be_doubled and to_be_doubled, and shorten: 607c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 100 * (tnode_child_length(tn) - tn->empty_children + 60891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tn->full_children) >= inflate_threshold * new_child_length 609c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 61019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * expand new_child_length: 611c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 100 * (tnode_child_length(tn) - tn->empty_children + 61291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tn->full_children) >= 61319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * inflate_threshold * tnode_child_length(tn) * 2 614c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 61519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * shorten again: 616c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 50 * (tn->full_children + tnode_child_length(tn) - 61791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tn->empty_children) >= inflate_threshold * 61819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * tnode_child_length(tn) 619c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 62019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 62119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 62219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson check_tnode(tn); 623c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 624e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson /* Keep root node larger */ 625e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson 626b299e4f001cfa16205f9121f4630970049652268David S. Miller if (!node_parent((struct rt_trie_node *)tn)) { 62780b71b80df14d885f7e50e115c1348398f418759Jens Låås inflate_threshold_use = inflate_threshold_root; 62880b71b80df14d885f7e50e115c1348398f418759Jens Låås halve_threshold_use = halve_threshold_root; 629a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet } else { 630e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson inflate_threshold_use = inflate_threshold; 63180b71b80df14d885f7e50e115c1348398f418759Jens Låås halve_threshold_use = halve_threshold; 63280b71b80df14d885f7e50e115c1348398f418759Jens Låås } 633e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson 63480b71b80df14d885f7e50e115c1348398f418759Jens Låås max_work = MAX_WORK; 63580b71b80df14d885f7e50e115c1348398f418759Jens Låås while ((tn->full_children > 0 && max_work-- && 636a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 50 * (tn->full_children + tnode_child_length(tn) 637a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger - tn->empty_children) 638a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger >= inflate_threshold_use * tnode_child_length(tn))) { 63919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 6402f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson old_tn = tn; 6412f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tn = inflate(t, tn); 642a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 6432f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (IS_ERR(tn)) { 6442f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tn = old_tn; 6452f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 6462f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson t->stats.resize_node_skipped++; 6472f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson#endif 6482f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson break; 6492f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 65019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 65119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 65219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson check_tnode(tn); 65319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 65480b71b80df14d885f7e50e115c1348398f418759Jens Låås /* Return if at least one inflate is run */ 655a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet if (max_work != MAX_WORK) 656b299e4f001cfa16205f9121f4630970049652268David S. Miller return (struct rt_trie_node *) tn; 65780b71b80df14d885f7e50e115c1348398f418759Jens Låås 65819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 65919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Halve as long as the number of empty children in this 66019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * node is above threshold. 66119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 6622f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 66380b71b80df14d885f7e50e115c1348398f418759Jens Låås max_work = MAX_WORK; 66480b71b80df14d885f7e50e115c1348398f418759Jens Låås while (tn->bits > 1 && max_work-- && 66519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 100 * (tnode_child_length(tn) - tn->empty_children) < 666e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson halve_threshold_use * tnode_child_length(tn)) { 6672f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 6682f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson old_tn = tn; 6692f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tn = halve(t, tn); 6702f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (IS_ERR(tn)) { 6712f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tn = old_tn; 6722f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 6732f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson t->stats.resize_node_skipped++; 6742f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson#endif 6752f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson break; 6762f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 6772f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 67819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 679c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 68019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Only one child remains */ 68180b71b80df14d885f7e50e115c1348398f418759Jens Låås if (tn->empty_children == tnode_child_length(tn) - 1) { 68280b71b80df14d885f7e50e115c1348398f418759Jens Lååsone_child: 68319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson for (i = 0; i < tnode_child_length(tn); i++) { 684b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n; 68519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 6860a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet n = rtnl_dereference(tn->child[i]); 6872373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (!n) 68891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 68991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 69091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* compress one level */ 69191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 6920680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger node_set_parent(n, NULL); 693e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tnode_free_safe(tn); 69491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return n; 69519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 69680b71b80df14d885f7e50e115c1348398f418759Jens Låås } 697b299e4f001cfa16205f9121f4630970049652268David S. Miller return (struct rt_trie_node *) tn; 69819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 69919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 7000a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet 7010a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazetstatic void tnode_clean_free(struct tnode *tn) 7020a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet{ 7030a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet int i; 7040a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet struct tnode *tofree; 7050a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet 7060a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet for (i = 0; i < tnode_child_length(tn); i++) { 7070a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet tofree = (struct tnode *)rtnl_dereference(tn->child[i]); 7080a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet if (tofree) 7090a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet tnode_free(tofree); 7100a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet } 7110a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet tnode_free(tn); 7120a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet} 7130a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet 7142f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonstatic struct tnode *inflate(struct trie *t, struct tnode *tn) 71519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 71619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *oldtnode = tn; 71719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int olen = tnode_child_length(tn); 71819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i; 71919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 7200c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("In inflate\n"); 72119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 72219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1); 72319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 7240c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger if (!tn) 7252f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson return ERR_PTR(-ENOMEM); 7262f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 7272f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson /* 728c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * Preallocate and store tnodes before the actual work so we 729c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * don't get into an inconsistent state if memory allocation 730c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * fails. In case of failure we return the oldnode and inflate 7312f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson * of tnode is ignored. 7322f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson */ 73391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 73491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (i = 0; i < olen; i++) { 735a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger struct tnode *inode; 7362f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 737a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger inode = (struct tnode *) tnode_get_child(oldtnode, i); 7382f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson if (inode && 7392f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson IS_TNODE(inode) && 7402f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson inode->pos == oldtnode->pos + oldtnode->bits && 7412f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson inode->bits > 1) { 7422f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson struct tnode *left, *right; 743ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos; 744c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 7452f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson left = tnode_new(inode->key&(~m), inode->pos + 1, 7462f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson inode->bits - 1); 7472f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (!left) 7482f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson goto nomem; 74991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 7502f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson right = tnode_new(inode->key|m, inode->pos + 1, 7512f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson inode->bits - 1); 7522f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 753e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (!right) { 7542f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tnode_free(left); 7552f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson goto nomem; 756e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki } 7572f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 758b299e4f001cfa16205f9121f4630970049652268David S. Miller put_child(t, tn, 2*i, (struct rt_trie_node *) left); 759b299e4f001cfa16205f9121f4630970049652268David S. Miller put_child(t, tn, 2*i+1, (struct rt_trie_node *) right); 7602f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 7612f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 7622f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 76391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (i = 0; i < olen; i++) { 764c95aaf9af5a1f6dee56d1f2ab4915cd722d608daStephen Hemminger struct tnode *inode; 765b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *node = tnode_get_child(oldtnode, i); 76691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct tnode *left, *right; 76791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson int size, j; 768c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 76919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* An empty child */ 77019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (node == NULL) 77119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 77219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 77319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* A leaf or an internal node with skipped bits */ 77419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 775c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (IS_LEAF(node) || ((struct tnode *) node)->pos > 77619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->pos + tn->bits - 1) { 777a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger if (tkey_extract_bits(node->key, 778a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger oldtnode->pos + oldtnode->bits, 779a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 1) == 0) 78019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, 2*i, node); 78119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson else 78219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, 2*i+1, node); 78319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 78419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 78519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 78619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* An internal node with two children */ 78719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson inode = (struct tnode *) node; 78819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 78919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (inode->bits == 1) { 7900a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet put_child(t, tn, 2*i, rtnl_dereference(inode->child[0])); 7910a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet put_child(t, tn, 2*i+1, rtnl_dereference(inode->child[1])); 79219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 793e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tnode_free_safe(inode); 79491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 79519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 79619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 79791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* An internal node with more than two children */ 79891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 79991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* We will replace this node 'inode' with two new 80091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * ones, 'left' and 'right', each with half of the 80191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * original children. The two new nodes will have 80291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * a position one bit further down the key and this 80391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * means that the "significant" part of their keys 80491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * (see the discussion near the top of this file) 80591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * will differ by one bit, which will be "0" in 80691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * left's key and "1" in right's key. Since we are 80791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * moving the key position by one step, the bit that 80891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * we are moving away from - the bit at position 80991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * (inode->pos) - is the one that will differ between 81091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * left and right. So... we synthesize that bit in the 81191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * two new keys. 81291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * The mask 'm' below will be a single "one" bit at 81391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * the position (inode->pos) 81491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 81519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 81691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* Use the old key, but set the new significant 81791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * bit to zero. 81891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 8192f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 82091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson left = (struct tnode *) tnode_get_child(tn, 2*i); 82191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, 2*i, NULL); 8222f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 82391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson BUG_ON(!left); 8242f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 82591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson right = (struct tnode *) tnode_get_child(tn, 2*i+1); 82691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, 2*i+1, NULL); 82719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 82891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson BUG_ON(!right); 82919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 83091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson size = tnode_child_length(left); 83191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (j = 0; j < size; j++) { 8320a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet put_child(t, left, j, rtnl_dereference(inode->child[j])); 8330a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet put_child(t, right, j, rtnl_dereference(inode->child[j + size])); 83419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 83591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, 2*i, resize(t, left)); 83691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, 2*i+1, resize(t, right)); 83791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 838e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tnode_free_safe(inode); 83919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 840e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tnode_free_safe(oldtnode); 84119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return tn; 8422f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonnomem: 8430a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet tnode_clean_free(tn); 8440a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet return ERR_PTR(-ENOMEM); 84519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 84619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8472f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonstatic struct tnode *halve(struct trie *t, struct tnode *tn) 84819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 84919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *oldtnode = tn; 850b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *left, *right; 85119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i; 85219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int olen = tnode_child_length(tn); 85319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8540c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("In halve\n"); 855c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 856c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1); 85719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8582f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (!tn) 8592f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson return ERR_PTR(-ENOMEM); 8602f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 8612f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson /* 862c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * Preallocate and store tnodes before the actual work so we 863c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * don't get into an inconsistent state if memory allocation 864c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * fails. In case of failure we return the oldnode and halve 8652f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson * of tnode is ignored. 8662f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson */ 8672f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 86891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (i = 0; i < olen; i += 2) { 8692f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson left = tnode_get_child(oldtnode, i); 8702f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson right = tnode_get_child(oldtnode, i+1); 871c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 8722f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson /* Two nonempty children */ 8730c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger if (left && right) { 8742f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson struct tnode *newn; 8750c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 8762f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson newn = tnode_new(left->key, tn->pos + tn->bits, 1); 8770c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 8780c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger if (!newn) 8792f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson goto nomem; 8800c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 881b299e4f001cfa16205f9121f4630970049652268David S. Miller put_child(t, tn, i/2, (struct rt_trie_node *)newn); 8822f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 8832f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 8842f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 88519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 88691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (i = 0; i < olen; i += 2) { 88791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct tnode *newBinNode; 88891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 88919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson left = tnode_get_child(oldtnode, i); 89019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson right = tnode_get_child(oldtnode, i+1); 891c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 89219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* At least one of the children is empty */ 89319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (left == NULL) { 89419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (right == NULL) /* Both are empty */ 89519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 89619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, i/2, right); 89791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 8980c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger } 89991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 90091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (right == NULL) { 90119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, i/2, left); 90291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 90391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 904c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 90519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Two nonempty children */ 90691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson newBinNode = (struct tnode *) tnode_get_child(tn, i/2); 90791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, i/2, NULL); 90891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, newBinNode, 0, left); 90991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, newBinNode, 1, right); 91091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, i/2, resize(t, newBinNode)); 91119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 912e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tnode_free_safe(oldtnode); 91319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return tn; 9142f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonnomem: 9150a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet tnode_clean_free(tn); 9160a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet return ERR_PTR(-ENOMEM); 91719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 91819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 919772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson/* readside must use rcu_read_lock currently dump routines 9202373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson via get_fa_head and dump */ 9212373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 922772cb712b1373d335ef2874ea357ec681edc754bRobert Olssonstatic struct leaf_info *find_leaf_info(struct leaf *l, int plen) 92319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 924772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson struct hlist_head *head = &l->list; 92519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_node *node; 92619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf_info *li; 92719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 9282373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson hlist_for_each_entry_rcu(li, node, head, hlist) 929c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (li->plen == plen) 93019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return li; 93191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 93219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 93319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 93419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 935a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic inline struct list_head *get_fa_head(struct leaf *l, int plen) 93619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 937772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson struct leaf_info *li = find_leaf_info(l, plen); 938c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 93991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (!li) 94091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return NULL; 941c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 94291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return &li->falh; 94319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 94419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 94519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic void insert_leaf_info(struct hlist_head *head, struct leaf_info *new) 94619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 947e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki struct leaf_info *li = NULL, *last = NULL; 948e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki struct hlist_node *node; 949e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 950e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (hlist_empty(head)) { 951e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki hlist_add_head_rcu(&new->hlist, head); 952e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki } else { 953e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki hlist_for_each_entry(li, node, head, hlist) { 954e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (new->plen > li->plen) 955e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki break; 956e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 957e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki last = li; 958e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki } 959e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (last) 960e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki hlist_add_after_rcu(&last->hlist, &new->hlist); 961e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki else 962e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki hlist_add_before_rcu(&new->hlist, &li->hlist); 963e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki } 96419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 96519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 9662373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson/* rcu_read_lock needs to be hold by caller from readside */ 9672373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 96819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic struct leaf * 96919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonfib_find_node(struct trie *t, u32 key) 97019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 97119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int pos; 97219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *tn; 973b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n; 97419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 97519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson pos = 0; 976a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet n = rcu_dereference_rtnl(t->trie); 97719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 97819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson while (n != NULL && NODE_TYPE(n) == T_TNODE) { 97919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn = (struct tnode *) n; 98091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 98119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson check_tnode(tn); 98291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 983c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { 98491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pos = tn->pos + tn->bits; 985a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger n = tnode_get_child_rcu(tn, 986a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tkey_extract_bits(key, 987a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn->pos, 988a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn->bits)); 98991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else 99019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 99119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 99219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Case we have found a leaf. Compare prefixes */ 99319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 99491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) 99591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return (struct leaf *)n; 99691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 99719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 99819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 99919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 10007b85576d15bf2574b0a451108f59f9ad4170dd3fJarek Poplawskistatic void trie_rebalance(struct trie *t, struct tnode *tn) 100119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 100219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int wasfull; 10033ed18d76d959e5cbfa5d70c8f7ba95476582a556Robert Olsson t_key cindex, key; 10040680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger struct tnode *tp; 100519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 10063ed18d76d959e5cbfa5d70c8f7ba95476582a556Robert Olsson key = tn->key; 10073ed18d76d959e5cbfa5d70c8f7ba95476582a556Robert Olsson 1008b299e4f001cfa16205f9121f4630970049652268David S. Miller while (tn != NULL && (tp = node_parent((struct rt_trie_node *)tn)) != NULL) { 100919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson cindex = tkey_extract_bits(key, tp->pos, tp->bits); 101019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); 1011a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn = (struct tnode *) resize(t, (struct tnode *)tn); 1012a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 1013a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tnode_put_child_reorg((struct tnode *)tp, cindex, 1014b299e4f001cfa16205f9121f4630970049652268David S. Miller (struct rt_trie_node *)tn, wasfull); 101591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1016b299e4f001cfa16205f9121f4630970049652268David S. Miller tp = node_parent((struct rt_trie_node *) tn); 1017008440e3ad4b72f5048d1b1f6f5ed894fdc5ad08Jarek Poplawski if (!tp) 1018cf778b00e96df6d64f8e21b8395d1f8a859ecdc7Eric Dumazet rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); 1019008440e3ad4b72f5048d1b1f6f5ed894fdc5ad08Jarek Poplawski 1020e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799fJarek Poplawski tnode_free_flush(); 10210680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger if (!tp) 102219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 10230680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger tn = tp; 102419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 10250680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger 102619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Handle last (top) tnode */ 10277b85576d15bf2574b0a451108f59f9ad4170dd3fJarek Poplawski if (IS_TNODE(tn)) 1028a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn = (struct tnode *)resize(t, (struct tnode *)tn); 102919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1030cf778b00e96df6d64f8e21b8395d1f8a859ecdc7Eric Dumazet rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); 10317b85576d15bf2574b0a451108f59f9ad4170dd3fJarek Poplawski tnode_free_flush(); 103219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 103319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 10342373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson/* only used from updater-side */ 10352373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 1036fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemmingerstatic struct list_head *fib_insert_node(struct trie *t, u32 key, int plen) 103719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 103819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int pos, newpos; 103919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *tp = NULL, *tn = NULL; 1040b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n; 104119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf *l; 104219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int missbit; 1043c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger struct list_head *fa_head = NULL; 104419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf_info *li; 104519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t_key cindex; 104619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 104719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson pos = 0; 10480a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet n = rtnl_dereference(t->trie); 104919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1050c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger /* If we point to NULL, stop. Either the tree is empty and we should 1051c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * just put a new leaf in if, or we have reached an empty child slot, 105219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * and we should just put our new leaf in that. 1053c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * If we point to a T_TNODE, check if it matches our key. Note that 1054c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * a T_TNODE might be skipping any number of bits - its 'pos' need 105519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * not be the parent's 'pos'+'bits'! 105619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 1057c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * If it does match the current key, get pos/bits from it, extract 105819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * the index from our key, push the T_TNODE and walk the tree. 105919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 106019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * If it doesn't, we have to replace it with a new T_TNODE. 106119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 1062c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * If we point to a T_LEAF, it might or might not have the same key 1063c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * as we do. If it does, just change the value, update the T_LEAF's 1064c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * value, and return it. 106519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * If it doesn't, we need to replace it with a T_TNODE. 106619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 106719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 106819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson while (n != NULL && NODE_TYPE(n) == T_TNODE) { 106919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn = (struct tnode *) n; 107091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1071c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger check_tnode(tn); 107291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1073c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { 107419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tp = tn; 107591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pos = tn->pos + tn->bits; 1076a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger n = tnode_get_child(tn, 1077a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tkey_extract_bits(key, 1078a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn->pos, 1079a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn->bits)); 108019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 10810680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger BUG_ON(n && node_parent(n) != tn); 108291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else 108319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 108419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 108519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 108619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 108719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * n ----> NULL, LEAF or TNODE 108819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 1089c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * tp is n's (parent) ----> NULL or TNODE 109019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 109119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 109291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson BUG_ON(tp && IS_LEAF(tp)); 109319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 109419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Case 1: n is a leaf. Compare prefixes */ 109519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1096c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) { 1097c95aaf9af5a1f6dee56d1f2ab4915cd722d608daStephen Hemminger l = (struct leaf *) n; 109819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson li = leaf_info_new(plen); 109991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1100fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger if (!li) 1101fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger return NULL; 110219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 110319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_head = &li->falh; 110419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson insert_leaf_info(&l->list, li); 110519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto done; 110619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 110719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson l = leaf_new(); 110819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1109fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger if (!l) 1110fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger return NULL; 111119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 111219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson l->key = key; 111319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson li = leaf_info_new(plen); 111419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1115c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!li) { 1116387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger free_leaf(l); 1117fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger return NULL; 1118f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson } 111919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 112019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_head = &li->falh; 112119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson insert_leaf_info(&l->list, li); 112219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 112319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (t->trie && n == NULL) { 112491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* Case 2: n is NULL, and will just insert a new leaf */ 112519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1126b299e4f001cfa16205f9121f4630970049652268David S. Miller node_set_parent((struct rt_trie_node *)l, tp); 112719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 112891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson cindex = tkey_extract_bits(key, tp->pos, tp->bits); 1129b299e4f001cfa16205f9121f4630970049652268David S. Miller put_child(t, (struct tnode *)tp, cindex, (struct rt_trie_node *)l); 113091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else { 113191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */ 1132c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger /* 1133c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * Add a new tnode here 113419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * first tnode need some special handling 113519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 113619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 113719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (tp) 113891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pos = tp->pos+tp->bits; 113919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson else 114091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pos = 0; 114191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1142c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (n) { 114319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson newpos = tkey_mismatch(key, pos, n->key); 114419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn = tnode_new(n->key, newpos, 1); 114591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else { 114619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson newpos = 0; 1147c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger tn = tnode_new(key, newpos, 1); /* First tnode */ 114819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 114919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1150c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!tn) { 1151f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson free_leaf_info(li); 1152387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger free_leaf(l); 1153fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger return NULL; 115491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 115591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1156b299e4f001cfa16205f9121f4630970049652268David S. Miller node_set_parent((struct rt_trie_node *)tn, tp); 115719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 115891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson missbit = tkey_extract_bits(key, newpos, 1); 1159b299e4f001cfa16205f9121f4630970049652268David S. Miller put_child(t, tn, missbit, (struct rt_trie_node *)l); 116019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, 1-missbit, n); 116119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1162c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (tp) { 116319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson cindex = tkey_extract_bits(key, tp->pos, tp->bits); 1164a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger put_child(t, (struct tnode *)tp, cindex, 1165b299e4f001cfa16205f9121f4630970049652268David S. Miller (struct rt_trie_node *)tn); 116691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else { 1167cf778b00e96df6d64f8e21b8395d1f8a859ecdc7Eric Dumazet rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); 116819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tp = tn; 116919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 117019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 117191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 117291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (tp && tp->pos + tp->bits > 32) 1173058bd4d2a4ff0aaa4a5381c67e776729d840c785Joe Perches pr_warn("fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n", 1174058bd4d2a4ff0aaa4a5381c67e776729d840c785Joe Perches tp, tp->pos, tp->bits, key, plen); 117591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 117619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Rebalance the trie */ 11772373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 11787b85576d15bf2574b0a451108f59f9ad4170dd3fJarek Poplawski trie_rebalance(t, tp); 1179f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olssondone: 118019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return fa_head; 118119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 118219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1183d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson/* 1184d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson * Caller must hold RTNL. 1185d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson */ 118616c6cf8bb471392fd09b48b7c27e7d83a446b4bcStephen Hemmingerint fib_table_insert(struct fib_table *tb, struct fib_config *cfg) 118719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 118819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 118919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_alias *fa, *new_fa; 1190c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger struct list_head *fa_head = NULL; 119119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *fi; 11924e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf int plen = cfg->fc_dst_len; 11934e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf u8 tos = cfg->fc_tos; 119419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson u32 key, mask; 119519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int err; 119619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf *l; 119719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 119819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (plen > 32) 119919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -EINVAL; 120019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 12014e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf key = ntohl(cfg->fc_dst); 120219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 12032dfe55b47e3d66ded5a84caf71e0da5710edf48bPatrick McHardy pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); 120419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 120591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson mask = ntohl(inet_make_mask(plen)); 120619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1207c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (key & ~mask) 120819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -EINVAL; 120919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 121019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson key = key & mask; 121119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 12124e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf fi = fib_create_info(cfg); 12134e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (IS_ERR(fi)) { 12144e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf err = PTR_ERR(fi); 121519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto err; 12164e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf } 121719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 121819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson l = fib_find_node(t, key); 1219c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger fa = NULL; 122019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1221c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (l) { 122219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_head = get_fa_head(l, plen); 122319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa = fib_find_alias(fa_head, tos, fi->fib_priority); 122419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 122519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 122619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Now fa, if non-NULL, points to the first fib alias 122719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * with the same keys [prefix,tos,priority], if such key already 122819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * exists or to the node before which we will insert new one. 122919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 123019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * If fa is NULL, we will need to allocate a new one and 123119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * insert to the head of f. 123219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 123319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * If f is NULL, no fib node matched the destination key 123419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * and we need to allocate a new one of those as well. 123519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 123619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1237936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa && fa->fa_tos == tos && 1238936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa->fa_info->fib_priority == fi->fib_priority) { 1239936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov struct fib_alias *fa_first, *fa_match; 124019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 124119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson err = -EEXIST; 12424e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (cfg->fc_nlflags & NLM_F_EXCL) 124319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 124419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1245936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov /* We have 2 goals: 1246936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov * 1. Find exact match for type, scope, fib_info to avoid 1247936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov * duplicate routes 1248936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it 1249936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov */ 1250936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa_match = NULL; 1251936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa_first = fa; 1252936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); 1253936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov list_for_each_entry_continue(fa, fa_head, fa_list) { 1254936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa->fa_tos != tos) 1255936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov break; 1256936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa->fa_info->fib_priority != fi->fib_priority) 1257936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov break; 1258936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa->fa_type == cfg->fc_type && 1259936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa->fa_info == fi) { 1260936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa_match = fa; 1261936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov break; 1262936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov } 1263936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov } 1264936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov 12654e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (cfg->fc_nlflags & NLM_F_REPLACE) { 126619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *fi_drop; 126719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson u8 state; 126819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1269936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa = fa_first; 1270936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa_match) { 1271936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa == fa_match) 1272936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov err = 0; 12736725033fa27c8f49e1221d2badbaaaf1ef459519Joonwoo Park goto out; 1274936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov } 12752373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson err = -ENOBUFS; 1276e94b1766097d53e6f3ccfb36c8baa562ffeda3fcChristoph Lameter new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); 12772373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (new_fa == NULL) 12782373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson goto out; 127919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 128019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fi_drop = fa->fa_info; 12812373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson new_fa->fa_tos = fa->fa_tos; 12822373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson new_fa->fa_info = fi; 12834e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf new_fa->fa_type = cfg->fc_type; 128419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson state = fa->fa_state; 1285936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov new_fa->fa_state = state & ~FA_S_ACCESSED; 128619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 12872373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_replace_rcu(&fa->fa_list, &new_fa->fa_list); 12882373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson alias_free_mem_rcu(fa); 128919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 129019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fib_release_info(fi_drop); 129119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (state & FA_S_ACCESSED) 129276e6ebfb40a2455c18234dcb0f9df37533215461Denis V. Lunev rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); 1293b8f558313506b5bc435f2e031f3bec4b1725098eMilan Kocian rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, 1294b8f558313506b5bc435f2e031f3bec4b1725098eMilan Kocian tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE); 129519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 129691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson goto succeeded; 129719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 129819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Error if we find a perfect match which 129919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * uses the same scope, type, and nexthop 130019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * information. 130119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 1302936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa_match) 1303936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov goto out; 1304a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 13054e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (!(cfg->fc_nlflags & NLM_F_APPEND)) 1306936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa = fa_first; 130719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 130819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson err = -ENOENT; 13094e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (!(cfg->fc_nlflags & NLM_F_CREATE)) 131019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 131119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 131219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson err = -ENOBUFS; 1313e94b1766097d53e6f3ccfb36c8baa562ffeda3fcChristoph Lameter new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); 131419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (new_fa == NULL) 131519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 131619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 131719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson new_fa->fa_info = fi; 131819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson new_fa->fa_tos = tos; 13194e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf new_fa->fa_type = cfg->fc_type; 132019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson new_fa->fa_state = 0; 132119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 132219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Insert new entry to the list. 132319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 132419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1325c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!fa_head) { 1326fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger fa_head = fib_insert_node(t, key, plen); 1327fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger if (unlikely(!fa_head)) { 1328fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger err = -ENOMEM; 1329f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson goto out_free_new_fa; 1330fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger } 1331f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson } 133219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 133321d8c49e01a0c1c6eb6c750cd04110db4a539284David S. Miller if (!plen) 133421d8c49e01a0c1c6eb6c750cd04110db4a539284David S. Miller tb->tb_num_default++; 133521d8c49e01a0c1c6eb6c750cd04110db4a539284David S. Miller 13362373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_add_tail_rcu(&new_fa->fa_list, 13372373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson (fa ? &fa->fa_list : fa_head)); 133819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 133976e6ebfb40a2455c18234dcb0f9df37533215461Denis V. Lunev rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); 13404e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, 1341b8f558313506b5bc435f2e031f3bec4b1725098eMilan Kocian &cfg->fc_nlinfo, 0); 134219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonsucceeded: 134319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 1344f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson 1345f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olssonout_free_new_fa: 1346f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson kmem_cache_free(fn_alias_kmem, new_fa); 134719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonout: 134819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fib_release_info(fi); 134991b9a277fc4d207249e459a455abf804ebb5499dOlof Johanssonerr: 135019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return err; 135119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 135219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1353772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson/* should be called with rcu_read_lock */ 13545b4704419cbd0b7597a91c19f9e8e8b17c1af071David S. Millerstatic int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l, 135522bd5b9b13f2931ac80949f8bfbc40e8cab05be7David S. Miller t_key key, const struct flowi4 *flp, 1356ebc0ffae5dfb4447e0a431ffe7fe1d467c48bbb9Eric Dumazet struct fib_result *res, int fib_flags) 135719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 135819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf_info *li; 135919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_head *hhead = &l->list; 136019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_node *node; 1361c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 13622373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson hlist_for_each_entry_rcu(li, node, hhead, hlist) { 13633be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller struct fib_alias *fa; 1364a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 13655c74501f76360ce6f410730b9b5e5976f38e8504Eric Dumazet if (l->key != (key & li->mask_plen)) 136619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 136719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 13683be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller list_for_each_entry_rcu(fa, &li->falh, fa_list) { 13693be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller struct fib_info *fi = fa->fa_info; 13703be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller int nhsel, err; 1371a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 137222bd5b9b13f2931ac80949f8bfbc40e8cab05be7David S. Miller if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) 13733be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller continue; 137437e826c513883099c298317bad1b3b677b2905fbDavid S. Miller if (fa->fa_info->fib_scope < flp->flowi4_scope) 13753be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller continue; 13763be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller fib_alias_accessed(fa); 13773be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller err = fib_props[fa->fa_type].error; 13783be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller if (err) { 137919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 13801fbc78439291627642517f15b9b91f3125588143Julian Anastasov t->stats.semantic_match_passed++; 13813be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller#endif 13821fbc78439291627642517f15b9b91f3125588143Julian Anastasov return err; 13833be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller } 13843be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller if (fi->fib_flags & RTNH_F_DEAD) 13853be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller continue; 13863be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { 13873be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller const struct fib_nh *nh = &fi->fib_nh[nhsel]; 13883be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller 13893be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller if (nh->nh_flags & RTNH_F_DEAD) 13903be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller continue; 139122bd5b9b13f2931ac80949f8bfbc40e8cab05be7David S. Miller if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif) 13923be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller continue; 13933be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller 13943be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller#ifdef CONFIG_IP_FIB_TRIE_STATS 13953be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller t->stats.semantic_match_passed++; 13963be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller#endif 13975c74501f76360ce6f410730b9b5e5976f38e8504Eric Dumazet res->prefixlen = li->plen; 13983be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller res->nh_sel = nhsel; 13993be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller res->type = fa->fa_type; 140037e826c513883099c298317bad1b3b677b2905fbDavid S. Miller res->scope = fa->fa_info->fib_scope; 14013be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller res->fi = fi; 14023be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller res->table = tb; 14033be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller res->fa_head = &li->falh; 14043be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller if (!(fib_flags & FIB_LOOKUP_NOREF)) 14055c74501f76360ce6f410730b9b5e5976f38e8504Eric Dumazet atomic_inc(&fi->fib_clntref); 14063be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller return 0; 14073be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller } 14083be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller } 14093be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller 14103be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller#ifdef CONFIG_IP_FIB_TRIE_STATS 14113be0686b6e2f953afe83626e871b4a7b0ceae49bDavid S. Miller t->stats.semantic_match_miss++; 141219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 141319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1414a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 14152e655571c618434c24ac2ca989374fdd84470d6dBen Hutchings return 1; 141619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 141719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 141822bd5b9b13f2931ac80949f8bfbc40e8cab05be7David S. Millerint fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, 1419ebc0ffae5dfb4447e0a431ffe7fe1d467c48bbb9Eric Dumazet struct fib_result *res, int fib_flags) 142019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 142119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 14222e655571c618434c24ac2ca989374fdd84470d6dBen Hutchings int ret; 1423b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n; 142419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *pn; 14253b004569d86d02786ebae496e75dc0b625be3e9aDavid S. Miller unsigned int pos, bits; 142622bd5b9b13f2931ac80949f8bfbc40e8cab05be7David S. Miller t_key key = ntohl(flp->daddr); 14273b004569d86d02786ebae496e75dc0b625be3e9aDavid S. Miller unsigned int chopped_off; 142819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t_key cindex = 0; 14293b004569d86d02786ebae496e75dc0b625be3e9aDavid S. Miller unsigned int current_prefix_length = KEYLENGTH; 143091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct tnode *cn; 1431874ffa8f72444d6253d2669fed304875c128f86bEric Dumazet t_key pref_mismatch; 143291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 14332373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_lock(); 143491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 14352373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson n = rcu_dereference(t->trie); 1436c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!n) 143719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto failed; 143819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 143919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 144019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t->stats.gets++; 144119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 144219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 144319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Just a leaf? */ 144419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (IS_LEAF(n)) { 14455b4704419cbd0b7597a91c19f9e8e8b17c1af071David S. Miller ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags); 1446a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger goto found; 144719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1448a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 144919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson pn = (struct tnode *) n; 145019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson chopped_off = 0; 1451c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 145291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson while (pn) { 145319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson pos = pn->pos; 145419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson bits = pn->bits; 145519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1456c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!chopped_off) 1457ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length), 1458ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger pos, bits); 145919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1460b902e5735272b6a79fe2853180b2ad6658aa9678Jarek Poplawski n = tnode_get_child_rcu(pn, cindex); 146119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 146219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (n == NULL) { 146319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 146419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t->stats.null_node_hit++; 146519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 146619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto backtrace; 146719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 146819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 146991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (IS_LEAF(n)) { 14705b4704419cbd0b7597a91c19f9e8e8b17c1af071David S. Miller ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags); 14712e655571c618434c24ac2ca989374fdd84470d6dBen Hutchings if (ret > 0) 147291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson goto backtrace; 1473a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger goto found; 147491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 147591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 147691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson cn = (struct tnode *)n; 147719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 147891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* 147991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * It's a tnode, and we can do some extra checks here if we 148091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * like, to avoid descending into a dead-end branch. 148191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * This tnode is in the parent's child array at index 148291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * key[p_pos..p_pos+p_bits] but potentially with some bits 148391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * chopped off, so in reality the index may be just a 148491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * subprefix, padded with zero at the end. 148591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * We can also take a look at any skipped bits in this 148691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tnode - everything up to p_pos is supposed to be ok, 148791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * and the non-chopped bits of the index (se previous 148891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * paragraph) are also guaranteed ok, but the rest is 148991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * considered unknown. 149091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * 149191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * The skipped bits are key[pos+bits..cn->pos]. 149291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 149319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 149491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* If current_prefix_length < pos+bits, we are already doing 149591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * actual prefix matching, which means everything from 149691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * pos+(bits-chopped_off) onward must be zero along some 149791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * branch of this subtree - otherwise there is *no* valid 149891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * prefix present. Here we can only check the skipped 149991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * bits. Remember, since we have already indexed into the 150091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * parent's child array, we know that the bits we chopped of 150191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * *are* zero. 150291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 150319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1504a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger /* NOTA BENE: Checking only skipped bits 1505a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger for the new node here */ 150619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 150791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (current_prefix_length < pos+bits) { 150891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (tkey_extract_bits(cn->key, current_prefix_length, 1509a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger cn->pos - current_prefix_length) 1510a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger || !(cn->child[0])) 151191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson goto backtrace; 151291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 151319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 151491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* 151591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * If chopped_off=0, the index is fully validated and we 151691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * only need to look at the skipped bits for this, the new, 151791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tnode. What we actually want to do is to find out if 151891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * these skipped bits match our key perfectly, or if we will 151991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * have to count on finding a matching prefix further down, 152091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * because if we do, we would like to have some way of 152191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * verifying the existence of such a prefix at this point. 152291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 152319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 152491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* The only thing we can do at this point is to verify that 152591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * any such matching prefix can indeed be a prefix to our 152691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * key, and if the bits in the node we are inspecting that 152791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * do not match our key are not ZERO, this cannot be true. 152891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * Thus, find out where there is a mismatch (before cn->pos) 152991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * and verify that all the mismatching bits are zero in the 153091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * new tnode's key. 153191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 153219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1533a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger /* 1534a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * Note: We aren't very concerned about the piece of 1535a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * the key that precede pn->pos+pn->bits, since these 1536a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * have already been checked. The bits after cn->pos 1537a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * aren't checked since these are by definition 1538a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * "unknown" at this point. Thus, what we want to see 1539a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * is if we are about to enter the "prefix matching" 1540a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * state, and in that case verify that the skipped 1541a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * bits that will prevail throughout this subtree are 1542a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * zero, as they have to be if we are to find a 1543a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * matching prefix. 154491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 154591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1546874ffa8f72444d6253d2669fed304875c128f86bEric Dumazet pref_mismatch = mask_pfx(cn->key ^ key, cn->pos); 154791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1548a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger /* 1549a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * In short: If skipped bits in this node do not match 1550a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * the search key, enter the "prefix matching" 1551a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * state.directly. 155291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 155391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (pref_mismatch) { 1554874ffa8f72444d6253d2669fed304875c128f86bEric Dumazet int mp = KEYLENGTH - fls(pref_mismatch); 155591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1556874ffa8f72444d6253d2669fed304875c128f86bEric Dumazet if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0) 155791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson goto backtrace; 155891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 155991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (current_prefix_length >= cn->pos) 156091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson current_prefix_length = mp; 1561c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger } 1562a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 156391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pn = (struct tnode *)n; /* Descend */ 156491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson chopped_off = 0; 156591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 156691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 156719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonbacktrace: 156819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson chopped_off++; 156919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 157019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* As zero don't change the child key (cindex) */ 1571a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger while ((chopped_off <= pn->bits) 1572a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger && !(cindex & (1<<(chopped_off-1)))) 157319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson chopped_off++; 157419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 157519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Decrease current_... with bits chopped off */ 157619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (current_prefix_length > pn->pos + pn->bits - chopped_off) 1577a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger current_prefix_length = pn->pos + pn->bits 1578a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger - chopped_off; 157991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 158019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 1581c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * Either we do the actual chop off according or if we have 158219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * chopped off all bits in this tnode walk up to our parent. 158319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 158419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 158591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (chopped_off <= pn->bits) { 158619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson cindex &= ~(1 << (chopped_off-1)); 158791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else { 1588b299e4f001cfa16205f9121f4630970049652268David S. Miller struct tnode *parent = node_parent_rcu((struct rt_trie_node *) pn); 15890680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger if (!parent) 159019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto failed; 159191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 159219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Get Child's index */ 15930680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits); 15940680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger pn = parent; 159519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson chopped_off = 0; 159619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 159719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 159819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t->stats.backtrack++; 159919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 160019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto backtrace; 1601c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger } 160219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 160319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonfailed: 1604c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger ret = 1; 160519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonfound: 16062373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_unlock(); 160719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return ret; 160819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 16096fc01438a94702bd160cb1b89203d9b97ae68cedFlorian WestphalEXPORT_SYMBOL_GPL(fib_table_lookup); 161019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16119195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger/* 16129195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger * Remove the leaf and return parent. 16139195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger */ 16149195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemmingerstatic void trie_leaf_remove(struct trie *t, struct leaf *l) 161519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 1616b299e4f001cfa16205f9121f4630970049652268David S. Miller struct tnode *tp = node_parent((struct rt_trie_node *) l); 1617c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 16189195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger pr_debug("entering trie_leaf_remove(%p)\n", l); 161919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1620c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (tp) { 16219195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits); 162219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, (struct tnode *)tp, cindex, NULL); 16237b85576d15bf2574b0a451108f59f9ad4170dd3fJarek Poplawski trie_rebalance(t, tp); 162491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else 1625a9b3cd7f323b2e57593e7215362a7b02fc933e3aStephen Hemminger RCU_INIT_POINTER(t->trie, NULL); 162619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1627387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger free_leaf(l); 162819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 162919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1630d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson/* 1631d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson * Caller must hold RTNL. 1632d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson */ 163316c6cf8bb471392fd09b48b7c27e7d83a446b4bcStephen Hemmingerint fib_table_delete(struct fib_table *tb, struct fib_config *cfg) 163419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 163519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 163619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson u32 key, mask; 16374e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf int plen = cfg->fc_dst_len; 16384e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf u8 tos = cfg->fc_tos; 163919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_alias *fa, *fa_to_delete; 164019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct list_head *fa_head; 164119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf *l; 164291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct leaf_info *li; 164391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1644c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (plen > 32) 164519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -EINVAL; 164619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16474e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf key = ntohl(cfg->fc_dst); 164891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson mask = ntohl(inet_make_mask(plen)); 164919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1650c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (key & ~mask) 165119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -EINVAL; 165219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 165319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson key = key & mask; 165419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson l = fib_find_node(t, key); 165519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1656c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!l) 165719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -ESRCH; 165819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 165919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_head = get_fa_head(l, plen); 166019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa = fib_find_alias(fa_head, tos, 0); 166119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 166219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (!fa) 166319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -ESRCH; 166419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16650c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t); 166619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 166719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_to_delete = NULL; 1668936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); 1669936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov list_for_each_entry_continue(fa, fa_head, fa_list) { 167019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *fi = fa->fa_info; 167119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 167219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (fa->fa_tos != tos) 167319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 167419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16754e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && 16764e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf (cfg->fc_scope == RT_SCOPE_NOWHERE || 167737e826c513883099c298317bad1b3b677b2905fbDavid S. Miller fa->fa_info->fib_scope == cfg->fc_scope) && 167874cb3c108bc0f599a4eb40980db8580cfba725c9Julian Anastasov (!cfg->fc_prefsrc || 167974cb3c108bc0f599a4eb40980db8580cfba725c9Julian Anastasov fi->fib_prefsrc == cfg->fc_prefsrc) && 16804e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf (!cfg->fc_protocol || 16814e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf fi->fib_protocol == cfg->fc_protocol) && 16824e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf fib_nh_match(cfg, fi) == 0) { 168319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_to_delete = fa; 168419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 168519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 168619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 168719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 168891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (!fa_to_delete) 168991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return -ESRCH; 169019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 169191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson fa = fa_to_delete; 16924e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, 1693b8f558313506b5bc435f2e031f3bec4b1725098eMilan Kocian &cfg->fc_nlinfo, 0); 169491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 169591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson l = fib_find_node(t, key); 1696772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson li = find_leaf_info(l, plen); 169719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16982373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_del_rcu(&fa->fa_list); 169919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 170021d8c49e01a0c1c6eb6c750cd04110db4a539284David S. Miller if (!plen) 170121d8c49e01a0c1c6eb6c750cd04110db4a539284David S. Miller tb->tb_num_default--; 170221d8c49e01a0c1c6eb6c750cd04110db4a539284David S. Miller 170391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (list_empty(fa_head)) { 17042373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson hlist_del_rcu(&li->hlist); 170591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson free_leaf_info(li); 17062373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson } 170719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 170891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (hlist_empty(&l->list)) 17099195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger trie_leaf_remove(t, l); 171019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 171191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (fa->fa_state & FA_S_ACCESSED) 171276e6ebfb40a2455c18234dcb0f9df37533215461Denis V. Lunev rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); 171319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 17142373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson fib_release_info(fa->fa_info); 17152373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson alias_free_mem_rcu(fa); 171691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return 0; 171719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 171819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1719ef3660ce0649fa10265455f539b72607cff53d02Stephen Hemmingerstatic int trie_flush_list(struct list_head *head) 172019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 172119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_alias *fa, *fa_node; 172219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int found = 0; 172319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 172419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson list_for_each_entry_safe(fa, fa_node, head, fa_list) { 172519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *fi = fa->fa_info; 172619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 17272373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (fi && (fi->fib_flags & RTNH_F_DEAD)) { 17282373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_del_rcu(&fa->fa_list); 17292373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson fib_release_info(fa->fa_info); 17302373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson alias_free_mem_rcu(fa); 173119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson found++; 173219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 173319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 173419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return found; 173519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 173619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1737ef3660ce0649fa10265455f539b72607cff53d02Stephen Hemmingerstatic int trie_flush_leaf(struct leaf *l) 173819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 173919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int found = 0; 174019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_head *lih = &l->list; 174119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_node *node, *tmp; 174219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf_info *li = NULL; 174319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 174419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson hlist_for_each_entry_safe(li, node, tmp, lih, hlist) { 1745ef3660ce0649fa10265455f539b72607cff53d02Stephen Hemminger found += trie_flush_list(&li->falh); 174619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 174719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (list_empty(&li->falh)) { 17482373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson hlist_del_rcu(&li->hlist); 174919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson free_leaf_info(li); 175019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 175119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 175219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return found; 175319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 175419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 175582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger/* 175682cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger * Scan for the next right leaf starting at node p->child[idx] 175782cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger * Since we have back pointer, no recursion necessary. 175882cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger */ 1759b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic struct leaf *leaf_walk_rcu(struct tnode *p, struct rt_trie_node *c) 176019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 176182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger do { 176282cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger t_key idx; 1763c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 1764c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (c) 176582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1; 1766c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger else 176782cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger idx = 0; 17682373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 176982cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger while (idx < 1u << p->bits) { 177082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger c = tnode_get_child_rcu(p, idx++); 17712373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (!c) 177291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 177391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 177482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger if (IS_LEAF(c)) { 17750a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet prefetch(rcu_dereference_rtnl(p->child[idx])); 177682cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return (struct leaf *) c; 177719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 177882cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 177982cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger /* Rescan start scanning in new node */ 178082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger p = (struct tnode *) c; 178182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger idx = 0; 178219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 178382cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 178482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger /* Node empty, walk back up to parent */ 1785b299e4f001cfa16205f9121f4630970049652268David S. Miller c = (struct rt_trie_node *) p; 1786a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet } while ((p = node_parent_rcu(c)) != NULL); 178782cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 178882cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return NULL; /* Root of trie */ 178982cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger} 179082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 179182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemmingerstatic struct leaf *trie_firstleaf(struct trie *t) 179282cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger{ 1793a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet struct tnode *n = (struct tnode *)rcu_dereference_rtnl(t->trie); 179482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 179582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger if (!n) 179682cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return NULL; 179782cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 179882cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger if (IS_LEAF(n)) /* trie is just a leaf */ 179982cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return (struct leaf *) n; 180082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 180182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return leaf_walk_rcu(n, NULL); 180282cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger} 180382cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 180482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemmingerstatic struct leaf *trie_nextleaf(struct leaf *l) 180582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger{ 1806b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *c = (struct rt_trie_node *) l; 1807b902e5735272b6a79fe2853180b2ad6658aa9678Jarek Poplawski struct tnode *p = node_parent_rcu(c); 180882cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 180982cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger if (!p) 181082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return NULL; /* trie with just one leaf */ 181182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 181282cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return leaf_walk_rcu(p, c); 181319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 181419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 181571d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemmingerstatic struct leaf *trie_leafindex(struct trie *t, int index) 181671d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger{ 181771d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger struct leaf *l = trie_firstleaf(t); 181871d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger 1819ec28cf738d899e9d0652108e1986101771aacb2eStephen Hemminger while (l && index-- > 0) 182071d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger l = trie_nextleaf(l); 1821ec28cf738d899e9d0652108e1986101771aacb2eStephen Hemminger 182271d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger return l; 182371d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger} 182471d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger 182571d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger 1826d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson/* 1827d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson * Caller must hold RTNL. 1828d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson */ 182916c6cf8bb471392fd09b48b7c27e7d83a446b4bcStephen Hemmingerint fib_table_flush(struct fib_table *tb) 183019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 183119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 18329195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger struct leaf *l, *ll = NULL; 183382cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger int found = 0; 183419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 183582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) { 1836ef3660ce0649fa10265455f539b72607cff53d02Stephen Hemminger found += trie_flush_leaf(l); 183719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 183819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (ll && hlist_empty(&ll->list)) 18399195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger trie_leaf_remove(t, ll); 184019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson ll = l; 184119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 184219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 184319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (ll && hlist_empty(&ll->list)) 18449195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger trie_leaf_remove(t, ll); 184519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 18460c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("trie_flush found=%d\n", found); 184719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return found; 184819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 184919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 18504aa2c466a7733af093a526e9d1cdd0b3b90d47e9Pavel Emelyanovvoid fib_free_table(struct fib_table *tb) 18514aa2c466a7733af093a526e9d1cdd0b3b90d47e9Pavel Emelyanov{ 18524aa2c466a7733af093a526e9d1cdd0b3b90d47e9Pavel Emelyanov kfree(tb); 18534aa2c466a7733af093a526e9d1cdd0b3b90d47e9Pavel Emelyanov} 18544aa2c466a7733af093a526e9d1cdd0b3b90d47e9Pavel Emelyanov 1855a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, 1856a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger struct fib_table *tb, 185719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct sk_buff *skb, struct netlink_callback *cb) 185819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 185919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i, s_i; 186019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_alias *fa; 186132ab5f80334fc067386c4c56c434010c01cff6b9Al Viro __be32 xkey = htonl(key); 186219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 186371d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger s_i = cb->args[5]; 186419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson i = 0; 186519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 18662373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson /* rcu_read_lock is hold by caller */ 18672373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 18682373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_for_each_entry_rcu(fa, fah, fa_list) { 186919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (i < s_i) { 187019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson i++; 187119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 187219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 187319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 187419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, 187519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson cb->nlh->nlmsg_seq, 187619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson RTM_NEWROUTE, 187719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_id, 187819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa->fa_type, 1879be403ea1856f1428b5912b42184acbba808c41d6Thomas Graf xkey, 188019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson plen, 188119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa->fa_tos, 188264347f786d13349d6a6f812f3a83c269e26c0136Stephen Hemminger fa->fa_info, NLM_F_MULTI) < 0) { 188371d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[5] = i; 188419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -1; 188591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 188619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson i++; 188719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 188871d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[5] = i; 188919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return skb->len; 189019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 189119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1892a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemmingerstatic int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb, 1893a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger struct sk_buff *skb, struct netlink_callback *cb) 189419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 1895a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger struct leaf_info *li; 1896a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger struct hlist_node *node; 1897a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger int i, s_i; 189819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 189971d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger s_i = cb->args[4]; 1900a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger i = 0; 190119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1902a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger /* rcu_read_lock is hold by caller */ 1903a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger hlist_for_each_entry_rcu(li, node, &l->list, hlist) { 1904a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (i < s_i) { 1905a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger i++; 190619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 1907a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger } 190891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1909a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (i > s_i) 191071d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[5] = 0; 191119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1912a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (list_empty(&li->falh)) 191319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 191419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1915a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) { 191671d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[4] = i; 191719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -1; 191819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1919a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger i++; 192019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1921a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger 192271d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[4] = i; 192319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return skb->len; 192419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 192519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 192616c6cf8bb471392fd09b48b7c27e7d83a446b4bcStephen Hemmingerint fib_table_dump(struct fib_table *tb, struct sk_buff *skb, 192716c6cf8bb471392fd09b48b7c27e7d83a446b4bcStephen Hemminger struct netlink_callback *cb) 192819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 1929a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger struct leaf *l; 193019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 1931d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger t_key key = cb->args[2]; 193271d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger int count = cb->args[3]; 193319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 19342373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_lock(); 1935d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger /* Dump starting at last key. 1936d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger * Note: 0.0.0.0/0 (ie default) is first key. 1937d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger */ 193871d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger if (count == 0) 1939d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger l = trie_firstleaf(t); 1940d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger else { 194171d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger /* Normally, continue from last key, but if that is missing 194271d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger * fallback to using slow rescan 194371d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger */ 1944d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger l = fib_find_node(t, key); 194571d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger if (!l) 194671d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger l = trie_leafindex(t, count); 1947d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger } 1948a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger 1949d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger while (l) { 1950d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger cb->args[2] = l->key; 1951a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) { 195271d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[3] = count; 1953a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger rcu_read_unlock(); 1954a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger return -1; 195519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1956d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger 195771d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger ++count; 1958d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger l = trie_nextleaf(l); 195971d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger memset(&cb->args[4], 0, 196071d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger sizeof(cb->args) - 4*sizeof(cb->args[0])); 196119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 196271d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[3] = count; 19632373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_unlock(); 1964a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger 196519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return skb->len; 196619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 196719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 19685348ba85a02ffe80a8af33a524b6610966760d3dDavid S. Millervoid __init fib_trie_init(void) 19697f9b80529b8a2ad8b3273b15fb444a0e34b760a9Stephen Hemminger{ 1970a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger fn_alias_kmem = kmem_cache_create("ip_fib_alias", 1971a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger sizeof(struct fib_alias), 1972bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger 0, SLAB_PANIC, NULL); 1973bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger 1974bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger trie_leaf_kmem = kmem_cache_create("ip_fib_trie", 1975bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger max(sizeof(struct leaf), 1976bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger sizeof(struct leaf_info)), 1977bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger 0, SLAB_PANIC, NULL); 19787f9b80529b8a2ad8b3273b15fb444a0e34b760a9Stephen Hemminger} 197919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 19807f9b80529b8a2ad8b3273b15fb444a0e34b760a9Stephen Hemminger 19815348ba85a02ffe80a8af33a524b6610966760d3dDavid S. Millerstruct fib_table *fib_trie_table(u32 id) 198219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 198319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_table *tb; 198419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t; 198519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 198619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie), 198719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson GFP_KERNEL); 198819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (tb == NULL) 198919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 199019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 199119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_id = id; 1992971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunev tb->tb_default = -1; 199321d8c49e01a0c1c6eb6c750cd04110db4a539284David S. Miller tb->tb_num_default = 0; 199419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 199519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t = (struct trie *) tb->tb_data; 1996c28a1cf448e59019fa681741963c3acaeaeb6d27Stephen Hemminger memset(t, 0, sizeof(*t)); 199719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 199819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return tb; 199919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 200019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2001cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger#ifdef CONFIG_PROC_FS 2002cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger/* Depth first Trie walk iterator */ 2003cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstruct fib_trie_iter { 20041c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev struct seq_net_private p; 20053d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct fib_table *tb; 2006cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct tnode *tnode; 2007a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet unsigned int index; 2008a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet unsigned int depth; 2009cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger}; 201019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2011b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic struct rt_trie_node *fib_trie_get_next(struct fib_trie_iter *iter) 201219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2013cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct tnode *tn = iter->tnode; 2014a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet unsigned int cindex = iter->index; 2015cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct tnode *p; 201619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 20176640e69731b42fd5e3d2b26201c8b34fc897a0eeEric W. Biederman /* A single entry routing table */ 20186640e69731b42fd5e3d2b26201c8b34fc897a0eeEric W. Biederman if (!tn) 20196640e69731b42fd5e3d2b26201c8b34fc897a0eeEric W. Biederman return NULL; 20206640e69731b42fd5e3d2b26201c8b34fc897a0eeEric W. Biederman 2021cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger pr_debug("get_next iter={node=%p index=%d depth=%d}\n", 2022cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->tnode, iter->index, iter->depth); 2023cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerrescan: 2024cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger while (cindex < (1<<tn->bits)) { 2025b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n = tnode_get_child_rcu(tn, cindex); 202619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2027cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (n) { 2028cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (IS_LEAF(n)) { 2029cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->tnode = tn; 2030cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->index = cindex + 1; 2031cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } else { 2032cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger /* push down one level */ 2033cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->tnode = (struct tnode *) n; 2034cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->index = 0; 2035cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger ++iter->depth; 2036cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 2037cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return n; 2038cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 203919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2040cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger ++cindex; 2041cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 204291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2043cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger /* Current node exhausted, pop back up */ 2044b299e4f001cfa16205f9121f4630970049652268David S. Miller p = node_parent_rcu((struct rt_trie_node *)tn); 2045cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (p) { 2046cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1; 2047cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger tn = p; 2048cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger --iter->depth; 2049cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger goto rescan; 205019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 2051cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 2052cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger /* got root? */ 2053cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return NULL; 205419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 205519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2056b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic struct rt_trie_node *fib_trie_get_first(struct fib_trie_iter *iter, 2057cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct trie *t) 205819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2059b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n; 20605ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson 2061132adf54639cf7dd9315e8df89c2faa59f6e46d9Stephen Hemminger if (!t) 20625ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson return NULL; 20635ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson 20645ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson n = rcu_dereference(t->trie); 20653d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (!n) 20665ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson return NULL; 206719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 20683d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (IS_TNODE(n)) { 20693d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->tnode = (struct tnode *) n; 20703d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->index = 0; 20713d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->depth = 1; 20723d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } else { 20733d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->tnode = NULL; 20743d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->index = 0; 20753d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->depth = 0; 207691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 20773d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 20783d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger return n; 2079cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 208091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2081cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void trie_collect_stats(struct trie *t, struct trie_stat *s) 2082cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 2083b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n; 2084cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct fib_trie_iter iter; 208591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2086cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger memset(s, 0, sizeof(*s)); 208791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2088cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger rcu_read_lock(); 20893d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) { 2090cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (IS_LEAF(n)) { 2091936722922f6d2366378de606a40c14f96915474dStephen Hemminger struct leaf *l = (struct leaf *)n; 2092936722922f6d2366378de606a40c14f96915474dStephen Hemminger struct leaf_info *li; 2093936722922f6d2366378de606a40c14f96915474dStephen Hemminger struct hlist_node *tmp; 2094936722922f6d2366378de606a40c14f96915474dStephen Hemminger 2095cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->leaves++; 2096cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->totdepth += iter.depth; 2097cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (iter.depth > s->maxdepth) 2098cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->maxdepth = iter.depth; 2099936722922f6d2366378de606a40c14f96915474dStephen Hemminger 2100936722922f6d2366378de606a40c14f96915474dStephen Hemminger hlist_for_each_entry_rcu(li, tmp, &l->list, hlist) 2101936722922f6d2366378de606a40c14f96915474dStephen Hemminger ++s->prefixes; 2102cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } else { 2103cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger const struct tnode *tn = (const struct tnode *) n; 2104cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger int i; 2105cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 2106cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->tnodes++; 2107132adf54639cf7dd9315e8df89c2faa59f6e46d9Stephen Hemminger if (tn->bits < MAX_STAT_DEPTH) 210806ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson s->nodesizes[tn->bits]++; 210906ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson 2110cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger for (i = 0; i < (1<<tn->bits); i++) 2111cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (!tn->child[i]) 2112cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->nullpointers++; 211319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 211419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 21152373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_unlock(); 211619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 211719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2118cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger/* 2119cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger * This outputs /proc/net/fib_triestats 2120cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger */ 2121cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void trie_show_stats(struct seq_file *seq, struct trie_stat *stat) 212219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2123a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet unsigned int i, max, pointers, bytes, avdepth; 2124c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 2125cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (stat->leaves) 2126cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger avdepth = stat->totdepth*100 / stat->leaves; 2127cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger else 2128cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger avdepth = 0; 212991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2130a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "\tAver depth: %u.%02d\n", 2131a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger avdepth / 100, avdepth % 100); 2132cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth); 213391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2134cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_printf(seq, "\tLeaves: %u\n", stat->leaves); 2135cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger bytes = sizeof(struct leaf) * stat->leaves; 2136936722922f6d2366378de606a40c14f96915474dStephen Hemminger 2137936722922f6d2366378de606a40c14f96915474dStephen Hemminger seq_printf(seq, "\tPrefixes: %u\n", stat->prefixes); 2138936722922f6d2366378de606a40c14f96915474dStephen Hemminger bytes += sizeof(struct leaf_info) * stat->prefixes; 2139936722922f6d2366378de606a40c14f96915474dStephen Hemminger 2140187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, "\tInternal nodes: %u\n\t", stat->tnodes); 2141cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger bytes += sizeof(struct tnode) * stat->tnodes; 214219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 214306ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson max = MAX_STAT_DEPTH; 214406ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson while (max > 0 && stat->nodesizes[max-1] == 0) 2145cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger max--; 214619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2147cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger pointers = 0; 2148cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger for (i = 1; i <= max; i++) 2149cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (stat->nodesizes[i] != 0) { 2150187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, " %u: %u", i, stat->nodesizes[i]); 2151cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger pointers += (1<<i) * stat->nodesizes[i]; 2152cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 2153cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_putc(seq, '\n'); 2154187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, "\tPointers: %u\n", pointers); 21552373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 2156b299e4f001cfa16205f9121f4630970049652268David S. Miller bytes += sizeof(struct rt_trie_node *) * pointers; 2157187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, "Null ptrs: %u\n", stat->nullpointers); 2158187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, "Total size: %u kB\n", (bytes + 1023) / 1024); 215966a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger} 21602373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 2161cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger#ifdef CONFIG_IP_FIB_TRIE_STATS 216266a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemmingerstatic void trie_show_usage(struct seq_file *seq, 216366a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger const struct trie_use_stats *stats) 216466a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger{ 216566a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger seq_printf(seq, "\nCounters:\n---------\n"); 2166a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "gets = %u\n", stats->gets); 2167a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "backtracks = %u\n", stats->backtrack); 2168a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "semantic match passed = %u\n", 2169a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger stats->semantic_match_passed); 2170a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "semantic match miss = %u\n", 2171a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger stats->semantic_match_miss); 2172a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "null node hit= %u\n", stats->null_node_hit); 2173a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "skipped node resize = %u\n\n", 2174a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger stats->resize_node_skipped); 2175cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 217666a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger#endif /* CONFIG_IP_FIB_TRIE_STATS */ 217766a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger 21783d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemmingerstatic void fib_table_print(struct seq_file *seq, struct fib_table *tb) 2179d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger{ 21803d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (tb->tb_id == RT_TABLE_LOCAL) 21813d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger seq_puts(seq, "Local:\n"); 21823d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger else if (tb->tb_id == RT_TABLE_MAIN) 21833d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger seq_puts(seq, "Main:\n"); 21843d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger else 21853d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger seq_printf(seq, "Id %d:\n", tb->tb_id); 2186d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger} 218719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 21883d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 2189cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_triestat_seq_show(struct seq_file *seq, void *v) 2190cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 21911c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev struct net *net = (struct net *)seq->private; 21923d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger unsigned int h; 2193877a9bff3889512d7326d6bf0ba6ed3ddda6d772Eric W. Biederman 2194d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger seq_printf(seq, 2195a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger "Basic info: size of leaf:" 2196a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger " %Zd bytes, size of tnode: %Zd bytes.\n", 2197d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger sizeof(struct leaf), sizeof(struct tnode)); 2198d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger 21993d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger for (h = 0; h < FIB_TABLE_HASHSZ; h++) { 22003d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_head *head = &net->ipv4.fib_table_hash[h]; 22013d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_node *node; 22023d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct fib_table *tb; 22033d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 22043d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { 22053d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct trie *t = (struct trie *) tb->tb_data; 22063d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct trie_stat stat; 2207877a9bff3889512d7326d6bf0ba6ed3ddda6d772Eric W. Biederman 22083d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (!t) 22093d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger continue; 22103d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 22113d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger fib_table_print(seq, tb); 22123d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 22133d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger trie_collect_stats(t, &stat); 22143d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger trie_show_stats(seq, &stat); 22153d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger#ifdef CONFIG_IP_FIB_TRIE_STATS 22163d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger trie_show_usage(seq, &t->stats); 22173d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger#endif 22183d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 22193d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 222019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2221cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return 0; 222219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 222319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2224cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_triestat_seq_open(struct inode *inode, struct file *file) 222519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2226de05c557b24c7dffc6d392e3db120cf11c9f6ae7Pavel Emelyanov return single_open_net(inode, file, fib_triestat_seq_show); 22271c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev} 22281c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev 22299a32144e9d7b4e21341174b1a83b82a82353be86Arjan van de Venstatic const struct file_operations fib_triestat_fops = { 2230cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .owner = THIS_MODULE, 2231cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .open = fib_triestat_seq_open, 2232cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .read = seq_read, 2233cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .llseek = seq_lseek, 2234b6fcbdb4f283f7ba67cec3cda6be23da8e959031Pavel Emelyanov .release = single_release_net, 2235cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger}; 2236cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 2237b299e4f001cfa16205f9121f4630970049652268David S. Millerstatic struct rt_trie_node *fib_trie_get_idx(struct seq_file *seq, loff_t pos) 223819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 22391218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct fib_trie_iter *iter = seq->private; 22401218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 2241cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger loff_t idx = 0; 22423d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger unsigned int h; 2243cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 22443d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger for (h = 0; h < FIB_TABLE_HASHSZ; h++) { 22453d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_head *head = &net->ipv4.fib_table_hash[h]; 22463d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_node *node; 22473d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct fib_table *tb; 2248cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 22493d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { 2250b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n; 22513d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 22523d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger for (n = fib_trie_get_first(iter, 22533d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger (struct trie *) tb->tb_data); 22543d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger n; n = fib_trie_get_next(iter)) 22553d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (pos == idx++) { 22563d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->tb = tb; 22573d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger return n; 22583d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 22593d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 2260cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 22613d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 226219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 226319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 226419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2265cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) 2266c95aaf9af5a1f6dee56d1f2ab4915cd722d608daStephen Hemminger __acquires(RCU) 226719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2268cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger rcu_read_lock(); 22691218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki return fib_trie_get_idx(seq, *pos); 227019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 227119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2272cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) 227319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2274cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct fib_trie_iter *iter = seq->private; 22751218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 22763d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct fib_table *tb = iter->tb; 22773d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_node *tb_node; 22783d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger unsigned int h; 2279b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n; 2280cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 228119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson ++*pos; 22823d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger /* next node in same table */ 22833d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger n = fib_trie_get_next(iter); 22843d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (n) 22853d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger return n; 228619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 22873d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger /* walk rest of this hash chain */ 22883d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger h = tb->tb_id & (FIB_TABLE_HASHSZ - 1); 22890a5c047507aaaf00519921336d19c0f8f5f9f363Eric Dumazet while ((tb_node = rcu_dereference(hlist_next_rcu(&tb->tb_hlist)))) { 22903d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger tb = hlist_entry(tb_node, struct fib_table, tb_hlist); 22913d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); 22923d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (n) 22933d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger goto found; 22943d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 229519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 22963d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger /* new hash chain */ 22973d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger while (++h < FIB_TABLE_HASHSZ) { 22983d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_head *head = &net->ipv4.fib_table_hash[h]; 22993d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger hlist_for_each_entry_rcu(tb, tb_node, head, tb_hlist) { 23003d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); 23013d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (n) 23023d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger goto found; 23033d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 23043d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 2305cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return NULL; 23063d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 23073d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemmingerfound: 23083d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->tb = tb; 23093d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger return n; 2310cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 231119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2312cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void fib_trie_seq_stop(struct seq_file *seq, void *v) 2313c95aaf9af5a1f6dee56d1f2ab4915cd722d608daStephen Hemminger __releases(RCU) 231419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2315cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger rcu_read_unlock(); 2316cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 231791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2318cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void seq_indent(struct seq_file *seq, int n) 2319cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 2320a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet while (n-- > 0) 2321a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet seq_puts(seq, " "); 2322cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 232319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 232428d36e3702fcbed73c38e877bcf2a8f8946b7f3dEric Dumazetstatic inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s) 2325cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 2326132adf54639cf7dd9315e8df89c2faa59f6e46d9Stephen Hemminger switch (s) { 2327cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_UNIVERSE: return "universe"; 2328cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_SITE: return "site"; 2329cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_LINK: return "link"; 2330cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_HOST: return "host"; 2331cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_NOWHERE: return "nowhere"; 2332cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger default: 233328d36e3702fcbed73c38e877bcf2a8f8946b7f3dEric Dumazet snprintf(buf, len, "scope=%d", s); 2334cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return buf; 2335cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 2336cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 233719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 233836cbd3dcc10384f813ec0814255f576c84f2bcd4Jan Engelhardtstatic const char *const rtn_type_names[__RTN_MAX] = { 2339cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_UNSPEC] = "UNSPEC", 2340cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_UNICAST] = "UNICAST", 2341cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_LOCAL] = "LOCAL", 2342cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_BROADCAST] = "BROADCAST", 2343cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_ANYCAST] = "ANYCAST", 2344cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_MULTICAST] = "MULTICAST", 2345cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_BLACKHOLE] = "BLACKHOLE", 2346cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_UNREACHABLE] = "UNREACHABLE", 2347cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_PROHIBIT] = "PROHIBIT", 2348cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_THROW] = "THROW", 2349cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_NAT] = "NAT", 2350cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_XRESOLVE] = "XRESOLVE", 2351cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger}; 235219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2353a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazetstatic inline const char *rtn_type(char *buf, size_t len, unsigned int t) 2354cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 2355cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (t < __RTN_MAX && rtn_type_names[t]) 2356cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return rtn_type_names[t]; 235728d36e3702fcbed73c38e877bcf2a8f8946b7f3dEric Dumazet snprintf(buf, len, "type %u", t); 2358cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return buf; 235919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 236019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2361cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger/* Pretty print the trie */ 2362cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_trie_seq_show(struct seq_file *seq, void *v) 236319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2364cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger const struct fib_trie_iter *iter = seq->private; 2365b299e4f001cfa16205f9121f4630970049652268David S. Miller struct rt_trie_node *n = v; 2366c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 23673d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (!node_parent_rcu(n)) 23683d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger fib_table_print(seq, iter->tb); 2369095b8501e4168ae5a879fcb9420ac48cbd43f95aRobert Olsson 2370cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (IS_TNODE(n)) { 2371cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct tnode *tn = (struct tnode *) n; 2372ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger __be32 prf = htonl(mask_pfx(tn->key, tn->pos)); 237391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 23741d25cd6cc2528e4af12ab18e84fe95ed78f3f21aRobert Olsson seq_indent(seq, iter->depth-1); 2375673d57e72398edfedc93fb50ff58048077c9d587Harvey Harrison seq_printf(seq, " +-- %pI4/%d %d %d %d\n", 2376673d57e72398edfedc93fb50ff58048077c9d587Harvey Harrison &prf, tn->pos, tn->bits, tn->full_children, 23771d25cd6cc2528e4af12ab18e84fe95ed78f3f21aRobert Olsson tn->empty_children); 2378e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 2379cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } else { 2380cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct leaf *l = (struct leaf *) n; 23811328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct leaf_info *li; 23821328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct hlist_node *node; 238332ab5f80334fc067386c4c56c434010c01cff6b9Al Viro __be32 val = htonl(l->key); 2384cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 2385cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_indent(seq, iter->depth); 2386673d57e72398edfedc93fb50ff58048077c9d587Harvey Harrison seq_printf(seq, " |-- %pI4\n", &val); 23871328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger 23881328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger hlist_for_each_entry_rcu(li, node, &l->list, hlist) { 23891328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct fib_alias *fa; 23901328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger 23911328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger list_for_each_entry_rcu(fa, &li->falh, fa_list) { 23921328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger char buf1[32], buf2[32]; 23931328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger 23941328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger seq_indent(seq, iter->depth+1); 23951328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger seq_printf(seq, " /%d %s %s", li->plen, 23961328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger rtn_scope(buf1, sizeof(buf1), 239737e826c513883099c298317bad1b3b677b2905fbDavid S. Miller fa->fa_info->fib_scope), 23981328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger rtn_type(buf2, sizeof(buf2), 23991328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger fa->fa_type)); 24001328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger if (fa->fa_tos) 2401b9c4d82a853713d49ac53b507964d7cf30ee408dDenis V. Lunev seq_printf(seq, " tos=%d", fa->fa_tos); 24021328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger seq_putc(seq, '\n'); 2403cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 2404cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 240519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 2406cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 240719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 240819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 240919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2410f690808e17925fc45217eb22e8670902ecee5c1bStephen Hemmingerstatic const struct seq_operations fib_trie_seq_ops = { 2411cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .start = fib_trie_seq_start, 2412cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .next = fib_trie_seq_next, 2413cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .stop = fib_trie_seq_stop, 2414cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .show = fib_trie_seq_show, 241519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 241619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2417cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_trie_seq_open(struct inode *inode, struct file *file) 241819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 24191c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev return seq_open_net(inode, file, &fib_trie_seq_ops, 24201c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev sizeof(struct fib_trie_iter)); 242119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 242219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 24239a32144e9d7b4e21341174b1a83b82a82353be86Arjan van de Venstatic const struct file_operations fib_trie_fops = { 2424cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .owner = THIS_MODULE, 2425cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .open = fib_trie_seq_open, 2426cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .read = seq_read, 2427cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .llseek = seq_lseek, 24281c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev .release = seq_release_net, 242919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 243019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 24318315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstruct fib_route_iter { 24328315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct seq_net_private p; 24338315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct trie *main_trie; 24348315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger loff_t pos; 24358315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger t_key key; 24368315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger}; 24378315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24388315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstatic struct leaf *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos) 24398315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger{ 24408315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct leaf *l = NULL; 24418315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct trie *t = iter->main_trie; 24428315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24438315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger /* use cache location of last found key */ 24448315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (iter->pos > 0 && pos >= iter->pos && (l = fib_find_node(t, iter->key))) 24458315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger pos -= iter->pos; 24468315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger else { 24478315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos = 0; 24488315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger l = trie_firstleaf(t); 24498315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger } 24508315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24518315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger while (l && pos-- > 0) { 24528315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos++; 24538315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger l = trie_nextleaf(l); 24548315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger } 24558315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24568315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (l) 24578315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->key = pos; /* remember it */ 24588315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger else 24598315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos = 0; /* forget it */ 24608315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24618315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return l; 24628315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger} 24638315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24648315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstatic void *fib_route_seq_start(struct seq_file *seq, loff_t *pos) 24658315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger __acquires(RCU) 24668315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger{ 24678315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct fib_route_iter *iter = seq->private; 24688315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct fib_table *tb; 24698315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24708315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger rcu_read_lock(); 24711218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki tb = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN); 24728315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (!tb) 24738315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return NULL; 24748315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24758315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->main_trie = (struct trie *) tb->tb_data; 24768315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (*pos == 0) 24778315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return SEQ_START_TOKEN; 24788315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger else 24798315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return fib_route_get_idx(iter, *pos - 1); 24808315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger} 24818315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24828315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstatic void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos) 24838315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger{ 24848315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct fib_route_iter *iter = seq->private; 24858315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct leaf *l = v; 24868315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24878315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger ++*pos; 24888315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (v == SEQ_START_TOKEN) { 24898315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos = 0; 24908315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger l = trie_firstleaf(iter->main_trie); 24918315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger } else { 24928315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos++; 24938315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger l = trie_nextleaf(l); 24948315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger } 24958315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24968315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (l) 24978315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->key = l->key; 24988315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger else 24998315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos = 0; 25008315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return l; 25018315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger} 25028315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25038315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstatic void fib_route_seq_stop(struct seq_file *seq, void *v) 25048315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger __releases(RCU) 25058315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger{ 25068315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger rcu_read_unlock(); 25078315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger} 25088315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 2509a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazetstatic unsigned int fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) 251019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2511a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet unsigned int flags = 0; 251219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2513a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT) 2514a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet flags = RTF_REJECT; 2515cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (fi && fi->fib_nh->nh_gw) 2516cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger flags |= RTF_GATEWAY; 251732ab5f80334fc067386c4c56c434010c01cff6b9Al Viro if (mask == htonl(0xFFFFFFFF)) 2518cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger flags |= RTF_HOST; 2519cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger flags |= RTF_UP; 2520cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return flags; 252119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 252219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2523cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger/* 2524cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger * This outputs /proc/net/route. 2525cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger * The format of the file is not supposed to be changed 2526a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet * and needs to be same as fib_hash output to avoid breaking 2527cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger * legacy utilities 2528cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger */ 2529cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_route_seq_show(struct seq_file *seq, void *v) 253019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2531cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct leaf *l = v; 25321328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct leaf_info *li; 25331328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct hlist_node *node; 253419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2535cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (v == SEQ_START_TOKEN) { 2536cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway " 2537cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU" 2538cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger "\tWindow\tIRTT"); 2539cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return 0; 2540cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 254119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 25421328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger hlist_for_each_entry_rcu(li, node, &l->list, hlist) { 2543cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct fib_alias *fa; 254432ab5f80334fc067386c4c56c434010c01cff6b9Al Viro __be32 mask, prefix; 254591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2546cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger mask = inet_make_mask(li->plen); 2547cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger prefix = htonl(l->key); 254819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2549cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger list_for_each_entry_rcu(fa, &li->falh, fa_list) { 25501371e37da299d4df6267ad0ddf010435782c28e9Herbert Xu const struct fib_info *fi = fa->fa_info; 2551a034ee3cca5726b14107f281f4bed1c0fd44472aEric Dumazet unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi); 25525e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov int len; 255319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2554cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (fa->fa_type == RTN_BROADCAST 2555cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger || fa->fa_type == RTN_MULTICAST) 2556cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger continue; 255719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2558cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (fi) 25595e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov seq_printf(seq, 25605e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov "%s\t%08X\t%08X\t%04X\t%d\t%u\t" 25615e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov "%d\t%08X\t%d\t%u\t%u%n", 2562cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger fi->fib_dev ? fi->fib_dev->name : "*", 2563cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger prefix, 2564cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger fi->fib_nh->nh_gw, flags, 0, 0, 2565cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger fi->fib_priority, 2566cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger mask, 2567a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger (fi->fib_advmss ? 2568a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger fi->fib_advmss + 40 : 0), 2569cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger fi->fib_window, 25705e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov fi->fib_rtt >> 3, &len); 2571cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger else 25725e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov seq_printf(seq, 25735e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov "*\t%08X\t%08X\t%04X\t%d\t%u\t" 25745e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov "%d\t%08X\t%d\t%u\t%u%n", 2575cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger prefix, 0, flags, 0, 0, 0, 25765e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov mask, 0, 0, 0, &len); 257719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 25785e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov seq_printf(seq, "%*s\n", 127 - len, ""); 2579cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 258019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 258119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 258219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 258319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 258419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2585f690808e17925fc45217eb22e8670902ecee5c1bStephen Hemmingerstatic const struct seq_operations fib_route_seq_ops = { 25868315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger .start = fib_route_seq_start, 25878315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger .next = fib_route_seq_next, 25888315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger .stop = fib_route_seq_stop, 2589cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .show = fib_route_seq_show, 259019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 259119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2592cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_route_seq_open(struct inode *inode, struct file *file) 259319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 25941c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev return seq_open_net(inode, file, &fib_route_seq_ops, 25958315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger sizeof(struct fib_route_iter)); 259619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 259719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 25989a32144e9d7b4e21341174b1a83b82a82353be86Arjan van de Venstatic const struct file_operations fib_route_fops = { 2599cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .owner = THIS_MODULE, 2600cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .open = fib_route_seq_open, 2601cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .read = seq_read, 2602cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .llseek = seq_lseek, 26031c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev .release = seq_release_net, 260419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 260519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 260661a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunevint __net_init fib_proc_init(struct net *net) 260719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 260861a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev if (!proc_net_fops_create(net, "fib_trie", S_IRUGO, &fib_trie_fops)) 2609cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger goto out1; 2610cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 261161a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev if (!proc_net_fops_create(net, "fib_triestat", S_IRUGO, 261261a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev &fib_triestat_fops)) 2613cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger goto out2; 2614cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 261561a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev if (!proc_net_fops_create(net, "route", S_IRUGO, &fib_route_fops)) 2616cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger goto out3; 2617cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 261819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 2619cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 2620cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerout3: 262161a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "fib_triestat"); 2622cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerout2: 262361a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "fib_trie"); 2624cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerout1: 2625cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return -ENOMEM; 262619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 262719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 262861a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunevvoid __net_exit fib_proc_exit(struct net *net) 262919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 263061a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "fib_trie"); 263161a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "fib_triestat"); 263261a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "route"); 263319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 263419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 263519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif /* CONFIG_PROC_FS */ 2636