From 344910a7a963165899fadc80bc64f55fde54c669 Mon Sep 17 00:00:00 2001
From: Masahide NAKAMURA <nakam@linux-ipv6.org>
Date: Fri, 1 Sep 2006 18:52:35 +0900
Subject: [PATCH] [XFRM]: Increment statistics.

Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
---
 net/ipv4/xfrm4_input.c  |   48 +++++++++++++++++++++++++++++----------
 net/ipv4/xfrm4_output.c |   17 ++++++++++---
 net/ipv6/xfrm6_input.c  |   57 +++++++++++++++++++++++++++++++++++-----------
 net/ipv6/xfrm6_output.c |   17 ++++++++++---
 net/xfrm/xfrm_policy.c  |   34 +++++++++++++++++++++++-----
 net/xfrm/xfrm_state.c   |    6 ++++-
 6 files changed, 138 insertions(+), 41 deletions(-)

diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 78e80de..96afb09 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -62,35 +62,51 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
 	int xfrm_nr = 0;
 	int decaps = 0;
 
-	if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) != 0)
+	if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) != 0) {
+		XFRM_INC_STATS(XFRM_MIB_INHDRERROR);
 		goto drop;
+	}
 
 	do {
 		struct iphdr *iph = skb->nh.iph;
 
-		if (xfrm_nr == XFRM_MAX_DEPTH)
+		if (xfrm_nr == XFRM_MAX_DEPTH) {
+			XFRM_INC_STATS(XFRM_MIB_INERROR);
 			goto drop;
+		}
 
 		x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi,
 				iph->protocol != IPPROTO_IPV6 ? iph->protocol : IPPROTO_IPIP, AF_INET);
-		if (x == NULL)
+		if (x == NULL) {
+			XFRM_INC_STATS(XFRM_MIB_INNOSTATES);
 			goto drop;
+		}
 
 		spin_lock(&x->lock);
-		if (unlikely(x->km.state != XFRM_STATE_VALID))
+		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
+			XFRM_INC_STATS(XFRM_MIB_INSTATEINVALID);
 			goto drop_unlock;
+		}
 
-		if ((x->encap ? x->encap->encap_type : 0) != encap_type)
+		if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
+			XFRM_INC_STATS(XFRM_MIB_INSTATEINVALID);
 			goto drop_unlock;
+		}
 
-		if (x->props.replay_window && xfrm_replay_check(x, seq))
+		if (x->props.replay_window && xfrm_replay_check(x, seq)) {
+			XFRM_INC_STATS(XFRM_MIB_INSEQOUTOFWINDOW);
 			goto drop_unlock;
+		}
 
-		if (xfrm_state_check_expire(x))
+		if (xfrm_state_check_expire(x)) {
+			XFRM_INC_STATS(XFRM_MIB_INSTATEEXPIRED);
 			goto drop_unlock;
+		}
 
-		if (x->type->input(x, skb))
+		if (x->type->input(x, skb)) {
+			XFRM_INC_STATS(XFRM_MIB_INSTATEPROTOERROR);
 			goto drop_unlock;
+		}
 
 		/* only the first xfrm gets the encap type */
 		encap_type = 0;
@@ -105,16 +121,20 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
 
 		xfrm_vec[xfrm_nr++] = x;
 
-		if (x->mode->input(x, skb))
+		if (x->mode->input(x, skb)) {
+			XFRM_INC_STATS(XFRM_MIB_INSTATEMODEERROR);
 			goto drop;
+		}
 
 		if (x->props.mode == XFRM_MODE_TUNNEL) {
 			decaps = 1;
 			break;
 		}
 
-		if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0)
+		if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0) {
+			XFRM_INC_STATS(XFRM_MIB_INHDRERROR);
 			goto drop;
+		}
 	} while (!err);
 
 	/* Allocate new secpath or COW existing one. */
@@ -122,14 +142,18 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
 	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
 		struct sec_path *sp;
 		sp = secpath_dup(skb->sp);
-		if (!sp)
+		if (!sp) {
+			XFRM_INC_STATS(XFRM_MIB_INERROR);
 			goto drop;
+		}
 		if (skb->sp)
 			secpath_put(skb->sp);
 		skb->sp = sp;
 	}
