~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/netfilter/nf_conntrack_ecache.c

Version: ~ [ linux-5.10-rc1 ] ~ [ linux-5.9.1 ] ~ [ linux-5.8.16 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.72 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.152 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.202 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.240 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.240 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* Event cache for netfilter. */
  2 
  3 /*
  4  * (C) 2005 Harald Welte <laforge@gnumonks.org>
  5  * (C) 2005 Patrick McHardy <kaber@trash.net>
  6  * (C) 2005-2006 Netfilter Core Team <coreteam@netfilter.org>
  7  * (C) 2005 USAGI/WIDE Project <http://www.linux-ipv6.org>
  8  *
  9  * This program is free software; you can redistribute it and/or modify
 10  * it under the terms of the GNU General Public License version 2 as
 11  * published by the Free Software Foundation.
 12  */
 13 
 14 #include <linux/types.h>
 15 #include <linux/netfilter.h>
 16 #include <linux/skbuff.h>
 17 #include <linux/vmalloc.h>
 18 #include <linux/stddef.h>
 19 #include <linux/err.h>
 20 #include <linux/percpu.h>
 21 #include <linux/kernel.h>
 22 #include <linux/netdevice.h>
 23 #include <linux/slab.h>
 24 #include <linux/export.h>
 25 
 26 #include <net/netfilter/nf_conntrack.h>
 27 #include <net/netfilter/nf_conntrack_core.h>
 28 #include <net/netfilter/nf_conntrack_extend.h>
 29 
 30 static DEFINE_MUTEX(nf_ct_ecache_mutex);
 31 
 32 /* deliver cached events and clear cache entry - must be called with locally
 33  * disabled softirqs */
 34 void nf_ct_deliver_cached_events(struct nf_conn *ct)
 35 {
 36         struct net *net = nf_ct_net(ct);
 37         unsigned long events, missed;
 38         struct nf_ct_event_notifier *notify;
 39         struct nf_conntrack_ecache *e;
 40         struct nf_ct_event item;
 41         int ret;
 42 
 43         rcu_read_lock();
 44         notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
 45         if (notify == NULL)
 46                 goto out_unlock;
 47 
 48         e = nf_ct_ecache_find(ct);
 49         if (e == NULL)
 50                 goto out_unlock;
 51 
 52         events = xchg(&e->cache, 0);
 53 
 54         if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct) || !events)
 55                 goto out_unlock;
 56 
 57         /* We make a copy of the missed event cache without taking
 58          * the lock, thus we may send missed events twice. However,
 59          * this does not harm and it happens very rarely. */
 60         missed = e->missed;
 61 
 62         if (!((events | missed) & e->ctmask))
 63                 goto out_unlock;
 64 
 65         item.ct = ct;
 66         item.portid = 0;
 67         item.report = 0;
 68 
 69         ret = notify->fcn(events | missed, &item);
 70 
 71         if (likely(ret >= 0 && !missed))
 72                 goto out_unlock;
 73 
 74         spin_lock_bh(&ct->lock);
 75         if (ret < 0)
 76                 e->missed |= events;
 77         else
 78                 e->missed &= ~missed;
 79         spin_unlock_bh(&ct->lock);
 80 
 81 out_unlock:
 82         rcu_read_unlock();
 83 }
 84 EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events);
 85 
 86 int nf_conntrack_register_notifier(struct net *net,
 87                                    struct nf_ct_event_notifier *new)
 88 {
 89         int ret;
 90         struct nf_ct_event_notifier *notify;
 91 
 92         mutex_lock(&nf_ct_ecache_mutex);
 93         notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb,
 94                                            lockdep_is_held(&nf_ct_ecache_mutex));
 95         if (notify != NULL) {
 96                 ret = -EBUSY;
 97                 goto out_unlock;
 98         }
 99         rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new);
