Blame view

net/core/drop_monitor.c 10.1 KB
9a8afc8d3   Neil Horman   Network Drop Moni...
1
2
3
4
5
  /*
   * Monitoring code for network dropped packet alerts
   *
   * Copyright (C) 2009 Neil Horman <nhorman@tuxdriver.com>
   */
e005d193d   Joe Perches   net: core: Use pr...
6
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9a8afc8d3   Neil Horman   Network Drop Moni...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/string.h>
  #include <linux/if_arp.h>
  #include <linux/inetdevice.h>
  #include <linux/inet.h>
  #include <linux/interrupt.h>
  #include <linux/netpoll.h>
  #include <linux/sched.h>
  #include <linux/delay.h>
  #include <linux/types.h>
  #include <linux/workqueue.h>
  #include <linux/netlink.h>
  #include <linux/net_dropmon.h>
  #include <linux/percpu.h>
  #include <linux/timer.h>
  #include <linux/bitops.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
24
  #include <linux/slab.h>
cad456d5a   Neil Horman   drop_monitor: con...
25
  #include <linux/module.h>
9a8afc8d3   Neil Horman   Network Drop Moni...
26
  #include <net/genetlink.h>
4ea7e3869   Neil Horman   dropmon: add abil...
27
  #include <net/netevent.h>
9a8afc8d3   Neil Horman   Network Drop Moni...
28

ad8d75fff   Steven Rostedt   tracing/events: m...
29
  #include <trace/events/skb.h>
9cbc1cb8c   David S. Miller   Merge branch 'mas...
30
  #include <trace/events/napi.h>
9a8afc8d3   Neil Horman   Network Drop Moni...
31
32
33
34
35
  
  #include <asm/unaligned.h>
  
  #define TRACE_ON 1
  #define TRACE_OFF 0
9a8afc8d3   Neil Horman   Network Drop Moni...
36
37
38
39
40
  /*
   * Globals, our netlink socket pointer
   * and the work handle that will send up
   * netlink alerts
   */
4ea7e3869   Neil Horman   dropmon: add abil...
41
  static int trace_state = TRACE_OFF;
cde2e9a65   Neil Horman   drop_monitor: fix...
42
  static DEFINE_MUTEX(trace_state_mutex);
9a8afc8d3   Neil Horman   Network Drop Moni...
43
44
  
  struct per_cpu_dm_data {
bec4596b4   Eric Dumazet   drop_monitor: don...
45
46
47
48
  	spinlock_t		lock;
  	struct sk_buff		*skb;
  	struct work_struct	dm_alert_work;
  	struct timer_list	send_timer;
9a8afc8d3   Neil Horman   Network Drop Moni...
49
  };
4ea7e3869   Neil Horman   dropmon: add abil...
50
51
  struct dm_hw_stat_delta {
  	struct net_device *dev;
5848cc096   Neil Horman   net: drop_monitor...
52
  	unsigned long last_rx;
4ea7e3869   Neil Horman   dropmon: add abil...
53
54
55
56
  	struct list_head list;
  	struct rcu_head rcu;
  	unsigned long last_drop_val;
  };
9a8afc8d3   Neil Horman   Network Drop Moni...
57
58
59
60
  static struct genl_family net_drop_monitor_family = {
  	.id             = GENL_ID_GENERATE,
  	.hdrsize        = 0,
  	.name           = "NET_DM",
683703a26   Neil Horman   drop_monitor: Upd...
61
  	.version        = 2,
9a8afc8d3   Neil Horman   Network Drop Moni...
62
63
64
65
66
67
  };
  
  static DEFINE_PER_CPU(struct per_cpu_dm_data, dm_cpu_data);
  
  static int dm_hit_limit = 64;
  static int dm_delay = 1;
4ea7e3869   Neil Horman   dropmon: add abil...
68
69
  static unsigned long dm_hw_check_delta = 2*HZ;
  static LIST_HEAD(hw_stats_list);