-	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
+	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) {
+		XFRM_INC_STATS(XFRM_MIB_INERROR);
 		goto drop;
+	}
 
 	memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
 	       xfrm_nr * sizeof(xfrm_vec[0]));
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 038ca16..a16dd1f 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -50,14 +50,18 @@ static int xfrm4_output_one(struct sk_buff *skb)
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		err = skb_checksum_help(skb);
-		if (err)
+		if (err) {
+			XFRM_INC_STATS(XFRM_MIB_OUTERROR);
 			goto error_nolock;
+		}
 	}
 
 	if (x->props.mode == XFRM_MODE_TUNNEL) {
 		err = xfrm4_tunnel_check_size(skb);
-		if (err)
+		if (err) {
+			XFRM_INC_STATS(XFRM_MIB_OUTLENGTHERROR);
 			goto error_nolock;
+		}
 	}
 
 	do {
@@ -67,12 +71,16 @@ static int xfrm4_output_one(struct sk_buff *skb)
 			goto error;
 
 		err = x->mode->output(x, skb);
-		if (err)
+		if (err) {
+			XFRM_INC_STATS(XFRM_MIB_OUTSTATEMODEERROR);
 			goto error;
+		}
 
 		err = x->type->output(x, skb);
-		if (err)
+		if (err) {
+			XFRM_INC_STATS(XFRM_MIB_OUTSTATEPROTOERROR);
 			goto error;
+		}
 
 		x->curlft.bytes += skb->len;
 		x->curlft.packets++;
@@ -80,6 +88,7 @@ static int xfrm4_output_one(struct sk_buff *skb)
 		spin_unlock_bh(&x->lock);
 
 		if (!(skb->dst = dst_pop(dst))) {
+			XFRM_INC_STATS(XFRM_MIB_OUTERROR);
 			err = -EHOSTUNREACH;
 			goto error_nolock;
 		}
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 31f651f..7b46f6a 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -31,32 +31,47 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi)
 	nexthdr = skb->nh.raw[nhoff];
 
 	seq = 0;
-	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
+	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
+		XFRM_INC_STATS(XFRM_MIB_INHDRERROR);
 		goto drop;
+	}
 
 	do {
 		struct ipv6hdr *iph = skb->nh.ipv6h;
 
-		if (xfrm_nr == XFRM_MAX_DEPTH)
+		if (xfrm_nr == XFRM_MAX_DEPTH) {
+			XFRM_INC_STATS(XFRM_MIB_INERROR);
 			goto drop;
+		}
 
 		x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi,
 				nexthdr != IPPROTO_IPIP ? nexthdr : IPPROTO_IPV6, AF_INET6);
-		if (x == NULL)
+		if (x == NULL) {
+			XFRM_INC_STATS(XFRM_MIB_INNOSTATES);
 			goto drop;
+		}
+
 		spin_lock(&x->lock);
-		if (unlikely(x->km.state != XFRM_STATE_VALID))
+		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
+			XFRM_INC_STATS(XFRM_MIB_INSTATEINVALID);
 			goto drop_unlock;
+		}
 
-		if (x->props.replay_window && xfrm_replay_check(x, seq))
+		if (x->props.replay_window && xfrm_replay_check(x, seq)) {
+			XFRM_INC_STATS(XFRM_MIB_INSEQOUTOFWINDOW);
 			goto drop_unlock;
+		}
 
-		if (xfrm_state_check_expire(x))
+		if (xfrm_state_check_expire(x)) {
+			XFRM_INC_STATS(XFRM_MIB_INSTATEEXPIRED);
 			goto drop_unlock;
+		}
 
 		nexthdr = x->type->input(x, skb);
-		if (nexthdr <= 0)
+		if (nexthdr <= 0) {
+			XFRM_INC_STATS(XFRM_MIB_INSTATEPROTOERROR);
 			goto drop_unlock;
+		}
 
 		skb->nh.raw[nhoff] = nexthdr;
 
@@ -70,31 +85,39 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi)
 
 		xfrm_vec[xfrm_nr++] = x;
 
-		if (x->mode->input(x, skb))
+		if (x->mode->input(x, skb)) {
+			XFRM_INC_STATS(XFRM_MIB_INSTATEMODEERROR);
 			goto drop;
+		}
 
 		if (x->props.mode == XFRM_MODE_TUNNEL) { /* XXX */
 			decaps = 1;
 			break;
 		}
 
-		if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0)
+		if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) {
+			XFRM_INC_STATS(XFRM_MIB_INHDRERROR);
 			goto drop;
+		}
 	} while (!err);
 
 	/* Allocate new secpath or COW existing one. */
 	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
 		struct sec_path *sp;
 		sp = secpath_dup(skb->sp);
