[XFRM]: Support to increment packet dropping statistics.
Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
558f82ef6e
commit
0aa647746e
4 changed files with 90 additions and 23 deletions
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ resume:
|
||||||
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 @@ resume:
|
||||||
|
|
||||||
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 @@ resume:
|
||||||
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)
|
||||||
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)
|
||||||
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,8 +1494,10 @@ restart:
|
||||||
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) {
|
||||||
|
@ -1529,6 +1531,7 @@ restart:
|
||||||
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 @@ restart:
|
||||||
*/
|
*/
|
||||||
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 @@ restart:
|
||||||
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 @@ restart:
|
||||||
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,8 +1628,10 @@ restart:
|
||||||
}
|
}
|
||||||
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. */
|
||||||
|
@ -1632,8 +1641,10 @@ restart:
|
||||||
|
|
||||||
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 @@ restart:
|
||||||
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 @@ restart:
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
&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,
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue