LCOV - code coverage report
Current view: top level - network - networkd-lldp-tx.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 15 202 7.4 %
Date: 2019-08-22 15:41:25 Functions: 2 9 22.2 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <endian.h>
       4             : #include <inttypes.h>
       5             : #include <net/if.h>
       6             : #include <net/if_arp.h>
       7             : #include <string.h>
       8             : 
       9             : #include "alloc-util.h"
      10             : #include "env-file.h"
      11             : #include "fd-util.h"
      12             : #include "hostname-util.h"
      13             : #include "missing_network.h"
      14             : #include "networkd-link.h"
      15             : #include "networkd-lldp-tx.h"
      16             : #include "networkd-manager.h"
      17             : #include "parse-util.h"
      18             : #include "random-util.h"
      19             : #include "socket-util.h"
      20             : #include "string-util.h"
      21             : #include "unaligned.h"
      22             : 
      23             : /* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
      24             : #define LLDP_TX_FAST_INIT 4U
      25             : 
      26             : /* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */
      27             : #define LLDP_TX_HOLD 4U
      28             : 
      29             : /* The jitter range to add, see 9.2.2. */
      30             : #define LLDP_JITTER_USEC (400U * USEC_PER_MSEC)
      31             : 
      32             : /* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */
      33             : #define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
      34             : 
      35             : /* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */
      36             : #define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
      37             : 
      38             : static const struct ether_addr lldp_multicast_addr[_LLDP_EMIT_MAX] = {
      39             :         [LLDP_EMIT_NEAREST_BRIDGE]  = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }},
      40             :         [LLDP_EMIT_NON_TPMR_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }},
      41             :         [LLDP_EMIT_CUSTOMER_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }},
      42             : };
      43             : 
      44           0 : bool link_lldp_emit_enabled(Link *link) {
      45           0 :         assert(link);
      46             : 
      47           0 :         if (link->flags & IFF_LOOPBACK)
      48           0 :                 return false;
      49             : 
      50           0 :         if (link->iftype != ARPHRD_ETHER)
      51           0 :                 return false;
      52             : 
      53           0 :         if (!link->network)
      54           0 :                 return false;
      55             : 
      56           0 :         return link->network->lldp_emit != LLDP_EMIT_NO;
      57             : }
      58             : 
      59           0 : static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) {
      60           0 :         assert(p);
      61             : 
      62           0 :         if (id > 127)
      63           0 :                 return -EBADMSG;
      64           0 :         if (sz > 511)
      65           0 :                 return -ENOBUFS;
      66             : 
      67           0 :         (*p)[0] = (id << 1) | !!(sz & 256);
      68           0 :         (*p)[1] = sz & 255;
      69             : 
      70           0 :         *p = *p + 2;
      71           0 :         return 0;
      72             : }
      73             : 
      74           0 : static int lldp_make_packet(
      75             :                 LLDPEmit mode,
      76             :                 const struct ether_addr *hwaddr,
      77             :                 const char *machine_id,
      78             :                 const char *ifname,
      79             :                 uint16_t ttl,
      80             :                 const char *port_description,
      81             :                 const char *hostname,
      82             :                 const char *pretty_hostname,
      83             :                 uint16_t system_capabilities,
      84             :                 uint16_t enabled_capabilities,
      85             :                 void **ret, size_t *sz) {
      86             : 
      87           0 :         size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0;
      88           0 :         _cleanup_free_ void *packet = NULL;
      89             :         struct ether_header *h;
      90             :         uint8_t *p;
      91             :         size_t l;
      92             :         int r;
      93             : 
      94           0 :         assert(mode > LLDP_EMIT_NO);
      95           0 :         assert(mode < _LLDP_EMIT_MAX);
      96           0 :         assert(hwaddr);
      97           0 :         assert(machine_id);
      98           0 :         assert(ifname);
      99           0 :         assert(ret);
     100           0 :         assert(sz);
     101             : 
     102           0 :         machine_id_length = strlen(machine_id);
     103           0 :         ifname_length = strlen(ifname);
     104             : 
     105           0 :         if (port_description)
     106           0 :                 port_description_length = strlen(port_description);
     107             : 
     108           0 :         if (hostname)
     109           0 :                 hostname_length = strlen(hostname);
     110             : 
     111           0 :         if (pretty_hostname)
     112           0 :                 pretty_hostname_length = strlen(pretty_hostname);
     113             : 
     114           0 :         l = sizeof(struct ether_header) +
     115             :                 /* Chassis ID */
     116             :                 2 + 1 + machine_id_length +
     117             :                 /* Port ID */
     118           0 :                 2 + 1 + ifname_length +
     119             :                 /* TTL */
     120             :                 2 + 2 +
     121             :                 /* System Capabilities */
     122             :                 2 + 4 +
     123             :                 /* End */
     124             :                 2;
     125             : 
     126             :         /* Port Description */
     127           0 :         if (port_description)
     128           0 :                 l += 2 + port_description_length;
     129             : 
     130             :         /* System Name */
     131           0 :         if (hostname)
     132           0 :                 l += 2 + hostname_length;
     133             : 
     134             :         /* System Description */
     135           0 :         if (pretty_hostname)
     136           0 :                 l += 2 + pretty_hostname_length;
     137             : 
     138           0 :         packet = malloc(l);
     139           0 :         if (!packet)
     140           0 :                 return -ENOMEM;
     141             : 
     142           0 :         h = (struct ether_header*) packet;
     143           0 :         h->ether_type = htobe16(ETHERTYPE_LLDP);
     144           0 :         memcpy(h->ether_dhost, lldp_multicast_addr + mode, ETH_ALEN);
     145           0 :         memcpy(h->ether_shost, hwaddr, ETH_ALEN);
     146             : 
     147           0 :         p = (uint8_t*) packet + sizeof(struct ether_header);
     148             : 
     149           0 :         r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length);
     150           0 :         if (r < 0)
     151           0 :                 return r;
     152           0 :         *(p++) = SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED;
     153           0 :         p = mempcpy(p, machine_id, machine_id_length);
     154             : 
     155           0 :         r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_ID, 1 + ifname_length);
     156           0 :         if (r < 0)
     157           0 :                 return r;
     158           0 :         *(p++) = SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME;
     159           0 :         p = mempcpy(p, ifname, ifname_length);
     160             : 
     161           0 :         r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_TTL, 2);
     162           0 :         if (r < 0)
     163           0 :                 return r;
     164           0 :         unaligned_write_be16(p, ttl);
     165           0 :         p += 2;
     166             : 
     167           0 :         if (port_description) {
     168           0 :                 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_DESCRIPTION, port_description_length);
     169           0 :                 if (r < 0)
     170           0 :                         return r;
     171           0 :                 p = mempcpy(p, port_description, port_description_length);
     172             :         }
     173             : 
     174           0 :         if (hostname) {
     175           0 :                 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_NAME, hostname_length);
     176           0 :                 if (r < 0)
     177           0 :                         return r;
     178           0 :                 p = mempcpy(p, hostname, hostname_length);
     179             :         }
     180             : 
     181           0 :         if (pretty_hostname) {
     182           0 :                 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length);
     183           0 :                 if (r < 0)
     184           0 :                         return r;
     185           0 :                 p = mempcpy(p, pretty_hostname, pretty_hostname_length);
     186             :         }
     187             : 
     188           0 :         r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_CAPABILITIES, 4);
     189           0 :         if (r < 0)
     190           0 :                 return r;
     191           0 :         unaligned_write_be16(p, system_capabilities);
     192           0 :         p += 2;
     193           0 :         unaligned_write_be16(p, enabled_capabilities);
     194           0 :         p += 2;
     195             : 
     196           0 :         r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_END, 0);
     197           0 :         if (r < 0)
     198           0 :                 return r;
     199             : 
     200           0 :         assert(p == (uint8_t*) packet + l);
     201             : 
     202           0 :         *ret = TAKE_PTR(packet);
     203           0 :         *sz = l;
     204             : 
     205           0 :         return 0;
     206             : }
     207             : 
     208           0 : static int lldp_send_packet(
     209             :                 int ifindex,
     210             :                 const struct ether_addr *address,
     211             :                 const void *packet,
     212             :                 size_t packet_size) {
     213             : 
     214           0 :         union sockaddr_union sa = {
     215             :                 .ll.sll_family = AF_PACKET,
     216           0 :                 .ll.sll_protocol = htobe16(ETHERTYPE_LLDP),
     217             :                 .ll.sll_ifindex = ifindex,
     218             :                 .ll.sll_halen = ETH_ALEN,
     219             :         };
     220             : 
     221           0 :         _cleanup_close_ int fd = -1;
     222             :         ssize_t l;
     223             : 
     224           0 :         assert(ifindex > 0);
     225           0 :         assert(address);
     226           0 :         assert(packet || packet_size <= 0);
     227             : 
     228           0 :         memcpy(sa.ll.sll_addr, address, ETH_ALEN);
     229             : 
     230           0 :         fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW);
     231           0 :         if (fd < 0)
     232           0 :                 return -errno;
     233             : 
     234           0 :         l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll));
     235           0 :         if (l < 0)
     236           0 :                 return -errno;
     237             : 
     238           0 :         if ((size_t) l != packet_size)
     239           0 :                 return -EIO;
     240             : 
     241           0 :         return 0;
     242             : }
     243             : 
     244           0 : static int link_send_lldp(Link *link) {
     245             :         char machine_id_string[SD_ID128_STRING_MAX];
     246           0 :         _cleanup_free_ char *hostname = NULL, *pretty_hostname = NULL;
     247           0 :         _cleanup_free_ void *packet = NULL;
     248           0 :         size_t packet_size = 0;
     249             :         sd_id128_t machine_id;
     250             :         uint16_t caps;
     251             :         usec_t ttl;
     252             :         int r;
     253             : 
     254           0 :         assert(link);
     255             : 
     256           0 :         if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO)
     257           0 :                 return 0;
     258             : 
     259           0 :         assert(link->network->lldp_emit < _LLDP_EMIT_MAX);
     260             : 
     261           0 :         r = sd_id128_get_machine(&machine_id);
     262           0 :         if (r < 0)
     263           0 :                 return r;
     264             : 
     265           0 :         (void) gethostname_strict(&hostname);
     266           0 :         (void) parse_env_file(NULL, "/etc/machine-info", "PRETTY_HOSTNAME", &pretty_hostname);
     267             : 
     268             :         assert_cc(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1 <= (UINT16_MAX - 1) * USEC_PER_SEC);
     269           0 :         ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC);
     270             : 
     271           0 :         caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ?
     272             :                 SD_LLDP_SYSTEM_CAPABILITIES_ROUTER :
     273             :                 SD_LLDP_SYSTEM_CAPABILITIES_STATION;
     274             : 
     275           0 :         r = lldp_make_packet(link->network->lldp_emit,
     276           0 :                              &link->mac,
     277           0 :                              sd_id128_to_string(machine_id, machine_id_string),
     278           0 :                              link->ifname,
     279           0 :                              (uint16_t) ttl,
     280           0 :                              link->network ? link->network->description : NULL,
     281             :                              hostname,
     282             :                              pretty_hostname,
     283             :                              SD_LLDP_SYSTEM_CAPABILITIES_STATION|SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE|SD_LLDP_SYSTEM_CAPABILITIES_ROUTER,
     284             :                              caps,
     285             :                              &packet, &packet_size);
     286           0 :         if (r < 0)
     287           0 :                 return r;
     288             : 
     289           0 :         return lldp_send_packet(link->ifindex, lldp_multicast_addr + link->network->lldp_emit, packet, packet_size);
     290             : }
     291             : 
     292           0 : static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
     293           0 :         Link *link = userdata;
     294             :         usec_t current, delay, next;
     295             :         int r;
     296             : 
     297           0 :         assert(s);
     298           0 :         assert(userdata);
     299             : 
     300           0 :         log_link_debug(link, "Sending LLDP packet...");
     301             : 
     302           0 :         r = link_send_lldp(link);
     303           0 :         if (r < 0)
     304           0 :                 log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m");
     305             : 
     306           0 :         if (link->lldp_tx_fast > 0)
     307           0 :                 link->lldp_tx_fast--;
     308             : 
     309           0 :         assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), &current) >= 0);
     310             : 
     311           0 :         delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC;
     312           0 :         next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC);
     313             : 
     314           0 :         r = sd_event_source_set_time(s, next);
     315           0 :         if (r < 0)
     316           0 :                 return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m");
     317             : 
     318           0 :         r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
     319           0 :         if (r < 0)
     320           0 :                 return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m");
     321             : 
     322           0 :         return 0;
     323             : }
     324             : 
     325           0 : int link_lldp_emit_start(Link *link) {
     326             :         usec_t next;
     327             :         int r;
     328             : 
     329           0 :         assert(link);
     330             : 
     331           0 :         if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) {
     332           0 :                 link_lldp_emit_stop(link);
     333           0 :                 return 0;
     334             :         }
     335             : 
     336             :         /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */
     337             : 
     338           0 :         link->lldp_tx_fast = LLDP_TX_FAST_INIT;
     339             : 
     340           0 :         next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC),
     341           0 :                      (usec_t) random_u64() % LLDP_JITTER_USEC);
     342             : 
     343           0 :         if (link->lldp_emit_event_source) {
     344             :                 usec_t old;
     345             : 
     346             :                 /* Lower the timeout, maybe */
     347           0 :                 r = sd_event_source_get_time(link->lldp_emit_event_source, &old);
     348           0 :                 if (r < 0)
     349           0 :                         return r;
     350             : 
     351           0 :                 if (old <= next)
     352           0 :                         return 0;
     353             : 
     354           0 :                 return sd_event_source_set_time(link->lldp_emit_event_source, next);
     355             :         } else {
     356           0 :                 r = sd_event_add_time(
     357           0 :                                 link->manager->event,
     358             :                                 &link->lldp_emit_event_source,
     359             :                                 clock_boottime_or_monotonic(),
     360             :                                 next,
     361             :                                 0,
     362             :                                 on_lldp_timer,
     363             :                                 link);
     364           0 :                 if (r < 0)
     365           0 :                         return r;
     366             : 
     367           0 :                 (void) sd_event_source_set_description(link->lldp_emit_event_source, "lldp-tx");
     368             :         }
     369             : 
     370           0 :         return 0;
     371             : }
     372             : 
     373          12 : void link_lldp_emit_stop(Link *link) {
     374          12 :         assert(link);
     375             : 
     376          12 :         link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source);
     377          12 : }
     378             : 
     379           3 : int config_parse_lldp_emit(
     380             :                 const char *unit,
     381             :                 const char *filename,
     382             :                 unsigned line,
     383             :                 const char *section,
     384             :                 unsigned section_line,
     385             :                 const char *lvalue,
     386             :                 int ltype,
     387             :                 const char *rvalue,
     388             :                 void *data,
     389             :                 void *userdata) {
     390             : 
     391           3 :         LLDPEmit *emit = data;
     392             :         int r;
     393             : 
     394           3 :         assert(filename);
     395           3 :         assert(lvalue);
     396           3 :         assert(rvalue);
     397             : 
     398           3 :         if (isempty(rvalue))
     399           0 :                 *emit = LLDP_EMIT_NO;
     400           3 :         else if (streq(rvalue, "nearest-bridge"))
     401           0 :                 *emit = LLDP_EMIT_NEAREST_BRIDGE;
     402           3 :         else if (streq(rvalue, "non-tpmr-bridge"))
     403           0 :                 *emit = LLDP_EMIT_NON_TPMR_BRIDGE;
     404           3 :         else if (streq(rvalue, "customer-bridge"))
     405           3 :                 *emit = LLDP_EMIT_CUSTOMER_BRIDGE;
     406             :         else {
     407           0 :                 r = parse_boolean(rvalue);
     408           0 :                 if (r < 0) {
     409           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse LLDP emission setting, ignoring: %s", rvalue);
     410           0 :                         return 0;
     411             :                 }
     412             : 
     413           0 :                 *emit = r ? LLDP_EMIT_NEAREST_BRIDGE : LLDP_EMIT_NO;
     414             :         }
     415             : 
     416           3 :         return 0;
     417             : }

Generated by: LCOV version 1.14