diff options
author | Lennart Poettering <lennart@poettering.net> | 2016-02-19 17:58:52 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2016-02-21 20:40:56 +0100 |
commit | 34437b4f9c9c51b0a6f93788bdb9a105b8e46b66 (patch) | |
tree | 4c5069ae6356036a4f347ca7acd8df8d0332d97c /src/libsystemd-network/lldp-internal.c | |
parent | 1b4cd0cf11feb7d41f2eff17f86fa55b31bb6841 (diff) | |
download | systemd-34437b4f9c9c51b0a6f93788bdb9a105b8e46b66.tar.gz |
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
Diffstat (limited to 'src/libsystemd-network/lldp-internal.c')
-rw-r--r-- | src/libsystemd-network/lldp-internal.c | 360 |
1 files changed, 0 insertions, 360 deletions
diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c deleted file mode 100644 index c8740ce5f0..0000000000 --- a/src/libsystemd-network/lldp-internal.c +++ /dev/null @@ -1,360 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include "sd-lldp.h" - -#include "alloc-util.h" -#include "lldp-internal.h" - -/* We store maximum 1K chassis entries */ -#define LLDP_MIB_MAX_CHASSIS 1024 - -/* Maximum Ports can be attached to any chassis */ -#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32 - -/* 10.5.5.2.2 mibUpdateObjects () - * The mibUpdateObjects () procedure updates the MIB objects corresponding to - * the TLVs contained in the received LLDPDU for the LLDP remote system - * indicated by the LLDP remote systems update process defined in 10.3.5 */ - -int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { - lldp_neighbour_port *p; - uint16_t length, ttl; - uint8_t *data; - uint8_t type; - int r; - - assert_return(c, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - /* Update the packet if we already have */ - LIST_FOREACH(port, p, c->ports) { - - if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) { - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - return r; - - p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - - sd_lldp_packet_unref(p->packet); - p->packet = tlv; - - prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx); - - return 0; - } - } - - return -1; -} - -int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) { - lldp_neighbour_port *p, *q; - uint8_t *data; - uint16_t length; - uint8_t type; - int r; - - assert_return(c, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - LIST_FOREACH_SAFE(port, p, q, c->ports) { - - /* Find the port */ - if (p->type == type && p->length == length && !memcmp(p->data, data, p->length)) { - lldp_neighbour_port_remove_and_free(p); - break; - } - } - - return 0; -} - -int lldp_mib_add_objects(Prioq *by_expiry, - Hashmap *neighbour_mib, - tlv_packet *tlv) { - _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; - _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; - lldp_chassis_id chassis_id; - bool new_chassis = false; - uint8_t subtype, *data; - uint16_t ttl, length; - int r; - - assert_return(by_expiry, -EINVAL); - assert_return(neighbour_mib, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length); - if (r < 0) - goto drop; - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - goto drop; - - /* Make hash key */ - chassis_id.type = subtype; - chassis_id.length = length; - chassis_id.data = data; - - /* Try to find the Chassis */ - c = hashmap_get(neighbour_mib, &chassis_id); - if (!c) { - - /* Don't create chassis if ttl 0 is received . Silently drop it */ - if (ttl == 0) { - log_lldp("TTL value 0 received. Skiping Chassis creation."); - goto drop; - } - - /* Admission Control: Can we store this packet ? */ - if (hashmap_size(neighbour_mib) >= LLDP_MIB_MAX_CHASSIS) { - - log_lldp("Exceeding number of chassie: %d. Dropping ...", - hashmap_size(neighbour_mib)); - goto drop; - } - - r = lldp_chassis_new(tlv, by_expiry, neighbour_mib, &c); - if (r < 0) - goto drop; - - new_chassis = true; - - r = hashmap_put(neighbour_mib, &c->chassis_id, c); - if (r < 0) - goto drop; - - } else { - - /* When the TTL field is set to zero, the receiving LLDP agent is notified all - * system information associated with the LLDP agent/port is to be deleted */ - if (ttl == 0) { - log_lldp("TTL value 0 received . Deleting associated Port ..."); - - lldp_mib_remove_objects(c, tlv); - - c = NULL; - goto drop; - } - - /* if we already have this port just update it */ - r = lldp_mib_update_objects(c, tlv); - if (r >= 0) { - c = NULL; - return r; - } - - /* Admission Control: Can this port attached to the existing chassis ? */ - if (c->n_ref >= LLDP_MIB_MAX_PORT_PER_CHASSIS) { - log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", c->n_ref); - - c = NULL; - goto drop; - } - } - - /* This is a new port */ - r = lldp_neighbour_port_new(c, tlv, &p); - if (r < 0) - goto drop; - - r = prioq_put(c->by_expiry, p, &p->prioq_idx); - if (r < 0) - goto drop; - - /* Attach new port to chassis */ - LIST_PREPEND(port, c->ports, p); - c->n_ref ++; - - p = NULL; - c = NULL; - - return 0; - - drop: - sd_lldp_packet_unref(tlv); - - if (new_chassis) - hashmap_remove(neighbour_mib, &c->chassis_id); - - return r; -} - -void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) { - lldp_chassis *c; - - assert(p); - assert(p->c); - - c = p->c; - - prioq_remove(c->by_expiry, p, &p->prioq_idx); - - LIST_REMOVE(port, c->ports, p); - lldp_neighbour_port_free(p); - - /* Drop the Chassis if no port is attached */ - c->n_ref --; - if (c->n_ref <= 1) { - hashmap_remove(c->neighbour_mib, &c->chassis_id); - lldp_chassis_free(c); - } -} - -void lldp_neighbour_port_free(lldp_neighbour_port *p) { - - if(!p) - return; - - sd_lldp_packet_unref(p->packet); - - free(p->data); - free(p); -} - -int lldp_neighbour_port_new(lldp_chassis *c, - tlv_packet *tlv, - lldp_neighbour_port **ret) { - _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; - uint16_t length, ttl; - uint8_t *data; - uint8_t type; - int r; - - assert(tlv); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - return r; - - p = new0(lldp_neighbour_port, 1); - if (!p) - return -ENOMEM; - - p->c = c; - p->type = type; - p->length = length; - p->packet = tlv; - p->prioq_idx = PRIOQ_IDX_NULL; - p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - - p->data = memdup(data, length); - if (!p->data) - return -ENOMEM; - - *ret = p; - p = NULL; - - return 0; -} - -void lldp_chassis_free(lldp_chassis *c) { - - if (!c) - return; - - if (c->n_ref > 1) - return; - - free(c->chassis_id.data); - free(c); -} - -int lldp_chassis_new(tlv_packet *tlv, - Prioq *by_expiry, - Hashmap *neighbour_mib, - lldp_chassis **ret) { - _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; - uint16_t length; - uint8_t *data; - uint8_t type; - int r; - - assert(tlv); - - r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - c = new0(lldp_chassis, 1); - if (!c) - return -ENOMEM; - - c->n_ref = 1; - c->chassis_id.type = type; - c->chassis_id.length = length; - - c->chassis_id.data = memdup(data, length); - if (!c->chassis_id.data) - return -ENOMEM; - - LIST_HEAD_INIT(c->ports); - - c->by_expiry = by_expiry; - c->neighbour_mib = neighbour_mib; - - *ret = c; - c = NULL; - - return 0; -} - -int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *packet = NULL; - tlv_packet *p; - uint16_t length; - int r; - - assert(fd); - assert(userdata); - - r = tlv_packet_new(&packet); - if (r < 0) - return r; - - length = read(fd, &packet->pdu, sizeof(packet->pdu)); - - /* Silently drop the packet */ - if ((size_t) length > ETHER_MAX_LEN) - return 0; - - packet->userdata = userdata; - - p = packet; - packet = NULL; - - return lldp_handle_packet(p, (uint16_t) length); -} |