]>
Commit | Line | Data |
---|---|---|
a416ff28 RB |
1 | /* |
2 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
3 | * you may not use this file except in compliance with the License. | |
4 | * You may obtain a copy of the License at: | |
5 | * | |
6 | * http://www.apache.org/licenses/LICENSE-2.0 | |
7 | * | |
8 | * Unless required by applicable law or agreed to in writing, software | |
9 | * distributed under the License is distributed on an "AS IS" BASIS, | |
10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
11 | * See the License for the specific language governing permissions and | |
12 | * limitations under the License. | |
13 | */ | |
14 | ||
15 | #include <config.h> | |
16 | ||
17 | #include <getopt.h> | |
bf5fa52a | 18 | #include <inttypes.h> |
a416ff28 RB |
19 | #include <stdlib.h> |
20 | #include <stdio.h> | |
21 | ||
22 | #include "command-line.h" | |
23 | #include "dirs.h" | |
24 | #include "fatal-signal.h" | |
e3df8838 | 25 | #include "ovn/lib/ovn-nb-idl.h" |
a416ff28 | 26 | #include "poll-loop.h" |
afc9da0b | 27 | #include "process.h" |
a416ff28 RB |
28 | #include "stream.h" |
29 | #include "stream-ssl.h" | |
30 | #include "util.h" | |
31 | #include "openvswitch/vlog.h" | |
32 | ||
33 | VLOG_DEFINE_THIS_MODULE(ovn_nbctl); | |
34 | ||
35 | struct nbctl_context { | |
36 | struct ovsdb_idl *idl; | |
37 | struct ovsdb_idl_txn *txn; | |
38 | }; | |
39 | ||
40 | static const char *db; | |
41 | ||
42 | static const char *default_db(void); | |
43 | ||
44 | static void | |
45 | usage(void) | |
46 | { | |
47 | printf("\ | |
48 | %s: OVN northbound DB management utility\n\ | |
49 | usage: %s [OPTIONS] COMMAND [ARG...]\n\ | |
50 | \n\ | |
907a0edf JP |
51 | General commands:\n\ |
52 | show print overview of database contents\n\ | |
6cfe8161 | 53 | show LSWITCH print overview of database contents for LSWITCH\n\ |
907a0edf | 54 | \n\ |
a367622a JP |
55 | Logical switch commands:\n\ |
56 | lswitch-add [LSWITCH] create a logical switch named LSWITCH\n\ | |
57 | lswitch-del LSWITCH delete LSWITCH and all its ports\n\ | |
58 | lswitch-list print the names of all logical switches\n\ | |
59 | lswitch-set-external-id LSWITCH KEY [VALUE]\n\ | |
60 | set or delete an external-id on LSWITCH\n\ | |
61 | lswitch-get-external-id LSWITCH [KEY]\n\ | |
62 | list one or all external-ids on LSWITCH\n\ | |
a416ff28 | 63 | \n\ |
a367622a JP |
64 | Logical port commands:\n\ |
65 | lport-add LSWITCH LPORT add logical port LPORT on LSWITCH\n\ | |
bf5fa52a RB |
66 | lport-add LSWITCH LPORT PARENT TAG\n\ |
67 | add logical port LPORT on LSWITCH with PARENT\n\ | |
68 | on TAG\n\ | |
a367622a JP |
69 | lport-del LPORT delete LPORT from its attached switch\n\ |
70 | lport-list LSWITCH print the names of all logical ports on LSWITCH\n\ | |
bf5fa52a RB |
71 | lport-get-parent LPORT get the parent of LPORT if set\n\ |
72 | lport-get-tag LPORT get the LPORT's tag if set\n\ | |
a367622a JP |
73 | lport-set-external-id LPORT KEY [VALUE]\n\ |
74 | set or delete an external-id on LPORT\n\ | |
75 | lport-get-external-id LPORT [KEY]\n\ | |
76 | list one or all external-ids on LPORT\n\ | |
2de82d90 BP |
77 | lport-set-macs LPORT [MAC]...\n\ |
78 | set MAC addresses for LPORT.\n\ | |
a367622a | 79 | lport-get-macs LPORT get a list of MAC addresses on LPORT\n\ |
92207865 BP |
80 | lport-set-port-security LPORT [ADDRS]...\n\ |
81 | set port security addresses for LPORT.\n\ | |
82 | lport-get-port-security LPORT get LPORT's port security addresses\n\ | |
a367622a | 83 | lport-get-up LPORT get state of LPORT ('up' or 'down')\n\ |
a416ff28 RB |
84 | \n\ |
85 | Options:\n\ | |
86 | --db=DATABASE connect to DATABASE\n\ | |
87 | (default: %s)\n\ | |
88 | -h, --help display this help message\n\ | |
89 | -o, --options list available options\n\ | |
90 | -V, --version display version information\n\ | |
91 | ", program_name, program_name, default_db()); | |
92 | vlog_usage(); | |
93 | stream_usage("database", true, true, false); | |
94 | } | |
95 | \f | |
96 | static const struct nbrec_logical_switch * | |
97 | lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id) | |
98 | { | |
99 | const struct nbrec_logical_switch *lswitch = NULL; | |
100 | bool is_uuid = false; | |
101 | bool duplicate = false; | |
102 | struct uuid lswitch_uuid; | |
103 | ||
104 | if (uuid_from_string(&lswitch_uuid, id)) { | |
105 | is_uuid = true; | |
106 | lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl, | |
107 | &lswitch_uuid); | |
c1f4da63 RB |
108 | } |
109 | ||
110 | if (!lswitch) { | |
a416ff28 RB |
111 | const struct nbrec_logical_switch *iter; |
112 | ||
113 | NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) { | |
114 | if (strcmp(iter->name, id)) { | |
115 | continue; | |
116 | } | |
117 | if (lswitch) { | |
118 | VLOG_WARN("There is more than one logical switch named '%s'. " | |
119 | "Use a UUID.", id); | |
120 | lswitch = NULL; | |
121 | duplicate = true; | |
122 | break; | |
123 | } | |
124 | lswitch = iter; | |
125 | } | |
126 | } | |
127 | ||
128 | if (!lswitch && !duplicate) { | |
129 | VLOG_WARN("lswitch not found for %s: '%s'", | |
130 | is_uuid ? "UUID" : "name", id); | |
131 | } | |
132 | ||
133 | return lswitch; | |
134 | } | |
135 | ||
907a0edf JP |
136 | static void |
137 | print_lswitch(const struct nbctl_context *nb_ctx, | |
138 | const struct nbrec_logical_switch *lswitch) | |
139 | { | |
140 | const struct nbrec_logical_port *lport; | |
141 | ||
142 | printf(" lswitch "UUID_FMT" (%s)\n", | |
143 | UUID_ARGS(&lswitch->header_.uuid), lswitch->name); | |
144 | ||
145 | NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) { | |
146 | int i; | |
147 | ||
148 | if (lport->lswitch == lswitch) { | |
149 | printf(" lport %s\n", lport->name); | |
150 | if (lport->parent_name && lport->n_tag) { | |
151 | printf(" parent: %s, tag:%"PRIu64"\n", | |
152 | lport->parent_name, lport->tag[0]); | |
153 | } | |
154 | if (lport->n_macs) { | |
155 | printf(" macs:"); | |
156 | for (i=0; i < lport->n_macs; i++) { | |
157 | printf(" %s", lport->macs[i]); | |
158 | } | |
159 | printf("\n"); | |
160 | } | |
161 | } | |
162 | } | |
163 | } | |
164 | ||
165 | static void | |
166 | do_show(struct ovs_cmdl_context *ctx) | |
167 | { | |
168 | struct nbctl_context *nb_ctx = ctx->pvt; | |
169 | const struct nbrec_logical_switch *lswitch; | |
170 | ||
171 | if (ctx->argc == 2) { | |
172 | lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); | |
173 | if (lswitch) { | |
174 | print_lswitch(nb_ctx, lswitch); | |
175 | } | |
176 | } else { | |
177 | NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) { | |
178 | print_lswitch(nb_ctx, lswitch); | |
179 | } | |
180 | } | |
181 | } | |
182 | ||
a416ff28 RB |
183 | static void |
184 | do_lswitch_add(struct ovs_cmdl_context *ctx) | |
185 | { | |
186 | struct nbctl_context *nb_ctx = ctx->pvt; | |
187 | struct nbrec_logical_switch *lswitch; | |
188 | ||
189 | lswitch = nbrec_logical_switch_insert(nb_ctx->txn); | |
190 | if (ctx->argc == 2) { | |
191 | nbrec_logical_switch_set_name(lswitch, ctx->argv[1]); | |
192 | } | |
193 | } | |
194 | ||
195 | static void | |
196 | do_lswitch_del(struct ovs_cmdl_context *ctx) | |
197 | { | |
198 | struct nbctl_context *nb_ctx = ctx->pvt; | |
199 | const char *id = ctx->argv[1]; | |
200 | const struct nbrec_logical_switch *lswitch; | |
201 | ||
202 | lswitch = lswitch_by_name_or_uuid(nb_ctx, id); | |
203 | if (!lswitch) { | |
204 | return; | |
205 | } | |
206 | ||
207 | nbrec_logical_switch_delete(lswitch); | |
208 | } | |
209 | ||
210 | static void | |
211 | do_lswitch_list(struct ovs_cmdl_context *ctx) | |
212 | { | |
213 | struct nbctl_context *nb_ctx = ctx->pvt; | |
214 | const struct nbrec_logical_switch *lswitch; | |
215 | ||
216 | NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) { | |
217 | printf(UUID_FMT " (%s)\n", | |
218 | UUID_ARGS(&lswitch->header_.uuid), lswitch->name); | |
219 | } | |
220 | } | |
221 | ||
222 | static void | |
223 | do_lswitch_set_external_id(struct ovs_cmdl_context *ctx) | |
224 | { | |
225 | struct nbctl_context *nb_ctx = ctx->pvt; | |
226 | const char *id = ctx->argv[1]; | |
227 | const struct nbrec_logical_switch *lswitch; | |
228 | struct smap new_external_ids; | |
229 | ||
230 | lswitch = lswitch_by_name_or_uuid(nb_ctx, id); | |
231 | if (!lswitch) { | |
232 | return; | |
233 | } | |
234 | ||
235 | smap_init(&new_external_ids); | |
236 | smap_clone(&new_external_ids, &lswitch->external_ids); | |
237 | if (ctx->argc == 4) { | |
238 | smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]); | |
239 | } else { | |
240 | smap_remove(&new_external_ids, ctx->argv[2]); | |
241 | } | |
242 | nbrec_logical_switch_set_external_ids(lswitch, &new_external_ids); | |
243 | smap_destroy(&new_external_ids); | |
244 | } | |
245 | ||
246 | static void | |
247 | do_lswitch_get_external_id(struct ovs_cmdl_context *ctx) | |
248 | { | |
249 | struct nbctl_context *nb_ctx = ctx->pvt; | |
250 | const char *id = ctx->argv[1]; | |
251 | const struct nbrec_logical_switch *lswitch; | |
252 | ||
253 | lswitch = lswitch_by_name_or_uuid(nb_ctx, id); | |
254 | if (!lswitch) { | |
255 | return; | |
256 | } | |
257 | ||
258 | if (ctx->argc == 3) { | |
259 | const char *key = ctx->argv[2]; | |
260 | const char *value; | |
261 | ||
262 | /* List one external ID */ | |
263 | ||
264 | value = smap_get(&lswitch->external_ids, key); | |
ee98038f | 265 | if (value) { |
a416ff28 | 266 | printf("%s\n", value); |
a416ff28 RB |
267 | } |
268 | } else { | |
269 | struct smap_node *node; | |
270 | ||
271 | /* List all external IDs */ | |
272 | ||
273 | SMAP_FOR_EACH(node, &lswitch->external_ids) { | |
274 | printf("%s=%s\n", node->key, node->value); | |
275 | } | |
276 | } | |
277 | } | |
278 | \f | |
279 | static const struct nbrec_logical_port * | |
280 | lport_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id) | |
281 | { | |
282 | const struct nbrec_logical_port *lport = NULL; | |
283 | bool is_uuid = false; | |
284 | struct uuid lport_uuid; | |
285 | ||
286 | if (uuid_from_string(&lport_uuid, id)) { | |
287 | is_uuid = true; | |
288 | lport = nbrec_logical_port_get_for_uuid(nb_ctx->idl, &lport_uuid); | |
c1f4da63 RB |
289 | } |
290 | ||
291 | if (!lport) { | |
a416ff28 RB |
292 | NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) { |
293 | if (!strcmp(lport->name, id)) { | |
294 | break; | |
295 | } | |
296 | } | |
297 | } | |
298 | ||
299 | if (!lport) { | |
300 | VLOG_WARN("lport not found for %s: '%s'", | |
301 | is_uuid ? "UUID" : "name", id); | |
302 | } | |
303 | ||
304 | return lport; | |
305 | } | |
306 | ||
307 | static void | |
308 | do_lport_add(struct ovs_cmdl_context *ctx) | |
309 | { | |
310 | struct nbctl_context *nb_ctx = ctx->pvt; | |
311 | struct nbrec_logical_port *lport; | |
312 | const struct nbrec_logical_switch *lswitch; | |
bf5fa52a | 313 | int64_t tag; |
a416ff28 | 314 | |
c8453791 | 315 | lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); |
a416ff28 RB |
316 | if (!lswitch) { |
317 | return; | |
318 | } | |
319 | ||
bf5fa52a RB |
320 | if (ctx->argc != 3 && ctx->argc != 5) { |
321 | /* If a parent_name is specififed, a tag must be specified as well. */ | |
322 | VLOG_WARN("Invalid arguments to lport-add."); | |
323 | return; | |
324 | } | |
325 | ||
326 | if (ctx->argc == 5) { | |
327 | /* Validate tag. */ | |
328 | if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) { | |
329 | VLOG_WARN("Invalid tag '%s'", ctx->argv[4]); | |
330 | return; | |
331 | } | |
332 | } | |
333 | ||
334 | /* Finally, create the transaction. */ | |
a416ff28 | 335 | lport = nbrec_logical_port_insert(nb_ctx->txn); |
c8453791 | 336 | nbrec_logical_port_set_name(lport, ctx->argv[2]); |
a416ff28 | 337 | nbrec_logical_port_set_lswitch(lport, lswitch); |
bf5fa52a RB |
338 | if (ctx->argc == 5) { |
339 | nbrec_logical_port_set_parent_name(lport, ctx->argv[3]); | |
340 | nbrec_logical_port_set_tag(lport, &tag, 1); | |
341 | } | |
a416ff28 RB |
342 | } |
343 | ||
344 | static void | |
345 | do_lport_del(struct ovs_cmdl_context *ctx) | |
346 | { | |
347 | struct nbctl_context *nb_ctx = ctx->pvt; | |
348 | const struct nbrec_logical_port *lport; | |
349 | ||
350 | lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]); | |
351 | if (!lport) { | |
352 | return; | |
353 | } | |
354 | ||
355 | nbrec_logical_port_delete(lport); | |
356 | } | |
357 | ||
358 | static bool | |
359 | is_lswitch(const struct nbrec_logical_switch *lswitch, | |
360 | struct uuid *lswitch_uuid, const char *name) | |
361 | { | |
362 | if (lswitch_uuid) { | |
363 | return uuid_equals(lswitch_uuid, &lswitch->header_.uuid); | |
364 | } else { | |
365 | return !strcmp(lswitch->name, name); | |
366 | } | |
367 | } | |
368 | ||
369 | ||
370 | static void | |
371 | do_lport_list(struct ovs_cmdl_context *ctx) | |
372 | { | |
373 | struct nbctl_context *nb_ctx = ctx->pvt; | |
374 | const char *id = ctx->argv[1]; | |
375 | const struct nbrec_logical_port *lport; | |
376 | bool is_uuid = false; | |
377 | struct uuid lswitch_uuid; | |
378 | ||
379 | if (uuid_from_string(&lswitch_uuid, id)) { | |
380 | is_uuid = true; | |
381 | } | |
382 | ||
383 | NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) { | |
384 | bool match; | |
385 | if (is_uuid) { | |
386 | match = is_lswitch(lport->lswitch, &lswitch_uuid, NULL); | |
387 | } else { | |
388 | match = is_lswitch(lport->lswitch, NULL, id); | |
389 | } | |
390 | if (!match) { | |
391 | continue; | |
392 | } | |
393 | printf(UUID_FMT " (%s)\n", | |
394 | UUID_ARGS(&lport->header_.uuid), lport->name); | |
395 | } | |
396 | } | |
397 | ||
bf5fa52a RB |
398 | static void |
399 | do_lport_get_parent(struct ovs_cmdl_context *ctx) | |
400 | { | |
401 | struct nbctl_context *nb_ctx = ctx->pvt; | |
402 | const struct nbrec_logical_port *lport; | |
403 | ||
404 | lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]); | |
405 | if (!lport) { | |
406 | return; | |
407 | } | |
408 | ||
409 | if (lport->parent_name) { | |
410 | printf("%s\n", lport->parent_name); | |
411 | } | |
412 | } | |
413 | ||
414 | static void | |
415 | do_lport_get_tag(struct ovs_cmdl_context *ctx) | |
416 | { | |
417 | struct nbctl_context *nb_ctx = ctx->pvt; | |
418 | const struct nbrec_logical_port *lport; | |
419 | ||
420 | lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]); | |
421 | if (!lport) { | |
422 | return; | |
423 | } | |
424 | ||
425 | if (lport->n_tag > 0) { | |
426 | printf("%"PRId64"\n", lport->tag[0]); | |
427 | } | |
428 | } | |
429 | ||
a416ff28 RB |
430 | static void |
431 | do_lport_set_external_id(struct ovs_cmdl_context *ctx) | |
432 | { | |
433 | struct nbctl_context *nb_ctx = ctx->pvt; | |
434 | const char *id = ctx->argv[1]; | |
435 | const struct nbrec_logical_port *lport; | |
436 | struct smap new_external_ids; | |
437 | ||
438 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
439 | if (!lport) { | |
440 | return; | |
441 | } | |
442 | ||
443 | smap_init(&new_external_ids); | |
444 | smap_clone(&new_external_ids, &lport->external_ids); | |
445 | if (ctx->argc == 4) { | |
446 | smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]); | |
447 | } else { | |
448 | smap_remove(&new_external_ids, ctx->argv[2]); | |
449 | } | |
450 | nbrec_logical_port_set_external_ids(lport, &new_external_ids); | |
451 | smap_destroy(&new_external_ids); | |
452 | } | |
453 | ||
454 | static void | |
455 | do_lport_get_external_id(struct ovs_cmdl_context *ctx) | |
456 | { | |
457 | struct nbctl_context *nb_ctx = ctx->pvt; | |
458 | const char *id = ctx->argv[1]; | |
459 | const struct nbrec_logical_port *lport; | |
460 | ||
461 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
462 | if (!lport) { | |
463 | return; | |
464 | } | |
465 | ||
466 | if (ctx->argc == 3) { | |
467 | const char *key = ctx->argv[2]; | |
468 | const char *value; | |
469 | ||
470 | /* List one external ID */ | |
471 | ||
472 | value = smap_get(&lport->external_ids, key); | |
ee98038f | 473 | if (value) { |
a416ff28 | 474 | printf("%s\n", value); |
a416ff28 RB |
475 | } |
476 | } else { | |
477 | struct smap_node *node; | |
478 | ||
479 | /* List all external IDs */ | |
480 | ||
481 | SMAP_FOR_EACH(node, &lport->external_ids) { | |
482 | printf("%s=%s\n", node->key, node->value); | |
483 | } | |
484 | } | |
485 | } | |
486 | ||
487 | static void | |
488 | do_lport_set_macs(struct ovs_cmdl_context *ctx) | |
489 | { | |
490 | struct nbctl_context *nb_ctx = ctx->pvt; | |
491 | const char *id = ctx->argv[1]; | |
492 | const struct nbrec_logical_port *lport; | |
493 | ||
494 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
495 | if (!lport) { | |
496 | return; | |
497 | } | |
498 | ||
499 | nbrec_logical_port_set_macs(lport, | |
500 | (const char **) ctx->argv + 2, ctx->argc - 2); | |
501 | } | |
502 | ||
503 | static void | |
504 | do_lport_get_macs(struct ovs_cmdl_context *ctx) | |
505 | { | |
506 | struct nbctl_context *nb_ctx = ctx->pvt; | |
507 | const char *id = ctx->argv[1]; | |
508 | const struct nbrec_logical_port *lport; | |
509 | size_t i; | |
510 | ||
511 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
512 | if (!lport) { | |
513 | return; | |
514 | } | |
515 | ||
516 | for (i = 0; i < lport->n_macs; i++) { | |
517 | printf("%s\n", lport->macs[i]); | |
518 | } | |
519 | } | |
65fb6826 | 520 | |
92207865 BP |
521 | static void |
522 | do_lport_set_port_security(struct ovs_cmdl_context *ctx) | |
523 | { | |
524 | struct nbctl_context *nb_ctx = ctx->pvt; | |
525 | const char *id = ctx->argv[1]; | |
526 | const struct nbrec_logical_port *lport; | |
527 | ||
528 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
529 | if (!lport) { | |
530 | return; | |
531 | } | |
532 | ||
533 | nbrec_logical_port_set_port_security(lport, | |
534 | (const char **) ctx->argv + 2, ctx->argc - 2); | |
535 | } | |
536 | ||
537 | static void | |
538 | do_lport_get_port_security(struct ovs_cmdl_context *ctx) | |
539 | { | |
540 | struct nbctl_context *nb_ctx = ctx->pvt; | |
541 | const char *id = ctx->argv[1]; | |
542 | const struct nbrec_logical_port *lport; | |
543 | size_t i; | |
544 | ||
545 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
546 | if (!lport) { | |
547 | return; | |
548 | } | |
549 | ||
550 | for (i = 0; i < lport->n_port_security; i++) { | |
551 | printf("%s\n", lport->port_security[i]); | |
552 | } | |
553 | } | |
554 | ||
65fb6826 RB |
555 | static void |
556 | do_lport_get_up(struct ovs_cmdl_context *ctx) | |
557 | { | |
558 | struct nbctl_context *nb_ctx = ctx->pvt; | |
559 | const char *id = ctx->argv[1]; | |
560 | const struct nbrec_logical_port *lport; | |
561 | ||
562 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
563 | if (!lport) { | |
564 | return; | |
565 | } | |
566 | ||
567 | printf("%s\n", (lport->up && *lport->up) ? "up" : "down"); | |
568 | } | |
a416ff28 RB |
569 | \f |
570 | static void | |
571 | parse_options(int argc, char *argv[]) | |
572 | { | |
573 | enum { | |
574 | VLOG_OPTION_ENUMS, | |
575 | }; | |
576 | static const struct option long_options[] = { | |
a7ac550b | 577 | {"db", required_argument, NULL, 'd'}, |
a416ff28 RB |
578 | {"help", no_argument, NULL, 'h'}, |
579 | {"options", no_argument, NULL, 'o'}, | |
580 | {"version", no_argument, NULL, 'V'}, | |
581 | VLOG_LONG_OPTIONS, | |
582 | STREAM_SSL_LONG_OPTIONS, | |
583 | {NULL, 0, NULL, 0}, | |
584 | }; | |
585 | char *short_options = ovs_cmdl_long_options_to_short_options(long_options); | |
586 | ||
587 | for (;;) { | |
588 | int c; | |
589 | ||
590 | c = getopt_long(argc, argv, short_options, long_options, NULL); | |
591 | if (c == -1) { | |
592 | break; | |
593 | } | |
594 | ||
595 | switch (c) { | |
596 | VLOG_OPTION_HANDLERS; | |
597 | STREAM_SSL_OPTION_HANDLERS; | |
598 | ||
599 | case 'd': | |
600 | db = optarg; | |
601 | break; | |
602 | ||
603 | case 'h': | |
604 | usage(); | |
605 | exit(EXIT_SUCCESS); | |
606 | ||
607 | case 'o': | |
608 | ovs_cmdl_print_options(long_options); | |
609 | exit(EXIT_SUCCESS); | |
610 | ||
611 | case 'V': | |
612 | ovs_print_version(0, 0); | |
613 | exit(EXIT_SUCCESS); | |
614 | ||
615 | default: | |
616 | break; | |
617 | } | |
618 | } | |
619 | ||
620 | if (!db) { | |
621 | db = default_db(); | |
622 | } | |
623 | ||
624 | free(short_options); | |
625 | } | |
626 | ||
627 | static const struct ovs_cmdl_command all_commands[] = { | |
907a0edf JP |
628 | { |
629 | .name = "show", | |
630 | .usage = "[LSWITCH]", | |
631 | .min_args = 0, | |
632 | .max_args = 1, | |
633 | .handler = do_show, | |
634 | }, | |
a416ff28 RB |
635 | { |
636 | .name = "lswitch-add", | |
a367622a | 637 | .usage = "[LSWITCH]", |
a416ff28 RB |
638 | .min_args = 0, |
639 | .max_args = 1, | |
640 | .handler = do_lswitch_add, | |
641 | }, | |
642 | { | |
643 | .name = "lswitch-del", | |
a367622a | 644 | .usage = "LSWITCH", |
a416ff28 RB |
645 | .min_args = 1, |
646 | .max_args = 1, | |
647 | .handler = do_lswitch_del, | |
648 | }, | |
649 | { | |
650 | .name = "lswitch-list", | |
651 | .usage = "", | |
652 | .min_args = 0, | |
653 | .max_args = 0, | |
654 | .handler = do_lswitch_list, | |
655 | }, | |
656 | { | |
657 | .name = "lswitch-set-external-id", | |
a367622a | 658 | .usage = "LSWITCH KEY [VALUE]", |
a416ff28 RB |
659 | .min_args = 2, |
660 | .max_args = 3, | |
661 | .handler = do_lswitch_set_external_id, | |
662 | }, | |
663 | { | |
664 | .name = "lswitch-get-external-id", | |
a367622a | 665 | .usage = "LSWITCH [KEY]", |
a416ff28 RB |
666 | .min_args = 1, |
667 | .max_args = 2, | |
668 | .handler = do_lswitch_get_external_id, | |
669 | }, | |
670 | { | |
671 | .name = "lport-add", | |
bf5fa52a | 672 | .usage = "LSWITCH LPORT [PARENT] [TAG]", |
a416ff28 | 673 | .min_args = 2, |
bf5fa52a | 674 | .max_args = 4, |
a416ff28 RB |
675 | .handler = do_lport_add, |
676 | }, | |
677 | { | |
678 | .name = "lport-del", | |
a367622a | 679 | .usage = "LPORT", |
a416ff28 RB |
680 | .min_args = 1, |
681 | .max_args = 1, | |
682 | .handler = do_lport_del, | |
683 | }, | |
684 | { | |
685 | .name = "lport-list", | |
a367622a | 686 | .usage = "LSWITCH", |
a416ff28 RB |
687 | .min_args = 1, |
688 | .max_args = 1, | |
689 | .handler = do_lport_list, | |
690 | }, | |
bf5fa52a RB |
691 | { |
692 | .name = "lport-get-parent", | |
693 | .usage = "LPORT", | |
694 | .min_args = 1, | |
695 | .max_args = 1, | |
696 | .handler = do_lport_get_parent, | |
697 | }, | |
698 | { | |
699 | .name = "lport-get-tag", | |
700 | .usage = "LPORT", | |
701 | .min_args = 1, | |
702 | .max_args = 1, | |
703 | .handler = do_lport_get_tag, | |
704 | }, | |
a416ff28 RB |
705 | { |
706 | .name = "lport-set-external-id", | |
a367622a | 707 | .usage = "LPORT KEY [VALUE]", |
a416ff28 RB |
708 | .min_args = 2, |
709 | .max_args = 3, | |
710 | .handler = do_lport_set_external_id, | |
711 | }, | |
712 | { | |
713 | .name = "lport-get-external-id", | |
a367622a | 714 | .usage = "LPORT [KEY]", |
a416ff28 RB |
715 | .min_args = 1, |
716 | .max_args = 2, | |
717 | .handler = do_lport_get_external_id, | |
718 | }, | |
719 | { | |
720 | .name = "lport-set-macs", | |
2de82d90 | 721 | .usage = "LPORT [MAC]...", |
a416ff28 RB |
722 | .min_args = 1, |
723 | /* Accept however many arguments the system will allow. */ | |
724 | .max_args = INT_MAX, | |
725 | .handler = do_lport_set_macs, | |
726 | }, | |
727 | { | |
728 | .name = "lport-get-macs", | |
a367622a | 729 | .usage = "LPORT", |
a416ff28 RB |
730 | .min_args = 1, |
731 | .max_args = 1, | |
732 | .handler = do_lport_get_macs, | |
733 | }, | |
92207865 BP |
734 | { |
735 | .name = "lport-set-port-security", | |
736 | .usage = "LPORT [ADDRS]...", | |
737 | .min_args = 0, | |
738 | /* Accept however many arguments the system will allow. */ | |
739 | .max_args = INT_MAX, | |
740 | .handler = do_lport_set_port_security, | |
741 | }, | |
742 | { | |
743 | .name = "lport-get-port-security", | |
744 | .usage = "LPORT", | |
745 | .min_args = 1, | |
746 | .max_args = 1, | |
747 | .handler = do_lport_get_port_security, | |
748 | }, | |
65fb6826 RB |
749 | { |
750 | .name = "lport-get-up", | |
a367622a | 751 | .usage = "LPORT", |
65fb6826 RB |
752 | .min_args = 1, |
753 | .max_args = 1, | |
754 | .handler = do_lport_get_up, | |
755 | }, | |
a416ff28 RB |
756 | |
757 | { | |
758 | /* sentinel */ | |
759 | .name = NULL, | |
760 | }, | |
761 | }; | |
762 | ||
763 | static const struct ovs_cmdl_command * | |
764 | get_all_commands(void) | |
765 | { | |
766 | return all_commands; | |
767 | } | |
768 | ||
769 | static const char * | |
770 | default_db(void) | |
771 | { | |
772 | static char *def; | |
773 | if (!def) { | |
774 | def = xasprintf("unix:%s/db.sock", ovs_rundir()); | |
775 | } | |
776 | return def; | |
777 | } | |
778 | ||
779 | int | |
780 | main(int argc, char *argv[]) | |
781 | { | |
782 | extern struct vlog_module VLM_reconnect; | |
783 | struct ovs_cmdl_context ctx; | |
784 | struct nbctl_context nb_ctx = { .idl = NULL, }; | |
785 | enum ovsdb_idl_txn_status txn_status; | |
786 | unsigned int seqno; | |
62ce36b2 | 787 | int res = 0; |
afc9da0b | 788 | char *args; |
a416ff28 RB |
789 | |
790 | fatal_ignore_sigpipe(); | |
791 | set_program_name(argv[0]); | |
792 | vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); | |
793 | vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN); | |
794 | parse_options(argc, argv); | |
795 | nbrec_init(); | |
796 | ||
afc9da0b JP |
797 | args = process_escape_args(argv); |
798 | ||
a416ff28 RB |
799 | nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false); |
800 | ctx.pvt = &nb_ctx; | |
801 | ctx.argc = argc - optind; | |
802 | ctx.argv = argv + optind; | |
803 | ||
804 | seqno = ovsdb_idl_get_seqno(nb_ctx.idl); | |
805 | for (;;) { | |
806 | ovsdb_idl_run(nb_ctx.idl); | |
807 | ||
808 | if (!ovsdb_idl_is_alive(nb_ctx.idl)) { | |
809 | int retval = ovsdb_idl_get_last_error(nb_ctx.idl); | |
810 | VLOG_ERR("%s: database connection failed (%s)", | |
811 | db, ovs_retval_to_string(retval)); | |
62ce36b2 RB |
812 | res = 1; |
813 | break; | |
a416ff28 RB |
814 | } |
815 | ||
816 | if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) { | |
817 | nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl); | |
afc9da0b | 818 | ovsdb_idl_txn_add_comment(nb_ctx.txn, "ovn-nbctl: %s", args); |
a416ff28 RB |
819 | ovs_cmdl_run_command(&ctx, get_all_commands()); |
820 | txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn); | |
821 | if (txn_status == TXN_TRY_AGAIN) { | |
6514cf48 RB |
822 | ovsdb_idl_txn_destroy(nb_ctx.txn); |
823 | nb_ctx.txn = NULL; | |
a416ff28 RB |
824 | continue; |
825 | } else { | |
826 | break; | |
827 | } | |
828 | } | |
829 | ||
830 | if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) { | |
831 | ovsdb_idl_wait(nb_ctx.idl); | |
832 | poll_block(); | |
833 | } | |
834 | } | |
835 | ||
836 | if (nb_ctx.txn) { | |
837 | ovsdb_idl_txn_destroy(nb_ctx.txn); | |
838 | } | |
839 | ovsdb_idl_destroy(nb_ctx.idl); | |
afc9da0b | 840 | free(args); |
a416ff28 | 841 | |
62ce36b2 | 842 | exit(res); |
a416ff28 | 843 | } |