From d5511f877e8bc0f705d2eea1c1054e7f847bb226 Mon Sep 17 00:00:00 2001
From: JP Abgrall <jpa@google.com>
Date: Fri, 19 Aug 2011 20:21:06 -0700
Subject: [PATCH 662/696] netfilter: xt_qtaguid: add some tagging/matching stats

/proc/net/xt_qtaguid/ctrl will now show:
  active tagged sockets: lines of "sock=%p tag=0x%llx (uid=%u)"
  sockets_tagged, : the number of sockets successfully tagged.
  sockets_untagged: the number of sockets successfully untagged.
  counter_set_changes: ctrl counter set change requests.
  delete_cmds: ctrl delete commands completed.
  iface_events: number of NETDEV_* events handled.
  match_found_sk: sk found in skbuff without ct assist.
  match_found_sk_in_ct: the number of times the connection tracker found
    a socket for us. This happens when the skbuff didn't have info.
  match_found_sk_none: the number of times no sk could be determined
    successfully looked up. This indicates we don't know who the
    data actually belongs to. This could be unsolicited traffic.

Change-Id: I3a65613bb24852e1eea768ab0320a6a7073ab9be
Signed-off-by: JP Abgrall <jpa@google.com>
---
 net/netfilter/xt_qtaguid.c |   64 ++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 968693c..5afd419 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -222,6 +222,28 @@ struct sock_tag {
 	tag_t tag;
 };
 
+struct qtaguid_event_counts {
+	/* Various successful events */
+	atomic64_t sockets_tagged;
+	atomic64_t sockets_untagged;
+	atomic64_t counter_set_changes;
+	atomic64_t delete_cmds;
+	atomic64_t iface_events;  /* Number of NETDEV_* events handled */
+	/*
+	 * match_found_sk_*: numbers related to the netfilter matching
+	 * function finding a sock for the sk_buff.
+	 */
+	atomic64_t match_found_sk;   /* An sk was already in the sk_buff. */
+	/* The connection tracker had the sk. */
+	atomic64_t match_found_sk_in_ct;
+	/*
+	 * No sk could be found. No apparent owner. Could happen with
+	 * unsolicited traffic.
+	 */
+	atomic64_t match_found_sk_none;
+};
+static struct qtaguid_event_counts qtu_events;
+
 static struct rb_root sock_tag_tree = RB_ROOT;
 static DEFINE_SPINLOCK(sock_tag_list_lock);
 
@@ -954,6 +976,7 @@ static int iface_inet6addr_event_handler(struct notifier_block *nb,
 		BUG_ON(!ifa || !ifa->idev);
 		dev = (struct net_device *)ifa->idev->dev;
 		iface_stat_create_ipv6(dev, ifa);
+		atomic64_inc(&qtu_events.iface_events);
 		break;
 	}
 	return NOTIFY_DONE;
@@ -977,6 +1000,7 @@ static int iface_inetaddr_event_handler(struct notifier_block *nb,
 		BUG_ON(!ifa || !ifa->ifa_dev);
 		dev = ifa->ifa_dev->dev;
 		iface_stat_create(dev, ifa);
+		atomic64_inc(&qtu_events.iface_events);
 		break;
 	}
 	return NOTIFY_DONE;
@@ -1149,6 +1173,10 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
 		 * it back, as nf_tproxy_get_sock_v4() got it.
 		 */
 		got_sock = sk;
+		if (sk)
+			atomic64_inc(&qtu_events.match_found_sk_in_ct);
+	} else {
+		atomic64_inc(&qtu_events.match_found_sk);
 	}
 	MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d proto=%d\n",
 		par->hooknum, sk, got_sock, ip_hdr(skb)->protocol);
@@ -1178,6 +1206,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
 			par->hooknum,
 			sk ? sk->sk_socket : NULL);
 		res = (info->match ^ info->invert) == 0;
+		atomic64_inc(&qtu_events.match_found_sk_none);
 		goto put_sock_ret_res;
 	} else if (info->match & info->invert & XT_QTAGUID_SOCKET) {
 		res = false;
@@ -1254,6 +1283,7 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned,
 		return 0;
 	}
 
+	/* TODO: support skipping num_items_returned on entry. */
 	CT_DEBUG("qtaguid: proc ctrl page=%p off=%ld char_count=%d *eof=%d\n",
 		page, items_to_skip, char_count, *eof);
 
@@ -1286,6 +1316,34 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned,
 		(*num_items_returned)++;
 	}
 	spin_unlock_bh(&sock_tag_list_lock);
+
+	if (item_index++ >= items_to_skip) {
+		len = snprintf(outp, char_count,
+			       "events: sockets_tagged=%llu "
+			       "sockets_untagged=%llu "
+			       "counter_set_changes=%llu "
+			       "delete_cmds=%llu "
+			       "iface_events=%llu "
+			       "match_found_sk=%llu "
+			       "match_found_sk_in_ct=%llu "
+			       "match_found_sk_none=%llu\n",
+			       atomic64_read(&qtu_events.sockets_tagged),
+			       atomic64_read(&qtu_events.sockets_untagged),
+			       atomic64_read(&qtu_events.counter_set_changes),
+			       atomic64_read(&qtu_events.delete_cmds),
+			       atomic64_read(&qtu_events.iface_events),
+			       atomic64_read(&qtu_events.match_found_sk),
+			       atomic64_read(&qtu_events.match_found_sk_in_ct),
+			       atomic64_read(&qtu_events.match_found_sk_none));
+		if (len >= char_count) {
+			*outp = '\0';
+			return outp - page;
+		}
+		outp += len;
+		char_count -= len;
+		(*num_items_returned)++;
+	}
+
 	*eof = 1;
 	return outp - page;
 }
@@ -1428,7 +1486,7 @@ static int ctrl_cmd_delete(const char *input)
 		spin_unlock_bh(&iface_entry->tag_stat_list_lock);
 	}
 	spin_unlock_bh(&iface_stat_list_lock);
-
+	atomic64_inc(&qtu_events.delete_cmds);
 	res = 0;
 
 err:
@@ -1487,7 +1545,7 @@ static int ctrl_cmd_counter_set(const char *input)
 	}
 	tcs->active_set = counter_set;
 	spin_unlock_bh(&tag_counter_set_list_lock);
-
+	atomic64_inc(&qtu_events.counter_set_changes);
 	res = 0;
 
 err:
@@ -1573,6 +1631,7 @@ static int ctrl_cmd_tag(const char *input)
 		sock_tag_entry->tag = combine_atag_with_uid(acct_tag,
 							    uid);
 		sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
+		atomic64_inc(&qtu_events.sockets_tagged);
 	}
 	spin_unlock_bh(&sock_tag_list_lock);
 	/* We keep the ref to the socket (file) until it is untagged */
@@ -1638,6 +1697,7 @@ static int ctrl_cmd_untag(const char *input)
 	sockfd_put(el_socket);
 	refcnt -= 2;
 	kfree(sock_tag_entry);
+	atomic64_inc(&qtu_events.sockets_untagged);
 	CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%d\n",
 		 input, refcnt);
 
-- 
1.7.1


