Make -P or --pidfile keep programs from running if already running.
[openvswitch] / secchan / secchan.c
index f3396ff73d023814a33eaba86d0c4801cca6cefb..92d5ed73b747592c6c096f8950a962b3f181cfd8 100644 (file)
@@ -77,6 +77,9 @@ enum fail_mode {
     FAIL_CLOSED                 /* Drop all packets. */
 };
 
+/* Maximum number of management connection listeners. */
+#define MAX_MGMT 8
+
 /* Settings that may be configured by the user. */
 struct settings {
     /* Overall mode of operation. */
@@ -87,7 +90,8 @@ struct settings {
     const char *nl_name;        /* Local datapath (must be "nl:" vconn). */
     char *of_name;              /* ofX network device name. */
     const char *controller_name; /* Controller (if not discovery mode). */
-    const char *listen_vconn_name; /* Listens for mgmt connections. */
+    const char *listener_names[MAX_MGMT]; /* Listen for mgmt connections. */
+    size_t n_listeners;          /* Number of mgmt connection listeners. */
 
     /* Failure behavior. */
     enum fail_mode fail_mode; /* Act as learning switch if no controller? */
@@ -128,6 +132,8 @@ struct hook {
     void *aux;
 };
 
+static struct vlog_rate_limit vrl = VLOG_RATE_LIMIT_INIT(60, 60);
+
 static void parse_options(int argc, char *argv[], struct settings *);
 static void usage(void) NO_RETURN;
 
@@ -189,11 +195,14 @@ main(int argc, char *argv[])
     struct hook hooks[8];
     size_t n_hooks = 0;
 
+    struct vconn *listeners[MAX_MGMT];
+    size_t n_listeners;
+
     struct rconn *local_rconn, *remote_rconn;
-    struct vconn *listen_vconn;
     struct relay *controller_relay;
     struct discovery *discovery;
     struct switch_status *switch_status;
+    int i;
     int retval;
 
     set_program_name(argv[0]);
@@ -204,16 +213,18 @@ main(int argc, char *argv[])
     signal(SIGPIPE, SIG_IGN);
 
     /* Start listening for management connections. */
-    if (s.listen_vconn_name) {
-        retval = vconn_open(s.listen_vconn_name, &listen_vconn);
+    n_listeners = 0;
+    for (i = 0; i < s.n_listeners; i++) {
+        const char *name = s.listener_names[i];
+        struct vconn *listener;
+        retval = vconn_open(name, &listener);
         if (retval && retval != EAGAIN) {
-            fatal(retval, "opening %s", s.listen_vconn_name);
+            fatal(retval, "opening %s", name);
         }
-        if (!vconn_is_passive(listen_vconn)) {
-            fatal(0, "%s is not a passive vconn", s.listen_vconn_name);
+        if (!vconn_is_passive(listener)) {
+            fatal(0, "%s is not a passive vconn", name);
         }
-    } else {
-        listen_vconn = NULL;
+        listeners[n_listeners++] = listener;
     }
 
     /* Initialize switch status hook. */
@@ -228,6 +239,7 @@ main(int argc, char *argv[])
         fatal(retval, "Could not listen for vlog connections");
     }
 
+    die_if_already_running();
     daemonize();
 
     VLOG_WARN("OpenFlow reference implementation version %s", VERSION);
@@ -277,9 +289,9 @@ main(int argc, char *argv[])
         LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) {
             relay_run(r, hooks, n_hooks);
         }
-        if (listen_vconn) {
+        for (i = 0; i < n_listeners; i++) {
             for (;;) {
-                struct relay *r = relay_accept(&s, listen_vconn);
+                struct relay *r = relay_accept(&s, listeners[i]);
                 if (!r) {
                     break;
                 }
@@ -309,8 +321,8 @@ main(int argc, char *argv[])
         LIST_FOR_EACH (r, struct relay, node, &relays) {
             relay_wait(r);
         }
-        if (listen_vconn) {
-            vconn_accept_wait(listen_vconn);
+        for (i = 0; i < n_listeners; i++) {
+            vconn_accept_wait(listeners[i]);
         }
         for (i = 0; i < n_hooks; i++) {
             if (hooks[i].wait_cb) {
@@ -353,7 +365,7 @@ relay_accept(const struct settings *s, struct vconn *listen_vconn)
     retval = vconn_accept(listen_vconn, &new_remote);
     if (retval) {
         if (retval != EAGAIN) {
-            VLOG_WARN("accept failed (%s)", strerror(retval));
+            VLOG_WARN_RL(&vrl, "accept failed (%s)", strerror(retval));
         }
         return NULL;
     }
@@ -367,8 +379,8 @@ relay_accept(const struct settings *s, struct vconn *listen_vconn)
     nl_name_without_subscription = xasprintf("%s:0", s->nl_name);
     retval = vconn_open(nl_name_without_subscription, &new_local);
     if (retval) {
-        VLOG_ERR("could not connect to %s (%s)",
-                 nl_name_without_subscription, strerror(retval));
+        VLOG_ERR_RL(&vrl, "could not connect to %s (%s)",
+                    nl_name_without_subscription, strerror(retval));
         vconn_close(new_remote);
         free(nl_name_without_subscription);
         return NULL;
@@ -582,7 +594,8 @@ in_band_packet_cb(struct relay *r, int half, void *in_band_)
         return false;
     }
     if (msg->size < offsetof(struct ofp_packet_in, data)) {
-        VLOG_WARN("packet too short (%zu bytes) for packet_in", msg->size);
+        VLOG_WARN_RL(&vrl, "packet too short (%zu bytes) for packet_in",
+                     msg->size);
         return false;
     }
 
@@ -604,8 +617,8 @@ in_band_packet_cb(struct relay *r, int half, void *in_band_)
         /* Sent to secure channel. */
         out_port = OFPP_LOCAL;
         if (mac_learning_learn(in_band->ml, flow.dl_src, in_port)) {
-            VLOG_DBG("learned that "ETH_ADDR_FMT" is on port %"PRIu16,
-                     ETH_ADDR_ARGS(flow.dl_src), in_port);
+            VLOG_DBG_RL(&vrl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16,
+                        ETH_ADDR_ARGS(flow.dl_src), in_port);
         }
     } else if (flow.dl_type == htons(ETH_TYPE_ARP)
                && eth_addr_is_broadcast(flow.dl_dst)
@@ -900,7 +913,8 @@ rate_limit_packet_cb(struct relay *r, int half, void *rl_)
         return false;
     }
     if (msg->size < offsetof(struct ofp_packet_in, data)) {
-        VLOG_WARN("packet too short (%zu bytes) for packet_in", msg->size);
+        VLOG_WARN_RL(&vrl, "packet too short (%zu bytes) for packet_in",
+                     msg->size);
         return false;
     }
 
@@ -1036,7 +1050,8 @@ switch_status_packet_cb(struct relay *r, int half, void *ss_)
         return false;
     }
     if (msg->size < sizeof(struct ofp_stats_request)) {
-        VLOG_WARN("packet too short (%zu bytes) for stats_request", msg->size);
+        VLOG_WARN_RL(&vrl, "packet too short (%zu bytes) for stats_request",
+                     msg->size);
         return false;
     }
 
@@ -1094,10 +1109,11 @@ rconn_status_cb(struct status_reply *sr, void *rconn_)
 static void
 config_status_cb(struct status_reply *sr, void *s_)
 {
-     const struct settings *s = s_;
+    const struct settings *s = s_;
+    size_t i;
 
-    if (s->listen_vconn_name) {
-        status_reply_put(sr, "management=%s", s->listen_vconn_name);
+    for (i = 0; i < s->n_listeners; i++) {
+        status_reply_put(sr, "management%zu=%s", i, s->listener_names[i]);
     }
     if (s->probe_interval) {
         status_reply_put(sr, "probe-interval=%d", s->probe_interval);
@@ -1317,13 +1333,13 @@ validate_dhcp_offer(const struct dhcp_msg *msg, void *s_)
 
     vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN);
     if (!vconn_name) {
-        VLOG_WARN("rejecting DHCP offer missing controller vconn");
+        VLOG_WARN_RL(&vrl, "rejecting DHCP offer missing controller vconn");
         return false;
     }
     accept = !regexec(&s->accept_controller_regex, vconn_name, 0, NULL, 0);
     if (!accept) {
-        VLOG_WARN("rejecting controller vconn that fails to match %s",
-                  s->accept_controller_re);
+        VLOG_WARN_RL(&vrl, "rejecting controller vconn that fails to match %s",
+                     s->accept_controller_re);
     }
     free(vconn_name);
     return accept;
@@ -1346,7 +1362,7 @@ parse_options(int argc, char *argv[], struct settings *s)
     static struct option long_options[] = {
         {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
         {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF},
-        {"fail",        required_argument, 0, 'f'},
+        {"fail",        required_argument, 0, 'F'},
         {"inactivity-probe", required_argument, 0, OPT_INACTIVITY_PROBE},
         {"max-idle",    required_argument, 0, OPT_MAX_IDLE},
         {"max-backoff", required_argument, 0, OPT_MAX_BACKOFF},
@@ -1354,6 +1370,7 @@ parse_options(int argc, char *argv[], struct settings *s)
         {"rate-limit",  optional_argument, 0, OPT_RATE_LIMIT},
         {"burst-limit", required_argument, 0, OPT_BURST_LIMIT},
         {"detach",      no_argument, 0, 'D'},
+        {"force",       no_argument, 0, 'f'},
         {"pidfile",     optional_argument, 0, 'P'},
         {"verbose",     optional_argument, 0, 'v'},
         {"help",        no_argument, 0, 'h'},
@@ -1366,7 +1383,7 @@ parse_options(int argc, char *argv[], struct settings *s)
     int retval;
 
     /* Set defaults that we can figure out before parsing options. */
-    s->listen_vconn_name = NULL;
+    s->n_listeners = 0;
     s->fail_mode = FAIL_OPEN;
     s->max_idle = 15;
     s->probe_interval = 15;
@@ -1391,7 +1408,7 @@ parse_options(int argc, char *argv[], struct settings *s)
             s->update_resolv_conf = false;
             break;
 
-        case 'f':
+        case 'F':
             if (!strcmp(optarg, "open")) {
                 s->fail_mode = FAIL_OPEN;
             } else if (!strcmp(optarg, "closed")) {
@@ -1456,11 +1473,16 @@ parse_options(int argc, char *argv[], struct settings *s)
             set_pidfile(optarg);
             break;
 
+        case 'f':
+            ignore_existing_pidfile();
+            break;
+
         case 'l':
-            if (s->listen_vconn_name) {
-                fatal(0, "-l or --listen may be only specified once");
+            if (s->n_listeners >= MAX_MGMT) {
+                fatal(0, "-l or --listen may be specified at most %d times",
+                      MAX_MGMT);
             }
-            s->listen_vconn_name = optarg;
+            s->listener_names[s->n_listeners++] = optarg;
             break;
 
         case 'h':
@@ -1570,7 +1592,7 @@ usage(void)
            "  --accept-vconn=REGEX    accept matching discovered controllers\n"
            "  --no-resolv-conf        do not update /etc/resolv.conf\n"
            "\nNetworking options:\n"
-           "  -f, --fail=open|closed  when controller connection fails:\n"
+           "  -F, --fail=open|closed  when controller connection fails:\n"
            "                            closed: drop all packets\n"
            "                            open (default): act as learning switch\n"
            "  --inactivity-probe=SECS time between inactivity probes\n"
@@ -1585,6 +1607,7 @@ usage(void)
            "\nOther options:\n"
            "  -D, --detach            run in background as daemon\n"
            "  -P, --pidfile[=FILE]    create pidfile (default: %s/secchan.pid)\n"
+           "  -f, --force             with -P, start even if already running\n"
            "  -v, --verbose=MODULE[:FACILITY[:LEVEL]]  set logging levels\n"
            "  -v, --verbose           set maximum verbosity level\n"
            "  -h, --help              display this help message\n"