100         ret = 0;
101 
102 out_unlock:
103         mutex_unlock(&nf_ct_ecache_mutex);
104         return ret;
105 }
106 EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier);
107 
108 void nf_conntrack_unregister_notifier(struct net *net,
109                                       struct nf_ct_event_notifier *new)
110 {
111         struct nf_ct_event_notifier *notify;
112 
113         mutex_lock(&nf_ct_ecache_mutex);
114         notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb,
115                                            lockdep_is_held(&nf_ct_ecache_mutex));
116         BUG_ON(notify != new);
117         RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, NULL);
118         mutex_unlock(&nf_ct_ecache_mutex);
119 }
120 EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
121 
122 int nf_ct_expect_register_notifier(struct net *net,
123                                    struct nf_exp_event_notifier *new)
124 {
125         int ret;
126         struct nf_exp_event_notifier *notify;
127 
128         mutex_lock(&nf_ct_ecache_mutex);
129         notify = rcu_dereference_protected(net->ct.nf_expect_event_cb,
130                                            lockdep_is_held(&nf_ct_ecache_mutex));
131         if (notify != NULL) {
132                 ret = -EBUSY;
133                 goto out_unlock;
134         }
135         rcu_assign_pointer(net->ct.nf_expect_event_cb, new);
136         ret = 0;
137 
138 out_unlock:
139         mutex_unlock(&nf_ct_ecache_mutex);
140         return ret;
141 }
142 EXPORT_SYMBOL_GPL(nf_ct_expect_register_notifier);
143 
144 void nf_ct_expect_unregister_notifier(struct net *net,
145                                       struct nf_exp_event_notifier *new)
146 {
147         struct nf_exp_event_notifier *notify;
148 
149         mutex_lock(&nf_ct_ecache_mutex);
150         notify = rcu_dereference_protected(net->ct.nf_expect_event_cb,
151                                            lockdep_is_held(&nf_ct_ecache_mutex));
152         BUG_ON(notify != new);
153         RCU_INIT_POINTER(net->ct.nf_expect_event_cb, NULL);
154         mutex_unlock(&nf_ct_ecache_mutex);
155 }
156 EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier);
157 
158 #define NF_CT_EVENTS_DEFAULT 1
159 static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT;
160 static int nf_ct_events_retry_timeout __read_mostly = 15*HZ;
161 
162 #ifdef CONFIG_SYSCTL
163 static struct ctl_table event_sysctl_table[] = {
164         {
165                 .procname       = "nf_conntrack_events",
166                 .data           = &init_net.ct.sysctl_events,
167                 .maxlen         = sizeof(unsigned int),
168                 .mode           = 0644,
169                 .proc_handler   = proc_dointvec,
170         },
171         {
172                 .procname       = "nf_conntrack_events_retry_timeout",
173                 .data           = &init_net.ct.sysctl_events_retry_timeout,
174                 .maxlen         = sizeof(unsigned int),
175                 .mode           = 0644,
176                 .proc_handler   = proc_dointvec_jiffies,
177         },
178         {}
179 };
180 #endif /* CONFIG_SYSCTL */
181 
182 static struct nf_ct_ext_type event_extend __read_mostly = {
183         .len    = sizeof(struct nf_conntrack_ecache),
184         .align  = __alignof__(struct nf_conntrack_ecache),
185         .id     = NF_CT_EXT_ECACHE,
186 };
187 
188 #ifdef CONFIG_SYSCTL
189 static int nf_conntrack_event_init_sysctl(struct net *net)
190 {
191         struct ctl_table *table;
192 
193         table = kmemdup(event_sysctl_table, sizeof(event_sysctl_table),
194                         GFP_KERNEL);
195         if (!table)
196                 goto out;
197 
198         table[0].data = &net->ct.sysctl_events;
199         table[1].data = &net->ct.sysctl_events_retry_timeout;
200 
201         /* Don't export sysctls to unprivileged users */
202         if (net->user_ns != &init_user_ns)
203                 table[0].procname = NULL;
204 
205         net->ct.event_sysctl_header =
206                 register_net_sysctl(net, "net/netfilter", table);
207         if (!net->ct.event_sysctl_header) {
208                 printk(KERN_ERR "nf_ct_event: can't register to sysctl.\n");
209                 goto out_register;
210         }
211         return 0;
212 
213 out_register:
214         kfree(table);
215 out:
216         return -ENOMEM;
217 }
218 
219 static void nf_conntrack_event_fini_sysctl(struct net *net)
220 {
221         struct ctl_table *table;
222 
223         table = net->ct.event_sysctl_header->ctl_table_arg;
224         unregister_net_sysctl_table(net->ct.event_sysctl_header);
225         kfree(table);
226 }
227 #else
228 static int nf_conntrack_event_init_sysctl(struct net *net)
229 {
230         return 0;
231 }
232 
233 static void nf_conntrack_event_fini_sysctl(struct net *net)
234 {
235 }
236 #endif /* CONFIG_SYSCTL */
237 
238 int nf_conntrack_ecache_pernet_init(struct net *net)
239 {
240         net->ct.sysctl_events = nf_ct_events;
241         net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout;
242         return nf_conntrack_event_init_sysctl(net);
243 }
244 
245 void nf_conntrack_ecache_pernet_fini(struct net *net)
246 {
247         nf_conntrack_event_fini_sysctl(net);
248 }
249 
250 int nf_conntrack_ecache_init(void)
251 {
252         int ret = nf_ct_extend_register(&event_extend);
253         if (ret < 0)
254                 pr_err("nf_ct_event: Unable to register event extension.\n");
255         return ret;
256 }
257 
258 void nf_conntrack_ecache_fini(void)
259 {
260         nf_ct_extend_unregister(&event_extend);
261 }
262 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp