diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/fib_rules.c | 8 | ||||
-rw-r--r-- | net/ipv4/fib_frontend.c | 59 | ||||
-rw-r--r-- | net/ipv4/fib_lookup.h | 1 | ||||
-rw-r--r-- | net/ipv4/fib_rules.c | 20 | ||||
-rw-r--r-- | net/ipv4/fib_trie.c | 172 |
5 files changed, 240 insertions, 20 deletions
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 44706e81b2e0..b55677fed1c8 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -492,6 +492,12 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) | |||
492 | goto errout; | 492 | goto errout; |
493 | } | 493 | } |
494 | 494 | ||
495 | if (ops->delete) { | ||
496 | err = ops->delete(rule); | ||
497 | if (err) | ||
498 | goto errout; | ||
499 | } | ||
500 | |||
495 | list_del_rcu(&rule->list); | 501 | list_del_rcu(&rule->list); |
496 | 502 | ||
497 | if (rule->action == FR_ACT_GOTO) { | 503 | if (rule->action == FR_ACT_GOTO) { |
@@ -517,8 +523,6 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) | |||
517 | 523 | ||
518 | notify_rule_change(RTM_DELRULE, rule, ops, nlh, | 524 | notify_rule_change(RTM_DELRULE, rule, ops, nlh, |
519 | NETLINK_CB(skb).portid); | 525 | NETLINK_CB(skb).portid); |
520 | if (ops->delete) | ||
521 | ops->delete(rule); | ||
522 | fib_rule_put(rule); | 526 | fib_rule_put(rule); |
523 | flush_route_cache(ops); | 527 | flush_route_cache(ops); |
524 | rules_ops_put(ops); | 528 | rules_ops_put(ops); |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index e067770235bf..7cda3b0521d8 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -52,14 +52,14 @@ static int __net_init fib4_rules_init(struct net *net) | |||
52 | { | 52 | { |
53 | struct fib_table *local_table, *main_table; | 53 | struct fib_table *local_table, *main_table; |
54 | 54 | ||
55 | local_table = fib_trie_table(RT_TABLE_LOCAL); | 55 | main_table = fib_trie_table(RT_TABLE_MAIN, NULL); |
56 | if (local_table == NULL) | ||
57 | return -ENOMEM; | ||
58 | |||
59 | main_table = fib_trie_table(RT_TABLE_MAIN); | ||
60 | if (main_table == NULL) | 56 | if (main_table == NULL) |
61 | goto fail; | 57 | goto fail; |
62 | 58 | ||
59 | local_table = fib_trie_table(RT_TABLE_LOCAL, main_table); | ||
60 | if (local_table == NULL) | ||
61 | return -ENOMEM; | ||
62 | |||
63 | hlist_add_head_rcu(&local_table->tb_hlist, | 63 | hlist_add_head_rcu(&local_table->tb_hlist, |
64 | &net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]); | 64 | &net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]); |
65 | hlist_add_head_rcu(&main_table->tb_hlist, | 65 | hlist_add_head_rcu(&main_table->tb_hlist, |
@@ -74,7 +74,7 @@ fail: | |||
74 | 74 | ||
75 | struct fib_table *fib_new_table(struct net *net, u32 id) | 75 | struct fib_table *fib_new_table(struct net *net, u32 id) |
76 | { | 76 | { |
77 | struct fib_table *tb; | 77 | struct fib_table *tb, *alias = NULL; |
78 | unsigned int h; | 78 | unsigned int h; |
79 | 79 | ||
80 | if (id == 0) | 80 | if (id == 0) |
@@ -83,7 +83,10 @@ struct fib_table *fib_new_table(struct net *net, u32 id) | |||
83 | if (tb) | 83 | if (tb) |
84 | return tb; | 84 | return tb; |
85 | 85 | ||
86 | tb = fib_trie_table(id); | 86 | if (id == RT_TABLE_LOCAL) |
87 | alias = fib_new_table(net, RT_TABLE_MAIN); | ||
88 | |||
89 | tb = fib_trie_table(id, alias); | ||
87 | if (!tb) | 90 | if (!tb) |
88 | return NULL; | 91 | return NULL; |
89 | 92 | ||
@@ -126,6 +129,48 @@ struct fib_table *fib_get_table(struct net *net, u32 id) | |||
126 | } | 129 | } |
127 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ | 130 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ |
128 | 131 | ||
132 | static void fib_replace_table(struct net *net, struct fib_table *old, | ||
133 | struct fib_table *new) | ||
134 | { | ||
135 | #ifdef CONFIG_IP_MULTIPLE_TABLES | ||
136 | switch (new->tb_id) { | ||
137 | case RT_TABLE_LOCAL: | ||
138 | rcu_assign_pointer(net->ipv4.fib_local, new); | ||
139 | break; | ||
140 | case RT_TABLE_MAIN: | ||
141 | rcu_assign_pointer(net->ipv4.fib_main, new); | ||
142 | break; | ||
143 | case RT_TABLE_DEFAULT: | ||
144 | rcu_assign_pointer(net->ipv4.fib_default, new); | ||
145 | break; | ||
146 | default: | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | #endif | ||
151 | /* replace the old table in the hlist */ | ||
152 | hlist_replace_rcu(&old->tb_hlist, &new->tb_hlist); | ||
153 | } | ||
154 | |||
155 | int fib_unmerge(struct net *net) | ||
156 | { | ||
157 | struct fib_table *old, *new; | ||
158 | |||
159 | old = fib_get_table(net, RT_TABLE_LOCAL); | ||
160 | new = fib_trie_unmerge(old); | ||
161 | |||
162 | if (!new) | ||
163 | return -ENOMEM; | ||
164 | |||
165 | /* replace merged table with clean table */ | ||
166 | if (new != old) { | ||
167 | fib_replace_table(net, old, new); | ||
168 | fib_free_table(old); | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
129 | static void fib_flush(struct net *net) | 174 | static void fib_flush(struct net *net) |
130 | { | 175 | { |
131 | int flushed = 0; | 176 | int flushed = 0; |
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h index ae2e6eede46e..c6211ed60b03 100644 --- a/net/ipv4/fib_lookup.h +++ b/net/ipv4/fib_lookup.h | |||
@@ -12,6 +12,7 @@ struct fib_alias { | |||
12 | u8 fa_type; | 12 | u8 fa_type; |
13 | u8 fa_state; | 13 | u8 fa_state; |
14 | u8 fa_slen; | 14 | u8 fa_slen; |
15 | u32 tb_id; | ||
15 | struct rcu_head rcu; | 16 | struct rcu_head rcu; |
16 | }; | 17 | }; |
17 | 18 | ||
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 190d0d00d744..e9bc5e42cf43 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c | |||
@@ -174,6 +174,11 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | |||
174 | if (frh->tos & ~IPTOS_TOS_MASK) | 174 | if (frh->tos & ~IPTOS_TOS_MASK) |
175 | goto errout; | 175 | goto errout; |
176 | 176 | ||
177 | /* split local/main if they are not already split */ | ||
178 | err = fib_unmerge(net); | ||
179 | if (err) | ||
180 | goto errout; | ||
181 | |||
177 | if (rule->table == RT_TABLE_UNSPEC) { | 182 | if (rule->table == RT_TABLE_UNSPEC) { |
178 | if (rule->action == FR_ACT_TO_TBL) { | 183 | if (rule->action == FR_ACT_TO_TBL) { |
179 | struct fib_table *table; | 184 | struct fib_table *table; |
@@ -216,17 +221,24 @@ errout: | |||
216 | return err; | 221 | return err; |
217 | } | 222 | } |
218 | 223 | ||
219 | static void fib4_rule_delete(struct fib_rule *rule) | 224 | static int fib4_rule_delete(struct fib_rule *rule) |
220 | { | 225 | { |
221 | struct net *net = rule->fr_net; | 226 | struct net *net = rule->fr_net; |
222 | #ifdef CONFIG_IP_ROUTE_CLASSID | 227 | int err; |
223 | struct fib4_rule *rule4 = (struct fib4_rule *) rule; | ||
224 | 228 | ||
225 | if (rule4->tclassid) | 229 | /* split local/main if they are not already split */ |
230 | err = fib_unmerge(net); | ||
231 | if (err) | ||
232 | goto errout; | ||
233 | |||
234 | #ifdef CONFIG_IP_ROUTE_CLASSID | ||
235 | if (((struct fib4_rule *)rule)->tclassid) | ||
226 | net->ipv4.fib_num_tclassid_users--; | 236 | net->ipv4.fib_num_tclassid_users--; |
227 | #endif | 237 | #endif |
228 | net->ipv4.fib_has_custom_rules = true; | 238 | net->ipv4.fib_has_custom_rules = true; |
229 | fib_flush_external(rule->fr_net); | 239 | fib_flush_external(rule->fr_net); |
240 | errout: | ||
241 | return err; | ||
230 | } | 242 | } |
231 | 243 | ||
232 | static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | 244 | static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 83290beaf7cf..7b2badd74ad8 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -1120,6 +1120,9 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) | |||
1120 | break; | 1120 | break; |
1121 | if (fa->fa_info->fib_priority != fi->fib_priority) | 1121 | if (fa->fa_info->fib_priority != fi->fib_priority) |
1122 | break; | 1122 | break; |
1123 | /* duplicate entry from another table */ | ||
1124 | if (WARN_ON(fa->tb_id != tb->tb_id)) | ||
1125 | continue; | ||
1123 | if (fa->fa_type == cfg->fc_type && | 1126 | if (fa->fa_type == cfg->fc_type && |
1124 | fa->fa_info == fi) { | 1127 | fa->fa_info == fi) { |
1125 | fa_match = fa; | 1128 | fa_match = fa; |
@@ -1197,6 +1200,7 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) | |||
1197 | new_fa->fa_type = cfg->fc_type; | 1200 | new_fa->fa_type = cfg->fc_type; |
1198 | new_fa->fa_state = 0; | 1201 | new_fa->fa_state = 0; |
1199 | new_fa->fa_slen = slen; | 1202 | new_fa->fa_slen = slen; |
1203 | new_fa->tb_id = tb->tb_id; | ||
1200 | 1204 | ||
1201 | /* (Optionally) offload fib entry to switch hardware. */ | 1205 | /* (Optionally) offload fib entry to switch hardware. */ |
1202 | err = netdev_switch_fib_ipv4_add(key, plen, fi, tos, | 1206 | err = netdev_switch_fib_ipv4_add(key, plen, fi, tos, |
@@ -1217,7 +1221,7 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) | |||
1217 | tb->tb_num_default++; | 1221 | tb->tb_num_default++; |
1218 | 1222 | ||
1219 | rt_cache_flush(cfg->fc_nlinfo.nl_net); | 1223 | rt_cache_flush(cfg->fc_nlinfo.nl_net); |
1220 | rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, | 1224 | rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id, |
1221 | &cfg->fc_nlinfo, 0); | 1225 | &cfg->fc_nlinfo, 0); |
1222 | succeeded: | 1226 | succeeded: |
1223 | return 0; | 1227 | return 0; |
@@ -1243,7 +1247,7 @@ static inline t_key prefix_mismatch(t_key key, struct key_vector *n) | |||
1243 | int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, | 1247 | int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, |
1244 | struct fib_result *res, int fib_flags) | 1248 | struct fib_result *res, int fib_flags) |
1245 | { | 1249 | { |
1246 | struct trie *t = (struct trie *)tb->tb_data; | 1250 | struct trie *t = (struct trie *) tb->tb_data; |
1247 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1251 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1248 | struct trie_use_stats __percpu *stats = t->stats; | 1252 | struct trie_use_stats __percpu *stats = t->stats; |
1249 | #endif | 1253 | #endif |
@@ -1483,6 +1487,9 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) | |||
1483 | if ((fa->fa_slen != slen) || (fa->fa_tos != tos)) | 1487 | if ((fa->fa_slen != slen) || (fa->fa_tos != tos)) |
1484 | break; | 1488 | break; |
1485 | 1489 | ||
1490 | if (fa->tb_id != tb->tb_id) | ||
1491 | continue; | ||
1492 | |||
1486 | if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && | 1493 | if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && |
1487 | (cfg->fc_scope == RT_SCOPE_NOWHERE || | 1494 | (cfg->fc_scope == RT_SCOPE_NOWHERE || |
1488 | fa->fa_info->fib_scope == cfg->fc_scope) && | 1495 | fa->fa_info->fib_scope == cfg->fc_scope) && |
@@ -1576,6 +1583,120 @@ found: | |||
1576 | return n; | 1583 | return n; |
1577 | } | 1584 | } |
1578 | 1585 | ||
1586 | static void fib_trie_free(struct fib_table *tb) | ||
1587 | { | ||
1588 | struct trie *t = (struct trie *)tb->tb_data; | ||
1589 | struct key_vector *pn = t->kv; | ||
1590 | unsigned long cindex = 1; | ||
1591 | struct hlist_node *tmp; | ||
1592 | struct fib_alias *fa; | ||
1593 | |||
1594 | /* walk trie in reverse order and free everything */ | ||
1595 | for (;;) { | ||
1596 | struct key_vector *n; | ||
1597 | |||
1598 | if (!(cindex--)) { | ||
1599 | t_key pkey = pn->key; | ||
1600 | |||
1601 | if (IS_TRIE(pn)) | ||
1602 | break; | ||
1603 | |||
1604 | n = pn; | ||
1605 | pn = node_parent(pn); | ||
1606 | |||
1607 | /* drop emptied tnode */ | ||
1608 | put_child_root(pn, n->key, NULL); | ||
1609 | node_free(n); | ||
1610 | |||
1611 | cindex = get_index(pkey, pn); | ||
1612 | |||
1613 | continue; | ||
1614 | } | ||
1615 | |||
1616 | /* grab the next available node */ | ||
1617 | n = get_child(pn, cindex); | ||
1618 | if (!n) | ||
1619 | continue; | ||
1620 | |||
1621 | if (IS_TNODE(n)) { | ||
1622 | /* record pn and cindex for leaf walking */ | ||
1623 | pn = n; | ||
1624 | cindex = 1ul << n->bits; | ||
1625 | |||
1626 | continue; | ||
1627 | } | ||
1628 | |||
1629 | hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { | ||
1630 | hlist_del_rcu(&fa->fa_list); | ||
1631 | alias_free_mem_rcu(fa); | ||
1632 | } | ||
1633 | |||
1634 | put_child_root(pn, n->key, NULL); | ||
1635 | node_free(n); | ||
1636 | } | ||
1637 | |||
1638 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1639 | free_percpu(t->stats); | ||
1640 | #endif | ||
1641 | kfree(tb); | ||
1642 | } | ||
1643 | |||
1644 | struct fib_table *fib_trie_unmerge(struct fib_table *oldtb) | ||
1645 | { | ||
1646 | struct trie *ot = (struct trie *)oldtb->tb_data; | ||
1647 | struct key_vector *l, *tp = ot->kv; | ||
1648 | struct fib_table *local_tb; | ||
1649 | struct fib_alias *fa; | ||
1650 | struct trie *lt; | ||
1651 | t_key key = 0; | ||
1652 | |||
1653 | if (oldtb->tb_data == oldtb->__data) | ||
1654 | return oldtb; | ||
1655 | |||
1656 | local_tb = fib_trie_table(RT_TABLE_LOCAL, NULL); | ||
1657 | if (!local_tb) | ||
1658 | return NULL; | ||
1659 | |||
1660 | lt = (struct trie *)local_tb->tb_data; | ||
1661 | |||
1662 | while ((l = leaf_walk_rcu(&tp, key)) != NULL) { | ||
1663 | struct key_vector *local_l = NULL, *local_tp; | ||
1664 | |||
1665 | hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) { | ||
1666 | struct fib_alias *new_fa; | ||
1667 | |||
1668 | if (local_tb->tb_id != fa->tb_id) | ||
1669 | continue; | ||
1670 | |||
1671 | /* clone fa for new local table */ | ||
1672 | new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); | ||
1673 | if (!new_fa) | ||
1674 | goto out; | ||
1675 | |||
1676 | memcpy(new_fa, fa, sizeof(*fa)); | ||
1677 | |||
1678 | /* insert clone into table */ | ||
1679 | if (!local_l) | ||
1680 | local_l = fib_find_node(lt, &local_tp, l->key); | ||
1681 | |||
1682 | if (fib_insert_alias(lt, local_tp, local_l, new_fa, | ||
1683 | NULL, l->key)) | ||
1684 | goto out; | ||
1685 | } | ||
1686 | |||
1687 | /* stop loop if key wrapped back to 0 */ | ||
1688 | key = l->key + 1; | ||
1689 | if (key < l->key) | ||
1690 | break; | ||
1691 | } | ||
1692 | |||
1693 | return local_tb; | ||
1694 | out: | ||
1695 | fib_trie_free(local_tb); | ||
1696 | |||
1697 | return NULL; | ||
1698 | } | ||
1699 | |||
1579 | /* Caller must hold RTNL */ | 1700 | /* Caller must hold RTNL */ |
1580 | void fib_table_flush_external(struct fib_table *tb) | 1701 | void fib_table_flush_external(struct fib_table *tb) |
1581 | { | 1702 | { |
@@ -1587,6 +1708,7 @@ void fib_table_flush_external(struct fib_table *tb) | |||
1587 | 1708 | ||
1588 | /* walk trie in reverse order */ | 1709 | /* walk trie in reverse order */ |
1589 | for (;;) { | 1710 | for (;;) { |
1711 | unsigned char slen = 0; | ||
1590 | struct key_vector *n; | 1712 | struct key_vector *n; |
1591 | 1713 | ||
1592 | if (!(cindex--)) { | 1714 | if (!(cindex--)) { |
@@ -1596,8 +1718,8 @@ void fib_table_flush_external(struct fib_table *tb) | |||
1596 | if (IS_TRIE(pn)) | 1718 | if (IS_TRIE(pn)) |
1597 | break; | 1719 | break; |
1598 | 1720 | ||
1599 | /* no need to resize like in flush below */ | 1721 | /* resize completed node */ |
1600 | pn = node_parent(pn); | 1722 | pn = resize(t, pn); |
1601 | cindex = get_index(pkey, pn); | 1723 | cindex = get_index(pkey, pn); |
1602 | 1724 | ||
1603 | continue; | 1725 | continue; |
@@ -1619,6 +1741,18 @@ void fib_table_flush_external(struct fib_table *tb) | |||
1619 | hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { | 1741 | hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { |
1620 | struct fib_info *fi = fa->fa_info; | 1742 | struct fib_info *fi = fa->fa_info; |
1621 | 1743 | ||
1744 | /* if alias was cloned to local then we just | ||
1745 | * need to remove the local copy from main | ||
1746 | */ | ||
1747 | if (tb->tb_id != fa->tb_id) { | ||
1748 | hlist_del_rcu(&fa->fa_list); | ||
1749 | alias_free_mem_rcu(fa); | ||
1750 | continue; | ||
1751 | } | ||
1752 | |||
1753 | /* record local slen */ | ||
1754 | slen = fa->fa_slen; | ||
1755 | |||
1622 | if (!fi || !(fi->fib_flags & RTNH_F_EXTERNAL)) | 1756 | if (!fi || !(fi->fib_flags & RTNH_F_EXTERNAL)) |
1623 | continue; | 1757 | continue; |
1624 | 1758 | ||
@@ -1627,6 +1761,16 @@ void fib_table_flush_external(struct fib_table *tb) | |||
1627 | fi, fa->fa_tos, | 1761 | fi, fa->fa_tos, |
1628 | fa->fa_type, tb->tb_id); | 1762 | fa->fa_type, tb->tb_id); |
1629 | } | 1763 | } |
1764 | |||
1765 | /* update leaf slen */ | ||
1766 | n->slen = slen; | ||
1767 | |||
1768 | if (hlist_empty(&n->leaf)) { | ||
1769 | put_child_root(pn, n->key, NULL); | ||
1770 | node_free(n); | ||
1771 | } else { | ||
1772 | leaf_pull_suffix(pn, n); | ||
1773 | } | ||
1630 | } | 1774 | } |
1631 | } | 1775 | } |
1632 | 1776 | ||
@@ -1711,7 +1855,8 @@ static void __trie_free_rcu(struct rcu_head *head) | |||
1711 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1855 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1712 | struct trie *t = (struct trie *)tb->tb_data; | 1856 | struct trie *t = (struct trie *)tb->tb_data; |
1713 | 1857 | ||
1714 | free_percpu(t->stats); | 1858 | if (tb->tb_data == tb->__data) |
1859 | free_percpu(t->stats); | ||
1715 | #endif /* CONFIG_IP_FIB_TRIE_STATS */ | 1860 | #endif /* CONFIG_IP_FIB_TRIE_STATS */ |
1716 | kfree(tb); | 1861 | kfree(tb); |
1717 | } | 1862 | } |
@@ -1738,6 +1883,11 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, | |||
1738 | continue; | 1883 | continue; |
1739 | } | 1884 | } |
1740 | 1885 | ||
1886 | if (tb->tb_id != fa->tb_id) { | ||
1887 | i++; | ||
1888 | continue; | ||
1889 | } | ||
1890 | |||
1741 | if (fib_dump_info(skb, NETLINK_CB(cb->skb).portid, | 1891 | if (fib_dump_info(skb, NETLINK_CB(cb->skb).portid, |
1742 | cb->nlh->nlmsg_seq, | 1892 | cb->nlh->nlmsg_seq, |
1743 | RTM_NEWROUTE, | 1893 | RTM_NEWROUTE, |
@@ -1804,18 +1954,26 @@ void __init fib_trie_init(void) | |||
1804 | 0, SLAB_PANIC, NULL); | 1954 | 0, SLAB_PANIC, NULL); |
1805 | } | 1955 | } |
1806 | 1956 | ||
1807 | struct fib_table *fib_trie_table(u32 id) | 1957 | struct fib_table *fib_trie_table(u32 id, struct fib_table *alias) |
1808 | { | 1958 | { |
1809 | struct fib_table *tb; | 1959 | struct fib_table *tb; |
1810 | struct trie *t; | 1960 | struct trie *t; |
1961 | size_t sz = sizeof(*tb); | ||
1962 | |||
1963 | if (!alias) | ||
1964 | sz += sizeof(struct trie); | ||
1811 | 1965 | ||
1812 | tb = kzalloc(sizeof(*tb) + sizeof(struct trie), GFP_KERNEL); | 1966 | tb = kzalloc(sz, GFP_KERNEL); |
1813 | if (tb == NULL) | 1967 | if (tb == NULL) |
1814 | return NULL; | 1968 | return NULL; |
1815 | 1969 | ||
1816 | tb->tb_id = id; | 1970 | tb->tb_id = id; |
1817 | tb->tb_default = -1; | 1971 | tb->tb_default = -1; |
1818 | tb->tb_num_default = 0; | 1972 | tb->tb_num_default = 0; |
1973 | tb->tb_data = (alias ? alias->__data : tb->__data); | ||
1974 | |||
1975 | if (alias) | ||
1976 | return tb; | ||
1819 | 1977 | ||
1820 | t = (struct trie *) tb->tb_data; | 1978 | t = (struct trie *) tb->tb_data; |
1821 | t->kv[0].pos = KEYLENGTH; | 1979 | t->kv[0].pos = KEYLENGTH; |