--- include/linux/ve.h +++ include/linux/ve.h @@ -250,11 +250,13 @@ struct ve_struct { int _fib_hash_size; int _fib_info_cnt; - struct fib_rule *_local_rule; - struct list_head _fib_rules; +#ifdef CONFIG_FIB_RULES + struct list_head _rules_ops; +#endif /* XXX: why a magic constant? */ #ifdef CONFIG_IP_MULTIPLE_TABLES struct hlist_head _fib_table_hash[256]; + struct fib_rules_ops *_fib4_ops; #else struct hlist_head _fib_table_hash[1]; struct fib_table *_main_table; @@ -287,6 +289,7 @@ struct ve_struct { #ifdef CONFIG_IPV6_MULTIPLE_TABLES struct hlist_head _fib6_table_hash[256]; struct fib6_table *_fib6_local_table; + struct fib_rules_ops *_fib6_ops; #else struct hlist_head _fib6_table_hash[1]; #endif --- include/net/ip6_fib.h +++ include/net/ip6_fib.h @@ -229,5 +229,10 @@ extern void fib6_tables_cleanup(void); extern void fib6_rules_init(void); extern void fib6_rules_cleanup(void); +#ifdef CONFIG_IPV6_MULTIPLE_TABLES +extern int fib6_rules_create(void); +extern void fib6_rules_destroy(void); +#endif + #endif #endif --- kernel/ve/ve.c +++ kernel/ve/ve.c @@ -14,6 +114,9 @@ struct ve_struct ve0 = { .ve_netns = &init_net, .is_running = 1, .op_sem = __RWSEM_INITIALIZER(ve0.op_sem), +#ifdef CONFIG_FIB_RULES + ._rules_ops = LIST_HEAD_INIT(ve0._rules_ops), +#endif }; EXPORT_SYMBOL(ve0); --- kernel/ve/vecalls.c +++ kernel/ve/vecalls.c @@ -1498,6 +1498,10 @@ static int do_env_create(envid_t veid, unsigned int flags, u32 class_id, if ((err = init_ve_sysctl(ve))) goto err_sysctl; +#ifdef CONFIG_FIB_RULES + INIT_LIST_HEAD(&ve->_rules_ops); +#endif + if ((err = init_ve_route(ve)) < 0) goto err_route; --- net/core/fib_rules.c +++ net/core/fib_rules.c @@ -16,8 +16,13 @@ #include #include -static LIST_HEAD(rules_ops); +static LIST_HEAD(_rules_ops); static DEFINE_SPINLOCK(rules_mod_lock); +#ifdef CONFIG_VE +#define rules_ops (get_exec_env()->_rules_ops) +#else +#define rules_ops _rules_ops +#endif int fib_default_rule_add(struct fib_rules_ops *ops, u32 pref, u32 table, u32 flags) --- net/ipv4/fib_rules.c +++ net/ipv4/fib_rules.c @@ -32,7 +32,13 @@ #include #include -static struct fib_rules_ops fib4_rules_ops; +static struct fib_rules_ops _fib4_rules_ops; +#ifdef CONFIG_VE +#define fib4_rules_ops (*get_exec_env()->_fib4_ops) +#else +#define fib4_rules_ops _fib4_rules_ops +#endif + struct fib4_rule { @@ -49,53 +55,53 @@ struct fib4_rule #endif }; -#ifdef CONFIG_VE -#define local_rule (*(get_exec_env()->_local_rule)) -#define fib4_rules (get_exec_env()->_fib_rules) -#else -#define local_rule loc_rule -static LIST_HEAD(fib4_rules); -#endif - #if defined(CONFIG_VE_CALLS) || defined(CONFIG_VE_CALLS_MODULE) #ifdef CONFIG_VE -static inline void init_rule_struct(struct fib_rule *r, +static inline void init_rule_struct(struct fib4_rule *r, u32 pref, unsigned char table, unsigned char action) { - memset(r, 0, sizeof(struct fib_rule)); - atomic_set(&r->refcnt, 1); - r->pref = pref; - r->table = table; - r->action = action; + memset(r, 0, sizeof(struct fib4_rule)); + atomic_set(&r->common.refcnt, 1); + r->common.pref = pref; + r->common.table = table; + r->common.action = action; } #endif int fib_rules_create(void) { #ifdef CONFIG_VE - struct fib_rule *default_rule, *main_rule, *loc_rule; + struct fib4_rule *default_rule, *main_rule, *loc_rule; + struct fib_rules_ops *ops; + + ops = kmalloc(sizeof(struct fib_rules_ops), GFP_KERNEL_UBC); + if (ops == NULL) + goto out_ops; + memcpy(ops, &_fib4_rules_ops, sizeof(struct fib_rules_ops)); + INIT_LIST_HEAD(&ops->rules_list); - default_rule = kmalloc(sizeof(struct fib_rule), GFP_KERNEL_UBC); + default_rule = kmalloc(sizeof(struct fib4_rule), GFP_KERNEL_UBC); if (default_rule == NULL) goto out_def; - main_rule = kmalloc(sizeof(struct fib_rule), GFP_KERNEL_UBC); + main_rule = kmalloc(sizeof(struct fib4_rule), GFP_KERNEL_UBC); if (main_rule == NULL) goto out_main; - loc_rule = kmalloc(sizeof(struct fib_rule), GFP_KERNEL_UBC); + loc_rule = kmalloc(sizeof(struct fib4_rule), GFP_KERNEL_UBC); if (loc_rule == NULL) goto out_loc; - init_rule_struct(default_rule, 0x7FFF, RT_TABLE_DEFAULT, RTN_UNICAST); - init_rule_struct(main_rule, 0x7FFE, RT_TABLE_MAIN, RTN_UNICAST); - init_rule_struct(loc_rule, 0, RT_TABLE_LOCAL, RTN_UNICAST); + init_rule_struct(default_rule, 0x7FFF, RT_TABLE_DEFAULT, FR_ACT_TO_TBL); + init_rule_struct(main_rule, 0x7FFE, RT_TABLE_MAIN, FR_ACT_TO_TBL); + init_rule_struct(loc_rule, 0, RT_TABLE_LOCAL, FR_ACT_TO_TBL); + + list_add_tail(&loc_rule->common.list, &ops->rules_list); + list_add_tail(&main_rule->common.list, &ops->rules_list); + list_add_tail(&default_rule->common.list, &ops->rules_list); - INIT_LIST_HEAD(&fib4_rules); - list_add_tail(&loc_rule->list, &fib4_rules); - list_add_tail(&main_rule->list, &fib4_rules); - list_add_tail(&default_rule->list, &fib4_rules); - get_exec_env()->_local_rule = loc_rule; + get_exec_env()->_fib4_ops = ops; + fib_rules_register(ops); return 0; @@ -104,6 +110,8 @@ out_loc: out_main: kfree(default_rule); out_def: + kfree(ops); +out_ops: return -1; #else return 0; @@ -113,17 +121,22 @@ out_def: void fib_rules_destroy(void) { #ifdef CONFIG_VE + struct ve_struct *ve; struct fib_rule *r; struct list_head *pos, *tmp; + ve = get_exec_env(); rtnl_lock(); - list_for_each_safe (pos, tmp, &fib4_rules) { + list_for_each_safe (pos, tmp, &ve->_fib4_ops->rules_list) { r = list_entry(pos, struct fib_rule, list); list_del_rcu(pos); fib_rule_put(r); } rtnl_unlock(); + + fib_rules_unregister(ve->_fib4_ops); + kfree(ve->_fib4_ops); #endif } #endif @@ -353,7 +366,7 @@ static void fib4_rule_flush_cache(void) rt_cache_flush(-1); } -static struct fib_rules_ops fib4_rules_ops = { +static struct fib_rules_ops _fib4_rules_ops = { .family = AF_INET, .rule_size = sizeof(struct fib4_rule), .addr_size = sizeof(u32), @@ -367,7 +380,7 @@ static struct fib_rules_ops fib4_rules_ops = { .flush_cache = fib4_rule_flush_cache, .nlgroup = RTNLGRP_IPV4_RULE, .policy = fib4_rule_policy, - .rules_list = LIST_HEAD_INIT(fib4_rules_ops.rules_list), + .rules_list = LIST_HEAD_INIT(_fib4_rules_ops.rules_list), .owner = THIS_MODULE, }; @@ -392,6 +405,9 @@ static int __init fib_default_rules_init(void) void __init fib4_rules_init(void) { +#ifdef CONFIG_VE + get_ve0()->_fib4_ops = &_fib4_rules_ops; +#endif BUG_ON(fib_default_rules_init()); - fib_rules_register(&fib4_rules_ops); + fib_rules_register(&_fib4_rules_ops); } --- net/ipv6/fib6_rules.c +++ net/ipv6/fib6_rules.c @@ -29,7 +29,89 @@ struct fib6_rule u8 tclass; }; -static struct fib_rules_ops fib6_rules_ops; +static struct fib_rules_ops _fib6_rules_ops; +#ifdef CONFIG_VE +#define fib6_rules_ops (*get_exec_env()->_fib6_ops) +#else +#define fib6_rules_ops _fib6_rules_ops +#endif + +#if defined(CONFIG_VE_CALLS) || defined(CONFIG_VE_CALLS_MODULE) +#ifdef CONFIG_VE +static inline void init_rule_struct(struct fib6_rule *r, + u32 pref, unsigned char table, unsigned char action) +{ + memset(r, 0, sizeof(struct fib6_rule)); + atomic_set(&r->common.refcnt, 1); + r->common.pref = pref; + r->common.table = table; + r->common.action = action; +} +#endif + +int fib6_rules_create(void) +{ +#ifdef CONFIG_VE + struct fib6_rule *main_rule, *loc_rule; + struct fib_rules_ops *ops; + + ops = kmalloc(sizeof(struct fib_rules_ops), GFP_KERNEL_UBC); + if (ops == NULL) + goto out_ops; + memcpy(ops, &_fib6_rules_ops, sizeof(struct fib_rules_ops)); + INIT_LIST_HEAD(&ops->rules_list); + + main_rule = kmalloc(sizeof(struct fib6_rule), GFP_KERNEL_UBC); + if (main_rule == NULL) + goto out_main; + + loc_rule = kmalloc(sizeof(struct fib6_rule), GFP_KERNEL_UBC); + if (loc_rule == NULL) + goto out_loc; + + init_rule_struct(main_rule, 0x7FFE, RT_TABLE_MAIN, RTN_UNICAST); + init_rule_struct(loc_rule, 0, RT_TABLE_LOCAL, RTN_UNICAST); + + list_add_tail(&loc_rule->common.list, &ops->rules_list); + list_add_tail(&main_rule->common.list, &ops->rules_list); + + get_exec_env()->_fib6_ops = ops; + fib_rules_register(ops); + return 0; + +out_loc: + kfree(main_rule); +out_main: + kfree(ops); +out_ops: + return -1; +#else + return 0; +#endif +} + +void fib6_rules_destroy(void) +{ +#ifdef CONFIG_VE + struct ve_struct *ve; + struct fib_rule *r; + struct list_head *pos, *tmp; + + ve = get_exec_env(); + rtnl_lock(); + list_for_each_safe (pos, tmp, &ve->_fib6_ops->rules_list) { + r = list_entry(pos, struct fib_rule, list); + + list_del_rcu(pos); + fib_rule_put(r); + } + rtnl_unlock(); + + fib_rules_unregister(ve->_fib6_ops); + kfree(ve->_fib6_ops); +#endif +} +#endif struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, pol_lookup_t lookup) @@ -234,7 +316,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) + nla_total_size(16); /* src */ } -static struct fib_rules_ops fib6_rules_ops = { +static struct fib_rules_ops _fib6_rules_ops = { .family = AF_INET6, .rule_size = sizeof(struct fib6_rule), .addr_size = sizeof(struct in6_addr), @@ -247,7 +329,7 @@ static struct fib_rules_ops fib6_rules_ops = { .nlmsg_payload = fib6_rule_nlmsg_payload, .nlgroup = RTNLGRP_IPV6_RULE, .policy = fib6_rule_policy, - .rules_list = LIST_HEAD_INIT(fib6_rules_ops.rules_list), + .rules_list = LIST_HEAD_INIT(_fib6_rules_ops.rules_list), .owner = THIS_MODULE, }; @@ -267,11 +349,17 @@ static int __init fib6_default_rules_init(void) void __init fib6_rules_init(void) { +#ifdef CONFIG_VE + get_ve0()->_fib6_ops = &_fib6_rules_ops; +#endif BUG_ON(fib6_default_rules_init()); - fib_rules_register(&fib6_rules_ops); + fib_rules_register(&_fib6_rules_ops); } void fib6_rules_cleanup(void) { - fib_rules_unregister(&fib6_rules_ops); + fib_rules_unregister(&_fib6_rules_ops); +#ifdef CONFIG_VE + get_ve0()->_fib6_ops = NULL; +#endif } --- net/ipv6/route.c +++ net/ipv6/route.c @@ -2536,12 +2536,9 @@ void ip6_route_cleanup(void) #ifdef CONFIG_VE int init_ve_route6(struct ve_struct *ve) { - struct ve_struct *old_env = set_exec_env(ve); ve->_fib6_table = kzalloc(sizeof(struct fib6_table), GFP_KERNEL_UBC); - if (!ve->_fib6_table) { - set_exec_env(old_env); + if (!ve->_fib6_table) return -ENOMEM; - } ve->_fib6_table->owner_env = ve; ve->_fib6_table->tb6_id = RT6_TABLE_MAIN; ve->_fib6_table->tb6_root.leaf = &ip6_null_entry; @@ -2550,36 +2547,40 @@ int init_ve_route6(struct ve_struct *ve) #ifdef CONFIG_IPV6_MULTIPLE_TABLES ve->_fib6_local_table = kzalloc(sizeof(struct fib6_table), GFP_KERNEL_UBC); - if (!ve->_fib6_local_table) { - kfree(ve->_fib6_table); - set_exec_env(old_env); - return -ENOMEM; - } + if (!ve->_fib6_local_table) + goto fail_local; ve->_fib6_local_table->owner_env = ve; ve->_fib6_local_table->tb6_id = RT6_TABLE_LOCAL; ve->_fib6_local_table->tb6_root.leaf = &ip6_null_entry; ve->_fib6_local_table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; + if (fib6_rules_create() < 0) + goto fail_rules; #endif fib6_tables_init(); - set_exec_env(old_env); return 0; + +#ifdef CONFIG_IPV6_MULTIPLE_TABLES +fail_rules: + kfree(ve->_fib6_local_table); +fail_local: + kfree(ve->_fib6_table); + return -ENOMEM; +#endif } EXPORT_SYMBOL(init_ve_route6); void fini_ve_route6(struct ve_struct *ve) { - struct ve_struct *old_env = set_exec_env(ve); - if (ve->_fib6_table) { rt6_ifdown(NULL); fib6_tables_cleanup(); kfree(ve->_fib6_table); #ifdef CONFIG_IPV6_MULTIPLE_TABLES kfree(ve->_fib6_local_table); + fib6_rules_destroy(); #endif } - set_exec_env(old_env); } EXPORT_SYMBOL(fini_ve_route6); #endif