-		if (!sp)
+		if (!sp) {
+			XFRM_INC_STATS(XFRM_MIB_INERROR);
 			goto drop;
+		}
 		if (skb->sp)
 			secpath_put(skb->sp);
 		skb->sp = sp;
 	}
 
-	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
+	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) {
+		XFRM_INC_STATS(XFRM_MIB_INERROR);
 		goto drop;
+	}
 
 	memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
 	       xfrm_nr * sizeof(xfrm_vec[0]));
@@ -221,22 +244,28 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 		break;
 	}
 
-	if (!xfrm_vec_one)
+	if (!xfrm_vec_one) {
+		XFRM_INC_STATS(XFRM_MIB_INNOSTATES);
 		goto drop;
+	}
 
 	/* Allocate new secpath or COW existing one. */
 	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
 		struct sec_path *sp;
 		sp = secpath_dup(skb->sp);
-		if (!sp)
+		if (!sp) {
+			XFRM_INC_STATS(XFRM_MIB_INERROR);
 			goto drop;
+		}
 		if (skb->sp)
 			secpath_put(skb->sp);
 		skb->sp = sp;
 	}
 
-	if (1 + skb->sp->len > XFRM_MAX_DEPTH)
+	if (1 + skb->sp->len > XFRM_MAX_DEPTH) {
+		XFRM_INC_STATS(XFRM_MIB_INERROR);
 		goto drop;
+	}
 
 	skb->sp->xvec[skb->sp->len] = xfrm_vec_one;
 	skb->sp->len ++;
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index d6d786b..bedb6ca 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -49,14 +49,18 @@ static int xfrm6_output_one(struct sk_buff *skb)
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		err = skb_checksum_help(skb);
-		if (err)
+		if (err) {
+			XFRM_INC_STATS(XFRM_MIB_OUTERROR);
 			goto error_nolock;
+		}
 	}
 
 	if (x->props.mode == XFRM_MODE_TUNNEL) {
 		err = xfrm6_tunnel_check_size(skb);
-		if (err)
+		if (err) {
+			XFRM_INC_STATS(XFRM_MIB_OUTLENGTHERROR);
 			goto error_nolock;
+		}
 	}
 
 	do {
@@ -66,12 +70,16 @@ static int xfrm6_output_one(struct sk_buff *skb)
 			goto error;
 
 		err = x->mode->output(x, skb);
-		if (err)
+		if (err) {
+			XFRM_INC_STATS(XFRM_MIB_OUTSTATEMODEERROR);
 			goto error;
+		}
 
 		err = x->type->output(x, skb);
-		if (err)
+		if (err) {
+			XFRM_INC_STATS(XFRM_MIB_OUTSTATEPROTOERROR);
 			goto error;
+		}
 
 		x->curlft.bytes += skb->len;
 		x->curlft.packets++;
@@ -83,6 +91,7 @@ static int xfrm6_output_one(struct sk_buff *skb)
 		skb->nh.raw = skb->data;
 
 		if (!(skb->dst = dst_pop(dst))) {
+			XFRM_INC_STATS(XFRM_MIB_OUTERROR);
 			err = -EHOSTUNREACH;
 			goto error_nolock;
 		}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index ad34b8b..ae0f686 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1397,6 +1397,7 @@ restart:
 	switch (policy->action) {
 	case XFRM_POLICY_BLOCK:
 		/* Prohibit the flow */
+		XFRM_INC_STATS(XFRM_MIB_OUTPOLBLOCK);
 		err = -EPERM;
 		goto error;
 
@@ -1416,6 +1417,7 @@ restart:
 		 */
 		dst = xfrm_find_bundle(fl, policy, family);
 		if (IS_ERR(dst)) {
+			XFRM_INC_STATS(XFRM_MIB_OUTBUNDLEERROR);
 			err = PTR_ERR(dst);
 			goto error;
 		}
@@ -1434,6 +1436,7 @@ restart:
 					goto error;
 				}
 				if (pols[1]->action == XFRM_POLICY_BLOCK) {
+					XFRM_INC_STATS(XFRM_MIB_OUTPOLBLOCK);
 					err = -EPERM;
 					goto error;
 				}
@@ -1472,6 +1475,7 @@ restart:
 				nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
 
 				if (nx == -EAGAIN && signal_pending(current)) {
+					XFRM_INC_STATS(XFRM_MIB_OUTNOSTATES);
 					err = -ERESTART;
 					goto error;
 				}
@@ -1482,8 +1486,10 @@ restart:
 				}
 				err = nx;
 			}
