]> git.proxmox.com Git - mirror_ovs.git/blame - datapath/brc_procfs.c
datapath: Add missing #include to datapath/flow.h.
[mirror_ovs.git] / datapath / brc_procfs.c
CommitLineData
a14bc59f 1/*
35f7605b 2 * Copyright (c) 2009, 2010 Nicira Networks.
a14bc59f
BP
3 * Distributed under the terms of the GNU GPL version 2.
4 *
5 * Significant portions of this file may be copied from parts of the Linux
6 * kernel, by Linus Torvalds and others.
7 */
8
064af421
BP
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/netdevice.h>
12#include <linux/proc_fs.h>
13#include <linux/seq_file.h>
14#include <net/genetlink.h>
35f7605b 15#include "brc_procfs.h"
064af421
BP
16#include "openvswitch/brcompat-netlink.h"
17
18/* This code implements a Generic Netlink command BRC_GENL_C_SET_PROC that can
19 * be used to add, modify, and delete arbitrary files in selected
20 * subdirectories of /proc. It's a horrible kluge prompted by the need to
21 * simulate certain /proc/net/vlan and /proc/net/bonding files for software
22 * that wants to read them, and with any luck it will go away eventually.
23 *
24 * The implementation is a kluge too. In particular, we want to release the
25 * strings copied into the 'data' members of proc_dir_entry when the
26 * proc_dir_entry structures are freed, but there doesn't appear to be a way to
27 * hook that, so instead we have to rely on being the only entity modifying the
28 * directories in question.
29 */
30
31static int brc_seq_show(struct seq_file *seq, void *unused)
32{
33 seq_puts(seq, seq->private);
34 return 0;
35}
36
37static int brc_seq_open(struct inode *inode, struct file *file)
38{
39 return single_open(file, brc_seq_show, PDE(inode)->data);
40}
41
42static struct file_operations brc_fops = {
43 .owner = THIS_MODULE,
44 .open = brc_seq_open,
45 .read = seq_read,
46 .llseek = seq_lseek,
47 .release = single_release,
48};
49
50static struct proc_dir_entry *proc_vlan_dir;
51static struct proc_dir_entry *proc_bonding_dir;
52
35f7605b 53static struct proc_dir_entry *brc_lookup_entry(struct proc_dir_entry *de, const char *name)
064af421
BP
54{
55 int namelen = strlen(name);
56 for (de = de->subdir; de; de = de->next) {
57 if (de->namelen != namelen)
58 continue;
59 if (!memcmp(name, de->name, de->namelen))
60 return de;
61 }
62 return NULL;
63}
64
65static struct proc_dir_entry *brc_open_dir(const char *dir_name,
66 struct proc_dir_entry *parent,
67 struct proc_dir_entry **dirp)
68{
69 if (!*dirp) {
70 struct proc_dir_entry *dir;
71 if (brc_lookup_entry(parent, dir_name)) {
72 printk(KERN_WARNING "%s proc directory exists, can't "
73 "simulate--probably its real module is "
74 "loaded\n", dir_name);
75 return NULL;
76 }
77 dir = *dirp = proc_mkdir(dir_name, parent);
78 }
79 return *dirp;
80}
81
82/* Maximum length of the BRC_GENL_A_PROC_DIR and BRC_GENL_A_PROC_NAME strings.
83 * If we could depend on supporting NLA_NUL_STRING and the .len member in
84 * Generic Netlink policy, then we could just put this in brc_genl_policy (and
85 * simplify brc_genl_set_proc() below too), but upstream 2.6.18 does not have
86 * either. */
87#define BRC_NAME_LEN_MAX 32
88
89int brc_genl_set_proc(struct sk_buff *skb, struct genl_info *info)
90{
91 struct proc_dir_entry *dir, *entry;
92 const char *dir_name, *name;
93 char *data;
94
95 if (!info->attrs[BRC_GENL_A_PROC_DIR] ||
96 VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DIR]) ||
97 !info->attrs[BRC_GENL_A_PROC_NAME] ||
98 VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_NAME]) ||
99 (info->attrs[BRC_GENL_A_PROC_DATA] &&
100 VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DATA])))
101 return -EINVAL;
102
103 dir_name = nla_data(info->attrs[BRC_GENL_A_PROC_DIR]);
104 name = nla_data(info->attrs[BRC_GENL_A_PROC_NAME]);
105 if (strlen(dir_name) > BRC_NAME_LEN_MAX ||
106 strlen(name) > BRC_NAME_LEN_MAX)
107 return -EINVAL;
108
109 if (!strcmp(dir_name, "net/vlan"))
110 dir = brc_open_dir("vlan", proc_net, &proc_vlan_dir);
111 else if (!strcmp(dir_name, "net/bonding"))
112 dir = brc_open_dir("bonding", proc_net, &proc_bonding_dir);
113 else
114 return -EINVAL;
115 if (!dir) {
116 /* Probably failed because the module that really implements
117 * the function in question is loaded and already owns the
118 * directory in question.*/
119 return -EBUSY;
120 }
121
122 entry = brc_lookup_entry(dir, name);
123 if (!info->attrs[BRC_GENL_A_PROC_DATA]) {
124 if (!entry)
125 return -ENOENT;
126
127 data = entry->data;
128 remove_proc_entry(name, dir);
129 if (brc_lookup_entry(dir, name))
130 return -EBUSY; /* Shouldn't happen */
131
132 kfree(data);
133 } else {
134 data = kstrdup(nla_data(info->attrs[BRC_GENL_A_PROC_DATA]),
135 GFP_KERNEL);
136 if (!data)
137 return -ENOMEM;
138
139 if (entry) {
140 char *old_data = entry->data;
141 entry->data = data;
142 kfree(old_data);
143 return 0;
144 }
145
146 entry = create_proc_entry(name, S_IFREG|S_IRUSR|S_IWUSR, dir);
147 if (!entry) {
148 kfree(data);
149 return -ENOBUFS;
150 }
151 entry->proc_fops = &brc_fops;
152 entry->data = data;
153 }
154 return 0;
155}
156
157static void kill_proc_dir(const char *dir_name,
158 struct proc_dir_entry *parent,
159 struct proc_dir_entry *dir)
160{
161 if (!dir)
162 return;
163 for (;;) {
164 struct proc_dir_entry *e;
165 char *data;
166 char name[BRC_NAME_LEN_MAX + 1];
167
168 e = dir->subdir;
169 if (!e)
170 break;
171
172 if (e->namelen >= sizeof name) {
173 /* Can't happen: we prevent adding names this long by
174 * limiting the BRC_GENL_A_PROC_NAME string to
175 * BRC_NAME_LEN_MAX bytes. */
176 WARN_ON(1);
177 break;
178 }
179 strcpy(name, e->name);
180
181 data = e->data;
182 e->data = NULL;
183 kfree(data);
184
185 remove_proc_entry(name, dir);
186 }
187 remove_proc_entry(dir_name, parent);
188}
189
190void brc_procfs_exit(void)
191{
192 kill_proc_dir("vlan", proc_net, proc_vlan_dir);
193 kill_proc_dir("bonding", proc_net, proc_bonding_dir);
194}