2222#include <linux/timer.h>
2323#include <linux/bitops.h>
2424#include <net/genetlink.h>
25+ #include <net/netevent.h>
2526
2627#include <trace/skb.h>
28+ #include <trace/napi.h>
2729
2830#include <asm/unaligned.h>
2931
@@ -38,7 +40,8 @@ static void send_dm_alert(struct work_struct *unused);
3840 * and the work handle that will send up
3941 * netlink alerts
4042 */
41- struct sock * dm_sock ;
43+ static int trace_state = TRACE_OFF ;
44+ static spinlock_t trace_state_lock = SPIN_LOCK_UNLOCKED ;
4245
4346struct per_cpu_dm_data {
4447 struct work_struct dm_alert_work ;
@@ -47,6 +50,13 @@ struct per_cpu_dm_data {
4750 struct timer_list send_timer ;
4851};
4952
53+ struct dm_hw_stat_delta {
54+ struct net_device * dev ;
55+ struct list_head list ;
56+ struct rcu_head rcu ;
57+ unsigned long last_drop_val ;
58+ };
59+
5060static struct genl_family net_drop_monitor_family = {
5161 .id = GENL_ID_GENERATE ,
5262 .hdrsize = 0 ,
@@ -59,7 +69,8 @@ static DEFINE_PER_CPU(struct per_cpu_dm_data, dm_cpu_data);
5969
6070static int dm_hit_limit = 64 ;
6171static int dm_delay = 1 ;
62-
72+ static unsigned long dm_hw_check_delta = 2 * HZ ;
73+ static LIST_HEAD (hw_stats_list );
6374
6475static void reset_per_cpu_data (struct per_cpu_dm_data * data )
6576{
@@ -115,7 +126,7 @@ static void sched_send_work(unsigned long unused)
115126 schedule_work (& data -> dm_alert_work );
116127}
117128
118- static void trace_kfree_skb_hit (struct sk_buff * skb , void * location )
129+ static void trace_drop_common (struct sk_buff * skb , void * location )
119130{
120131 struct net_dm_alert_msg * msg ;
121132 struct nlmsghdr * nlh ;
@@ -159,24 +170,80 @@ static void trace_kfree_skb_hit(struct sk_buff *skb, void *location)
159170 return ;
160171}
161172
173+ static void trace_kfree_skb_hit (struct sk_buff * skb , void * location )
174+ {
175+ trace_drop_common (skb , location );
176+ }
177+
178+ static void trace_napi_poll_hit (struct napi_struct * napi )
179+ {
180+ struct dm_hw_stat_delta * new_stat ;
181+
182+ /*
183+ * Ratelimit our check time to dm_hw_check_delta jiffies
184+ */
185+ if (!time_after (jiffies , napi -> dev -> last_rx + dm_hw_check_delta ))
186+ return ;
187+
188+ rcu_read_lock ();
189+ list_for_each_entry_rcu (new_stat , & hw_stats_list , list ) {
190+ if ((new_stat -> dev == napi -> dev ) &&
191+ (napi -> dev -> stats .rx_dropped != new_stat -> last_drop_val )) {
192+ trace_drop_common (NULL , NULL );
193+ new_stat -> last_drop_val = napi -> dev -> stats .rx_dropped ;
194+ break ;
195+ }
196+ }
197+ rcu_read_unlock ();
198+ }
199+
200+
201+ static void free_dm_hw_stat (struct rcu_head * head )
202+ {
203+ struct dm_hw_stat_delta * n ;
204+ n = container_of (head , struct dm_hw_stat_delta , rcu );
205+ kfree (n );
206+ }
207+
162208static int set_all_monitor_traces (int state )
163209{
164210 int rc = 0 ;
211+ struct dm_hw_stat_delta * new_stat = NULL ;
212+ struct dm_hw_stat_delta * temp ;
213+
214+ spin_lock (& trace_state_lock );
165215
166216 switch (state ) {
167217 case TRACE_ON :
168218 rc |= register_trace_kfree_skb (trace_kfree_skb_hit );
219+ rc |= register_trace_napi_poll (trace_napi_poll_hit );
169220 break ;
170221 case TRACE_OFF :
171222 rc |= unregister_trace_kfree_skb (trace_kfree_skb_hit );
223+ rc |= unregister_trace_napi_poll (trace_napi_poll_hit );
172224
173225 tracepoint_synchronize_unregister ();
226+
227+ /*
228+ * Clean the device list
229+ */
230+ list_for_each_entry_safe (new_stat , temp , & hw_stats_list , list ) {
231+ if (new_stat -> dev == NULL ) {
232+ list_del_rcu (& new_stat -> list );
233+ call_rcu (& new_stat -> rcu , free_dm_hw_stat );
234+ }
235+ }
174236 break ;
175237 default :
176238 rc = 1 ;
177239 break ;
178240 }
179241
242+ if (!rc )
243+ trace_state = state ;
244+
245+ spin_unlock (& trace_state_lock );
246+
180247 if (rc )
181248 return - EINPROGRESS ;
182249 return rc ;
@@ -204,6 +271,44 @@ static int net_dm_cmd_trace(struct sk_buff *skb,
204271 return - ENOTSUPP ;
205272}
206273
274+ static int dropmon_net_event (struct notifier_block * ev_block ,
275+ unsigned long event , void * ptr )
276+ {
277+ struct net_device * dev = ptr ;
278+ struct dm_hw_stat_delta * new_stat = NULL ;
279+ struct dm_hw_stat_delta * tmp ;
280+
281+ switch (event ) {
282+ case NETDEV_REGISTER :
283+ new_stat = kzalloc (sizeof (struct dm_hw_stat_delta ), GFP_KERNEL );
284+
285+ if (!new_stat )
286+ goto out ;
287+
288+ new_stat -> dev = dev ;
289+ INIT_RCU_HEAD (& new_stat -> rcu );
290+ spin_lock (& trace_state_lock );
291+ list_add_rcu (& new_stat -> list , & hw_stats_list );
292+ spin_unlock (& trace_state_lock );
293+ break ;
294+ case NETDEV_UNREGISTER :
295+ spin_lock (& trace_state_lock );
296+ list_for_each_entry_safe (new_stat , tmp , & hw_stats_list , list ) {
297+ if (new_stat -> dev == dev ) {
298+ new_stat -> dev = NULL ;
299+ if (trace_state == TRACE_OFF ) {
300+ list_del_rcu (& new_stat -> list );
301+ call_rcu (& new_stat -> rcu , free_dm_hw_stat );
302+ break ;
303+ }
304+ }
305+ }
306+ spin_unlock (& trace_state_lock );
307+ break ;
308+ }
309+ out :
310+ return NOTIFY_DONE ;
311+ }
207312
208313static struct genl_ops dropmon_ops [] = {
209314 {
@@ -220,6 +325,10 @@ static struct genl_ops dropmon_ops[] = {
220325 },
221326};
222327
328+ static struct notifier_block dropmon_net_notifier = {
329+ .notifier_call = dropmon_net_event
330+ };
331+
223332static int __init init_net_drop_monitor (void )
224333{
225334 int cpu ;
@@ -243,12 +352,18 @@ static int __init init_net_drop_monitor(void)
243352 ret = genl_register_ops (& net_drop_monitor_family ,
244353 & dropmon_ops [i ]);
245354 if (ret ) {
246- printk (KERN_CRIT "failed to register operation %d\n" ,
355+ printk (KERN_CRIT "Failed to register operation %d\n" ,
247356 dropmon_ops [i ].cmd );
248357 goto out_unreg ;
249358 }
250359 }
251360
361+ rc = register_netdevice_notifier (& dropmon_net_notifier );
362+ if (rc < 0 ) {
363+ printk (KERN_CRIT "Failed to register netdevice notifier\n" );
364+ goto out_unreg ;
365+ }
366+
252367 rc = 0 ;
253368
254369 for_each_present_cpu (cpu ) {
@@ -259,6 +374,7 @@ static int __init init_net_drop_monitor(void)
259374 data -> send_timer .data = cpu ;
260375 data -> send_timer .function = sched_send_work ;
261376 }
377+
262378 goto out ;
263379
264380out_unreg :
0 commit comments