Commit 0aa64774 authored by Masahide NAKAMURA's avatar Masahide NAKAMURA Committed by David S. Miller

[XFRM]: Support to increment packet dropping statistics.

Signed-off-by: default avatarMasahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 558f82ef
...@@ -72,6 +72,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, ...@@ -72,6 +72,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
sp = secpath_dup(skb->sp); sp = secpath_dup(skb->sp);
if (!sp) { if (!sp) {
XFRM_INC_STATS(LINUX_MIB_XFRMINERROR);
goto drop; goto drop;
} }
if (skb->sp) if (skb->sp)
...@@ -80,6 +81,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, ...@@ -80,6 +81,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
} }
if (1 + skb->sp->len == XFRM_MAX_DEPTH) { if (1 + skb->sp->len == XFRM_MAX_DEPTH) {
XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR);
goto drop; goto drop;
} }
...@@ -149,6 +151,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, ...@@ -149,6 +151,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
} }
if (!x) { if (!x) {
XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES);
goto drop; goto drop;
} }
......
...@@ -119,8 +119,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) ...@@ -119,8 +119,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
struct sec_path *sp; struct sec_path *sp;
sp = secpath_dup(skb->sp); sp = secpath_dup(skb->sp);
if (!sp) if (!sp) {
XFRM_INC_STATS(LINUX_MIB_XFRMINERROR);
goto drop; goto drop;
}
if (skb->sp) if (skb->sp)
secpath_put(skb->sp); secpath_put(skb->sp);
skb->sp = sp; skb->sp = sp;
...@@ -131,31 +133,45 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) ...@@ -131,31 +133,45 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
family = XFRM_SPI_SKB_CB(skb)->family; family = XFRM_SPI_SKB_CB(skb)->family;
seq = 0; 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(LINUX_MIB_XFRMINHDRERROR);
goto drop; goto drop;
}
do { do {
if (skb->sp->len == XFRM_MAX_DEPTH) if (skb->sp->len == XFRM_MAX_DEPTH) {
XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR);
goto drop; goto drop;
}
x = xfrm_state_lookup(daddr, spi, nexthdr, family); x = xfrm_state_lookup(daddr, spi, nexthdr, family);
if (x == NULL) if (x == NULL) {
XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES);
goto drop; goto drop;
}
skb->sp->xvec[skb->sp->len++] = x; skb->sp->xvec[skb->sp->len++] = x;
spin_lock(&x->lock); spin_lock(&x->lock);
if (unlikely(x->km.state != XFRM_STATE_VALID)) if (unlikely(x->km.state != XFRM_STATE_VALID)) {
XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID);
goto drop_unlock; 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(LINUX_MIB_XFRMINSTATEINVALID);
goto drop_unlock; 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(LINUX_MIB_XFRMINSEQOUTOFWINDOW);
goto drop_unlock; goto drop_unlock;
}
if (xfrm_state_check_expire(x)) if (xfrm_state_check_expire(x)) {
XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEEXPIRED);
goto drop_unlock; goto drop_unlock;
}
spin_unlock(&x->lock); spin_unlock(&x->lock);
...@@ -171,6 +187,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) ...@@ -171,6 +187,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
if (nexthdr <= 0) { if (nexthdr <= 0) {
if (nexthdr == -EBADMSG) if (nexthdr == -EBADMSG)
x->stats.integrity_failed++; x->stats.integrity_failed++;
XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEPROTOERROR);
goto drop_unlock; goto drop_unlock;
} }
...@@ -187,8 +204,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) ...@@ -187,8 +204,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
if (x->inner_mode->input(x, skb)) if (x->inner_mode->input(x, skb)) {
XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMODEERROR);
goto drop; goto drop;
}
if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
decaps = 1; decaps = 1;
...@@ -203,8 +222,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) ...@@ -203,8 +222,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
family = x->outer_mode->afinfo->family; family = x->outer_mode->afinfo->family;
err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
if (err < 0) if (err < 0) {
XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR);
goto drop; goto drop;
}
} while (!err); } while (!err);
nf_reset(skb); nf_reset(skb);
......
...@@ -69,10 +69,13 @@ static int xfrm_output_one(struct sk_buff *skb, int err) ...@@ -69,10 +69,13 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
err = x->type->output(x, skb); err = x->type->output(x, skb);
resume: resume:
if (err) if (err) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATEPROTOERROR);
goto error_nolock; goto error_nolock;
}
if (!(skb->dst = dst_pop(dst))) { if (!(skb->dst = dst_pop(dst))) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR);
err = -EHOSTUNREACH; err = -EHOSTUNREACH;
goto error_nolock; goto error_nolock;
} }
...@@ -167,6 +170,7 @@ int xfrm_output(struct sk_buff *skb) ...@@ -167,6 +170,7 @@ int xfrm_output(struct sk_buff *skb)
if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb->ip_summed == CHECKSUM_PARTIAL) {
err = skb_checksum_help(skb); err = skb_checksum_help(skb);
if (err) { if (err) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR);
kfree_skb(skb); kfree_skb(skb);
return err; return err;
} }
......
...@@ -1494,9 +1494,11 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1494,9 +1494,11 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
err = PTR_ERR(policy); err = PTR_ERR(policy);
if (IS_ERR(policy)) if (IS_ERR(policy)) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR);
goto dropdst; goto dropdst;
} }
}
if (!policy) { if (!policy) {
/* To accelerate a bit... */ /* To accelerate a bit... */
...@@ -1529,6 +1531,7 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1529,6 +1531,7 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
default: default:
case XFRM_POLICY_BLOCK: case XFRM_POLICY_BLOCK:
/* Prohibit the flow */ /* Prohibit the flow */
XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLBLOCK);
err = -EPERM; err = -EPERM;
goto error; goto error;
...@@ -1548,6 +1551,7 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1548,6 +1551,7 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
*/ */
dst = xfrm_find_bundle(fl, policy, family); dst = xfrm_find_bundle(fl, policy, family);
if (IS_ERR(dst)) { if (IS_ERR(dst)) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
err = PTR_ERR(dst); err = PTR_ERR(dst);
goto error; goto error;
} }
...@@ -1562,10 +1566,12 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1562,10 +1566,12 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
XFRM_POLICY_OUT); XFRM_POLICY_OUT);
if (pols[1]) { if (pols[1]) {
if (IS_ERR(pols[1])) { if (IS_ERR(pols[1])) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR);
err = PTR_ERR(pols[1]); err = PTR_ERR(pols[1]);
goto error; goto error;
} }
if (pols[1]->action == XFRM_POLICY_BLOCK) { if (pols[1]->action == XFRM_POLICY_BLOCK) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLBLOCK);
err = -EPERM; err = -EPERM;
goto error; goto error;
} }
...@@ -1611,6 +1617,7 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1611,6 +1617,7 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
if (nx == -EAGAIN && signal_pending(current)) { if (nx == -EAGAIN && signal_pending(current)) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES);
err = -ERESTART; err = -ERESTART;
goto error; goto error;
} }
...@@ -1621,9 +1628,11 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1621,9 +1628,11 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
} }
err = nx; err = nx;
} }
if (err < 0) if (err < 0) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES);
goto error; goto error;
} }
}
if (nx == 0) { if (nx == 0) {
/* Flow passes not transformed. */ /* Flow passes not transformed. */
xfrm_pols_put(pols, npols); xfrm_pols_put(pols, npols);
...@@ -1632,8 +1641,10 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1632,8 +1641,10 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig); dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig);
err = PTR_ERR(dst); err = PTR_ERR(dst);
if (IS_ERR(dst)) if (IS_ERR(dst)) {
XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLEGENERROR);
goto error; goto error;
}
for (pi = 0; pi < npols; pi++) { for (pi = 0; pi < npols; pi++) {
read_lock_bh(&pols[pi]->lock); read_lock_bh(&pols[pi]->lock);
...@@ -1652,6 +1663,10 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1652,6 +1663,10 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
if (dst) if (dst)
dst_free(dst); dst_free(dst);
if (pol_dead)
XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLDEAD);
else
XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
err = -EHOSTUNREACH; err = -EHOSTUNREACH;
goto error; goto error;
} }
...@@ -1664,6 +1679,7 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1664,6 +1679,7 @@ int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
write_unlock_bh(&policy->lock); write_unlock_bh(&policy->lock);
if (dst) if (dst)
dst_free(dst); dst_free(dst);
XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
goto error; goto error;
} }
...@@ -1817,8 +1833,11 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -1817,8 +1833,11 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
dir &= XFRM_POLICY_MASK; dir &= XFRM_POLICY_MASK;
fl_dir = policy_to_flow_dir(dir); fl_dir = policy_to_flow_dir(dir);
if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) {
XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR);
return 0; return 0;
}
nf_nat_decode_session(skb, &fl, family); nf_nat_decode_session(skb, &fl, family);
/* First, check used SA against their selectors. */ /* First, check used SA against their selectors. */
...@@ -1827,28 +1846,35 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -1827,28 +1846,35 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
for (i=skb->sp->len-1; i>=0; i--) { for (i=skb->sp->len-1; i>=0; i--) {
struct xfrm_state *x = skb->sp->xvec[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(LINUX_MIB_XFRMINSTATEMISMATCH);
return 0; return 0;
} }
} }
}
pol = NULL; pol = NULL;
if (sk && sk->sk_policy[dir]) { if (sk && sk->sk_policy[dir]) {
pol = xfrm_sk_policy_lookup(sk, dir, &fl); pol = xfrm_sk_policy_lookup(sk, dir, &fl);
if (IS_ERR(pol)) if (IS_ERR(pol)) {
XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR);
return 0; return 0;
} }
}
if (!pol) if (!pol)
pol = flow_cache_lookup(&fl, family, fl_dir, pol = flow_cache_lookup(&fl, family, fl_dir,
xfrm_policy_lookup); xfrm_policy_lookup);
if (IS_ERR(pol)) if (IS_ERR(pol)) {
XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR);
return 0; return 0;
}
if (!pol) { if (!pol) {
if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
xfrm_secpath_reject(xerr_idx, skb, &fl); xfrm_secpath_reject(xerr_idx, skb, &fl);
XFRM_INC_STATS(LINUX_MIB_XFRMINNOPOLS);
return 0; return 0;
} }
return 1; return 1;
...@@ -1864,8 +1890,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -1864,8 +1890,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
&fl, family, &fl, family,
XFRM_POLICY_IN); XFRM_POLICY_IN);
if (pols[1]) { if (pols[1]) {
if (IS_ERR(pols[1])) if (IS_ERR(pols[1])) {
XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR);
return 0; return 0;
}
pols[1]->curlft.use_time = get_seconds(); pols[1]->curlft.use_time = get_seconds();
npols ++; npols ++;
} }
...@@ -1886,10 +1914,14 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -1886,10 +1914,14 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
for (pi = 0; pi < npols; pi++) { for (pi = 0; pi < npols; pi++) {
if (pols[pi] != pol && if (pols[pi] != pol &&
pols[pi]->action != XFRM_POLICY_ALLOW) pols[pi]->action != XFRM_POLICY_ALLOW) {
XFRM_INC_STATS(LINUX_MIB_XFRMINPOLBLOCK);
goto reject; goto reject;
if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) }
if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) {
XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR);
goto reject_error; goto reject_error;
}
for (i = 0; i < pols[pi]->xfrm_nr; i++) for (i = 0; i < pols[pi]->xfrm_nr; i++)
tpp[ti++] = &pols[pi]->xfrm_vec[i]; tpp[ti++] = &pols[pi]->xfrm_vec[i];
} }
...@@ -1911,16 +1943,20 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -1911,16 +1943,20 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
if (k < -1) if (k < -1)
/* "-2 - errored_index" returned */ /* "-2 - errored_index" returned */
xerr_idx = -(2+k); xerr_idx = -(2+k);
XFRM_INC_STATS(LINUX_MIB_XFRMINTMPLMISMATCH);
goto reject; goto reject;
} }
} }
if (secpath_has_nontransport(sp, k, &xerr_idx)) if (secpath_has_nontransport(sp, k, &xerr_idx)) {
XFRM_INC_STATS(LINUX_MIB_XFRMINTMPLMISMATCH);
goto reject; goto reject;
}
xfrm_pols_put(pols, npols); xfrm_pols_put(pols, npols);
return 1; return 1;
} }
XFRM_INC_STATS(LINUX_MIB_XFRMINPOLBLOCK);
reject: reject:
xfrm_secpath_reject(xerr_idx, skb, &fl); xfrm_secpath_reject(xerr_idx, skb, &fl);
...@@ -1934,8 +1970,11 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) ...@@ -1934,8 +1970,11 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
{ {
struct flowi fl; struct flowi fl;
if (xfrm_decode_session(skb, &fl, family) < 0) if (xfrm_decode_session(skb, &fl, family) < 0) {
/* XXX: we should have something like FWDHDRERROR here. */
XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR);
return 0; return 0;
}
return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment