blob: 08bf6c839e2563157828baf3e9e546ebb6c400d5 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/******************************************************************************
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 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 * ============================================================================
14 * Jan 20, 1998 Ben Greear Initial Version
15 *****************************************************************************/
16
Joe Perchesafab2d22011-05-26 10:58:31 +000017#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/module.h>
Patrick McHardy61362762008-07-14 22:51:55 -070020#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/kernel.h>
Patrick McHardy61362762008-07-14 22:51:55 -070022#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#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>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020028#include <net/net_namespace.h>
Pavel Emelyanova59a8c12008-04-16 00:51:51 -070029#include <net/netns/generic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include "vlanproc.h"
31#include "vlan.h"
32
33/****** Function Prototypes *************************************************/
34
35/* Methods for preparing data for reading proc entries */
36static int vlan_seq_show(struct seq_file *seq, void *v);
37static void *vlan_seq_start(struct seq_file *seq, loff_t *pos);
38static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos);
39static void vlan_seq_stop(struct seq_file *seq, void *);
40static int vlandev_seq_show(struct seq_file *seq, void *v);
41
42/*
43 * Global Data
44 */
45
46
47/*
YOSHIFUJI Hideaki122952f2007-02-09 23:24:25 +090048 * Names of the proc directory entries
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 */
50
51static const char name_root[] = "vlan";
52static const char name_conf[] = "config";
53
54/*
55 * Structures for interfacing with the /proc filesystem.
Lucas De Marchi25985ed2011-03-30 22:57:33 -030056 * VLAN creates its own directory /proc/net/vlan with the following
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 * entries:
58 * config device status/configuration
59 * <device> entry for each device
60 */
61
62/*
YOSHIFUJI Hideaki122952f2007-02-09 23:24:25 +090063 * Generic /proc/net/vlan/<file> file and inode operations
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 */
65
Philippe De Muyter56b3d972007-07-10 23:07:31 -070066static const struct seq_operations vlan_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 .start = vlan_seq_start,
68 .next = vlan_seq_next,
69 .stop = vlan_seq_stop,
70 .show = vlan_seq_show,
71};
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073/*
Anatol Pomozov4907cb72012-09-01 10:31:09 -070074 * Proc filesystem directory entries.
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 */
76
Linus Torvalds1da177e2005-04-16 15:20:36 -070077/* Strings */
Jan Engelhardt36cbd3d2009-08-05 10:42:58 -070078static const char *const vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = {
Patrick McHardy2029cc22008-01-21 00:26:41 -080079 [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",
Linus Torvalds1da177e2005-04-16 15:20:36 -070083};
84/*
85 * Interface functions
86 */
87
88/*
89 * Clean up /proc/net/vlan entries
90 */
91
Pavel Emelyanovcd1c7012008-04-16 00:51:12 -070092void vlan_proc_cleanup(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
Pavel Emelyanova59a8c12008-04-16 00:51:51 -070094 struct vlan_net *vn = net_generic(net, vlan_net_id);
Pavel Emelyanovcd1c7012008-04-16 00:51:12 -070095
Pavel Emelyanova59a8c12008-04-16 00:51:51 -070096 if (vn->proc_vlan_conf)
97 remove_proc_entry(name_conf, vn->proc_vlan_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Pavel Emelyanova59a8c12008-04-16 00:51:51 -070099 if (vn->proc_vlan_dir)
Gao fengece31ff2013-02-18 01:34:56 +0000100 remove_proc_entry(name_root, net->proc_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
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}
106
107/*
108 * Create /proc/net/vlan entries
109 */
110
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +0000111int __net_init vlan_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
Pavel Emelyanova59a8c12008-04-16 00:51:51 -0700113 struct vlan_net *vn = net_generic(net, vlan_net_id);
Pavel Emelyanovcd1c7012008-04-16 00:51:12 -0700114
Pavel Emelyanova59a8c12008-04-16 00:51:51 -0700115 vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
116 if (!vn->proc_vlan_dir)
Patrick McHardy69ab4b72008-01-21 00:25:15 -0800117 goto err;
118
Christoph Hellwigc3506372018-04-10 19:42:55 +0200119 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));
Pavel Emelyanova59a8c12008-04-16 00:51:51 -0700122 if (!vn->proc_vlan_conf)
Patrick McHardy69ab4b72008-01-21 00:25:15 -0800123 goto err;
Patrick McHardy69ab4b72008-01-21 00:25:15 -0800124 return 0;
125
126err:
Joe Perchesafab2d22011-05-26 10:58:31 +0000127 pr_err("can't create entry in proc filesystem!\n");
Pavel Emelyanovcd1c7012008-04-16 00:51:12 -0700128 vlan_proc_cleanup(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 return -ENOBUFS;
130}
131
132/*
133 * Add directory entry for VLAN device.
134 */
135
Patrick McHardy2029cc22008-01-21 00:26:41 -0800136int vlan_proc_add_dev(struct net_device *vlandev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
Jiri Pirko7da82c02011-12-08 04:11:15 +0000138 struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
Pavel Emelyanova59a8c12008-04-16 00:51:51 -0700139 struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
WANG Cong9c5ff242014-07-25 15:25:10 -0700141 if (!strcmp(vlandev->name, name_conf))
142 return -EINVAL;
Christoph Hellwig3f3942a2018-05-15 15:57:23 +0200143 vlan->dent = proc_create_single_data(vlandev->name, S_IFREG | 0600,
144 vn->proc_vlan_dir, vlandev_seq_show, vlandev);
Jiri Pirko7da82c02011-12-08 04:11:15 +0000145 if (!vlan->dent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 return 0;
148}
149
150/*
151 * Delete directory entry for VLAN device.
152 */
Zhang Shengjue4999f22016-02-18 02:29:30 +0000153void vlan_proc_rem_dev(struct net_device *vlandev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 /** NOTE: This will consume the memory pointed to by dent, it seems. */
David Howellsa8ca16e2013-04-12 17:27:28 +0100156 proc_remove(vlan_dev_priv(vlandev)->dent);
157 vlan_dev_priv(vlandev)->dent = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158}
159
160/****** Proc filesystem entry points ****************************************/
161
162/*
163 * The following few functions build the content of /proc/net/vlan/config
164 */
165
YOSHIFUJI Hideaki122952f2007-02-09 23:24:25 +0900166/* start read of /proc/net/vlan/config */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167static void *vlan_seq_start(struct seq_file *seq, loff_t *pos)
stephen hemminger9e067592009-11-10 07:54:48 +0000168 __acquires(rcu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169{
170 struct net_device *dev;
Pavel Emelyanov80de2d92008-04-16 00:52:24 -0700171 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 loff_t i = 1;
173
stephen hemminger9e067592009-11-10 07:54:48 +0000174 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 if (*pos == 0)
176 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki122952f2007-02-09 23:24:25 +0900177
stephen hemminger9e067592009-11-10 07:54:48 +0000178 for_each_netdev_rcu(net, dev) {
Pavel Emelianov7562f872007-05-03 15:13:45 -0700179 if (!is_vlan_dev(dev))
180 continue;
YOSHIFUJI Hideaki122952f2007-02-09 23:24:25 +0900181
Pavel Emelianov7562f872007-05-03 15:13:45 -0700182 if (i++ == *pos)
183 return dev;
184 }
185
186 return NULL;
YOSHIFUJI Hideaki122952f2007-02-09 23:24:25 +0900187}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
190{
Pavel Emelianov7562f872007-05-03 15:13:45 -0700191 struct net_device *dev;
Pavel Emelyanov80de2d92008-04-16 00:52:24 -0700192 struct net *net = seq_file_net(seq);
Pavel Emelianov7562f872007-05-03 15:13:45 -0700193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 ++*pos;
195
Joe Perchesea110732011-06-13 16:21:26 +0000196 dev = v;
Pavel Emelianov7562f872007-05-03 15:13:45 -0700197 if (v == SEQ_START_TOKEN)
Pavel Emelyanov80de2d92008-04-16 00:52:24 -0700198 dev = net_device_entry(&net->dev_base_head);
Pavel Emelianov7562f872007-05-03 15:13:45 -0700199
stephen hemminger9e067592009-11-10 07:54:48 +0000200 for_each_netdev_continue_rcu(net, dev) {
Pavel Emelianov7562f872007-05-03 15:13:45 -0700201 if (!is_vlan_dev(dev))
202 continue;
203
204 return dev;
205 }
206
207 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208}
209
210static void vlan_seq_stop(struct seq_file *seq, void *v)
stephen hemminger9e067592009-11-10 07:54:48 +0000211 __releases(rcu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212{
stephen hemminger9e067592009-11-10 07:54:48 +0000213 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214}
215
216static int vlan_seq_show(struct seq_file *seq, void *v)
217{
Pavel Emelyanov7a17a2f2008-04-16 00:54:39 -0700218 struct net *net = seq_file_net(seq);
219 struct vlan_net *vn = net_generic(net, vlan_net_id);
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 if (v == SEQ_START_TOKEN) {
222 const char *nmtype = NULL;
223
224 seq_puts(seq, "VLAN Dev name | VLAN ID\n");
225
Pavel Emelyanov7a17a2f2008-04-16 00:54:39 -0700226 if (vn->name_type < ARRAY_SIZE(vlan_name_type_str))
227 nmtype = vlan_name_type_str[vn->name_type];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
YOSHIFUJI Hideaki122952f2007-02-09 23:24:25 +0900229 seq_printf(seq, "Name-Type: %s\n",
Patrick McHardy2029cc22008-01-21 00:26:41 -0800230 nmtype ? nmtype : "UNKNOWN");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 } else {
232 const struct net_device *vlandev = v;
Jiri Pirko7da82c02011-12-08 04:11:15 +0000233 const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
YOSHIFUJI Hideaki122952f2007-02-09 23:24:25 +0900235 seq_printf(seq, "%-15s| %d | %s\n", vlandev->name,
Jiri Pirko7da82c02011-12-08 04:11:15 +0000236 vlan->vlan_id, vlan->real_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 }
238 return 0;
239}
240
241static int vlandev_seq_show(struct seq_file *seq, void *offset)
242{
243 struct net_device *vlandev = (struct net_device *) seq->private;
Jiri Pirko7da82c02011-12-08 04:11:15 +0000244 const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
Eric Dumazet28172732010-07-07 14:58:56 -0700245 struct rtnl_link_stats64 temp;
Ben Hutchingsbe1f3c22010-06-08 07:19:54 +0000246 const struct rtnl_link_stats64 *stats;
Ben Hutchingsbe1f3c22010-06-08 07:19:54 +0000247 static const char fmt64[] = "%30s %12llu\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 int i;
249
Joonwoo Park26a25232008-07-08 03:22:16 -0700250 if (!is_vlan_dev(vlandev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 return 0;
252
Eric Dumazet28172732010-07-07 14:58:56 -0700253 stats = dev_get_stats(vlandev, &temp);
Patrick McHardy2029cc22008-01-21 00:26:41 -0800254 seq_printf(seq,
Jakub Kicinski2106efd2021-11-22 17:24:47 -0800255 "%s VID: %d REORDER_HDR: %i dev->priv_flags: %llx\n",
Jiri Pirko7da82c02011-12-08 04:11:15 +0000256 vlandev->name, vlan->vlan_id,
257 (int)(vlan->flags & 1), vlandev->priv_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Ben Hutchingsbe1f3c22010-06-08 07:19:54 +0000259 seq_printf(seq, fmt64, "total frames received", stats->rx_packets);
260 seq_printf(seq, fmt64, "total bytes received", stats->rx_bytes);
261 seq_printf(seq, fmt64, "Broadcast/Multicast Rcvd", stats->multicast);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 seq_puts(seq, "\n");
Ben Hutchingsbe1f3c22010-06-08 07:19:54 +0000263 seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
264 seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
Jiri Pirko7da82c02011-12-08 04:11:15 +0000265 seq_printf(seq, "Device: %s", vlan->real_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 /* now show all PRIORITY mappings relating to this VLAN */
Patrick McHardy2029cc22008-01-21 00:26:41 -0800267 seq_printf(seq, "\nINGRESS priority mappings: "
268 "0:%u 1:%u 2:%u 3:%u 4:%u 5:%u 6:%u 7:%u\n",
Jiri Pirko7da82c02011-12-08 04:11:15 +0000269 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]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Ferenc Wagner309f7962008-11-10 13:37:40 -0800278 seq_printf(seq, " EGRESS priority mappings: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 for (i = 0; i < 16; i++) {
280 const struct vlan_priority_tci_mapping *mp
Jiri Pirko7da82c02011-12-08 04:11:15 +0000281 = vlan->egress_priority_map[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 while (mp) {
Patrick McHardy734423c2007-06-13 12:07:07 -0700283 seq_printf(seq, "%u:%hu ",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 mp->priority, ((mp->vlan_qos >> 13) & 0x7));
285 mp = mp->next;
286 }
287 }
288 seq_puts(seq, "\n");
289
290 return 0;
291}