]> git.proxmox.com Git - mirror_ovs.git/blame - vswitchd/ovs-brcompatd.c
ovs-brcompatd: Fix sending replies to kernel requests.
[mirror_ovs.git] / vswitchd / ovs-brcompatd.c
CommitLineData
e0edde6f 1/* Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
064af421 2 *
a14bc59f
BP
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:
064af421 6 *
a14bc59f 7 * http://www.apache.org/licenses/LICENSE-2.0
064af421 8 *
a14bc59f
BP
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.
064af421
BP
14 */
15
16#include <config.h>
17
3c303e5f 18#include <asm/param.h>
064af421
BP
19#include <assert.h>
20#include <errno.h>
21#include <getopt.h>
22#include <inttypes.h>
23#include <limits.h>
24#include <net/if.h>
25#include <linux/genetlink.h>
26#include <linux/rtnetlink.h>
27#include <signal.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/types.h>
5b44dc99 31#include <sys/wait.h>
064af421 32#include <sys/stat.h>
3c303e5f 33#include <time.h>
064af421
BP
34#include <fcntl.h>
35#include <unistd.h>
36
064af421
BP
37#include "command-line.h"
38#include "coverage.h"
39#include "daemon.h"
40#include "dirs.h"
3c303e5f 41#include "dynamic-string.h"
064af421 42#include "fatal-signal.h"
1e86ae6f 43#include "json.h"
064af421
BP
44#include "leak-checker.h"
45#include "netdev.h"
46#include "netlink.h"
45c8d3a1 47#include "netlink-notifier.h"
2fe27d5a 48#include "netlink-socket.h"
064af421
BP
49#include "ofpbuf.h"
50#include "openvswitch/brcompat-netlink.h"
3c303e5f 51#include "packets.h"
064af421
BP
52#include "poll-loop.h"
53#include "process.h"
5326a0fd 54#include "rtnetlink-link.h"
064af421 55#include "signals.h"
96ca8c29 56#include "sset.h"
2b01925c 57#include "svec.h"
064af421
BP
58#include "timeval.h"
59#include "unixctl.h"
60#include "util.h"
5136ce49 61#include "vlog.h"
064af421 62
d98e6007 63VLOG_DEFINE_THIS_MODULE(brcompatd);
064af421 64
064af421
BP
65/* xxx Just hangs if datapath is rmmod/insmod. Learn to reconnect? */
66
2b01925c 67static void parse_options(int argc, char *argv[]);
064af421
BP
68static void usage(void) NO_RETURN;
69
70static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 60);
71
2b01925c
BP
72/* --appctl: Absolute path to ovs-appctl. */
73static char *appctl_program;
74
75/* --vsctl: Absolute path to ovs-vsctl. */
76static char *vsctl_program;
77
78/* Options that we should generally pass to ovs-vsctl. */
ea523221 79#define VSCTL_OPTIONS "--timeout=5", "-vconsole:warn"
064af421 80
064af421
BP
81/* Netlink socket to bridge compatibility kernel module. */
82static struct nl_sock *brc_sock;
83
84/* The Generic Netlink family number used for bridge compatibility. */
85static int brc_family;
86
87static const struct nl_policy brc_multicast_policy[] = {
88 [BRC_GENL_A_MC_GROUP] = {.type = NL_A_U32 }
89};
90
2b01925c
BP
91static char *
92capture_vsctl_valist(const char *arg0, va_list args)
93{
94 char *stdout_log, *stderr_log;
95 enum vlog_level log_level;
96 struct svec argv;
97 int status;
98 char *msg;
99
100 /* Compose arguments. */
101 svec_init(&argv);
102 svec_add(&argv, arg0);
103 for (;;) {
104 const char *arg = va_arg(args, const char *);
105 if (!arg) {
106 break;
107 }
108 svec_add(&argv, arg);
109 }
110 svec_terminate(&argv);
111
112 /* Run process. */
113 if (process_run_capture(argv.names, &stdout_log, &stderr_log, SIZE_MAX,
114 &status)) {
115 svec_destroy(&argv);
116 return NULL;
117 }
118
119 /* Log results. */
120 if (WIFEXITED(status)) {
121 int code = WEXITSTATUS(status);
122 log_level = code == 0 ? VLL_DBG : code == 1 ? VLL_WARN : VLL_ERR;
123 } else {
124 log_level = VLL_ERR;
125 }
126 msg = process_status_msg(status);
127 VLOG(log_level, "ovs-vsctl exited (%s)", msg);
128 if (stdout_log && *stdout_log) {
129 VLOG(log_level, "ovs-vsctl wrote to stdout:\n%s\n", stdout_log);
130 }
131 if (stderr_log && *stderr_log) {
132 VLOG(log_level, "ovs-vsctl wrote to stderr:\n%s\n", stderr_log);
133 }
134 free(msg);
135
136 svec_destroy(&argv);
137
138 free(stderr_log);
139 if (WIFEXITED(status) && !WEXITSTATUS(status)) {
140 return stdout_log;
141 } else {
142 free(stdout_log);
143 return NULL;
144 }
145}
146
147static char * SENTINEL(0)
148capture_vsctl(const char *arg0, ...)
149{
150 char *stdout_log;
151 va_list args;
152
153 va_start(args, arg0);
154 stdout_log = capture_vsctl_valist(arg0, args);
155 va_end(args);
156
157 return stdout_log;
158}
159
160static bool SENTINEL(0)
161run_vsctl(const char *arg0, ...)
162{
163 char *stdout_log;
164 va_list args;
165 bool ok;
166
167 va_start(args, arg0);
168 stdout_log = capture_vsctl_valist(arg0, args);
169 va_end(args);
170
171 ok = stdout_log != NULL;
172 free(stdout_log);
173 return ok;
174}
175
064af421
BP
176static int
177lookup_brc_multicast_group(int *multicast_group)
178{
179 struct nl_sock *sock;
180 struct ofpbuf request, *reply;
181 struct nlattr *attrs[ARRAY_SIZE(brc_multicast_policy)];
182 int retval;
183
cceb11f5 184 retval = nl_sock_create(NETLINK_GENERIC, &sock);
064af421
BP
185 if (retval) {
186 return retval;
187 }
188 ofpbuf_init(&request, 0);
69123704 189 nl_msg_put_genlmsghdr(&request, 0, brc_family,
064af421
BP
190 NLM_F_REQUEST, BRC_GENL_C_QUERY_MC, 1);
191 retval = nl_sock_transact(sock, &request, &reply);
192 ofpbuf_uninit(&request);
193 if (retval) {
194 nl_sock_destroy(sock);
195 return retval;
196 }
197 if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN,
198 brc_multicast_policy, attrs,
199 ARRAY_SIZE(brc_multicast_policy))) {
200 nl_sock_destroy(sock);
201 ofpbuf_delete(reply);
202 return EPROTO;
203 }
204 *multicast_group = nl_attr_get_u32(attrs[BRC_GENL_A_MC_GROUP]);
205 nl_sock_destroy(sock);
206 ofpbuf_delete(reply);
207
208 return 0;
209}
210
211/* Opens a socket for brcompat notifications. Returns 0 if successful,
212 * otherwise a positive errno value. */
213static int
214brc_open(struct nl_sock **sock)
215{
216 int multicast_group = 0;
217 int retval;
218
219 retval = nl_lookup_genl_family(BRC_GENL_FAMILY_NAME, &brc_family);
220 if (retval) {
221 return retval;
222 }
223
224 retval = lookup_brc_multicast_group(&multicast_group);
225 if (retval) {
226 return retval;
227 }
228
cceb11f5 229 retval = nl_sock_create(NETLINK_GENERIC, sock);
064af421
BP
230 if (retval) {
231 return retval;
232 }
233
cceb11f5
BP
234 retval = nl_sock_join_mcgroup(*sock, multicast_group);
235 if (retval) {
236 nl_sock_destroy(*sock);
237 *sock = NULL;
238 }
239 return retval;
064af421
BP
240}
241
242static const struct nl_policy brc_dp_policy[] = {
243 [BRC_GENL_A_DP_NAME] = { .type = NL_A_STRING },
244};
245
064af421
BP
246static int
247parse_command(struct ofpbuf *buffer, uint32_t *seq, const char **br_name,
3c303e5f 248 const char **port_name, uint64_t *count, uint64_t *skip)
064af421
BP
249{
250 static const struct nl_policy policy[] = {
7f42c1d7 251 [BRC_GENL_A_DP_NAME] = { .type = NL_A_STRING, .optional = true },
064af421 252 [BRC_GENL_A_PORT_NAME] = { .type = NL_A_STRING, .optional = true },
3c303e5f
BP
253 [BRC_GENL_A_FDB_COUNT] = { .type = NL_A_U64, .optional = true },
254 [BRC_GENL_A_FDB_SKIP] = { .type = NL_A_U64, .optional = true },
064af421
BP
255 };
256 struct nlattr *attrs[ARRAY_SIZE(policy)];
257
258 if (!nl_policy_parse(buffer, NLMSG_HDRLEN + GENL_HDRLEN, policy,
259 attrs, ARRAY_SIZE(policy))
7f42c1d7 260 || (br_name && !attrs[BRC_GENL_A_DP_NAME])
3c303e5f
BP
261 || (port_name && !attrs[BRC_GENL_A_PORT_NAME])
262 || (count && !attrs[BRC_GENL_A_FDB_COUNT])
263 || (skip && !attrs[BRC_GENL_A_FDB_SKIP])) {
064af421
BP
264 return EINVAL;
265 }
266
267 *seq = ((struct nlmsghdr *) buffer->data)->nlmsg_seq;
7f42c1d7
BP
268 if (br_name) {
269 *br_name = nl_attr_get_string(attrs[BRC_GENL_A_DP_NAME]);
270 }
064af421
BP
271 if (port_name) {
272 *port_name = nl_attr_get_string(attrs[BRC_GENL_A_PORT_NAME]);
273 }
3c303e5f
BP
274 if (count) {
275 *count = nl_attr_get_u64(attrs[BRC_GENL_A_FDB_COUNT]);
276 }
277 if (skip) {
278 *skip = nl_attr_get_u64(attrs[BRC_GENL_A_FDB_SKIP]);
279 }
064af421
BP
280 return 0;
281}
282
ff459dd6
BP
283/* Composes and returns a reply to a request made by the datapath with error
284 * code 'error'. The caller may add additional attributes to the message, then
285 * it may send it with send_reply(). */
41e754bc 286static struct ofpbuf *
ff459dd6 287compose_reply(int error)
064af421 288{
41e754bc 289 struct ofpbuf *reply = ofpbuf_new(4096);
69123704 290 nl_msg_put_genlmsghdr(reply, 32, brc_family, NLM_F_REQUEST,
064af421 291 BRC_GENL_C_DP_RESULT, 1);
41e754bc
BP
292 nl_msg_put_u32(reply, BRC_GENL_A_ERR_CODE, error);
293 return reply;
294}
064af421 295
ff459dd6
BP
296/* Sends 'reply' to the datapath, using sequence number 'nlmsg_seq', and frees
297 * it. */
41e754bc 298static void
ff459dd6 299send_reply(struct ofpbuf *reply, uint32_t nlmsg_seq)
41e754bc 300{
ff459dd6 301 int retval = nl_sock_send_seq(brc_sock, reply, nlmsg_seq, false);
064af421
BP
302 if (retval) {
303 VLOG_WARN_RL(&rl, "replying to brcompat request: %s",
304 strerror(retval));
305 }
41e754bc
BP
306 ofpbuf_delete(reply);
307}
308
309/* Composes and sends a reply to a request made by the datapath with Netlink
310 * sequence number 'seq' and error code 'error'. */
311static void
312send_simple_reply(uint32_t seq, int error)
313{
ff459dd6 314 send_reply(compose_reply(error), seq);
064af421
BP
315}
316
317static int
2b01925c 318handle_bridge_cmd(struct ofpbuf *buffer, bool add)
064af421
BP
319{
320 const char *br_name;
321 uint32_t seq;
322 int error;
323
3c303e5f 324 error = parse_command(buffer, &seq, &br_name, NULL, NULL, NULL);
064af421 325 if (!error) {
2b01925c
BP
326 const char *vsctl_cmd = add ? "add-br" : "del-br";
327 const char *brctl_cmd = add ? "addbr" : "delbr";
328 if (!run_vsctl(vsctl_program, VSCTL_OPTIONS,
329 "--", vsctl_cmd, br_name,
330 "--", "comment", "ovs-brcompatd:", brctl_cmd, br_name,
331 (char *) NULL)) {
332 error = add ? EEXIST : ENXIO;
333 }
41e754bc 334 send_simple_reply(seq, error);
064af421
BP
335 }
336 return error;
337}
338
339static const struct nl_policy brc_port_policy[] = {
340 [BRC_GENL_A_DP_NAME] = { .type = NL_A_STRING },
341 [BRC_GENL_A_PORT_NAME] = { .type = NL_A_STRING },
342};
343
064af421 344static int
2b01925c 345handle_port_cmd(struct ofpbuf *buffer, bool add)
064af421 346{
064af421
BP
347 const char *br_name, *port_name;
348 uint32_t seq;
349 int error;
350
3c303e5f 351 error = parse_command(buffer, &seq, &br_name, &port_name, NULL, NULL);
064af421 352 if (!error) {
2b01925c
BP
353 const char *vsctl_cmd = add ? "add-port" : "del-port";
354 const char *brctl_cmd = add ? "addif" : "delif";
355 if (!run_vsctl(vsctl_program, VSCTL_OPTIONS,
356 "--", vsctl_cmd, br_name, port_name,
357 "--", "comment", "ovs-brcompatd:", brctl_cmd,
358 br_name, port_name, (char *) NULL)) {
064af421 359 error = EINVAL;
064af421 360 }
41e754bc 361 send_simple_reply(seq, error);
064af421 362 }
064af421
BP
363 return error;
364}
365
2b01925c 366static char *
9cb8877c 367linux_bridge_to_ovs_bridge(const char *linux_name, int *br_vlanp)
ae1281cf 368{
2b01925c 369 char *save_ptr = NULL;
9cb8877c 370 const char *br_name, *br_vlan;
2b01925c
BP
371 char *br_name_copy;
372 char *output;
ae1281cf 373
9cb8877c
BP
374 output = capture_vsctl(vsctl_program, VSCTL_OPTIONS,
375 "--", "br-to-parent", linux_name,
376 "--", "br-to-vlan", linux_name,
377 (char *) NULL);
2b01925c
BP
378 if (!output) {
379 return NULL;
380 }
381
382 br_name = strtok_r(output, " \t\r\n", &save_ptr);
9cb8877c
BP
383 br_vlan = strtok_r(NULL, " \t\r\n", &save_ptr);
384 if (!br_name || !br_vlan) {
2b01925c
BP
385 free(output);
386 return NULL;
387 }
388 br_name_copy = xstrdup(br_name);
9cb8877c 389 *br_vlanp = atoi(br_vlan);
2b01925c
BP
390
391 free(output);
392
393 return br_name_copy;
394}
395
396static void
397get_bridge_ifaces(const char *br_name, struct sset *ifaces)
398{
399 char *save_ptr = NULL;
400 char *output;
401 char *iface;
402
403 output = capture_vsctl(vsctl_program, VSCTL_OPTIONS, "list-ifaces",
404 br_name, (char *) NULL);
405 if (!output) {
406 return;
407 }
408
409 for (iface = strtok_r(output, " \t\r\n", &save_ptr); iface;
410 iface = strtok_r(NULL, " \t\r\n", &save_ptr)) {
411 sset_add(ifaces, iface);
ae1281cf 412 }
2b01925c 413 free(output);
ae1281cf
BP
414}
415
3c303e5f 416static int
2b01925c 417handle_fdb_query_cmd(struct ofpbuf *buffer)
3c303e5f
BP
418{
419 /* This structure is copied directly from the Linux 2.6.30 header files.
420 * It would be more straightforward to #include <linux/if_bridge.h>, but
421 * the 'port_hi' member was only introduced in Linux 2.6.26 and so systems
422 * with old header files won't have it. */
423 struct __fdb_entry {
424 __u8 mac_addr[6];
425 __u8 port_no;
426 __u8 is_local;
427 __u32 ageing_timer_value;
428 __u8 port_hi;
429 __u8 pad0;
430 __u16 unused;
431 };
432
433 struct mac {
434 uint8_t addr[6];
435 };
436 struct mac *local_macs;
437 int n_local_macs;
438 int i;
439
c735214e
BP
440 /* Impedance matching between the vswitchd and Linux kernel notions of what
441 * a bridge is. The kernel only handles a single VLAN per bridge, but
442 * vswitchd can deal with all the VLANs on a single bridge. We have to
443 * pretend that the former is the case even though the latter is the
444 * implementation. */
9852694f 445 const char *linux_name; /* Name used by brctl. */
c735214e 446 int br_vlan; /* VLAN tag. */
96ca8c29 447 struct sset ifaces;
c735214e 448
3c303e5f 449 struct ofpbuf query_data;
96ca8c29 450 const char *iface_name;
41e754bc 451 struct ofpbuf *reply;
3c303e5f 452 uint64_t count, skip;
2b01925c 453 char *br_name;
3c303e5f
BP
454 char *output;
455 char *save_ptr;
456 uint32_t seq;
457 int error;
458
9b80f761 459 /* Parse the command received from brcompat. */
9852694f 460 error = parse_command(buffer, &seq, &linux_name, NULL, &count, &skip);
3c303e5f
BP
461 if (error) {
462 return error;
463 }
464
c735214e 465 /* Figure out vswitchd bridge and VLAN. */
9cb8877c 466 br_name = linux_bridge_to_ovs_bridge(linux_name, &br_vlan);
2b01925c
BP
467 if (!br_name) {
468 error = EINVAL;
ae1281cf
BP
469 send_simple_reply(seq, error);
470 return error;
c735214e
BP
471 }
472
3c303e5f 473 /* Fetch the forwarding database using ovs-appctl. */
2b01925c
BP
474 output = capture_vsctl(appctl_program, "fdb/show", br_name,
475 (char *) NULL);
476 if (!output) {
477 error = ECHILD;
41e754bc 478 send_simple_reply(seq, error);
3c303e5f
BP
479 return error;
480 }
481
482 /* Fetch the MAC address for each interface on the bridge, so that we can
483 * fill in the is_local field in the response. */
96ca8c29 484 sset_init(&ifaces);
2b01925c 485 get_bridge_ifaces(linux_name, &ifaces);
96ca8c29 486 local_macs = xmalloc(sset_count(&ifaces) * sizeof *local_macs);
3c303e5f 487 n_local_macs = 0;
96ca8c29 488 SSET_FOR_EACH (iface_name, &ifaces) {
3c303e5f 489 struct mac *mac = &local_macs[n_local_macs];
07c318f4
BP
490 struct netdev *netdev;
491
18812dff 492 error = netdev_open(iface_name, "system", &netdev);
4869f1b1 493 if (!error) {
07c318f4
BP
494 if (!netdev_get_etheraddr(netdev, mac->addr)) {
495 n_local_macs++;
496 }
497 netdev_close(netdev);
3c303e5f
BP
498 }
499 }
96ca8c29 500 sset_destroy(&ifaces);
3c303e5f
BP
501
502 /* Parse the response from ovs-appctl and convert it to binary format to
503 * pass back to the kernel. */
504 ofpbuf_init(&query_data, sizeof(struct __fdb_entry) * 8);
505 save_ptr = NULL;
506 strtok_r(output, "\n", &save_ptr); /* Skip header line. */
507 while (count > 0) {
508 struct __fdb_entry *entry;
509 int port, vlan, age;
510 uint8_t mac[ETH_ADDR_LEN];
511 char *line;
512 bool is_local;
513
514 line = strtok_r(NULL, "\n", &save_ptr);
515 if (!line) {
516 break;
517 }
518
519 if (sscanf(line, "%d %d "ETH_ADDR_SCAN_FMT" %d",
520 &port, &vlan, ETH_ADDR_SCAN_ARGS(mac), &age)
521 != 2 + ETH_ADDR_SCAN_COUNT + 1) {
db5ce514 522 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
3c303e5f
BP
523 VLOG_INFO_RL(&rl, "fdb/show output has invalid format: %s", line);
524 continue;
525 }
526
c735214e
BP
527 if (vlan != br_vlan) {
528 continue;
529 }
530
3c303e5f
BP
531 if (skip > 0) {
532 skip--;
533 continue;
534 }
535
536 /* Is this the MAC address of an interface on the bridge? */
537 is_local = false;
538 for (i = 0; i < n_local_macs; i++) {
539 if (eth_addr_equals(local_macs[i].addr, mac)) {
540 is_local = true;
541 break;
542 }
543 }
544
545 entry = ofpbuf_put_uninit(&query_data, sizeof *entry);
546 memcpy(entry->mac_addr, mac, ETH_ADDR_LEN);
547 entry->port_no = port & 0xff;
548 entry->is_local = is_local;
549 entry->ageing_timer_value = age * HZ;
550 entry->port_hi = (port & 0xff00) >> 8;
551 entry->pad0 = 0;
552 entry->unused = 0;
553 count--;
554 }
555 free(output);
556
41e754bc 557 /* Compose and send reply to datapath. */
ff459dd6 558 reply = compose_reply(0);
41e754bc
BP
559 nl_msg_put_unspec(reply, BRC_GENL_A_FDB_DATA,
560 query_data.data, query_data.size);
ff459dd6 561 send_reply(reply, seq);
41e754bc
BP
562
563 /* Free memory. */
3c303e5f 564 ofpbuf_uninit(&query_data);
05edc34c 565 free(local_macs);
3c303e5f
BP
566
567 return 0;
568}
569
db322751 570static void
2b01925c 571send_ifindex_reply(uint32_t seq, char *output)
db322751 572{
2b01925c
BP
573 size_t allocated_indices;
574 char *save_ptr = NULL;
db322751
BP
575 struct ofpbuf *reply;
576 const char *iface;
577 size_t n_indices;
578 int *indices;
db322751 579
2b01925c
BP
580 indices = NULL;
581 n_indices = allocated_indices = 0;
582 for (iface = strtok_r(output, " \t\r\n", &save_ptr); iface;
583 iface = strtok_r(NULL, " \t\r\n", &save_ptr)) {
584 int ifindex;
585
586 if (n_indices >= allocated_indices) {
587 indices = x2nrealloc(indices, &allocated_indices, sizeof *indices);
588 }
589
590 ifindex = if_nametoindex(iface);
db322751
BP
591 if (ifindex) {
592 indices[n_indices++] = ifindex;
593 }
594 }
595
596 /* Compose and send reply. */
ff459dd6 597 reply = compose_reply(0);
db322751
BP
598 nl_msg_put_unspec(reply, BRC_GENL_A_IFINDEXES,
599 indices, n_indices * sizeof *indices);
ff459dd6 600 send_reply(reply, seq);
db322751
BP
601
602 /* Free memory. */
603 free(indices);
604}
605
606static int
2b01925c 607handle_get_bridges_cmd(struct ofpbuf *buffer)
db322751 608{
2b01925c 609 char *output;
db322751 610 uint32_t seq;
db322751
BP
611 int error;
612
613 /* Parse Netlink command.
614 *
615 * The command doesn't actually have any arguments, but we need the
616 * sequence number to send the reply. */
617 error = parse_command(buffer, &seq, NULL, NULL, NULL, NULL);
618 if (error) {
619 return error;
620 }
621
2b01925c
BP
622 output = capture_vsctl(vsctl_program, VSCTL_OPTIONS, "list-br", (char *) NULL);
623 if (!output) {
624 return ENODEV;
db322751
BP
625 }
626
2b01925c
BP
627 send_ifindex_reply(seq, output);
628 free(output);
db322751
BP
629 return 0;
630}
631
632static int
2b01925c 633handle_get_ports_cmd(struct ofpbuf *buffer)
db322751 634{
9852694f 635 const char *linux_name;
2b01925c
BP
636 uint32_t seq;
637 char *output;
db322751
BP
638 int error;
639
640 /* Parse Netlink command. */
9852694f 641 error = parse_command(buffer, &seq, &linux_name, NULL, NULL, NULL);
db322751
BP
642 if (error) {
643 return error;
644 }
645
2b01925c
BP
646 output = capture_vsctl(vsctl_program, VSCTL_OPTIONS, "list-ports", linux_name,
647 (char *) NULL);
648 if (!output) {
649 return ENODEV;
db322751
BP
650 }
651
2b01925c
BP
652 send_ifindex_reply(seq, output);
653 free(output);
db322751
BP
654 return 0;
655}
656
72d32ac0
BP
657static bool
658brc_recv_update__(struct ofpbuf *buffer)
1cec7ca1
BP
659{
660 for (;;) {
72d32ac0 661 int retval = nl_sock_recv(brc_sock, buffer, false);
1cec7ca1
BP
662 switch (retval) {
663 case 0:
664 if (nl_msg_nlmsgerr(buffer, NULL)
665 || nl_msg_nlmsghdr(buffer)->nlmsg_type == NLMSG_DONE) {
666 break;
667 }
72d32ac0 668 return true;
1cec7ca1
BP
669
670 case ENOBUFS:
671 break;
672
673 case EAGAIN:
72d32ac0 674 return false;
1cec7ca1
BP
675
676 default:
677 VLOG_WARN_RL(&rl, "brc_recv_update: %s", strerror(retval));
72d32ac0 678 return false;
1cec7ca1 679 }
1cec7ca1
BP
680 }
681}
682
9852694f 683static void
2b01925c 684brc_recv_update(void)
064af421 685{
064af421 686 struct genlmsghdr *genlmsghdr;
72d32ac0
BP
687 uint64_t buffer_stub[1024 / 8];
688 struct ofpbuf buffer;
064af421 689
72d32ac0
BP
690 ofpbuf_use_stub(&buffer, buffer_stub, sizeof buffer_stub);
691 if (!brc_recv_update__(&buffer)) {
692 goto error;
064af421
BP
693 }
694
72d32ac0 695 genlmsghdr = nl_msg_genlmsghdr(&buffer);
064af421
BP
696 if (!genlmsghdr) {
697 VLOG_WARN_RL(&rl, "received packet too short for generic NetLink");
698 goto error;
699 }
700
72d32ac0 701 if (nl_msg_nlmsghdr(&buffer)->nlmsg_type != brc_family) {
064af421 702 VLOG_DBG_RL(&rl, "received type (%"PRIu16") != brcompat family (%d)",
72d32ac0 703 nl_msg_nlmsghdr(&buffer)->nlmsg_type, brc_family);
064af421
BP
704 goto error;
705 }
706
e1f406a3
BP
707 /* Service all pending network device notifications before executing the
708 * command. This is very important to avoid a race in a scenario like the
709 * following, which is what happens with XenServer Tools version 5.0.0
710 * during boot of a Windows VM:
711 *
712 * 1. Create tap1.0 and vif1.0.
713 * 2. Delete tap1.0.
714 * 3. Delete vif1.0.
715 * 4. Re-create vif1.0.
716 *
717 * We must process the network device notification from step 3 before we
718 * process the brctl command from step 4. If we process them in the
719 * reverse order, then step 4 completes as a no-op but step 3 then deletes
720 * the port that was just added.
721 *
722 * (XenServer Tools 5.5.0 does not exhibit this behavior, and neither does
723 * a VM without Tools installed at all.)
724 */
18a23781 725 rtnetlink_link_run();
e1f406a3 726
064af421
BP
727 switch (genlmsghdr->cmd) {
728 case BRC_GENL_C_DP_ADD:
72d32ac0 729 handle_bridge_cmd(&buffer, true);
064af421
BP
730 break;
731
732 case BRC_GENL_C_DP_DEL:
72d32ac0 733 handle_bridge_cmd(&buffer, false);
064af421
BP
734 break;
735
736 case BRC_GENL_C_PORT_ADD:
72d32ac0 737 handle_port_cmd(&buffer, true);
064af421
BP
738 break;
739
740 case BRC_GENL_C_PORT_DEL:
72d32ac0 741 handle_port_cmd(&buffer, false);
064af421
BP
742 break;
743
3c303e5f 744 case BRC_GENL_C_FDB_QUERY:
72d32ac0 745 handle_fdb_query_cmd(&buffer);
3c303e5f
BP
746 break;
747
db322751 748 case BRC_GENL_C_GET_BRIDGES:
72d32ac0 749 handle_get_bridges_cmd(&buffer);
db322751
BP
750 break;
751
752 case BRC_GENL_C_GET_PORTS:
72d32ac0 753 handle_get_ports_cmd(&buffer);
db322751
BP
754 break;
755
064af421 756 default:
9852694f 757 VLOG_WARN_RL(&rl, "received unknown brc netlink command: %d\n",
1e86ae6f 758 genlmsghdr->cmd);
9852694f 759 break;
064af421
BP
760 }
761
064af421 762error:
72d32ac0 763 ofpbuf_uninit(&buffer);
064af421
BP
764}
765
064af421 766static void
2b01925c
BP
767netdev_changed_cb(const struct rtnetlink_link_change *change,
768 void *aux OVS_UNUSED)
064af421 769{
5326a0fd
BP
770 char br_name[IFNAMSIZ];
771 const char *port_name;
064af421 772
5326a0fd 773 if (!change) {
064af421 774 VLOG_WARN_RL(&rl, "network monitor socket overflowed");
5326a0fd
BP
775 return;
776 }
d295e8e9 777
5326a0fd
BP
778 if (change->nlmsg_type != RTM_DELLINK || !change->master_ifindex) {
779 return;
780 }
064af421 781
5326a0fd
BP
782 port_name = change->ifname;
783 if (!if_indextoname(change->master_ifindex, br_name)) {
784 return;
785 }
b959290b 786
5326a0fd
BP
787 VLOG_INFO("network device %s destroyed, removing from bridge %s",
788 port_name, br_name);
789
2b01925c 790 run_vsctl(vsctl_program, VSCTL_OPTIONS,
9ed3ba29 791 "--", "--if-exists", "del-port", port_name,
2b01925c
BP
792 "--", "comment", "ovs-brcompatd:", port_name, "disappeared",
793 (char *) NULL);
064af421
BP
794}
795
796int
797main(int argc, char *argv[])
798{
480ce8ab 799 extern struct vlog_module VLM_reconnect;
2ee6545f 800 struct nln_notifier *link_notifier;
064af421
BP
801 struct unixctl_server *unixctl;
802 int retval;
803
40f0707c 804 proctitle_init(argc, argv);
064af421 805 set_program_name(argv[0]);
480ce8ab 806 vlog_set_levels(&VLM_reconnect, VLF_ANY_FACILITY, VLL_WARN);
9852694f 807
2b01925c 808 parse_options(argc, argv);
064af421
BP
809 signal(SIGPIPE, SIG_IGN);
810 process_init();
811
95440284 812 daemonize_start();
064af421
BP
813
814 retval = unixctl_server_create(NULL, &unixctl);
815 if (retval) {
4d12270a 816 exit(EXIT_FAILURE);
064af421
BP
817 }
818
819 if (brc_open(&brc_sock)) {
279c9e03
BP
820 VLOG_FATAL("could not open brcompat socket. Check "
821 "\"brcompat\" kernel module.");
064af421
BP
822 }
823
2ee6545f 824 link_notifier = rtnetlink_link_notifier_create(netdev_changed_cb, NULL);
064af421 825
95440284
BP
826 daemonize_complete();
827
064af421
BP
828 for (;;) {
829 unixctl_server_run(unixctl);
18a23781 830 rtnetlink_link_run();
2b01925c 831 brc_recv_update();
5ff22a06 832
8b61709d 833 netdev_run();
064af421 834
064af421
BP
835 nl_sock_wait(brc_sock, POLLIN);
836 unixctl_server_wait(unixctl);
18a23781 837 rtnetlink_link_wait();
8b61709d 838 netdev_wait();
064af421
BP
839 poll_block();
840 }
841
2ee6545f 842 rtnetlink_link_notifier_destroy(link_notifier);
9852694f 843
064af421
BP
844 return 0;
845}
846
3c303e5f 847static void
064af421
BP
848parse_options(int argc, char *argv[])
849{
850 enum {
2b01925c
BP
851 OPT_APPCTL,
852 OPT_VSCTL,
064af421 853 VLOG_OPTION_ENUMS,
8274ae95
BP
854 LEAK_CHECKER_OPTION_ENUMS,
855 DAEMON_OPTION_ENUMS
064af421
BP
856 };
857 static struct option long_options[] = {
e3c17733
BP
858 {"help", no_argument, NULL, 'h'},
859 {"version", no_argument, NULL, 'V'},
2b01925c
BP
860 {"appctl", required_argument, NULL, OPT_APPCTL},
861 {"vsctl", required_argument, NULL, OPT_VSCTL},
064af421
BP
862 DAEMON_LONG_OPTIONS,
863 VLOG_LONG_OPTIONS,
864 LEAK_CHECKER_LONG_OPTIONS,
e3c17733 865 {NULL, 0, NULL, 0},
064af421
BP
866 };
867 char *short_options = long_options_to_short_options(long_options);
2b01925c
BP
868 const char *appctl = "ovs-appctl";
869 const char *vsctl = "ovs-vsctl";
064af421 870
064af421
BP
871 for (;;) {
872 int c;
873
874 c = getopt_long(argc, argv, short_options, long_options, NULL);
875 if (c == -1) {
876 break;
877 }
878
879 switch (c) {
064af421
BP
880 case 'h':
881 usage();
882
883 case 'V':
55d5bb44 884 ovs_print_version(0, 0);
064af421
BP
885 exit(EXIT_SUCCESS);
886
2b01925c
BP
887 case OPT_APPCTL:
888 appctl = optarg;
889 break;
890
891 case OPT_VSCTL:
892 vsctl = optarg;
064af421
BP
893 break;
894
895 VLOG_OPTION_HANDLERS
896 DAEMON_OPTION_HANDLERS
897 LEAK_CHECKER_OPTION_HANDLERS
898
899 case '?':
900 exit(EXIT_FAILURE);
901
902 default:
903 abort();
904 }
905 }
906 free(short_options);
907
2b01925c
BP
908 appctl_program = process_search_path(appctl);
909 if (!appctl_program) {
910 VLOG_FATAL("%s: not found in $PATH (use --appctl to specify an "
911 "alternate location)", appctl);
912 }
3c303e5f 913
2b01925c
BP
914 vsctl_program = process_search_path(vsctl);
915 if (!vsctl_program) {
916 VLOG_FATAL("%s: not found in $PATH (use --vsctl to specify an "
917 "alternate location)", vsctl);
918 }
064af421 919
2b01925c
BP
920 if (argc != optind) {
921 VLOG_FATAL("no non-option arguments are supported; "
279c9e03 922 "use --help for usage");
064af421 923 }
064af421
BP
924}
925
926static void
927usage(void)
928{
929 printf("%s: bridge compatibility front-end for ovs-vswitchd\n"
2b01925c 930 "usage: %s [OPTIONS]\n",
064af421
BP
931 program_name, program_name);
932 printf("\nConfiguration options:\n"
2b01925c
BP
933 " --appctl=PROGRAM overrides $PATH for finding ovs-appctl\n"
934 " --vsctl=PROGRAM overrides $PATH for finding ovs-vsctl\n"
064af421
BP
935 );
936 daemon_usage();
937 vlog_usage();
938 printf("\nOther options:\n"
939 " -h, --help display this help message\n"
940 " -V, --version display version information\n");
941 leak_checker_usage();
064af421
BP
942 exit(EXIT_SUCCESS);
943}