]>
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\ |
e9e8bcdf RB |
84 | lport-set-enabled LPORT STATE\n\ |
85 | set administrative state LPORT\n\ | |
86 | ('enabled' or 'disabled')\n\ | |
87 | lport-get-enabled LPORT get administrative state LPORT\n\ | |
88 | ('enabled' or 'disabled')\n\ | |
a416ff28 RB |
89 | \n\ |
90 | Options:\n\ | |
91 | --db=DATABASE connect to DATABASE\n\ | |
92 | (default: %s)\n\ | |
93 | -h, --help display this help message\n\ | |
94 | -o, --options list available options\n\ | |
95 | -V, --version display version information\n\ | |
96 | ", program_name, program_name, default_db()); | |
97 | vlog_usage(); | |
98 | stream_usage("database", true, true, false); | |
99 | } | |
100 | \f | |
101 | static const struct nbrec_logical_switch * | |
102 | lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id) | |
103 | { | |
104 | const struct nbrec_logical_switch *lswitch = NULL; | |
105 | bool is_uuid = false; | |
106 | bool duplicate = false; | |
107 | struct uuid lswitch_uuid; | |
108 | ||
109 | if (uuid_from_string(&lswitch_uuid, id)) { | |
110 | is_uuid = true; | |
111 | lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl, | |
112 | &lswitch_uuid); | |
c1f4da63 RB |
113 | } |
114 | ||
115 | if (!lswitch) { | |
a416ff28 RB |
116 | const struct nbrec_logical_switch *iter; |
117 | ||
118 | NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) { | |
119 | if (strcmp(iter->name, id)) { | |
120 | continue; | |
121 | } | |
122 | if (lswitch) { | |
123 | VLOG_WARN("There is more than one logical switch named '%s'. " | |
124 | "Use a UUID.", id); | |
125 | lswitch = NULL; | |
126 | duplicate = true; | |
127 | break; | |
128 | } | |
129 | lswitch = iter; | |
130 | } | |
131 | } | |
132 | ||
133 | if (!lswitch && !duplicate) { | |
134 | VLOG_WARN("lswitch not found for %s: '%s'", | |
135 | is_uuid ? "UUID" : "name", id); | |
136 | } | |
137 | ||
138 | return lswitch; | |
139 | } | |
140 | ||
907a0edf | 141 | static void |
445a266a | 142 | print_lswitch(const struct nbrec_logical_switch *lswitch) |
907a0edf | 143 | { |
907a0edf JP |
144 | printf(" lswitch "UUID_FMT" (%s)\n", |
145 | UUID_ARGS(&lswitch->header_.uuid), lswitch->name); | |
146 | ||
445a266a BP |
147 | for (size_t i = 0; i < lswitch->n_ports; i++) { |
148 | const struct nbrec_logical_port *lport = lswitch->ports[i]; | |
907a0edf | 149 | |
445a266a BP |
150 | printf(" lport %s\n", lport->name); |
151 | if (lport->parent_name && lport->n_tag) { | |
152 | printf(" parent: %s, tag:%"PRIu64"\n", | |
153 | lport->parent_name, lport->tag[0]); | |
154 | } | |
155 | if (lport->n_macs) { | |
156 | printf(" macs:"); | |
157 | for (size_t j = 0; j < lport->n_macs; j++) { | |
158 | printf(" %s", lport->macs[j]); | |
907a0edf | 159 | } |
445a266a | 160 | printf("\n"); |
907a0edf JP |
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) { | |
445a266a | 174 | print_lswitch(lswitch); |
907a0edf JP |
175 | } |
176 | } else { | |
177 | NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) { | |
445a266a | 178 | print_lswitch(lswitch); |
907a0edf JP |
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 | 320 | if (ctx->argc != 3 && ctx->argc != 5) { |
445a266a | 321 | /* If a parent_name is specified, a tag must be specified as well. */ |
bf5fa52a RB |
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 | ||
445a266a | 334 | /* Create the logical port. */ |
a416ff28 | 335 | lport = nbrec_logical_port_insert(nb_ctx->txn); |
c8453791 | 336 | nbrec_logical_port_set_name(lport, ctx->argv[2]); |
bf5fa52a RB |
337 | if (ctx->argc == 5) { |
338 | nbrec_logical_port_set_parent_name(lport, ctx->argv[3]); | |
339 | nbrec_logical_port_set_tag(lport, &tag, 1); | |
340 | } | |
445a266a BP |
341 | |
342 | /* Insert the logical port into the logical switch. */ | |
343 | nbrec_logical_switch_verify_ports(lswitch); | |
344 | struct nbrec_logical_port **new_ports = xmalloc(sizeof *new_ports * | |
345 | (lswitch->n_ports + 1)); | |
346 | memcpy(new_ports, lswitch->ports, sizeof *new_ports * lswitch->n_ports); | |
347 | new_ports[lswitch->n_ports] = lport; | |
348 | nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports + 1); | |
349 | free(new_ports); | |
350 | } | |
351 | ||
352 | /* Removes lport 'lswitch->ports[idx]'. */ | |
353 | static void | |
354 | remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx) | |
355 | { | |
356 | const struct nbrec_logical_port *lport = lswitch->ports[idx]; | |
357 | ||
358 | /* First remove 'lport' from the array of ports. This is what will | |
359 | * actually cause the logical port to be deleted when the transaction is | |
360 | * sent to the database server (due to garbage collection). */ | |
361 | struct nbrec_logical_port **new_ports | |
362 | = xmemdup(lswitch->ports, sizeof *new_ports * lswitch->n_ports); | |
363 | new_ports[idx] = new_ports[lswitch->n_ports - 1]; | |
364 | nbrec_logical_switch_verify_ports(lswitch); | |
365 | nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports - 1); | |
366 | free(new_ports); | |
367 | ||
368 | /* Delete 'lport' from the IDL. This won't have a real effect on the | |
369 | * database server (the IDL will suppress it in fact) but it means that it | |
370 | * won't show up when we iterate with NBREC_LOGICAL_PORT_FOR_EACH later. */ | |
371 | nbrec_logical_port_delete(lport); | |
a416ff28 RB |
372 | } |
373 | ||
374 | static void | |
375 | do_lport_del(struct ovs_cmdl_context *ctx) | |
376 | { | |
377 | struct nbctl_context *nb_ctx = ctx->pvt; | |
378 | const struct nbrec_logical_port *lport; | |
379 | ||
380 | lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]); | |
381 | if (!lport) { | |
382 | return; | |
383 | } | |
384 | ||
445a266a BP |
385 | /* Find the switch that contains 'lport', then delete it. */ |
386 | const struct nbrec_logical_switch *lswitch; | |
387 | NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, nb_ctx->idl) { | |
388 | for (size_t i = 0; i < lswitch->n_ports; i++) { | |
389 | if (lswitch->ports[i] == lport) { | |
390 | remove_lport(lswitch, i); | |
391 | return; | |
392 | } | |
393 | } | |
a416ff28 | 394 | } |
a416ff28 | 395 | |
445a266a BP |
396 | VLOG_WARN("logical port %s is not part of any logical switch", |
397 | ctx->argv[1]); | |
398 | } | |
a416ff28 RB |
399 | |
400 | static void | |
401 | do_lport_list(struct ovs_cmdl_context *ctx) | |
402 | { | |
403 | struct nbctl_context *nb_ctx = ctx->pvt; | |
404 | const char *id = ctx->argv[1]; | |
445a266a | 405 | const struct nbrec_logical_switch *lswitch; |
a416ff28 | 406 | |
445a266a BP |
407 | lswitch = lswitch_by_name_or_uuid(nb_ctx, id); |
408 | if (!lswitch) { | |
409 | return; | |
a416ff28 RB |
410 | } |
411 | ||
445a266a BP |
412 | for (size_t i = 0; i < lswitch->n_ports; i++) { |
413 | const struct nbrec_logical_port *lport = lswitch->ports[i]; | |
a416ff28 RB |
414 | printf(UUID_FMT " (%s)\n", |
415 | UUID_ARGS(&lport->header_.uuid), lport->name); | |
416 | } | |
417 | } | |
418 | ||
bf5fa52a RB |
419 | static void |
420 | do_lport_get_parent(struct ovs_cmdl_context *ctx) | |
421 | { | |
422 | struct nbctl_context *nb_ctx = ctx->pvt; | |
423 | const struct nbrec_logical_port *lport; | |
424 | ||
425 | lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]); | |
426 | if (!lport) { | |
427 | return; | |
428 | } | |
429 | ||
430 | if (lport->parent_name) { | |
431 | printf("%s\n", lport->parent_name); | |
432 | } | |
433 | } | |
434 | ||
435 | static void | |
436 | do_lport_get_tag(struct ovs_cmdl_context *ctx) | |
437 | { | |
438 | struct nbctl_context *nb_ctx = ctx->pvt; | |
439 | const struct nbrec_logical_port *lport; | |
440 | ||
441 | lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]); | |
442 | if (!lport) { | |
443 | return; | |
444 | } | |
445 | ||
446 | if (lport->n_tag > 0) { | |
447 | printf("%"PRId64"\n", lport->tag[0]); | |
448 | } | |
449 | } | |
450 | ||
a416ff28 RB |
451 | static void |
452 | do_lport_set_external_id(struct ovs_cmdl_context *ctx) | |
453 | { | |
454 | struct nbctl_context *nb_ctx = ctx->pvt; | |
455 | const char *id = ctx->argv[1]; | |
456 | const struct nbrec_logical_port *lport; | |
457 | struct smap new_external_ids; | |
458 | ||
459 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
460 | if (!lport) { | |
461 | return; | |
462 | } | |
463 | ||
464 | smap_init(&new_external_ids); | |
465 | smap_clone(&new_external_ids, &lport->external_ids); | |
466 | if (ctx->argc == 4) { | |
467 | smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]); | |
468 | } else { | |
469 | smap_remove(&new_external_ids, ctx->argv[2]); | |
470 | } | |
471 | nbrec_logical_port_set_external_ids(lport, &new_external_ids); | |
472 | smap_destroy(&new_external_ids); | |
473 | } | |
474 | ||
475 | static void | |
476 | do_lport_get_external_id(struct ovs_cmdl_context *ctx) | |
477 | { | |
478 | struct nbctl_context *nb_ctx = ctx->pvt; | |
479 | const char *id = ctx->argv[1]; | |
480 | const struct nbrec_logical_port *lport; | |
481 | ||
482 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
483 | if (!lport) { | |
484 | return; | |
485 | } | |
486 | ||
487 | if (ctx->argc == 3) { | |
488 | const char *key = ctx->argv[2]; | |
489 | const char *value; | |
490 | ||
491 | /* List one external ID */ | |
492 | ||
493 | value = smap_get(&lport->external_ids, key); | |
ee98038f | 494 | if (value) { |
a416ff28 | 495 | printf("%s\n", value); |
a416ff28 RB |
496 | } |
497 | } else { | |
498 | struct smap_node *node; | |
499 | ||
500 | /* List all external IDs */ | |
501 | ||
502 | SMAP_FOR_EACH(node, &lport->external_ids) { | |
503 | printf("%s=%s\n", node->key, node->value); | |
504 | } | |
505 | } | |
506 | } | |
507 | ||
508 | static void | |
509 | do_lport_set_macs(struct ovs_cmdl_context *ctx) | |
510 | { | |
511 | struct nbctl_context *nb_ctx = ctx->pvt; | |
512 | const char *id = ctx->argv[1]; | |
513 | const struct nbrec_logical_port *lport; | |
514 | ||
515 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
516 | if (!lport) { | |
517 | return; | |
518 | } | |
519 | ||
520 | nbrec_logical_port_set_macs(lport, | |
521 | (const char **) ctx->argv + 2, ctx->argc - 2); | |
522 | } | |
523 | ||
524 | static void | |
525 | do_lport_get_macs(struct ovs_cmdl_context *ctx) | |
526 | { | |
527 | struct nbctl_context *nb_ctx = ctx->pvt; | |
528 | const char *id = ctx->argv[1]; | |
529 | const struct nbrec_logical_port *lport; | |
530 | size_t i; | |
531 | ||
532 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
533 | if (!lport) { | |
534 | return; | |
535 | } | |
536 | ||
537 | for (i = 0; i < lport->n_macs; i++) { | |
538 | printf("%s\n", lport->macs[i]); | |
539 | } | |
540 | } | |
65fb6826 | 541 | |
92207865 BP |
542 | static void |
543 | do_lport_set_port_security(struct ovs_cmdl_context *ctx) | |
544 | { | |
545 | struct nbctl_context *nb_ctx = ctx->pvt; | |
546 | const char *id = ctx->argv[1]; | |
547 | const struct nbrec_logical_port *lport; | |
548 | ||
549 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
550 | if (!lport) { | |
551 | return; | |
552 | } | |
553 | ||
554 | nbrec_logical_port_set_port_security(lport, | |
555 | (const char **) ctx->argv + 2, ctx->argc - 2); | |
556 | } | |
557 | ||
558 | static void | |
559 | do_lport_get_port_security(struct ovs_cmdl_context *ctx) | |
560 | { | |
561 | struct nbctl_context *nb_ctx = ctx->pvt; | |
562 | const char *id = ctx->argv[1]; | |
563 | const struct nbrec_logical_port *lport; | |
564 | size_t i; | |
565 | ||
566 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
567 | if (!lport) { | |
568 | return; | |
569 | } | |
570 | ||
571 | for (i = 0; i < lport->n_port_security; i++) { | |
572 | printf("%s\n", lport->port_security[i]); | |
573 | } | |
574 | } | |
575 | ||
65fb6826 RB |
576 | static void |
577 | do_lport_get_up(struct ovs_cmdl_context *ctx) | |
578 | { | |
579 | struct nbctl_context *nb_ctx = ctx->pvt; | |
580 | const char *id = ctx->argv[1]; | |
581 | const struct nbrec_logical_port *lport; | |
582 | ||
583 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
584 | if (!lport) { | |
585 | return; | |
586 | } | |
587 | ||
588 | printf("%s\n", (lport->up && *lport->up) ? "up" : "down"); | |
589 | } | |
e9e8bcdf RB |
590 | |
591 | static void | |
592 | do_lport_set_enabled(struct ovs_cmdl_context *ctx) | |
593 | { | |
594 | struct nbctl_context *nb_ctx = ctx->pvt; | |
595 | const char *id = ctx->argv[1]; | |
596 | const char *state = ctx->argv[2]; | |
597 | const struct nbrec_logical_port *lport; | |
598 | ||
599 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
600 | if (!lport) { | |
601 | return; | |
602 | } | |
603 | ||
604 | if (!strcasecmp(state, "enabled")) { | |
605 | bool enabled = true; | |
606 | nbrec_logical_port_set_enabled(lport, &enabled, 1); | |
607 | } else if (!strcasecmp(state, "disabled")) { | |
608 | bool enabled = false; | |
609 | nbrec_logical_port_set_enabled(lport, &enabled, 1); | |
610 | } else { | |
611 | VLOG_ERR("Invalid state '%s' provided to lport-set-enabled", state); | |
612 | } | |
613 | } | |
614 | ||
615 | static void | |
616 | do_lport_get_enabled(struct ovs_cmdl_context *ctx) | |
617 | { | |
618 | struct nbctl_context *nb_ctx = ctx->pvt; | |
619 | const char *id = ctx->argv[1]; | |
620 | const struct nbrec_logical_port *lport; | |
621 | ||
622 | lport = lport_by_name_or_uuid(nb_ctx, id); | |
623 | if (!lport) { | |
624 | return; | |
625 | } | |
626 | ||
627 | printf("%s\n", | |
628 | (!lport->enabled || *lport->enabled) ? "enabled" : "disabled"); | |
629 | } | |
a416ff28 RB |
630 | \f |
631 | static void | |
632 | parse_options(int argc, char *argv[]) | |
633 | { | |
634 | enum { | |
635 | VLOG_OPTION_ENUMS, | |
636 | }; | |
637 | static const struct option long_options[] = { | |
a7ac550b | 638 | {"db", required_argument, NULL, 'd'}, |
a416ff28 RB |
639 | {"help", no_argument, NULL, 'h'}, |
640 | {"options", no_argument, NULL, 'o'}, | |
641 | {"version", no_argument, NULL, 'V'}, | |
642 | VLOG_LONG_OPTIONS, | |
643 | STREAM_SSL_LONG_OPTIONS, | |
644 | {NULL, 0, NULL, 0}, | |
645 | }; | |
646 | char *short_options = ovs_cmdl_long_options_to_short_options(long_options); | |
647 | ||
648 | for (;;) { | |
649 | int c; | |
650 | ||
651 | c = getopt_long(argc, argv, short_options, long_options, NULL); | |
652 | if (c == -1) { | |
653 | break; | |
654 | } | |
655 | ||
656 | switch (c) { | |
657 | VLOG_OPTION_HANDLERS; | |
658 | STREAM_SSL_OPTION_HANDLERS; | |
659 | ||
660 | case 'd': | |
661 | db = optarg; | |
662 | break; | |
663 | ||
664 | case 'h': | |
665 | usage(); | |
666 | exit(EXIT_SUCCESS); | |
667 | ||
668 | case 'o': | |
669 | ovs_cmdl_print_options(long_options); | |
670 | exit(EXIT_SUCCESS); | |
671 | ||
672 | case 'V': | |
673 | ovs_print_version(0, 0); | |
674 | exit(EXIT_SUCCESS); | |
675 | ||
676 | default: | |
677 | break; | |
678 | } | |
679 | } | |
680 | ||
681 | if (!db) { | |
682 | db = default_db(); | |
683 | } | |
684 | ||
685 | free(short_options); | |
686 | } | |
687 | ||
688 | static const struct ovs_cmdl_command all_commands[] = { | |
907a0edf JP |
689 | { |
690 | .name = "show", | |
691 | .usage = "[LSWITCH]", | |
692 | .min_args = 0, | |
693 | .max_args = 1, | |
694 | .handler = do_show, | |
695 | }, | |
a416ff28 RB |
696 | { |
697 | .name = "lswitch-add", | |
a367622a | 698 | .usage = "[LSWITCH]", |
a416ff28 RB |
699 | .min_args = 0, |
700 | .max_args = 1, | |
701 | .handler = do_lswitch_add, | |
702 | }, | |
703 | { | |
704 | .name = "lswitch-del", | |
a367622a | 705 | .usage = "LSWITCH", |
a416ff28 RB |
706 | .min_args = 1, |
707 | .max_args = 1, | |
708 | .handler = do_lswitch_del, | |
709 | }, | |
710 | { | |
711 | .name = "lswitch-list", | |
712 | .usage = "", | |
713 | .min_args = 0, | |
714 | .max_args = 0, | |
715 | .handler = do_lswitch_list, | |
716 | }, | |
717 | { | |
718 | .name = "lswitch-set-external-id", | |
a367622a | 719 | .usage = "LSWITCH KEY [VALUE]", |
a416ff28 RB |
720 | .min_args = 2, |
721 | .max_args = 3, | |
722 | .handler = do_lswitch_set_external_id, | |
723 | }, | |
724 | { | |
725 | .name = "lswitch-get-external-id", | |
a367622a | 726 | .usage = "LSWITCH [KEY]", |
a416ff28 RB |
727 | .min_args = 1, |
728 | .max_args = 2, | |
729 | .handler = do_lswitch_get_external_id, | |
730 | }, | |
731 | { | |
732 | .name = "lport-add", | |
bf5fa52a | 733 | .usage = "LSWITCH LPORT [PARENT] [TAG]", |
a416ff28 | 734 | .min_args = 2, |
bf5fa52a | 735 | .max_args = 4, |
a416ff28 RB |
736 | .handler = do_lport_add, |
737 | }, | |
738 | { | |
739 | .name = "lport-del", | |
a367622a | 740 | .usage = "LPORT", |
a416ff28 RB |
741 | .min_args = 1, |
742 | .max_args = 1, | |
743 | .handler = do_lport_del, | |
744 | }, | |
745 | { | |
746 | .name = "lport-list", | |
a367622a | 747 | .usage = "LSWITCH", |
a416ff28 RB |
748 | .min_args = 1, |
749 | .max_args = 1, | |
750 | .handler = do_lport_list, | |
751 | }, | |
bf5fa52a RB |
752 | { |
753 | .name = "lport-get-parent", | |
754 | .usage = "LPORT", | |
755 | .min_args = 1, | |
756 | .max_args = 1, | |
757 | .handler = do_lport_get_parent, | |
758 | }, | |
759 | { | |
760 | .name = "lport-get-tag", | |
761 | .usage = "LPORT", | |
762 | .min_args = 1, | |
763 | .max_args = 1, | |
764 | .handler = do_lport_get_tag, | |
765 | }, | |
a416ff28 RB |
766 | { |
767 | .name = "lport-set-external-id", | |
a367622a | 768 | .usage = "LPORT KEY [VALUE]", |
a416ff28 RB |
769 | .min_args = 2, |
770 | .max_args = 3, | |
771 | .handler = do_lport_set_external_id, | |
772 | }, | |
773 | { | |
774 | .name = "lport-get-external-id", | |
a367622a | 775 | .usage = "LPORT [KEY]", |
a416ff28 RB |
776 | .min_args = 1, |
777 | .max_args = 2, | |
778 | .handler = do_lport_get_external_id, | |
779 | }, | |
780 | { | |
781 | .name = "lport-set-macs", | |
2de82d90 | 782 | .usage = "LPORT [MAC]...", |
a416ff28 RB |
783 | .min_args = 1, |
784 | /* Accept however many arguments the system will allow. */ | |
785 | .max_args = INT_MAX, | |
786 | .handler = do_lport_set_macs, | |
787 | }, | |
788 | { | |
789 | .name = "lport-get-macs", | |
a367622a | 790 | .usage = "LPORT", |
a416ff28 RB |
791 | .min_args = 1, |
792 | .max_args = 1, | |
793 | .handler = do_lport_get_macs, | |
794 | }, | |
92207865 BP |
795 | { |
796 | .name = "lport-set-port-security", | |
797 | .usage = "LPORT [ADDRS]...", | |
798 | .min_args = 0, | |
799 | /* Accept however many arguments the system will allow. */ | |
800 | .max_args = INT_MAX, | |
801 | .handler = do_lport_set_port_security, | |
802 | }, | |
803 | { | |
804 | .name = "lport-get-port-security", | |
805 | .usage = "LPORT", | |
806 | .min_args = 1, | |
807 | .max_args = 1, | |
808 | .handler = do_lport_get_port_security, | |
809 | }, | |
65fb6826 RB |
810 | { |
811 | .name = "lport-get-up", | |
a367622a | 812 | .usage = "LPORT", |
65fb6826 RB |
813 | .min_args = 1, |
814 | .max_args = 1, | |
815 | .handler = do_lport_get_up, | |
816 | }, | |
e9e8bcdf RB |
817 | { |
818 | .name = "lport-set-enabled", | |
819 | .usage = "LPORT STATE", | |
820 | .min_args = 2, | |
821 | .max_args = 2, | |
822 | .handler = do_lport_set_enabled, | |
823 | }, | |
824 | { | |
825 | .name = "lport-get-enabled", | |
826 | .usage = "LPORT", | |
827 | .min_args = 1, | |
828 | .max_args = 1, | |
829 | .handler = do_lport_get_enabled, | |
830 | }, | |
a416ff28 RB |
831 | |
832 | { | |
833 | /* sentinel */ | |
834 | .name = NULL, | |
835 | }, | |
836 | }; | |
837 | ||
838 | static const struct ovs_cmdl_command * | |
839 | get_all_commands(void) | |
840 | { | |
841 | return all_commands; | |
842 | } | |
843 | ||
844 | static const char * | |
845 | default_db(void) | |
846 | { | |
847 | static char *def; | |
848 | if (!def) { | |
d75ef07f BP |
849 | def = getenv("OVN_NB_DB"); |
850 | if (!def) { | |
851 | def = xasprintf("unix:%s/db.sock", ovs_rundir()); | |
852 | } | |
a416ff28 RB |
853 | } |
854 | return def; | |
855 | } | |
856 | ||
857 | int | |
858 | main(int argc, char *argv[]) | |
859 | { | |
860 | extern struct vlog_module VLM_reconnect; | |
861 | struct ovs_cmdl_context ctx; | |
862 | struct nbctl_context nb_ctx = { .idl = NULL, }; | |
863 | enum ovsdb_idl_txn_status txn_status; | |
864 | unsigned int seqno; | |
62ce36b2 | 865 | int res = 0; |
afc9da0b | 866 | char *args; |
a416ff28 RB |
867 | |
868 | fatal_ignore_sigpipe(); | |
869 | set_program_name(argv[0]); | |
870 | vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); | |
871 | vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN); | |
872 | parse_options(argc, argv); | |
873 | nbrec_init(); | |
874 | ||
afc9da0b JP |
875 | args = process_escape_args(argv); |
876 | ||
a416ff28 RB |
877 | nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false); |
878 | ctx.pvt = &nb_ctx; | |
879 | ctx.argc = argc - optind; | |
880 | ctx.argv = argv + optind; | |
881 | ||
882 | seqno = ovsdb_idl_get_seqno(nb_ctx.idl); | |
883 | for (;;) { | |
884 | ovsdb_idl_run(nb_ctx.idl); | |
885 | ||
886 | if (!ovsdb_idl_is_alive(nb_ctx.idl)) { | |
887 | int retval = ovsdb_idl_get_last_error(nb_ctx.idl); | |
888 | VLOG_ERR("%s: database connection failed (%s)", | |
889 | db, ovs_retval_to_string(retval)); | |
62ce36b2 RB |
890 | res = 1; |
891 | break; | |
a416ff28 RB |
892 | } |
893 | ||
894 | if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) { | |
895 | nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl); | |
afc9da0b | 896 | ovsdb_idl_txn_add_comment(nb_ctx.txn, "ovn-nbctl: %s", args); |
a416ff28 RB |
897 | ovs_cmdl_run_command(&ctx, get_all_commands()); |
898 | txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn); | |
899 | if (txn_status == TXN_TRY_AGAIN) { | |
6514cf48 RB |
900 | ovsdb_idl_txn_destroy(nb_ctx.txn); |
901 | nb_ctx.txn = NULL; | |
a416ff28 RB |
902 | continue; |
903 | } else { | |
904 | break; | |
905 | } | |
906 | } | |
907 | ||
908 | if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) { | |
909 | ovsdb_idl_wait(nb_ctx.idl); | |
910 | poll_block(); | |
911 | } | |
912 | } | |
913 | ||
914 | if (nb_ctx.txn) { | |
915 | ovsdb_idl_txn_destroy(nb_ctx.txn); | |
916 | } | |
917 | ovsdb_idl_destroy(nb_ctx.idl); | |
afc9da0b | 918 | free(args); |
a416ff28 | 919 | |
62ce36b2 | 920 | exit(res); |
a416ff28 | 921 | } |