mirror of
https://github.com/systemd/systemd.git
synced 2024-12-26 02:23:34 +08:00
Merge pull request #15234 from ssahani/mud-lldp
LLDP : Introduce Manufacturer Usage Description (MUD)
This commit is contained in:
commit
876acda0ed
@ -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
|
||||
|
@ -50,6 +50,7 @@ static void lldp_neighbor_free(sd_lldp_neighbor *n) {
|
||||
free(n->port_description);
|
||||
free(n->system_name);
|
||||
free(n->system_description);
|
||||
free(n->mud_url);
|
||||
free(n->chassis_id_as_string);
|
||||
free(n->port_id_as_string);
|
||||
free(n);
|
||||
@ -292,9 +293,20 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) {
|
||||
|
||||
break;
|
||||
|
||||
case SD_LLDP_TYPE_PRIVATE:
|
||||
case SD_LLDP_TYPE_PRIVATE: {
|
||||
if (length < 4)
|
||||
log_lldp("Found private TLV that is too short, ignoring.");
|
||||
else {
|
||||
/* RFC 8520: MUD URL */
|
||||
if (memcmp(p, SD_LLDP_OUI_MUD, sizeof(SD_LLDP_OUI_MUD)) == 0 &&
|
||||
p[sizeof(SD_LLDP_OUI_MUD)] == SD_LLDP_OUI_SUBTYPE_MUD_USAGE_DESCRIPTION) {
|
||||
r = parse_string(&n->mud_url, p + sizeof(SD_LLDP_OUI_MUD) + 1,
|
||||
length - 1 - sizeof(SD_LLDP_OUI_MUD));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@ -593,6 +605,17 @@ _public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const ch
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!n->mud_url)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = n->mud_url;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
@ -54,6 +54,7 @@ struct sd_lldp_neighbor {
|
||||
char *port_description;
|
||||
char *system_name;
|
||||
char *system_description;
|
||||
char *mud_url;
|
||||
|
||||
uint16_t port_vlan_id;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -96,6 +96,9 @@ enum {
|
||||
#define SD_LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 }
|
||||
#define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f }
|
||||
|
||||
#define SD_LLDP_OUI_MUD (uint8_t[]) { 0x00, 0x00, 0x5E }
|
||||
#define SD_LLDP_OUI_SUBTYPE_MUD_USAGE_DESCRIPTION 0x01
|
||||
|
||||
/* IEEE 802.1AB-2009 Annex E */
|
||||
enum {
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1,
|
||||
@ -169,6 +172,7 @@ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec);
|
||||
int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
|
||||
int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
|
||||
|
||||
|
@ -199,6 +199,8 @@ LifetimeSec=
|
||||
EgressUntagged=
|
||||
VLAN=
|
||||
PVID=
|
||||
[LLDP]
|
||||
MUDURL=
|
||||
[CAN]
|
||||
SamplePoint=
|
||||
BitRate=
|
||||
|
Loading…
Reference in New Issue
Block a user