]> git.proxmox.com Git - mirror_ovs.git/blame - utilities/ovs-controller.c
openflow-1.3.h: Fix typo
[mirror_ovs.git] / utilities / ovs-controller.c
CommitLineData
064af421 1/*
82c8c53c 2 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
064af421 3 *
a14bc59f
BP
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
064af421 7 *
a14bc59f
BP
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
064af421
BP
15 */
16
17#include <config.h>
18
19#include <errno.h>
20#include <getopt.h>
21#include <limits.h>
22#include <signal.h>
23#include <stdlib.h>
882c2399 24#include <stdio.h>
064af421
BP
25#include <string.h>
26
27#include "command-line.h"
28#include "compiler.h"
29#include "daemon.h"
064af421 30#include "learning-switch.h"
09913dfd 31#include "ofp-parse.h"
be721d87 32#include "ofp-version-opt.h"
064af421
BP
33#include "ofpbuf.h"
34#include "openflow/openflow.h"
35#include "poll-loop.h"
36#include "rconn.h"
44bac24b 37#include "simap.h"
fe55ad15 38#include "stream-ssl.h"
064af421
BP
39#include "timeval.h"
40#include "unixctl.h"
41#include "util.h"
064af421 42#include "vconn.h"
064af421 43#include "vlog.h"
f125905c 44#include "socket-util.h"
7a25bd99 45#include "ofp-util.h"
5136ce49 46
d98e6007 47VLOG_DEFINE_THIS_MODULE(controller);
064af421
BP
48
49#define MAX_SWITCHES 16
50#define MAX_LISTENERS 16
51
52struct switch_ {
53 struct lswitch *lswitch;
064af421
BP
54};
55
d4cdc6b4 56/* -H, --hub: Learn the ports on which MAC addresses appear? */
064af421
BP
57static bool learn_macs = true;
58
d4cdc6b4
BP
59/* -n, --noflow: Set up flows? (If not, every packet is processed at the
60 * controller.) */
d6fbec6d 61static bool set_up_flows = true;
064af421 62
9af9e2e8
JT
63/* -N, --normal: Use "NORMAL" action instead of explicit port? */
64static bool action_normal = false;
65
eec25dc1 66/* -w, --wildcard: 0 to disable wildcard flow entries, an OFPFW10_* bitmask to
7286b1e1
BP
67 * enable specific wildcards, or UINT32_MAX to use the default wildcards. */
68static uint32_t wildcards = 0;
9af9e2e8 69
064af421
BP
70/* --max-idle: Maximum idle time, in seconds, before flows expire. */
71static int max_idle = 60;
72
7778bd15
BP
73/* --mute: If true, accept connections from switches but do not reply to any
74 * of their messages (for debugging fail-open mode). */
75static bool mute = false;
76
d4cdc6b4
BP
77/* -q, --queue: default OpenFlow queue, none if UINT32_MAX. */
78static uint32_t default_queue = UINT32_MAX;
79
44bac24b
BP
80/* -Q, --port-queue: map from port name to port number. */
81static struct simap port_queues = SIMAP_INITIALIZER(&port_queues);
611e9a35 82
27527aa0
BP
83/* --with-flows: Flows to send to switch. */
84static struct ofputil_flow_mod *default_flows;
85static size_t n_default_flows;
db0b6c29 86static enum ofputil_protocol usable_protocols;
882c2399 87
b66bdf30
BP
88/* --unixctl: Name of unixctl socket, or null to use the default. */
89static char *unixctl_path = NULL;
90
58bdd092 91static void new_switch(struct switch_ *, struct vconn *);
064af421
BP
92static void parse_options(int argc, char *argv[]);
93static void usage(void) NO_RETURN;
94
95int
96main(int argc, char *argv[])
97{
98 struct unixctl_server *unixctl;
99 struct switch_ switches[MAX_SWITCHES];
100 struct pvconn *listeners[MAX_LISTENERS];
101 int n_switches, n_listeners;
102 int retval;
103 int i;
104
40f0707c 105 proctitle_init(argc, argv);
064af421 106 set_program_name(argv[0]);
064af421
BP
107 parse_options(argc, argv);
108 signal(SIGPIPE, SIG_IGN);
109
110 if (argc - optind < 1) {
111 ovs_fatal(0, "at least one vconn argument required; "
112 "use --help for usage");
113 }
114
115 n_switches = n_listeners = 0;
116 for (i = optind; i < argc; i++) {
117 const char *name = argv[i];
118 struct vconn *vconn;
064af421 119
82c8c53c
BP
120 retval = vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT,
121 &vconn);
064af421
BP
122 if (!retval) {
123 if (n_switches >= MAX_SWITCHES) {
124 ovs_fatal(0, "max %d switch connections", n_switches);
125 }
58bdd092 126 new_switch(&switches[n_switches++], vconn);
064af421
BP
127 continue;
128 } else if (retval == EAFNOSUPPORT) {
129 struct pvconn *pvconn;
be721d87 130 retval = pvconn_open(name, get_allowed_ofp_versions(),
82c8c53c 131 DSCP_DEFAULT, &pvconn);
064af421
BP
132 if (!retval) {
133 if (n_listeners >= MAX_LISTENERS) {
134 ovs_fatal(0, "max %d passive connections", n_listeners);
135 }
136 listeners[n_listeners++] = pvconn;
137 }
138 }
139 if (retval) {
10a89ef0 140 VLOG_ERR("%s: connect: %s", name, ovs_strerror(retval));
064af421
BP
141 }
142 }
143 if (n_switches == 0 && n_listeners == 0) {
144 ovs_fatal(0, "no active or passive switch connections");
145 }
146
95440284 147 daemonize_start();
064af421 148
b66bdf30 149 retval = unixctl_server_create(unixctl_path, &unixctl);
064af421 150 if (retval) {
4d12270a 151 exit(EXIT_FAILURE);
064af421
BP
152 }
153
95440284
BP
154 daemonize_complete();
155
064af421 156 while (n_switches > 0 || n_listeners > 0) {
064af421
BP
157 /* Accept connections on listening vconns. */
158 for (i = 0; i < n_listeners && n_switches < MAX_SWITCHES; ) {
159 struct vconn *new_vconn;
064af421 160
7a25bd99 161 retval = pvconn_accept(listeners[i], &new_vconn);
064af421
BP
162 if (!retval || retval == EAGAIN) {
163 if (!retval) {
58bdd092 164 new_switch(&switches[n_switches++], new_vconn);
064af421
BP
165 }
166 i++;
167 } else {
168 pvconn_close(listeners[i]);
169 listeners[i] = listeners[--n_listeners];
170 }
171 }
172
002c3f17
BP
173 /* Do some switching work. . */
174 for (i = 0; i < n_switches; ) {
064af421 175 struct switch_ *this = &switches[i];
ba186119 176 lswitch_run(this->lswitch);
002c3f17
BP
177 if (lswitch_is_alive(this->lswitch)) {
178 i++;
179 } else {
180 lswitch_destroy(this->lswitch);
181 switches[i] = switches[--n_switches];
182 }
064af421
BP
183 }
184
185 unixctl_server_run(unixctl);
186
187 /* Wait for something to happen. */
188 if (n_switches < MAX_SWITCHES) {
189 for (i = 0; i < n_listeners; i++) {
190 pvconn_wait(listeners[i]);
191 }
192 }
193 for (i = 0; i < n_switches; i++) {
194 struct switch_ *sw = &switches[i];
064af421
BP
195 lswitch_wait(sw->lswitch);
196 }
197 unixctl_server_wait(unixctl);
198 poll_block();
199 }
200
201 return 0;
202}
203
204static void
58bdd092 205new_switch(struct switch_ *sw, struct vconn *vconn)
064af421 206{
ad67e568 207 struct lswitch_config cfg;
002c3f17 208 struct rconn *rconn;
ad67e568 209
be721d87 210 rconn = rconn_create(60, 0, DSCP_DEFAULT, get_allowed_ofp_versions());
002c3f17 211 rconn_connect_unreliably(rconn, vconn, NULL);
882c2399 212
ad67e568
BP
213 cfg.mode = (action_normal ? LSW_NORMAL
214 : learn_macs ? LSW_LEARN
215 : LSW_FLOOD);
7286b1e1 216 cfg.wildcards = wildcards;
ad67e568 217 cfg.max_idle = set_up_flows ? max_idle : -1;
27527aa0
BP
218 cfg.default_flows = default_flows;
219 cfg.n_default_flows = n_default_flows;
db0b6c29 220 cfg.usable_protocols = usable_protocols;
d4cdc6b4
BP
221 cfg.default_queue = default_queue;
222 cfg.port_queues = &port_queues;
002c3f17
BP
223 cfg.mute = mute;
224 sw->lswitch = lswitch_create(rconn, &cfg);
064af421
BP
225}
226
d4cdc6b4
BP
227static void
228add_port_queue(char *s)
229{
230 char *save_ptr = NULL;
231 char *port_name;
232 char *queue_id;
233
234 port_name = strtok_r(s, ":", &save_ptr);
235 queue_id = strtok_r(NULL, "", &save_ptr);
236 if (!queue_id) {
237 ovs_fatal(0, "argument to -Q or --port-queue should take the form "
238 "\"<port-name>:<queue-id>\"");
239 }
240
44bac24b 241 if (!simap_put(&port_queues, port_name, atoi(queue_id))) {
d4cdc6b4
BP
242 ovs_fatal(0, "<port-name> arguments for -Q or --port-queue must "
243 "be unique");
244 }
245}
246
064af421
BP
247static void
248parse_options(int argc, char *argv[])
249{
250 enum {
251 OPT_MAX_IDLE = UCHAR_MAX + 1,
252 OPT_PEER_CA_CERT,
7778bd15 253 OPT_MUTE,
882c2399 254 OPT_WITH_FLOWS,
b66bdf30 255 OPT_UNIXCTL,
8274ae95 256 VLOG_OPTION_ENUMS,
be721d87
SH
257 DAEMON_OPTION_ENUMS,
258 OFP_VERSION_OPTION_ENUMS
064af421 259 };
07fc4ed3 260 static const struct option long_options[] = {
e3c17733
BP
261 {"hub", no_argument, NULL, 'H'},
262 {"noflow", no_argument, NULL, 'n'},
263 {"normal", no_argument, NULL, 'N'},
7286b1e1 264 {"wildcards", optional_argument, NULL, 'w'},
e3c17733
BP
265 {"max-idle", required_argument, NULL, OPT_MAX_IDLE},
266 {"mute", no_argument, NULL, OPT_MUTE},
267 {"queue", required_argument, NULL, 'q'},
268 {"port-queue", required_argument, NULL, 'Q'},
269 {"with-flows", required_argument, NULL, OPT_WITH_FLOWS},
270 {"unixctl", required_argument, NULL, OPT_UNIXCTL},
271 {"help", no_argument, NULL, 'h'},
064af421 272 DAEMON_LONG_OPTIONS,
be721d87 273 OFP_VERSION_LONG_OPTIONS,
064af421 274 VLOG_LONG_OPTIONS,
bf8f2167 275 STREAM_SSL_LONG_OPTIONS,
e3c17733
BP
276 {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
277 {NULL, 0, NULL, 0},
064af421
BP
278 };
279 char *short_options = long_options_to_short_options(long_options);
280
281 for (;;) {
282 int indexptr;
bdda5aca 283 char *error;
064af421
BP
284 int c;
285
286 c = getopt_long(argc, argv, short_options, long_options, &indexptr);
287 if (c == -1) {
288 break;
289 }
290
291 switch (c) {
292 case 'H':
293 learn_macs = false;
294 break;
295
296 case 'n':
d6fbec6d 297 set_up_flows = false;
064af421
BP
298 break;
299
7778bd15
BP
300 case OPT_MUTE:
301 mute = true;
302 break;
303
9af9e2e8
JT
304 case 'N':
305 action_normal = true;
306 break;
307
308 case 'w':
7286b1e1 309 wildcards = optarg ? strtol(optarg, NULL, 16) : UINT32_MAX;
9af9e2e8
JT
310 break;
311
064af421
BP
312 case OPT_MAX_IDLE:
313 if (!strcmp(optarg, "permanent")) {
314 max_idle = OFP_FLOW_PERMANENT;
315 } else {
316 max_idle = atoi(optarg);
317 if (max_idle < 1 || max_idle > 65535) {
318 ovs_fatal(0, "--max-idle argument must be between 1 and "
319 "65535 or the word 'permanent'");
320 }
321 }
322 break;
323
611e9a35 324 case 'q':
d4cdc6b4
BP
325 default_queue = atoi(optarg);
326 break;
327
328 case 'Q':
329 add_port_queue(optarg);
611e9a35
BP
330 break;
331
882c2399 332 case OPT_WITH_FLOWS:
bdda5aca 333 error = parse_ofp_flow_mod_file(optarg, OFPFC_ADD, &default_flows,
db0b6c29
JR
334 &n_default_flows,
335 &usable_protocols);
bdda5aca
BP
336 if (error) {
337 ovs_fatal(0, "%s", error);
338 }
882c2399
JP
339 break;
340
b66bdf30
BP
341 case OPT_UNIXCTL:
342 unixctl_path = optarg;
343 break;
344
064af421
BP
345 case 'h':
346 usage();
347
064af421 348 VLOG_OPTION_HANDLERS
be721d87 349 OFP_VERSION_OPTION_HANDLERS
064af421
BP
350 DAEMON_OPTION_HANDLERS
351
fe55ad15 352 STREAM_SSL_OPTION_HANDLERS
064af421
BP
353
354 case OPT_PEER_CA_CERT:
fe55ad15 355 stream_ssl_set_peer_ca_cert_file(optarg);
064af421 356 break;
064af421
BP
357
358 case '?':
359 exit(EXIT_FAILURE);
360
361 default:
362 abort();
363 }
364 }
365 free(short_options);
d4cdc6b4 366
44bac24b 367 if (!simap_is_empty(&port_queues) || default_queue != UINT32_MAX) {
d4cdc6b4
BP
368 if (action_normal) {
369 ovs_error(0, "queue IDs are incompatible with -N or --normal; "
370 "not using OFPP_NORMAL");
371 action_normal = false;
372 }
373
374 if (!learn_macs) {
375 ovs_error(0, "queue IDs are incompatible with -H or --hub; "
376 "not acting as hub");
377 learn_macs = true;
378 }
379 }
064af421
BP
380}
381
382static void
383usage(void)
384{
385 printf("%s: OpenFlow controller\n"
386 "usage: %s [OPTIONS] METHOD\n"
387 "where METHOD is any OpenFlow connection method.\n",
388 program_name, program_name);
389 vconn_usage(true, true, false);
390 daemon_usage();
be721d87 391 ofp_version_usage();
064af421
BP
392 vlog_usage();
393 printf("\nOther options:\n"
394 " -H, --hub act as hub instead of learning switch\n"
395 " -n, --noflow pass traffic, but don't add flows\n"
396 " --max-idle=SECS max idle time for new flows\n"
d4cdc6b4 397 " -N, --normal use OFPP_NORMAL action\n"
7286b1e1 398 " -w, --wildcards[=MASK] wildcard (specified) bits in flows\n"
d4cdc6b4
BP
399 " -q, --queue=QUEUE-ID OpenFlow queue ID to use for output\n"
400 " -Q PORT-NAME:QUEUE-ID use QUEUE-ID for frames from PORT-NAME\n"
882c2399 401 " --with-flows FILE use the flows from FILE\n"
b66bdf30 402 " --unixctl=SOCKET override default control socket name\n"
064af421
BP
403 " -h, --help display this help message\n"
404 " -V, --version display version information\n");
405 exit(EXIT_SUCCESS);
406}