9a8afc8d3   Neil Horman   Network Drop Moni...
70

bec4596b4   Eric Dumazet   drop_monitor: don...
71
  static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data)
9a8afc8d3   Neil Horman   Network Drop Moni...
72
73
74
  {
  	size_t al;
  	struct net_dm_alert_msg *msg;
683703a26   Neil Horman   drop_monitor: Upd...
75
  	struct nlattr *nla;
3885ca785   Neil Horman   drop_monitor: Mak...
76
  	struct sk_buff *skb;
bec4596b4   Eric Dumazet   drop_monitor: don...
77
  	unsigned long flags;
9f7551e05   Reiter Wolfgang   drop_monitor: add...
78
  	void *msg_header;
9a8afc8d3   Neil Horman   Network Drop Moni...
79
80
81
  
  	al = sizeof(struct net_dm_alert_msg);
  	al += dm_hit_limit * sizeof(struct net_dm_drop_point);
683703a26   Neil Horman   drop_monitor: Upd...
82
  	al += sizeof(struct nlattr);
3885ca785   Neil Horman   drop_monitor: Mak...
83
  	skb = genlmsg_new(al, GFP_KERNEL);
9f7551e05   Reiter Wolfgang   drop_monitor: add...
84
85
  	if (!skb)
  		goto err;
3885ca785   Neil Horman   drop_monitor: Mak...
86

9f7551e05   Reiter Wolfgang   drop_monitor: add...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  	msg_header = genlmsg_put(skb, 0, 0, &net_drop_monitor_family,
  				 0, NET_DM_CMD_ALERT);
  	if (!msg_header) {
  		nlmsg_free(skb);
  		skb = NULL;
  		goto err;
  	}
  	nla = nla_reserve(skb, NLA_UNSPEC,
  			  sizeof(struct net_dm_alert_msg));
  	if (!nla) {
  		nlmsg_free(skb);
  		skb = NULL;
  		goto err;
  	}
  	msg = nla_data(nla);
  	memset(msg, 0, al);
9f7551e05   Reiter Wolfgang   drop_monitor: add...
103
104
105
106
107
  	goto out;
  
  err:
  	mod_timer(&data->send_timer, jiffies + HZ / 10);
  out:
bec4596b4   Eric Dumazet   drop_monitor: don...
108
109
110
  	spin_lock_irqsave(&data->lock, flags);
  	swap(data->skb, skb);
  	spin_unlock_irqrestore(&data->lock, flags);
9f65f5d47   Reiter Wolfgang   drop_monitor: con...
111
112
113
114
115
116
  	if (skb) {
  		struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
  		struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlh);
  
  		genlmsg_end(skb, genlmsg_data(gnlh));
  	}
bec4596b4   Eric Dumazet   drop_monitor: don...
117
  	return skb;
9a8afc8d3   Neil Horman   Network Drop Moni...
118
  }
85bae4bd8   stephen hemminger   drop_monitor: mak...
119
  static const struct genl_multicast_group dropmon_mcgrps[] = {
2a94fe48f   Johannes Berg   genetlink: make m...
120
  	{ .name = "events", },
e5dcecba0   Johannes Berg   drop_monitor/gene...
121
  };
bec4596b4   Eric Dumazet   drop_monitor: don...
122
  static void send_dm_alert(struct work_struct *work)
9a8afc8d3   Neil Horman   Network Drop Moni...
123
124
  {
  	struct sk_buff *skb;
bec4596b4   Eric Dumazet   drop_monitor: don...
125
  	struct per_cpu_dm_data *data;
9a8afc8d3   Neil Horman   Network Drop Moni...
126

bec4596b4   Eric Dumazet   drop_monitor: don...
127
  	data = container_of(work, struct per_cpu_dm_data, dm_alert_work);
4fdcfa128   Neil Horman   drop_monitor: pre...
128

bec4596b4   Eric Dumazet   drop_monitor: don...
129
  	skb = reset_per_cpu_data(data);
9a8afc8d3   Neil Horman   Network Drop Moni...
130

3885ca785   Neil Horman   drop_monitor: Mak...
131
  	if (skb)
68eb55031   Johannes Berg   genetlink: pass f...
132
  		genlmsg_multicast(&net_drop_monitor_family, skb, 0,
2a94fe48f   Johannes Berg   genetlink: make m...
133
  				  0, GFP_KERNEL);
9a8afc8d3   Neil Horman   Network Drop Moni...
134
135
136
137
138
  }
  
  /*
   * This is the timer function to delay the sending of an alert
   * in the event that more drops will arrive during the
bec4596b4   Eric Dumazet   drop_monitor: don...
139
   * hysteresis period.
9a8afc8d3   Neil Horman   Network Drop Moni...
140
   */
bec4596b4   Eric Dumazet   drop_monitor: don...
141
  static void sched_send_work(unsigned long _data)
9a8afc8d3   Neil Horman   Network Drop Moni...
142
  {
bec4596b4   Eric Dumazet   drop_monitor: don...
143
  	struct per_cpu_dm_data *data = (struct per_cpu_dm_data *)_data;
3885ca785   Neil Horman   drop_monitor: Mak...
144

bec4596b4   Eric Dumazet   drop_monitor: don...
145
  	schedule_work(&data->dm_alert_work);
9a8afc8d3   Neil Horman   Network Drop Moni...
146
  }
4ea7e3869   Neil Horman   dropmon: add abil...
147
  static void trace_drop_common(struct sk_buff *skb, void *location)
9a8afc8d3   Neil Horman   Network Drop Moni...
148
149
150
  {
  	struct net_dm_alert_msg *msg;
  	struct nlmsghdr *nlh;
683703a26   Neil Horman   drop_monitor: Upd...
151
  	struct nlattr *nla;
9a8afc8d3   Neil Horman   Network Drop Moni...
152
  	int i;
3885ca785   Neil Horman   drop_monitor: Mak...
153
  	struct sk_buff *dskb;
bec4596b4   Eric Dumazet   drop_monitor: don...
154
155
  	struct per_cpu_dm_data *data;
  	unsigned long flags;
9a8afc8d3   Neil Horman   Network Drop Moni...
156

bec4596b4   Eric Dumazet   drop_monitor: don...
157
  	local_irq_save(flags);
903ceff7c   Christoph Lameter   net: Replace get_...
158
  	data = this_cpu_ptr(&dm_cpu_data);
bec4596b4   Eric Dumazet   drop_monitor: don...
159
160
  	spin_lock(&data->lock);
  	dskb = data->skb;
3885ca785   Neil Horman   drop_monitor: Mak...
161
162
163
  
  	if (!dskb)
  		goto out;
3885ca785   Neil Horman   drop_monitor: Mak...
164
  	nlh = (struct nlmsghdr *)dskb->data;
683703a26   Neil Horman   drop_monitor: Upd...
165
166
  	nla = genlmsg_data(nlmsg_data(nlh));
  	msg = nla_data(nla);
9a8afc8d3   Neil Horman   Network Drop Moni...
167
168
169
170
171
172
  	for (i = 0; i < msg->entries; i++) {
  		if (!memcmp(&location, msg->points[i].pc, sizeof(void *))) {
  			msg->points[i].count++;
  			goto out;
  		}
  	}
bec4596b4   Eric Dumazet   drop_monitor: don...
173
174
  	if (msg->entries == dm_hit_limit)
  		goto out;
9a8afc8d3   Neil Horman   Network Drop Moni...
175
176
177
  	/*
  	 * We need to create a new entry
  	 */
3885ca785   Neil Horman   drop_monitor: Mak...
178
  	__nla_reserve_nohdr(dskb, sizeof(struct net_dm_drop_point));
683703a26   Neil Horman   drop_monitor: Upd...
179
  	nla->nla_len += NLA_ALIGN(sizeof(struct net_dm_drop_point));
9a8afc8d3   Neil Horman   Network Drop Moni...
180
181
182
183
184
185
  	memcpy(msg->points[msg->entries].pc, &location, sizeof(void *));
  	msg->points[msg->entries].count = 1;
  	msg->entries++;
  
  	if (!timer_pending(&data->send_timer)) {
  		data->send_timer.expires = jiffies + dm_delay * HZ;
bec4596b4   Eric Dumazet   drop_monitor: don...
186
  		add_timer(&data->send_timer);
9a8afc8d3   Neil Horman   Network Drop Moni...
187
188
189
  	}
  
  out:
bec4596b4   Eric Dumazet   drop_monitor: don...
190
  	spin_unlock_irqrestore(&data->lock, flags);
9a8afc8d3   Neil Horman   Network Drop Moni...
191
  }
