summaryrefslogtreecommitdiffstats
path: root/src/client/conf-power.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/conf-power.c')
-rw-r--r--src/client/conf-power.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/src/client/conf-power.c b/src/client/conf-power.c
new file mode 100644
index 0000000..7c33540
--- /dev/null
+++ b/src/client/conf-power.c
@@ -0,0 +1,389 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2013 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include "client.h"
+#include "../log.h"
+
+static int
+cmd_medpower(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env,
+ const void *arg)
+{
+ log_debug("lldpctl", "set MED power");
+ lldpctl_atom_t *port;
+ const char *name;
+ while ((port = cmd_iterate_on_ports(conn, env, &name))) {
+ lldpctl_atom_t *med_power;
+ const char *what = NULL;
+
+ med_power = lldpctl_atom_get(port, lldpctl_k_port_med_power);
+ if (med_power == NULL) {
+ log_warnx("lldpctl",
+ "unable to set LLDP-MED power: support seems unavailable");
+ continue; /* Need to finish the loop */
+ }
+
+ if ((what = "device type",
+ lldpctl_atom_set_str(med_power, lldpctl_k_med_power_type,
+ cmdenv_get(env, "device-type"))) == NULL ||
+ (what = "power source",
+ lldpctl_atom_set_str(med_power, lldpctl_k_med_power_source,
+ cmdenv_get(env, "source"))) == NULL ||
+ (what = "power priority",
+ lldpctl_atom_set_str(med_power, lldpctl_k_med_power_priority,
+ cmdenv_get(env, "priority"))) == NULL ||
+ (what = "power value",
+ lldpctl_atom_set_str(med_power, lldpctl_k_med_power_val,
+ cmdenv_get(env, "value"))) == NULL)
+ log_warnx("lldpctl",
+ "unable to set LLDP MED power value for %s on %s. %s.",
+ what, name, lldpctl_last_strerror(conn));
+ else {
+ if (lldpctl_atom_set(port, lldpctl_k_port_med_power,
+ med_power) == NULL) {
+ log_warnx("lldpctl",
+ "unable to set LLDP MED power on %s. %s.", name,
+ lldpctl_last_strerror(conn));
+ } else
+ log_info("lldpctl",
+ "LLDP-MED power has been set for port %s", name);
+ }
+
+ lldpctl_atom_dec_ref(med_power);
+ }
+ return 1;
+}
+
+static int
+cmd_store_powerpairs_env_value_and_pop2(struct lldpctl_conn_t *conn, struct writer *w,
+ struct cmd_env *env, const void *value)
+{
+ return cmd_store_something_env_value_and_pop2("powerpairs", env, value);
+}
+static int
+cmd_store_class_env_value_and_pop2(struct lldpctl_conn_t *conn, struct writer *w,
+ struct cmd_env *env, const void *value)
+{
+ return cmd_store_something_env_value_and_pop2("class", env, value);
+}
+static int
+cmd_store_prio_env_value_and_pop2(struct lldpctl_conn_t *conn, struct writer *w,
+ struct cmd_env *env, const void *value)
+{
+ return cmd_store_something_env_value_and_pop2("priority", env, value);
+}
+
+static int
+cmd_dot3power(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env,
+ const void *arg)
+{
+ log_debug("lldpctl", "set dot3 power");
+ lldpctl_atom_t *port;
+ const char *name;
+ while ((port = cmd_iterate_on_ports(conn, env, &name))) {
+ lldpctl_atom_t *dot3_power;
+ const char *what = NULL;
+ int ok = 1;
+
+ dot3_power = lldpctl_atom_get(port, lldpctl_k_port_dot3_power);
+ if (dot3_power == NULL) {
+ log_warnx("lldpctl",
+ "unable to set Dot3 power: support seems unavailable");
+ continue; /* Need to finish the loop */
+ }
+
+ if ((what = "device type",
+ lldpctl_atom_set_str(dot3_power,
+ lldpctl_k_dot3_power_devicetype,
+ cmdenv_get(env, "device-type"))) == NULL ||
+ /* Flags */
+ (what = "supported flag",
+ lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_supported,
+ cmdenv_get(env, "supported") ? 1 : 0)) == NULL ||
+ (what = "enabled flag",
+ lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_enabled,
+ cmdenv_get(env, "enabled") ? 1 : 0)) == NULL ||
+ (what = "paircontrol flag",
+ lldpctl_atom_set_int(dot3_power,
+ lldpctl_k_dot3_power_paircontrol,
+ cmdenv_get(env, "paircontrol") ? 1 : 0)) == NULL ||
+ /* Powerpairs */
+ (what = "power pairs",
+ lldpctl_atom_set_str(dot3_power, lldpctl_k_dot3_power_pairs,
+ cmdenv_get(env, "powerpairs"))) == NULL ||
+ /* Class */
+ (what = "power class",
+ cmdenv_get(env, "class") ?
+ lldpctl_atom_set_str(dot3_power, lldpctl_k_dot3_power_class,
+ cmdenv_get(env, "class")) :
+ lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_class,
+ 0)) == NULL ||
+ (what = "802.3at type",
+ lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_type,
+ 0)) == NULL) {
+ log_warnx("lldpctl",
+ "unable to set LLDP Dot3 power value for %s on %s. %s.",
+ what, name, lldpctl_last_strerror(conn));
+ ok = 0;
+ } else if (cmdenv_get(env, "typeat")) {
+ int typeat = cmdenv_get(env, "typeat")[0] - '0';
+ const char *source = cmdenv_get(env, "source");
+ if ((what = "802.3at type",
+ lldpctl_atom_set_int(dot3_power,
+ lldpctl_k_dot3_power_type, typeat)) == NULL ||
+ (what = "source",
+ lldpctl_atom_set_int(dot3_power,
+ lldpctl_k_dot3_power_source,
+ (!strcmp(source, "primary")) ?
+ LLDP_DOT3_POWER_SOURCE_PRIMARY :
+ (!strcmp(source, "backup")) ?
+ LLDP_DOT3_POWER_SOURCE_BACKUP :
+ (!strcmp(source, "pse")) ?
+ LLDP_DOT3_POWER_SOURCE_PSE :
+ (!strcmp(source, "local")) ?
+ LLDP_DOT3_POWER_SOURCE_LOCAL :
+ (!strcmp(source, "both")) ?
+ LLDP_DOT3_POWER_SOURCE_BOTH :
+ LLDP_DOT3_POWER_SOURCE_UNKNOWN)) == NULL ||
+ (what = "priority",
+ lldpctl_atom_set_str(dot3_power,
+ lldpctl_k_dot3_power_priority,
+ cmdenv_get(env, "priority"))) == NULL ||
+ (what = "requested power",
+ lldpctl_atom_set_str(dot3_power,
+ lldpctl_k_dot3_power_requested,
+ cmdenv_get(env, "requested"))) == NULL ||
+ (what = "allocated power",
+ lldpctl_atom_set_str(dot3_power,
+ lldpctl_k_dot3_power_allocated,
+ cmdenv_get(env, "allocated"))) == NULL) {
+ log_warnx("lldpctl",
+ "unable to set LLDP Dot3 power value for %s on %s. %s.",
+ what, name, lldpctl_last_strerror(conn));
+ ok = 0;
+ }
+ }
+ if (ok) {
+ if (lldpctl_atom_set(port, lldpctl_k_port_dot3_power,
+ dot3_power) == NULL) {
+ log_warnx("lldpctl",
+ "unable to set LLDP Dot3 power on %s. %s.", name,
+ lldpctl_last_strerror(conn));
+ } else
+ log_info("lldpctl",
+ "LLDP Dot3 power has been set for port %s", name);
+ }
+
+ lldpctl_atom_dec_ref(dot3_power);
+ }
+ return 1;
+}
+
+static int
+cmd_check_type_but_no(struct cmd_env *env, const void *arg)
+{
+ const char *what = arg;
+ if (!cmdenv_get(env, "device-type")) return 0;
+ if (cmdenv_get(env, what)) return 0;
+ return 1;
+}
+static int
+cmd_check_typeat_but_no(struct cmd_env *env, const void *arg)
+{
+ const char *what = arg;
+ if (!cmdenv_get(env, "typeat")) return 0;
+ if (cmdenv_get(env, what)) return 0;
+ return 1;
+}
+static int
+cmd_check_type(struct cmd_env *env, const char *type)
+{
+ const char *etype = cmdenv_get(env, "device-type");
+ if (!etype) return 0;
+ return (!strcmp(type, etype));
+}
+static int
+cmd_check_pse(struct cmd_env *env, const void *arg)
+{
+ return cmd_check_type(env, "pse");
+}
+static int
+cmd_check_pd(struct cmd_env *env, const void *arg)
+{
+ return cmd_check_type(env, "pd");
+}
+
+static void
+register_commands_pow_source(struct cmd_node *source)
+{
+ commands_new(source, "unknown", "Unknown power source", NULL,
+ cmd_store_env_value_and_pop2, "source");
+ commands_new(source, "primary", "Primary power source", cmd_check_pse,
+ cmd_store_env_value_and_pop2, "source");
+ commands_new(source, "backup", "Backup power source", cmd_check_pse,
+ cmd_store_env_value_and_pop2, "source");
+ commands_new(source, "pse", "Power source is PSE", cmd_check_pd,
+ cmd_store_env_value_and_pop2, "source");
+ commands_new(source, "local", "Local power source", cmd_check_pd,
+ cmd_store_env_value_and_pop2, "source");
+ commands_new(source, "both", "Both PSE and local source available",
+ cmd_check_pd, cmd_store_env_value_and_pop2, "source");
+}
+
+static void
+register_commands_pow_priority(struct cmd_node *priority, int key)
+{
+ for (lldpctl_map_t *prio_map = lldpctl_key_get_map(key); prio_map->string;
+ prio_map++) {
+ char *tag = strdup(totag(prio_map->string));
+ SUPPRESS_LEAK(tag);
+ commands_new(priority, tag, prio_map->string, NULL,
+ cmd_store_prio_env_value_and_pop2, prio_map->string);
+ }
+}
+
+/**
+ * Register `configure med power` commands.
+ */
+void
+register_commands_medpow(struct cmd_node *configure_med)
+{
+ struct cmd_node *configure_medpower = commands_new(configure_med, "power",
+ "MED power configuration", NULL, NULL, NULL);
+
+ commands_new(configure_medpower, NEWLINE, "Apply new MED power configuration",
+ cmd_check_env, cmd_medpower, "device-type,source,priority,value");
+
+ /* Type: PSE or PD */
+ commands_new(configure_medpower, "pd", "MED power consumer", cmd_check_no_env,
+ cmd_store_env_value_and_pop, "device-type");
+ commands_new(configure_medpower, "pse", "MED power provider", cmd_check_no_env,
+ cmd_store_env_value_and_pop, "device-type");
+
+ /* Source */
+ struct cmd_node *source = commands_new(configure_medpower, "source",
+ "MED power source", cmd_check_type_but_no, NULL, "source");
+ register_commands_pow_source(source);
+
+ /* Priority */
+ struct cmd_node *priority = commands_new(configure_medpower, "priority",
+ "MED power priority", cmd_check_type_but_no, NULL, "priority");
+ register_commands_pow_priority(priority, lldpctl_k_med_power_priority);
+
+ /* Value */
+ commands_new(commands_new(configure_medpower, "value", "MED power value",
+ cmd_check_type_but_no, NULL, "value"),
+ NULL, "MED power value in milliwatts", NULL, cmd_store_env_value_and_pop2,
+ "value");
+}
+
+static int
+cmd_check_env_power(struct cmd_env *env, const void *nothing)
+{
+ /* We need type and powerpair but if we have typeat, we also request
+ * source, priority, requested and allocated. */
+ if (!cmdenv_get(env, "device-type")) return 0;
+ if (!cmdenv_get(env, "powerpairs")) return 0;
+ if (cmdenv_get(env, "typeat")) {
+ return (!!cmdenv_get(env, "source") && !!cmdenv_get(env, "priority") &&
+ !!cmdenv_get(env, "requested") && !!cmdenv_get(env, "allocated"));
+ }
+ return 1;
+}
+
+/**
+ * Register `configure med dot3` commands.
+ */
+void
+register_commands_dot3pow(struct cmd_node *configure_dot3)
+{
+ struct cmd_node *configure_dot3power = commands_new(configure_dot3, "power",
+ "Dot3 power configuration", NULL, NULL, NULL);
+
+ commands_new(configure_dot3power, NEWLINE, "Apply new Dot3 power configuration",
+ cmd_check_env_power, cmd_dot3power, NULL);
+
+ /* Type: PSE or PD */
+ commands_new(configure_dot3power, "pd", "Dot3 power consumer", cmd_check_no_env,
+ cmd_store_env_value_and_pop, "device-type");
+ commands_new(configure_dot3power, "pse", "Dot3 power provider",
+ cmd_check_no_env, cmd_store_env_value_and_pop, "device-type");
+
+ /* Flags */
+ commands_new(configure_dot3power, "supported", "MDI power support present",
+ cmd_check_type_but_no, cmd_store_env_and_pop, "supported");
+ commands_new(configure_dot3power, "enabled", "MDI power support enabled",
+ cmd_check_type_but_no, cmd_store_env_and_pop, "enabled");
+ commands_new(configure_dot3power, "paircontrol",
+ "MDI power pair can be selected", cmd_check_type_but_no,
+ cmd_store_env_and_pop, "paircontrol");
+
+ /* Power pairs */
+ struct cmd_node *powerpairs = commands_new(configure_dot3power, "powerpairs",
+ "Which pairs are currently used for power (mandatory)",
+ cmd_check_type_but_no, NULL, "powerpairs");
+ for (lldpctl_map_t *pp_map = lldpctl_key_get_map(lldpctl_k_dot3_power_pairs);
+ pp_map->string; pp_map++) {
+ commands_new(powerpairs, pp_map->string, pp_map->string, NULL,
+ cmd_store_powerpairs_env_value_and_pop2, pp_map->string);
+ }
+
+ /* Class */
+ struct cmd_node *class = commands_new(configure_dot3power, "class",
+ "Power class", cmd_check_type_but_no, NULL, "class");
+ for (lldpctl_map_t *class_map = lldpctl_key_get_map(lldpctl_k_dot3_power_class);
+ class_map->string; class_map++) {
+ const char *tag = strdup(totag(class_map->string));
+ SUPPRESS_LEAK(tag);
+ commands_new(class, tag, class_map->string, NULL,
+ cmd_store_class_env_value_and_pop2, class_map->string);
+ }
+
+ /* 802.3at type */
+ struct cmd_node *typeat = commands_new(configure_dot3power, "type",
+ "802.3at device type", cmd_check_type_but_no, NULL, "typeat");
+ commands_new(typeat, "1", "802.3at type 1", NULL, cmd_store_env_value_and_pop2,
+ "typeat");
+ commands_new(typeat, "2", "802.3at type 2", NULL, cmd_store_env_value_and_pop2,
+ "typeat");
+
+ /* Source */
+ struct cmd_node *source = commands_new(configure_dot3power, "source",
+ "802.3at dot3 power source (mandatory)", cmd_check_typeat_but_no, NULL,
+ "source");
+ register_commands_pow_source(source);
+
+ /* Priority */
+ struct cmd_node *priority = commands_new(configure_dot3power, "priority",
+ "802.3at dot3 power priority (mandatory)", cmd_check_typeat_but_no, NULL,
+ "priority");
+ register_commands_pow_priority(priority, lldpctl_k_dot3_power_priority);
+
+ /* Values */
+ commands_new(commands_new(configure_dot3power, "requested",
+ "802.3at dot3 power value requested (mandatory)",
+ cmd_check_typeat_but_no, NULL, "requested"),
+ NULL, "802.3at power value requested in milliwatts", NULL,
+ cmd_store_env_value_and_pop2, "requested");
+ commands_new(commands_new(configure_dot3power, "allocated",
+ "802.3at dot3 power value allocated (mandatory)",
+ cmd_check_typeat_but_no, NULL, "allocated"),
+ NULL, "802.3at power value allocated in milliwatts", NULL,
+ cmd_store_env_value_and_pop2, "allocated");
+}