diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/atoms/config.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/src/lib/atoms/config.c b/src/lib/atoms/config.c new file mode 100644 index 0000000..8a4af2e --- /dev/null +++ b/src/lib/atoms/config.c @@ -0,0 +1,338 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im> + * + * 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 <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <arpa/inet.h> + +#include "../lldpctl.h" +#include "../../log.h" +#include "../atom.h" +#include "../helpers.h" + +static struct atom_map bond_slave_src_mac_map = { + .key = lldpctl_k_config_bond_slave_src_mac_type, + .map = { + { LLDP_BOND_SLAVE_SRC_MAC_TYPE_REAL, "real"}, + { LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO, "zero"}, + { LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED, "fixed"}, + { LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED, "local" }, + { LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN, NULL}, + }, +}; + +static struct atom_map lldp_portid_map = { + .key = lldpctl_k_config_lldp_portid_type, + .map = { + { LLDP_PORTID_SUBTYPE_IFNAME, "ifname"}, + { LLDP_PORTID_SUBTYPE_LLADDR, "macaddress"}, + { LLDP_PORTID_SUBTYPE_LOCAL, "local"}, + { LLDP_PORTID_SUBTYPE_UNKNOWN, NULL}, + }, +}; + +static struct atom_map lldp_agent_map = { + .key = lldpctl_k_config_lldp_agent_type, + .map = { + { LLDP_AGENT_TYPE_NEAREST_BRIDGE, "nearest bridge"}, + { LLDP_AGENT_TYPE_NEAREST_NONTPMR_BRIDGE, "nearest non-TPMR bridge"}, + { LLDP_AGENT_TYPE_NEAREST_CUSTOMER_BRIDGE, "nearest customer bridge"}, + { LLDP_AGENT_TYPE_UNKNOWN, NULL}, + }, +}; + +ATOM_MAP_REGISTER(bond_slave_src_mac_map, 1); +ATOM_MAP_REGISTER(lldp_portid_map, 2); +ATOM_MAP_REGISTER(lldp_agent_map, 3); + +static int +_lldpctl_atom_new_config(lldpctl_atom_t *atom, va_list ap) +{ + struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; + c->config = va_arg(ap, struct lldpd_config *); + return 1; +} + +static void +_lldpctl_atom_free_config(lldpctl_atom_t *atom) +{ + struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; + lldpd_config_cleanup(c->config); + free(c->config); +} + +static const char * +_lldpctl_atom_get_str_config(lldpctl_atom_t *atom, lldpctl_key_t key) +{ + char *res = NULL; + struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; + switch (key) { + case lldpctl_k_config_mgmt_pattern: + res = c->config->c_mgmt_pattern; + break; + case lldpctl_k_config_iface_pattern: + res = c->config->c_iface_pattern; + break; + case lldpctl_k_config_perm_iface_pattern: + res = c->config->c_perm_ifaces; + break; + case lldpctl_k_config_cid_pattern: + res = c->config->c_cid_pattern; + break; + case lldpctl_k_config_cid_string: + res = c->config->c_cid_string; + break; + case lldpctl_k_config_description: + res = c->config->c_description; + break; + case lldpctl_k_config_platform: + res = c->config->c_platform; + break; + case lldpctl_k_config_hostname: + res = c->config->c_hostname; + break; + case lldpctl_k_config_bond_slave_src_mac_type: + return map_lookup(bond_slave_src_mac_map.map, + c->config->c_bond_slave_src_mac_type); + case lldpctl_k_config_lldp_portid_type: + return map_lookup(lldp_portid_map.map, c->config->c_lldp_portid_type); + case lldpctl_k_config_lldp_agent_type: + return map_lookup(lldp_agent_map.map, c->config->c_lldp_agent_type); + default: + SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); + return NULL; + } + return res ? res : ""; +} + +static struct _lldpctl_atom_config_t * +__lldpctl_atom_set_str_config(struct _lldpctl_atom_config_t *c, char **local, + char **global, const char *value) +{ + if (value) { + char *aval = NULL; + size_t len = strlen(value) + 1; + aval = _lldpctl_alloc_in_atom((lldpctl_atom_t *)c, len); + if (!aval) return NULL; + memcpy(aval, value, len); + *local = aval; + free(*global); + *global = strdup(aval); + } else { + free(*global); + *local = *global = NULL; + } + return c; +} + +static lldpctl_atom_t * +_lldpctl_atom_set_str_config(lldpctl_atom_t *atom, lldpctl_key_t key, const char *value) +{ + struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; + struct lldpd_config config; + memcpy(&config, c->config, sizeof(struct lldpd_config)); + char *canary = NULL; + int rc; + + switch (key) { + case lldpctl_k_config_perm_iface_pattern: + if (!__lldpctl_atom_set_str_config(c, &config.c_perm_ifaces, + &c->config->c_perm_ifaces, value)) + return NULL; + break; + case lldpctl_k_config_iface_pattern: + if (!__lldpctl_atom_set_str_config(c, &config.c_iface_pattern, + &c->config->c_iface_pattern, value)) + return NULL; + break; + case lldpctl_k_config_mgmt_pattern: + if (!__lldpctl_atom_set_str_config(c, &config.c_mgmt_pattern, + &c->config->c_mgmt_pattern, value)) + return NULL; + break; + case lldpctl_k_config_cid_string: + if (!__lldpctl_atom_set_str_config(c, &config.c_cid_string, + &c->config->c_cid_string, value)) + return NULL; + break; + case lldpctl_k_config_description: + if (!__lldpctl_atom_set_str_config(c, &config.c_description, + &c->config->c_description, value)) + return NULL; + break; + case lldpctl_k_config_platform: + if (!__lldpctl_atom_set_str_config(c, &config.c_platform, + &c->config->c_platform, value)) + return NULL; + break; + case lldpctl_k_config_hostname: + if (!__lldpctl_atom_set_str_config(c, &config.c_hostname, + &c->config->c_hostname, value)) + return NULL; + break; + default: + SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); + return NULL; + } + + if (asprintf(&canary, "%d%s", key, value ? value : "(NULL)") == -1) { + SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); + return NULL; + } + rc = _lldpctl_do_something(atom->conn, CONN_STATE_SET_CONFIG_SEND, + CONN_STATE_SET_CONFIG_RECV, canary, SET_CONFIG, &config, + &MARSHAL_INFO(lldpd_config), NULL, NULL); + free(canary); + if (rc == 0) return atom; + +#undef SET_STR + + return NULL; +} + +static long int +_lldpctl_atom_get_int_config(lldpctl_atom_t *atom, lldpctl_key_t key) +{ + struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; + switch (key) { + case lldpctl_k_config_paused: + return c->config->c_paused; + case lldpctl_k_config_tx_interval: + return (c->config->c_tx_interval + 999) / 1000; /* s units */ + case lldpctl_k_config_tx_interval_ms: + return c->config->c_tx_interval; /* ms units */ + case lldpctl_k_config_receiveonly: + return c->config->c_receiveonly; + case lldpctl_k_config_advertise_version: + return c->config->c_advertise_version; + case lldpctl_k_config_ifdescr_update: + return c->config->c_set_ifdescr; + case lldpctl_k_config_iface_promisc: + return c->config->c_promisc; + case lldpctl_k_config_chassis_cap_advertise: + return c->config->c_cap_advertise; + case lldpctl_k_config_chassis_cap_override: + return c->config->c_cap_override; + case lldpctl_k_config_chassis_mgmt_advertise: + return c->config->c_mgmt_advertise; +#ifdef ENABLE_LLDPMED + case lldpctl_k_config_lldpmed_noinventory: + return c->config->c_noinventory; + case lldpctl_k_config_fast_start_enabled: + return c->config->c_enable_fast_start; + case lldpctl_k_config_fast_start_interval: + return c->config->c_tx_fast_interval; +#endif + case lldpctl_k_config_tx_hold: + return c->config->c_tx_hold; + case lldpctl_k_config_max_neighbors: + return c->config->c_max_neighbors; + default: + return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); + } +} + +static lldpctl_atom_t * +_lldpctl_atom_set_int_config(lldpctl_atom_t *atom, lldpctl_key_t key, long int value) +{ + int rc; + char *canary = NULL; + struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; + struct lldpd_config config; + memcpy(&config, c->config, sizeof(struct lldpd_config)); + + switch (key) { + case lldpctl_k_config_paused: + config.c_paused = c->config->c_paused = value; + break; + case lldpctl_k_config_tx_interval: + config.c_tx_interval = value * 1000; + if (value > 0) c->config->c_tx_interval = value * 1000; + break; + case lldpctl_k_config_tx_interval_ms: + config.c_tx_interval = value; + if (value > 0) c->config->c_tx_interval = value; + break; + case lldpctl_k_config_ifdescr_update: + config.c_set_ifdescr = c->config->c_set_ifdescr = value; + break; + case lldpctl_k_config_iface_promisc: + config.c_promisc = c->config->c_promisc = value; + break; + case lldpctl_k_config_chassis_cap_advertise: + config.c_cap_advertise = c->config->c_cap_advertise = value; + break; + case lldpctl_k_config_chassis_cap_override: + config.c_cap_override = c->config->c_cap_override = value; + break; + case lldpctl_k_config_chassis_mgmt_advertise: + config.c_mgmt_advertise = c->config->c_mgmt_advertise = value; + break; +#ifdef ENABLE_LLDPMED + case lldpctl_k_config_fast_start_enabled: + config.c_enable_fast_start = c->config->c_enable_fast_start = value; + break; + case lldpctl_k_config_fast_start_interval: + config.c_tx_fast_interval = c->config->c_tx_fast_interval = value; + break; +#endif + case lldpctl_k_config_tx_hold: + config.c_tx_hold = value; + if (value > 0) c->config->c_tx_hold = value; + break; + case lldpctl_k_config_max_neighbors: + config.c_max_neighbors = value; + if (value > 0) c->config->c_max_neighbors = value; + break; + case lldpctl_k_config_bond_slave_src_mac_type: + config.c_bond_slave_src_mac_type = value; + c->config->c_bond_slave_src_mac_type = value; + break; + case lldpctl_k_config_lldp_portid_type: + config.c_lldp_portid_type = value; + c->config->c_lldp_portid_type = value; + break; + case lldpctl_k_config_lldp_agent_type: + config.c_lldp_agent_type = value; + c->config->c_lldp_agent_type = value; + break; + default: + SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); + return NULL; + } + + if (asprintf(&canary, "%d%ld", key, value) == -1) { + SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); + return NULL; + } + rc = _lldpctl_do_something(atom->conn, CONN_STATE_SET_CONFIG_SEND, + CONN_STATE_SET_CONFIG_RECV, canary, SET_CONFIG, &config, + &MARSHAL_INFO(lldpd_config), NULL, NULL); + free(canary); + if (rc == 0) return atom; + return NULL; +} + +static struct atom_builder config = { atom_config, + sizeof(struct _lldpctl_atom_config_t), .init = _lldpctl_atom_new_config, + .free = _lldpctl_atom_free_config, .get_str = _lldpctl_atom_get_str_config, + .set_str = _lldpctl_atom_set_str_config, + .get_int = _lldpctl_atom_get_int_config, + .set_int = _lldpctl_atom_set_int_config }; + +ATOM_BUILDER_REGISTER(config, 1); |