X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=vtep%2Fvtep-ctl.c;h=bf42f1c25a4f38a4046dc8f1ef4b010fd9e2ca34;hb=600766e877efa2713b9c87d127f7190d8ab48da9;hp=309c0b3c8d48baaa41b16f081d63ae004e4fc16b;hpb=3935f67dbc6915dfc7ab01f97e0f8a874cfec151;p=cascardo%2Fovs.git diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c index 309c0b3c8..bf42f1c25 100644 --- a/vtep/vtep-ctl.c +++ b/vtep/vtep-ctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2014 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2014, 2015, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -70,6 +70,13 @@ static int timeout; /* Format for table output. */ static struct table_style table_style = TABLE_STYLE_DEFAULT; +/* The IDL we're using and the current transaction, if any. + * This is for use by vtep_ctl_exit() only, to allow it to clean up. + * Other code should use its context arguments. */ +static struct ovsdb_idl *the_idl; +static struct ovsdb_idl_txn *the_idl_txn; + +OVS_NO_RETURN static void vtep_ctl_exit(int status); static void vtep_ctl_cmd_init(void); OVS_NO_RETURN static void usage(void); static void parse_options(int argc, char *argv[], struct shash *local_options); @@ -80,11 +87,13 @@ static void do_vtep_ctl(const char *args, struct ctl_command *, size_t n, static struct vtep_ctl_lswitch *find_lswitch(struct vtep_ctl_context *, const char *name, bool must_exist); +static struct vtep_ctl_lrouter *find_lrouter(struct vtep_ctl_context *, + const char *name, + bool must_exist); int main(int argc, char *argv[]) { - extern struct vlog_module VLM_reconnect; struct ovsdb_idl *idl; struct ctl_command *commands; struct shash local_options; @@ -95,7 +104,7 @@ main(int argc, char *argv[]) set_program_name(argv[0]); fatal_ignore_sigpipe(); vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); - vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN); + vlog_set_levels_from_string_assert("reconnect:warn"); vteprec_init(); vtep_ctl_cmd_init(); @@ -128,6 +137,11 @@ main(int argc, char *argv[]) seqno = ovsdb_idl_get_seqno(idl); for (;;) { ovsdb_idl_run(idl); + if (!ovsdb_idl_is_alive(idl)) { + int retval = ovsdb_idl_get_last_error(idl); + ctl_fatal("%s: database connection failed (%s)", + db, ovs_retval_to_string(retval)); + } if (seqno != ovsdb_idl_get_seqno(idl)) { seqno = ovsdb_idl_get_seqno(idl); @@ -209,7 +223,7 @@ parse_options(int argc, char *argv[], struct shash *local_options) break; case OPT_NO_SYSLOG: - vlog_set_levels(&VLM_vtep_ctl, VLF_SYSLOG, VLL_WARN); + vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN); break; case OPT_DRY_RUN: @@ -270,6 +284,23 @@ parse_options(int argc, char *argv[], struct shash *local_options) free(options); } +/* Frees the current transaction and the underlying IDL and then calls + * exit(status). + * + * Freeing the transaction and the IDL is not strictly necessary, but it makes + * for a clean memory leak report from valgrind in the normal case. That makes + * it easier to notice real memory leaks. */ +static void +vtep_ctl_exit(int status) +{ + if (the_idl_txn) { + ovsdb_idl_txn_abort(the_idl_txn); + ovsdb_idl_txn_destroy(the_idl_txn); + } + ovsdb_idl_destroy(the_idl); + exit(status); +} + static void usage(void) { @@ -305,6 +336,12 @@ Logical Switch commands:\n\ unbind-ls PS PORT VLAN unbind logical switch on VLAN from PORT\n\ list-bindings PS PORT list bindings for PORT on PS\n\ \n\ +Logical Router commands:\n\ + add-lr LR create a new logical router named LR\n\ + del-lr LR delete LR\n\ + list-lr print the names of all the logical routers\n\ + lr-exists LR exit 2 if LR does not exist\n\ +\n\ MAC binding commands:\n\ add-ucast-local LS MAC [ENCAP] IP add ucast local entry in LS\n\ del-ucast-local LS MAC del ucast local entry from LS\n\ @@ -340,36 +377,48 @@ Other options:\n\ } -struct cmd_show_table cmd_show_tables[] = { +static struct cmd_show_table cmd_show_tables[] = { {&vteprec_table_global, NULL, {&vteprec_global_col_managers, &vteprec_global_col_switches, NULL}, - false}, + {NULL, NULL, NULL} + }, {&vteprec_table_manager, &vteprec_manager_col_target, {&vteprec_manager_col_is_connected, NULL, NULL}, - false}, + {NULL, NULL, NULL} + }, {&vteprec_table_physical_switch, &vteprec_physical_switch_col_name, - {&vteprec_physical_switch_col_tunnel_ips, - &vteprec_physical_switch_col_ports, - NULL}, - false}, + {&vteprec_physical_switch_col_management_ips, + &vteprec_physical_switch_col_tunnel_ips, + &vteprec_physical_switch_col_ports}, + {NULL, NULL, NULL} + }, {&vteprec_table_physical_port, &vteprec_physical_port_col_name, {&vteprec_physical_port_col_vlan_bindings, NULL, NULL}, - false}, + {NULL, NULL, NULL} + }, + + {&vteprec_table_logical_switch, + &vteprec_logical_switch_col_name, + {NULL, + NULL, + NULL}, + {NULL, NULL, NULL} + }, - {NULL, NULL, {NULL, NULL, NULL}, false} + {NULL, NULL, {NULL, NULL, NULL}, {NULL, NULL, NULL}} }; /* vtep-ctl specific context. Inherits the 'struct ctl_context' as base. */ @@ -396,9 +445,11 @@ struct vtep_ctl_context { * struct vtep_ctl_lswitch. */ struct shash plocs; /* Maps from "+" to * struct vteprec_physical_locator. */ + struct shash lrouters; /* Maps from logical router name to + * struct vtep_ctl_lrouter. */ }; -/* Casts 'base' into 'strcut vtep_ctl_context'. */ +/* Casts 'base' into 'struct vtep_ctl_context'. */ static struct vtep_ctl_context * vtep_ctl_context_cast(struct ctl_context *base) { @@ -427,6 +478,11 @@ struct vtep_ctl_lswitch { struct shash mcast_remote; /* Maps from mac to vtep_ctl_mcast_mac. */ }; +struct vtep_ctl_lrouter { + const struct vteprec_logical_router *lr_cfg; + char *name; +}; + struct vtep_ctl_mcast_mac { const struct vteprec_mcast_macs_local *local_cfg; const struct vteprec_mcast_macs_remote *remote_cfg; @@ -488,7 +544,7 @@ del_cached_port(struct vtep_ctl_context *vtepctl_ctx, free(port); } -static struct vtep_ctl_pswitch * +static void add_pswitch_to_cache(struct vtep_ctl_context *vtepctl_ctx, struct vteprec_physical_switch *ps_cfg) { @@ -497,7 +553,6 @@ add_pswitch_to_cache(struct vtep_ctl_context *vtepctl_ctx, ps->name = xstrdup(ps_cfg->name); list_init(&ps->ports); shash_add(&vtepctl_ctx->pswitches, ps->name, ps); - return ps; } static void @@ -608,6 +663,28 @@ del_cached_ls_binding(struct vtep_ctl_port *port, const char *vlan) shash_find_and_delete(&port->bindings, vlan); } +static struct vtep_ctl_lrouter * +add_lrouter_to_cache(struct vtep_ctl_context *vtepctl_ctx, + const struct vteprec_logical_router *lr_cfg) +{ + struct vtep_ctl_lrouter *lr = xmalloc(sizeof *lr); + lr->lr_cfg = lr_cfg; + lr->name = xstrdup(lr_cfg->name); + shash_add(&vtepctl_ctx->lrouters, lr->name, lr); + return lr; +} + +static void +del_cached_lrouter(struct vtep_ctl_context *ctx, struct vtep_ctl_lrouter *lr) +{ + if (lr->lr_cfg) { + vteprec_logical_router_delete(lr->lr_cfg); + } + shash_find_and_delete(&ctx->lrouters, lr->name); + free(lr->name); + free(lr); +} + static struct vteprec_physical_locator * find_ploc(struct vtep_ctl_context *vtepctl_ctx, const char *encap, const char *dst_ip) @@ -752,6 +829,13 @@ vtep_ctl_context_invalidate_cache(struct ctl_context *ctx) } shash_destroy(&vtepctl_ctx->lswitches); shash_destroy(&vtepctl_ctx->plocs); + + SHASH_FOR_EACH (node, &vtepctl_ctx->lrouters) { + struct vtep_ctl_lrouter *lr = node->data; + free(lr->name); + free(lr); + } + shash_destroy(&vtepctl_ctx->lrouters); } static void @@ -768,6 +852,8 @@ pre_get_info(struct ctl_context *ctx) ovsdb_idl_add_column(ctx->idl, &vteprec_logical_switch_col_name); + ovsdb_idl_add_column(ctx->idl, &vteprec_logical_router_col_name); + ovsdb_idl_add_column(ctx->idl, &vteprec_ucast_macs_local_col_MAC); ovsdb_idl_add_column(ctx->idl, &vteprec_ucast_macs_local_col_locator); ovsdb_idl_add_column(ctx->idl, @@ -808,12 +894,14 @@ vtep_ctl_context_populate_cache(struct ctl_context *ctx) struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx); const struct vteprec_global *vtep_global = vtepctl_ctx->vtep_global; const struct vteprec_logical_switch *ls_cfg; + const struct vteprec_logical_router *lr_cfg; const struct vteprec_ucast_macs_local *ucast_local_cfg; const struct vteprec_ucast_macs_remote *ucast_remote_cfg; const struct vteprec_mcast_macs_local *mcast_local_cfg; const struct vteprec_mcast_macs_remote *mcast_remote_cfg; const struct vteprec_tunnel *tunnel_cfg; struct sset pswitches, ports, lswitches; + struct sset lrouters; size_t i; if (vtepctl_ctx->cache_valid) { @@ -825,12 +913,12 @@ vtep_ctl_context_populate_cache(struct ctl_context *ctx) shash_init(&vtepctl_ctx->ports); shash_init(&vtepctl_ctx->lswitches); shash_init(&vtepctl_ctx->plocs); + shash_init(&vtepctl_ctx->lrouters); sset_init(&pswitches); sset_init(&ports); for (i = 0; i < vtep_global->n_switches; i++) { struct vteprec_physical_switch *ps_cfg = vtep_global->switches[i]; - struct vtep_ctl_pswitch *ps; size_t j; if (!sset_add(&pswitches, ps_cfg->name)) { @@ -838,10 +926,7 @@ vtep_ctl_context_populate_cache(struct ctl_context *ctx) ps_cfg->name); continue; } - ps = add_pswitch_to_cache(vtepctl_ctx, ps_cfg); - if (!ps) { - continue; - } + add_pswitch_to_cache(vtepctl_ctx, ps_cfg); for (j = 0; j < ps_cfg->n_ports; j++) { struct vteprec_physical_port *port_cfg = ps_cfg->ports[j]; @@ -866,6 +951,17 @@ vtep_ctl_context_populate_cache(struct ctl_context *ctx) } sset_destroy(&lswitches); + sset_init(&lrouters); + VTEPREC_LOGICAL_ROUTER_FOR_EACH (lr_cfg, ctx->idl) { + if (!sset_add(&lrouters, lr_cfg->name)) { + VLOG_WARN("%s: database contains duplicate logical router name", + lr_cfg->name); + continue; + } + add_lrouter_to_cache(vtepctl_ctx, lr_cfg); + } + sset_destroy(&lrouters); + VTEPREC_UCAST_MACS_LOCAL_FOR_EACH (ucast_local_cfg, ctx->idl) { struct vtep_ctl_lswitch *ls; @@ -1187,7 +1283,7 @@ cmd_ps_exists(struct ctl_context *ctx) vtep_ctl_context_populate_cache(ctx); if (!find_pswitch(vtepctl_ctx, ctx->argv[1], false)) { - ctl_exit(2); + vtep_ctl_exit(2); } } @@ -1361,7 +1457,7 @@ cmd_ls_exists(struct ctl_context *ctx) vtep_ctl_context_populate_cache(ctx); if (!find_lswitch(vtepctl_ctx, ctx->argv[1], false)) { - ctl_exit(2); + vtep_ctl_exit(2); } } @@ -1427,6 +1523,94 @@ cmd_unbind_ls(struct ctl_context *ctx) vtep_ctl_context_invalidate_cache(ctx); } +static struct vtep_ctl_lrouter * +find_lrouter(struct vtep_ctl_context *vtepctl_ctx, + const char *name, bool must_exist) +{ + struct vtep_ctl_lrouter *lr; + + ovs_assert(vtepctl_ctx->cache_valid); + + lr = shash_find_data(&vtepctl_ctx->lrouters, name); + if (must_exist && !lr) { + ctl_fatal("no logical router named %s", name); + } + return lr; +} + +static void +cmd_add_lr(struct ctl_context *ctx) +{ + struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx); + const char *lr_name = ctx->argv[1]; + bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; + struct vteprec_logical_router *lr; + + vtep_ctl_context_populate_cache(ctx); + if (find_lrouter(vtepctl_ctx, lr_name, false)) { + if (!may_exist) { + ctl_fatal("cannot create logical router %s because it " + "already exists", lr_name); + } + return; + } + + lr = vteprec_logical_router_insert(ctx->txn); + vteprec_logical_router_set_name(lr, lr_name); + + vtep_ctl_context_invalidate_cache(ctx); +} + +static void +del_lrouter(struct vtep_ctl_context *vtepctl_ctx, struct vtep_ctl_lrouter *lr) +{ + del_cached_lrouter(vtepctl_ctx, lr); +} + +static void +cmd_del_lr(struct ctl_context *ctx) +{ + struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx); + bool must_exist = !shash_find(&ctx->options, "--if-exists"); + struct vtep_ctl_lrouter *lr; + + vtep_ctl_context_populate_cache(ctx); + lr = find_lrouter(vtepctl_ctx, ctx->argv[1], must_exist); + if (lr) { + del_lrouter(vtepctl_ctx, lr); + } +} + +static void +cmd_list_lr(struct ctl_context *ctx) +{ + struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx); + struct shash_node *node; + struct svec lrouters; + + vtep_ctl_context_populate_cache(ctx); + + svec_init(&lrouters); + SHASH_FOR_EACH (node, &vtepctl_ctx->lrouters) { + struct vtep_ctl_lrouter *lr = node->data; + + svec_add(&lrouters, lr->name); + } + output_sorted(&lrouters, &ctx->output); + svec_destroy(&lrouters); +} + +static void +cmd_lr_exists(struct ctl_context *ctx) +{ + struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx); + + vtep_ctl_context_populate_cache(ctx); + if (!find_lrouter(vtepctl_ctx, ctx->argv[1], false)) { + vtep_ctl_exit(2); + } +} + static void add_ucast_entry(struct ctl_context *ctx, bool local) { @@ -1955,7 +2139,7 @@ cmd_set_manager(struct ctl_context *ctx) } /* Parameter commands. */ -const struct ctl_table_class tables[] = { +static const struct ctl_table_class tables[] = { {&vteprec_table_global, {{&vteprec_table_global, NULL, NULL}, {NULL, NULL, NULL}}}, @@ -2008,6 +2192,18 @@ const struct ctl_table_class tables[] = { {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}, + {&vteprec_table_logical_router, + {{&vteprec_table_logical_router, &vteprec_logical_router_col_name, NULL}, + {NULL, NULL, NULL}}}, + + {&vteprec_table_arp_sources_local, + {{NULL, NULL, NULL}, + {NULL, NULL, NULL}}}, + + {&vteprec_table_arp_sources_remote, + {{NULL, NULL, NULL}, + {NULL, NULL, NULL}}}, + {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}} }; @@ -2264,6 +2460,12 @@ static const struct ctl_command_syntax vtep_commands[] = { {"bind-ls", 4, 4, NULL, pre_get_info, cmd_bind_ls, NULL, "", RO}, {"unbind-ls", 3, 3, NULL, pre_get_info, cmd_unbind_ls, NULL, "", RO}, + /* Logical Router commands. */ + {"add-lr", 1, 1, NULL, pre_get_info, cmd_add_lr, NULL, "--may-exist", RW}, + {"del-lr", 1, 1, NULL, pre_get_info, cmd_del_lr, NULL, "--if-exists", RW}, + {"list-lr", 0, 0, NULL, pre_get_info, cmd_list_lr, NULL, "", RO}, + {"lr-exists", 1, 1, NULL, pre_get_info, cmd_lr_exists, NULL, "", RO}, + /* MAC binding commands. */ {"add-ucast-local", 3, 4, NULL, pre_get_info, cmd_add_ucast_local, NULL, "", RW}, @@ -2303,6 +2505,6 @@ static const struct ctl_command_syntax vtep_commands[] = { static void vtep_ctl_cmd_init(void) { - ctl_init(); + ctl_init(tables, cmd_show_tables, vtep_ctl_exit); ctl_register_commands(vtep_commands); }