]> git.proxmox.com Git - mirror_ovs.git/blob - vswitchd/proc-net-compat.c
Import from old repository commit 61ef2b42a9c4ba8e1600f15bb0236765edc2ad45.
[mirror_ovs.git] / vswitchd / proc-net-compat.c
1 /* Copyright (c) 2009 Nicira Networks
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 #include <config.h>
19 #include "proc-net-compat.h"
20 #include <assert.h>
21 #include <dirent.h>
22 #include <errno.h>
23 #include <inttypes.h>
24 #include <string.h>
25 #include "dynamic-string.h"
26 #include "hash.h"
27 #include "netlink-protocol.h"
28 #include "netlink.h"
29 #include "ofpbuf.h"
30 #include "openvswitch/brcompat-netlink.h"
31 #include "hmap.h"
32 #include "shash.h"
33 #include "svec.h"
34
35 #define THIS_MODULE VLM_proc_net_compat
36 #include "vlog.h"
37
38 /* Netlink socket to bridge compatibility kernel module. */
39 static struct nl_sock *brc_sock;
40
41 /* The Generic Netlink family number used for bridge compatibility. */
42 static int brc_family = 0;
43
44 /* Rate limiting for log messages. */
45 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
46
47 static void flush_dir(const char *dir);
48 static int set_proc_file(const char *dir, const char *file, const char *data);
49
50 /* Initializes the /proc/net compatibility layer. Returns 0 if successful,
51 * otherwise a positive errno value. */
52 int
53 proc_net_compat_init(void)
54 {
55 if (!brc_sock) {
56 int retval = nl_lookup_genl_family(BRC_GENL_FAMILY_NAME, &brc_family);
57 if (retval) {
58 return retval;
59 }
60
61 retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &brc_sock);
62 if (retval) {
63 return retval;
64 }
65
66 flush_dir("/proc/net/vlan");
67 flush_dir("/proc/net/bonding");
68 }
69 return 0;
70 }
71
72 static int
73 set_proc_file(const char *dir, const char *file, const char *data)
74 {
75 struct ofpbuf request, *reply;
76 int retval;
77
78 ofpbuf_init(&request, 0);
79 nl_msg_put_genlmsghdr(&request, brc_sock, 1024, brc_family, NLM_F_REQUEST,
80 BRC_GENL_C_SET_PROC, 1);
81 nl_msg_put_string(&request, BRC_GENL_A_PROC_DIR, dir);
82 nl_msg_put_string(&request, BRC_GENL_A_PROC_NAME, file);
83 if (data) {
84 nl_msg_put_string(&request, BRC_GENL_A_PROC_DATA, data);
85 }
86
87 retval = nl_sock_transact(brc_sock, &request, &reply);
88 ofpbuf_uninit(&request);
89 ofpbuf_delete(reply);
90 if (retval) {
91 VLOG_WARN_RL(&rl, "failed to %s /proc/%s/%s (%s)",
92 data ? "update" : "remove", dir, file, strerror(retval));
93 }
94 return retval;
95 }
96
97 static void
98 flush_dir(const char *dir)
99 {
100 const char *subdir;
101 struct dirent *de;
102 DIR *stream;
103
104 assert(!memcmp(dir, "/proc/", 6));
105 subdir = dir + 6;
106
107 stream = opendir(dir);
108 if (!stream) {
109 if (errno != ENOENT) {
110 VLOG_WARN_RL(&rl, "%s: open failed (%s)", dir, strerror(errno));
111 }
112 return;
113 }
114
115 while ((de = readdir(stream)) != NULL) {
116 if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) {
117 set_proc_file(subdir, de->d_name, NULL);
118 }
119 }
120 closedir(stream);
121 }
122 \f
123 /* If 'bond' is nonnull, creates a file in /proc/net/bonding for a bond with
124 * the given 'name' and the details in 'bond'. If 'bond' is null, deletes
125 * the /proc/net/bonding file with the given 'name'.
126 *
127 * This function has no effect unless proc_net_compat_init() has been
128 * called. */
129 void
130 proc_net_compat_update_bond(const char *name, const struct compat_bond *bond)
131 {
132 struct ds ds;
133 int i;
134
135 if (!brc_sock) {
136 return;
137 }
138
139 if (!bond) {
140 set_proc_file("net/bonding", name, NULL);
141 return;
142 }
143
144 ds_init(&ds);
145 ds_put_format(
146 &ds,
147 "Ethernet Channel Bonding Driver: ovs-vswitchd "
148 VERSION BUILDNR" ("__DATE__" "__TIME__")\n"
149 "Bonding Mode: source load balancing\n"
150 "Primary Slave: None\n"
151 "Currently Active Slave: None\n"
152 "MII Status: %s\n"
153 "MII Polling Interval (ms): 100\n"
154 "Up Delay (ms): %d\n"
155 "Down Delay (ms): %d\n"
156 "\n"
157 "Source load balancing info:\n",
158 bond->up ? "up" : "down", bond->updelay, bond->downdelay);
159 for (i = 0; i < bond->n_slaves; i++) {
160 const struct compat_bond_slave *slave = &bond->slaves[i];
161 ds_put_format(
162 &ds,
163 "\n"
164 "Slave Interface: %s\n"
165 "MII Status: %s\n"
166 "Link Failure Count: 0\n"
167 "Permanent HW addr: "ETH_ADDR_FMT"\n",
168 slave->name, slave->up ? "up" : "down",
169 ETH_ADDR_ARGS(slave->mac));
170 }
171 set_proc_file("net/bonding", name, ds_cstr(&ds));
172 ds_destroy(&ds);
173 }
174 \f
175 /* /proc/net/vlan compatibility.
176 *
177 * This is much more complex than I expected it to be. */
178
179 struct compat_vlan {
180 /* Hash key. */
181 struct hmap_node trunk_node; /* Hash map node. */
182 char *trunk_dev; /* Name of trunk network device. */
183 int vid; /* VLAN number. */
184
185 /* Auxiliary data. */
186 char *vlan_dev; /* sprintf("%s.%d", trunk_dev, vid); */
187 struct svec tagged_devs; /* Name of tagged network device(s). */
188 };
189
190 /* Current set of VLAN devices, indexed two different ways. */
191 static struct hmap vlans_by_trunk = HMAP_INITIALIZER(&vlans_by_trunk);
192 static struct shash vlans_by_tagged = SHASH_INITIALIZER(&vlans_by_tagged);
193
194 static bool remove_tagged_dev(struct shash_node *, const char *tagged_dev);
195 static void update_vlan_config(void);
196 static void set_vlan_proc_file(const struct compat_vlan *);
197 static uint32_t hash_vlan(const char *trunk_dev, uint32_t vid);
198
199 /* Updates the /proc/net/vlan compatibility layer's idea of what trunk device
200 * and VLAN the given 'tagged_dev' is associated with. If 'tagged_dev' has an
201 * implicit VLAN tag, then 'trunk_dev' should be the name of a network device
202 * on the same bridge that trunks that VLAN, and 'vid' should be the VLAN tag
203 * number. If 'tagged_dev' does not have an implicit VLAN tag, then
204 * 'trunk_dev' should be NULL and 'vid' should be -1.
205 *
206 * This function has no effect unless proc_net_compat_init() has been
207 * called. */
208 void
209 proc_net_compat_update_vlan(const char *tagged_dev, const char *trunk_dev,
210 int vid)
211 {
212 struct compat_vlan *vlan;
213 struct shash_node *node;
214
215 if (!brc_sock) {
216 return;
217 }
218
219 /* Find the compat_vlan that we currently have for 'tagged_dev' (if
220 * any). */
221 node = shash_find(&vlans_by_tagged, tagged_dev);
222 vlan = node ? node->data : NULL;
223 if (vid <= 0 || !trunk_dev) {
224 if (vlan) {
225 if (remove_tagged_dev(node, tagged_dev)) {
226 update_vlan_config();
227 }
228 }
229 } else {
230 if (vlan) {
231 if (!strcmp(trunk_dev, vlan->trunk_dev) && vid == vlan->vid) {
232 /* No change. */
233 return;
234 } else {
235 /* 'tagged_dev' is attached to the wrong compat_vlan. Start
236 * by removing it from that one. */
237 remove_tagged_dev(node, tagged_dev);
238 node = NULL;
239 vlan = NULL;
240 }
241 }
242
243 /* 'tagged_dev' is not attached to any compat_vlan. Find the
244 * compat_vlan corresponding to (trunk_dev,vid) to attach it to, or
245 * create a new compat_vlan if none exists for (trunk_dev,vid). */
246 HMAP_FOR_EACH_WITH_HASH (vlan, struct compat_vlan, trunk_node,
247 hash_vlan(trunk_dev, vid),
248 &vlans_by_trunk) {
249 if (!strcmp(trunk_dev, vlan->trunk_dev) && vid == vlan->vid) {
250 break;
251 }
252 }
253 if (!vlan) {
254 /* Create a new compat_vlan for (trunk_dev,vid). */
255 vlan = xcalloc(1, sizeof *vlan);
256 vlan->trunk_dev = xstrdup(trunk_dev);
257 vlan->vid = vid;
258 vlan->vlan_dev = xasprintf("%s.%d", trunk_dev, vid);
259 svec_init(&vlan->tagged_devs);
260 hmap_insert(&vlans_by_trunk, &vlan->trunk_node,
261 hash_vlan(trunk_dev, vid));
262 set_vlan_proc_file(vlan);
263 }
264
265 /* Attach 'tagged_dev' to 'vlan'. */
266 svec_add(&vlan->tagged_devs, tagged_dev);
267 shash_add(&vlans_by_tagged, tagged_dev, vlan);
268 svec_sort(&vlan->tagged_devs);
269 update_vlan_config();
270 }
271 }
272
273 /* Remove 'tagged_dev' from the compat_vlan in 'node'. If that causes the
274 * compat_vlan to have no tagged_devs left, destroy the compat_vlan too. */
275 static bool
276 remove_tagged_dev(struct shash_node *node, const char *tagged_dev)
277 {
278 struct compat_vlan *vlan = node->data;
279
280 svec_del(&vlan->tagged_devs, tagged_dev);
281 shash_delete(&vlans_by_tagged, node);
282 if (!vlan->tagged_devs.n) {
283 set_proc_file("net/vlan", vlan->vlan_dev, NULL);
284
285 hmap_remove(&vlans_by_trunk, &vlan->trunk_node);
286 svec_destroy(&vlan->tagged_devs);
287 free(vlan->trunk_dev);
288 free(vlan->vlan_dev);
289 free(vlan);
290 return true;
291 }
292 return false;
293 }
294
295 /* Returns a hash value for (trunk_dev,vid). */
296 static uint32_t
297 hash_vlan(const char *trunk_dev, uint32_t vid)
298 {
299 return hash_int(vid, hash_string(trunk_dev, 0));
300 }
301
302 /* Update /proc/net/vlan/<vlan_dev> for 'vlan'. */
303 static void
304 set_vlan_proc_file(const struct compat_vlan *vlan)
305 {
306 struct ds ds;
307
308 ds_init(&ds);
309 ds_put_format(
310 &ds,
311 "%s VID: %d\t REORDER_HDR: 1 dev->priv_flags: 81\n"
312 " total frames received 0\n"
313 " total bytes received 0\n"
314 " Broadcast/Multicast Rcvd 0\n"
315 "\n"
316 " total frames transmitted 0\n"
317 " total bytes transmitted 0\n"
318 " total headroom inc 0\n"
319 " total encap on xmit 0\n"
320 "Device: %s\n"
321 "INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0\n"
322 "EGRESSS priority Mappings: \n",
323 vlan->vlan_dev, vlan->vid, vlan->trunk_dev);
324 set_proc_file("net/vlan", vlan->vlan_dev, ds_cstr(&ds));
325 ds_destroy(&ds);
326 }
327
328 /* Update /proc/net/vlan/config. */
329 static void
330 update_vlan_config(void)
331 {
332 struct compat_vlan *vlan;
333 struct ds ds;
334
335 ds_init(&ds);
336 ds_put_cstr(&ds, "VLAN Dev name | VLAN ID\n"
337 "Name-Type: VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD\n");
338 HMAP_FOR_EACH (vlan, struct compat_vlan, trunk_node, &vlans_by_trunk) {
339 ds_put_format(&ds, "%-15s| %d | %s\n",
340 vlan->vlan_dev, vlan->vid, vlan->trunk_dev);
341 }
342 set_proc_file("net/vlan", "config", ds_cstr(&ds));
343 ds_destroy(&ds);
344 }