From e55e7492216618820047ec9e03d290bfe1d13385 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sat, 11 Jul 2015 22:29:12 +0200 Subject: [PATCH] lib: add compatibility layer with chassis-related information When querying a port, if we don't find the requested information, check if the chassis has the information as well. --- src/lib/atom.c | 2 +- src/lib/atom.h | 2 ++ src/lib/atoms/chassis.c | 20 +++++++++++++++----- src/lib/atoms/port.c | 26 ++++++++++++++++++-------- tests/lldpcli.conf | 2 +- 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/lib/atom.c b/src/lib/atom.c index 054c7bd3..ddf849ee 100644 --- a/src/lib/atom.c +++ b/src/lib/atom.c @@ -452,7 +452,7 @@ lldpctl_get_local_chassis(lldpctl_conn_t *conn) &p, &MARSHAL_INFO(lldpd_chassis)); if (rc == 0) { chassis = p; - return _lldpctl_new_atom(conn, atom_chassis, chassis, NULL); + return _lldpctl_new_atom(conn, atom_chassis, chassis, NULL, 0); } return NULL; } diff --git a/src/lib/atom.h b/src/lib/atom.h index 613d8594..18abf6fa 100644 --- a/src/lib/atom.h +++ b/src/lib/atom.h @@ -175,6 +175,7 @@ struct _lldpctl_atom_chassis_t { lldpctl_atom_t base; struct lldpd_chassis *chassis; struct _lldpctl_atom_port_t *parent; /* Optional: parent of this atom (owning our reference) */ + int embedded; /* This atom is "embedded" (not refcounted) */ }; struct _lldpctl_atom_port_t { @@ -182,6 +183,7 @@ struct _lldpctl_atom_port_t { struct lldpd_hardware *hardware; /* Local port only */ 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 */ }; /* Can represent any simple list holding just a reference to a port. */ diff --git a/src/lib/atoms/chassis.c b/src/lib/atoms/chassis.c index 4316103e..006996fc 100644 --- a/src/lib/atoms/chassis.c +++ b/src/lib/atoms/chassis.c @@ -55,7 +55,8 @@ _lldpctl_atom_new_chassis(lldpctl_atom_t *atom, va_list ap) (struct _lldpctl_atom_chassis_t *)atom; p->chassis = va_arg(ap, struct lldpd_chassis*); p->parent = va_arg(ap, struct _lldpctl_atom_port_t*); - if (p->parent) + p->embedded = va_arg(ap, int); + if (p->parent && !p->embedded) lldpctl_atom_inc_ref((lldpctl_atom_t*)p->parent); return 1; } @@ -67,9 +68,15 @@ _lldpctl_atom_free_chassis(lldpctl_atom_t *atom) (struct _lldpctl_atom_chassis_t *)atom; /* When we have a parent, the chassis structure is in fact part of the * parent, just decrement the reference count of the parent. Otherwise, - * we need to free the whole chassis. */ - if (p->parent) lldpctl_atom_dec_ref((lldpctl_atom_t*)p->parent); - else lldpd_chassis_cleanup(p->chassis, 1); + * we need to free the whole chassis. When embedded, we don't alter the + * reference count of the parent. Therefore, it's important to also not + * increase the reference count of this atom. See + * `_lldpctl_atom_get_atom_chassis' for how to handle that. */ + if (p->parent) { + if (!p->embedded) + lldpctl_atom_dec_ref((lldpctl_atom_t*)p->parent); + } else + lldpd_chassis_cleanup(p->chassis, 1); } static lldpctl_atom_t* @@ -82,7 +89,10 @@ _lldpctl_atom_get_atom_chassis(lldpctl_atom_t *atom, lldpctl_key_t key) switch (key) { case lldpctl_k_chassis_mgmt: return _lldpctl_new_atom(atom->conn, atom_mgmts_list, - p, chassis); + (p->parent && p->embedded)? + (lldpctl_atom_t *)p->parent: + (lldpctl_atom_t *)p, + chassis); default: 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 e419a8ed..7cab6959 100644 --- a/src/lib/atoms/port.c +++ b/src/lib/atoms/port.c @@ -141,6 +141,11 @@ _lldpctl_atom_new_port(lldpctl_atom_t *atom, va_list ap) port->parent = va_arg(ap, struct _lldpctl_atom_port_t*); if (port->parent) lldpctl_atom_inc_ref((lldpctl_atom_t*)port->parent); + + /* Internal atom. We are the parent, but our reference count is not + * incremented. */ + port->chassis = _lldpctl_new_atom(atom->conn, atom_chassis, + port->port->p_chassis, port, 1); return 1; } @@ -167,6 +172,10 @@ _lldpctl_atom_free_port(lldpctl_atom_t *atom) struct lldpd_chassis *one_chassis, *one_chassis_next; struct lldpd_port *one_port; + /* Free internal chassis atom. Should be freed immediately since we + * should have the only reference. */ + lldpctl_atom_dec_ref((lldpctl_atom_t*)port->chassis); + /* We need to free the whole struct lldpd_hardware: local port, local * chassis and remote ports... The same chassis may be present several * times. We build a list of chassis (we don't use reference count). */ @@ -223,7 +232,7 @@ _lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key) switch (key) { case lldpctl_k_port_chassis: return _lldpctl_new_atom(atom->conn, atom_chassis, - port->p_chassis, p); + port->p_chassis, p, 0); #ifdef ENABLE_DOT3 case lldpctl_k_port_dot3_power: return _lldpctl_new_atom(atom->conn, atom_dot3_power, @@ -255,8 +264,8 @@ _lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key) return _lldpctl_new_atom(atom->conn, atom_custom_list, p); #endif default: - SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); - return NULL; + /* Compatibility: query the associated chassis too */ + return lldpctl_atom_get(p->chassis, key); } } @@ -430,8 +439,8 @@ _lldpctl_atom_get_str_port(lldpctl_atom_t *atom, lldpctl_key_t key) #endif default: - SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); - return NULL; + /* Compatibility: query the associated chassis too */ + return lldpctl_atom_get_str(p->chassis, key); } } @@ -528,7 +537,8 @@ _lldpctl_atom_get_int_port(lldpctl_atom_t *atom, lldpctl_key_t key) return port->p_pvid; #endif default: - return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); + /* Compatibility: query the associated chassis too */ + return lldpctl_atom_get_int(p->chassis, key); } return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); } @@ -545,8 +555,8 @@ _lldpctl_atom_get_buf_port(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n) *n = port->p_id_len; return (uint8_t*)port->p_id; default: - SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); - return NULL; + /* Compatibility: query the associated chassis too */ + return lldpctl_atom_get_buffer(p->chassis, key, n); } } diff --git a/tests/lldpcli.conf b/tests/lldpcli.conf index 9a5b9fec..94d2d41f 100644 --- a/tests/lldpcli.conf +++ b/tests/lldpcli.conf @@ -49,4 +49,4 @@ configure ports eth0 dot3 power pse supported enabled paircontrol powerpairs spa configure dot3 power pd supported enabled powerpairs spare class class-3 type 1 source pse priority low requested 10000 allocated 15000 # A convenient way to "test" lldpcli and liblldpctl is to load those commands in lldpcli with valgrind: -# libtool execute valgrind --suppressions=../src/client/lldpcli.supp --leak-check=full src/client/lldpcli -c ../src/client/lldpcli.conf +# libtool execute valgrind --suppressions=../src/client/lldpcli.supp --leak-check=full src/client/lldpcli -c ../tests/lldpcli.conf -- 2.39.5