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