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        vlan->dent =
 175                proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR,
 176                                 vn->proc_vlan_dir, &vlandev_fops, vlandev);
 177        if (!vlan->dent)
 178                return -ENOBUFS;
 179        return 0;
 180}
 181
 182/*
 183 *      Delete directory entry for VLAN device.
 184 */
 185int vlan_proc_rem_dev(struct net_device *vlandev)
 186{
 187        /** NOTE:  This will consume the memory pointed to by dent, it seems. */
 188        proc_remove(vlan_dev_priv(vlandev)->dent);
 189        vlan_dev_priv(vlandev)->dent = NULL;
 190        return 0;
 191}
 192
 193/****** Proc filesystem entry points ****************************************/
 194
 195/*
 196 * The following few functions build the content of /proc/net/vlan/config
 197 */
 198
 199/* start read of /proc/net/vlan/config */
 200static void *vlan_seq_start(struct seq_file *seq, loff_t *pos)
 201        __acquires(rcu)
 202{
 203        struct net_device *dev;
 204        struct net *net = seq_file_net(seq);
 205        loff_t i = 1;
 206
 207        rcu_read_lock();
 208        if (*pos == 0)
 209                return SEQ_START_TOKEN;
 210
 211        for_each_netdev_rcu(net, dev) {
 212                if (!is_vlan_dev(dev))
 213                        continue;
 214
 215                if (i++ == *pos)
 216                        return dev;
 217        }
 218
 219        return  NULL;
 220}
 221
 222static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 223{
 224        struct net_device *dev;
 225        struct net *net = seq_file_net(seq);
 226
 227        ++*pos;
 228
 229        dev = v;
 230        if (v == SEQ_START_TOKEN)
 231                dev = net_device_entry(&net->dev_base_head);
 232
 233        for_each_netdev_continue_rcu(net, dev) {
 234                if (!is_vlan_dev(dev))
 235                        continue;
 236
 237                return dev;
 238        }
 239
 240        return NULL;
 241}
 242
 243static void vlan_seq_stop(struct seq_file *seq, void *v)
 244        __releases(rcu)
 245{
 246        rcu_read_unlock();
 247}
 248
 249static int vlan_seq_show(struct seq_file *seq, void *v)
 250{
 251        struct net *net = seq_file_net(seq);
 252        struct vlan_net *vn = net_generic(net, vlan_net_id);
 253
 254        if (v == SEQ_START_TOKEN) {
 255                const char *nmtype = NULL;
 256
 257                seq_puts(seq, "VLAN Dev name     | VLAN ID\n");
 258
 259                if (vn->name_type < ARRAY_SIZE(vlan_name_type_str))
 260                    nmtype =  vlan_name_type_str[vn->name_type];
 261
 262                seq_printf(seq, "Name-Type: %s\n",
 263                           nmtype ? nmtype :  "UNKNOWN");
 264        } else {
 265                const struct net_device *vlandev = v;
 266                const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
 267
 268                seq_printf(seq, "%-15s| %d  | %s\n",  vlandev->name,
 269                           vlan->vlan_id,    vlan->real_dev->name);
 270        }
 271        return 0;
 272}
 273
 274static int vlandev_seq_show(struct seq_file *seq, void *offset)
 275{
 276        struct net_device *vlandev = (struct net_device *) seq->private;
 277        const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
 278        struct rtnl_link_stats64 temp;
 279        const struct rtnl_link_stats64 *stats;
 280        static const char fmt64[] = "%30s %12llu\n";
 281        int i;
 282
 283        if (!is_vlan_dev(vlandev))
 284                return 0;
 285
 286        stats = dev_get_stats(vlandev, &temp);
 287        seq_printf(seq,
 288                   "%s  VID: %d  REORDER_HDR: %i  dev->priv_flags: %hx\n",
 289                   vlandev->name, vlan->vlan_id,
 290                   (int)(vlan->flags & 1), vlandev->priv_flags);
 291
 292        seq_printf(seq, fmt64, "total frames received", stats->rx_packets);
 293        seq_printf(seq, fmt64, "total bytes received", stats->rx_bytes);
 294        seq_printf(seq, fmt64, "Broadcast/Multicast Rcvd", stats->multicast);
 295        seq_puts(seq, "\n");
 296        seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
 297        seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
 298        seq_printf(seq, "Device: %s", vlan->real_dev->name);
 299        /* now show all PRIORITY mappings relating to this VLAN */
 300        seq_printf(seq, "\nINGRESS priority mappings: "
 301                        "0:%u  1:%u  2:%u  3:%u  4:%u  5:%u  6:%u 7:%u\n",
 302                   vlan->ingress_priority_map[0],
 303                   vlan->ingress_priority_map[1],
 304                   vlan->ingress_priority_map[2],
 305                   vlan->ingress_priority_map[3],
 306                   vlan->ingress_priority_map[4],
 307                   vlan->ingress_priority_map[5],
 308                   vlan->ingress_priority_map[6],
 309                   vlan->ingress_priority_map[7]);
 310
 311        seq_printf(seq, " EGRESS priority mappings: ");
 312        for (i = 0; i < 16; i++) {
 313                const struct vlan_priority_tci_mapping *mp
 314                        = vlan->egress_priority_map[i];
 315                while (mp) {
 316                        seq_printf(seq, "%u:%hu ",
 317                                   mp->priority, ((mp->vlan_qos >> 13) & 0x7));
 318                        mp = mp->next;
 319                }
 320        }
 321        seq_puts(seq, "\n");
 322
 323        return 0;
 324}
 325