aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_trie.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r--net/ipv4/fib_trie.c104
1 files changed, 67 insertions, 37 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index f2f47033f31f..35851c96bdfb 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1205,20 +1205,45 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
1205 * and we need to allocate a new one of those as well. 1205 * and we need to allocate a new one of those as well.
1206 */ 1206 */
1207 1207
1208 if (fa && fa->fa_info->fib_priority == fi->fib_priority) { 1208 if (fa && fa->fa_tos == tos &&
1209 struct fib_alias *fa_orig; 1209 fa->fa_info->fib_priority == fi->fib_priority) {
1210 struct fib_alias *fa_first, *fa_match;
1210 1211
1211 err = -EEXIST; 1212 err = -EEXIST;
1212 if (cfg->fc_nlflags & NLM_F_EXCL) 1213 if (cfg->fc_nlflags & NLM_F_EXCL)
1213 goto out; 1214 goto out;
1214 1215
1216 /* We have 2 goals:
1217 * 1. Find exact match for type, scope, fib_info to avoid
1218 * duplicate routes
1219 * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it
1220 */
1221 fa_match = NULL;
1222 fa_first = fa;
1223 fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
1224 list_for_each_entry_continue(fa, fa_head, fa_list) {
1225 if (fa->fa_tos != tos)
1226 break;
1227 if (fa->fa_info->fib_priority != fi->fib_priority)
1228 break;
1229 if (fa->fa_type == cfg->fc_type &&
1230 fa->fa_scope == cfg->fc_scope &&
1231 fa->fa_info == fi) {
1232 fa_match = fa;
1233 break;
1234 }
1235 }
1236
1215 if (cfg->fc_nlflags & NLM_F_REPLACE) { 1237 if (cfg->fc_nlflags & NLM_F_REPLACE) {
1216 struct fib_info *fi_drop; 1238 struct fib_info *fi_drop;
1217 u8 state; 1239 u8 state;
1218 1240
1219 if (fi->fib_treeref > 1) 1241 fa = fa_first;
1242 if (fa_match) {
1243 if (fa == fa_match)
1244 err = 0;
1220 goto out; 1245 goto out;
1221 1246 }
1222 err = -ENOBUFS; 1247 err = -ENOBUFS;
1223 new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); 1248 new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
1224 if (new_fa == NULL) 1249 if (new_fa == NULL)
@@ -1230,7 +1255,7 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
1230 new_fa->fa_type = cfg->fc_type; 1255 new_fa->fa_type = cfg->fc_type;
1231 new_fa->fa_scope = cfg->fc_scope; 1256 new_fa->fa_scope = cfg->fc_scope;
1232 state = fa->fa_state; 1257 state = fa->fa_state;
1233 new_fa->fa_state &= ~FA_S_ACCESSED; 1258 new_fa->fa_state = state & ~FA_S_ACCESSED;
1234 1259
1235 list_replace_rcu(&fa->fa_list, &new_fa->fa_list); 1260 list_replace_rcu(&fa->fa_list, &new_fa->fa_list);
1236 alias_free_mem_rcu(fa); 1261 alias_free_mem_rcu(fa);
@@ -1247,20 +1272,11 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
1247 * uses the same scope, type, and nexthop 1272 * uses the same scope, type, and nexthop
1248 * information. 1273 * information.
1249 */ 1274 */
1250 fa_orig = fa; 1275 if (fa_match)
1251 list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) { 1276 goto out;
1252 if (fa->fa_tos != tos)
1253 break;
1254 if (fa->fa_info->fib_priority != fi->fib_priority)
1255 break;
1256 if (fa->fa_type == cfg->fc_type &&
1257 fa->fa_scope == cfg->fc_scope &&
1258 fa->fa_info == fi)
1259 goto out;
1260 }
1261 1277
1262 if (!(cfg->fc_nlflags & NLM_F_APPEND)) 1278 if (!(cfg->fc_nlflags & NLM_F_APPEND))
1263 fa = fa_orig; 1279 fa = fa_first;
1264 } 1280 }
1265 err = -ENOENT; 1281 err = -ENOENT;
1266 if (!(cfg->fc_nlflags & NLM_F_CREATE)) 1282 if (!(cfg->fc_nlflags & NLM_F_CREATE))
@@ -1600,9 +1616,8 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
1600 pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t); 1616 pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
1601 1617
1602 fa_to_delete = NULL; 1618 fa_to_delete = NULL;
1603 fa_head = fa->fa_list.prev; 1619 fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
1604 1620 list_for_each_entry_continue(fa, fa_head, fa_list) {
1605 list_for_each_entry(fa, fa_head, fa_list) {
1606 struct fib_info *fi = fa->fa_info; 1621 struct fib_info *fi = fa->fa_info;
1607 1622
1608 if (fa->fa_tos != tos) 1623 if (fa->fa_tos != tos)
@@ -1743,6 +1758,19 @@ static struct leaf *trie_nextleaf(struct leaf *l)
1743 return leaf_walk_rcu(p, c); 1758 return leaf_walk_rcu(p, c);
1744} 1759}
1745 1760
1761static struct leaf *trie_leafindex(struct trie *t, int index)
1762{
1763 struct leaf *l = trie_firstleaf(t);
1764
1765 while (index-- > 0) {
1766 l = trie_nextleaf(l);
1767 if (!l)
1768 break;
1769 }
1770 return l;
1771}
1772
1773
1746/* 1774/*
1747 * Caller must hold RTNL. 1775 * Caller must hold RTNL.
1748 */ 1776 */
@@ -1848,7 +1876,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
1848 struct fib_alias *fa; 1876 struct fib_alias *fa;
1849 __be32 xkey = htonl(key); 1877 __be32 xkey = htonl(key);
1850 1878
1851 s_i = cb->args[4]; 1879 s_i = cb->args[5];
1852 i = 0; 1880 i = 0;
1853 1881
1854 /* rcu_read_lock is hold by caller */ 1882 /* rcu_read_lock is hold by caller */
@@ -1869,12 +1897,12 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
1869 plen, 1897 plen,
1870 fa->fa_tos, 1898 fa->fa_tos,
1871 fa->fa_info, NLM_F_MULTI) < 0) { 1899 fa->fa_info, NLM_F_MULTI) < 0) {
1872 cb->args[4] = i; 1900 cb->args[5] = i;
1873 return -1; 1901 return -1;
1874 } 1902 }
1875 i++; 1903 i++;
1876 } 1904 }
1877 cb->args[4] = i; 1905 cb->args[5] = i;
1878 return skb->len; 1906 return skb->len;
1879} 1907}
1880 1908
@@ -1885,7 +1913,7 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
1885 struct hlist_node *node; 1913 struct hlist_node *node;
1886 int i, s_i; 1914 int i, s_i;
1887 1915
1888 s_i = cb->args[3]; 1916 s_i = cb->args[4];
1889 i = 0; 1917 i = 0;
1890 1918
1891 /* rcu_read_lock is hold by caller */ 1919 /* rcu_read_lock is hold by caller */
@@ -1896,19 +1924,19 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
1896 } 1924 }
1897 1925
1898 if (i > s_i) 1926 if (i > s_i)
1899 cb->args[4] = 0; 1927 cb->args[5] = 0;
1900 1928
1901 if (list_empty(&li->falh)) 1929 if (list_empty(&li->falh))
1902 continue; 1930 continue;
1903 1931
1904 if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) { 1932 if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) {
1905 cb->args[3] = i; 1933 cb->args[4] = i;
1906 return -1; 1934 return -1;
1907 } 1935 }
1908 i++; 1936 i++;
1909 } 1937 }
1910 1938
1911 cb->args[3] = i; 1939 cb->args[4] = i;
1912 return skb->len; 1940 return skb->len;
1913} 1941}
1914 1942
@@ -1918,35 +1946,37 @@ static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
1918 struct leaf *l; 1946 struct leaf *l;
1919 struct trie *t = (struct trie *) tb->tb_data; 1947 struct trie *t = (struct trie *) tb->tb_data;
1920 t_key key = cb->args[2]; 1948 t_key key = cb->args[2];
1949 int count = cb->args[3];
1921 1950
1922 rcu_read_lock(); 1951 rcu_read_lock();
1923 /* Dump starting at last key. 1952 /* Dump starting at last key.
1924 * Note: 0.0.0.0/0 (ie default) is first key. 1953 * Note: 0.0.0.0/0 (ie default) is first key.
1925 */ 1954 */
1926 if (!key) 1955 if (count == 0)
1927 l = trie_firstleaf(t); 1956 l = trie_firstleaf(t);
1928 else { 1957 else {
1958 /* Normally, continue from last key, but if that is missing
1959 * fallback to using slow rescan
1960 */
1929 l = fib_find_node(t, key); 1961 l = fib_find_node(t, key);
1930 if (!l) { 1962 if (!l)
1931 /* The table changed during the dump, rather than 1963 l = trie_leafindex(t, count);
1932 * giving partial data, just make application retry.
1933 */
1934 rcu_read_unlock();
1935 return -EBUSY;
1936 }
1937 } 1964 }
1938 1965
1939 while (l) { 1966 while (l) {
1940 cb->args[2] = l->key; 1967 cb->args[2] = l->key;
1941 if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) { 1968 if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
1969 cb->args[3] = count;
1942 rcu_read_unlock(); 1970 rcu_read_unlock();
1943 return -1; 1971 return -1;
1944 } 1972 }
1945 1973
1974 ++count;
1946 l = trie_nextleaf(l); 1975 l = trie_nextleaf(l);
1947 memset(&cb->args[3], 0, 1976 memset(&cb->args[4], 0,
1948 sizeof(cb->args) - 3*sizeof(cb->args[0])); 1977 sizeof(cb->args) - 4*sizeof(cb->args[0]));
1949 } 1978 }
1979 cb->args[3] = count;
1950 rcu_read_unlock(); 1980 rcu_read_unlock();
1951 1981
1952 return skb->len; 1982 return skb->len;