| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2013-01-02 17:10:43 -08:00
										 |  |  |  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2009-06-15 15:11:30 -07:00
										 |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at: | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2009-06-15 15:11:30 -07:00
										 |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <config.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <getopt.h>
 | 
					
						
							|  |  |  | #include <limits.h>
 | 
					
						
							|  |  |  | #include <signal.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2010-07-28 15:18:25 -07:00
										 |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "command-line.h"
 | 
					
						
							|  |  |  | #include "compiler.h"
 | 
					
						
							|  |  |  | #include "daemon.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-26 10:44:46 -08:00
										 |  |  | #include "fatal-signal.h"
 | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | #include "learning-switch.h"
 | 
					
						
							| 
									
										
										
										
											2010-09-23 14:08:13 -07:00
										 |  |  | #include "ofp-parse.h"
 | 
					
						
							| 
									
										
										
										
											2012-11-19 14:59:33 +09:00
										 |  |  | #include "ofp-version-opt.h"
 | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | #include "ofpbuf.h"
 | 
					
						
							|  |  |  | #include "openflow/openflow.h"
 | 
					
						
							|  |  |  | #include "poll-loop.h"
 | 
					
						
							|  |  |  | #include "rconn.h"
 | 
					
						
							| 
									
										
										
										
											2012-05-22 10:32:02 -07:00
										 |  |  | #include "simap.h"
 | 
					
						
							| 
									
										
										
										
											2010-01-06 14:35:20 -08:00
										 |  |  | #include "stream-ssl.h"
 | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | #include "timeval.h"
 | 
					
						
							|  |  |  | #include "unixctl.h"
 | 
					
						
							|  |  |  | #include "util.h"
 | 
					
						
							|  |  |  | #include "vconn.h"
 | 
					
						
							|  |  |  | #include "vlog.h"
 | 
					
						
							| 
									
										
										
										
											2012-03-10 15:58:10 -08:00
										 |  |  | #include "socket-util.h"
 | 
					
						
							| 
									
										
										
										
											2012-11-04 21:41:02 -08:00
										 |  |  | #include "ofp-util.h"
 | 
					
						
							| 
									
										
										
										
											2010-07-16 11:02:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-19 14:47:01 -07:00
										 |  |  | VLOG_DEFINE_THIS_MODULE(controller); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define MAX_SWITCHES 16
 | 
					
						
							|  |  |  | #define MAX_LISTENERS 16
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct switch_ { | 
					
						
							|  |  |  |     struct lswitch *lswitch; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  | /* -H, --hub: Learn the ports on which MAC addresses appear? */ | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | static bool learn_macs = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  | /* -n, --noflow: Set up flows?  (If not, every packet is processed at the
 | 
					
						
							|  |  |  |  * controller.) */ | 
					
						
							| 
									
										
										
										
											2009-10-26 14:41:32 -07:00
										 |  |  | static bool set_up_flows = true; | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 12:48:32 -08:00
										 |  |  | /* -N, --normal: Use "NORMAL" action instead of explicit port? */ | 
					
						
							|  |  |  | static bool action_normal = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-21 21:51:03 -07:00
										 |  |  | /* -w, --wildcard: 0 to disable wildcard flow entries, an OFPFW10_* bitmask to
 | 
					
						
							| 
									
										
										
										
											2011-06-01 09:09:20 -07:00
										 |  |  |  * enable specific wildcards, or UINT32_MAX to use the default wildcards. */ | 
					
						
							|  |  |  | static uint32_t wildcards = 0; | 
					
						
							| 
									
										
										
										
											2009-11-19 12:48:32 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | /* --max-idle: Maximum idle time, in seconds, before flows expire. */ | 
					
						
							|  |  |  | static int max_idle = 60; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-16 15:12:19 -07:00
										 |  |  | /* --mute: If true, accept connections from switches but do not reply to any
 | 
					
						
							|  |  |  |  * of their messages (for debugging fail-open mode). */ | 
					
						
							|  |  |  | static bool mute = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  | /* -q, --queue: default OpenFlow queue, none if UINT32_MAX. */ | 
					
						
							|  |  |  | static uint32_t default_queue = UINT32_MAX; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-22 10:32:02 -07:00
										 |  |  | /* -Q, --port-queue: map from port name to port number. */ | 
					
						
							|  |  |  | static struct simap port_queues = SIMAP_INITIALIZER(&port_queues); | 
					
						
							| 
									
										
										
										
											2010-07-15 17:08:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-10 13:30:23 -08:00
										 |  |  | /* --with-flows: Flows to send to switch. */ | 
					
						
							|  |  |  | static struct ofputil_flow_mod *default_flows; | 
					
						
							|  |  |  | static size_t n_default_flows; | 
					
						
							| 
									
										
										
										
											2013-08-20 18:41:45 -07:00
										 |  |  | static enum ofputil_protocol usable_protocols; | 
					
						
							| 
									
										
										
										
											2010-07-28 15:18:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-23 11:24:38 -07:00
										 |  |  | /* --unixctl: Name of unixctl socket, or null to use the default. */ | 
					
						
							|  |  |  | static char *unixctl_path = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-03 14:19:33 -07:00
										 |  |  | static void new_switch(struct switch_ *, struct vconn *); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | static void parse_options(int argc, char *argv[]); | 
					
						
							|  |  |  | static void usage(void) NO_RETURN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | main(int argc, char *argv[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct unixctl_server *unixctl; | 
					
						
							|  |  |  |     struct switch_ switches[MAX_SWITCHES]; | 
					
						
							|  |  |  |     struct pvconn *listeners[MAX_LISTENERS]; | 
					
						
							|  |  |  |     int n_switches, n_listeners; | 
					
						
							|  |  |  |     int retval; | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-19 15:00:56 -08:00
										 |  |  |     proctitle_init(argc, argv); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |     set_program_name(argv[0]); | 
					
						
							|  |  |  |     parse_options(argc, argv); | 
					
						
							| 
									
										
										
										
											2014-02-26 10:44:46 -08:00
										 |  |  |     fatal_ignore_sigpipe(); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (argc - optind < 1) { | 
					
						
							|  |  |  |         ovs_fatal(0, "at least one vconn argument required; " | 
					
						
							|  |  |  |                   "use --help for usage"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     n_switches = n_listeners = 0; | 
					
						
							|  |  |  |     for (i = optind; i < argc; i++) { | 
					
						
							|  |  |  |         const char *name = argv[i]; | 
					
						
							|  |  |  |         struct vconn *vconn; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-02 17:10:43 -08:00
										 |  |  |         retval = vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT, | 
					
						
							|  |  |  |                             &vconn); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |         if (!retval) { | 
					
						
							|  |  |  |             if (n_switches >= MAX_SWITCHES) { | 
					
						
							|  |  |  |                 ovs_fatal(0, "max %d switch connections", n_switches); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-06-03 14:19:33 -07:00
										 |  |  |             new_switch(&switches[n_switches++], vconn); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |             continue; | 
					
						
							|  |  |  |         } else if (retval == EAFNOSUPPORT) { | 
					
						
							|  |  |  |             struct pvconn *pvconn; | 
					
						
							| 
									
										
										
										
											2012-11-19 14:59:33 +09:00
										 |  |  |             retval = pvconn_open(name, get_allowed_ofp_versions(), | 
					
						
							| 
									
										
										
										
											2013-01-02 17:10:43 -08:00
										 |  |  |                                  DSCP_DEFAULT, &pvconn); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |             if (!retval) { | 
					
						
							|  |  |  |                 if (n_listeners >= MAX_LISTENERS) { | 
					
						
							|  |  |  |                     ovs_fatal(0, "max %d passive connections", n_listeners); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 listeners[n_listeners++] = pvconn; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (retval) { | 
					
						
							| 
									
										
										
										
											2013-06-24 10:54:49 -07:00
										 |  |  |             VLOG_ERR("%s: connect: %s", name, ovs_strerror(retval)); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (n_switches == 0 && n_listeners == 0) { | 
					
						
							|  |  |  |         ovs_fatal(0, "no active or passive switch connections"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-17 10:56:01 -08:00
										 |  |  |     daemonize_start(); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-23 11:24:38 -07:00
										 |  |  |     retval = unixctl_server_create(unixctl_path, &unixctl); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |     if (retval) { | 
					
						
							| 
									
										
										
										
											2010-01-15 10:31:57 -08:00
										 |  |  |         exit(EXIT_FAILURE); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-17 10:56:01 -08:00
										 |  |  |     daemonize_complete(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |     while (n_switches > 0 || n_listeners > 0) { | 
					
						
							|  |  |  |         /* Accept connections on listening vconns. */ | 
					
						
							|  |  |  |         for (i = 0; i < n_listeners && n_switches < MAX_SWITCHES; ) { | 
					
						
							|  |  |  |             struct vconn *new_vconn; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-04 21:41:02 -08:00
										 |  |  |             retval = pvconn_accept(listeners[i], &new_vconn); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |             if (!retval || retval == EAGAIN) { | 
					
						
							|  |  |  |                 if (!retval) { | 
					
						
							| 
									
										
										
										
											2010-06-03 14:19:33 -07:00
										 |  |  |                     new_switch(&switches[n_switches++], new_vconn); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 i++; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 pvconn_close(listeners[i]); | 
					
						
							|  |  |  |                 listeners[i] = listeners[--n_listeners]; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-24 16:15:37 -07:00
										 |  |  |         /* Do some switching work.  . */ | 
					
						
							|  |  |  |         for (i = 0; i < n_switches; ) { | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |             struct switch_ *this = &switches[i]; | 
					
						
							| 
									
										
										
										
											2010-08-11 17:24:13 -07:00
										 |  |  |             lswitch_run(this->lswitch); | 
					
						
							| 
									
										
										
										
											2012-07-24 16:15:37 -07:00
										 |  |  |             if (lswitch_is_alive(this->lswitch)) { | 
					
						
							|  |  |  |                 i++; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 lswitch_destroy(this->lswitch); | 
					
						
							|  |  |  |                 switches[i] = switches[--n_switches]; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         unixctl_server_run(unixctl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Wait for something to happen. */ | 
					
						
							|  |  |  |         if (n_switches < MAX_SWITCHES) { | 
					
						
							|  |  |  |             for (i = 0; i < n_listeners; i++) { | 
					
						
							|  |  |  |                 pvconn_wait(listeners[i]); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         for (i = 0; i < n_switches; i++) { | 
					
						
							|  |  |  |             struct switch_ *sw = &switches[i]; | 
					
						
							|  |  |  |             lswitch_wait(sw->lswitch); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         unixctl_server_wait(unixctl); | 
					
						
							|  |  |  |         poll_block(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2010-06-03 14:19:33 -07:00
										 |  |  | new_switch(struct switch_ *sw, struct vconn *vconn) | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-23 14:12:09 -07:00
										 |  |  |     struct lswitch_config cfg; | 
					
						
							| 
									
										
										
										
											2012-07-24 16:15:37 -07:00
										 |  |  |     struct rconn *rconn; | 
					
						
							| 
									
										
										
										
											2010-09-23 14:12:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-19 14:59:33 +09:00
										 |  |  |     rconn = rconn_create(60, 0, DSCP_DEFAULT, get_allowed_ofp_versions()); | 
					
						
							| 
									
										
										
										
											2012-07-24 16:15:37 -07:00
										 |  |  |     rconn_connect_unreliably(rconn, vconn, NULL); | 
					
						
							| 
									
										
										
										
											2010-07-28 15:18:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-23 14:12:09 -07:00
										 |  |  |     cfg.mode = (action_normal ? LSW_NORMAL | 
					
						
							|  |  |  |                 : learn_macs ? LSW_LEARN | 
					
						
							|  |  |  |                 : LSW_FLOOD); | 
					
						
							| 
									
										
										
										
											2011-06-01 09:09:20 -07:00
										 |  |  |     cfg.wildcards = wildcards; | 
					
						
							| 
									
										
										
										
											2010-09-23 14:12:09 -07:00
										 |  |  |     cfg.max_idle = set_up_flows ? max_idle : -1; | 
					
						
							| 
									
										
										
										
											2012-02-10 13:30:23 -08:00
										 |  |  |     cfg.default_flows = default_flows; | 
					
						
							|  |  |  |     cfg.n_default_flows = n_default_flows; | 
					
						
							| 
									
										
										
										
											2013-08-20 18:41:45 -07:00
										 |  |  |     cfg.usable_protocols = usable_protocols; | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  |     cfg.default_queue = default_queue; | 
					
						
							|  |  |  |     cfg.port_queues = &port_queues; | 
					
						
							| 
									
										
										
										
											2012-07-24 16:15:37 -07:00
										 |  |  |     cfg.mute = mute; | 
					
						
							|  |  |  |     sw->lswitch = lswitch_create(rconn, &cfg); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  | static void | 
					
						
							|  |  |  | add_port_queue(char *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char *save_ptr = NULL; | 
					
						
							|  |  |  |     char *port_name; | 
					
						
							|  |  |  |     char *queue_id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     port_name = strtok_r(s, ":", &save_ptr); | 
					
						
							|  |  |  |     queue_id = strtok_r(NULL, "", &save_ptr); | 
					
						
							|  |  |  |     if (!queue_id) { | 
					
						
							|  |  |  |         ovs_fatal(0, "argument to -Q or --port-queue should take the form " | 
					
						
							|  |  |  |                   "\"<port-name>:<queue-id>\""); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-22 10:32:02 -07:00
										 |  |  |     if (!simap_put(&port_queues, port_name, atoi(queue_id))) { | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  |         ovs_fatal(0, "<port-name> arguments for -Q or --port-queue must " | 
					
						
							|  |  |  |                   "be unique"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | static void | 
					
						
							|  |  |  | parse_options(int argc, char *argv[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     enum { | 
					
						
							|  |  |  |         OPT_MAX_IDLE = UCHAR_MAX + 1, | 
					
						
							|  |  |  |         OPT_PEER_CA_CERT, | 
					
						
							| 
									
										
										
										
											2009-09-16 15:12:19 -07:00
										 |  |  |         OPT_MUTE, | 
					
						
							| 
									
										
										
										
											2010-07-28 15:18:25 -07:00
										 |  |  |         OPT_WITH_FLOWS, | 
					
						
							| 
									
										
										
										
											2010-03-23 11:24:38 -07:00
										 |  |  |         OPT_UNIXCTL, | 
					
						
							| 
									
										
										
										
											2011-01-28 12:39:15 -08:00
										 |  |  |         VLOG_OPTION_ENUMS, | 
					
						
							| 
									
										
										
										
											2012-11-19 14:59:33 +09:00
										 |  |  |         DAEMON_OPTION_ENUMS, | 
					
						
							|  |  |  |         OFP_VERSION_OPTION_ENUMS | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2013-04-23 16:40:56 -07:00
										 |  |  |     static const struct option long_options[] = { | 
					
						
							| 
									
										
										
										
											2011-05-04 13:49:42 -07:00
										 |  |  |         {"hub",         no_argument, NULL, 'H'}, | 
					
						
							|  |  |  |         {"noflow",      no_argument, NULL, 'n'}, | 
					
						
							|  |  |  |         {"normal",      no_argument, NULL, 'N'}, | 
					
						
							| 
									
										
										
										
											2011-06-01 09:09:20 -07:00
										 |  |  |         {"wildcards",   optional_argument, NULL, 'w'}, | 
					
						
							| 
									
										
										
										
											2011-05-04 13:49:42 -07:00
										 |  |  |         {"max-idle",    required_argument, NULL, OPT_MAX_IDLE}, | 
					
						
							|  |  |  |         {"mute",        no_argument, NULL, OPT_MUTE}, | 
					
						
							|  |  |  |         {"queue",       required_argument, NULL, 'q'}, | 
					
						
							|  |  |  |         {"port-queue",  required_argument, NULL, 'Q'}, | 
					
						
							|  |  |  |         {"with-flows",  required_argument, NULL, OPT_WITH_FLOWS}, | 
					
						
							|  |  |  |         {"unixctl",     required_argument, NULL, OPT_UNIXCTL}, | 
					
						
							|  |  |  |         {"help",        no_argument, NULL, 'h'}, | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |         DAEMON_LONG_OPTIONS, | 
					
						
							| 
									
										
										
										
											2012-11-19 14:59:33 +09:00
										 |  |  |         OFP_VERSION_LONG_OPTIONS, | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |         VLOG_LONG_OPTIONS, | 
					
						
							| 
									
										
										
										
											2011-05-10 09:17:37 -07:00
										 |  |  |         STREAM_SSL_LONG_OPTIONS, | 
					
						
							| 
									
										
										
										
											2011-05-04 13:49:42 -07:00
										 |  |  |         {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT}, | 
					
						
							|  |  |  |         {NULL, 0, NULL, 0}, | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  |     char *short_options = long_options_to_short_options(long_options); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (;;) { | 
					
						
							|  |  |  |         int indexptr; | 
					
						
							| 
									
										
										
										
											2013-07-08 10:15:00 -07:00
										 |  |  |         char *error; | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |         int c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         c = getopt_long(argc, argv, short_options, long_options, &indexptr); | 
					
						
							|  |  |  |         if (c == -1) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (c) { | 
					
						
							|  |  |  |         case 'H': | 
					
						
							|  |  |  |             learn_macs = false; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case 'n': | 
					
						
							| 
									
										
										
										
											2009-10-26 14:41:32 -07:00
										 |  |  |             set_up_flows = false; | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-16 15:12:19 -07:00
										 |  |  |         case OPT_MUTE: | 
					
						
							|  |  |  |             mute = true; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 12:48:32 -08:00
										 |  |  |         case 'N': | 
					
						
							|  |  |  |             action_normal = true; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case 'w': | 
					
						
							| 
									
										
										
										
											2011-06-01 09:09:20 -07:00
										 |  |  |             wildcards = optarg ? strtol(optarg, NULL, 16) : UINT32_MAX; | 
					
						
							| 
									
										
										
										
											2009-11-19 12:48:32 -08:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |         case OPT_MAX_IDLE: | 
					
						
							|  |  |  |             if (!strcmp(optarg, "permanent")) { | 
					
						
							|  |  |  |                 max_idle = OFP_FLOW_PERMANENT; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 max_idle = atoi(optarg); | 
					
						
							|  |  |  |                 if (max_idle < 1 || max_idle > 65535) { | 
					
						
							|  |  |  |                     ovs_fatal(0, "--max-idle argument must be between 1 and " | 
					
						
							|  |  |  |                               "65535 or the word 'permanent'"); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-15 17:08:17 -07:00
										 |  |  |         case 'q': | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  |             default_queue = atoi(optarg); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case 'Q': | 
					
						
							|  |  |  |             add_port_queue(optarg); | 
					
						
							| 
									
										
										
										
											2010-07-15 17:08:17 -07:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-28 15:18:25 -07:00
										 |  |  |         case OPT_WITH_FLOWS: | 
					
						
							| 
									
										
										
										
											2013-07-08 10:15:00 -07:00
										 |  |  |             error = parse_ofp_flow_mod_file(optarg, OFPFC_ADD, &default_flows, | 
					
						
							| 
									
										
										
										
											2013-08-20 18:41:45 -07:00
										 |  |  |                                             &n_default_flows, | 
					
						
							| 
									
										
										
										
											2013-11-15 14:19:57 -08:00
										 |  |  |                                             &usable_protocols); | 
					
						
							| 
									
										
										
										
											2013-07-08 10:15:00 -07:00
										 |  |  |             if (error) { | 
					
						
							|  |  |  |                 ovs_fatal(0, "%s", error); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-07-28 15:18:25 -07:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-23 11:24:38 -07:00
										 |  |  |         case OPT_UNIXCTL: | 
					
						
							|  |  |  |             unixctl_path = optarg; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |         case 'h': | 
					
						
							|  |  |  |             usage(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         VLOG_OPTION_HANDLERS | 
					
						
							| 
									
										
										
										
											2012-11-19 14:59:33 +09:00
										 |  |  |         OFP_VERSION_OPTION_HANDLERS | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |         DAEMON_OPTION_HANDLERS | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-06 14:35:20 -08:00
										 |  |  |         STREAM_SSL_OPTION_HANDLERS | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         case OPT_PEER_CA_CERT: | 
					
						
							| 
									
										
										
										
											2010-01-06 14:35:20 -08:00
										 |  |  |             stream_ssl_set_peer_ca_cert_file(optarg); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case '?': | 
					
						
							|  |  |  |             exit(EXIT_FAILURE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             abort(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     free(short_options); | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-22 10:32:02 -07:00
										 |  |  |     if (!simap_is_empty(&port_queues) || default_queue != UINT32_MAX) { | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  |         if (action_normal) { | 
					
						
							|  |  |  |             ovs_error(0, "queue IDs are incompatible with -N or --normal; " | 
					
						
							|  |  |  |                       "not using OFPP_NORMAL"); | 
					
						
							|  |  |  |             action_normal = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!learn_macs) { | 
					
						
							|  |  |  |             ovs_error(0, "queue IDs are incompatible with -H or --hub; " | 
					
						
							|  |  |  |                       "not acting as hub"); | 
					
						
							|  |  |  |             learn_macs = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | usage(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     printf("%s: OpenFlow controller\n" | 
					
						
							|  |  |  |            "usage: %s [OPTIONS] METHOD\n" | 
					
						
							|  |  |  |            "where METHOD is any OpenFlow connection method.\n", | 
					
						
							|  |  |  |            program_name, program_name); | 
					
						
							|  |  |  |     vconn_usage(true, true, false); | 
					
						
							|  |  |  |     daemon_usage(); | 
					
						
							| 
									
										
										
										
											2012-11-19 14:59:33 +09:00
										 |  |  |     ofp_version_usage(); | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |     vlog_usage(); | 
					
						
							|  |  |  |     printf("\nOther options:\n" | 
					
						
							|  |  |  |            "  -H, --hub               act as hub instead of learning switch\n" | 
					
						
							|  |  |  |            "  -n, --noflow            pass traffic, but don't add flows\n" | 
					
						
							|  |  |  |            "  --max-idle=SECS         max idle time for new flows\n" | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  |            "  -N, --normal            use OFPP_NORMAL action\n" | 
					
						
							| 
									
										
										
										
											2011-06-01 09:09:20 -07:00
										 |  |  |            "  -w, --wildcards[=MASK]  wildcard (specified) bits in flows\n" | 
					
						
							| 
									
										
										
										
											2010-10-01 13:41:40 -07:00
										 |  |  |            "  -q, --queue=QUEUE-ID    OpenFlow queue ID to use for output\n" | 
					
						
							|  |  |  |            "  -Q PORT-NAME:QUEUE-ID   use QUEUE-ID for frames from PORT-NAME\n" | 
					
						
							| 
									
										
										
										
											2010-07-28 15:18:25 -07:00
										 |  |  |            "  --with-flows FILE       use the flows from FILE\n" | 
					
						
							| 
									
										
										
										
											2010-03-23 11:24:38 -07:00
										 |  |  |            "  --unixctl=SOCKET        override default control socket name\n" | 
					
						
							| 
									
										
										
										
											2009-07-08 13:19:16 -07:00
										 |  |  |            "  -h, --help              display this help message\n" | 
					
						
							|  |  |  |            "  -V, --version           display version information\n"); | 
					
						
							|  |  |  |     exit(EXIT_SUCCESS); | 
					
						
							|  |  |  | } |