Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /******************************************************************************
3 : : * vlanproc.c VLAN Module. /proc filesystem interface.
4 : : *
5 : : * This module is completely hardware-independent and provides
6 : : * access to the router using Linux /proc filesystem.
7 : : *
8 : : * Author: Ben Greear, <greearb@candelatech.com> coppied from wanproc.c
9 : : * by: Gene Kozin <genek@compuserve.com>
10 : : *
11 : : * Copyright: (c) 1998 Ben Greear
12 : : *
13 : : * ============================================================================
14 : : * Jan 20, 1998 Ben Greear Initial Version
15 : : *****************************************************************************/
16 : :
17 : : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18 : :
19 : : #include <linux/module.h>
20 : : #include <linux/errno.h>
21 : : #include <linux/kernel.h>
22 : : #include <linux/string.h>
23 : : #include <linux/proc_fs.h>
24 : : #include <linux/seq_file.h>
25 : : #include <linux/fs.h>
26 : : #include <linux/netdevice.h>
27 : : #include <linux/if_vlan.h>
28 : : #include <net/net_namespace.h>
29 : : #include <net/netns/generic.h>
30 : : #include "vlanproc.h"
31 : : #include "vlan.h"
32 : :
33 : : /****** Function Prototypes *************************************************/
34 : :
35 : : /* Methods for preparing data for reading proc entries */
36 : : static int vlan_seq_show(struct seq_file *seq, void *v);
37 : : static void *vlan_seq_start(struct seq_file *seq, loff_t *pos);
38 : : static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos);
39 : : static void vlan_seq_stop(struct seq_file *seq, void *);
40 : : static int vlandev_seq_show(struct seq_file *seq, void *v);
41 : :
42 : : /*
43 : : * Global Data
44 : : */
45 : :
46 : :
47 : : /*
48 : : * Names of the proc directory entries
49 : : */
50 : :
51 : : static const char name_root[] = "vlan";
52 : : static const char name_conf[] = "config";
53 : :
54 : : /*
55 : : * Structures for interfacing with the /proc filesystem.
56 : : * VLAN creates its own directory /proc/net/vlan with the following
57 : : * entries:
58 : : * config device status/configuration
59 : : * <device> entry for each device
60 : : */
61 : :
62 : : /*
63 : : * Generic /proc/net/vlan/<file> file and inode operations
64 : : */
65 : :
66 : : static const struct seq_operations vlan_seq_ops = {
67 : : .start = vlan_seq_start,
68 : : .next = vlan_seq_next,
69 : : .stop = vlan_seq_stop,
70 : : .show = vlan_seq_show,
71 : : };
72 : :
73 : : /*
74 : : * Proc filesystem directory entries.
75 : : */
76 : :
77 : : /* Strings */
78 : : static const char *const vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = {
79 : : [VLAN_NAME_TYPE_RAW_PLUS_VID] = "VLAN_NAME_TYPE_RAW_PLUS_VID",
80 : : [VLAN_NAME_TYPE_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_PLUS_VID_NO_PAD",
81 : : [VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD",
82 : : [VLAN_NAME_TYPE_PLUS_VID] = "VLAN_NAME_TYPE_PLUS_VID",
83 : : };
84 : : /*
85 : : * Interface functions
86 : : */
87 : :
88 : : /*
89 : : * Clean up /proc/net/vlan entries
90 : : */
91 : :
92 : 2 : void vlan_proc_cleanup(struct net *net)
93 : : {
94 : 2 : struct vlan_net *vn = net_generic(net, vlan_net_id);
95 : :
96 [ + - ]: 2 : if (vn->proc_vlan_conf)
97 : 2 : remove_proc_entry(name_conf, vn->proc_vlan_dir);
98 : :
99 [ + - ]: 2 : if (vn->proc_vlan_dir)
100 : 2 : remove_proc_entry(name_root, net->proc_net);
101 : :
102 : : /* Dynamically added entries should be cleaned up as their vlan_device
103 : : * is removed, so we should not have to take care of it here...
104 : : */
105 : 2 : }
106 : :
107 : : /*
108 : : * Create /proc/net/vlan entries
109 : : */
110 : :
111 : 406 : int __net_init vlan_proc_init(struct net *net)
112 : : {
113 : 406 : struct vlan_net *vn = net_generic(net, vlan_net_id);
114 : :
115 : 812 : vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
116 [ + - ]: 406 : if (!vn->proc_vlan_dir)
117 : : goto err;
118 : :
119 : 406 : vn->proc_vlan_conf = proc_create_net(name_conf, S_IFREG | 0600,
120 : : vn->proc_vlan_dir, &vlan_seq_ops,
121 : : sizeof(struct seq_net_private));
122 [ - + ]: 406 : if (!vn->proc_vlan_conf)
123 : : goto err;
124 : : return 0;
125 : :
126 : : err:
127 : 0 : pr_err("can't create entry in proc filesystem!\n");
128 : 0 : vlan_proc_cleanup(net);
129 : 0 : return -ENOBUFS;
130 : : }
131 : :
132 : : /*
133 : : * Add directory entry for VLAN device.
134 : : */
135 : :
136 : 0 : int vlan_proc_add_dev(struct net_device *vlandev)
137 : : {
138 : : struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
139 : 0 : struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);
140 : :
141 [ # # ]: 0 : if (!strcmp(vlandev->name, name_conf))
142 : : return -EINVAL;
143 : 0 : vlan->dent = proc_create_single_data(vlandev->name, S_IFREG | 0600,
144 : : vn->proc_vlan_dir, vlandev_seq_show, vlandev);
145 [ # # ]: 0 : if (!vlan->dent)
146 : : return -ENOBUFS;
147 : 0 : return 0;
148 : : }
149 : :
150 : : /*
151 : : * Delete directory entry for VLAN device.
152 : : */
153 : 0 : void vlan_proc_rem_dev(struct net_device *vlandev)
154 : : {
155 : : /** NOTE: This will consume the memory pointed to by dent, it seems. */
156 : 0 : proc_remove(vlan_dev_priv(vlandev)->dent);
157 : 0 : vlan_dev_priv(vlandev)->dent = NULL;
158 : 0 : }
159 : :
160 : : /****** Proc filesystem entry points ****************************************/
161 : :
162 : : /*
163 : : * The following few functions build the content of /proc/net/vlan/config
164 : : */
165 : :
166 : : /* start read of /proc/net/vlan/config */
167 : 0 : static void *vlan_seq_start(struct seq_file *seq, loff_t *pos)
168 : : __acquires(rcu)
169 : : {
170 : : struct net_device *dev;
171 : : struct net *net = seq_file_net(seq);
172 : : loff_t i = 1;
173 : :
174 : : rcu_read_lock();
175 [ # # ]: 0 : if (*pos == 0)
176 : : return SEQ_START_TOKEN;
177 : :
178 [ # # ]: 0 : for_each_netdev_rcu(net, dev) {
179 [ # # ]: 0 : if (!is_vlan_dev(dev))
180 : 0 : continue;
181 : :
182 [ # # ]: 0 : if (i++ == *pos)
183 : 0 : return dev;
184 : : }
185 : :
186 : : return NULL;
187 : : }
188 : :
189 : 0 : static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
190 : : {
191 : : struct net_device *dev;
192 : : struct net *net = seq_file_net(seq);
193 : :
194 : 0 : ++*pos;
195 : :
196 : : dev = v;
197 [ # # ]: 0 : if (v == SEQ_START_TOKEN)
198 : 0 : dev = net_device_entry(&net->dev_base_head);
199 : :
200 [ # # ]: 0 : for_each_netdev_continue_rcu(net, dev) {
201 [ # # ]: 0 : if (!is_vlan_dev(dev))
202 : 0 : continue;
203 : :
204 : 0 : return dev;
205 : : }
206 : :
207 : : return NULL;
208 : : }
209 : :
210 : 0 : static void vlan_seq_stop(struct seq_file *seq, void *v)
211 : : __releases(rcu)
212 : : {
213 : : rcu_read_unlock();
214 : 0 : }
215 : :
216 : 0 : static int vlan_seq_show(struct seq_file *seq, void *v)
217 : : {
218 : : struct net *net = seq_file_net(seq);
219 : 0 : struct vlan_net *vn = net_generic(net, vlan_net_id);
220 : :
221 [ # # ]: 0 : if (v == SEQ_START_TOKEN) {
222 : : const char *nmtype = NULL;
223 : :
224 : 0 : seq_puts(seq, "VLAN Dev name | VLAN ID\n");
225 : :
226 [ # # ]: 0 : if (vn->name_type < ARRAY_SIZE(vlan_name_type_str))
227 : 0 : nmtype = vlan_name_type_str[vn->name_type];
228 : :
229 [ # # ]: 0 : seq_printf(seq, "Name-Type: %s\n",
230 : : nmtype ? nmtype : "UNKNOWN");
231 : : } else {
232 : : const struct net_device *vlandev = v;
233 : : const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
234 : :
235 : 0 : seq_printf(seq, "%-15s| %d | %s\n", vlandev->name,
236 : 0 : vlan->vlan_id, vlan->real_dev->name);
237 : : }
238 : 0 : return 0;
239 : : }
240 : :
241 : 0 : static int vlandev_seq_show(struct seq_file *seq, void *offset)
242 : : {
243 : 0 : struct net_device *vlandev = (struct net_device *) seq->private;
244 : : const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
245 : : struct rtnl_link_stats64 temp;
246 : : const struct rtnl_link_stats64 *stats;
247 : : static const char fmt64[] = "%30s %12llu\n";
248 : : int i;
249 : :
250 [ # # ]: 0 : if (!is_vlan_dev(vlandev))
251 : : return 0;
252 : :
253 : 0 : stats = dev_get_stats(vlandev, &temp);
254 : 0 : seq_printf(seq,
255 : : "%s VID: %d REORDER_HDR: %i dev->priv_flags: %hx\n",
256 : 0 : vlandev->name, vlan->vlan_id,
257 : 0 : (int)(vlan->flags & 1), vlandev->priv_flags);
258 : :
259 : 0 : seq_printf(seq, fmt64, "total frames received", stats->rx_packets);
260 : 0 : seq_printf(seq, fmt64, "total bytes received", stats->rx_bytes);
261 : 0 : seq_printf(seq, fmt64, "Broadcast/Multicast Rcvd", stats->multicast);
262 : 0 : seq_puts(seq, "\n");
263 : 0 : seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
264 : 0 : seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
265 : 0 : seq_printf(seq, "Device: %s", vlan->real_dev->name);
266 : : /* now show all PRIORITY mappings relating to this VLAN */
267 : 0 : seq_printf(seq, "\nINGRESS priority mappings: "
268 : : "0:%u 1:%u 2:%u 3:%u 4:%u 5:%u 6:%u 7:%u\n",
269 : : vlan->ingress_priority_map[0],
270 : : vlan->ingress_priority_map[1],
271 : : vlan->ingress_priority_map[2],
272 : : vlan->ingress_priority_map[3],
273 : : vlan->ingress_priority_map[4],
274 : : vlan->ingress_priority_map[5],
275 : : vlan->ingress_priority_map[6],
276 : : vlan->ingress_priority_map[7]);
277 : :
278 : 0 : seq_printf(seq, " EGRESS priority mappings: ");
279 [ # # ]: 0 : for (i = 0; i < 16; i++) {
280 : 0 : const struct vlan_priority_tci_mapping *mp
281 : : = vlan->egress_priority_map[i];
282 [ # # ]: 0 : while (mp) {
283 : 0 : seq_printf(seq, "%u:%hu ",
284 : 0 : mp->priority, ((mp->vlan_qos >> 13) & 0x7));
285 : 0 : mp = mp->next;
286 : : }
287 : : }
288 : 0 : seq_puts(seq, "\n");
289 : :
290 : 0 : return 0;
291 : : }
|