]>
git.proxmox.com Git - mirror_ovs.git/blob - vswitchd/proc-net-compat.c
1 /* Copyright (c) 2009 Nicira Networks
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 #include "proc-net-compat.h"
23 #include "dynamic-string.h"
25 #include "netlink-protocol.h"
28 #include "openvswitch/brcompat-netlink.h"
33 #define THIS_MODULE VLM_proc_net_compat
36 /* Netlink socket to bridge compatibility kernel module. */
37 static struct nl_sock
*brc_sock
;
39 /* The Generic Netlink family number used for bridge compatibility. */
40 static int brc_family
= 0;
42 /* Rate limiting for log messages. */
43 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 5);
45 static void flush_dir(const char *dir
);
46 static int set_proc_file(const char *dir
, const char *file
, const char *data
);
48 /* Initializes the /proc/net compatibility layer. Returns 0 if successful,
49 * otherwise a positive errno value. */
51 proc_net_compat_init(void)
54 int retval
= nl_lookup_genl_family(BRC_GENL_FAMILY_NAME
, &brc_family
);
59 retval
= nl_sock_create(NETLINK_GENERIC
, 0, 0, 0, &brc_sock
);
64 flush_dir("/proc/net/vlan");
65 flush_dir("/proc/net/bonding");
71 set_proc_file(const char *dir
, const char *file
, const char *data
)
73 struct ofpbuf request
, *reply
;
76 ofpbuf_init(&request
, 0);
77 nl_msg_put_genlmsghdr(&request
, brc_sock
, 1024, brc_family
, NLM_F_REQUEST
,
78 BRC_GENL_C_SET_PROC
, 1);
79 nl_msg_put_string(&request
, BRC_GENL_A_PROC_DIR
, dir
);
80 nl_msg_put_string(&request
, BRC_GENL_A_PROC_NAME
, file
);
82 nl_msg_put_string(&request
, BRC_GENL_A_PROC_DATA
, data
);
85 retval
= nl_sock_transact(brc_sock
, &request
, &reply
);
86 ofpbuf_uninit(&request
);
89 VLOG_WARN_RL(&rl
, "failed to %s /proc/%s/%s (%s)",
90 data
? "update" : "remove", dir
, file
, strerror(retval
));
96 flush_dir(const char *dir
)
102 assert(!memcmp(dir
, "/proc/", 6));
105 stream
= opendir(dir
);
107 if (errno
!= ENOENT
) {
108 VLOG_WARN_RL(&rl
, "%s: open failed (%s)", dir
, strerror(errno
));
113 while ((de
= readdir(stream
)) != NULL
) {
114 if (strcmp(de
->d_name
, ".") && strcmp(de
->d_name
, "..")) {
115 set_proc_file(subdir
, de
->d_name
, NULL
);
121 /* If 'bond' is nonnull, creates a file in /proc/net/bonding for a bond with
122 * the given 'name' and the details in 'bond'. If 'bond' is null, deletes
123 * the /proc/net/bonding file with the given 'name'.
125 * This function has no effect unless proc_net_compat_init() has been
128 proc_net_compat_update_bond(const char *name
, const struct compat_bond
*bond
)
138 set_proc_file("net/bonding", name
, NULL
);
145 "Ethernet Channel Bonding Driver: ovs-vswitchd "
146 VERSION BUILDNR
" ("__DATE__
" "__TIME__
")\n"
147 "Bonding Mode: source load balancing\n"
148 "Primary Slave: None\n"
149 "Currently Active Slave: None\n"
151 "MII Polling Interval (ms): 100\n"
152 "Up Delay (ms): %d\n"
153 "Down Delay (ms): %d\n"
155 "Source load balancing info:\n",
156 bond
->up
? "up" : "down", bond
->updelay
, bond
->downdelay
);
157 for (i
= 0; i
< bond
->n_slaves
; i
++) {
158 const struct compat_bond_slave
*slave
= &bond
->slaves
[i
];
162 "Slave Interface: %s\n"
164 "Link Failure Count: 0\n"
165 "Permanent HW addr: "ETH_ADDR_FMT
"\n",
166 slave
->name
, slave
->up
? "up" : "down",
167 ETH_ADDR_ARGS(slave
->mac
));
169 set_proc_file("net/bonding", name
, ds_cstr(&ds
));
173 /* /proc/net/vlan compatibility.
175 * This is much more complex than I expected it to be. */
179 struct hmap_node trunk_node
; /* Hash map node. */
180 char *trunk_dev
; /* Name of trunk network device. */
181 int vid
; /* VLAN number. */
183 /* Auxiliary data. */
184 char *vlan_dev
; /* sprintf("%s.%d", trunk_dev, vid); */
185 struct svec tagged_devs
; /* Name of tagged network device(s). */
188 /* Current set of VLAN devices, indexed two different ways. */
189 static struct hmap vlans_by_trunk
= HMAP_INITIALIZER(&vlans_by_trunk
);
190 static struct shash vlans_by_tagged
= SHASH_INITIALIZER(&vlans_by_tagged
);
192 static bool remove_tagged_dev(struct shash_node
*, const char *tagged_dev
);
193 static void update_vlan_config(void);
194 static void set_vlan_proc_file(const struct compat_vlan
*);
195 static uint32_t hash_vlan(const char *trunk_dev
, uint32_t vid
);
197 /* Updates the /proc/net/vlan compatibility layer's idea of what trunk device
198 * and VLAN the given 'tagged_dev' is associated with. If 'tagged_dev' has an
199 * implicit VLAN tag, then 'trunk_dev' should be the name of a network device
200 * on the same bridge that trunks that VLAN, and 'vid' should be the VLAN tag
201 * number. If 'tagged_dev' does not have an implicit VLAN tag, then
202 * 'trunk_dev' should be NULL and 'vid' should be -1.
204 * This function has no effect unless proc_net_compat_init() has been
207 proc_net_compat_update_vlan(const char *tagged_dev
, const char *trunk_dev
,
210 struct compat_vlan
*vlan
;
211 struct shash_node
*node
;
217 /* Find the compat_vlan that we currently have for 'tagged_dev' (if
219 node
= shash_find(&vlans_by_tagged
, tagged_dev
);
220 vlan
= node
? node
->data
: NULL
;
221 if (vid
<= 0 || !trunk_dev
) {
223 if (remove_tagged_dev(node
, tagged_dev
)) {
224 update_vlan_config();
229 if (!strcmp(trunk_dev
, vlan
->trunk_dev
) && vid
== vlan
->vid
) {
233 /* 'tagged_dev' is attached to the wrong compat_vlan. Start
234 * by removing it from that one. */
235 remove_tagged_dev(node
, tagged_dev
);
241 /* 'tagged_dev' is not attached to any compat_vlan. Find the
242 * compat_vlan corresponding to (trunk_dev,vid) to attach it to, or
243 * create a new compat_vlan if none exists for (trunk_dev,vid). */
244 HMAP_FOR_EACH_WITH_HASH (vlan
, struct compat_vlan
, trunk_node
,
245 hash_vlan(trunk_dev
, vid
),
247 if (!strcmp(trunk_dev
, vlan
->trunk_dev
) && vid
== vlan
->vid
) {
252 /* Create a new compat_vlan for (trunk_dev,vid). */
253 vlan
= xcalloc(1, sizeof *vlan
);
254 vlan
->trunk_dev
= xstrdup(trunk_dev
);
256 vlan
->vlan_dev
= xasprintf("%s.%d", trunk_dev
, vid
);
257 svec_init(&vlan
->tagged_devs
);
258 hmap_insert(&vlans_by_trunk
, &vlan
->trunk_node
,
259 hash_vlan(trunk_dev
, vid
));
260 set_vlan_proc_file(vlan
);
263 /* Attach 'tagged_dev' to 'vlan'. */
264 svec_add(&vlan
->tagged_devs
, tagged_dev
);
265 shash_add(&vlans_by_tagged
, tagged_dev
, vlan
);
266 svec_sort(&vlan
->tagged_devs
);
267 update_vlan_config();
271 /* Remove 'tagged_dev' from the compat_vlan in 'node'. If that causes the
272 * compat_vlan to have no tagged_devs left, destroy the compat_vlan too. */
274 remove_tagged_dev(struct shash_node
*node
, const char *tagged_dev
)
276 struct compat_vlan
*vlan
= node
->data
;
278 svec_del(&vlan
->tagged_devs
, tagged_dev
);
279 shash_delete(&vlans_by_tagged
, node
);
280 if (!vlan
->tagged_devs
.n
) {
281 set_proc_file("net/vlan", vlan
->vlan_dev
, NULL
);
283 hmap_remove(&vlans_by_trunk
, &vlan
->trunk_node
);
284 svec_destroy(&vlan
->tagged_devs
);
285 free(vlan
->trunk_dev
);
286 free(vlan
->vlan_dev
);
293 /* Returns a hash value for (trunk_dev,vid). */
295 hash_vlan(const char *trunk_dev
, uint32_t vid
)
297 return hash_int(vid
, hash_string(trunk_dev
, 0));
300 /* Update /proc/net/vlan/<vlan_dev> for 'vlan'. */
302 set_vlan_proc_file(const struct compat_vlan
*vlan
)
309 "%s VID: %d\t REORDER_HDR: 1 dev->priv_flags: 81\n"
310 " total frames received 0\n"
311 " total bytes received 0\n"
312 " Broadcast/Multicast Rcvd 0\n"
314 " total frames transmitted 0\n"
315 " total bytes transmitted 0\n"
316 " total headroom inc 0\n"
317 " total encap on xmit 0\n"
319 "INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0\n"
320 "EGRESSS priority Mappings: \n",
321 vlan
->vlan_dev
, vlan
->vid
, vlan
->trunk_dev
);
322 set_proc_file("net/vlan", vlan
->vlan_dev
, ds_cstr(&ds
));
326 /* Update /proc/net/vlan/config. */
328 update_vlan_config(void)
330 struct compat_vlan
*vlan
;
334 ds_put_cstr(&ds
, "VLAN Dev name | VLAN ID\n"
335 "Name-Type: VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD\n");
336 HMAP_FOR_EACH (vlan
, struct compat_vlan
, trunk_node
, &vlans_by_trunk
) {
337 ds_put_format(&ds
, "%-15s| %d | %s\n",
338 vlan
->vlan_dev
, vlan
->vid
, vlan
->trunk_dev
);
340 set_proc_file("net/vlan", "config", ds_cstr(&ds
));