From 9da663f7810ca416bbc17c01571bc67b83bf0956 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sat, 22 Aug 2015 16:34:24 +0200 Subject: [PATCH] Add a default local port as a template for any future local port. This default local port can be modified through the library and any future ports will use it as a template. --- NEWS | 2 ++ src/client/client.h | 2 ++ src/client/commands.c | 46 +++++++++++++++++++++++++ src/client/conf-lldp.c | 27 ++++++++------- src/client/conf-med.c | 11 +++--- src/client/conf-power.c | 22 +++++------- src/ctl.h | 1 + src/daemon/client.c | 46 +++++++++++++++++++------ src/daemon/lldpd.c | 74 ++++++++++++++++++++++++++++++++++++----- src/daemon/lldpd.h | 1 + src/lib/Makefile.am | 2 +- src/lib/atom.c | 22 +++++++++++- src/lib/atom.h | 5 ++- src/lib/atoms/dot3.c | 2 +- src/lib/atoms/med.c | 14 ++++---- src/lib/atoms/port.c | 28 +++++++++++----- src/lib/connection.c | 2 +- src/lib/lldpctl.h | 18 +++++++++- src/lib/lldpctl.map | 5 +++ 19 files changed, 255 insertions(+), 75 deletions(-) diff --git a/NEWS b/NEWS index af965aa7..8b814d8e 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ lldpd (0.8.0) * Change: + For Linux, switch to libnl3. Be aware of the licensing issues in case of static linking. + + Introduce the notion of default local port. New interfaces will + use it as a base. This allows setting various MED stuff. lldpd (0.7.17) * Fix: diff --git a/src/client/client.h b/src/client/client.h index 9e7fa46d..64de5faa 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -98,6 +98,8 @@ int cmd_store_something_env_value_and_pop2(const char *, struct cmd_env *, void *); lldpctl_atom_t* cmd_iterate_on_interfaces(struct lldpctl_conn_t *, struct cmd_env *); +lldpctl_atom_t* cmd_iterate_on_ports(struct lldpctl_conn_t *, + struct cmd_env *, const char **); void cmd_restrict_ports(struct cmd_node *); void cmd_restrict_protocol(struct cmd_node *); diff --git a/src/client/commands.c b/src/client/commands.c index 3fa48ace..de96ea72 100644 --- a/src/client/commands.c +++ b/src/client/commands.c @@ -711,6 +711,52 @@ cmd_iterate_on_interfaces(struct lldpctl_conn_t *conn, struct cmd_env *env) return iface; } +/** + * Provide an iterator on all ports contained in "ports", as well as the + * default port. + * + * @warning This function is not reentrant. It uses static variables to keep + * track of ports that have already been provided. Moreover, to release all + * resources, the iterator should be used until its end. + * + * @param conn The connection. + * @param env The environment. + * @param name Name of the interface (for logging purpose) + * @return The next interface in the set of ports (or in all ports if no `ports` + * variable is present in the environment), including the default port + * if no `ports` variable is present in the environment. + */ +lldpctl_atom_t* +cmd_iterate_on_ports(struct lldpctl_conn_t *conn, struct cmd_env *env, const char **name) +{ + static int put_default = 0; + static lldpctl_atom_t *last_port = NULL; + const char *interfaces = cmdenv_get(env, "ports"); + + if (last_port) { + lldpctl_atom_dec_ref(last_port); + last_port = NULL; + } + if (!put_default) { + lldpctl_atom_t *iface = cmd_iterate_on_interfaces(conn, env); + if (iface) { + *name = lldpctl_atom_get_str(iface, lldpctl_k_interface_name); + last_port = lldpctl_get_port(iface); + return last_port; + } + if (!iface && !interfaces) { + put_default = 1; + *name = "(default)"; + last_port = lldpctl_get_default_port(conn); + return last_port; + } + return NULL; + } else { + put_default = 0; + return NULL; + } +} + /** * Restrict the command to some ports. */ diff --git a/src/client/conf-lldp.c b/src/client/conf-lldp.c index a39de5eb..3c7bb322 100644 --- a/src/client/conf-lldp.c +++ b/src/client/conf-lldp.c @@ -73,7 +73,8 @@ static int cmd_portid_type_local(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env, void *arg) { - lldpctl_atom_t *iface; + lldpctl_atom_t *port; + const char *name; const char *id = cmdenv_get(env, "port-id"); const char *descr = cmdenv_get(env, "port-descr"); @@ -84,17 +85,15 @@ cmd_portid_type_local(struct lldpctl_conn_t *conn, struct writer *w, return 0; } - while ((iface = cmd_iterate_on_interfaces(conn, env))) { - lldpctl_atom_t *port = lldpctl_get_port(iface); + while ((port = cmd_iterate_on_ports(conn, env, &name))) { if (lldpctl_atom_set_str(port, lldpctl_k_port_id, id) == NULL) { - log_warnx("lldpctl", "unable to set LLDP PortID." - " %s", lldpctl_last_strerror(conn)); + log_warnx("lldpctl", "unable to set LLDP PortID for %s." + " %s", name, lldpctl_last_strerror(conn)); } if (descr && lldpctl_atom_set_str(port, lldpctl_k_port_descr, descr) == NULL) { - log_warnx("lldpctl", "unable to set LLDP Port Description." - " %s", lldpctl_last_strerror(conn)); + log_warnx("lldpctl", "unable to set LLDP Port Description for %s." + " %s", name, lldpctl_last_strerror(conn)); } - lldpctl_atom_dec_ref(port); } return 1; @@ -207,8 +206,9 @@ static int cmd_custom_tlv_set(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env, void *arg) { - lldpctl_atom_t *iface; + lldpctl_atom_t *port; const char *s; + const char *name; uint8_t oui[LLDP_TLV_ORG_OUI_LEN]; uint8_t oui_info[LLDP_TLV_ORG_OUI_INFO_MAXLEN]; int oui_info_len = 0; @@ -257,17 +257,17 @@ cmd_custom_tlv_set(struct lldpctl_conn_t *conn, struct writer *w, } set: - while ((iface = cmd_iterate_on_interfaces(conn, env))) { - lldpctl_atom_t *port = lldpctl_get_port(iface); + while ((port = cmd_iterate_on_ports(conn, env, &name))) { lldpctl_atom_t *custom_tlvs; if (!arg) { lldpctl_atom_set(port, lldpctl_k_custom_tlvs_clear, NULL); } else if (!(custom_tlvs = lldpctl_atom_get(port, lldpctl_k_custom_tlvs))) { - log_warnx("lldpctl", "unable to get custom TLVs for port"); + log_warnx("lldpctl", "unable to get custom TLVs for port %s", name); } else { lldpctl_atom_t *tlv = lldpctl_atom_create(custom_tlvs); if (!tlv) { - log_warnx("lldpctl", "unable to create new custom TLV for port"); + log_warnx("lldpctl", "unable to create new custom TLV for port %s", + name); } else { /* Configure custom TLV */ lldpctl_atom_set_buffer(tlv, lldpctl_k_custom_tlv_oui, oui, sizeof(oui)); @@ -281,7 +281,6 @@ set: } lldpctl_atom_dec_ref(custom_tlvs); } - lldpctl_atom_dec_ref(port); } return 1; diff --git a/src/client/conf-med.c b/src/client/conf-med.c index 0a8cfaf0..226b3d82 100644 --- a/src/client/conf-med.c +++ b/src/client/conf-med.c @@ -25,10 +25,9 @@ static int _cmd_medlocation(struct lldpctl_conn_t *conn, struct cmd_env *env, int format) { - lldpctl_atom_t *iface; - while ((iface = cmd_iterate_on_interfaces(conn, env))) { - const char *name = lldpctl_atom_get_str(iface, lldpctl_k_interface_name); - lldpctl_atom_t *port = lldpctl_get_port(iface); + lldpctl_atom_t *port; + const char *name; + while ((port = cmd_iterate_on_ports(conn, env, &name))) { lldpctl_atom_t *med_location = NULL, *med_locations = NULL; const char *what = NULL; int ok = 0; @@ -36,7 +35,7 @@ _cmd_medlocation(struct lldpctl_conn_t *conn, med_locations = lldpctl_atom_get(port, lldpctl_k_port_med_locations); if (med_locations == NULL) { log_warnx("lldpctl", "unable to set LLDP-MED location: support seems unavailable"); - goto end; + continue; /* Iterator needs to be run until end */ } med_location = lldpctl_atom_iter_value(med_locations, @@ -131,10 +130,8 @@ _cmd_medlocation(struct lldpctl_conn_t *conn, name); } - end: lldpctl_atom_dec_ref(med_location); lldpctl_atom_dec_ref(med_locations); - lldpctl_atom_dec_ref(port); } return 1; } diff --git a/src/client/conf-power.c b/src/client/conf-power.c index b529a764..79bddb51 100644 --- a/src/client/conf-power.c +++ b/src/client/conf-power.c @@ -26,17 +26,16 @@ cmd_medpower(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env, void *arg) { log_debug("lldpctl", "set MED power"); - lldpctl_atom_t *iface; - while ((iface = cmd_iterate_on_interfaces(conn, env))) { - const char *name = lldpctl_atom_get_str(iface, lldpctl_k_interface_name); - lldpctl_atom_t *port = lldpctl_get_port(iface); + 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"); - goto end; + continue; /* Need to finish the loop */ } if ((what = "device type", lldpctl_atom_set_str(med_power, @@ -64,9 +63,7 @@ cmd_medpower(struct lldpctl_conn_t *conn, struct writer *w, name); } - end: lldpctl_atom_dec_ref(med_power); - lldpctl_atom_dec_ref(port); } return 1; } @@ -95,10 +92,9 @@ cmd_dot3power(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env, void *arg) { log_debug("lldpctl", "set dot3 power"); - lldpctl_atom_t *iface; - while ((iface = cmd_iterate_on_interfaces(conn, env))) { - const char *name = lldpctl_atom_get_str(iface, lldpctl_k_interface_name); - lldpctl_atom_t *port = lldpctl_get_port(iface); + 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; @@ -106,7 +102,7 @@ cmd_dot3power(struct lldpctl_conn_t *conn, struct writer *w, 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"); - goto end; + continue; /* Need to finish the loop */ } if ((what = "device type", lldpctl_atom_set_str(dot3_power, @@ -177,9 +173,7 @@ cmd_dot3power(struct lldpctl_conn_t *conn, struct writer *w, name); } - end: lldpctl_atom_dec_ref(dot3_power); - lldpctl_atom_dec_ref(port); } return 1; } diff --git a/src/ctl.h b/src/ctl.h index 92c81976..86425b62 100644 --- a/src/ctl.h +++ b/src/ctl.h @@ -32,6 +32,7 @@ enum hmsg_type { GET_INTERFACES, /* Get list of interfaces */ GET_CHASSIS, /* Get local chassis */ GET_INTERFACE, /* Get all information related to an interface */ + GET_DEFAULT_PORT, /* Get all information related to default port */ SET_PORT, /* Set port-related information (location, power, policy) */ SUBSCRIBE, /* Subscribe to neighbor changes */ NOTIFICATION, /* Notification message (sent by lldpd!) */ diff --git a/src/daemon/client.c b/src/daemon/client.c index 17f19d4b..80d50104 100644 --- a/src/daemon/client.c +++ b/src/daemon/client.c @@ -246,7 +246,7 @@ static ssize_t client_handle_get_local_chassis(struct lldpd *cfg, enum hmsg_type *type, void *input, int input_len, void **output, int *subscribed) { - struct lldpd_chassis *chassis = LOCAL_CHASSIS(cfg); + struct lldpd_chassis *chassis = LOCAL_CHASSIS(cfg); ssize_t output_len; log_debug("rpc", "client request the local chassis"); @@ -297,6 +297,23 @@ client_handle_get_interface(struct lldpd *cfg, enum hmsg_type *type, return 0; } +/* Return all available information related to an interface + Input: name of the interface (serialized) + Output: Information about the interface (lldpd_hardware) +*/ +static ssize_t +client_handle_get_default_port(struct lldpd *cfg, enum hmsg_type *type, + void *input, int input_len, void **output, int *subscribed) +{ + log_debug("rpc", "client request the default local port"); + ssize_t output_len = lldpd_port_serialize(cfg->g_default_local_port, output); + if (output_len <= 0) { + *type = NONE; + return 0; + } + return output_len; +} + static int _client_handle_set_port(struct lldpd *cfg, struct lldpd_port *port, struct lldpd_port_set *set) @@ -415,15 +432,23 @@ client_handle_set_port(struct lldpd *cfg, enum hmsg_type *type, } /* Search the appropriate hardware */ - log_debug("rpc", "client request change to port %s", set->ifname); - TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) - if (!strcmp(hardware->h_ifname, set->ifname)) { - struct lldpd_port *port = &hardware->h_lport; - if (_client_handle_set_port(cfg, port, set) == -1) - goto set_port_finished; - ret = 1; - break; - } + if (strlen(set->ifname) == 0) { + log_debug("rpc", "client request change to default port"); + if (_client_handle_set_port(cfg, cfg->g_default_local_port, set) == -1) + goto set_port_finished; + ret = 1; + } else { + log_debug("rpc", "client request change to port %s", set->ifname); + TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) { + if (!strcmp(hardware->h_ifname, set->ifname)) { + struct lldpd_port *port = &hardware->h_lport; + if (_client_handle_set_port(cfg, port, set) == -1) + goto set_port_finished; + ret = 1; + break; + } + } + } if (ret == 0) log_warn("rpc", "no interface %s found", set->ifname); @@ -476,6 +501,7 @@ static struct client_handle client_handles[] = { { SET_CONFIG, "Set configuration", client_handle_set_configuration }, { GET_INTERFACES, "Get interfaces", client_handle_get_interfaces }, { GET_INTERFACE, "Get interface", client_handle_get_interface }, + { GET_DEFAULT_PORT, "Get default port", client_handle_get_default_port }, { GET_CHASSIS, "Get local chassis", client_handle_get_local_chassis }, { SET_PORT, "Set port", client_handle_set_port }, { SUBSCRIBE, "Subscribe", client_handle_subscribe }, diff --git a/src/daemon/lldpd.c b/src/daemon/lldpd.c index f32cd05b..c47209de 100644 --- a/src/daemon/lldpd.c +++ b/src/daemon/lldpd.c @@ -139,6 +139,64 @@ lldpd_get_hardware(struct lldpd *cfg, char *name, int index, struct lldpd_ops *o return hardware; } +/** + * Allocate the default local port. This port will be cloned each time we need a + * new local port. + */ +static void +lldpd_alloc_default_local_port(struct lldpd *cfg) +{ + struct lldpd_port *port; + + if ((port = (struct lldpd_port *) + calloc(1, sizeof(struct lldpd_port))) == NULL) + fatal("main", NULL); + +#ifdef ENABLE_DOT1 + TAILQ_INIT(&port->p_vlans); + TAILQ_INIT(&port->p_ppvids); + TAILQ_INIT(&port->p_pids); +#endif +#ifdef ENABLE_CUSTOM + TAILQ_INIT(&port->p_custom_list); +#endif + cfg->g_default_local_port = port; +} + +/** + * Clone a given port. The destination needs to be already allocated. + */ +static int +lldpd_clone_port(struct lldpd_port *destination, struct lldpd_port *source) +{ + + u_int8_t *output = NULL; + ssize_t output_len; + struct lldpd_port *cloned = NULL; + output_len = lldpd_port_serialize(source, (void**)&output); + if (output_len == -1 || + lldpd_port_unserialize(output, output_len, &cloned) <= 0) { + log_warnx("alloc", "unable to clone default port"); + goto end; + } + memcpy(destination, cloned, sizeof(struct lldpd_port)); + free(cloned); cloned = NULL; +#ifdef ENABLE_DOT1 + marshal_repair_tailq(lldpd_vlan, &destination->p_vlans, v_entries); + marshal_repair_tailq(lldpd_ppvid, &destination->p_ppvids, p_entries); + marshal_repair_tailq(lldpd_pi, &destination->p_pids, p_entries); +#endif +#ifdef ENABLE_CUSTOM + marshal_repair_tailq(lldpd_custom, &destination->p_custom_list, next); +#endif + return 0; + +end: + free(output); + if (cloned != NULL) lldpd_port_cleanup(cloned, 1); + return -1; +} + struct lldpd_hardware * lldpd_alloc_hardware(struct lldpd *cfg, char *name, int index) { @@ -150,6 +208,13 @@ lldpd_alloc_hardware(struct lldpd *cfg, char *name, int index) calloc(1, sizeof(struct lldpd_hardware))) == NULL) return NULL; + /* Clone default local port */ + if (lldpd_clone_port(&hardware->h_lport, cfg->g_default_local_port) == -1) { + log_warnx("alloc", "unable to clone default port"); + free(hardware); + return NULL; + } + hardware->h_cfg = cfg; strlcpy(hardware->h_ifname, name, sizeof(hardware->h_ifname)); hardware->h_ifindex = index; @@ -164,14 +229,6 @@ lldpd_alloc_hardware(struct lldpd *cfg, char *name, int index) hardware->h_lport.p_med_cap_enabled |= LLDP_MED_CAP_IV; } #endif -#ifdef ENABLE_DOT1 - TAILQ_INIT(&hardware->h_lport.p_vlans); - TAILQ_INIT(&hardware->h_lport.p_ppvids); - TAILQ_INIT(&hardware->h_lport.p_pids); -#endif -#ifdef ENABLE_CUSTOM - TAILQ_INIT(&hardware->h_lport.p_custom_list); -#endif levent_hardware_init(hardware); return hardware; @@ -1601,6 +1658,7 @@ lldpd_main(int argc, char *argv[], char *envp[]) calloc(1, sizeof(struct lldpd))) == NULL) fatal("main", NULL); + lldpd_alloc_default_local_port(cfg); cfg->g_ctlname = ctlname; cfg->g_ctl = ctl; cfg->g_config.c_mgmt_pattern = mgmtp; diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index cf6f2fa9..07b93569 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -417,6 +417,7 @@ struct lldpd { struct lldpd_netlink *g_netlink; #endif + struct lldpd_port *g_default_local_port; #define LOCAL_CHASSIS(cfg) ((struct lldpd_chassis *)(TAILQ_FIRST(&cfg->g_chassis))) TAILQ_HEAD(, lldpd_chassis) g_chassis; TAILQ_HEAD(, lldpd_hardware) g_hardware; diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 9f5e89de..b419b551 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -21,7 +21,7 @@ liblldpctl_la_LIBADD = $(top_builddir)/src/libcommon-daemon-lib.la libfixedpoin # -version-number could be computed from -version-info, mostly major # is `current` - `age`, minor is `age` and revision is `revision' and # major.minor should be used when updaing lldpctl.map. -liblldpctl_la_LDFLAGS = $(AM_LDFLAGS) -version-info 11:0:7 +liblldpctl_la_LDFLAGS = $(AM_LDFLAGS) -version-info 12:0:8 liblldpctl_la_DEPENDENCIES = libfixedpoint.la if HAVE_LD_VERSION_SCRIPT diff --git a/src/lib/atom.c b/src/lib/atom.c index ddf849ee..70858553 100644 --- a/src/lib/atom.c +++ b/src/lib/atom.c @@ -479,12 +479,32 @@ lldpctl_get_port(lldpctl_atom_t *atom) &p, &MARSHAL_INFO(lldpd_hardware)); if (rc == 0) { hardware = p; - return _lldpctl_new_atom(conn, atom_port, + return _lldpctl_new_atom(conn, atom_port, 1, hardware, &hardware->h_lport, NULL); } return NULL; } +lldpctl_atom_t* +lldpctl_get_default_port(lldpctl_conn_t *conn) +{ + struct lldpd_port *port; + void *p; + int rc; + + RESET_ERROR(conn); + + rc = _lldpctl_do_something(conn, + CONN_STATE_GET_DEFAULT_PORT_SEND, CONN_STATE_GET_DEFAULT_PORT_RECV, "", + GET_DEFAULT_PORT, NULL, NULL, + &p, &MARSHAL_INFO(lldpd_port)); + if (rc == 0) { + port = p; + return _lldpctl_new_atom(conn, atom_port, 1, NULL, port, NULL); + } + return NULL; +} + static lldpctl_map_t empty_map[] = {{ 0, NULL }}; static struct atom_map atom_map_list = { diff --git a/src/lib/atom.h b/src/lib/atom.h index 18abf6fa..e179fd02 100644 --- a/src/lib/atom.h +++ b/src/lib/atom.h @@ -52,6 +52,8 @@ struct lldpctl_conn_t { #define CONN_STATE_SET_CONFIG_RECV 11 #define CONN_STATE_GET_CHASSIS_SEND 12 #define CONN_STATE_GET_CHASSIS_RECV 13 +#define CONN_STATE_GET_DEFAULT_PORT_SEND 14 +#define CONN_STATE_GET_DEFAULT_PORT_RECV 15 int state; /* Current state */ char *state_data; /* Data attached to the state. It is used to * check that we are using the same data as a @@ -180,7 +182,8 @@ struct _lldpctl_atom_chassis_t { struct _lldpctl_atom_port_t { lldpctl_atom_t base; - struct lldpd_hardware *hardware; /* Local port only */ + int local; /* Local or remote port? */ + struct lldpd_hardware *hardware; /* Local port only (but optional) */ struct lldpd_port *port; /* Local and remote */ struct _lldpctl_atom_port_t *parent; /* Local port if we are a remote port */ lldpctl_atom_t *chassis; /* Internal atom for chassis */ diff --git a/src/lib/atoms/dot3.c b/src/lib/atoms/dot3.c index 9e21abde..19d62c46 100644 --- a/src/lib/atoms/dot3.c +++ b/src/lib/atoms/dot3.c @@ -176,7 +176,7 @@ _lldpctl_atom_set_int_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key, struct lldpd_port *port = dpow->parent->port; /* Only local port can be modified */ - if (dpow->parent->hardware == NULL) { + if (!dpow->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } diff --git a/src/lib/atoms/med.c b/src/lib/atoms/med.c index 45ee2e2f..6c425c64 100644 --- a/src/lib/atoms/med.c +++ b/src/lib/atoms/med.c @@ -226,7 +226,7 @@ _lldpctl_atom_set_int_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key, (struct _lldpctl_atom_med_policy_t *)atom; /* Only local port can be modified */ - if (m->parent->hardware == NULL) { + if (!m->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } @@ -399,7 +399,7 @@ _lldpctl_atom_set_int_med_location(lldpctl_atom_t *atom, lldpctl_key_t key, (struct _lldpctl_atom_med_location_t *)atom; /* Only local port can be modified */ - if (mloc->parent->hardware == NULL) { + if (!mloc->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } @@ -568,7 +568,7 @@ _lldpctl_atom_set_str_med_location(lldpctl_atom_t *atom, lldpctl_key_t key, char *end = NULL; /* Only local port can be modified */ - if (mloc->parent->hardware == NULL) { + if (!mloc->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } @@ -683,7 +683,7 @@ _lldpctl_atom_set_atom_med_location(lldpctl_atom_t *atom, lldpctl_key_t key, uint8_t *new; /* Only local port can be modified */ - if (m->parent->hardware == NULL) { + if (!m->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } @@ -818,7 +818,7 @@ _lldpctl_atom_set_int_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key, (struct _lldpctl_atom_med_caelement_t *)atom; /* Only local port can be modified */ - if (el->parent->parent->hardware == NULL) { + if (!el->parent->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } @@ -870,7 +870,7 @@ _lldpctl_atom_set_str_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key, size_t len; /* Only local port can be modified */ - if (el->parent->parent->hardware == NULL) { + if (!el->parent->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } @@ -972,7 +972,7 @@ _lldpctl_atom_set_int_med_power(lldpctl_atom_t *atom, lldpctl_key_t key, struct lldpd_port *port = dpow->parent->port; /* Only local port can be modified */ - if (dpow->parent->hardware == NULL) { + if (!dpow->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } diff --git a/src/lib/atoms/port.c b/src/lib/atoms/port.c index 7cab6959..5719616e 100644 --- a/src/lib/atoms/port.c +++ b/src/lib/atoms/port.c @@ -127,7 +127,7 @@ static lldpctl_atom_t* _lldpctl_atom_value_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter) { struct lldpd_port *port = (struct lldpd_port *)iter; - return _lldpctl_new_atom(atom->conn, atom_port, NULL, port, + return _lldpctl_new_atom(atom->conn, atom_port, 0, NULL, port, ((struct _lldpctl_atom_any_list_t *)atom)->parent); } @@ -136,6 +136,7 @@ _lldpctl_atom_new_port(lldpctl_atom_t *atom, va_list ap) { struct _lldpctl_atom_port_t *port = (struct _lldpctl_atom_port_t *)atom; + port->local = va_arg(ap, int); port->hardware = va_arg(ap, struct lldpd_hardware*); port->port = va_arg(ap, struct lldpd_port*); port->parent = va_arg(ap, struct _lldpctl_atom_port_t*); @@ -186,8 +187,10 @@ _lldpctl_atom_free_port(lldpctl_atom_t *atom) else if (!hardware) { /* No parent, no hardware, we assume a single neighbor: one * port, one chassis. */ - lldpd_chassis_cleanup(port->port->p_chassis, 1); - port->port->p_chassis = NULL; + if (port->port->p_chassis) { + lldpd_chassis_cleanup(port->port->p_chassis, 1); + port->port->p_chassis = NULL; + } lldpd_port_cleanup(port->port, 1); free(port->port); } @@ -231,8 +234,12 @@ _lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key) /* Local and remote port */ switch (key) { case lldpctl_k_port_chassis: - return _lldpctl_new_atom(atom->conn, atom_chassis, - port->p_chassis, p, 0); + if (port->p_chassis) { + return _lldpctl_new_atom(atom->conn, atom_chassis, + port->p_chassis, p, 0); + } + SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); + return NULL; #ifdef ENABLE_DOT3 case lldpctl_k_port_dot3_power: return _lldpctl_new_atom(atom->conn, atom_dot3_power, @@ -265,7 +272,10 @@ _lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key) #endif default: /* Compatibility: query the associated chassis too */ - return lldpctl_atom_get(p->chassis, key); + if (port->p_chassis) + return lldpctl_atom_get(p->chassis, key); + SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); + return NULL; } } @@ -291,8 +301,8 @@ _lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_ato struct _lldpctl_atom_custom_t *custom; #endif - /* Local port only */ - if (hardware == NULL) { + /* Local and default port only */ + if (!p->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } @@ -360,7 +370,7 @@ _lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_ato return NULL; } - set.ifname = hardware->h_ifname; + set.ifname = hardware ? hardware->h_ifname : ""; if (asprintf(&canary, "%d%p%s", key, value, set.ifname) == -1) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); diff --git a/src/lib/connection.c b/src/lib/connection.c index 691b3bd2..aeb702e5 100644 --- a/src/lib/connection.c +++ b/src/lib/connection.c @@ -208,7 +208,7 @@ check_for_notification(lldpctl_conn_t *conn) interface = _lldpctl_new_atom(conn, atom_interface, change->ifname); if (interface == NULL) goto end; - neighbor = _lldpctl_new_atom(conn, atom_port, + neighbor = _lldpctl_new_atom(conn, atom_port, 0, NULL, change->neighbor, NULL); if (neighbor == NULL) goto end; conn->watch_cb(conn, type, interface, neighbor, conn->watch_data); diff --git a/src/lib/lldpctl.h b/src/lib/lldpctl.h index c1774e88..c76ccd5c 100644 --- a/src/lib/lldpctl.h +++ b/src/lib/lldpctl.h @@ -560,7 +560,7 @@ lldpctl_atom_t *lldpctl_get_local_chassis(lldpctl_conn_t *conn); * atom retrieved from an interation on @c lldpctl_get_interfaces(). * @return Atom related to this port which may be used in subsequent functions. * - * This functions may have to do IO to get the information related to the given + * This function may have to do IO to get the information related to the given * port. Depending on the IO mode, information may not be available right now * and the function should be called again later. If @c NULL is returned, check * what the last error is. If it is @c LLDPCTL_ERR_WOULDBLOCK, try again later @@ -568,6 +568,22 @@ lldpctl_atom_t *lldpctl_get_local_chassis(lldpctl_conn_t *conn); */ lldpctl_atom_t *lldpctl_get_port(lldpctl_atom_t *port); +/** + * Retrieve the default port information. + * + * This port contains default settings whenever a new port needs to be created. + * + * @param conn Previously allocated handler to a connection to lldpd. + * @return Atom of the default port which may be used in subsequent functions. + * + * This function may have to do IO to get the information related to the given + * port. Depending on the IO mode, information may not be available right now + * and the function should be called again later. If @c NULL is returned, check + * what the last error is. If it is @c LLDPCTL_ERR_WOULDBLOCK, try again later + * (when more data is available). + */ +lldpctl_atom_t *lldpctl_get_default_port(lldpctl_conn_t *conn); + /**@}*/ /** diff --git a/src/lib/lldpctl.map b/src/lib/lldpctl.map index c8f46d5d..c725381a 100644 --- a/src/lib/lldpctl.map +++ b/src/lib/lldpctl.map @@ -1,3 +1,8 @@ +LIBLLDPCTL_4.8 { + global: + lldpctl_get_default_port; +}; + LIBLLDPCTL_4.7 { global: lldpctl_get_local_chassis; -- 2.39.5