Root/
1 | /****************************************************************************** |
2 | * vlanproc.c VLAN Module. /proc filesystem interface. |
3 | * |
4 | * This module is completely hardware-independent and provides |
5 | * access to the router using Linux /proc filesystem. |
6 | * |
7 | * Author: Ben Greear, <greearb@candelatech.com> coppied from wanproc.c |
8 | * by: Gene Kozin <genek@compuserve.com> |
9 | * |
10 | * Copyright: (c) 1998 Ben Greear |
11 | * |
12 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License |
14 | * as published by the Free Software Foundation; either version |
15 | * 2 of the License, or (at your option) any later version. |
16 | * ============================================================================ |
17 | * Jan 20, 1998 Ben Greear Initial Version |
18 | *****************************************************************************/ |
19 | |
20 | #include <linux/module.h> |
21 | #include <linux/errno.h> |
22 | #include <linux/kernel.h> |
23 | #include <linux/string.h> |
24 | #include <linux/proc_fs.h> |
25 | #include <linux/seq_file.h> |
26 | #include <linux/fs.h> |
27 | #include <linux/netdevice.h> |
28 | #include <linux/if_vlan.h> |
29 | #include <net/net_namespace.h> |
30 | #include <net/netns/generic.h> |
31 | #include "vlanproc.h" |
32 | #include "vlan.h" |
33 | |
34 | /****** Function Prototypes *************************************************/ |
35 | |
36 | /* Methods for preparing data for reading proc entries */ |
37 | static int vlan_seq_show(struct seq_file *seq, void *v); |
38 | static void *vlan_seq_start(struct seq_file *seq, loff_t *pos); |
39 | static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos); |
40 | static void vlan_seq_stop(struct seq_file *seq, void *); |
41 | static int vlandev_seq_show(struct seq_file *seq, void *v); |
42 | |
43 | /* |
44 | * Global Data |
45 | */ |
46 | |
47 | |
48 | /* |
49 | * Names of the proc directory entries |
50 | */ |
51 | |
52 | static const char name_root[] = "vlan"; |
53 | static const char name_conf[] = "config"; |
54 | |
55 | /* |
56 | * Structures for interfacing with the /proc filesystem. |
57 | * VLAN creates its own directory /proc/net/vlan with the folowing |
58 | * entries: |
59 | * config device status/configuration |
60 | * <device> entry for each device |
61 | */ |
62 | |
63 | /* |
64 | * Generic /proc/net/vlan/<file> file and inode operations |
65 | */ |
66 | |
67 | static const struct seq_operations vlan_seq_ops = { |
68 | .start = vlan_seq_start, |
69 | .next = vlan_seq_next, |
70 | .stop = vlan_seq_stop, |
71 | .show = vlan_seq_show, |
72 | }; |
73 | |
74 | static int vlan_seq_open(struct inode *inode, struct file *file) |
75 | { |
76 | return seq_open_net(inode, file, &vlan_seq_ops, |
77 | sizeof(struct seq_net_private)); |
78 | } |
79 | |
80 | static const struct file_operations vlan_fops = { |
81 | .owner = THIS_MODULE, |
82 | .open = vlan_seq_open, |
83 | .read = seq_read, |
84 | .llseek = seq_lseek, |
85 | .release = seq_release_net, |
86 | }; |
87 | |
88 | /* |
89 | * /proc/net/vlan/<device> file and inode operations |
90 | */ |
91 | |
92 | static int vlandev_seq_open(struct inode *inode, struct file *file) |
93 | { |
94 | return single_open(file, vlandev_seq_show, PDE(inode)->data); |
95 | } |
96 | |
97 | static const struct file_operations vlandev_fops = { |
98 | .owner = THIS_MODULE, |
99 | .open = vlandev_seq_open, |
100 | .read = seq_read, |
101 | .llseek = seq_lseek, |
102 | .release = single_release, |
103 | }; |
104 | |
105 | /* |
106 | * Proc filesystem derectory entries. |
107 | */ |
108 | |
109 | /* Strings */ |
110 | static const char *const vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = { |
111 | [VLAN_NAME_TYPE_RAW_PLUS_VID] = "VLAN_NAME_TYPE_RAW_PLUS_VID", |
112 | [VLAN_NAME_TYPE_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_PLUS_VID_NO_PAD", |
113 | [VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD", |
114 | [VLAN_NAME_TYPE_PLUS_VID] = "VLAN_NAME_TYPE_PLUS_VID", |
115 | }; |
116 | /* |
117 | * Interface functions |
118 | */ |
119 | |
120 | /* |
121 | * Clean up /proc/net/vlan entries |
122 | */ |
123 | |
124 | void vlan_proc_cleanup(struct net *net) |
125 | { |
126 | struct vlan_net *vn = net_generic(net, vlan_net_id); |
127 | |
128 | if (vn->proc_vlan_conf) |
129 | remove_proc_entry(name_conf, vn->proc_vlan_dir); |
130 | |
131 | if (vn->proc_vlan_dir) |
132 | proc_net_remove(net, name_root); |
133 | |
134 | /* Dynamically added entries should be cleaned up as their vlan_device |
135 | * is removed, so we should not have to take care of it here... |
136 | */ |
137 | } |
138 | |
139 | /* |
140 | * Create /proc/net/vlan entries |
141 | */ |
142 | |
143 | int vlan_proc_init(struct net *net) |
144 | { |
145 | struct vlan_net *vn = net_generic(net, vlan_net_id); |
146 | |
147 | vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); |
148 | if (!vn->proc_vlan_dir) |
149 | goto err; |
150 | |
151 | vn->proc_vlan_conf = proc_create(name_conf, S_IFREG|S_IRUSR|S_IWUSR, |
152 | vn->proc_vlan_dir, &vlan_fops); |
153 | if (!vn->proc_vlan_conf) |
154 | goto err; |
155 | return 0; |
156 | |
157 | err: |
158 | pr_err("%s: can't create entry in proc filesystem!\n", __func__); |
159 | vlan_proc_cleanup(net); |
160 | return -ENOBUFS; |
161 | } |
162 | |
163 | /* |
164 | * Add directory entry for VLAN device. |
165 | */ |
166 | |
167 | int vlan_proc_add_dev(struct net_device *vlandev) |
168 | { |
169 | struct vlan_dev_info *dev_info = vlan_dev_info(vlandev); |
170 | struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); |
171 | |
172 | dev_info->dent = |
173 | proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR, |
174 | vn->proc_vlan_dir, &vlandev_fops, vlandev); |
175 | if (!dev_info->dent) |
176 | return -ENOBUFS; |
177 | return 0; |
178 | } |
179 | |
180 | /* |
181 | * Delete directory entry for VLAN device. |
182 | */ |
183 | int vlan_proc_rem_dev(struct net_device *vlandev) |
184 | { |
185 | struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); |
186 | |
187 | /** NOTE: This will consume the memory pointed to by dent, it seems. */ |
188 | if (vlan_dev_info(vlandev)->dent) { |
189 | remove_proc_entry(vlan_dev_info(vlandev)->dent->name, |
190 | vn->proc_vlan_dir); |
191 | vlan_dev_info(vlandev)->dent = NULL; |
192 | } |
193 | return 0; |
194 | } |
195 | |
196 | /****** Proc filesystem entry points ****************************************/ |
197 | |
198 | /* |
199 | * The following few functions build the content of /proc/net/vlan/config |
200 | */ |
201 | |
202 | /* start read of /proc/net/vlan/config */ |
203 | static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) |
204 | __acquires(dev_base_lock) |
205 | { |
206 | struct net_device *dev; |
207 | struct net *net = seq_file_net(seq); |
208 | loff_t i = 1; |
209 | |
210 | read_lock(&dev_base_lock); |
211 | |
212 | if (*pos == 0) |
213 | return SEQ_START_TOKEN; |
214 | |
215 | for_each_netdev(net, dev) { |
216 | if (!is_vlan_dev(dev)) |
217 | continue; |
218 | |
219 | if (i++ == *pos) |
220 | return dev; |
221 | } |
222 | |
223 | return NULL; |
224 | } |
225 | |
226 | static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
227 | { |
228 | struct net_device *dev; |
229 | struct net *net = seq_file_net(seq); |
230 | |
231 | ++*pos; |
232 | |
233 | dev = (struct net_device *)v; |
234 | if (v == SEQ_START_TOKEN) |
235 | dev = net_device_entry(&net->dev_base_head); |
236 | |
237 | for_each_netdev_continue(net, dev) { |
238 | if (!is_vlan_dev(dev)) |
239 | continue; |
240 | |
241 | return dev; |
242 | } |
243 | |
244 | return NULL; |
245 | } |
246 | |
247 | static void vlan_seq_stop(struct seq_file *seq, void *v) |
248 | __releases(dev_base_lock) |
249 | { |
250 | read_unlock(&dev_base_lock); |
251 | } |
252 | |
253 | static int vlan_seq_show(struct seq_file *seq, void *v) |
254 | { |
255 | struct net *net = seq_file_net(seq); |
256 | struct vlan_net *vn = net_generic(net, vlan_net_id); |
257 | |
258 | if (v == SEQ_START_TOKEN) { |
259 | const char *nmtype = NULL; |
260 | |
261 | seq_puts(seq, "VLAN Dev name | VLAN ID\n"); |
262 | |
263 | if (vn->name_type < ARRAY_SIZE(vlan_name_type_str)) |
264 | nmtype = vlan_name_type_str[vn->name_type]; |
265 | |
266 | seq_printf(seq, "Name-Type: %s\n", |
267 | nmtype ? nmtype : "UNKNOWN"); |
268 | } else { |
269 | const struct net_device *vlandev = v; |
270 | const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev); |
271 | |
272 | seq_printf(seq, "%-15s| %d | %s\n", vlandev->name, |
273 | dev_info->vlan_id, dev_info->real_dev->name); |
274 | } |
275 | return 0; |
276 | } |
277 | |
278 | static int vlandev_seq_show(struct seq_file *seq, void *offset) |
279 | { |
280 | struct net_device *vlandev = (struct net_device *) seq->private; |
281 | const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev); |
282 | const struct net_device_stats *stats; |
283 | static const char fmt[] = "%30s %12lu\n"; |
284 | int i; |
285 | |
286 | if (!is_vlan_dev(vlandev)) |
287 | return 0; |
288 | |
289 | stats = dev_get_stats(vlandev); |
290 | seq_printf(seq, |
291 | "%s VID: %d REORDER_HDR: %i dev->priv_flags: %hx\n", |
292 | vlandev->name, dev_info->vlan_id, |
293 | (int)(dev_info->flags & 1), vlandev->priv_flags); |
294 | |
295 | seq_printf(seq, fmt, "total frames received", stats->rx_packets); |
296 | seq_printf(seq, fmt, "total bytes received", stats->rx_bytes); |
297 | seq_printf(seq, fmt, "Broadcast/Multicast Rcvd", stats->multicast); |
298 | seq_puts(seq, "\n"); |
299 | seq_printf(seq, fmt, "total frames transmitted", stats->tx_packets); |
300 | seq_printf(seq, fmt, "total bytes transmitted", stats->tx_bytes); |
301 | seq_printf(seq, fmt, "total headroom inc", |
302 | dev_info->cnt_inc_headroom_on_tx); |
303 | seq_printf(seq, fmt, "total encap on xmit", |
304 | dev_info->cnt_encap_on_xmit); |
305 | seq_printf(seq, "Device: %s", dev_info->real_dev->name); |
306 | /* now show all PRIORITY mappings relating to this VLAN */ |
307 | seq_printf(seq, "\nINGRESS priority mappings: " |
308 | "0:%u 1:%u 2:%u 3:%u 4:%u 5:%u 6:%u 7:%u\n", |
309 | dev_info->ingress_priority_map[0], |
310 | dev_info->ingress_priority_map[1], |
311 | dev_info->ingress_priority_map[2], |
312 | dev_info->ingress_priority_map[3], |
313 | dev_info->ingress_priority_map[4], |
314 | dev_info->ingress_priority_map[5], |
315 | dev_info->ingress_priority_map[6], |
316 | dev_info->ingress_priority_map[7]); |
317 | |
318 | seq_printf(seq, " EGRESS priority mappings: "); |
319 | for (i = 0; i < 16; i++) { |
320 | const struct vlan_priority_tci_mapping *mp |
321 | = dev_info->egress_priority_map[i]; |
322 | while (mp) { |
323 | seq_printf(seq, "%u:%hu ", |
324 | mp->priority, ((mp->vlan_qos >> 13) & 0x7)); |
325 | mp = mp->next; |
326 | } |
327 | } |
328 | seq_puts(seq, "\n"); |
329 | |
330 | return 0; |
331 | } |
332 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9