diff mbox

[ovs-dev,3/6] Support physical endpts and binding to logical ports in sbctl

Message ID 1458159951-21345-4-git-send-email-dball@vmware.com
State Deferred
Headers show

Commit Message

Darrell Ball March 16, 2016, 8:25 p.m. UTC
Signed-off-by: Darrell Ball <dball@vmware.com>
---
 ovn/utilities/ovn-sbctl.c | 295 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 291 insertions(+), 4 deletions(-)
diff mbox

Patch

diff --git a/ovn/utilities/ovn-sbctl.c b/ovn/utilities/ovn-sbctl.c
index 0f402cd..382128b 100644
--- a/ovn/utilities/ovn-sbctl.c
+++ b/ovn/utilities/ovn-sbctl.c
@@ -311,11 +311,25 @@  Chassis commands:\n\
                                            and ENCAP-IP\n\
   chassis-del CHASSIS         delete CHASSIS and all of its encaps\n\
                               and gateway_ports\n\
+Physical Endpoint commands:\n\
+  phys-endpt-add PHYS-ENDPT CHASSIS PORT TYPE ING-ENC EGR-ENC\n\
+                                 create a new phys endpt named\n\
+                                 PHYS-ENDPT on CHASSIS/PORT\n\
+                                 with TYPE encap\n\
+                                 and encap values ING-ENC EGR-ENC\n\
+                                 chassis and port may be omitted \n\
+  phys-endpt-del PHYS-ENDPT      delete PHYS-ENDPT \n\
 \n\
 Port binding commands:\n\
   lport-bind LPORT CHASSIS    bind logical port LPORT to CHASSIS\n\
   lport-unbind LPORT          reset the port binding of logical port LPORT\n\
 \n\
+Port binding Phys Endpt commands:\n\
+  lport-bind-phys-endpt LPORT PHYS-ENDPT\n\
+                             bind logical port LPORT to PHYS-ENDPT\n\
+  lport-unbind-phys-endpt LPORT\n\
+                          reset the binding of LPORT to PHYS-ENDPT\n\
+\n\
 Logical flow commands:\n\
   lflow-list [DATAPATH]       List logical flows for all or a single datapath\n\
   dump-flows [DATAPATH]       Alias for lflow-list\n\
@@ -357,6 +371,9 @@  struct sbctl_context {
     struct shash chassis;
     /* Maps from lport name to struct sbctl_port_binding. */
     struct shash port_bindings;
+
+    /* Maps from phys_endpt name to struct sbctl_physical_endpoint. */
+    struct shash phys_endpts_name_to_rec;
 };
 
 /* Casts 'base' into 'struct sbctl_context'. */
@@ -374,6 +391,10 @@  struct sbctl_port_binding {
     const struct sbrec_port_binding *bd_cfg;
 };
 
+struct sbctl_physical_endpoint {
+    const struct sbrec_physical_endpoint *phys_endpt_db_rec;
+};
+
 static void
 sbctl_context_invalidate_cache(struct ctl_context *ctx)
 {
@@ -382,9 +403,10 @@  sbctl_context_invalidate_cache(struct ctl_context *ctx)
     if (!sbctl_ctx->cache_valid) {
         return;
     }
-    sbctl_ctx->cache_valid = false;
     shash_destroy_free_data(&sbctl_ctx->chassis);
     shash_destroy_free_data(&sbctl_ctx->port_bindings);
+    shash_destroy_free_data(&sbctl_ctx->phys_endpts_name_to_rec);
+    sbctl_ctx->cache_valid = false;
 }
 
 static void
@@ -393,7 +415,8 @@  sbctl_context_populate_cache(struct ctl_context *ctx)
     struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
     const struct sbrec_chassis *chassis_rec;
     const struct sbrec_port_binding *port_binding_rec;
-    struct sset chassis, port_bindings;
+    const struct sbrec_physical_endpoint *phys_endpt_db_rec;
+    struct sset chassis, port_bindings, physical_endpoints_set;
 
     if (sbctl_ctx->cache_valid) {
         /* Cache is already populated. */
@@ -402,6 +425,8 @@  sbctl_context_populate_cache(struct ctl_context *ctx)
     sbctl_ctx->cache_valid = true;
     shash_init(&sbctl_ctx->chassis);
     shash_init(&sbctl_ctx->port_bindings);
+    shash_init(&sbctl_ctx->phys_endpts_name_to_rec);
+
     sset_init(&chassis);
     SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->idl) {
         struct sbctl_chassis *ch;
@@ -435,10 +460,30 @@  sbctl_context_populate_cache(struct ctl_context *ctx)
                   bd);
     }
     sset_destroy(&port_bindings);
+
+    sset_init(&physical_endpoints_set);
+    SBREC_PHYSICAL_ENDPOINT_FOR_EACH(phys_endpt_db_rec, ctx->idl) {
+        struct sbctl_physical_endpoint *phys_endpt_lrec;
+
+        if (!sset_add(&physical_endpoints_set, phys_endpt_db_rec->name)) {
+            VLOG_WARN("database contains duplicate physical endpoint record "
+                      "for name (%s)",
+					  phys_endpt_db_rec->name);
+            continue;
+        }
+
+        phys_endpt_lrec
+		     = xmalloc(sizeof *phys_endpt_lrec);
+        phys_endpt_lrec->phys_endpt_db_rec = phys_endpt_db_rec;
+        shash_add(&sbctl_ctx->phys_endpts_name_to_rec,
+                  phys_endpt_db_rec->name, phys_endpt_lrec);
+    }
+    sset_destroy(&physical_endpoints_set);
+
 }
 
 static void
-check_conflicts(struct sbctl_context *sbctl_ctx, const char *name,
+chassis_check_conflict(struct sbctl_context *sbctl_ctx, const char *name,
                 char *msg)
 {
     if (shash_find(&sbctl_ctx->chassis, name)) {
@@ -448,6 +493,18 @@  check_conflicts(struct sbctl_context *sbctl_ctx, const char *name,
     free(msg);
 }
 
+static void
+physical_endpoint_check_conflict(
+          struct sbctl_context *sbctl_ctx, const char *name,
+          char *msg)
+{
+    if (shash_find(&sbctl_ctx->phys_endpts_name_to_rec, name)) {
+        ctl_fatal("%s because a physical endpoint named %s already exists",
+                    msg, name);
+    }
+    free(msg);
+}
+
 static struct sbctl_chassis *
 find_chassis(struct sbctl_context *sbctl_ctx, const char *name,
              bool must_exist)
@@ -480,6 +537,23 @@  find_port_binding(struct sbctl_context *sbctl_ctx, const char *name,
     return bd;
 }
 
+static struct sbctl_physical_endpoint *
+find_phys_endpt(struct sbctl_context *sbctl_ctx, const char *name,
+                bool must_exist)
+{
+    struct sbctl_physical_endpoint *phys_endpt_lrec;
+
+    ovs_assert(sbctl_ctx->cache_valid);
+
+    phys_endpt_lrec =
+        shash_find_data(&sbctl_ctx->phys_endpts_name_to_rec, name);
+    if (must_exist && !phys_endpt_lrec) {
+        ctl_fatal("no physical endpoint named %s", name);
+    }
+
+    return phys_endpt_lrec;
+}
+
 static void
 pre_get_info(struct ctl_context *ctx)
 {
@@ -489,8 +563,16 @@  pre_get_info(struct ctl_context *ctx)
     ovsdb_idl_add_column(ctx->idl, &sbrec_encap_col_type);
     ovsdb_idl_add_column(ctx->idl, &sbrec_encap_col_ip);
 
+    ovsdb_idl_add_column(ctx->idl, &sbrec_physical_endpoint_col_name);
+    ovsdb_idl_add_column(ctx->idl, &sbrec_physical_endpoint_col_chassis);
+    ovsdb_idl_add_column(ctx->idl, &sbrec_physical_endpoint_col_chassis_port);
+    ovsdb_idl_add_column(ctx->idl, &sbrec_physical_endpoint_col_type);
+    ovsdb_idl_add_column(ctx->idl, &sbrec_physical_endpoint_col_ingress_encap);
+    ovsdb_idl_add_column(ctx->idl, &sbrec_physical_endpoint_col_egress_encap);
+
     ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_logical_port);
     ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_chassis);
+    ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_phys_endpts);
 
     ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_logical_datapath);
     ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_pipeline);
@@ -518,6 +600,13 @@  static struct cmd_show_table cmd_show_tables[] = {
       NULL},
      {NULL, NULL, NULL}},
 
+     {&sbrec_table_physical_endpoint,
+	  &sbrec_physical_endpoint_col_name,
+	  {&sbrec_physical_endpoint_col_chassis,
+	   &sbrec_physical_endpoint_col_chassis_port,
+	   &sbrec_physical_endpoint_col_ingress_encap},
+	  {NULL, NULL, NULL}},
+
     {NULL, NULL, {NULL, NULL, NULL}, {NULL, NULL, NULL}},
 };
 
@@ -541,7 +630,7 @@  cmd_chassis_add(struct ctl_context *ctx)
             return;
         }
     }
-    check_conflicts(sbctl_ctx, ch_name,
+    chassis_check_conflict(sbctl_ctx, ch_name,
                     xasprintf("cannot create a chassis named %s", ch_name));
 
     char *tokstr = xstrdup(encap_types);
@@ -598,6 +687,113 @@  cmd_chassis_del(struct ctl_context *ctx)
 }
 
 static void
+cmd_phys_endpt_add(struct ctl_context *ctx)
+{
+    struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
+    bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
+    const char *phys_endpt_names, *chassis_name, *chassis_port_name;
+    const char *type_name, *ing_encap, *egr_encap;
+    struct sbctl_chassis *sbctl_ch;
+    int v;
+
+    if (ctx->argc == 7) {
+        phys_endpt_names = ctx->argv[1];
+        chassis_name = ctx->argv[2];
+        chassis_port_name = ctx->argv[3];
+        type_name = ctx->argv[4];
+        ing_encap = ctx->argv[5];
+        egr_encap = ctx->argv[6];
+    } else if (ctx->argc == 5) {
+        phys_endpt_names = ctx->argv[1];
+        chassis_name = NULL;
+        chassis_port_name = NULL;
+        type_name = ctx->argv[2];
+        ing_encap = ctx->argv[3];
+        egr_encap = ctx->argv[4];
+    } else {
+        ctl_fatal("phys endpt config must have 6 args "
+                  "or 4 args if no chassis and chassis port "
+                  "is supplied ");
+    }
+
+    sbctl_context_populate_cache(ctx);
+    if (may_exist) {
+        struct sbctl_physical_endpoint
+            *phys_endpt_lrec =
+               find_phys_endpt(
+                    sbctl_ctx, phys_endpt_names, false);
+        if (phys_endpt_lrec) {
+            return;
+        }
+    }
+    physical_endpoint_check_conflict(
+        sbctl_ctx, phys_endpt_names,
+        xasprintf("cannot create physical endpoint %s",
+                  phys_endpt_names));
+
+    /* Reminder: Splice out a encap verify function.
+       Presently only supporting single vlan with same
+       value for ingress and egress */
+    if ( (strcmp(type_name, "vlan")) ||
+        (!str_to_int(ing_encap, 10, &v) || v < 0 || v > 4095) ||
+        (!str_to_int(egr_encap, 10, &v) || v < 0 || v > 4095) ||
+        (strcmp(ing_encap, egr_encap))) {
+        ctl_fatal("phys endpt (%s) unsupported encap ",
+                  phys_endpt_names);
+    }
+
+    struct sbrec_physical_endpoint *phys_endpt_db_rec =
+       sbrec_physical_endpoint_insert(ctx->txn);
+
+    sbrec_physical_endpoint_set_name(
+            phys_endpt_db_rec,
+            phys_endpt_names);
+
+    sbctl_ch = find_chassis(sbctl_ctx, chassis_name, true);
+    sbrec_physical_endpoint_set_chassis(
+            phys_endpt_db_rec,
+			sbctl_ch->ch_cfg);
+
+    sbrec_physical_endpoint_set_chassis_port(
+            phys_endpt_db_rec,
+			chassis_port_name);
+    sbrec_physical_endpoint_set_type(
+            phys_endpt_db_rec,
+            type_name);
+    sbrec_physical_endpoint_set_ingress_encap(
+            phys_endpt_db_rec,
+			ing_encap);
+    sbrec_physical_endpoint_set_egress_encap(
+            phys_endpt_db_rec,
+            egr_encap);
+
+    sbctl_context_invalidate_cache(ctx);
+}
+
+static void
+cmd_phys_endpt_del(struct ctl_context *ctx)
+{
+    struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
+    bool must_exist = !shash_find(&ctx->options, "--if-exists");
+    struct sbctl_physical_endpoint *phys_endpt_lrec;
+
+    sbctl_context_populate_cache(ctx);
+    phys_endpt_lrec = find_phys_endpt(
+            sbctl_ctx, ctx->argv[1], must_exist);
+    if (phys_endpt_lrec) {
+        if (phys_endpt_lrec->phys_endpt_db_rec) {
+
+            sbrec_physical_endpoint_delete(
+                phys_endpt_lrec->phys_endpt_db_rec);
+        }
+        shash_find_and_delete(
+                     &sbctl_ctx->phys_endpts_name_to_rec,
+                     ctx->argv[1]);
+        free(phys_endpt_lrec);
+    }
+}
+
+static void
 cmd_lport_bind(struct ctl_context *ctx)
 {
     struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
@@ -642,6 +838,79 @@  cmd_lport_unbind(struct ctl_context *ctx)
     }
 }
 
+static void
+cmd_lport_bind_phys_endpts(struct ctl_context *ctx)
+{
+    struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
+    bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
+    struct sbctl_port_binding *sbctl_bd;
+    struct sbctl_physical_endpoint *phys_endpt_lrec;
+    char *lport_name, *phys_endpt_names;
+
+
+    /* port_binding must exist, chassis must exist! */
+    lport_name = ctx->argv[1];
+    phys_endpt_names = ctx->argv[2];
+
+    sbctl_context_populate_cache(ctx);
+    sbctl_bd = find_port_binding(sbctl_ctx, lport_name, true);
+
+    if (sbctl_bd->bd_cfg->phys_endpts) {
+        if (may_exist) {
+            return;
+        } else {
+            ctl_fatal("lport (%s) already bound to phys_endpts ",
+                      lport_name);
+        }
+    }
+
+    /* Parse the individual endpoints from the endpoints string
+     * and dump them into a set
+     */
+    char *tokstr = xstrdup(phys_endpt_names);
+    char *token, *save_ptr = NULL;
+    struct sset phys_endpt_names_set = SSET_INITIALIZER(&phys_endpt_names_set);
+    for (token = strtok_r(tokstr, ",", &save_ptr); token != NULL;
+         token = strtok_r(NULL, ",", &save_ptr)) {
+        sset_add(&phys_endpt_names_set, token);
+    }
+    free(tokstr);
+
+    size_t num_phys_endpts = sset_count(&phys_endpt_names_set);
+    struct sbrec_physical_endpoint **phys_endpts =
+        xmalloc(num_phys_endpts * sizeof *phys_endpts);
+    const char *phys_endpt_name;
+    int i = 0;
+    SSET_FOR_EACH (phys_endpt_name, &phys_endpt_names_set){
+        phys_endpt_lrec = find_phys_endpt(sbctl_ctx, phys_endpt_name, true);
+        if (phys_endpt_lrec) {
+            phys_endpts[i] = CONST_CAST(struct sbrec_physical_endpoint *,
+                                        phys_endpt_lrec->phys_endpt_db_rec);
+            i++;
+        }
+    }
+    sset_destroy(&phys_endpt_names_set);
+
+    sbrec_port_binding_set_phys_endpts(sbctl_bd->bd_cfg, phys_endpts, i);
+    sbctl_context_invalidate_cache(ctx);
+}
+
+static void
+cmd_lport_unbind_phys_endpts(struct ctl_context *ctx)
+{
+    struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
+    bool must_exist = !shash_find(&ctx->options, "--if-exists");
+    struct sbctl_port_binding *sbctl_bd;
+    char *lport_name;
+
+    lport_name = ctx->argv[1];
+    sbctl_context_populate_cache(ctx);
+    sbctl_bd = find_port_binding(sbctl_ctx, lport_name, must_exist);
+    if (sbctl_bd) {
+        sbrec_port_binding_set_phys_endpts(sbctl_bd->bd_cfg, NULL, 0);
+    }
+}
+
 enum {
     PL_INGRESS,
     PL_EGRESS,
@@ -775,6 +1044,11 @@  static const struct ctl_table_class tables[] = {
      {{&sbrec_table_mac_binding, &sbrec_mac_binding_col_logical_port, NULL},
       {NULL, NULL, NULL}}},
 
+    {&sbrec_table_physical_endpoint,
+     {{&sbrec_table_physical_endpoint,
+       &sbrec_physical_endpoint_col_name, NULL},
+      {NULL, NULL, NULL}}},
+
     {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
 };
 
@@ -1011,17 +1285,30 @@  sbctl_exit(int status)
 
 static const struct ctl_command_syntax sbctl_commands[] = {
     /* Chassis commands. */
+
     {"chassis-add", 3, 3, "CHASSIS ENCAP-TYPE ENCAP-IP", pre_get_info,
      cmd_chassis_add, NULL, "--may-exist", RW},
     {"chassis-del", 1, 1, "CHASSIS", pre_get_info, cmd_chassis_del, NULL,
      "--if-exists", RW},
 
+	/* Physical Endpoint commands */
+	{"phys-endpt-add", 4, 6, "PHYS-ENDPT CHASSIS PORT TYPE ING-ENC EGR-ENC",
+     pre_get_info, cmd_phys_endpt_add, NULL, "--may-exist", RW},
+	{"phys-endpt-del", 1, 1, "PHYS-ENDPT",
+     pre_get_info, cmd_phys_endpt_del, NULL, "--if-exists", RW},
+
     /* Port binding commands. */
     {"lport-bind", 2, 2, "LPORT CHASSIS", pre_get_info, cmd_lport_bind, NULL,
      "--may-exist", RW},
     {"lport-unbind", 1, 1, "LPORT", pre_get_info, cmd_lport_unbind, NULL,
      "--if-exists", RW},
 
+	/* Port to physical endpoint binding */
+    {"lport-bind-phys-endpt", 2, 2, "LPORT PHYS-ENDPT", pre_get_info,
+     cmd_lport_bind_phys_endpts, NULL, "--may-exist", RW},
+    {"lport-unbind-phys-endpt", 1, 1, "LPORT", pre_get_info,
+     cmd_lport_unbind_phys_endpts, NULL, "--if-exists", RW},
+
     /* Logical flow commands */
     {"lflow-list", 0, 1, "[DATAPATH]", pre_get_info, cmd_lflow_list, NULL,
      "", RO},