network: add support for HSR netdev
Add support for creating HSR/PRP interfaces. HSR (High-availability Seamless Redundancy) and PRP (Parallel Redundancy Protocol) are two protocols that provide seamless failover against failure of any single network component. They are both implemented by the "hsr" kernel driver.
This commit is contained in:
committed by
Yu Watanabe
parent
c1b0e39ffd
commit
f7996e2a33
@@ -239,6 +239,13 @@ static const NLAPolicy rtnl_link_info_data_gre_policies[] = {
|
||||
[IFLA_GRE_ERSPAN_HWID] = BUILD_POLICY(U16),
|
||||
};
|
||||
|
||||
static const NLAPolicy rtnl_link_info_data_hsr_policies[] = {
|
||||
[IFLA_HSR_SLAVE1] = BUILD_POLICY(U32),
|
||||
[IFLA_HSR_SLAVE2] = BUILD_POLICY(U32),
|
||||
[IFLA_HSR_MULTICAST_SPEC] = BUILD_POLICY(U8),
|
||||
[IFLA_HSR_PROTOCOL] = BUILD_POLICY(U8),
|
||||
};
|
||||
|
||||
static const NLAPolicy rtnl_link_info_data_ipoib_policies[] = {
|
||||
[IFLA_IPOIB_PKEY] = BUILD_POLICY(U16),
|
||||
[IFLA_IPOIB_MODE] = BUILD_POLICY(U16),
|
||||
@@ -413,8 +420,8 @@ static const NLAPolicySetUnionElement rtnl_link_info_data_policy_set_union_eleme
|
||||
BUILD_UNION_ELEMENT_BY_STRING("gretap", rtnl_link_info_data_gre),
|
||||
/*
|
||||
BUILD_UNION_ELEMENT_BY_STRING("gtp", rtnl_link_info_data_gtp),
|
||||
BUILD_UNION_ELEMENT_BY_STRING("hsr", rtnl_link_info_data_hsr),
|
||||
*/
|
||||
BUILD_UNION_ELEMENT_BY_STRING("hsr", rtnl_link_info_data_hsr),
|
||||
BUILD_UNION_ELEMENT_BY_STRING("ip6erspan", rtnl_link_info_data_gre),
|
||||
BUILD_UNION_ELEMENT_BY_STRING("ip6gre", rtnl_link_info_data_gre),
|
||||
BUILD_UNION_ELEMENT_BY_STRING("ip6gretap", rtnl_link_info_data_gre),
|
||||
|
||||
@@ -10,6 +10,7 @@ sources = files(
|
||||
'netdev/dummy.c',
|
||||
'netdev/fou-tunnel.c',
|
||||
'netdev/geneve.c',
|
||||
'netdev/hsr.c',
|
||||
'netdev/ifb.c',
|
||||
'netdev/ipoib.c',
|
||||
'netdev/ipvlan.c',
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
/* Make sure the net/if.h header is included before any linux/ one */
|
||||
#include <net/if.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "hsr.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
static const char * const hsr_protocol_table[_NETDEV_HSR_PROTOCOL_MAX] = {
|
||||
[NETDEV_HSR_PROTOCOL_HSR] = "hsr",
|
||||
[NETDEV_HSR_PROTOCOL_PRP] = "prp",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(hsr_protocol, HsrProtocol);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_hsr_protocol, hsr_protocol, HsrProtocol);
|
||||
|
||||
static int hsr_get_port_links(NetDev *netdev, Link **ret1, Link **ret2) {
|
||||
Hsr *h = ASSERT_PTR(HSR(netdev));
|
||||
Link *link1, *link2;
|
||||
int r;
|
||||
|
||||
r = link_get_by_name(netdev->manager, h->ports[0], &link1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_get_by_name(netdev->manager, h->ports[1], &link2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret1)
|
||||
*ret1 = link1;
|
||||
if (ret2)
|
||||
*ret2 = link2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_hsr_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Hsr *h = ASSERT_PTR(HSR(netdev));
|
||||
Link *link1, *link2;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = hsr_get_port_links(netdev, &link1, &link2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (link1->ifindex == link2->ifindex)
|
||||
return log_netdev_warning_errno(
|
||||
netdev, SYNTHETIC_ERRNO(EINVAL), "the two HSR ports must be different");
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_HSR_SLAVE1, link1->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_HSR_SLAVE2, link2->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_HSR_PROTOCOL, h->protocol);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_HSR_MULTICAST_SPEC, h->supervision);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_hsr_config_verify(NetDev *netdev, const char *filename) {
|
||||
Hsr *h = ASSERT_PTR(HSR(netdev));
|
||||
|
||||
assert(filename);
|
||||
|
||||
if (strv_length(h->ports) != 2)
|
||||
return log_netdev_warning_errno(
|
||||
netdev,
|
||||
SYNTHETIC_ERRNO(EINVAL),
|
||||
"HSR needs two ports set, ignoring \"%s\".",
|
||||
filename);
|
||||
|
||||
if (streq(h->ports[0], h->ports[1]))
|
||||
return log_netdev_warning_errno(
|
||||
netdev,
|
||||
SYNTHETIC_ERRNO(EINVAL),
|
||||
"the two HSR ports must be different, ignoring \"%s\".",
|
||||
filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_hsr_is_ready_to_create(NetDev *netdev, Link *link) {
|
||||
return hsr_get_port_links(netdev, NULL, NULL) >= 0;
|
||||
}
|
||||
|
||||
static void netdev_hsr_done(NetDev *netdev) {
|
||||
Hsr *h = ASSERT_PTR(HSR(netdev));
|
||||
|
||||
strv_free(h->ports);
|
||||
}
|
||||
|
||||
static void netdev_hsr_init(NetDev *netdev) {
|
||||
Hsr *h = ASSERT_PTR(HSR(netdev));
|
||||
|
||||
h->protocol = NETDEV_HSR_PROTOCOL_HSR;
|
||||
}
|
||||
|
||||
const NetDevVTable hsr_vtable = {
|
||||
.object_size = sizeof(Hsr),
|
||||
.init = netdev_hsr_init,
|
||||
.done = netdev_hsr_done,
|
||||
.config_verify = netdev_hsr_config_verify,
|
||||
.is_ready_to_create = netdev_hsr_is_ready_to_create,
|
||||
.fill_message_create = netdev_hsr_fill_message_create,
|
||||
.sections = NETDEV_COMMON_SECTIONS "HSR\0",
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
typedef struct Hsr Hsr;
|
||||
|
||||
#include <linux/if_link.h>
|
||||
|
||||
#include "netdev.h"
|
||||
|
||||
typedef enum HsrProtocol {
|
||||
NETDEV_HSR_PROTOCOL_HSR = HSR_PROTOCOL_HSR,
|
||||
NETDEV_HSR_PROTOCOL_PRP = HSR_PROTOCOL_PRP,
|
||||
_NETDEV_HSR_PROTOCOL_MAX,
|
||||
_NETDEV_HSR_PROTOCOL_INVALID = -EINVAL,
|
||||
} HsrProtocol;
|
||||
|
||||
struct Hsr {
|
||||
NetDev meta;
|
||||
|
||||
char **ports;
|
||||
HsrProtocol protocol;
|
||||
uint8_t supervision;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(HSR, Hsr);
|
||||
extern const NetDevVTable hsr_vtable;
|
||||
|
||||
HsrProtocol hsr_protocol_from_string(const char *d) _pure_;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_hsr_protocol);
|
||||
@@ -12,6 +12,7 @@ _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
|
||||
#include "conf-parser.h"
|
||||
#include "fou-tunnel.h"
|
||||
#include "geneve.h"
|
||||
#include "hsr.h"
|
||||
#include "ipoib.h"
|
||||
#include "ipvlan.h"
|
||||
#include "l2tp-tunnel.h"
|
||||
@@ -172,6 +173,9 @@ GENEVE.DestinationPort, config_parse_ip_port,
|
||||
GENEVE.IPDoNotFragment, config_parse_geneve_df, 0, offsetof(Geneve, geneve_df)
|
||||
GENEVE.FlowLabel, config_parse_geneve_flow_label, 0, 0
|
||||
GENEVE.InheritInnerProtocol, config_parse_bool, 0, offsetof(Geneve, inherit_inner_protocol)
|
||||
HSR.Ports, config_parse_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Hsr, ports)
|
||||
HSR.Protocol, config_parse_hsr_protocol, 0, offsetof(Hsr, protocol)
|
||||
HSR.Supervision, config_parse_uint8, 0, offsetof(Hsr, supervision)
|
||||
MACsec.Port, config_parse_macsec_port, 0, 0
|
||||
MACsec.Encrypt, config_parse_tristate, 0, offsetof(MACsec, encrypt)
|
||||
MACsecReceiveChannel.Port, config_parse_macsec_port, 0, 0
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "fou-tunnel.h"
|
||||
#include "geneve.h"
|
||||
#include "hsr.h"
|
||||
#include "ifb.h"
|
||||
#include "ipoib.h"
|
||||
#include "ipvlan.h"
|
||||
@@ -65,6 +66,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
|
||||
[NETDEV_KIND_GENEVE] = &geneve_vtable,
|
||||
[NETDEV_KIND_GRE] = &gre_vtable,
|
||||
[NETDEV_KIND_GRETAP] = &gretap_vtable,
|
||||
[NETDEV_KIND_HSR] = &hsr_vtable,
|
||||
[NETDEV_KIND_IFB] = &ifb_vtable,
|
||||
[NETDEV_KIND_IP6GRE] = &ip6gre_vtable,
|
||||
[NETDEV_KIND_IP6GRETAP] = &ip6gretap_vtable,
|
||||
@@ -106,6 +108,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
|
||||
[NETDEV_KIND_GENEVE] = "geneve",
|
||||
[NETDEV_KIND_GRE] = "gre",
|
||||
[NETDEV_KIND_GRETAP] = "gretap",
|
||||
[NETDEV_KIND_HSR] = "hsr",
|
||||
[NETDEV_KIND_IFB] = "ifb",
|
||||
[NETDEV_KIND_IP6GRE] = "ip6gre",
|
||||
[NETDEV_KIND_IP6GRETAP] = "ip6gretap",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"-Bridge\0" \
|
||||
"-FooOverUDP\0" \
|
||||
"-GENEVE\0" \
|
||||
"-HSR\0" \
|
||||
"-IPoIB\0" \
|
||||
"-IPVLAN\0" \
|
||||
"-IPVTAP\0" \
|
||||
@@ -59,6 +60,7 @@ typedef enum NetDevKind {
|
||||
NETDEV_KIND_GENEVE,
|
||||
NETDEV_KIND_GRE,
|
||||
NETDEV_KIND_GRETAP,
|
||||
NETDEV_KIND_HSR,
|
||||
NETDEV_KIND_IFB,
|
||||
NETDEV_KIND_IP6GRE,
|
||||
NETDEV_KIND_IP6GRETAP,
|
||||
|
||||
Reference in New Issue
Block a user