X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=secchan%2Fsecchan.c;h=d1df8283dedfe21b74226d552e7ffb27a3e64c80;hb=2c775287e298648ac695df4e66cffe99f1b497c1;hp=8906eb03117b6a365635e80fd0fd066f93706f4b;hpb=ab43666b205d968b4ce7428b9a730b70ff81042f;p=sliver-openvswitch.git diff --git a/secchan/secchan.c b/secchan/secchan.c index 8906eb031..d1df8283d 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -45,12 +45,11 @@ #include #include -#include "buffer.h" #include "command-line.h" #include "compiler.h" #include "daemon.h" -#include "dhcp.h" #include "dhcp-client.h" +#include "dhcp.h" #include "dynamic-string.h" #include "fault.h" #include "flow.h" @@ -58,6 +57,7 @@ #include "list.h" #include "mac-learning.h" #include "netdev.h" +#include "ofpbuf.h" #include "openflow.h" #include "packets.h" #include "poll-loop.h" @@ -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? */ @@ -107,7 +111,7 @@ struct settings { struct half { struct rconn *rconn; - struct buffer *rxbuf; + struct ofpbuf *rxbuf; int n_txq; /* No. of packets queued for tx on 'rconn'. */ }; @@ -191,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]); @@ -206,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. */ @@ -230,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); @@ -279,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; } @@ -311,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) { @@ -420,7 +430,7 @@ relay_run(struct relay *r, const struct hook hooks[], size_t n_hooks) const struct hook *h; for (h = hooks; h < &hooks[n_hooks]; h++) { if (h->packet_cb(r, i, h->aux)) { - buffer_delete(this->rxbuf); + ofpbuf_delete(this->rxbuf); this->rxbuf = NULL; progress = true; break; @@ -436,7 +446,7 @@ relay_run(struct relay *r, const struct hook hooks[], size_t n_hooks) if (!retval) { progress = true; } else { - buffer_delete(this->rxbuf); + ofpbuf_delete(this->rxbuf); } this->rxbuf = NULL; } @@ -482,7 +492,7 @@ relay_destroy(struct relay *r) for (i = 0; i < 2; i++) { struct half *this = &r->halves[i]; rconn_destroy(this->rconn); - buffer_delete(this->rxbuf); + ofpbuf_delete(this->rxbuf); } free(r); } @@ -499,7 +509,7 @@ struct in_band_data { }; static void -queue_tx(struct rconn *rc, struct in_band_data *in_band, struct buffer *b) +queue_tx(struct rconn *rc, struct in_band_data *in_band, struct ofpbuf *b) { rconn_send_with_limit(rc, b, &in_band->n_queued, 10); } @@ -566,11 +576,11 @@ in_band_packet_cb(struct relay *r, int half, void *in_band_) { struct in_band_data *in_band = in_band_; struct rconn *rc = r->halves[HALF_LOCAL].rconn; - struct buffer *msg = r->halves[HALF_LOCAL].rxbuf; + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; struct ofp_packet_in *opi; struct ofp_header *oh; size_t pkt_ofs, pkt_len; - struct buffer pkt; + struct ofpbuf pkt; struct flow flow; uint16_t in_port, out_port; const uint8_t *controller_mac; @@ -615,18 +625,30 @@ in_band_packet_cb(struct relay *r, int half, void *in_band_) && is_controller_mac(flow.dl_src, in_band)) { /* ARP sent by controller. */ out_port = OFPP_FLOOD; - } else if (is_controller_mac(flow.dl_dst, in_band) - && in_port == mac_learning_lookup(in_band->ml, - controller_mac)) { - /* Drop controller traffic that arrives on the controller port. */ - queue_tx(rc, in_band, make_add_flow(&flow, ntohl(opi->buffer_id), - in_band->s->max_idle, 0)); - return true; + } else if (is_controller_mac(flow.dl_dst, in_band)) { + if (mac_learning_learn(in_band->ml, 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); + } + + out_port = mac_learning_lookup(in_band->ml, controller_mac); + if (in_port != out_port) { + return false; + } + + /* This is controller traffic that arrived on the controller port. + * It will get dropped below. */ + } else if (is_controller_mac(flow.dl_src, in_band)) { + out_port = mac_learning_lookup(in_band->ml, flow.dl_dst); } else { return false; } - if (out_port != OFPP_FLOOD) { + if (in_port == out_port) { + /* The input and output port match. Set up a flow to drop packets. */ + queue_tx(rc, in_band, make_add_flow(&flow, ntohl(opi->buffer_id), + in_band->s->max_idle, 0)); + } else if (out_port != OFPP_FLOOD) { /* The output port is known, so add a new flow. */ queue_tx(rc, in_band, make_add_simple_flow(&flow, ntohl(opi->buffer_id), @@ -640,7 +662,7 @@ in_band_packet_cb(struct relay *r, int half, void *in_band_) } else { /* We don't know that MAC. Send along the packet without setting up a * flow. */ - struct buffer *b; + struct ofpbuf *b; if (ntohl(opi->buffer_id) == UINT32_MAX) { b = make_unbuffered_packet_out(&pkt, in_port, out_port); } else { @@ -788,7 +810,7 @@ struct rate_limiter { struct rconn *remote_rconn; /* One queue per physical port. */ - struct queue queues[OFPP_MAX]; + struct ofp_queue queues[OFPP_MAX]; int n_queued; /* Sum over queues[*].n. */ int next_tx_port; /* Next port to check in round-robin. */ @@ -815,9 +837,9 @@ struct rate_limiter { static void drop_packet(struct rate_limiter *rl) { - struct queue *longest; /* Queue currently selected as longest. */ + struct ofp_queue *longest; /* Queue currently selected as longest. */ int n_longest; /* # of queues of same length as 'longest'. */ - struct queue *q; + struct ofp_queue *q; longest = &rl->queues[0]; n_longest = 1; @@ -837,19 +859,19 @@ drop_packet(struct rate_limiter *rl) } /* FIXME: do we want to pop the tail instead? */ - buffer_delete(queue_pop_head(longest)); + ofpbuf_delete(queue_pop_head(longest)); rl->n_queued--; } /* Remove and return the next packet to transmit (in round-robin order). */ -static struct buffer * +static struct ofpbuf * dequeue_packet(struct rate_limiter *rl) { unsigned int i; for (i = 0; i < OFPP_MAX; i++) { unsigned int port = (rl->next_tx_port + i) % OFPP_MAX; - struct queue *q = &rl->queues[port]; + struct ofp_queue *q = &rl->queues[port]; if (q->n) { rl->next_tx_port = (port + 1) % OFPP_MAX; rl->n_queued--; @@ -891,7 +913,7 @@ rate_limit_packet_cb(struct relay *r, int half, void *rl_) { struct rate_limiter *rl = rl_; const struct settings *s = rl->s; - struct buffer *msg = r->halves[HALF_LOCAL].rxbuf; + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; struct ofp_header *oh; if (half == HALF_REMOTE) { @@ -920,7 +942,7 @@ rate_limit_packet_cb(struct relay *r, int half, void *rl_) if (rl->n_queued >= s->burst_limit) { drop_packet(rl); } - queue_push_tail(&rl->queues[port], buffer_clone(msg)); + queue_push_tail(&rl->queues[port], ofpbuf_clone(msg)); rl->n_queued++; rl->n_limited++; return true; @@ -952,7 +974,7 @@ rate_limit_periodic_cb(void *rl_) * because the TCP connection is responsible for buffering and there is * no point in trying to transmit faster than the TCP connection can * handle. */ - struct buffer *b = dequeue_packet(rl); + struct ofpbuf *b = dequeue_packet(rl); if (rconn_send_with_limit(rl->remote_rconn, b, &rl->n_txq, 10)) { rl->n_tx_dropped++; } @@ -1022,13 +1044,13 @@ switch_status_packet_cb(struct relay *r, int half, void *ss_) { struct switch_status *ss = ss_; struct rconn *rc = r->halves[HALF_REMOTE].rconn; - struct buffer *msg = r->halves[HALF_REMOTE].rxbuf; + struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; struct switch_status_category *c; struct ofp_stats_request *osr; struct ofp_stats_reply *reply; struct status_reply sr; struct ofp_header *oh; - struct buffer *b; + struct ofpbuf *b; int retval; if (half == HALF_LOCAL) { @@ -1082,6 +1104,7 @@ rconn_status_cb(struct status_reply *sr, void *rconn_) status_reply_put(sr, "name=%s", rconn_get_name(rconn)); status_reply_put(sr, "state=%s", rconn_get_state(rconn)); + status_reply_put(sr, "backoff=%d", rconn_get_backoff(rconn)); status_reply_put(sr, "is-connected=%s", rconn_is_connected(rconn) ? "true" : "false"); status_reply_put(sr, "sent-msgs=%u", rconn_packets_sent(rconn)); @@ -1094,15 +1117,17 @@ rconn_status_cb(struct status_reply *sr, void *rconn_) (long int) (now - rconn_get_last_connection(rconn))); status_reply_put(sr, "time-connected=%lu", rconn_get_total_time_connected(rconn)); + status_reply_put(sr, "state-elapsed=%u", rconn_get_state_elapsed(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); @@ -1191,11 +1216,10 @@ discovery_status_cb(struct status_reply *sr, void *d_) { struct discovery *d = d_; - status_reply_put(sr, "discovery.accept-remote=%s", - d->s->accept_controller_re); - status_reply_put(sr, "discovery.n-changes=%d", d->n_changes); - status_reply_put(sr, "discovery.state=%s", dhclient_get_state(d->dhcp)); - status_reply_put(sr, "discovery.state-elapsed=%u", + status_reply_put(sr, "accept-remote=%s", d->s->accept_controller_re); + status_reply_put(sr, "n-changes=%d", d->n_changes); + status_reply_put(sr, "state=%s", dhclient_get_state(d->dhcp)); + status_reply_put(sr, "state-elapsed=%u", dhclient_get_state_elapsed(d->dhcp)); if (dhclient_is_bound(d->dhcp)) { uint32_t ip = dhclient_get_ip(d->dhcp); @@ -1207,25 +1231,24 @@ discovery_status_cb(struct status_reply *sr, void *d_) char *domain_name; int i; - status_reply_put(sr, "discovery.ip="IP_FMT, IP_ARGS(&ip)); - status_reply_put(sr, "discovery.netmask="IP_FMT, IP_ARGS(&netmask)); + status_reply_put(sr, "ip="IP_FMT, IP_ARGS(&ip)); + status_reply_put(sr, "netmask="IP_FMT, IP_ARGS(&netmask)); if (router) { - status_reply_put(sr, "discovery.router="IP_FMT, IP_ARGS(&router)); + status_reply_put(sr, "router="IP_FMT, IP_ARGS(&router)); } for (i = 0; dhcp_msg_get_ip(cfg, DHCP_CODE_DNS_SERVER, i, &dns_server); i++) { - status_reply_put(sr, "discovery.dns%d="IP_FMT, - i, IP_ARGS(&dns_server)); + status_reply_put(sr, "dns%d="IP_FMT, i, IP_ARGS(&dns_server)); } domain_name = dhcp_msg_get_string(cfg, DHCP_CODE_DOMAIN_NAME); if (domain_name) { - status_reply_put(sr, "discovery.domain=%s", domain_name); + status_reply_put(sr, "domain=%s", domain_name); free(domain_name); } - status_reply_put(sr, "discovery.lease-remaining=%u", + status_reply_put(sr, "lease-remaining=%u", dhclient_get_lease_remaining(d->dhcp)); } } @@ -1351,7 +1374,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}, @@ -1359,6 +1382,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'}, @@ -1371,7 +1395,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; @@ -1396,7 +1420,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")) { @@ -1461,11 +1485,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': @@ -1575,7 +1604,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" @@ -1590,6 +1619,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"