1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
/*
*
* SNMP MIB entries for the IP subsystem.
*
* Alan Cox <gw4pts@gw4pts.ampr.org>
*
* We don't chose to implement SNMP in the kernel (this would
* be silly as SNMP is a pain in the backside in places). We do
* however need to collect the MIB statistics and export them
* out of /proc (eventually)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#ifndef _SNMP_H
#define _SNMP_H
#include <linux/cache.h>
#include <linux/snmp.h>
#include <linux/smp.h>
/*
* Mibs are stored in array of unsigned long.
*/
/*
* struct snmp_mib{}
* - list of entries for particular API (such as /proc/net/snmp)
* - name of entries.
*/
struct snmp_mib {
const char *name;
int entry;
};
#define SNMP_MIB_ITEM(_name,_entry) { \
.name = _name, \
.entry = _entry, \
}
#define SNMP_MIB_SENTINEL { \
.name = NULL, \
.entry = 0, \
}
/*
* We use unsigned longs for most mibs but u64 for ipstats.
*/
#include <linux/u64_stats_sync.h>
/* IPstats */
#define IPSTATS_MIB_MAX __IPSTATS_MIB_MAX
struct ipstats_mib {
/* mibs[] must be first field of struct ipstats_mib */
u64 mibs[IPSTATS_MIB_MAX];
struct u64_stats_sync syncp;
};
/* ICMP */
#define ICMP_MIB_MAX __ICMP_MIB_MAX
struct icmp_mib {
unsigned long mibs[ICMP_MIB_MAX];
};
#define ICMPMSG_MIB_MAX __ICMPMSG_MIB_MAX
struct icmpmsg_mib {
atomic_long_t mibs[ICMPMSG_MIB_MAX];
};
/* ICMP6 (IPv6-ICMP) */
#define ICMP6_MIB_MAX __ICMP6_MIB_MAX
/* per network ns counters */
struct icmpv6_mib {
unsigned long mibs[ICMP6_MIB_MAX];
};
/* per device counters, (shared on all cpus) */
struct icmpv6_mib_device {
atomic_long_t mibs[ICMP6_MIB_MAX];
};
#define ICMP6MSG_MIB_MAX __ICMP6MSG_MIB_MAX
/* per network ns counters */
struct icmpv6msg_mib {
unsigned long mibs[ICMP6MSG_MIB_MAX];
};
/* per device counters, (shared on all cpus) */
struct icmpv6msg_mib_device {
atomic_long_t mibs[ICMP6MSG_MIB_MAX];
};
/* TCP */
#define TCP_MIB_MAX __TCP_MIB_MAX
struct tcp_mib {
unsigned long mibs[TCP_MIB_MAX];
};
/* UDP */
#define UDP_MIB_MAX __UDP_MIB_MAX
struct udp_mib {
unsigned long mibs[UDP_MIB_MAX];
};
/* Linux */
#define LINUX_MIB_MAX __LINUX_MIB_MAX
struct linux_mib {
unsigned long mibs[LINUX_MIB_MAX];
};
/* Linux Xfrm */
#define LINUX_MIB_XFRMMAX __LINUX_MIB_XFRMMAX
struct linux_xfrm_mib {
unsigned long mibs[LINUX_MIB_XFRMMAX];
};
#define SNMP_ARRAY_SZ 1
#define DEFINE_SNMP_STAT(type, name) \
__typeof__(type) __percpu *name[SNMP_ARRAY_SZ]
#define DEFINE_SNMP_STAT_ATOMIC(type, name) \
__typeof__(type) *name
#define DECLARE_SNMP_STAT(type, name) \
extern __typeof__(type) __percpu *name[SNMP_ARRAY_SZ]
#define SNMP_INC_STATS_BH(mib, field) \
__this_cpu_inc(mib[0]->mibs[field])
#define SNMP_INC_STATS_USER(mib, field) \
irqsafe_cpu_inc(mib[0]->mibs[field])
#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) \
atomic_long_inc(&mib->mibs[field])
#define SNMP_INC_STATS(mib, field) \
irqsafe_cpu_inc(mib[0]->mibs[field])
#define SNMP_DEC_STATS(mib, field) \
irqsafe_cpu_dec(mib[0]->mibs[field])
#define SNMP_ADD_STATS_BH(mib, field, addend) \
__this_cpu_add(mib[0]->mibs[field], addend)
#define SNMP_ADD_STATS_USER(mib, field, addend) \
irqsafe_cpu_add(mib[0]->mibs[field], addend)
#define SNMP_ADD_STATS(mib, field, addend) \
irqsafe_cpu_add(mib[0]->mibs[field], addend)
/*
* Use "__typeof__(*mib[0]) *ptr" instead of "__typeof__(mib[0]) ptr"
* to make @ptr a non-percpu pointer.
*/
#define SNMP_UPD_PO_STATS(mib, basefield, addend) \
do { \
irqsafe_cpu_inc(mib[0]->mibs[basefield##PKTS]); \
irqsafe_cpu_add(mib[0]->mibs[basefield##OCTETS], addend); \
} while (0)
#define SNMP_UPD_PO_STATS_BH(mib, basefield, addend) \
do { \
__this_cpu_inc(mib[0]->mibs[basefield##PKTS]); \
__this_cpu_add(mib[0]->mibs[basefield##OCTETS], addend); \
} while (0)
#if BITS_PER_LONG==32
#define SNMP_ADD_STATS64_BH(mib, field, addend) \
do { \
__typeof__(*mib[0]) *ptr = __this_cpu_ptr((mib)[0]); \
u64_stats_update_begin(&ptr->syncp); \
ptr->mibs[field] += addend; \
u64_stats_update_end(&ptr->syncp); \
} while (0)
#define SNMP_ADD_STATS64_USER(mib, field, addend) \
do { \
local_bh_disable(); \
SNMP_ADD_STATS64_BH(mib, field, addend); \
local_bh_enable(); \
} while (0)
#define SNMP_ADD_STATS64(mib, field, addend) \
SNMP_ADD_STATS64_USER(mib, field, addend)
#define SNMP_INC_STATS64_BH(mib, field) SNMP_ADD_STATS64_BH(mib, field, 1)
#define SNMP_INC_STATS64_USER(mib, field) SNMP_ADD_STATS64_USER(mib, field, 1)
#define SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1)
#define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) \
do { \
__typeof__(*mib[0]) *ptr; \
ptr = __this_cpu_ptr((mib)[0]); \
u64_stats_update_begin(&ptr->syncp); \
ptr->mibs[basefield##PKTS]++; \
ptr->mibs[basefield##OCTETS] += addend; \
u64_stats_update_end(&ptr->syncp); \
} while (0)
#define SNMP_UPD_PO_STATS64(mib, basefield, addend) \
do { \
local_bh_disable(); \
SNMP_UPD_PO_STATS64_BH(mib, basefield, addend); \
local_bh_enable(); \
} while (0)
#else
#define SNMP_INC_STATS64_BH(mib, field) SNMP_INC_STATS_BH(mib, field)
#define SNMP_INC_STATS64_USER(mib, field) SNMP_INC_STATS_USER(mib, field)
#define SNMP_INC_STATS64(mib, field) SNMP_INC_STATS(mib, field)
#define SNMP_DEC_STATS64(mib, field) SNMP_DEC_STATS(mib, field)
#define SNMP_ADD_STATS64_BH(mib, field, addend) SNMP_ADD_STATS_BH(mib, field, addend)
#define SNMP_ADD_STATS64_USER(mib, field, addend) SNMP_ADD_STATS_USER(mib, field, addend)
#define SNMP_ADD_STATS64(mib, field, addend) SNMP_ADD_STATS(mib, field, addend)
#define SNMP_UPD_PO_STATS64(mib, basefield, addend) SNMP_UPD_PO_STATS(mib, basefield, addend)
#define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) SNMP_UPD_PO_STATS_BH(mib, basefield, addend)
#endif
#endif
|