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