fib_trie.c revision 76e6ebfb40a2455c18234dcb0f9df37533215461
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 * 1519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * This work is based on the LPC-trie which is originally descibed 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. 1919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * http://www.nada.kth.se/~snilsson/public/papers/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 5105eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson#define VERSION "0.408" 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> 74457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h> 7519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/ip.h> 7619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/protocol.h> 7719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/route.h> 7819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/tcp.h> 7919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/sock.h> 8019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include <net/ip_fib.h> 8119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#include "fib_lookup.h" 8219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8306ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson#define MAX_STAT_DEPTH 32 8419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#define KEYLENGTH (8*sizeof(t_key)) 8619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssontypedef unsigned int t_key; 8819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#define T_TNODE 0 9019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#define T_LEAF 1 9119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#define NODE_TYPE_MASK 0x1UL 922373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson#define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK) 932373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 9491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson#define IS_TNODE(n) (!(n->parent & T_LEAF)) 9591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson#define IS_LEAF(n) (n->parent & T_LEAF) 9619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 9719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct node { 9891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson unsigned long parent; 998d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet t_key key; 10019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 10119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 10219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct leaf { 10391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson unsigned long parent; 1048d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet t_key key; 10519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_head list; 1062373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct rcu_head rcu; 10719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 10819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 10919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct leaf_info { 11019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_node hlist; 1112373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct rcu_head rcu; 11219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int plen; 11319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct list_head falh; 11419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 11519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 11619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct tnode { 11791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson unsigned long parent; 1188d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet t_key key; 119112d8cfcbf4f5ef0cf669cb5864f1206972076d6Eric Dumazet unsigned char pos; /* 2log(KEYLENGTH) bits needed */ 120112d8cfcbf4f5ef0cf669cb5864f1206972076d6Eric Dumazet unsigned char bits; /* 2log(KEYLENGTH) bits needed */ 1218d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet unsigned int full_children; /* KEYLENGTH bits needed */ 1228d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet unsigned int empty_children; /* KEYLENGTH bits needed */ 12315be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger union { 12415be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger struct rcu_head rcu; 12515be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger struct work_struct work; 12615be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger }; 12791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct node *child[0]; 12819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 12919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 13019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 13119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct trie_use_stats { 13219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int gets; 13319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int backtrack; 13419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int semantic_match_passed; 13519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int semantic_match_miss; 13619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int null_node_hit; 1372f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson unsigned int resize_node_skipped; 13819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 13919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 14019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 14119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct trie_stat { 14219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int totdepth; 14319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int maxdepth; 14419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int tnodes; 14519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int leaves; 14619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson unsigned int nullpointers; 147936722922f6d2366378de606a40c14f96915474dStephen Hemminger unsigned int prefixes; 14806ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson unsigned int nodesizes[MAX_STAT_DEPTH]; 149c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger}; 15019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 15119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstruct trie { 15291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct node *trie; 15319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 15419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie_use_stats stats; 15519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 15619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 15719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 15819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic void put_child(struct trie *t, struct tnode *tn, int i, struct node *n); 159a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, 160a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger int wasfull); 16119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic struct node *resize(struct trie *t, struct tnode *tn); 1622f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonstatic struct tnode *inflate(struct trie *t, struct tnode *tn); 1632f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonstatic struct tnode *halve(struct trie *t, struct tnode *tn); 16419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 165e18b890bb0881bbab6f4f1a6cd20d9c60d66b003Christoph Lameterstatic struct kmem_cache *fn_alias_kmem __read_mostly; 166bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemmingerstatic struct kmem_cache *trie_leaf_kmem __read_mostly; 16719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1680680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemmingerstatic inline struct tnode *node_parent(struct node *node) 1690680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger{ 170b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet return (struct tnode *)(node->parent & ~NODE_TYPE_MASK); 171b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet} 172b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet 173b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazetstatic inline struct tnode *node_parent_rcu(struct node *node) 174b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet{ 175b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet struct tnode *ret = node_parent(node); 1760680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger 1770680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger return rcu_dereference(ret); 1780680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger} 1790680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger 1806440cc9e0f48ade57af7be28008cbfa6a991f287Stephen Hemminger/* Same as rcu_assign_pointer 1816440cc9e0f48ade57af7be28008cbfa6a991f287Stephen Hemminger * but that macro() assumes that value is a pointer. 1826440cc9e0f48ade57af7be28008cbfa6a991f287Stephen Hemminger */ 1830680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemmingerstatic inline void node_set_parent(struct node *node, struct tnode *ptr) 1840680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger{ 1856440cc9e0f48ade57af7be28008cbfa6a991f287Stephen Hemminger smp_wmb(); 1866440cc9e0f48ade57af7be28008cbfa6a991f287Stephen Hemminger node->parent = (unsigned long)ptr | NODE_TYPE(node); 1870680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger} 1882373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 189b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazetstatic inline struct node *tnode_get_child(struct tnode *tn, unsigned int i) 190b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet{ 191b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet BUG_ON(i >= 1U << tn->bits); 1922373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 193b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet return tn->child[i]; 194b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet} 195b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet 196b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazetstatic inline struct node *tnode_get_child_rcu(struct tnode *tn, unsigned int i) 19719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 198b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet struct node *ret = tnode_get_child(tn, i); 19919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 200b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet return rcu_dereference(ret); 20119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 20219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 203bb435b8d816582064ee0ddb1e2a6fbca67f34108Stephen Hemmingerstatic inline int tnode_child_length(const struct tnode *tn) 20419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 20591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return 1 << tn->bits; 20619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 20719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 208ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemmingerstatic inline t_key mask_pfx(t_key k, unsigned short l) 209ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger{ 210ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l); 211ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger} 212ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger 21319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic inline t_key tkey_extract_bits(t_key a, int offset, int bits) 21419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 21591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (offset < KEYLENGTH) 21619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return ((t_key)(a << offset)) >> (KEYLENGTH - bits); 21791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson else 21819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 21919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 22019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 22119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic inline int tkey_equals(t_key a, t_key b) 22219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 223c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger return a == b; 22419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 22519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 22619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b) 22719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 228c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (bits == 0 || offset >= KEYLENGTH) 229c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger return 1; 23091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson bits = bits > KEYLENGTH ? KEYLENGTH : bits; 23191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0; 232c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger} 23319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 23419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic inline int tkey_mismatch(t_key a, int offset, t_key b) 23519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 23619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t_key diff = a ^ b; 23719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i = offset; 23819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 239c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!diff) 240c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger return 0; 241c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger while ((diff << i) >> (KEYLENGTH-1) == 0) 24219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson i++; 24319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return i; 24419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 24519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 24619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson/* 247e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki To understand this stuff, an understanding of keys and all their bits is 248e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki necessary. Every node in the trie has a key associated with it, but not 24919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson all of the bits in that key are significant. 25019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 25119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson Consider a node 'n' and its parent 'tp'. 25219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 253e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki If n is a leaf, every bit in its key is significant. Its presence is 254e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki necessitated by path compression, since during a tree traversal (when 255e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki searching for a leaf - unless we are doing an insertion) we will completely 256e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki ignore all skipped bits we encounter. Thus we need to verify, at the end of 257e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki a potentially successful search, that we have indeed been walking the 25819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson correct key path. 25919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 260e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki Note that we can never "miss" the correct key in the tree if present by 261e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki following the wrong path. Path compression ensures that segments of the key 262e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki that are the same for all keys with a given prefix are skipped, but the 263e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki skipped part *is* identical for each node in the subtrie below the skipped 264e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki bit! trie_insert() in this implementation takes care of that - note the 26519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson call to tkey_sub_equals() in trie_insert(). 26619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 267e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if n is an internal node - a 'tnode' here, the various parts of its key 26819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson have many different meanings. 26919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 270e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki Example: 27119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson _________________________________________________________________ 27219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C | 27319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson ----------------------------------------------------------------- 274e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 27519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 27619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson _________________________________________________________________ 27719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u | 27819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson ----------------------------------------------------------------- 27919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 28019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 28119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tp->pos = 7 28219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tp->bits = 3 28319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson n->pos = 15 28491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson n->bits = 4 28519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 286e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki First, let's just ignore the bits that come before the parent tp, that is 287e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki the bits from 0 to (tp->pos-1). They are *known* but at this point we do 28819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson not use them for anything. 28919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 29019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the 291e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki index into the parent's child array. That is, they will be used to find 29219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 'n' among tp's children. 29319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 29419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits 29519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson for the node n. 29619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 297e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki All the bits we have seen so far are significant to the node n. The rest 29819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson of the bits are really not needed or indeed known in n->key. 29919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 300e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into 30119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson n's child array, and will of course be different for each child. 302e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 303c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 30419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson The rest of the bits, from (n->pos + n->bits) onward, are completely unknown 30519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson at this point. 30619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 30719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson*/ 30819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 3090c7770c740156c8802c23d24fc094d06967d997dStephen Hemmingerstatic inline void check_tnode(const struct tnode *tn) 31019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 3110c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger WARN_ON(tn && tn->pos+tn->bits > 32); 31219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 31319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 314f5026fabda54e5ab5d469d8cfac5f46b4d321ce9Denis V. Lunevstatic const int halve_threshold = 25; 315f5026fabda54e5ab5d469d8cfac5f46b4d321ce9Denis V. Lunevstatic const int inflate_threshold = 50; 316f5026fabda54e5ab5d469d8cfac5f46b4d321ce9Denis V. Lunevstatic const int halve_threshold_root = 8; 317f5026fabda54e5ab5d469d8cfac5f46b4d321ce9Denis V. Lunevstatic const int inflate_threshold_root = 15; 31819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 3192373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 3202373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic void __alias_free_mem(struct rcu_head *head) 32119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 3222373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct fib_alias *fa = container_of(head, struct fib_alias, rcu); 3232373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson kmem_cache_free(fn_alias_kmem, fa); 32419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 32519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 3262373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic inline void alias_free_mem_rcu(struct fib_alias *fa) 32719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 3282373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson call_rcu(&fa->rcu, __alias_free_mem); 3292373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 33091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 3312373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic void __leaf_free_rcu(struct rcu_head *head) 3322373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson{ 333bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger struct leaf *l = container_of(head, struct leaf, rcu); 334bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger kmem_cache_free(trie_leaf_kmem, l); 3352373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 33691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 337387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemmingerstatic inline void free_leaf(struct leaf *l) 338387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger{ 339387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger call_rcu_bh(&l->rcu, __leaf_free_rcu); 340387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger} 341387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger 3422373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic void __leaf_info_free_rcu(struct rcu_head *head) 34319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 3442373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson kfree(container_of(head, struct leaf_info, rcu)); 34519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 34619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 3472373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic inline void free_leaf_info(struct leaf_info *leaf) 34819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 3492373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson call_rcu(&leaf->rcu, __leaf_info_free_rcu); 35019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 35119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 3528d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazetstatic struct tnode *tnode_alloc(size_t size) 353f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy{ 3542373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (size <= PAGE_SIZE) 3558d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet return kzalloc(size, GFP_KERNEL); 35615be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger else 35715be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); 35815be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger} 3592373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 36015be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemmingerstatic void __tnode_vfree(struct work_struct *arg) 36115be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger{ 36215be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger struct tnode *tn = container_of(arg, struct tnode, work); 36315be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger vfree(tn); 364f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy} 365f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy 3662373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic void __tnode_free_rcu(struct rcu_head *head) 367f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy{ 3682373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct tnode *tn = container_of(head, struct tnode, rcu); 3698d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet size_t size = sizeof(struct tnode) + 3708d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet (sizeof(struct node *) << tn->bits); 371f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy 372f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy if (size <= PAGE_SIZE) 373f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy kfree(tn); 37415be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger else { 37515be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger INIT_WORK(&tn->work, __tnode_vfree); 37615be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger schedule_work(&tn->work); 37715be75cdb5db442d0e33d37b20832b88f3ccd383Stephen Hemminger } 378f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy} 379f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy 3802373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic inline void tnode_free(struct tnode *tn) 3812373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson{ 382387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger if (IS_LEAF(tn)) 383387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger free_leaf((struct leaf *) tn); 384387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger else 385550e29bc96e6f1ced2bca82dace197b009434367Robert Olsson call_rcu(&tn->rcu, __tnode_free_rcu); 3862373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 3872373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 3882373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic struct leaf *leaf_new(void) 3892373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson{ 390bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); 3912373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (l) { 3922373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson l->parent = T_LEAF; 3932373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson INIT_HLIST_HEAD(&l->list); 3942373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson } 3952373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson return l; 3962373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 3972373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 3982373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olssonstatic struct leaf_info *leaf_info_new(int plen) 3992373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson{ 4002373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct leaf_info *li = kmalloc(sizeof(struct leaf_info), GFP_KERNEL); 4012373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (li) { 4022373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson li->plen = plen; 4032373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson INIT_LIST_HEAD(&li->falh); 4042373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson } 4052373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson return li; 4062373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson} 4072373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 408a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic struct tnode *tnode_new(t_key key, int pos, int bits) 40919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 4108d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet size_t sz = sizeof(struct tnode) + (sizeof(struct node *) << bits); 411f0e36f8cee8101604378085171c980d9cc71d779Patrick McHardy struct tnode *tn = tnode_alloc(sz); 41219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 41391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (tn) { 4142373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson tn->parent = T_TNODE; 41519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->pos = pos; 41619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->bits = bits; 41719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->key = key; 41819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->full_children = 0; 41919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->empty_children = 1<<bits; 42019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 421c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 4228d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet pr_debug("AT %p s=%u %lu\n", tn, (unsigned int) sizeof(struct tnode), 4238d96544475b236a0f319e492f4828aa8c0801c7fEric Dumazet (unsigned long) (sizeof(struct node) << bits)); 42419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return tn; 42519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 42619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 42719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson/* 42819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Check whether a tnode 'n' is "full", i.e. it is an internal node 42919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * and no bits are skipped. See discussion in dyntree paper p. 6 43019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 43119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 432bb435b8d816582064ee0ddb1e2a6fbca67f34108Stephen Hemmingerstatic inline int tnode_full(const struct tnode *tn, const struct node *n) 43319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 434c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (n == NULL || IS_LEAF(n)) 43519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 43619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 43719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return ((struct tnode *) n)->pos == tn->pos + tn->bits; 43819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 43919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 440a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic inline void put_child(struct trie *t, struct tnode *tn, int i, 441a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger struct node *n) 44219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 44319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tnode_put_child_reorg(tn, i, n, -1); 44419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 44519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 446c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger /* 44719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Add a child at position i overwriting the old value. 44819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Update the value of full_children and empty_children. 44919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 45019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 451a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, 452a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger int wasfull) 45319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 4542373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson struct node *chi = tn->child[i]; 45519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int isfull; 45619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 4570c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger BUG_ON(i >= 1<<tn->bits); 4580c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 45919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* update emptyChildren */ 46019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (n == NULL && chi != NULL) 46119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->empty_children++; 46219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson else if (n != NULL && chi == NULL) 46319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->empty_children--; 464c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 46519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* update fullChildren */ 46691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (wasfull == -1) 46719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson wasfull = tnode_full(tn, chi); 46819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 46919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson isfull = tnode_full(tn, n); 470c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (wasfull && !isfull) 47119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->full_children--; 472c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger else if (!wasfull && isfull) 47319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->full_children++; 47491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 475c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (n) 4760680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger node_set_parent(n, tn); 47719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 4782373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_assign_pointer(tn->child[i], n); 47919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 48019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 481c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemmingerstatic struct node *resize(struct trie *t, struct tnode *tn) 48219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 48319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i; 4842f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson int err = 0; 4852f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson struct tnode *old_tn; 486e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson int inflate_threshold_use; 487e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson int halve_threshold_use; 48805eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson int max_resize; 48919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 490e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (!tn) 49119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 49219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 4930c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n", 4940c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger tn, inflate_threshold, halve_threshold); 49519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 49619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* No children */ 49719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (tn->empty_children == tnode_child_length(tn)) { 49819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tnode_free(tn); 49919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 50019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 50119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* One child */ 50219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (tn->empty_children == tnode_child_length(tn) - 1) 50319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson for (i = 0; i < tnode_child_length(tn); i++) { 50491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct node *n; 50519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 50691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson n = tn->child[i]; 5072373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (!n) 50891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 50991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 51091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* compress one level */ 5110680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger node_set_parent(n, NULL); 51291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson tnode_free(tn); 51391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return n; 51419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 515c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger /* 51619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Double as long as the resulting node has a number of 51719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * nonempty nodes that are above the threshold. 51819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 51919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 52019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 521c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * From "Implementing a dynamic compressed trie" by Stefan Nilsson of 522c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * the Helsinki University of Technology and Matti Tikkanen of Nokia 52319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Telecommunications, page 6: 524c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * "A node is doubled if the ratio of non-empty children to all 52519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * children in the *doubled* node is at least 'high'." 52619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 527c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 'high' in this instance is the variable 'inflate_threshold'. It 528c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * is expressed as a percentage, so we multiply it with 529c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * tnode_child_length() and instead of multiplying by 2 (since the 530c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * child array will be doubled by inflate()) and multiplying 531c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * the left-hand side by 100 (to handle the percentage thing) we 53219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * multiply the left-hand side by 50. 533c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 534c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * The left-hand side may look a bit weird: tnode_child_length(tn) 535c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * - tn->empty_children is of course the number of non-null children 536c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * in the current node. tn->full_children is the number of "full" 53719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * children, that is non-null tnodes with a skip value of 0. 538c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * All of those will be doubled in the resulting inflated tnode, so 53919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * we just count them one extra time here. 540c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 54119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * A clearer way to write this would be: 542c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 54319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * to_be_doubled = tn->full_children; 544c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children - 54519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * tn->full_children; 54619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 54719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * new_child_length = tnode_child_length(tn) * 2; 54819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 549c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) / 55019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * new_child_length; 55119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * if (new_fill_factor >= inflate_threshold) 552c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 553c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * ...and so on, tho it would mess up the while () loop. 554c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 55519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * anyway, 55619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >= 55719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * inflate_threshold 558c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 55919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * avoid a division: 56019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 100 * (not_to_be_doubled + 2*to_be_doubled) >= 56119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * inflate_threshold * new_child_length 562c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 56319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * expand not_to_be_doubled and to_be_doubled, and shorten: 564c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 100 * (tnode_child_length(tn) - tn->empty_children + 56591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tn->full_children) >= inflate_threshold * new_child_length 566c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 56719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * expand new_child_length: 568c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 100 * (tnode_child_length(tn) - tn->empty_children + 56991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tn->full_children) >= 57019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * inflate_threshold * tnode_child_length(tn) * 2 571c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 57219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * shorten again: 573c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 50 * (tn->full_children + tnode_child_length(tn) - 57491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tn->empty_children) >= inflate_threshold * 57519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * tnode_child_length(tn) 576c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * 57719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 57819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 57919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson check_tnode(tn); 580c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 581e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson /* Keep root node larger */ 582e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson 583132adf54639cf7dd9315e8df89c2faa59f6e46d9Stephen Hemminger if (!tn->parent) 584e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson inflate_threshold_use = inflate_threshold_root; 585e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki else 586e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson inflate_threshold_use = inflate_threshold; 587e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson 5882f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson err = 0; 58905eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson max_resize = 10; 59005eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson while ((tn->full_children > 0 && max_resize-- && 591a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 50 * (tn->full_children + tnode_child_length(tn) 592a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger - tn->empty_children) 593a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger >= inflate_threshold_use * tnode_child_length(tn))) { 59419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 5952f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson old_tn = tn; 5962f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tn = inflate(t, tn); 597a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 5982f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (IS_ERR(tn)) { 5992f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tn = old_tn; 6002f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 6012f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson t->stats.resize_node_skipped++; 6022f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson#endif 6032f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson break; 6042f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 60519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 60619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 60705eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson if (max_resize < 0) { 60805eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson if (!tn->parent) 609a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger pr_warning("Fix inflate_threshold_root." 610a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger " Now=%d size=%d bits\n", 611a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger inflate_threshold_root, tn->bits); 61205eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson else 613a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger pr_warning("Fix inflate_threshold." 614a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger " Now=%d size=%d bits\n", 615a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger inflate_threshold, tn->bits); 61605eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson } 61705eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson 61819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson check_tnode(tn); 61919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 62019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 62119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Halve as long as the number of empty children in this 62219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * node is above threshold. 62319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 6242f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 625e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson 626e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson /* Keep root node larger */ 627e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson 628132adf54639cf7dd9315e8df89c2faa59f6e46d9Stephen Hemminger if (!tn->parent) 629e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson halve_threshold_use = halve_threshold_root; 630e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki else 631e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson halve_threshold_use = halve_threshold; 632e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson 6332f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson err = 0; 63405eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson max_resize = 10; 63505eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson while (tn->bits > 1 && max_resize-- && 63619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 100 * (tnode_child_length(tn) - tn->empty_children) < 637e6308be85afee685347fa3440bed10faaa5d6c1aRobert Olsson halve_threshold_use * tnode_child_length(tn)) { 6382f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 6392f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson old_tn = tn; 6402f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tn = halve(t, tn); 6412f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (IS_ERR(tn)) { 6422f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tn = old_tn; 6432f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 6442f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson t->stats.resize_node_skipped++; 6452f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson#endif 6462f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson break; 6472f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 6482f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 64919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 65005eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson if (max_resize < 0) { 65105eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson if (!tn->parent) 652a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger pr_warning("Fix halve_threshold_root." 653a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger " Now=%d size=%d bits\n", 654a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger halve_threshold_root, tn->bits); 65505eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson else 656a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger pr_warning("Fix halve_threshold." 657a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger " Now=%d size=%d bits\n", 658a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger halve_threshold, tn->bits); 65905eee48c5af8213a71bd908ce17f577b2b776f79Robert Olsson } 660c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 66119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Only one child remains */ 66219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (tn->empty_children == tnode_child_length(tn) - 1) 66319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson for (i = 0; i < tnode_child_length(tn); i++) { 66491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct node *n; 66519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 66691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson n = tn->child[i]; 6672373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (!n) 66891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 66991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 67091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* compress one level */ 67191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 6720680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger node_set_parent(n, NULL); 67391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson tnode_free(tn); 67491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return n; 67519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 67619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 67719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return (struct node *) tn; 67819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 67919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 6802f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonstatic struct tnode *inflate(struct trie *t, struct tnode *tn) 68119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 68219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *oldtnode = tn; 68319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int olen = tnode_child_length(tn); 68419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i; 68519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 6860c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("In inflate\n"); 68719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 68819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1); 68919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 6900c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger if (!tn) 6912f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson return ERR_PTR(-ENOMEM); 6922f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 6932f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson /* 694c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * Preallocate and store tnodes before the actual work so we 695c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * don't get into an inconsistent state if memory allocation 696c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * fails. In case of failure we return the oldnode and inflate 6972f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson * of tnode is ignored. 6982f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson */ 69991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 70091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (i = 0; i < olen; i++) { 701a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger struct tnode *inode; 7022f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 703a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger inode = (struct tnode *) tnode_get_child(oldtnode, i); 7042f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson if (inode && 7052f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson IS_TNODE(inode) && 7062f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson inode->pos == oldtnode->pos + oldtnode->bits && 7072f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson inode->bits > 1) { 7082f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson struct tnode *left, *right; 709ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos; 710c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 7112f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson left = tnode_new(inode->key&(~m), inode->pos + 1, 7122f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson inode->bits - 1); 7132f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (!left) 7142f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson goto nomem; 71591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 7162f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson right = tnode_new(inode->key|m, inode->pos + 1, 7172f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson inode->bits - 1); 7182f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 719e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (!right) { 7202f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tnode_free(left); 7212f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson goto nomem; 722e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki } 7232f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 7242f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson put_child(t, tn, 2*i, (struct node *) left); 7252f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson put_child(t, tn, 2*i+1, (struct node *) right); 7262f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 7272f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 7282f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 72991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (i = 0; i < olen; i++) { 730c95aaf9af5a1f6dee56d1f2ab4915cd722d608daStephen Hemminger struct tnode *inode; 73119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct node *node = tnode_get_child(oldtnode, i); 73291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct tnode *left, *right; 73391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson int size, j; 734c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 73519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* An empty child */ 73619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (node == NULL) 73719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 73819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 73919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* A leaf or an internal node with skipped bits */ 74019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 741c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (IS_LEAF(node) || ((struct tnode *) node)->pos > 74219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn->pos + tn->bits - 1) { 743a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger if (tkey_extract_bits(node->key, 744a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger oldtnode->pos + oldtnode->bits, 745a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 1) == 0) 74619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, 2*i, node); 74719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson else 74819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, 2*i+1, node); 74919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 75019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 75119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 75219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* An internal node with two children */ 75319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson inode = (struct tnode *) node; 75419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 75519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (inode->bits == 1) { 75619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, 2*i, inode->child[0]); 75719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, 2*i+1, inode->child[1]); 75819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 75919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tnode_free(inode); 76091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 76119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 76219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 76391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* An internal node with more than two children */ 76491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 76591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* We will replace this node 'inode' with two new 76691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * ones, 'left' and 'right', each with half of the 76791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * original children. The two new nodes will have 76891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * a position one bit further down the key and this 76991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * means that the "significant" part of their keys 77091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * (see the discussion near the top of this file) 77191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * will differ by one bit, which will be "0" in 77291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * left's key and "1" in right's key. Since we are 77391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * moving the key position by one step, the bit that 77491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * we are moving away from - the bit at position 77591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * (inode->pos) - is the one that will differ between 77691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * left and right. So... we synthesize that bit in the 77791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * two new keys. 77891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * The mask 'm' below will be a single "one" bit at 77991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * the position (inode->pos) 78091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 78119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 78291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* Use the old key, but set the new significant 78391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * bit to zero. 78491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 7852f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 78691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson left = (struct tnode *) tnode_get_child(tn, 2*i); 78791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, 2*i, NULL); 7882f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 78991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson BUG_ON(!left); 7902f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 79191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson right = (struct tnode *) tnode_get_child(tn, 2*i+1); 79291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, 2*i+1, NULL); 79319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 79491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson BUG_ON(!right); 79519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 79691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson size = tnode_child_length(left); 79791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (j = 0; j < size; j++) { 79891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, left, j, inode->child[j]); 79991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, right, j, inode->child[j + size]); 80019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 80191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, 2*i, resize(t, left)); 80291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, 2*i+1, resize(t, right)); 80391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 80491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson tnode_free(inode); 80519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 80619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tnode_free(oldtnode); 80719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return tn; 8082f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonnomem: 8092f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson { 8102f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson int size = tnode_child_length(tn); 8112f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson int j; 8122f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson 8130c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger for (j = 0; j < size; j++) 8142f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (tn->child[j]) 8152f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tnode_free((struct tnode *)tn->child[j]); 8162f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson 8172f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tnode_free(tn); 8180c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 8192f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson return ERR_PTR(-ENOMEM); 8202f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson } 82119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 82219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8232f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonstatic struct tnode *halve(struct trie *t, struct tnode *tn) 82419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 82519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *oldtnode = tn; 82619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct node *left, *right; 82719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i; 82819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int olen = tnode_child_length(tn); 82919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8300c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("In halve\n"); 831c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 832c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1); 83319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 8342f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (!tn) 8352f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson return ERR_PTR(-ENOMEM); 8362f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 8372f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson /* 838c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * Preallocate and store tnodes before the actual work so we 839c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * don't get into an inconsistent state if memory allocation 840c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * fails. In case of failure we return the oldnode and halve 8412f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson * of tnode is ignored. 8422f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson */ 8432f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 84491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (i = 0; i < olen; i += 2) { 8452f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson left = tnode_get_child(oldtnode, i); 8462f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson right = tnode_get_child(oldtnode, i+1); 847c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 8482f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson /* Two nonempty children */ 8490c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger if (left && right) { 8502f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson struct tnode *newn; 8510c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 8522f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson newn = tnode_new(left->key, tn->pos + tn->bits, 1); 8530c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 8540c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger if (!newn) 8552f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson goto nomem; 8560c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 8572f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson put_child(t, tn, i/2, (struct node *)newn); 8582f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 8592f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson 8602f36895aa774cf4d1c3d68921e0209e796b66600Robert Olsson } 86119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 86291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson for (i = 0; i < olen; i += 2) { 86391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct tnode *newBinNode; 86491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 86519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson left = tnode_get_child(oldtnode, i); 86619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson right = tnode_get_child(oldtnode, i+1); 867c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 86819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* At least one of the children is empty */ 86919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (left == NULL) { 87019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (right == NULL) /* Both are empty */ 87119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 87219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, i/2, right); 87391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 8740c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger } 87591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 87691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (right == NULL) { 87719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, i/2, left); 87891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 87991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 880c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 88119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Two nonempty children */ 88291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson newBinNode = (struct tnode *) tnode_get_child(tn, i/2); 88391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, i/2, NULL); 88491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, newBinNode, 0, left); 88591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, newBinNode, 1, right); 88691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, tn, i/2, resize(t, newBinNode)); 88719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 88819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tnode_free(oldtnode); 88919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return tn; 8902f80b3c8262d0d646812f776db024d88d569a0c1Robert Olssonnomem: 8912f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson { 8922f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson int size = tnode_child_length(tn); 8932f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson int j; 8942f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson 8950c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger for (j = 0; j < size; j++) 8962f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson if (tn->child[j]) 8972f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tnode_free((struct tnode *)tn->child[j]); 8982f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson 8992f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson tnode_free(tn); 9000c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger 9012f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson return ERR_PTR(-ENOMEM); 9022f80b3c8262d0d646812f776db024d88d569a0c1Robert Olsson } 90319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 90419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 905772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson/* readside must use rcu_read_lock currently dump routines 9062373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson via get_fa_head and dump */ 9072373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 908772cb712b1373d335ef2874ea357ec681edc754bRobert Olssonstatic struct leaf_info *find_leaf_info(struct leaf *l, int plen) 90919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 910772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson struct hlist_head *head = &l->list; 91119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_node *node; 91219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf_info *li; 91319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 9142373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson hlist_for_each_entry_rcu(li, node, head, hlist) 915c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (li->plen == plen) 91619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return li; 91791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 91819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 91919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 92019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 921a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic inline struct list_head *get_fa_head(struct leaf *l, int plen) 92219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 923772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson struct leaf_info *li = find_leaf_info(l, plen); 924c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 92591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (!li) 92691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return NULL; 927c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 92891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return &li->falh; 92919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 93019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 93119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic void insert_leaf_info(struct hlist_head *head, struct leaf_info *new) 93219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 933e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki struct leaf_info *li = NULL, *last = NULL; 934e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki struct hlist_node *node; 935e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 936e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (hlist_empty(head)) { 937e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki hlist_add_head_rcu(&new->hlist, head); 938e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki } else { 939e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki hlist_for_each_entry(li, node, head, hlist) { 940e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (new->plen > li->plen) 941e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki break; 942e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 943e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki last = li; 944e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki } 945e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki if (last) 946e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki hlist_add_after_rcu(&last->hlist, &new->hlist); 947e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki else 948e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki hlist_add_before_rcu(&new->hlist, &li->hlist); 949e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki } 95019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 95119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 9522373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson/* rcu_read_lock needs to be hold by caller from readside */ 9532373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 95419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic struct leaf * 95519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonfib_find_node(struct trie *t, u32 key) 95619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 95719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int pos; 95819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *tn; 95919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct node *n; 96019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 96119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson pos = 0; 9622373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson n = rcu_dereference(t->trie); 96319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 96419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson while (n != NULL && NODE_TYPE(n) == T_TNODE) { 96519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn = (struct tnode *) n; 96691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 96719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson check_tnode(tn); 96891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 969c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { 97091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pos = tn->pos + tn->bits; 971a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger n = tnode_get_child_rcu(tn, 972a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tkey_extract_bits(key, 973a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn->pos, 974a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn->bits)); 97591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else 97619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 97719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 97819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Case we have found a leaf. Compare prefixes */ 97919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 98091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) 98191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return (struct leaf *)n; 98291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 98319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 98419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 98519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 98619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic struct node *trie_rebalance(struct trie *t, struct tnode *tn) 98719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 98819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int wasfull; 9890680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger t_key cindex, key = tn->key; 9900680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger struct tnode *tp; 99119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 9920680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { 99319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson cindex = tkey_extract_bits(key, tp->pos, tp->bits); 99419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); 995a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn = (struct tnode *) resize(t, (struct tnode *)tn); 996a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 997a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tnode_put_child_reorg((struct tnode *)tp, cindex, 998a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger (struct node *)tn, wasfull); 99991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 10000680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger tp = node_parent((struct node *) tn); 10010680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger if (!tp) 100219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 10030680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger tn = tp; 100419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 10050680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger 100619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Handle last (top) tnode */ 1007c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (IS_TNODE(tn)) 1008a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn = (struct tnode *)resize(t, (struct tnode *)tn); 100919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1010a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger return (struct node *)tn; 101119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 101219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 10132373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson/* only used from updater-side */ 10142373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 1015fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemmingerstatic struct list_head *fib_insert_node(struct trie *t, u32 key, int plen) 101619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 101719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int pos, newpos; 101819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *tp = NULL, *tn = NULL; 101919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct node *n; 102019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf *l; 102119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int missbit; 1022c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger struct list_head *fa_head = NULL; 102319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf_info *li; 102419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t_key cindex; 102519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 102619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson pos = 0; 1027c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger n = t->trie; 102819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1029c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger /* If we point to NULL, stop. Either the tree is empty and we should 1030c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * just put a new leaf in if, or we have reached an empty child slot, 103119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * and we should just put our new leaf in that. 1032c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * If we point to a T_TNODE, check if it matches our key. Note that 1033c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * a T_TNODE might be skipping any number of bits - its 'pos' need 103419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * not be the parent's 'pos'+'bits'! 103519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 1036c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * If it does match the current key, get pos/bits from it, extract 103719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * the index from our key, push the T_TNODE and walk the tree. 103819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 103919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * If it doesn't, we have to replace it with a new T_TNODE. 104019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 1041c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * If we point to a T_LEAF, it might or might not have the same key 1042c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * as we do. If it does, just change the value, update the T_LEAF's 1043c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * value, and return it. 104419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * If it doesn't, we need to replace it with a T_TNODE. 104519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 104619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 104719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson while (n != NULL && NODE_TYPE(n) == T_TNODE) { 104819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn = (struct tnode *) n; 104991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1050c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger check_tnode(tn); 105191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1052c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { 105319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tp = tn; 105491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pos = tn->pos + tn->bits; 1055a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger n = tnode_get_child(tn, 1056a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tkey_extract_bits(key, 1057a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn->pos, 1058a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tn->bits)); 105919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 10600680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger BUG_ON(n && node_parent(n) != tn); 106191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else 106219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 106319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 106419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 106519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 106619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * n ----> NULL, LEAF or TNODE 106719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 1068c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * tp is n's (parent) ----> NULL or TNODE 106919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 107019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 107191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson BUG_ON(tp && IS_LEAF(tp)); 107219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 107319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Case 1: n is a leaf. Compare prefixes */ 107419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1075c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) { 1076c95aaf9af5a1f6dee56d1f2ab4915cd722d608daStephen Hemminger l = (struct leaf *) n; 107719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson li = leaf_info_new(plen); 107891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1079fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger if (!li) 1080fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger return NULL; 108119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 108219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_head = &li->falh; 108319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson insert_leaf_info(&l->list, li); 108419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto done; 108519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 108619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson l = leaf_new(); 108719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1088fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger if (!l) 1089fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger return NULL; 109019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 109119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson l->key = key; 109219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson li = leaf_info_new(plen); 109319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1094c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!li) { 1095387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger free_leaf(l); 1096fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger return NULL; 1097f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson } 109819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 109919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_head = &li->falh; 110019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson insert_leaf_info(&l->list, li); 110119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 110219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (t->trie && n == NULL) { 110391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* Case 2: n is NULL, and will just insert a new leaf */ 110419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 11050680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger node_set_parent((struct node *)l, tp); 110619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 110791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson cindex = tkey_extract_bits(key, tp->pos, tp->bits); 110891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson put_child(t, (struct tnode *)tp, cindex, (struct node *)l); 110991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else { 111091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */ 1111c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger /* 1112c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * Add a new tnode here 111319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * first tnode need some special handling 111419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 111519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 111619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (tp) 111791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pos = tp->pos+tp->bits; 111819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson else 111991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pos = 0; 112091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1121c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (n) { 112219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson newpos = tkey_mismatch(key, pos, n->key); 112319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tn = tnode_new(n->key, newpos, 1); 112491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else { 112519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson newpos = 0; 1126c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger tn = tnode_new(key, newpos, 1); /* First tnode */ 112719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 112819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1129c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!tn) { 1130f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson free_leaf_info(li); 1131387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger free_leaf(l); 1132fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger return NULL; 113391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 113491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 11350680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger node_set_parent((struct node *)tn, tp); 113619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 113791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson missbit = tkey_extract_bits(key, newpos, 1); 113819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, missbit, (struct node *)l); 113919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, tn, 1-missbit, n); 114019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1141c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (tp) { 114219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson cindex = tkey_extract_bits(key, tp->pos, tp->bits); 1143a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger put_child(t, (struct tnode *)tp, cindex, 1144a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger (struct node *)tn); 114591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else { 1146a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger rcu_assign_pointer(t->trie, (struct node *)tn); 114719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tp = tn; 114819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 114919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 115091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 115191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (tp && tp->pos + tp->bits > 32) 1152a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger pr_warning("fib_trie" 1153a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger " tp=%p pos=%d, bits=%d, key=%0x plen=%d\n", 1154a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger tp, tp->pos, tp->bits, key, plen); 115591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 115619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Rebalance the trie */ 11572373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 11582373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_assign_pointer(t->trie, trie_rebalance(t, tp)); 1159f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olssondone: 116019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return fa_head; 116119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 116219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1163d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson/* 1164d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson * Caller must hold RTNL. 1165d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson */ 11664e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Grafstatic int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg) 116719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 116819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 116919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_alias *fa, *new_fa; 1170c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger struct list_head *fa_head = NULL; 117119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *fi; 11724e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf int plen = cfg->fc_dst_len; 11734e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf u8 tos = cfg->fc_tos; 117419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson u32 key, mask; 117519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int err; 117619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf *l; 117719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 117819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (plen > 32) 117919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -EINVAL; 118019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 11814e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf key = ntohl(cfg->fc_dst); 118219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 11832dfe55b47e3d66ded5a84caf71e0da5710edf48bPatrick McHardy pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); 118419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 118591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson mask = ntohl(inet_make_mask(plen)); 118619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1187c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (key & ~mask) 118819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -EINVAL; 118919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 119019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson key = key & mask; 119119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 11924e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf fi = fib_create_info(cfg); 11934e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (IS_ERR(fi)) { 11944e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf err = PTR_ERR(fi); 119519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto err; 11964e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf } 119719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 119819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson l = fib_find_node(t, key); 1199c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger fa = NULL; 120019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1201c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (l) { 120219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_head = get_fa_head(l, plen); 120319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa = fib_find_alias(fa_head, tos, fi->fib_priority); 120419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 120519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 120619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Now fa, if non-NULL, points to the first fib alias 120719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * with the same keys [prefix,tos,priority], if such key already 120819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * exists or to the node before which we will insert new one. 120919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 121019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * If fa is NULL, we will need to allocate a new one and 121119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * insert to the head of f. 121219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * 121319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * If f is NULL, no fib node matched the destination key 121419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * and we need to allocate a new one of those as well. 121519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 121619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1217936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa && fa->fa_tos == tos && 1218936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa->fa_info->fib_priority == fi->fib_priority) { 1219936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov struct fib_alias *fa_first, *fa_match; 122019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 122119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson err = -EEXIST; 12224e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (cfg->fc_nlflags & NLM_F_EXCL) 122319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 122419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1225936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov /* We have 2 goals: 1226936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov * 1. Find exact match for type, scope, fib_info to avoid 1227936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov * duplicate routes 1228936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it 1229936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov */ 1230936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa_match = NULL; 1231936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa_first = fa; 1232936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); 1233936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov list_for_each_entry_continue(fa, fa_head, fa_list) { 1234936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa->fa_tos != tos) 1235936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov break; 1236936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa->fa_info->fib_priority != fi->fib_priority) 1237936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov break; 1238936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa->fa_type == cfg->fc_type && 1239936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa->fa_scope == cfg->fc_scope && 1240936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa->fa_info == fi) { 1241936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa_match = fa; 1242936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov break; 1243936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov } 1244936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov } 1245936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov 12464e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (cfg->fc_nlflags & NLM_F_REPLACE) { 124719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *fi_drop; 124819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson u8 state; 124919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1250936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa = fa_first; 1251936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa_match) { 1252936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa == fa_match) 1253936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov err = 0; 12546725033fa27c8f49e1221d2badbaaaf1ef459519Joonwoo Park goto out; 1255936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov } 12562373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson err = -ENOBUFS; 1257e94b1766097d53e6f3ccfb36c8baa562ffeda3fcChristoph Lameter new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); 12582373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (new_fa == NULL) 12592373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson goto out; 126019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 126119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fi_drop = fa->fa_info; 12622373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson new_fa->fa_tos = fa->fa_tos; 12632373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson new_fa->fa_info = fi; 12644e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf new_fa->fa_type = cfg->fc_type; 12654e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf new_fa->fa_scope = cfg->fc_scope; 126619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson state = fa->fa_state; 1267936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov new_fa->fa_state = state & ~FA_S_ACCESSED; 126819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 12692373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_replace_rcu(&fa->fa_list, &new_fa->fa_list); 12702373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson alias_free_mem_rcu(fa); 127119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 127219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fib_release_info(fi_drop); 127319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (state & FA_S_ACCESSED) 127476e6ebfb40a2455c18234dcb0f9df37533215461Denis V. Lunev rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); 1275b8f558313506b5bc435f2e031f3bec4b1725098eMilan Kocian rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, 1276b8f558313506b5bc435f2e031f3bec4b1725098eMilan Kocian tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE); 127719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 127891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson goto succeeded; 127919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 128019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Error if we find a perfect match which 128119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * uses the same scope, type, and nexthop 128219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * information. 128319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 1284936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov if (fa_match) 1285936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov goto out; 1286a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 12874e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (!(cfg->fc_nlflags & NLM_F_APPEND)) 1288936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa = fa_first; 128919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 129019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson err = -ENOENT; 12914e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if (!(cfg->fc_nlflags & NLM_F_CREATE)) 129219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 129319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 129419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson err = -ENOBUFS; 1295e94b1766097d53e6f3ccfb36c8baa562ffeda3fcChristoph Lameter new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); 129619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (new_fa == NULL) 129719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 129819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 129919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson new_fa->fa_info = fi; 130019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson new_fa->fa_tos = tos; 13014e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf new_fa->fa_type = cfg->fc_type; 13024e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf new_fa->fa_scope = cfg->fc_scope; 130319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson new_fa->fa_state = 0; 130419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 130519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * Insert new entry to the list. 130619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 130719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1308c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!fa_head) { 1309fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger fa_head = fib_insert_node(t, key, plen); 1310fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger if (unlikely(!fa_head)) { 1311fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger err = -ENOMEM; 1312f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson goto out_free_new_fa; 1313fea86ad8123df0d49188cbc1dd2f48da6ae49d65Stephen Hemminger } 1314f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson } 131519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 13162373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_add_tail_rcu(&new_fa->fa_list, 13172373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson (fa ? &fa->fa_list : fa_head)); 131819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 131976e6ebfb40a2455c18234dcb0f9df37533215461Denis V. Lunev rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); 13204e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, 1321b8f558313506b5bc435f2e031f3bec4b1725098eMilan Kocian &cfg->fc_nlinfo, 0); 132219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonsucceeded: 132319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 1324f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson 1325f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olssonout_free_new_fa: 1326f835e471b557c45d2e5701ea5215f6e739b4eb39Robert Olsson kmem_cache_free(fn_alias_kmem, new_fa); 132719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonout: 132819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fib_release_info(fi); 132991b9a277fc4d207249e459a455abf804ebb5499dOlof Johanssonerr: 133019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return err; 133119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 133219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1333772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson/* should be called with rcu_read_lock */ 1334a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic int check_leaf(struct trie *t, struct leaf *l, 1335a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger t_key key, const struct flowi *flp, 1336a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger struct fib_result *res) 133719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 133819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf_info *li; 133919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_head *hhead = &l->list; 134019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_node *node; 1341c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 13422373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson hlist_for_each_entry_rcu(li, node, hhead, hlist) { 1343a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger int err; 1344a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger int plen = li->plen; 1345a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger __be32 mask = inet_make_mask(plen); 1346a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 1347888454c57a45511808d3fa52597b3d765df034a6Al Viro if (l->key != (key & ntohl(mask))) 134819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 134919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1350a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger err = fib_semantic_match(&li->falh, flp, res, 1351a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger htonl(l->key), mask, plen); 1352a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 135319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 1354a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger if (err <= 0) 135519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t->stats.semantic_match_passed++; 1356a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger else 1357a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger t->stats.semantic_match_miss++; 135819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 1359a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger if (err <= 0) 1360a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger return plen; 136119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1362a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 1363a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger return -1; 136419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 136519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1366a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, 1367a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger struct fib_result *res) 136819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 136919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 137019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int plen, ret = 0; 137119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct node *n; 137219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct tnode *pn; 137319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int pos, bits; 137491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson t_key key = ntohl(flp->fl4_dst); 137519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int chopped_off; 137619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t_key cindex = 0; 137719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int current_prefix_length = KEYLENGTH; 137891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct tnode *cn; 137991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson t_key node_prefix, key_prefix, pref_mismatch; 138091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson int mp; 138191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 13822373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_lock(); 138391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 13842373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson n = rcu_dereference(t->trie); 1385c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!n) 138619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto failed; 138719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 138819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 138919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t->stats.gets++; 139019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 139119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 139219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Just a leaf? */ 139319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (IS_LEAF(n)) { 1394a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger plen = check_leaf(t, (struct leaf *)n, key, flp, res); 1395a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger if (plen < 0) 1396a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger goto failed; 1397a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger ret = 0; 1398a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger goto found; 139919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1400a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 140119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson pn = (struct tnode *) n; 140219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson chopped_off = 0; 1403c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 140491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson while (pn) { 140519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson pos = pn->pos; 140619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson bits = pn->bits; 140719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1408c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!chopped_off) 1409ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length), 1410ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger pos, bits); 141119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 141219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson n = tnode_get_child(pn, cindex); 141319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 141419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (n == NULL) { 141519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 141619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t->stats.null_node_hit++; 141719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 141819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto backtrace; 141919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 142019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 142191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (IS_LEAF(n)) { 1422a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger plen = check_leaf(t, (struct leaf *)n, key, flp, res); 1423a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger if (plen < 0) 142491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson goto backtrace; 1425a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 1426a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger ret = 0; 1427a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger goto found; 142891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 142991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 143091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson cn = (struct tnode *)n; 143119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 143291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* 143391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * It's a tnode, and we can do some extra checks here if we 143491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * like, to avoid descending into a dead-end branch. 143591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * This tnode is in the parent's child array at index 143691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * key[p_pos..p_pos+p_bits] but potentially with some bits 143791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * chopped off, so in reality the index may be just a 143891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * subprefix, padded with zero at the end. 143991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * We can also take a look at any skipped bits in this 144091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tnode - everything up to p_pos is supposed to be ok, 144191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * and the non-chopped bits of the index (se previous 144291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * paragraph) are also guaranteed ok, but the rest is 144391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * considered unknown. 144491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * 144591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * The skipped bits are key[pos+bits..cn->pos]. 144691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 144719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 144891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* If current_prefix_length < pos+bits, we are already doing 144991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * actual prefix matching, which means everything from 145091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * pos+(bits-chopped_off) onward must be zero along some 145191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * branch of this subtree - otherwise there is *no* valid 145291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * prefix present. Here we can only check the skipped 145391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * bits. Remember, since we have already indexed into the 145491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * parent's child array, we know that the bits we chopped of 145591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * *are* zero. 145691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 145719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1458a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger /* NOTA BENE: Checking only skipped bits 1459a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger for the new node here */ 146019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 146191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (current_prefix_length < pos+bits) { 146291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (tkey_extract_bits(cn->key, current_prefix_length, 1463a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger cn->pos - current_prefix_length) 1464a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger || !(cn->child[0])) 146591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson goto backtrace; 146691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 146719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 146891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* 146991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * If chopped_off=0, the index is fully validated and we 147091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * only need to look at the skipped bits for this, the new, 147191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * tnode. What we actually want to do is to find out if 147291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * these skipped bits match our key perfectly, or if we will 147391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * have to count on finding a matching prefix further down, 147491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * because if we do, we would like to have some way of 147591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * verifying the existence of such a prefix at this point. 147691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 147719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 147891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson /* The only thing we can do at this point is to verify that 147991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * any such matching prefix can indeed be a prefix to our 148091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * key, and if the bits in the node we are inspecting that 148191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * do not match our key are not ZERO, this cannot be true. 148291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * Thus, find out where there is a mismatch (before cn->pos) 148391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * and verify that all the mismatching bits are zero in the 148491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson * new tnode's key. 148591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 148619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1487a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger /* 1488a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * Note: We aren't very concerned about the piece of 1489a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * the key that precede pn->pos+pn->bits, since these 1490a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * have already been checked. The bits after cn->pos 1491a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * aren't checked since these are by definition 1492a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * "unknown" at this point. Thus, what we want to see 1493a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * is if we are about to enter the "prefix matching" 1494a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * state, and in that case verify that the skipped 1495a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * bits that will prevail throughout this subtree are 1496a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * zero, as they have to be if we are to find a 1497a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * matching prefix. 149891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 149991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1500ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger node_prefix = mask_pfx(cn->key, cn->pos); 1501ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger key_prefix = mask_pfx(key, cn->pos); 150291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pref_mismatch = key_prefix^node_prefix; 150391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson mp = 0; 150491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1505a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger /* 1506a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * In short: If skipped bits in this node do not match 1507a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * the search key, enter the "prefix matching" 1508a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger * state.directly. 150991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson */ 151091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (pref_mismatch) { 151191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) { 151291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson mp++; 1513a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger pref_mismatch = pref_mismatch << 1; 151491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 151591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp); 151691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 151791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (key_prefix != 0) 151891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson goto backtrace; 151991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 152091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (current_prefix_length >= cn->pos) 152191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson current_prefix_length = mp; 1522c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger } 1523a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger 152491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson pn = (struct tnode *)n; /* Descend */ 152591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson chopped_off = 0; 152691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 152791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 152819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonbacktrace: 152919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson chopped_off++; 153019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 153119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* As zero don't change the child key (cindex) */ 1532a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger while ((chopped_off <= pn->bits) 1533a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger && !(cindex & (1<<(chopped_off-1)))) 153419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson chopped_off++; 153519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 153619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Decrease current_... with bits chopped off */ 153719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (current_prefix_length > pn->pos + pn->bits - chopped_off) 1538a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger current_prefix_length = pn->pos + pn->bits 1539a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger - chopped_off; 154091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 154119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* 1542c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger * Either we do the actual chop off according or if we have 154319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson * chopped off all bits in this tnode walk up to our parent. 154419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson */ 154519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 154691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (chopped_off <= pn->bits) { 154719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson cindex &= ~(1 << (chopped_off-1)); 154891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else { 15490680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger struct tnode *parent = node_parent((struct node *) pn); 15500680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger if (!parent) 155119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto failed; 155291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 155319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson /* Get Child's index */ 15540680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits); 15550680191642c27c81c9be4557d9c6aa3487c15f69Stephen Hemminger pn = parent; 155619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson chopped_off = 0; 155719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 155819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#ifdef CONFIG_IP_FIB_TRIE_STATS 155919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t->stats.backtrack++; 156019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif 156119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto backtrace; 1562c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger } 156319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 156419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonfailed: 1565c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger ret = 1; 156619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonfound: 15672373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_unlock(); 156819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return ret; 156919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 157019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 15719195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger/* 15729195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger * Remove the leaf and return parent. 15739195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger */ 15749195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemmingerstatic void trie_leaf_remove(struct trie *t, struct leaf *l) 157519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 15769195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger struct tnode *tp = node_parent((struct node *) l); 1577c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 15789195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger pr_debug("entering trie_leaf_remove(%p)\n", l); 157919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1580c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (tp) { 15819195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits); 158219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson put_child(t, (struct tnode *)tp, cindex, NULL); 15832373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_assign_pointer(t->trie, trie_rebalance(t, tp)); 158491b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } else 15852373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_assign_pointer(t->trie, NULL); 158619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1587387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3fStephen Hemminger free_leaf(l); 158819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 158919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1590d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson/* 1591d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson * Caller must hold RTNL. 1592d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson */ 15934e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Grafstatic int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg) 159419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 159519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 159619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson u32 key, mask; 15974e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf int plen = cfg->fc_dst_len; 15984e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf u8 tos = cfg->fc_tos; 159919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_alias *fa, *fa_to_delete; 160019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct list_head *fa_head; 160119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf *l; 160291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson struct leaf_info *li; 160391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1604c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (plen > 32) 160519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -EINVAL; 160619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16074e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf key = ntohl(cfg->fc_dst); 160891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson mask = ntohl(inet_make_mask(plen)); 160919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1610c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (key & ~mask) 161119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -EINVAL; 161219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 161319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson key = key & mask; 161419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson l = fib_find_node(t, key); 161519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1616c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!l) 161719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -ESRCH; 161819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 161919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_head = get_fa_head(l, plen); 162019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa = fib_find_alias(fa_head, tos, 0); 162119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 162219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (!fa) 162319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -ESRCH; 162419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16250c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t); 162619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 162719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_to_delete = NULL; 1628936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); 1629936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6Julian Anastasov list_for_each_entry_continue(fa, fa_head, fa_list) { 163019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *fi = fa->fa_info; 163119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 163219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (fa->fa_tos != tos) 163319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 163419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16354e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && 16364e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf (cfg->fc_scope == RT_SCOPE_NOWHERE || 16374e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf fa->fa_scope == cfg->fc_scope) && 16384e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf (!cfg->fc_protocol || 16394e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf fi->fib_protocol == cfg->fc_protocol) && 16404e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf fib_nh_match(cfg, fi) == 0) { 164119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_to_delete = fa; 164219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 164319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 164419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 164519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 164691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (!fa_to_delete) 164791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return -ESRCH; 164819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 164991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson fa = fa_to_delete; 16504e902c57417c4c285b98ba2722468d1c3ed83d1bThomas Graf rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, 1651b8f558313506b5bc435f2e031f3bec4b1725098eMilan Kocian &cfg->fc_nlinfo, 0); 165291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 165391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson l = fib_find_node(t, key); 1654772cb712b1373d335ef2874ea357ec681edc754bRobert Olsson li = find_leaf_info(l, plen); 165519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16562373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_del_rcu(&fa->fa_list); 165719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 165891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (list_empty(fa_head)) { 16592373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson hlist_del_rcu(&li->hlist); 166091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson free_leaf_info(li); 16612373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson } 166219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 166391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (hlist_empty(&l->list)) 16649195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger trie_leaf_remove(t, l); 166519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 166691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson if (fa->fa_state & FA_S_ACCESSED) 166776e6ebfb40a2455c18234dcb0f9df37533215461Denis V. Lunev rt_cache_flush(cfg->fc_nlinfo.nl_net, -1); 166819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16692373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson fib_release_info(fa->fa_info); 16702373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson alias_free_mem_rcu(fa); 167191b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson return 0; 167219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 167319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1674ef3660ce0649fa10265455f539b72607cff53d02Stephen Hemmingerstatic int trie_flush_list(struct list_head *head) 167519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 167619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_alias *fa, *fa_node; 167719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int found = 0; 167819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 167919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson list_for_each_entry_safe(fa, fa_node, head, fa_list) { 168019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *fi = fa->fa_info; 168119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 16822373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (fi && (fi->fib_flags & RTNH_F_DEAD)) { 16832373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_del_rcu(&fa->fa_list); 16842373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson fib_release_info(fa->fa_info); 16852373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson alias_free_mem_rcu(fa); 168619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson found++; 168719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 168819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 168919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return found; 169019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 169119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1692ef3660ce0649fa10265455f539b72607cff53d02Stephen Hemmingerstatic int trie_flush_leaf(struct leaf *l) 169319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 169419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int found = 0; 169519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_head *lih = &l->list; 169619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct hlist_node *node, *tmp; 169719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf_info *li = NULL; 169819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 169919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson hlist_for_each_entry_safe(li, node, tmp, lih, hlist) { 1700ef3660ce0649fa10265455f539b72607cff53d02Stephen Hemminger found += trie_flush_list(&li->falh); 170119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 170219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (list_empty(&li->falh)) { 17032373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson hlist_del_rcu(&li->hlist); 170419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson free_leaf_info(li); 170519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 170619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 170719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return found; 170819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 170919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 171082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger/* 171182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger * Scan for the next right leaf starting at node p->child[idx] 171282cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger * Since we have back pointer, no recursion necessary. 171382cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger */ 171482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemmingerstatic struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c) 171519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 171682cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger do { 171782cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger t_key idx; 1718c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 1719c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (c) 172082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1; 1721c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger else 172282cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger idx = 0; 17232373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 172482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger while (idx < 1u << p->bits) { 172582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger c = tnode_get_child_rcu(p, idx++); 17262373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson if (!c) 172791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson continue; 172891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 172982cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger if (IS_LEAF(c)) { 173082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger prefetch(p->child[idx]); 173182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return (struct leaf *) c; 173219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 173382cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 173482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger /* Rescan start scanning in new node */ 173582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger p = (struct tnode *) c; 173682cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger idx = 0; 173719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 173882cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 173982cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger /* Node empty, walk back up to parent */ 174091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson c = (struct node *) p; 174182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger } while ( (p = node_parent_rcu(c)) != NULL); 174282cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 174382cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return NULL; /* Root of trie */ 174482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger} 174582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 174682cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemmingerstatic struct leaf *trie_firstleaf(struct trie *t) 174782cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger{ 174882cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger struct tnode *n = (struct tnode *) rcu_dereference(t->trie); 174982cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 175082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger if (!n) 175182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return NULL; 175282cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 175382cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger if (IS_LEAF(n)) /* trie is just a leaf */ 175482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return (struct leaf *) n; 175582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 175682cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return leaf_walk_rcu(n, NULL); 175782cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger} 175882cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 175982cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemmingerstatic struct leaf *trie_nextleaf(struct leaf *l) 176082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger{ 176182cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger struct node *c = (struct node *) l; 176282cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger struct tnode *p = node_parent(c); 176382cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 176482cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger if (!p) 176582cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return NULL; /* trie with just one leaf */ 176682cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger 176782cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger return leaf_walk_rcu(p, c); 176819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 176919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 177071d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemmingerstatic struct leaf *trie_leafindex(struct trie *t, int index) 177171d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger{ 177271d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger struct leaf *l = trie_firstleaf(t); 177371d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger 1774ec28cf738d899e9d0652108e1986101771aacb2eStephen Hemminger while (l && index-- > 0) 177571d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger l = trie_nextleaf(l); 1776ec28cf738d899e9d0652108e1986101771aacb2eStephen Hemminger 177771d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger return l; 177871d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger} 177971d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger 178071d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger 1781d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson/* 1782d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson * Caller must hold RTNL. 1783d562f1f8a92035d5d4681c178fccb991ce57f33aRobert Olsson */ 178419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olssonstatic int fn_trie_flush(struct fib_table *tb) 178519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 178619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 17879195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger struct leaf *l, *ll = NULL; 178882cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger int found = 0; 178919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 179082cfbb008572b1a953091ef78f767aa3ca213092Stephen Hemminger for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) { 1791ef3660ce0649fa10265455f539b72607cff53d02Stephen Hemminger found += trie_flush_leaf(l); 179219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 179319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (ll && hlist_empty(&ll->list)) 17949195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger trie_leaf_remove(t, ll); 179519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson ll = l; 179619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 179719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 179819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (ll && hlist_empty(&ll->list)) 17999195bef7fb0ba0a91d5ffa566bcf8e007e3c7172Stephen Hemminger trie_leaf_remove(t, ll); 180019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 18010c7770c740156c8802c23d24fc094d06967d997dStephen Hemminger pr_debug("trie_flush found=%d\n", found); 180219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return found; 180319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 180419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1805a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic void fn_trie_select_default(struct fib_table *tb, 1806a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger const struct flowi *flp, 1807a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger struct fib_result *res) 180819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 180919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 181019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int order, last_idx; 181119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *fi = NULL; 181219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *last_resort; 181319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_alias *fa = NULL; 181419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct list_head *fa_head; 181519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct leaf *l; 181619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 181719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson last_idx = -1; 181819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson last_resort = NULL; 181919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson order = -1; 182019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 18212373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_lock(); 1822c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 182319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson l = fib_find_node(t, 0); 1824c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!l) 182519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 182619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 182719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa_head = get_fa_head(l, 0); 1828c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (!fa_head) 182919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 183019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1831c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (list_empty(fa_head)) 183219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 183319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 18342373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_for_each_entry_rcu(fa, fa_head, fa_list) { 183519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_info *next_fi = fa->fa_info; 183691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 183719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (fa->fa_scope != res->scope || 183819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa->fa_type != RTN_UNICAST) 183919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 184091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 184119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (next_fi->fib_priority > res->fi->fib_priority) 184219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 184319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (!next_fi->fib_nh[0].nh_gw || 184419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) 184519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 184619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa->fa_state |= FA_S_ACCESSED; 184791b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 184819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (fi == NULL) { 184919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (next_fi != res->fi) 185019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson break; 185119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } else if (!fib_detect_death(fi, order, &last_resort, 1852971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunev &last_idx, tb->tb_default)) { 1853a2bbe6822f8928e254452765c07cb863633113b8Denis V. Lunev fib_result_assign(res, fi); 1854971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunev tb->tb_default = order; 185519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 185619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 185719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fi = next_fi; 185819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson order++; 185919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 186019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (order <= 0 || fi == NULL) { 1861971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunev tb->tb_default = -1; 186219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 186319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 186419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1865971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunev if (!fib_detect_death(fi, order, &last_resort, &last_idx, 1866971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunev tb->tb_default)) { 1867a2bbe6822f8928e254452765c07cb863633113b8Denis V. Lunev fib_result_assign(res, fi); 1868971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunev tb->tb_default = order; 186919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson goto out; 187019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1871a2bbe6822f8928e254452765c07cb863633113b8Denis V. Lunev if (last_idx >= 0) 1872a2bbe6822f8928e254452765c07cb863633113b8Denis V. Lunev fib_result_assign(res, last_resort); 1873971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunev tb->tb_default = last_idx; 1874971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunevout: 18752373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_unlock(); 187619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 187719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1878a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, 1879a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger struct fib_table *tb, 188019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct sk_buff *skb, struct netlink_callback *cb) 188119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 188219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson int i, s_i; 188319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_alias *fa; 188432ab5f80334fc067386c4c56c434010c01cff6b9Al Viro __be32 xkey = htonl(key); 188519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 188671d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger s_i = cb->args[5]; 188719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson i = 0; 188819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 18892373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson /* rcu_read_lock is hold by caller */ 18902373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 18912373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson list_for_each_entry_rcu(fa, fah, fa_list) { 189219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (i < s_i) { 189319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson i++; 189419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 189519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 189619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 189719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, 189819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson cb->nlh->nlmsg_seq, 189919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson RTM_NEWROUTE, 190019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_id, 190119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa->fa_type, 190219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa->fa_scope, 1903be403ea1856f1428b5912b42184acbba808c41d6Thomas Graf xkey, 190419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson plen, 190519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson fa->fa_tos, 190664347f786d13349d6a6f812f3a83c269e26c0136Stephen Hemminger fa->fa_info, NLM_F_MULTI) < 0) { 190771d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[5] = i; 190819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -1; 190991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 191019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson i++; 191119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 191271d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[5] = i; 191319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return skb->len; 191419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 191519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1916a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemmingerstatic int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb, 1917a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger struct sk_buff *skb, struct netlink_callback *cb) 191819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 1919a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger struct leaf_info *li; 1920a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger struct hlist_node *node; 1921a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger int i, s_i; 192219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 192371d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger s_i = cb->args[4]; 1924a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger i = 0; 192519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1926a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger /* rcu_read_lock is hold by caller */ 1927a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger hlist_for_each_entry_rcu(li, node, &l->list, hlist) { 1928a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (i < s_i) { 1929a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger i++; 193019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 1931a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger } 193291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 1933a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (i > s_i) 193471d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[5] = 0; 193519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1936a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (list_empty(&li->falh)) 193719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson continue; 193819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1939a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) { 194071d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[4] = i; 194119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return -1; 194219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1943a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger i++; 194419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1945a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger 194671d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[4] = i; 194719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return skb->len; 194819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 194919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 1950a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemmingerstatic int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, 1951a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger struct netlink_callback *cb) 195219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 1953a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger struct leaf *l; 195419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t = (struct trie *) tb->tb_data; 1955d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger t_key key = cb->args[2]; 195671d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger int count = cb->args[3]; 195719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 19582373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_lock(); 1959d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger /* Dump starting at last key. 1960d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger * Note: 0.0.0.0/0 (ie default) is first key. 1961d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger */ 196271d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger if (count == 0) 1963d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger l = trie_firstleaf(t); 1964d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger else { 196571d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger /* Normally, continue from last key, but if that is missing 196671d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger * fallback to using slow rescan 196771d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger */ 1968d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger l = fib_find_node(t, key); 196971d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger if (!l) 197071d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger l = trie_leafindex(t, count); 1971d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger } 1972a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger 1973d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger while (l) { 1974d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger cb->args[2] = l->key; 1975a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) { 197671d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[3] = count; 1977a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger rcu_read_unlock(); 1978a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger return -1; 197919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 1980d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger 198171d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger ++count; 1982d5ce8a0e97073169b5fe0b7c52bd020cdb017dfaStephen Hemminger l = trie_nextleaf(l); 198371d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger memset(&cb->args[4], 0, 198471d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger sizeof(cb->args) - 4*sizeof(cb->args[0])); 198519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 198671d67e666e73e3b7e9ef124745ee2e454ac04be8Stephen Hemminger cb->args[3] = count; 19872373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_unlock(); 1988a88ee229253b31e3a844b30525ff77fbfe3111d3Stephen Hemminger 198919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return skb->len; 199019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 199119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 19927f9b80529b8a2ad8b3273b15fb444a0e34b760a9Stephen Hemmingervoid __init fib_hash_init(void) 19937f9b80529b8a2ad8b3273b15fb444a0e34b760a9Stephen Hemminger{ 1994a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger fn_alias_kmem = kmem_cache_create("ip_fib_alias", 1995a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger sizeof(struct fib_alias), 1996bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger 0, SLAB_PANIC, NULL); 1997bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger 1998bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger trie_leaf_kmem = kmem_cache_create("ip_fib_trie", 1999bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger max(sizeof(struct leaf), 2000bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger sizeof(struct leaf_info)), 2001bc3c8c1e02ae89668239742fd592f21e1998fa46Stephen Hemminger 0, SLAB_PANIC, NULL); 20027f9b80529b8a2ad8b3273b15fb444a0e34b760a9Stephen Hemminger} 200319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 20047f9b80529b8a2ad8b3273b15fb444a0e34b760a9Stephen Hemminger 20057f9b80529b8a2ad8b3273b15fb444a0e34b760a9Stephen Hemminger/* Fix more generic FIB names for init later */ 20067f9b80529b8a2ad8b3273b15fb444a0e34b760a9Stephen Hemmingerstruct fib_table *fib_hash_table(u32 id) 200719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 200819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct fib_table *tb; 200919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson struct trie *t; 201019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 201119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie), 201219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson GFP_KERNEL); 201319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson if (tb == NULL) 201419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 201519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 201619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_id = id; 2017971b893e79db0f7dccfcea15dbdebca3ca64a84dDenis V. Lunev tb->tb_default = -1; 201819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_lookup = fn_trie_lookup; 201919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_insert = fn_trie_insert; 202019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_delete = fn_trie_delete; 202119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_flush = fn_trie_flush; 202219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_select_default = fn_trie_select_default; 202319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson tb->tb_dump = fn_trie_dump; 202419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 202519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson t = (struct trie *) tb->tb_data; 2026c28a1cf448e59019fa681741963c3acaeaeb6d27Stephen Hemminger memset(t, 0, sizeof(*t)); 202719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2028c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger if (id == RT_TABLE_LOCAL) 2029a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger pr_info("IPv4 FIB: Using LC-trie version %s\n", VERSION); 203019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 203119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return tb; 203219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 203319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2034cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger#ifdef CONFIG_PROC_FS 2035cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger/* Depth first Trie walk iterator */ 2036cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstruct fib_trie_iter { 20371c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev struct seq_net_private p; 20383d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct fib_table *tb; 2039cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct tnode *tnode; 2040cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger unsigned index; 2041cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger unsigned depth; 2042cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger}; 204319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2044cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic struct node *fib_trie_get_next(struct fib_trie_iter *iter) 204519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2046cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct tnode *tn = iter->tnode; 2047cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger unsigned cindex = iter->index; 2048cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct tnode *p; 204919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 20506640e69731b42fd5e3d2b26201c8b34fc897a0eeEric W. Biederman /* A single entry routing table */ 20516640e69731b42fd5e3d2b26201c8b34fc897a0eeEric W. Biederman if (!tn) 20526640e69731b42fd5e3d2b26201c8b34fc897a0eeEric W. Biederman return NULL; 20536640e69731b42fd5e3d2b26201c8b34fc897a0eeEric W. Biederman 2054cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger pr_debug("get_next iter={node=%p index=%d depth=%d}\n", 2055cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->tnode, iter->index, iter->depth); 2056cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerrescan: 2057cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger while (cindex < (1<<tn->bits)) { 2058b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet struct node *n = tnode_get_child_rcu(tn, cindex); 205919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2060cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (n) { 2061cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (IS_LEAF(n)) { 2062cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->tnode = tn; 2063cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->index = cindex + 1; 2064cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } else { 2065cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger /* push down one level */ 2066cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->tnode = (struct tnode *) n; 2067cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger iter->index = 0; 2068cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger ++iter->depth; 2069cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 2070cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return n; 2071cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 207219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2073cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger ++cindex; 2074cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 207591b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2076cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger /* Current node exhausted, pop back up */ 2077b59cfbf77dc8368c2c90b012c79553613f4d70c3Eric Dumazet p = node_parent_rcu((struct node *)tn); 2078cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (p) { 2079cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1; 2080cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger tn = p; 2081cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger --iter->depth; 2082cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger goto rescan; 208319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 2084cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 2085cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger /* got root? */ 2086cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return NULL; 208719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 208819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2089cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic struct node *fib_trie_get_first(struct fib_trie_iter *iter, 2090cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct trie *t) 209119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 20923d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct node *n; 20935ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson 2094132adf54639cf7dd9315e8df89c2faa59f6e46d9Stephen Hemminger if (!t) 20955ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson return NULL; 20965ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson 20975ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson n = rcu_dereference(t->trie); 20983d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (!n) 20995ddf0eb2bfd613e941dd8748870c71da2e5ad409Robert Olsson return NULL; 210019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 21013d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (IS_TNODE(n)) { 21023d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->tnode = (struct tnode *) n; 21033d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->index = 0; 21043d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->depth = 1; 21053d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } else { 21063d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->tnode = NULL; 21073d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->index = 0; 21083d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->depth = 0; 210991b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson } 21103d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 21113d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger return n; 2112cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 211391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2114cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void trie_collect_stats(struct trie *t, struct trie_stat *s) 2115cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 2116cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct node *n; 2117cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct fib_trie_iter iter; 211891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2119cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger memset(s, 0, sizeof(*s)); 212091b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2121cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger rcu_read_lock(); 21223d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) { 2123cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (IS_LEAF(n)) { 2124936722922f6d2366378de606a40c14f96915474dStephen Hemminger struct leaf *l = (struct leaf *)n; 2125936722922f6d2366378de606a40c14f96915474dStephen Hemminger struct leaf_info *li; 2126936722922f6d2366378de606a40c14f96915474dStephen Hemminger struct hlist_node *tmp; 2127936722922f6d2366378de606a40c14f96915474dStephen Hemminger 2128cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->leaves++; 2129cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->totdepth += iter.depth; 2130cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (iter.depth > s->maxdepth) 2131cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->maxdepth = iter.depth; 2132936722922f6d2366378de606a40c14f96915474dStephen Hemminger 2133936722922f6d2366378de606a40c14f96915474dStephen Hemminger hlist_for_each_entry_rcu(li, tmp, &l->list, hlist) 2134936722922f6d2366378de606a40c14f96915474dStephen Hemminger ++s->prefixes; 2135cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } else { 2136cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger const struct tnode *tn = (const struct tnode *) n; 2137cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger int i; 2138cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 2139cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->tnodes++; 2140132adf54639cf7dd9315e8df89c2faa59f6e46d9Stephen Hemminger if (tn->bits < MAX_STAT_DEPTH) 214106ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson s->nodesizes[tn->bits]++; 214206ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson 2143cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger for (i = 0; i < (1<<tn->bits); i++) 2144cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (!tn->child[i]) 2145cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger s->nullpointers++; 214619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 214719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 21482373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson rcu_read_unlock(); 214919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 215019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2151cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger/* 2152cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger * This outputs /proc/net/fib_triestats 2153cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger */ 2154cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void trie_show_stats(struct seq_file *seq, struct trie_stat *stat) 215519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2156cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger unsigned i, max, pointers, bytes, avdepth; 2157c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 2158cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (stat->leaves) 2159cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger avdepth = stat->totdepth*100 / stat->leaves; 2160cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger else 2161cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger avdepth = 0; 216291b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2163a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "\tAver depth: %u.%02d\n", 2164a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger avdepth / 100, avdepth % 100); 2165cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth); 216691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2167cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_printf(seq, "\tLeaves: %u\n", stat->leaves); 2168cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger bytes = sizeof(struct leaf) * stat->leaves; 2169936722922f6d2366378de606a40c14f96915474dStephen Hemminger 2170936722922f6d2366378de606a40c14f96915474dStephen Hemminger seq_printf(seq, "\tPrefixes: %u\n", stat->prefixes); 2171936722922f6d2366378de606a40c14f96915474dStephen Hemminger bytes += sizeof(struct leaf_info) * stat->prefixes; 2172936722922f6d2366378de606a40c14f96915474dStephen Hemminger 2173187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, "\tInternal nodes: %u\n\t", stat->tnodes); 2174cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger bytes += sizeof(struct tnode) * stat->tnodes; 217519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 217606ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson max = MAX_STAT_DEPTH; 217706ef921d60bbf6f765d1b9492fb4fc88ac7814bdRobert Olsson while (max > 0 && stat->nodesizes[max-1] == 0) 2178cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger max--; 217919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2180cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger pointers = 0; 2181cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger for (i = 1; i <= max; i++) 2182cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (stat->nodesizes[i] != 0) { 2183187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, " %u: %u", i, stat->nodesizes[i]); 2184cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger pointers += (1<<i) * stat->nodesizes[i]; 2185cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 2186cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_putc(seq, '\n'); 2187187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, "\tPointers: %u\n", pointers); 21882373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 2189cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger bytes += sizeof(struct node *) * pointers; 2190187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, "Null ptrs: %u\n", stat->nullpointers); 2191187b5188a78694fa6608fa1252d5197a7b3ab076Stephen Hemminger seq_printf(seq, "Total size: %u kB\n", (bytes + 1023) / 1024); 219266a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger} 21932373ce1ca04dd46bf2b8b0f9a799eb2a90da92fbRobert Olsson 2194cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger#ifdef CONFIG_IP_FIB_TRIE_STATS 219566a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemmingerstatic void trie_show_usage(struct seq_file *seq, 219666a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger const struct trie_use_stats *stats) 219766a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger{ 219866a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger seq_printf(seq, "\nCounters:\n---------\n"); 2199a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "gets = %u\n", stats->gets); 2200a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "backtracks = %u\n", stats->backtrack); 2201a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "semantic match passed = %u\n", 2202a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger stats->semantic_match_passed); 2203a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "semantic match miss = %u\n", 2204a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger stats->semantic_match_miss); 2205a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "null node hit= %u\n", stats->null_node_hit); 2206a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger seq_printf(seq, "skipped node resize = %u\n\n", 2207a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger stats->resize_node_skipped); 2208cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 220966a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger#endif /* CONFIG_IP_FIB_TRIE_STATS */ 221066a2f7fd2fddee1ddc5d1d286cd832e50a97258eStephen Hemminger 22113d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemmingerstatic void fib_table_print(struct seq_file *seq, struct fib_table *tb) 2212d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger{ 22133d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (tb->tb_id == RT_TABLE_LOCAL) 22143d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger seq_puts(seq, "Local:\n"); 22153d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger else if (tb->tb_id == RT_TABLE_MAIN) 22163d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger seq_puts(seq, "Main:\n"); 22173d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger else 22183d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger seq_printf(seq, "Id %d:\n", tb->tb_id); 2219d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger} 222019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 22213d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 2222cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_triestat_seq_show(struct seq_file *seq, void *v) 2223cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 22241c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev struct net *net = (struct net *)seq->private; 22253d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger unsigned int h; 2226877a9bff3889512d7326d6bf0ba6ed3ddda6d772Eric W. Biederman 2227d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger seq_printf(seq, 2228a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger "Basic info: size of leaf:" 2229a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger " %Zd bytes, size of tnode: %Zd bytes.\n", 2230d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger sizeof(struct leaf), sizeof(struct tnode)); 2231d717a9a62049a03e85c3c2dd3399416eeb34a8beStephen Hemminger 22323d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger for (h = 0; h < FIB_TABLE_HASHSZ; h++) { 22333d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_head *head = &net->ipv4.fib_table_hash[h]; 22343d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_node *node; 22353d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct fib_table *tb; 22363d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 22373d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { 22383d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct trie *t = (struct trie *) tb->tb_data; 22393d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct trie_stat stat; 2240877a9bff3889512d7326d6bf0ba6ed3ddda6d772Eric W. Biederman 22413d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (!t) 22423d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger continue; 22433d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 22443d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger fib_table_print(seq, tb); 22453d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 22463d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger trie_collect_stats(t, &stat); 22473d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger trie_show_stats(seq, &stat); 22483d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger#ifdef CONFIG_IP_FIB_TRIE_STATS 22493d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger trie_show_usage(seq, &t->stats); 22503d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger#endif 22513d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 22523d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 225319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2254cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return 0; 225519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 225619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2257cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_triestat_seq_open(struct inode *inode, struct file *file) 225819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 22591c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev int err; 22601c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev struct net *net; 22611c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev 22621c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev net = get_proc_net(inode); 22631c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev if (net == NULL) 22641c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev return -ENXIO; 22651c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev err = single_open(file, fib_triestat_seq_show, net); 22661c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev if (err < 0) { 22671c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev put_net(net); 22681c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev return err; 22691c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev } 22701c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev return 0; 22711c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev} 22721c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev 22731c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunevstatic int fib_triestat_seq_release(struct inode *ino, struct file *f) 22741c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev{ 22751c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev struct seq_file *seq = f->private_data; 22761c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev put_net(seq->private); 22771c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev return single_release(ino, f); 227819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 227919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 22809a32144e9d7b4e21341174b1a83b82a82353be86Arjan van de Venstatic const struct file_operations fib_triestat_fops = { 2281cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .owner = THIS_MODULE, 2282cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .open = fib_triestat_seq_open, 2283cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .read = seq_read, 2284cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .llseek = seq_lseek, 22851c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev .release = fib_triestat_seq_release, 2286cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger}; 2287cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 22881218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideakistatic struct node *fib_trie_get_idx(struct seq_file *seq, loff_t pos) 228919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 22901218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct fib_trie_iter *iter = seq->private; 22911218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 2292cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger loff_t idx = 0; 22933d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger unsigned int h; 2294cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 22953d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger for (h = 0; h < FIB_TABLE_HASHSZ; h++) { 22963d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_head *head = &net->ipv4.fib_table_hash[h]; 22973d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_node *node; 22983d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct fib_table *tb; 2299cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 23003d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { 23013d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct node *n; 23023d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 23033d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger for (n = fib_trie_get_first(iter, 23043d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger (struct trie *) tb->tb_data); 23053d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger n; n = fib_trie_get_next(iter)) 23063d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (pos == idx++) { 23073d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->tb = tb; 23083d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger return n; 23093d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 23103d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 2311cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 23123d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 231319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return NULL; 231419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 231519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2316cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) 2317c95aaf9af5a1f6dee56d1f2ab4915cd722d608daStephen Hemminger __acquires(RCU) 231819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2319cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger rcu_read_lock(); 23201218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki return fib_trie_get_idx(seq, *pos); 232119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 232219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2323cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) 232419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2325cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct fib_trie_iter *iter = seq->private; 23261218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 23273d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct fib_table *tb = iter->tb; 23283d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_node *tb_node; 23293d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger unsigned int h; 23303d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct node *n; 2331cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 233219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson ++*pos; 23333d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger /* next node in same table */ 23343d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger n = fib_trie_get_next(iter); 23353d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (n) 23363d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger return n; 233719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 23383d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger /* walk rest of this hash chain */ 23393d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger h = tb->tb_id & (FIB_TABLE_HASHSZ - 1); 23403d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) { 23413d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger tb = hlist_entry(tb_node, struct fib_table, tb_hlist); 23423d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); 23433d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (n) 23443d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger goto found; 23453d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 234619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 23473d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger /* new hash chain */ 23483d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger while (++h < FIB_TABLE_HASHSZ) { 23493d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger struct hlist_head *head = &net->ipv4.fib_table_hash[h]; 23503d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger hlist_for_each_entry_rcu(tb, tb_node, head, tb_hlist) { 23513d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); 23523d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (n) 23533d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger goto found; 23543d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 23553d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger } 2356cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return NULL; 23573d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger 23583d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemmingerfound: 23593d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger iter->tb = tb; 23603d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger return n; 2361cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 236219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2363cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void fib_trie_seq_stop(struct seq_file *seq, void *v) 2364c95aaf9af5a1f6dee56d1f2ab4915cd722d608daStephen Hemminger __releases(RCU) 236519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2366cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger rcu_read_unlock(); 2367cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 236891b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2369cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic void seq_indent(struct seq_file *seq, int n) 2370cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 2371cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger while (n-- > 0) seq_puts(seq, " "); 2372cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 237319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 237428d36e3702fcbed73c38e877bcf2a8f8946b7f3dEric Dumazetstatic inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s) 2375cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 2376132adf54639cf7dd9315e8df89c2faa59f6e46d9Stephen Hemminger switch (s) { 2377cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_UNIVERSE: return "universe"; 2378cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_SITE: return "site"; 2379cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_LINK: return "link"; 2380cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_HOST: return "host"; 2381cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger case RT_SCOPE_NOWHERE: return "nowhere"; 2382cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger default: 238328d36e3702fcbed73c38e877bcf2a8f8946b7f3dEric Dumazet snprintf(buf, len, "scope=%d", s); 2384cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return buf; 2385cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 2386cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger} 238719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2388cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic const char *rtn_type_names[__RTN_MAX] = { 2389cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_UNSPEC] = "UNSPEC", 2390cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_UNICAST] = "UNICAST", 2391cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_LOCAL] = "LOCAL", 2392cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_BROADCAST] = "BROADCAST", 2393cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_ANYCAST] = "ANYCAST", 2394cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_MULTICAST] = "MULTICAST", 2395cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_BLACKHOLE] = "BLACKHOLE", 2396cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_UNREACHABLE] = "UNREACHABLE", 2397cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_PROHIBIT] = "PROHIBIT", 2398cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_THROW] = "THROW", 2399cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_NAT] = "NAT", 2400cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [RTN_XRESOLVE] = "XRESOLVE", 2401cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger}; 240219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 240328d36e3702fcbed73c38e877bcf2a8f8946b7f3dEric Dumazetstatic inline const char *rtn_type(char *buf, size_t len, unsigned t) 2404cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger{ 2405cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (t < __RTN_MAX && rtn_type_names[t]) 2406cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return rtn_type_names[t]; 240728d36e3702fcbed73c38e877bcf2a8f8946b7f3dEric Dumazet snprintf(buf, len, "type %u", t); 2408cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return buf; 240919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 241019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2411cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger/* Pretty print the trie */ 2412cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_trie_seq_show(struct seq_file *seq, void *v) 241319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2414cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger const struct fib_trie_iter *iter = seq->private; 2415cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct node *n = v; 2416c877efb207bf4629cfa97ac13412f7392a873485Stephen Hemminger 24173d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger if (!node_parent_rcu(n)) 24183d3b2d25a4debaff05a9e6f5c55a0d31e4334234Stephen Hemminger fib_table_print(seq, iter->tb); 2419095b8501e4168ae5a879fcb9420ac48cbd43f95aRobert Olsson 2420cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (IS_TNODE(n)) { 2421cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct tnode *tn = (struct tnode *) n; 2422ab66b4a7a3969077f6e2a18a0d2d849d3b84a337Stephen Hemminger __be32 prf = htonl(mask_pfx(tn->key, tn->pos)); 242391b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 24241d25cd6cc2528e4af12ab18e84fe95ed78f3f21aRobert Olsson seq_indent(seq, iter->depth-1); 2425a7d632b6b4ad1c92746ed409e41f9dc571ec04e2YOSHIFUJI Hideaki seq_printf(seq, " +-- " NIPQUAD_FMT "/%d %d %d %d\n", 2426e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, 24271d25cd6cc2528e4af12ab18e84fe95ed78f3f21aRobert Olsson tn->empty_children); 2428e905a9edab7f4f14f9213b52234e4a346c690911YOSHIFUJI Hideaki 2429cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } else { 2430cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct leaf *l = (struct leaf *) n; 24311328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct leaf_info *li; 24321328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct hlist_node *node; 243332ab5f80334fc067386c4c56c434010c01cff6b9Al Viro __be32 val = htonl(l->key); 2434cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 2435cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_indent(seq, iter->depth); 2436a7d632b6b4ad1c92746ed409e41f9dc571ec04e2YOSHIFUJI Hideaki seq_printf(seq, " |-- " NIPQUAD_FMT "\n", NIPQUAD(val)); 24371328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger 24381328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger hlist_for_each_entry_rcu(li, node, &l->list, hlist) { 24391328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct fib_alias *fa; 24401328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger 24411328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger list_for_each_entry_rcu(fa, &li->falh, fa_list) { 24421328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger char buf1[32], buf2[32]; 24431328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger 24441328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger seq_indent(seq, iter->depth+1); 24451328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger seq_printf(seq, " /%d %s %s", li->plen, 24461328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger rtn_scope(buf1, sizeof(buf1), 24471328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger fa->fa_scope), 24481328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger rtn_type(buf2, sizeof(buf2), 24491328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger fa->fa_type)); 24501328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger if (fa->fa_tos) 2451b9c4d82a853713d49ac53b507964d7cf30ee408dDenis V. Lunev seq_printf(seq, " tos=%d", fa->fa_tos); 24521328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger seq_putc(seq, '\n'); 2453cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 2454cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 245519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 2456cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 245719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 245819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 245919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2460f690808e17925fc45217eb22e8670902ecee5c1bStephen Hemmingerstatic const struct seq_operations fib_trie_seq_ops = { 2461cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .start = fib_trie_seq_start, 2462cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .next = fib_trie_seq_next, 2463cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .stop = fib_trie_seq_stop, 2464cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .show = fib_trie_seq_show, 246519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 246619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2467cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_trie_seq_open(struct inode *inode, struct file *file) 246819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 24691c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev return seq_open_net(inode, file, &fib_trie_seq_ops, 24701c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev sizeof(struct fib_trie_iter)); 247119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 247219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 24739a32144e9d7b4e21341174b1a83b82a82353be86Arjan van de Venstatic const struct file_operations fib_trie_fops = { 2474cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .owner = THIS_MODULE, 2475cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .open = fib_trie_seq_open, 2476cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .read = seq_read, 2477cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .llseek = seq_lseek, 24781c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev .release = seq_release_net, 247919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 248019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 24818315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstruct fib_route_iter { 24828315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct seq_net_private p; 24838315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct trie *main_trie; 24848315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger loff_t pos; 24858315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger t_key key; 24868315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger}; 24878315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24888315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstatic struct leaf *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos) 24898315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger{ 24908315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct leaf *l = NULL; 24918315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct trie *t = iter->main_trie; 24928315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 24938315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger /* use cache location of last found key */ 24948315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (iter->pos > 0 && pos >= iter->pos && (l = fib_find_node(t, iter->key))) 24958315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger pos -= iter->pos; 24968315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger else { 24978315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos = 0; 24988315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger l = trie_firstleaf(t); 24998315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger } 25008315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25018315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger while (l && pos-- > 0) { 25028315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos++; 25038315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger l = trie_nextleaf(l); 25048315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger } 25058315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25068315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (l) 25078315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->key = pos; /* remember it */ 25088315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger else 25098315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos = 0; /* forget it */ 25108315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25118315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return l; 25128315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger} 25138315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25148315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstatic void *fib_route_seq_start(struct seq_file *seq, loff_t *pos) 25158315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger __acquires(RCU) 25168315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger{ 25178315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct fib_route_iter *iter = seq->private; 25188315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct fib_table *tb; 25198315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25208315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger rcu_read_lock(); 25211218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki tb = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN); 25228315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (!tb) 25238315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return NULL; 25248315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25258315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->main_trie = (struct trie *) tb->tb_data; 25268315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (*pos == 0) 25278315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return SEQ_START_TOKEN; 25288315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger else 25298315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return fib_route_get_idx(iter, *pos - 1); 25308315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger} 25318315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25328315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstatic void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos) 25338315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger{ 25348315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct fib_route_iter *iter = seq->private; 25358315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger struct leaf *l = v; 25368315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25378315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger ++*pos; 25388315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (v == SEQ_START_TOKEN) { 25398315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos = 0; 25408315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger l = trie_firstleaf(iter->main_trie); 25418315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger } else { 25428315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos++; 25438315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger l = trie_nextleaf(l); 25448315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger } 25458315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25468315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger if (l) 25478315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->key = l->key; 25488315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger else 25498315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger iter->pos = 0; 25508315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger return l; 25518315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger} 25528315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 25538315f5d80a90247bf92232f92ca49933ac49327bStephen Hemmingerstatic void fib_route_seq_stop(struct seq_file *seq, void *v) 25548315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger __releases(RCU) 25558315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger{ 25568315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger rcu_read_unlock(); 25578315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger} 25588315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger 255932ab5f80334fc067386c4c56c434010c01cff6b9Al Virostatic unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) 256019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2561cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger static unsigned type2flags[RTN_MAX + 1] = { 2562cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger [7] = RTF_REJECT, [8] = RTF_REJECT, 2563cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger }; 2564cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger unsigned flags = type2flags[type]; 256519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2566cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (fi && fi->fib_nh->nh_gw) 2567cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger flags |= RTF_GATEWAY; 256832ab5f80334fc067386c4c56c434010c01cff6b9Al Viro if (mask == htonl(0xFFFFFFFF)) 2569cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger flags |= RTF_HOST; 2570cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger flags |= RTF_UP; 2571cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return flags; 257219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 257319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2574cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger/* 2575cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger * This outputs /proc/net/route. 2576cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger * The format of the file is not supposed to be changed 2577cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger * and needs to be same as fib_hash output to avoid breaking 2578cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger * legacy utilities 2579cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger */ 2580cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_route_seq_show(struct seq_file *seq, void *v) 258119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 2582cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct leaf *l = v; 25831328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct leaf_info *li; 25841328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger struct hlist_node *node; 258519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2586cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (v == SEQ_START_TOKEN) { 2587cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway " 2588cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU" 2589cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger "\tWindow\tIRTT"); 2590cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return 0; 2591cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 259219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 25931328042e268c936189f15eba5bd9a5a4605a8581Stephen Hemminger hlist_for_each_entry_rcu(li, node, &l->list, hlist) { 2594cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger struct fib_alias *fa; 259532ab5f80334fc067386c4c56c434010c01cff6b9Al Viro __be32 mask, prefix; 259691b9a277fc4d207249e459a455abf804ebb5499dOlof Johansson 2597cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger mask = inet_make_mask(li->plen); 2598cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger prefix = htonl(l->key); 259919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2600cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger list_for_each_entry_rcu(fa, &li->falh, fa_list) { 26011371e37da299d4df6267ad0ddf010435782c28e9Herbert Xu const struct fib_info *fi = fa->fa_info; 2602cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger unsigned flags = fib_flag_trans(fa->fa_type, mask, fi); 26035e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov int len; 260419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2605cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (fa->fa_type == RTN_BROADCAST 2606cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger || fa->fa_type == RTN_MULTICAST) 2607cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger continue; 260819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2609cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger if (fi) 26105e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov seq_printf(seq, 26115e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov "%s\t%08X\t%08X\t%04X\t%d\t%u\t" 26125e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov "%d\t%08X\t%d\t%u\t%u%n", 2613cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger fi->fib_dev ? fi->fib_dev->name : "*", 2614cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger prefix, 2615cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger fi->fib_nh->nh_gw, flags, 0, 0, 2616cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger fi->fib_priority, 2617cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger mask, 2618a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger (fi->fib_advmss ? 2619a07f5f508a4d9728c8e57d7f66294bf5b254ff7fStephen Hemminger fi->fib_advmss + 40 : 0), 2620cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger fi->fib_window, 26215e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov fi->fib_rtt >> 3, &len); 2622cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger else 26235e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov seq_printf(seq, 26245e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov "*\t%08X\t%08X\t%04X\t%d\t%u\t" 26255e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov "%d\t%08X\t%d\t%u\t%u%n", 2626cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger prefix, 0, flags, 0, 0, 0, 26275e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov mask, 0, 0, 0, &len); 262819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 26295e659e4cb0eedacdc1f621a61e400a4611ddef8aPavel Emelyanov seq_printf(seq, "%*s\n", 127 - len, ""); 2630cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger } 263119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson } 263219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 263319baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 263419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 263519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2636f690808e17925fc45217eb22e8670902ecee5c1bStephen Hemmingerstatic const struct seq_operations fib_route_seq_ops = { 26378315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger .start = fib_route_seq_start, 26388315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger .next = fib_route_seq_next, 26398315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger .stop = fib_route_seq_stop, 2640cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .show = fib_route_seq_show, 264119baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 264219baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 2643cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerstatic int fib_route_seq_open(struct inode *inode, struct file *file) 264419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 26451c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev return seq_open_net(inode, file, &fib_route_seq_ops, 26468315f5d80a90247bf92232f92ca49933ac49327bStephen Hemminger sizeof(struct fib_route_iter)); 264719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 264819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 26499a32144e9d7b4e21341174b1a83b82a82353be86Arjan van de Venstatic const struct file_operations fib_route_fops = { 2650cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .owner = THIS_MODULE, 2651cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .open = fib_route_seq_open, 2652cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .read = seq_read, 2653cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger .llseek = seq_lseek, 26541c340b2fd73880136c438e6e7978288fbec8273fDenis V. Lunev .release = seq_release_net, 265519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson}; 265619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 265761a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunevint __net_init fib_proc_init(struct net *net) 265819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 265961a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev if (!proc_net_fops_create(net, "fib_trie", S_IRUGO, &fib_trie_fops)) 2660cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger goto out1; 2661cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 266261a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev if (!proc_net_fops_create(net, "fib_triestat", S_IRUGO, 266361a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev &fib_triestat_fops)) 2664cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger goto out2; 2665cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 266661a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev if (!proc_net_fops_create(net, "route", S_IRUGO, &fib_route_fops)) 2667cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger goto out3; 2668cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 266919baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson return 0; 2670cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger 2671cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerout3: 267261a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "fib_triestat"); 2673cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerout2: 267461a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "fib_trie"); 2675cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemmingerout1: 2676cb7b593c2c808b32a1ea188599713c434b95f849Stephen Hemminger return -ENOMEM; 267719baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 267819baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 267961a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunevvoid __net_exit fib_proc_exit(struct net *net) 268019baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson{ 268161a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "fib_trie"); 268261a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "fib_triestat"); 268361a0265344786a548e8a0b26cb668e78a71f9602Denis V. Lunev proc_net_remove(net, "route"); 268419baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson} 268519baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson 268619baf839ff4a8daa1f2a7400897094fc18e4f5e9Robert Olsson#endif /* CONFIG_PROC_FS */ 2687