-			if (err < 0)
+			if (err < 0) {
+				XFRM_INC_STATS(XFRM_MIB_OUTNOSTATES);
 				goto error;
+			}
 		}
 		if (nx == 0) {
 			/* Flow passes not transformed. */
@@ -1498,6 +1504,7 @@ restart:
 			int i;
 			for (i=0; i<nx; i++)
 				xfrm_state_put(xfrm[i]);
+			XFRM_INC_STATS(XFRM_MIB_OUTBUNDLEERROR);
 			goto error;
 		}
 
@@ -1518,6 +1525,7 @@ restart:
 			if (dst)
 				dst_free(dst);
 
+			XFRM_INC_STATS(XFRM_MIB_OUTBUNDLEERROR);
 			err = -EHOSTUNREACH;
 			goto error;
 		}
@@ -1660,8 +1668,11 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
 	u8 fl_dir = policy_to_flow_dir(dir);
 	int xerr_idx = -1;
 
-	if (xfrm_decode_session(skb, &fl, family) < 0)
+	if (xfrm_decode_session(skb, &fl, family) < 0) {
+		XFRM_INC_STATS(XFRM_MIB_INHDRERROR);
 		return 0;
+	}
+
 	nf_nat_decode_session(skb, &fl, family);
 
 	/* First, check used SA against their selectors. */
@@ -1670,8 +1681,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
 
 		for (i=skb->sp->len-1; i>=0; i--) {
 			struct xfrm_state *x = skb->sp->xvec[i];
-			if (!xfrm_selector_match(&x->sel, &fl, family))
+			if (!xfrm_selector_match(&x->sel, &fl, family)) {
+				XFRM_INC_STATS(XFRM_MIB_INSTATEINVALID);
 				return 0;
+			}
 		}
 	}
 
@@ -1692,6 +1705,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
 	if (!pol) {
 		if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
 			xfrm_secpath_reject(xerr_idx, skb, &fl);
+			XFRM_INC_STATS(XFRM_MIB_INNOPOLS);
 			return 0;
 		}
 		return 1;
@@ -1729,10 +1743,14 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
 
 		for (pi = 0; pi < npols; pi++) {
 			if (pols[pi] != pol &&
-			    pols[pi]->action != XFRM_POLICY_ALLOW)
+			    pols[pi]->action != XFRM_POLICY_ALLOW) {
+				XFRM_INC_STATS(XFRM_MIB_INPOLBLOCK);
 				goto reject;
-			if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH)
+			}
+			if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) {
+				XFRM_INC_STATS(XFRM_MIB_INERROR);
 				goto reject_error;
+			}
 			for (i = 0; i < pols[pi]->xfrm_nr; i++)
 				tpp[ti++] = &pols[pi]->xfrm_vec[i];
 		}
@@ -1754,16 +1772,20 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
 				if (k < -1)
 					/* "-2 - errored_index" returned */
 					xerr_idx = -(2+k);
+				XFRM_INC_STATS(XFRM_MIB_INTMPLMISMATCH);
 				goto reject;
 			}
 		}
 
-		if (secpath_has_nontransport(sp, k, &xerr_idx))
+		if (secpath_has_nontransport(sp, k, &xerr_idx)) {
+			XFRM_INC_STATS(XFRM_MIB_INTMPLMISMATCH);
 			goto reject;
+		}
 
 		xfrm_pols_put(pols, npols);
 		return 1;
 	}
+	XFRM_INC_STATS(XFRM_MIB_INPOLBLOCK);
 
 reject:
 	xfrm_secpath_reject(xerr_idx, skb, &fl);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 90f7af5..473804f 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1133,9 +1133,13 @@ static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
 int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err = xfrm_state_check_expire(x);
-	if (err < 0)
+	if (err < 0) {
+		XFRM_INC_STATS(XFRM_MIB_OUTSTATEEXPIRED);
 		goto err;
+	}
 	err = xfrm_state_check_space(x, skb);
+	if (err)
+		XFRM_INC_STATS(XFRM_MIB_OUTLENGTHERROR);
 err:
 	return err;
 }
-- 
1.5.0.3