38516ab59   Steven Rostedt   tracing: Let trac...
192
  static void trace_kfree_skb_hit(void *ignore, struct sk_buff *skb, void *location)
4ea7e3869   Neil Horman   dropmon: add abil...
193
194
195
  {
  	trace_drop_common(skb, location);
  }
1db19db7f   Jesper Dangaard Brouer   net: tracepoint n...
196
197
  static void trace_napi_poll_hit(void *ignore, struct napi_struct *napi,
  				int work, int budget)
4ea7e3869   Neil Horman   dropmon: add abil...
198
199
200
201
  {
  	struct dm_hw_stat_delta *new_stat;
  
  	/*
5848cc096   Neil Horman   net: drop_monitor...
202
  	 * Don't check napi structures with no associated device
4ea7e3869   Neil Horman   dropmon: add abil...
203
  	 */
5848cc096   Neil Horman   net: drop_monitor...
204
  	if (!napi->dev)
4ea7e3869   Neil Horman   dropmon: add abil...
205
206
207
208
  		return;
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(new_stat, &hw_stats_list, list) {
5848cc096   Neil Horman   net: drop_monitor...
209
210
211
212
213
214
  		/*
  		 * only add a note to our monitor buffer if:
  		 * 1) this is the dev we received on
  		 * 2) its after the last_rx delta
  		 * 3) our rx_dropped count has gone up
  		 */
4ea7e3869   Neil Horman   dropmon: add abil...
215
  		if ((new_stat->dev == napi->dev)  &&
5848cc096   Neil Horman   net: drop_monitor...
216
  		    (time_after(jiffies, new_stat->last_rx + dm_hw_check_delta)) &&
4ea7e3869   Neil Horman   dropmon: add abil...
217
218
219
  		    (napi->dev->stats.rx_dropped != new_stat->last_drop_val)) {
  			trace_drop_common(NULL, NULL);
  			new_stat->last_drop_val = napi->dev->stats.rx_dropped;
5848cc096   Neil Horman   net: drop_monitor...
220
  			new_stat->last_rx = jiffies;
4ea7e3869   Neil Horman   dropmon: add abil...
221
222
223
224
225
  			break;
  		}
  	}
  	rcu_read_unlock();
  }
