LLDP: Add support to transmit MUD URL

This commit is contained in:
Susant Sahani 2020-03-30 21:57:58 +02:00
parent f69b4ae885
commit e9a8c550c1
7 changed files with 108 additions and 1 deletions

View File

@ -459,6 +459,7 @@
reception.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>BindCarrier=</varname></term>
<listitem>
@ -2351,6 +2352,28 @@
</variablelist>
</refsect1>
<refsect1>
<title>[LLDP] Section Options</title>
<para>The <literal>[LLDP]</literal> section manages the Link Layer Discovery Protocol (LLDP) and accepts the
following keys.</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>MUDURL=</varname></term>
<listitem>
<para>Controls support for Ethernet LLDP packet's Manufacturer Usage Description (MUD). MUD is an embedded software
standard defined by the IETF that allows IoT Device makers to advertise device specifications, including the intended
communication patterns for their device when it connects to the network. The network can then use this intent to author
a context-specific access policy, so the device functions only within those parameters. Takes an URL of length up to 255
characters. A superficial verification that the string is a valid URL
will be performed. See
<ulink url="https://tools.ietf.org/html/rfc8520">RFC 8520</ulink> for details. The MUD URL received
from the LLDP packets will be saved at the state files and can be read via
<function>sd_lldp_neighbor_get_mud_url()</function> function.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[CAN] Section Options</title>
<para>The <literal>[CAN]</literal> section manages the Controller Area Network (CAN bus) and accepts the

View File

@ -6,6 +6,7 @@
#include <net/if_arp.h>
#include "alloc-util.h"
#include "escape.h"
#include "env-file.h"
#include "fd-util.h"
#include "hostname-util.h"
@ -18,6 +19,7 @@
#include "socket-util.h"
#include "string-util.h"
#include "unaligned.h"
#include "web-util.h"
/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
#define LLDP_TX_FAST_INIT 4U
@ -81,9 +83,11 @@ static int lldp_make_packet(
const char *pretty_hostname,
uint16_t system_capabilities,
uint16_t enabled_capabilities,
char *mud,
void **ret, size_t *sz) {
size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0;
size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0,
pretty_hostname_length = 0, mud_length = 0;
_cleanup_free_ void *packet = NULL;
struct ether_header *h;
uint8_t *p;
@ -110,6 +114,9 @@ static int lldp_make_packet(
if (pretty_hostname)
pretty_hostname_length = strlen(pretty_hostname);
if (mud)
mud_length = strlen(mud);
l = sizeof(struct ether_header) +
/* Chassis ID */
2 + 1 + machine_id_length +
@ -134,6 +141,10 @@ static int lldp_make_packet(
if (pretty_hostname)
l += 2 + pretty_hostname_length;
/* MUD URL */
if (mud)
l += 2 + sizeof(SD_LLDP_OUI_MUD) + 1 + mud_length;
packet = malloc(l);
if (!packet)
return -ENOMEM;
@ -184,6 +195,32 @@ static int lldp_make_packet(
p = mempcpy(p, pretty_hostname, pretty_hostname_length);
}
if (mud) {
uint8_t oui_mud[sizeof(SD_LLDP_OUI_MUD)] = {0x00, 0x00, 0x5E};
/*
* +--------+--------+----------+---------+--------------
* |TLV Type| len | OUI |subtype | MUDString
* | =127 | |= 00 00 5E| = 1 |
* |(7 bits)|(9 bits)|(3 octets)|(1 octet)|(1-255 octets)
* +--------+--------+----------+---------+--------------
* where:
* o TLV Type = 127 indicates a vendor-specific TLV
* o len = indicates the TLV string length
* o OUI = 00 00 5E is the organizationally unique identifier of IANA
* o subtype = 1 (as assigned by IANA for the MUDstring)
* o MUDstring = the length MUST NOT exceed 255 octets
*/
r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PRIVATE, sizeof(SD_LLDP_OUI_MUD) + 1 + mud_length);
if (r < 0)
return r;
p = mempcpy(p, &oui_mud, sizeof(SD_LLDP_OUI_MUD));
*(p++) = SD_LLDP_OUI_SUBTYPE_MUD_USAGE_DESCRIPTION;
p = mempcpy(p, mud, mud_length);
}
r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_CAPABILITIES, 4);
if (r < 0)
return r;
@ -281,6 +318,7 @@ static int link_send_lldp(Link *link) {
pretty_hostname,
SD_LLDP_SYSTEM_CAPABILITIES_STATION|SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE|SD_LLDP_SYSTEM_CAPABILITIES_ROUTER,
caps,
link->network ? link->network->lldp_mud : NULL,
&packet, &packet_size);
if (r < 0)
return r;
@ -414,3 +452,40 @@ int config_parse_lldp_emit(
return 0;
}
int config_parse_lldp_mud(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ char *unescaped = NULL;
Network *n = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
r = cunescape(rvalue, 0, &unescaped);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to Failed to unescape LLDP MUD URL, ignoring: %s", rvalue);
return 0;
}
if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Failed to parse LLDP MUD URL '%s', ignoring: %m", rvalue);
return 0;
}
return free_and_replace(n->lldp_mud, unescaped);
}

View File

@ -20,3 +20,4 @@ int link_lldp_emit_start(Link *link);
void link_lldp_emit_stop(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_lldp_emit);
CONFIG_PARSER_PROTOTYPE(config_parse_lldp_mud);

View File

@ -259,6 +259,7 @@ IPv6Prefix.PreferredLifetimeSec, config_parse_prefix_lifetime,
IPv6Prefix.Assign, config_parse_prefix_assign, 0, 0
IPv6RoutePrefix.Route, config_parse_route_prefix, 0, 0
IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0
LLDP.MUDURL, config_parse_lldp_mud, 0, 0
CAN.BitRate, config_parse_can_bitrate, 0, offsetof(Network, can_bitrate)
CAN.SamplePoint, config_parse_permille, 0, offsetof(Network, can_sample_point)
CAN.DataBitRate, config_parse_can_bitrate, 0, offsetof(Network, can_data_bitrate)

View File

@ -485,6 +485,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
"IPv6PrefixDelegation\0"
"IPv6Prefix\0"
"IPv6RoutePrefix\0"
"LLDP\0"
"TrafficControlQueueingDiscipline\0"
"CAN\0"
"QDisc\0"
@ -726,6 +727,8 @@ static Network *network_free(Network *network) {
set_free_free(network->dnssec_negative_trust_anchors);
free(network->lldp_mud);
ordered_hashmap_free(network->dhcp_client_send_options);
ordered_hashmap_free(network->dhcp_client_send_vendor_options);
ordered_hashmap_free(network->dhcp_server_send_options);

View File

@ -258,8 +258,10 @@ struct Network {
bool required_for_online; /* Is this network required to be considered online? */
LinkOperationalStateRange required_operstate_for_online;
/* LLDP support */
LLDPMode lldp_mode; /* LLDP reception */
LLDPEmit lldp_emit; /* LLDP transmission */
char *lldp_mud; /* LLDP MUD URL */
LIST_HEAD(Address, static_addresses);
LIST_HEAD(Route, static_routes);

View File

@ -199,6 +199,8 @@ LifetimeSec=
EgressUntagged=
VLAN=
PVID=
[LLDP]
MUDURL=
[CAN]
SamplePoint=
BitRate=