xref: /openbmc/linux/net/8021q/vlanproc.c (revision 8624a95e)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /******************************************************************************
31da177e4SLinus Torvalds  * vlanproc.c	VLAN Module. /proc filesystem interface.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *		This module is completely hardware-independent and provides
61da177e4SLinus Torvalds  *		access to the router using Linux /proc filesystem.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Author:	Ben Greear, <greearb@candelatech.com> coppied from wanproc.c
91da177e4SLinus Torvalds  *               by: Gene Kozin	<genek@compuserve.com>
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Copyright:	(c) 1998 Ben Greear
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * ============================================================================
141da177e4SLinus Torvalds  * Jan 20, 1998        Ben Greear     Initial Version
151da177e4SLinus Torvalds  *****************************************************************************/
161da177e4SLinus Torvalds 
17afab2d29SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18afab2d29SJoe Perches 
191da177e4SLinus Torvalds #include <linux/module.h>
2061362766SPatrick McHardy #include <linux/errno.h>
211da177e4SLinus Torvalds #include <linux/kernel.h>
2261362766SPatrick McHardy #include <linux/string.h>
231da177e4SLinus Torvalds #include <linux/proc_fs.h>
241da177e4SLinus Torvalds #include <linux/seq_file.h>
251da177e4SLinus Torvalds #include <linux/fs.h>
261da177e4SLinus Torvalds #include <linux/netdevice.h>
271da177e4SLinus Torvalds #include <linux/if_vlan.h>
28457c4cbcSEric W. Biederman #include <net/net_namespace.h>
29a59a8c1cSPavel Emelyanov #include <net/netns/generic.h>
301da177e4SLinus Torvalds #include "vlanproc.h"
311da177e4SLinus Torvalds #include "vlan.h"
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds /****** Function Prototypes *************************************************/
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds /* Methods for preparing data for reading proc entries */
361da177e4SLinus Torvalds static int vlan_seq_show(struct seq_file *seq, void *v);
371da177e4SLinus Torvalds static void *vlan_seq_start(struct seq_file *seq, loff_t *pos);
381da177e4SLinus Torvalds static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos);
391da177e4SLinus Torvalds static void vlan_seq_stop(struct seq_file *seq, void *);
401da177e4SLinus Torvalds static int vlandev_seq_show(struct seq_file *seq, void *v);
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds /*
431da177e4SLinus Torvalds  *	Global Data
441da177e4SLinus Torvalds  */
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds /*
481da177e4SLinus Torvalds  *	Names of the proc directory entries
491da177e4SLinus Torvalds  */
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds static const char name_root[]	 = "vlan";
521da177e4SLinus Torvalds static const char name_conf[]	 = "config";
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds /*
551da177e4SLinus Torvalds  *	Structures for interfacing with the /proc filesystem.
5625985edcSLucas De Marchi  *	VLAN creates its own directory /proc/net/vlan with the following
571da177e4SLinus Torvalds  *	entries:
581da177e4SLinus Torvalds  *	config		device status/configuration
591da177e4SLinus Torvalds  *	<device>	entry for each  device
601da177e4SLinus Torvalds  */
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds /*
631da177e4SLinus Torvalds  *	Generic /proc/net/vlan/<file> file and inode operations
641da177e4SLinus Torvalds  */
651da177e4SLinus Torvalds 
6656b3d975SPhilippe De Muyter static const struct seq_operations vlan_seq_ops = {
671da177e4SLinus Torvalds 	.start = vlan_seq_start,
681da177e4SLinus Torvalds 	.next = vlan_seq_next,
691da177e4SLinus Torvalds 	.stop = vlan_seq_stop,
701da177e4SLinus Torvalds 	.show = vlan_seq_show,
711da177e4SLinus Torvalds };
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds /*
744907cb7bSAnatol Pomozov  * Proc filesystem directory entries.
751da177e4SLinus Torvalds  */
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds /* Strings */
7836cbd3dcSJan Engelhardt static const char *const vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = {
791da177e4SLinus Torvalds     [VLAN_NAME_TYPE_RAW_PLUS_VID]        = "VLAN_NAME_TYPE_RAW_PLUS_VID",
801da177e4SLinus Torvalds     [VLAN_NAME_TYPE_PLUS_VID_NO_PAD]	 = "VLAN_NAME_TYPE_PLUS_VID_NO_PAD",
811da177e4SLinus Torvalds     [VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD",
821da177e4SLinus Torvalds     [VLAN_NAME_TYPE_PLUS_VID]		 = "VLAN_NAME_TYPE_PLUS_VID",
831da177e4SLinus Torvalds };
841da177e4SLinus Torvalds /*
851da177e4SLinus Torvalds  *	Interface functions
861da177e4SLinus Torvalds  */
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds /*
891da177e4SLinus Torvalds  *	Clean up /proc/net/vlan entries
901da177e4SLinus Torvalds  */
911da177e4SLinus Torvalds 
vlan_proc_cleanup(struct net * net)92cd1c7014SPavel Emelyanov void vlan_proc_cleanup(struct net *net)
931da177e4SLinus Torvalds {
94a59a8c1cSPavel Emelyanov 	struct vlan_net *vn = net_generic(net, vlan_net_id);
95cd1c7014SPavel Emelyanov 
96a59a8c1cSPavel Emelyanov 	if (vn->proc_vlan_conf)
97a59a8c1cSPavel Emelyanov 		remove_proc_entry(name_conf, vn->proc_vlan_dir);
981da177e4SLinus Torvalds 
99a59a8c1cSPavel Emelyanov 	if (vn->proc_vlan_dir)
100ece31ffdSGao feng 		remove_proc_entry(name_root, net->proc_net);
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds 	/* Dynamically added entries should be cleaned up as their vlan_device
1031da177e4SLinus Torvalds 	 * is removed, so we should not have to take care of it here...
1041da177e4SLinus Torvalds 	 */
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds /*
1081da177e4SLinus Torvalds  *	Create /proc/net/vlan entries
1091da177e4SLinus Torvalds  */
1101da177e4SLinus Torvalds 
vlan_proc_init(struct net * net)1112c8c1e72SAlexey Dobriyan int __net_init vlan_proc_init(struct net *net)
1121da177e4SLinus Torvalds {
113a59a8c1cSPavel Emelyanov 	struct vlan_net *vn = net_generic(net, vlan_net_id);
114cd1c7014SPavel Emelyanov 
115a59a8c1cSPavel Emelyanov 	vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
116a59a8c1cSPavel Emelyanov 	if (!vn->proc_vlan_dir)
11769ab4b7dSPatrick McHardy 		goto err;
11869ab4b7dSPatrick McHardy 
119c3506372SChristoph Hellwig 	vn->proc_vlan_conf = proc_create_net(name_conf, S_IFREG | 0600,
120c3506372SChristoph Hellwig 			vn->proc_vlan_dir, &vlan_seq_ops,
121c3506372SChristoph Hellwig 			sizeof(struct seq_net_private));
122a59a8c1cSPavel Emelyanov 	if (!vn->proc_vlan_conf)
12369ab4b7dSPatrick McHardy 		goto err;
1241da177e4SLinus Torvalds 	return 0;
12569ab4b7dSPatrick McHardy 
12669ab4b7dSPatrick McHardy err:
127afab2d29SJoe Perches 	pr_err("can't create entry in proc filesystem!\n");
128cd1c7014SPavel Emelyanov 	vlan_proc_cleanup(net);
1291da177e4SLinus Torvalds 	return -ENOBUFS;
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds /*
1331da177e4SLinus Torvalds  *	Add directory entry for VLAN device.
1341da177e4SLinus Torvalds  */
1351da177e4SLinus Torvalds 
vlan_proc_add_dev(struct net_device * vlandev)1361da177e4SLinus Torvalds int vlan_proc_add_dev(struct net_device *vlandev)
1371da177e4SLinus Torvalds {
1387da82c06SJiri Pirko 	struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
139a59a8c1cSPavel Emelyanov 	struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);
1401da177e4SLinus Torvalds 
1419c5ff24fSWANG Cong 	if (!strcmp(vlandev->name, name_conf))
1429c5ff24fSWANG Cong 		return -EINVAL;
1433f3942acSChristoph Hellwig 	vlan->dent = proc_create_single_data(vlandev->name, S_IFREG | 0600,
1443f3942acSChristoph Hellwig 			vn->proc_vlan_dir, vlandev_seq_show, vlandev);
1457da82c06SJiri Pirko 	if (!vlan->dent)
1461da177e4SLinus Torvalds 		return -ENOBUFS;
1471da177e4SLinus Torvalds 	return 0;
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds /*
1511da177e4SLinus Torvalds  *	Delete directory entry for VLAN device.
1521da177e4SLinus Torvalds  */
vlan_proc_rem_dev(struct net_device * vlandev)153e4999f25SZhang Shengju void vlan_proc_rem_dev(struct net_device *vlandev)
1541da177e4SLinus Torvalds {
1551da177e4SLinus Torvalds 	/** NOTE:  This will consume the memory pointed to by dent, it seems. */
156a8ca16eaSDavid Howells 	proc_remove(vlan_dev_priv(vlandev)->dent);
1577da82c06SJiri Pirko 	vlan_dev_priv(vlandev)->dent = NULL;
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds /****** Proc filesystem entry points ****************************************/
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds /*
1631da177e4SLinus Torvalds  * The following few functions build the content of /proc/net/vlan/config
1641da177e4SLinus Torvalds  */
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds /* start read of /proc/net/vlan/config */
vlan_seq_start(struct seq_file * seq,loff_t * pos)1671da177e4SLinus Torvalds static void *vlan_seq_start(struct seq_file *seq, loff_t *pos)
1689e067597Sstephen hemminger 	__acquires(rcu)
1691da177e4SLinus Torvalds {
1701da177e4SLinus Torvalds 	struct net_device *dev;
17180de2d98SPavel Emelyanov 	struct net *net = seq_file_net(seq);
1721da177e4SLinus Torvalds 	loff_t i = 1;
1731da177e4SLinus Torvalds 
1749e067597Sstephen hemminger 	rcu_read_lock();
1751da177e4SLinus Torvalds 	if (*pos == 0)
1761da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
1771da177e4SLinus Torvalds 
1789e067597Sstephen hemminger 	for_each_netdev_rcu(net, dev) {
1797562f876SPavel Emelianov 		if (!is_vlan_dev(dev))
1807562f876SPavel Emelianov 			continue;
1811da177e4SLinus Torvalds 
1827562f876SPavel Emelianov 		if (i++ == *pos)
1837562f876SPavel Emelianov 			return dev;
1847562f876SPavel Emelianov 	}
1857562f876SPavel Emelianov 
1867562f876SPavel Emelianov 	return  NULL;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds 
vlan_seq_next(struct seq_file * seq,void * v,loff_t * pos)1891da177e4SLinus Torvalds static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1901da177e4SLinus Torvalds {
1917562f876SPavel Emelianov 	struct net_device *dev;
19280de2d98SPavel Emelyanov 	struct net *net = seq_file_net(seq);
1937562f876SPavel Emelianov 
1941da177e4SLinus Torvalds 	++*pos;
1951da177e4SLinus Torvalds 
196ea110733SJoe Perches 	dev = v;
1977562f876SPavel Emelianov 	if (v == SEQ_START_TOKEN)
19880de2d98SPavel Emelyanov 		dev = net_device_entry(&net->dev_base_head);
1997562f876SPavel Emelianov 
2009e067597Sstephen hemminger 	for_each_netdev_continue_rcu(net, dev) {
2017562f876SPavel Emelianov 		if (!is_vlan_dev(dev))
2027562f876SPavel Emelianov 			continue;
2037562f876SPavel Emelianov 
2047562f876SPavel Emelianov 		return dev;
2057562f876SPavel Emelianov 	}
2067562f876SPavel Emelianov 
2077562f876SPavel Emelianov 	return NULL;
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds 
vlan_seq_stop(struct seq_file * seq,void * v)2101da177e4SLinus Torvalds static void vlan_seq_stop(struct seq_file *seq, void *v)
2119e067597Sstephen hemminger 	__releases(rcu)
2121da177e4SLinus Torvalds {
2139e067597Sstephen hemminger 	rcu_read_unlock();
2141da177e4SLinus Torvalds }
2151da177e4SLinus Torvalds 
vlan_seq_show(struct seq_file * seq,void * v)2161da177e4SLinus Torvalds static int vlan_seq_show(struct seq_file *seq, void *v)
2171da177e4SLinus Torvalds {
2187a17a2f7SPavel Emelyanov 	struct net *net = seq_file_net(seq);
2197a17a2f7SPavel Emelyanov 	struct vlan_net *vn = net_generic(net, vlan_net_id);
2207a17a2f7SPavel Emelyanov 
2211da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
2221da177e4SLinus Torvalds 		const char *nmtype = NULL;
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds 		seq_puts(seq, "VLAN Dev name	 | VLAN ID\n");
2251da177e4SLinus Torvalds 
2267a17a2f7SPavel Emelyanov 		if (vn->name_type < ARRAY_SIZE(vlan_name_type_str))
2277a17a2f7SPavel Emelyanov 		    nmtype =  vlan_name_type_str[vn->name_type];
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 		seq_printf(seq, "Name-Type: %s\n",
2301da177e4SLinus Torvalds 			   nmtype ? nmtype :  "UNKNOWN");
2311da177e4SLinus Torvalds 	} else {
2321da177e4SLinus Torvalds 		const struct net_device *vlandev = v;
2337da82c06SJiri Pirko 		const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds 		seq_printf(seq, "%-15s| %d  | %s\n",  vlandev->name,
2367da82c06SJiri Pirko 			   vlan->vlan_id,    vlan->real_dev->name);
2371da177e4SLinus Torvalds 	}
2381da177e4SLinus Torvalds 	return 0;
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds 
vlandev_seq_show(struct seq_file * seq,void * offset)2411da177e4SLinus Torvalds static int vlandev_seq_show(struct seq_file *seq, void *offset)
2421da177e4SLinus Torvalds {
2431da177e4SLinus Torvalds 	struct net_device *vlandev = (struct net_device *) seq->private;
2447da82c06SJiri Pirko 	const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
24528172739SEric Dumazet 	struct rtnl_link_stats64 temp;
246be1f3c2cSBen Hutchings 	const struct rtnl_link_stats64 *stats;
247be1f3c2cSBen Hutchings 	static const char fmt64[] = "%30s %12llu\n";
2481da177e4SLinus Torvalds 	int i;
2491da177e4SLinus Torvalds 
25026a25239SJoonwoo Park 	if (!is_vlan_dev(vlandev))
2511da177e4SLinus Torvalds 		return 0;
2521da177e4SLinus Torvalds 
25328172739SEric Dumazet 	stats = dev_get_stats(vlandev, &temp);
2542029cc2cSPatrick McHardy 	seq_printf(seq,
2552106efdaSJakub Kicinski 		   "%s  VID: %d	 REORDER_HDR: %i  dev->priv_flags: %llx\n",
2567da82c06SJiri Pirko 		   vlandev->name, vlan->vlan_id,
2577da82c06SJiri Pirko 		   (int)(vlan->flags & 1), vlandev->priv_flags);
2581da177e4SLinus Torvalds 
259be1f3c2cSBen Hutchings 	seq_printf(seq, fmt64, "total frames received", stats->rx_packets);
260be1f3c2cSBen Hutchings 	seq_printf(seq, fmt64, "total bytes received", stats->rx_bytes);
261be1f3c2cSBen Hutchings 	seq_printf(seq, fmt64, "Broadcast/Multicast Rcvd", stats->multicast);
2621da177e4SLinus Torvalds 	seq_puts(seq, "\n");
263be1f3c2cSBen Hutchings 	seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
264be1f3c2cSBen Hutchings 	seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
2657da82c06SJiri Pirko 	seq_printf(seq, "Device: %s", vlan->real_dev->name);
2661da177e4SLinus Torvalds 	/* now show all PRIORITY mappings relating to this VLAN */
2672029cc2cSPatrick McHardy 	seq_printf(seq, "\nINGRESS priority mappings: "
2682029cc2cSPatrick McHardy 			"0:%u  1:%u  2:%u  3:%u  4:%u  5:%u  6:%u 7:%u\n",
2697da82c06SJiri Pirko 		   vlan->ingress_priority_map[0],
2707da82c06SJiri Pirko 		   vlan->ingress_priority_map[1],
2717da82c06SJiri Pirko 		   vlan->ingress_priority_map[2],
2727da82c06SJiri Pirko 		   vlan->ingress_priority_map[3],
2737da82c06SJiri Pirko 		   vlan->ingress_priority_map[4],
2747da82c06SJiri Pirko 		   vlan->ingress_priority_map[5],
2757da82c06SJiri Pirko 		   vlan->ingress_priority_map[6],
2767da82c06SJiri Pirko 		   vlan->ingress_priority_map[7]);
2771da177e4SLinus Torvalds 
278309f796fSFerenc Wagner 	seq_printf(seq, " EGRESS priority mappings: ");
2791da177e4SLinus Torvalds 	for (i = 0; i < 16; i++) {
2801da177e4SLinus Torvalds 		const struct vlan_priority_tci_mapping *mp
2817da82c06SJiri Pirko 			= vlan->egress_priority_map[i];
2821da177e4SLinus Torvalds 		while (mp) {
283*8624a95eSBill Wendling 			seq_printf(seq, "%u:%d ",
2841da177e4SLinus Torvalds 				   mp->priority, ((mp->vlan_qos >> 13) & 0x7));
2851da177e4SLinus Torvalds 			mp = mp->next;
2861da177e4SLinus Torvalds 		}
2871da177e4SLinus Torvalds 	}
2881da177e4SLinus Torvalds 	seq_puts(seq, "\n");
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 	return 0;
2911da177e4SLinus Torvalds }
292