summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/snmp.h2
-rw-r--r--include/net/icmp.h8
-rw-r--r--include/net/snmp.h5
-rw-r--r--net/ipv4/af_inet.c6
-rw-r--r--net/ipv4/icmp.c53
-rw-r--r--net/ipv4/ip_output.c4
-rw-r--r--net/ipv4/proc.c120
-rw-r--r--net/ipv4/raw.c3
8 files changed, 123 insertions, 78 deletions
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 86977e31548..d8fd3ec4148 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -82,6 +82,8 @@ enum
__ICMP_MIB_MAX
};
+#define __ICMPMSG_MIB_MAX 512 /* Out+In for all 8-bit ICMP types */
+
/* icmp6 mib definitions */
/*
* RFC 2466: ICMPv6-MIB
diff --git a/include/net/icmp.h b/include/net/icmp.h
index dc09474efcf..9f7ef3c8bae 100644
--- a/include/net/icmp.h
+++ b/include/net/icmp.h
@@ -30,9 +30,16 @@ struct icmp_err {
extern struct icmp_err icmp_err_convert[];
DECLARE_SNMP_STAT(struct icmp_mib, icmp_statistics);
+DECLARE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics);
#define ICMP_INC_STATS(field) SNMP_INC_STATS(icmp_statistics, field)
#define ICMP_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmp_statistics, field)
#define ICMP_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmp_statistics, field)
+#define ICMPMSGOUT_INC_STATS(field) SNMP_INC_STATS(icmpmsg_statistics, field+256)
+#define ICMPMSGOUT_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmpmsg_statistics, field+256)
+#define ICMPMSGOUT_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpmsg_statistics, field+256)
+#define ICMPMSGIN_INC_STATS(field) SNMP_INC_STATS(icmpmsg_statistics, field)
+#define ICMPMSGIN_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmpmsg_statistics, field)
+#define ICMPMSGIN_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpmsg_statistics, field)
struct dst_entry;
struct net_proto_family;
@@ -42,6 +49,7 @@ extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info);
extern int icmp_rcv(struct sk_buff *skb);
extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg);
extern void icmp_init(struct net_proto_family *ops);
+extern void icmp_out_count(unsigned char type);
/* Move into dst.h ? */
extern int xrlim_allow(struct dst_entry *dst, int timeout);
diff --git a/include/net/snmp.h b/include/net/snmp.h
index a566e11d2f9..ea206bff0dc 100644
--- a/include/net/snmp.h
+++ b/include/net/snmp.h
@@ -82,6 +82,11 @@ struct icmp_mib {
unsigned long mibs[ICMP_MIB_MAX];
} __SNMP_MIB_ALIGN__;
+#define ICMPMSG_MIB_MAX __ICMPMSG_MIB_MAX
+struct icmpmsg_mib {
+ unsigned long mibs[ICMPMSG_MIB_MAX];
+} __SNMP_MIB_ALIGN__;
+
/* ICMP6 (IPv6-ICMP) */
#define ICMP6_MIB_MAX __ICMP6_MIB_MAX
struct icmpv6_mib {
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index e594a2c8966..621b128897d 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1302,6 +1302,10 @@ static int __init init_ipv4_mibs(void)
sizeof(struct icmp_mib),
__alignof__(struct icmp_mib)) < 0)
goto err_icmp_mib;
+ if (snmp_mib_init((void **)icmpmsg_statistics,
+ sizeof(struct icmpmsg_mib),
+ __alignof__(struct icmpmsg_mib)) < 0)
+ goto err_icmpmsg_mib;
if (snmp_mib_init((void **)tcp_statistics,
sizeof(struct tcp_mib),
__alignof__(struct tcp_mib)) < 0)
@@ -1324,6 +1328,8 @@ err_udplite_mib:
err_udp_mib:
snmp_mib_free((void **)tcp_statistics);
err_tcp_mib:
+ snmp_mib_free((void **)icmpmsg_statistics);
+err_icmpmsg_mib:
snmp_mib_free((void **)icmp_statistics);
err_icmp_mib:
snmp_mib_free((void **)ip_statistics);
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 68a22670f59..272c69e106e 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -115,6 +115,7 @@ struct icmp_bxm {
* Statistics
*/
DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics) __read_mostly;
+DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics) __read_mostly;
/* An array of errno for error messages from dest unreach. */
/* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */
@@ -214,8 +215,6 @@ int sysctl_icmp_errors_use_inbound_ifaddr __read_mostly;
*/
struct icmp_control {
- int output_entry; /* Field for increment on output */
- int input_entry; /* Field for increment on input */
void (*handler)(struct sk_buff *skb);
short error; /* This ICMP is classed as an error message */
};
@@ -316,12 +315,10 @@ out:
/*
* Maintain the counters used in the SNMP statistics for outgoing ICMP
*/
-static void icmp_out_count(int type)
+void icmp_out_count(unsigned char type)
{
- if (type <= NR_ICMP_TYPES) {
- ICMP_INC_STATS(icmp_pointers[type].output_entry);
- ICMP_INC_STATS(ICMP_MIB_OUTMSGS);
- }
+ ICMPMSGOUT_INC_STATS(type);
+ ICMP_INC_STATS(ICMP_MIB_OUTMSGS);
}
/*
@@ -390,7 +387,6 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
return;
icmp_param->data.icmph.checksum = 0;
- icmp_out_count(icmp_param->data.icmph.type);
inet->tos = ip_hdr(skb)->tos;
daddr = ipc.addr = rt->rt_src;
@@ -952,6 +948,7 @@ int icmp_rcv(struct sk_buff *skb)
icmph = icmp_hdr(skb);
+ ICMPMSGIN_INC_STATS_BH(icmph->type);
/*
* 18 is the highest 'known' ICMP type. Anything else is a mystery
*
@@ -986,7 +983,6 @@ int icmp_rcv(struct sk_buff *skb)
}
}
- ICMP_INC_STATS_BH(icmp_pointers[icmph->type].input_entry);
icmp_pointers[icmph->type].handler(skb);
drop:
@@ -1002,109 +998,71 @@ error:
*/
static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
[ICMP_ECHOREPLY] = {
- .output_entry = ICMP_MIB_OUTECHOREPS,
- .input_entry = ICMP_MIB_INECHOREPS,
.handler = icmp_discard,
},
[1] = {
- .output_entry = ICMP_MIB_DUMMY,
- .input_entry = ICMP_MIB_INERRORS,
.handler = icmp_discard,
.error = 1,
},
[2] = {
- .output_entry = ICMP_MIB_DUMMY,
- .input_entry = ICMP_MIB_INERRORS,
.handler = icmp_discard,
.error = 1,
},
[ICMP_DEST_UNREACH] = {
- .output_entry = ICMP_MIB_OUTDESTUNREACHS,
- .input_entry = ICMP_MIB_INDESTUNREACHS,
.handler = icmp_unreach,
.error = 1,
},
[ICMP_SOURCE_QUENCH] = {
- .output_entry = ICMP_MIB_OUTSRCQUENCHS,
- .input_entry = ICMP_MIB_INSRCQUENCHS,
.handler = icmp_unreach,
.error = 1,
},
[ICMP_REDIRECT] = {
- .output_entry = ICMP_MIB_OUTREDIRECTS,
- .input_entry = ICMP_MIB_INREDIRECTS,
.handler = icmp_redirect,
.error = 1,
},
[6] = {
- .output_entry = ICMP_MIB_DUMMY,
- .input_entry = ICMP_MIB_INERRORS,
.handler = icmp_discard,
.error = 1,
},
[7] = {
- .output_entry = ICMP_MIB_DUMMY,
- .input_entry = ICMP_MIB_INERRORS,
.handler = icmp_discard,
.error = 1,
},
[ICMP_ECHO] = {
- .output_entry = ICMP_MIB_OUTECHOS,
- .input_entry = ICMP_MIB_INECHOS,
.handler = icmp_echo,
},
[9] = {
- .output_entry = ICMP_MIB_DUMMY,
- .input_entry = ICMP_MIB_INERRORS,
.handler = icmp_discard,
.error = 1,
},
[10] = {
- .output_entry = ICMP_MIB_DUMMY,
- .input_entry = ICMP_MIB_INERRORS,
.handler = icmp_discard,
.error = 1,
},
[ICMP_TIME_EXCEEDED] = {
- .output_entry = ICMP_MIB_OUTTIMEEXCDS,
- .input_entry = ICMP_MIB_INTIMEEXCDS,
.handler = icmp_unreach,
.error = 1,
},
[ICMP_PARAMETERPROB] = {
- .output_entry = ICMP_MIB_OUTPARMPROBS,
- .input_entry = ICMP_MIB_INPARMPROBS,
.handler = icmp_unreach,
.error = 1,
},
[ICMP_TIMESTAMP] = {
- .output_entry = ICMP_MIB_OUTTIMESTAMPS,
- .input_entry = ICMP_MIB_INTIMESTAMPS,
.handler = icmp_timestamp,
},
[ICMP_TIMESTAMPREPLY] = {
- .output_entry = ICMP_MIB_OUTTIMESTAMPREPS,
- .input_entry = ICMP_MIB_INTIMESTAMPREPS,
.handler = icmp_discard,
},
[ICMP_INFO_REQUEST] = {
- .output_entry = ICMP_MIB_DUMMY,
- .input_entry = ICMP_MIB_DUMMY,
.handler = icmp_discard,
},
[ICMP_INFO_REPLY] = {
- .output_entry = ICMP_MIB_DUMMY,
- .input_entry = ICMP_MIB_DUMMY,
.handler = icmp_discard,
},
[ICMP_ADDRESS] = {
- .output_entry = ICMP_MIB_OUTADDRMASKS,
- .input_entry = ICMP_MIB_INADDRMASKS,
.handler = icmp_address,
},
[ICMP_ADDRESSREPLY] = {
- .output_entry = ICMP_MIB_OUTADDRMASKREPS,
- .input_entry = ICMP_MIB_INADDRMASKREPS,
.handler = icmp_address_reply,
},
};
@@ -1146,4 +1104,5 @@ void __init icmp_init(struct net_proto_family *ops)
EXPORT_SYMBOL(icmp_err_convert);
EXPORT_SYMBOL(icmp_send);
EXPORT_SYMBOL(icmp_statistics);
+EXPORT_SYMBOL(icmpmsg_statistics);
EXPORT_SYMBOL(xrlim_allow);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 0f1d7beacf7..77f67b7cb9b 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1261,6 +1261,10 @@ int ip_push_pending_frames(struct sock *sk)
skb->priority = sk->sk_priority;
skb->dst = dst_clone(&rt->u.dst);
+ if (iph->protocol == IPPROTO_ICMP)
+ icmp_out_count(((struct icmphdr *)
+ skb_transport_header(skb))->type);
+
/* Netfilter gets whole the not fragmented skb. */
err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
skb->dst->dev, dst_output);
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 95a8f8f2de7..2015148b41a 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -124,33 +124,30 @@ static const struct snmp_mib snmp4_ipextstats_list[] = {
static const struct snmp_mib snmp4_icmp_list[] = {
SNMP_MIB_ITEM("InMsgs", ICMP_MIB_INMSGS),
SNMP_MIB_ITEM("InErrors", ICMP_MIB_INERRORS),
- SNMP_MIB_ITEM("InDestUnreachs", ICMP_MIB_INDESTUNREACHS),
- SNMP_MIB_ITEM("InTimeExcds", ICMP_MIB_INTIMEEXCDS),
- SNMP_MIB_ITEM("InParmProbs", ICMP_MIB_INPARMPROBS),
- SNMP_MIB_ITEM("InSrcQuenchs", ICMP_MIB_INSRCQUENCHS),
- SNMP_MIB_ITEM("InRedirects", ICMP_MIB_INREDIRECTS),
- SNMP_MIB_ITEM("InEchos", ICMP_MIB_INECHOS),
- SNMP_MIB_ITEM("InEchoReps", ICMP_MIB_INECHOREPS),
- SNMP_MIB_ITEM("InTimestamps", ICMP_MIB_INTIMESTAMPS),
- SNMP_MIB_ITEM("InTimestampReps", ICMP_MIB_INTIMESTAMPREPS),
- SNMP_MIB_ITEM("InAddrMasks", ICMP_MIB_INADDRMASKS),
- SNMP_MIB_ITEM("InAddrMaskReps", ICMP_MIB_INADDRMASKREPS),
SNMP_MIB_ITEM("OutMsgs", ICMP_MIB_OUTMSGS),
SNMP_MIB_ITEM("OutErrors", ICMP_MIB_OUTERRORS),
- SNMP_MIB_ITEM("OutDestUnreachs", ICMP_MIB_OUTDESTUNREACHS),
- SNMP_MIB_ITEM("OutTimeExcds", ICMP_MIB_OUTTIMEEXCDS),
- SNMP_MIB_ITEM("OutParmProbs", ICMP_MIB_OUTPARMPROBS),
- SNMP_MIB_ITEM("OutSrcQuenchs", ICMP_MIB_OUTSRCQUENCHS),
- SNMP_MIB_ITEM("OutRedirects", ICMP_MIB_OUTREDIRECTS),
- SNMP_MIB_ITEM("OutEchos", ICMP_MIB_OUTECHOS),
- SNMP_MIB_ITEM("OutEchoReps", ICMP_MIB_OUTECHOREPS),
- SNMP_MIB_ITEM("OutTimestamps", ICMP_MIB_OUTTIMESTAMPS),
- SNMP_MIB_ITEM("OutTimestampReps", ICMP_MIB_OUTTIMESTAMPREPS),
- SNMP_MIB_ITEM("OutAddrMasks", ICMP_MIB_OUTADDRMASKS),
- SNMP_MIB_ITEM("OutAddrMaskReps", ICMP_MIB_OUTADDRMASKREPS),
SNMP_MIB_SENTINEL
};
+static struct {
+ char *name;
+ int index;
+} icmpmibmap[] = {
+ { "DestUnreachs", ICMP_DEST_UNREACH },
+ { "TimeExcds", ICMP_TIME_EXCEEDED },
+ { "ParmProbs", ICMP_PARAMETERPROB },
+ { "SrcQuenchs", ICMP_SOURCE_QUENCH },
+ { "Redirects", ICMP_REDIRECT },
+ { "Echos", ICMP_ECHO },
+ { "EchoReps", ICMP_ECHOREPLY },
+ { "Timestamps", ICMP_TIMESTAMP },
+ { "TimestampReps", ICMP_TIMESTAMPREPLY },
+ { "AddrMasks", ICMP_ADDRESS },
+ { "AddrMaskReps", ICMP_ADDRESSREPLY },
+ { 0, 0 }
+};
+
+
static const struct snmp_mib snmp4_tcp_list[] = {
SNMP_MIB_ITEM("RtoAlgorithm", TCP_MIB_RTOALGORITHM),
SNMP_MIB_ITEM("RtoMin", TCP_MIB_RTOMIN),
@@ -251,6 +248,72 @@ static const struct snmp_mib snmp4_net_list[] = {
SNMP_MIB_SENTINEL
};
+static void icmpmsg_put(struct seq_file *seq)
+{
+#define PERLINE 16
+
+ int j, i, count;
+ static int out[PERLINE];
+
+ count = 0;
+ for (i = 0; i < ICMPMSG_MIB_MAX; i++) {
+
+ if (snmp_fold_field((void **) icmpmsg_statistics, i))
+ out[count++] = i;
+ if (count < PERLINE)
+ continue;
+
+ seq_printf(seq, "\nIcmpMsg:");
+ for (j = 0; j < PERLINE; ++j)
+ seq_printf(seq, " %sType%u", i & 0x100 ? "Out" : "In",
+ i & 0xff);
+ seq_printf(seq, "\nIcmpMsg: ");
+ for (j = 0; j < PERLINE; ++j)
+ seq_printf(seq, " %lu",
+ snmp_fold_field((void **) icmpmsg_statistics,
+ out[j]));
+ seq_putc(seq, '\n');
+ }
+ if (count) {
+ seq_printf(seq, "\nIcmpMsg:");
+ for (j = 0; j < count; ++j)
+ seq_printf(seq, " %sType%u", out[j] & 0x100 ? "Out" :
+ "In", out[j] & 0xff);
+ seq_printf(seq, "\nIcmpMsg:");
+ for (j = 0; j < count; ++j)
+ seq_printf(seq, " %lu", snmp_fold_field((void **)
+ icmpmsg_statistics, out[j]));
+ }
+
+#undef PERLINE
+}
+
+static void icmp_put(struct seq_file *seq)
+{
+ int i;
+
+ seq_puts(seq, "\nIcmp: InMsgs InErrors");
+ for (i=0; icmpmibmap[i].name != NULL; i++)
+ seq_printf(seq, " In%s", icmpmibmap[i].name);
+ seq_printf(seq, " OutMsgs OutErrors");
+ for (i=0; icmpmibmap[i].name != NULL; i++)
+ seq_printf(seq, " Out%s", icmpmibmap[i].name);
+ seq_printf(seq, "\nIcmp: %lu %lu",
+ snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INMSGS),
+ snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INERRORS));
+ for (i=0; icmpmibmap[i].name != NULL; i++)
+ seq_printf(seq, " %lu",
+ snmp_fold_field((void **) icmpmsg_statistics,
+ icmpmibmap[i].index));
+ seq_printf(seq, " %lu %lu",
+ snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTMSGS),
+ snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTERRORS));
+ for (i=0; icmpmibmap[i].name != NULL; i++)
+ seq_printf(seq, " %lu",
+ snmp_fold_field((void **) icmpmsg_statistics,
+ icmpmibmap[i].index));
+}
+
/*
* Called from the PROCfs module. This outputs /proc/net/snmp.
*/
@@ -271,15 +334,8 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
snmp_fold_field((void **)ip_statistics,
snmp4_ipstats_list[i].entry));
- seq_puts(seq, "\nIcmp:");
- for (i = 0; snmp4_icmp_list[i].name != NULL; i++)
- seq_printf(seq, " %s", snmp4_icmp_list[i].name);
-
- seq_puts(seq, "\nIcmp:");
- for (i = 0; snmp4_icmp_list[i].name != NULL; i++)
- seq_printf(seq, " %lu",
- snmp_fold_field((void **)icmp_statistics,
- snmp4_icmp_list[i].entry));
+ icmp_put(seq); /* RFC 2011 compatibility */
+ icmpmsg_put(seq);
seq_puts(seq, "\nTcp:");
for (i = 0; snmp4_tcp_list[i].name != NULL; i++)
@@ -336,6 +392,8 @@ static const struct file_operations snmp_seq_fops = {
.release = single_release,
};
+
+
/*
* Output /proc/net/netstat
*/
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 216e01b0f44..07070c7067f 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -314,6 +314,9 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}
+ if (iph->protocol == IPPROTO_ICMP)
+ icmp_out_count(((struct icmphdr *)
+ skb_transport_header(skb))->type);
err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
dst_output);