9a8afc8d3   Neil Horman   Network Drop Moni...
226
227
228
  static int set_all_monitor_traces(int state)
  {
  	int rc = 0;
4ea7e3869   Neil Horman   dropmon: add abil...
229
230
  	struct dm_hw_stat_delta *new_stat = NULL;
  	struct dm_hw_stat_delta *temp;
cde2e9a65   Neil Horman   drop_monitor: fix...
231
  	mutex_lock(&trace_state_mutex);
9a8afc8d3   Neil Horman   Network Drop Moni...
232

4b706372f   Neil Horman   drop_monitor: Add...
233
234
235
236
  	if (state == trace_state) {
  		rc = -EAGAIN;
  		goto out_unlock;
  	}
9a8afc8d3   Neil Horman   Network Drop Moni...
237
238
  	switch (state) {
  	case TRACE_ON:
cad456d5a   Neil Horman   drop_monitor: con...
239
240
241
242
  		if (!try_module_get(THIS_MODULE)) {
  			rc = -ENODEV;
  			break;
  		}
38516ab59   Steven Rostedt   tracing: Let trac...
243
244
  		rc |= register_trace_kfree_skb(trace_kfree_skb_hit, NULL);
  		rc |= register_trace_napi_poll(trace_napi_poll_hit, NULL);
9a8afc8d3   Neil Horman   Network Drop Moni...
245
  		break;
cad456d5a   Neil Horman   drop_monitor: con...
246

9a8afc8d3   Neil Horman   Network Drop Moni...
247
  	case TRACE_OFF:
38516ab59   Steven Rostedt   tracing: Let trac...
248
249
  		rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit, NULL);
  		rc |= unregister_trace_napi_poll(trace_napi_poll_hit, NULL);
9a8afc8d3   Neil Horman   Network Drop Moni...
250
251
  
  		tracepoint_synchronize_unregister();
4ea7e3869   Neil Horman   dropmon: add abil...
252
253
254
255
256
257
258
  
  		/*
  		 * Clean the device list
  		 */
  		list_for_each_entry_safe(new_stat, temp, &hw_stats_list, list) {
  			if (new_stat->dev == NULL) {
  				list_del_rcu(&new_stat->list);
fa81c0e1d   Lai Jiangshan   net,rcu: convert ...
259
  				kfree_rcu(new_stat, rcu);
4ea7e3869   Neil Horman   dropmon: add abil...
260
261
  			}
  		}
cad456d5a   Neil Horman   drop_monitor: con...
262
263
  
  		module_put(THIS_MODULE);
9a8afc8d3   Neil Horman   Network Drop Moni...
264
265
266
267
268
  		break;
  	default:
  		rc = 1;
  		break;
  	}
4ea7e3869   Neil Horman   dropmon: add abil...
269
270
  	if (!rc)
  		trace_state = state;
4b706372f   Neil Horman   drop_monitor: Add...
271
272
  	else
  		rc = -EINPROGRESS;
4ea7e3869   Neil Horman   dropmon: add abil...
273

4b706372f   Neil Horman   drop_monitor: Add...
274
  out_unlock:
cde2e9a65   Neil Horman   drop_monitor: fix...
275
  	mutex_unlock(&trace_state_mutex);
4ea7e3869   Neil Horman   dropmon: add abil...
276

9a8afc8d3   Neil Horman   Network Drop Moni...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
  	return rc;
  }
  
  
  static int net_dm_cmd_config(struct sk_buff *skb,
  			struct genl_info *info)
  {
  	return -ENOTSUPP;
  }
  
  static int net_dm_cmd_trace(struct sk_buff *skb,
  			struct genl_info *info)
  {
  	switch (info->genlhdr->cmd) {
  	case NET_DM_CMD_START:
  		return set_all_monitor_traces(TRACE_ON);
9a8afc8d3   Neil Horman   Network Drop Moni...
293
294
  	case NET_DM_CMD_STOP:
  		return set_all_monitor_traces(TRACE_OFF);
9a8afc8d3   Neil Horman   Network Drop Moni...
295
296
297
298
  	}
  
  	return -ENOTSUPP;
  }
4ea7e3869   Neil Horman   dropmon: add abil...
299
  static int dropmon_net_event(struct notifier_block *ev_block,
351638e7d   Jiri Pirko   net: pass info st...
300
  			     unsigned long event, void *ptr)
4ea7e3869   Neil Horman   dropmon: add abil...
301
  {
351638e7d   Jiri Pirko   net: pass info st...
302
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
4ea7e3869   Neil Horman   dropmon: add abil...
303
304
305
306
307
308
309
310
311
312
313
  	struct dm_hw_stat_delta *new_stat = NULL;
  	struct dm_hw_stat_delta *tmp;
  
  	switch (event) {
  	case NETDEV_REGISTER:
  		new_stat = kzalloc(sizeof(struct dm_hw_stat_delta), GFP_KERNEL);
  
  		if (!new_stat)
  			goto out;
  
  		new_stat->dev = dev;
5848cc096   Neil Horman   net: drop_monitor...
314
  		new_stat->last_rx = jiffies;
cde2e9a65   Neil Horman   drop_monitor: fix...
315
  		mutex_lock(&trace_state_mutex);
4ea7e3869   Neil Horman   dropmon: add abil...
316
  		list_add_rcu(&new_stat->list, &hw_stats_list);
cde2e9a65   Neil Horman   drop_monitor: fix...
317
  		mutex_unlock(&trace_state_mutex);
4ea7e3869   Neil Horman   dropmon: add abil...
318
319
  		break;
  	case NETDEV_UNREGISTER:
cde2e9a65   Neil Horman   drop_monitor: fix...
320
  		mutex_lock(&trace_state_mutex);
4ea7e3869   Neil Horman   dropmon: add abil...
321
322
323
324
325
  		list_for_each_entry_safe(new_stat, tmp, &hw_stats_list, list) {
  			if (new_stat->dev == dev) {
  				new_stat->dev = NULL;
  				if (trace_state == TRACE_OFF) {
  					list_del_rcu(&new_stat->list);
fa81c0e1d   Lai Jiangshan   net,rcu: convert ...
326
  					kfree_rcu(new_stat, rcu);
4ea7e3869   Neil Horman   dropmon: add abil...
327
328
329
330
  					break;
  				}
  			}
  		}
cde2e9a65   Neil Horman   drop_monitor: fix...
331
  		mutex_unlock(&trace_state_mutex);
4ea7e3869   Neil Horman   dropmon: add abil...
332
333
334
335
336
  		break;
  	}
  out:
  	return NOTIFY_DONE;
  }
9a8afc8d3   Neil Horman   Network Drop Moni...
337

4534de830   Johannes Berg   genetlink: make a...
338
  static const struct genl_ops dropmon_ops[] = {
9a8afc8d3   Neil Horman   Network Drop Moni...
339
340
341
342
343
344
345
346
347
348
349
350
351
  	{
  		.cmd = NET_DM_CMD_CONFIG,
  		.doit = net_dm_cmd_config,
  	},
  	{
  		.cmd = NET_DM_CMD_START,
  		.doit = net_dm_cmd_trace,
  	},
  	{
  		.cmd = NET_DM_CMD_STOP,
  		.doit = net_dm_cmd_trace,
  	},
  };
4ea7e3869   Neil Horman   dropmon: add abil...
352
353
354
  static struct notifier_block dropmon_net_notifier = {
  	.notifier_call = dropmon_net_event
  };
9a8afc8d3   Neil Horman   Network Drop Moni...
355
356
  static int __init init_net_drop_monitor(void)
  {
9a8afc8d3   Neil Horman   Network Drop Moni...
357
  	struct per_cpu_dm_data *data;
a256be70c   Changli Gao   drop_monitor: use...
358
  	int cpu, rc;
e005d193d   Joe Perches   net: core: Use pr...
359
360
  	pr_info("Initializing network drop monitor service
  ");
9a8afc8d3   Neil Horman   Network Drop Moni...
361
362
  
  	if (sizeof(void *) > 8) {
e005d193d   Joe Perches   net: core: Use pr...
363
364
  		pr_err("Unable to store program counters on this arch, Drop monitor failed
  ");
9a8afc8d3   Neil Horman   Network Drop Moni...
365
366
  		return -ENOSPC;
  	}
2a94fe48f   Johannes Berg   genetlink: make m...
367
368
  	rc = genl_register_family_with_ops_groups(&net_drop_monitor_family,
  						  dropmon_ops, dropmon_mcgrps);
a256be70c   Changli Gao   drop_monitor: use...
369
  	if (rc) {
e005d193d   Joe Perches   net: core: Use pr...
370
371
  		pr_err("Could not create drop monitor netlink family
  ");
a256be70c   Changli Gao   drop_monitor: use...
372
  		return rc;
9a8afc8d3   Neil Horman   Network Drop Moni...
373
  	}
2a94fe48f   Johannes Berg   genetlink: make m...
374
  	WARN_ON(net_drop_monitor_family.mcgrp_offset != NET_DM_GRP_ALERT);
e5dcecba0   Johannes Berg   drop_monitor/gene...
375

4ea7e3869   Neil Horman   dropmon: add abil...
376
377
  	rc = register_netdevice_notifier(&dropmon_net_notifier);
  	if (rc < 0) {
e005d193d   Joe Perches   net: core: Use pr...
378
379
  		pr_crit("Failed to register netdevice notifier
  ");
4ea7e3869   Neil Horman   dropmon: add abil...
380
381
  		goto out_unreg;
  	}
9a8afc8d3   Neil Horman   Network Drop Moni...
382
  	rc = 0;
cad456d5a   Neil Horman   drop_monitor: con...
383
  	for_each_possible_cpu(cpu) {
9a8afc8d3   Neil Horman   Network Drop Moni...
384
  		data = &per_cpu(dm_cpu_data, cpu);
9a8afc8d3   Neil Horman   Network Drop Moni...
385
386
  		INIT_WORK(&data->dm_alert_work, send_dm_alert);
  		init_timer(&data->send_timer);
bec4596b4   Eric Dumazet   drop_monitor: don...
387
  		data->send_timer.data = (unsigned long)data;
9a8afc8d3   Neil Horman   Network Drop Moni...
388
  		data->send_timer.function = sched_send_work;
bec4596b4   Eric Dumazet   drop_monitor: don...
389
  		spin_lock_init(&data->lock);
4fdcfa128   Neil Horman   drop_monitor: pre...
390
  		reset_per_cpu_data(data);
9a8afc8d3   Neil Horman   Network Drop Moni...
391
  	}
4ea7e3869   Neil Horman   dropmon: add abil...
392

3885ca785   Neil Horman   drop_monitor: Mak...
393

9a8afc8d3   Neil Horman   Network Drop Moni...
394
395
396
397
398
399
400
  	goto out;
  
  out_unreg:
  	genl_unregister_family(&net_drop_monitor_family);
  out:
  	return rc;
  }
cad456d5a   Neil Horman   drop_monitor: con...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  static void exit_net_drop_monitor(void)
  {
  	struct per_cpu_dm_data *data;
  	int cpu;
  
  	BUG_ON(unregister_netdevice_notifier(&dropmon_net_notifier));
  
  	/*
  	 * Because of the module_get/put we do in the trace state change path
  	 * we are guarnateed not to have any current users when we get here
  	 * all we need to do is make sure that we don't have any running timers
  	 * or pending schedule calls
  	 */
  
  	for_each_possible_cpu(cpu) {
  		data = &per_cpu(dm_cpu_data, cpu);
  		del_timer_sync(&data->send_timer);
  		cancel_work_sync(&data->dm_alert_work);
  		/*
  		 * At this point, we should have exclusive access
  		 * to this struct and can free the skb inside it
  		 */
  		kfree_skb(data->skb);
  	}
  
  	BUG_ON(genl_unregister_family(&net_drop_monitor_family));
  }
  
  module_init(init_net_drop_monitor);
  module_exit(exit_net_drop_monitor);
  
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>");
3fdcbd453   Neil Horman   drop_monitor: Add...
434
  MODULE_ALIAS_GENL_FAMILY("NET_DM");