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