diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2008-11-04 08:27:15 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2008-11-04 08:27:15 -0500 |
commit | 6beceee5aa2cb94c4ae9f0784c7d3135d343f5b5 (patch) | |
tree | 9f6bd8ee8c966a2ad5eab64a2472c395ef29e2f4 | |
parent | 511061e2dd1b84bb21bb97c9216a19606c29ac02 (diff) |
netfilter: netns ebtables: part 2
* return ebt_table from ebt_register_table(), module code will save it into
per-netns data for unregistration
* duplicate ebt_table at the very beginning of registration -- it's added into
list, so one ebt_table wouldn't end up in many lists (and each netns has
different one)
* introduce underscored tables in individial modules, this is temporary to not
break bisection.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r-- | include/linux/netfilter_bridge/ebtables.h | 3 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtable_broute.c | 19 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtable_filter.c | 17 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtable_nat.c | 19 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 23 |
5 files changed, 47 insertions, 34 deletions
diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index 624e7883068c..e40ddb94b1af 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h | |||
@@ -300,7 +300,8 @@ struct ebt_table | |||
300 | 300 | ||
301 | #define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \ | 301 | #define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \ |
302 | ~(__alignof__(struct ebt_replace)-1)) | 302 | ~(__alignof__(struct ebt_replace)-1)) |
303 | extern int ebt_register_table(struct net *net, struct ebt_table *table); | 303 | extern struct ebt_table *ebt_register_table(struct net *net, |
304 | struct ebt_table *table); | ||
304 | extern void ebt_unregister_table(struct ebt_table *table); | 305 | extern void ebt_unregister_table(struct ebt_table *table); |
305 | extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb, | 306 | extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb, |
306 | const struct net_device *in, const struct net_device *out, | 307 | const struct net_device *in, const struct net_device *out, |
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index 1731ce8f7479..3277d682dfcf 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c | |||
@@ -41,22 +41,23 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks) | |||
41 | return 0; | 41 | return 0; |
42 | } | 42 | } |
43 | 43 | ||
44 | static struct ebt_table broute_table = | 44 | static struct ebt_table __broute_table = |
45 | { | 45 | { |
46 | .name = "broute", | 46 | .name = "broute", |
47 | .table = &initial_table, | 47 | .table = &initial_table, |
48 | .valid_hooks = 1 << NF_BR_BROUTING, | 48 | .valid_hooks = 1 << NF_BR_BROUTING, |
49 | .lock = __RW_LOCK_UNLOCKED(broute_table.lock), | 49 | .lock = __RW_LOCK_UNLOCKED(__broute_table.lock), |
50 | .check = check, | 50 | .check = check, |
51 | .me = THIS_MODULE, | 51 | .me = THIS_MODULE, |
52 | }; | 52 | }; |
53 | static struct ebt_table *broute_table; | ||
53 | 54 | ||
54 | static int ebt_broute(struct sk_buff *skb) | 55 | static int ebt_broute(struct sk_buff *skb) |
55 | { | 56 | { |
56 | int ret; | 57 | int ret; |
57 | 58 | ||
58 | ret = ebt_do_table(NF_BR_BROUTING, skb, skb->dev, NULL, | 59 | ret = ebt_do_table(NF_BR_BROUTING, skb, skb->dev, NULL, |
59 | &broute_table); | 60 | broute_table); |
60 | if (ret == NF_DROP) | 61 | if (ret == NF_DROP) |
61 | return 1; /* route it */ | 62 | return 1; /* route it */ |
62 | return 0; /* bridge it */ | 63 | return 0; /* bridge it */ |
@@ -64,21 +65,19 @@ static int ebt_broute(struct sk_buff *skb) | |||
64 | 65 | ||
65 | static int __init ebtable_broute_init(void) | 66 | static int __init ebtable_broute_init(void) |
66 | { | 67 | { |
67 | int ret; | 68 | broute_table = ebt_register_table(&init_net, &__broute_table); |
68 | 69 | if (IS_ERR(broute_table)) | |
69 | ret = ebt_register_table(&init_net, &broute_table); | 70 | return PTR_ERR(broute_table); |
70 | if (ret < 0) | ||
71 | return ret; | ||
72 | /* see br_input.c */ | 71 | /* see br_input.c */ |
73 | rcu_assign_pointer(br_should_route_hook, ebt_broute); | 72 | rcu_assign_pointer(br_should_route_hook, ebt_broute); |
74 | return ret; | 73 | return 0; |
75 | } | 74 | } |
76 | 75 | ||
77 | static void __exit ebtable_broute_fini(void) | 76 | static void __exit ebtable_broute_fini(void) |
78 | { | 77 | { |
79 | rcu_assign_pointer(br_should_route_hook, NULL); | 78 | rcu_assign_pointer(br_should_route_hook, NULL); |
80 | synchronize_net(); | 79 | synchronize_net(); |
81 | ebt_unregister_table(&broute_table); | 80 | ebt_unregister_table(broute_table); |
82 | } | 81 | } |
83 | 82 | ||
84 | module_init(ebtable_broute_init); | 83 | module_init(ebtable_broute_init); |
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index af8953c9a57c..596564c7aa58 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c | |||
@@ -50,21 +50,22 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks) | |||
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | 52 | ||
53 | static struct ebt_table frame_filter = | 53 | static struct ebt_table __frame_filter = |
54 | { | 54 | { |
55 | .name = "filter", | 55 | .name = "filter", |
56 | .table = &initial_table, | 56 | .table = &initial_table, |
57 | .valid_hooks = FILTER_VALID_HOOKS, | 57 | .valid_hooks = FILTER_VALID_HOOKS, |
58 | .lock = __RW_LOCK_UNLOCKED(frame_filter.lock), | 58 | .lock = __RW_LOCK_UNLOCKED(__frame_filter.lock), |
59 | .check = check, | 59 | .check = check, |
60 | .me = THIS_MODULE, | 60 | .me = THIS_MODULE, |
61 | }; | 61 | }; |
62 | static struct ebt_table *frame_filter; | ||
62 | 63 | ||
63 | static unsigned int | 64 | static unsigned int |
64 | ebt_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, | 65 | ebt_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, |
65 | const struct net_device *out, int (*okfn)(struct sk_buff *)) | 66 | const struct net_device *out, int (*okfn)(struct sk_buff *)) |
66 | { | 67 | { |
67 | return ebt_do_table(hook, skb, in, out, &frame_filter); | 68 | return ebt_do_table(hook, skb, in, out, frame_filter); |
68 | } | 69 | } |
69 | 70 | ||
70 | static struct nf_hook_ops ebt_ops_filter[] __read_mostly = { | 71 | static struct nf_hook_ops ebt_ops_filter[] __read_mostly = { |
@@ -95,19 +96,19 @@ static int __init ebtable_filter_init(void) | |||
95 | { | 96 | { |
96 | int ret; | 97 | int ret; |
97 | 98 | ||
98 | ret = ebt_register_table(&init_net, &frame_filter); | 99 | frame_filter = ebt_register_table(&init_net, &__frame_filter); |
99 | if (ret < 0) | 100 | if (IS_ERR(frame_filter)) |
100 | return ret; | 101 | return PTR_ERR(frame_filter); |
101 | ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter)); | 102 | ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter)); |
102 | if (ret < 0) | 103 | if (ret < 0) |
103 | ebt_unregister_table(&frame_filter); | 104 | ebt_unregister_table(frame_filter); |
104 | return ret; | 105 | return ret; |
105 | } | 106 | } |
106 | 107 | ||
107 | static void __exit ebtable_filter_fini(void) | 108 | static void __exit ebtable_filter_fini(void) |
108 | { | 109 | { |
109 | nf_unregister_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter)); | 110 | nf_unregister_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter)); |
110 | ebt_unregister_table(&frame_filter); | 111 | ebt_unregister_table(frame_filter); |
111 | } | 112 | } |
112 | 113 | ||
113 | module_init(ebtable_filter_init); | 114 | module_init(ebtable_filter_init); |
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index bafe16029bd7..0d8fc5bcddd1 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c | |||
@@ -50,28 +50,29 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks) | |||
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | 52 | ||
53 | static struct ebt_table frame_nat = | 53 | static struct ebt_table __frame_nat = |
54 | { | 54 | { |
55 | .name = "nat", | 55 | .name = "nat", |
56 | .table = &initial_table, | 56 | .table = &initial_table, |
57 | .valid_hooks = NAT_VALID_HOOKS, | 57 | .valid_hooks = NAT_VALID_HOOKS, |
58 | .lock = __RW_LOCK_UNLOCKED(frame_nat.lock), | 58 | .lock = __RW_LOCK_UNLOCKED(__frame_nat.lock), |
59 | .check = check, | 59 | .check = check, |
60 | .me = THIS_MODULE, | 60 | .me = THIS_MODULE, |
61 | }; | 61 | }; |
62 | static struct ebt_table *frame_nat; | ||
62 | 63 | ||
63 | static unsigned int | 64 | static unsigned int |
64 | ebt_nat_dst(unsigned int hook, struct sk_buff *skb, const struct net_device *in | 65 | ebt_nat_dst(unsigned int hook, struct sk_buff *skb, const struct net_device *in |
65 | , const struct net_device *out, int (*okfn)(struct sk_buff *)) | 66 | , const struct net_device *out, int (*okfn)(struct sk_buff *)) |
66 | { | 67 | { |
67 | return ebt_do_table(hook, skb, in, out, &frame_nat); | 68 | return ebt_do_table(hook, skb, in, out, frame_nat); |
68 | } | 69 | } |
69 | 70 | ||
70 | static unsigned int | 71 | static unsigned int |
71 | ebt_nat_src(unsigned int hook, struct sk_buff *skb, const struct net_device *in | 72 | ebt_nat_src(unsigned int hook, struct sk_buff *skb, const struct net_device *in |
72 | , const struct net_device *out, int (*okfn)(struct sk_buff *)) | 73 | , const struct net_device *out, int (*okfn)(struct sk_buff *)) |
73 | { | 74 | { |
74 | return ebt_do_table(hook, skb, in, out, &frame_nat); | 75 | return ebt_do_table(hook, skb, in, out, frame_nat); |
75 | } | 76 | } |
76 | 77 | ||
77 | static struct nf_hook_ops ebt_ops_nat[] __read_mostly = { | 78 | static struct nf_hook_ops ebt_ops_nat[] __read_mostly = { |
@@ -102,19 +103,19 @@ static int __init ebtable_nat_init(void) | |||
102 | { | 103 | { |
103 | int ret; | 104 | int ret; |
104 | 105 | ||
105 | ret = ebt_register_table(&init_net, &frame_nat); | 106 | frame_nat = ebt_register_table(&init_net, &__frame_nat); |
106 | if (ret < 0) | 107 | if (IS_ERR(frame_nat)) |
107 | return ret; | 108 | return PTR_ERR(frame_nat); |
108 | ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat)); | 109 | ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat)); |
109 | if (ret < 0) | 110 | if (ret < 0) |
110 | ebt_unregister_table(&frame_nat); | 111 | ebt_unregister_table(frame_nat); |
111 | return ret; | 112 | return ret; |
112 | } | 113 | } |
113 | 114 | ||
114 | static void __exit ebtable_nat_fini(void) | 115 | static void __exit ebtable_nat_fini(void) |
115 | { | 116 | { |
116 | nf_unregister_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat)); | 117 | nf_unregister_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat)); |
117 | ebt_unregister_table(&frame_nat); | 118 | ebt_unregister_table(frame_nat); |
118 | } | 119 | } |
119 | 120 | ||
120 | module_init(ebtable_nat_init); | 121 | module_init(ebtable_nat_init); |
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index c1a82b2826eb..82e17527e21e 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -1098,7 +1098,7 @@ free_newinfo: | |||
1098 | return ret; | 1098 | return ret; |
1099 | } | 1099 | } |
1100 | 1100 | ||
1101 | int ebt_register_table(struct net *net, struct ebt_table *table) | 1101 | struct ebt_table *ebt_register_table(struct net *net, struct ebt_table *table) |
1102 | { | 1102 | { |
1103 | struct ebt_table_info *newinfo; | 1103 | struct ebt_table_info *newinfo; |
1104 | struct ebt_table *t; | 1104 | struct ebt_table *t; |
@@ -1110,14 +1110,21 @@ int ebt_register_table(struct net *net, struct ebt_table *table) | |||
1110 | repl->entries_size == 0 || | 1110 | repl->entries_size == 0 || |
1111 | repl->counters || table->private) { | 1111 | repl->counters || table->private) { |
1112 | BUGPRINT("Bad table data for ebt_register_table!!!\n"); | 1112 | BUGPRINT("Bad table data for ebt_register_table!!!\n"); |
1113 | return -EINVAL; | 1113 | return ERR_PTR(-EINVAL); |
1114 | } | ||
1115 | |||
1116 | /* Don't add one table to multiple lists. */ | ||
1117 | table = kmemdup(table, sizeof(struct ebt_table), GFP_KERNEL); | ||
1118 | if (!table) { | ||
1119 | ret = -ENOMEM; | ||
1120 | goto out; | ||
1114 | } | 1121 | } |
1115 | 1122 | ||
1116 | countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids; | 1123 | countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids; |
1117 | newinfo = vmalloc(sizeof(*newinfo) + countersize); | 1124 | newinfo = vmalloc(sizeof(*newinfo) + countersize); |
1118 | ret = -ENOMEM; | 1125 | ret = -ENOMEM; |
1119 | if (!newinfo) | 1126 | if (!newinfo) |
1120 | return -ENOMEM; | 1127 | goto free_table; |
1121 | 1128 | ||
1122 | p = vmalloc(repl->entries_size); | 1129 | p = vmalloc(repl->entries_size); |
1123 | if (!p) | 1130 | if (!p) |
@@ -1149,7 +1156,7 @@ int ebt_register_table(struct net *net, struct ebt_table *table) | |||
1149 | 1156 | ||
1150 | if (table->check && table->check(newinfo, table->valid_hooks)) { | 1157 | if (table->check && table->check(newinfo, table->valid_hooks)) { |
1151 | BUGPRINT("The table doesn't like its own initial data, lol\n"); | 1158 | BUGPRINT("The table doesn't like its own initial data, lol\n"); |
1152 | return -EINVAL; | 1159 | return ERR_PTR(-EINVAL); |
1153 | } | 1160 | } |
1154 | 1161 | ||
1155 | table->private = newinfo; | 1162 | table->private = newinfo; |
@@ -1173,7 +1180,7 @@ int ebt_register_table(struct net *net, struct ebt_table *table) | |||
1173 | } | 1180 | } |
1174 | list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]); | 1181 | list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]); |
1175 | mutex_unlock(&ebt_mutex); | 1182 | mutex_unlock(&ebt_mutex); |
1176 | return 0; | 1183 | return table; |
1177 | free_unlock: | 1184 | free_unlock: |
1178 | mutex_unlock(&ebt_mutex); | 1185 | mutex_unlock(&ebt_mutex); |
1179 | free_chainstack: | 1186 | free_chainstack: |
@@ -1185,7 +1192,10 @@ free_chainstack: | |||
1185 | vfree(newinfo->entries); | 1192 | vfree(newinfo->entries); |
1186 | free_newinfo: | 1193 | free_newinfo: |
1187 | vfree(newinfo); | 1194 | vfree(newinfo); |
1188 | return ret; | 1195 | free_table: |
1196 | kfree(table); | ||
1197 | out: | ||
1198 | return ERR_PTR(ret); | ||
1189 | } | 1199 | } |
1190 | 1200 | ||
1191 | void ebt_unregister_table(struct ebt_table *table) | 1201 | void ebt_unregister_table(struct ebt_table *table) |
@@ -1206,6 +1216,7 @@ void ebt_unregister_table(struct ebt_table *table) | |||
1206 | vfree(table->private->chainstack); | 1216 | vfree(table->private->chainstack); |
1207 | } | 1217 | } |
1208 | vfree(table->private); | 1218 | vfree(table->private); |
1219 | kfree(table); | ||
1209 | } | 1220 | } |
1210 | 1221 | ||
1211 | /* userspace just supplied us with counters */ | 1222 | /* userspace just supplied us with counters */ |