diff options
Diffstat (limited to '')
-rw-r--r-- | src/client/conf-power.c | 389 |
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"); +} |