linux/net/8021q/vlanproc.c
<<
>>
Prefs
   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 */
  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/*
  48 *      Names of the proc directory entries
  49 */
  50
  51static const char name_root[]    = "vlan";
  52static 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
  66static 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 */
  78static 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
  92void vlan_proc_cleanup(struct net *net)
  93{
  94        struct vlan_net *vn = net_generic(net, vlan_net_id);
  95
  96        if (vn->proc_vlan_conf)
  97                remove_proc_entry(name_conf, vn->proc_vlan_dir);
  98
  99        if (vn->proc_vlan_dir)
 100                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}
 106
 107/*
 108 *      Create /proc/net/vlan entries
 109 */
 110
 111int __net_init vlan_proc_init(struct net *net)
 112{
 113        struct vlan_net *vn = net_generic(net, vlan_net_id);
 114
 115        vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
 116        if (!vn->proc_vlan_dir)
 117                goto err;
 118
 119        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        if (!vn->proc_vlan_conf)
 123                goto err;
 124        return 0;
 125
 126err:
 127        pr_err("can't create entry in proc filesystem!\n");
 128        vlan_proc_cleanup(net);
 129        return -ENOBUFS;
 130}
 131
 132/*
 133 *      Add directory entry for VLAN device.
 134 */
 135
 136int vlan_proc_add_dev(struct net_device *vlandev)
 137{
 138        struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
 139        struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);
 140
 141        if (!strcmp(vlandev->name, name_conf))
 142                return -EINVAL;
 143        vlan->dent = proc_create_single_data(vlandev->name, S_IFREG | 0600,
 144                        vn->proc_vlan_dir, vlandev_seq_show, vlandev);
 145        if (!vlan->dent)
 146                return -ENOBUFS;
 147        return 0;
 148}
 149
 150/*
 151 *      Delete directory entry for VLAN device.
 152 */
 153void vlan_proc_rem_dev(struct net_device *vlandev)
 154{
 155        /** NOTE:  This will consume the memory pointed to by dent, it seems. */
 156        proc_remove(vlan_dev_priv(vlandev)->dent);
 157        vlan_dev_priv(vlandev)->dent = NULL;
 158}
 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 */
 167static 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        if (*pos == 0)
 176                return SEQ_START_TOKEN;
 177
 178        for_each_netdev_rcu(net, dev) {
 179                if (!is_vlan_dev(dev))
 180                        continue;
 181
 182                if (i++ == *pos)
 183                        return dev;
 184        }
 185
 186        return  NULL;
 187}
 188
 189static 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        ++*pos;
 195
 196        dev = v;
 197        if (v == SEQ_START_TOKEN)
 198                dev = net_device_entry(&net->dev_base_head);
 199
 200        for_each_netdev_continue_rcu(net, dev) {
 201                if (!is_vlan_dev(dev))
 202                        continue;
 203
 204                return dev;
 205        }
 206
 207        return NULL;
 208}
 209
 210static void vlan_seq_stop(struct seq_file *seq, void *v)
 211        __releases(rcu)
 212{
 213        rcu_read_unlock();
 214}
 215
 216static int vlan_seq_show(struct seq_file *seq, void *v)
 217{
 218        struct net *net = seq_file_net(seq);
 219        struct vlan_net *vn = net_generic(net, vlan_net_id);
 220
 221        if (v == SEQ_START_TOKEN) {
 222                const char *nmtype = NULL;
 223
 224                seq_puts(seq, "VLAN Dev name     | VLAN ID\n");
 225
 226                if (vn->name_type < ARRAY_SIZE(vlan_name_type_str))
 227                    nmtype =  vlan_name_type_str[vn->name_type];
 228
 229                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                seq_printf(seq, "%-15s| %d  | %s\n",  vlandev->name,
 236                           vlan->vlan_id,    vlan->real_dev->name);
 237        }
 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;
 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        if (!is_vlan_dev(vlandev))
 251                return 0;
 252
 253        stats = dev_get_stats(vlandev, &temp);
 254        seq_printf(seq,
 255                   "%s  VID: %d  REORDER_HDR: %i  dev->priv_flags: %hx\n",
 256                   vlandev->name, vlan->vlan_id,
 257                   (int)(vlan->flags & 1), vlandev->priv_flags);
 258
 259        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);
 262        seq_puts(seq, "\n");
 263        seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
 264        seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
 265        seq_printf(seq, "Device: %s", vlan->real_dev->name);
 266        /* now show all PRIORITY mappings relating to this VLAN */
 267        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        seq_printf(seq, " EGRESS priority mappings: ");
 279        for (i = 0; i < 16; i++) {
 280                const struct vlan_priority_tci_mapping *mp
 281                        = vlan->egress_priority_map[i];
 282                while (mp) {
 283                        seq_printf(seq, "%u:%hu ",
 284                                   mp->priority, ((mp->vlan_qos >> 13) & 0x7));
 285                        mp = mp->next;
 286                }
 287        }
 288        seq_puts(seq, "\n");
 289
 290        return 0;
 291}
 292