linux/net/8021q/vlanproc.c
<<
>>
Prefs
   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 */
  37static int vlan_seq_show(struct seq_file *seq, void *v);
  38static void *vlan_seq_start(struct seq_file *seq, loff_t *pos);
  39static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos);
  40static void vlan_seq_stop(struct seq_file *seq, void *);
  41static 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
  52static const char name_root[]    = "vlan";
  53static 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
  67static 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
  74static 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
  80static 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
  92static int vlandev_seq_open(struct inode *inode, struct file *file)
  93{
  94        return single_open(file, vlandev_seq_show, PDE(inode)->data);
  95}
  96
  97static 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 */
 110static 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
 124void 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
 143int 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
 157err:
 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
 167int 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 */
 183int 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 */
 203static 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
 226static 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
 247static void vlan_seq_stop(struct seq_file *seq, void *v)
 248        __releases(dev_base_lock)
 249{
 250        read_unlock(&dev_base_lock);
 251}
 252
 253static 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
 278static 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