platform: add support for macsec links

Add support for a new macsec link type and its netlink attributes to
the platform code.
This commit is contained in:
Beniamino Galvani 2016-06-30 18:20:09 +02:00 committed by Thomas Haller
parent 00463a6e09
commit 85103656e9
6 changed files with 279 additions and 0 deletions

View file

@ -129,6 +129,7 @@ typedef enum {
NM_LINK_TYPE_IP6TNL,
NM_LINK_TYPE_IPIP,
NM_LINK_TYPE_LOOPBACK,
NM_LINK_TYPE_MACSEC,
NM_LINK_TYPE_MACVLAN,
NM_LINK_TYPE_MACVTAP,
NM_LINK_TYPE_OPENVSWITCH,
@ -160,6 +161,7 @@ typedef enum {
NMP_OBJECT_TYPE_LNK_INFINIBAND,
NMP_OBJECT_TYPE_LNK_IP6TNL,
NMP_OBJECT_TYPE_LNK_IPIP,
NMP_OBJECT_TYPE_LNK_MACSEC,
NMP_OBJECT_TYPE_LNK_MACVLAN,
NMP_OBJECT_TYPE_LNK_MACVTAP,
NMP_OBJECT_TYPE_LNK_SIT,

View file

@ -21,6 +21,7 @@
#include "nm-linux-platform.h"
#include <endian.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
@ -111,6 +112,25 @@
/*****************************************************************************/
#define IFLA_MACSEC_UNSPEC 0
#define IFLA_MACSEC_SCI 1
#define IFLA_MACSEC_PORT 2
#define IFLA_MACSEC_ICV_LEN 3
#define IFLA_MACSEC_CIPHER_SUITE 4
#define IFLA_MACSEC_WINDOW 5
#define IFLA_MACSEC_ENCODING_SA 6
#define IFLA_MACSEC_ENCRYPT 7
#define IFLA_MACSEC_PROTECT 8
#define IFLA_MACSEC_INC_SCI 9
#define IFLA_MACSEC_ES 10
#define IFLA_MACSEC_SCB 11
#define IFLA_MACSEC_REPLAY_PROTECT 12
#define IFLA_MACSEC_VALIDATION 13
#define IFLA_MACSEC_PAD 14
#define __IFLA_MACSEC_MAX 15
/*****************************************************************************/
#define _NMLOG_PREFIX_NAME "platform-linux"
#define _NMLOG_DOMAIN LOGD_PLATFORM
#define _NMLOG2_DOMAIN LOGD_PLATFORM
@ -365,6 +385,7 @@ static const LinkDesc linktypes[] = {
{ NM_LINK_TYPE_IP6TNL, "ip6tnl", "ip6tnl", NULL },
{ NM_LINK_TYPE_IPIP, "ipip", "ipip", NULL },
{ NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL },
{ NM_LINK_TYPE_MACSEC, "macsec", "macsec", NULL },
{ NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL },
{ NM_LINK_TYPE_MACVTAP, "macvtap", "macvtap", NULL },
{ NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL },
@ -1109,6 +1130,56 @@ _parse_lnk_macvlan (const char *kind, struct nlattr *info_data)
/*****************************************************************************/
static NMPObject *
_parse_lnk_macsec (const char *kind, struct nlattr *info_data)
{
static struct nla_policy policy[__IFLA_MACSEC_MAX] = {
[IFLA_MACSEC_SCI] = { .type = NLA_U64 },
[IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 },
[IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 },
[IFLA_MACSEC_WINDOW] = { .type = NLA_U32 },
[IFLA_MACSEC_ENCODING_SA] = { .type = NLA_U8 },
[IFLA_MACSEC_ENCRYPT] = { .type = NLA_U8 },
[IFLA_MACSEC_PROTECT] = { .type = NLA_U8 },
[IFLA_MACSEC_INC_SCI] = { .type = NLA_U8 },
[IFLA_MACSEC_ES] = { .type = NLA_U8 },
[IFLA_MACSEC_SCB] = { .type = NLA_U8 },
[IFLA_MACSEC_REPLAY_PROTECT] = { .type = NLA_U8 },
[IFLA_MACSEC_VALIDATION] = { .type = NLA_U8 },
};
struct nlattr *tb[__IFLA_MACSEC_MAX];
int err;
NMPObject *obj;
NMPlatformLnkMacsec *props;
if (!info_data || !nm_streq0 (kind, "macsec"))
return NULL;
err = nla_parse_nested (tb, __IFLA_MACSEC_MAX - 1, info_data, policy);
if (err < 0)
return NULL;
obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_MACSEC, NULL);
props = &obj->lnk_macsec;
props->sci = tb[IFLA_MACSEC_SCI] ? be64toh (nla_get_u64 (tb[IFLA_MACSEC_SCI])) : 0;
props->icv_length = tb[IFLA_MACSEC_ICV_LEN] ? nla_get_u8 (tb[IFLA_MACSEC_ICV_LEN]) : 0;
props->cipher_suite = tb [IFLA_MACSEC_CIPHER_SUITE] ? nla_get_u64 (tb[IFLA_MACSEC_CIPHER_SUITE]) : 0;
props->window = tb [IFLA_MACSEC_WINDOW] ? nla_get_u32 (tb[IFLA_MACSEC_WINDOW]) : 0;
props->encoding_sa = tb[IFLA_MACSEC_ENCODING_SA] ? !!nla_get_u8 (tb[IFLA_MACSEC_ENCODING_SA]) : 0;
props->encrypt = tb[IFLA_MACSEC_ENCRYPT] ? !!nla_get_u8 (tb[IFLA_MACSEC_ENCRYPT]) : 0;
props->protect = tb[IFLA_MACSEC_PROTECT] ? !!nla_get_u8 (tb[IFLA_MACSEC_PROTECT]) : 0;
props->include_sci = tb[IFLA_MACSEC_INC_SCI] ? !!nla_get_u8 (tb[IFLA_MACSEC_INC_SCI]) : 0;
props->es = tb[IFLA_MACSEC_ES] ? !!nla_get_u8 (tb[IFLA_MACSEC_ES]) : 0;
props->scb = tb[IFLA_MACSEC_SCB] ? !!nla_get_u8 (tb[IFLA_MACSEC_SCB]) : 0;
props->replay_protect = tb[IFLA_MACSEC_REPLAY_PROTECT] ? !!nla_get_u8 (tb[IFLA_MACSEC_REPLAY_PROTECT]) : 0;
props->validation = tb[IFLA_MACSEC_VALIDATION] ? nla_get_u8 (tb[IFLA_MACSEC_VALIDATION]) : 0;
return obj;
}
/*****************************************************************************/
static NMPObject *
_parse_lnk_sit (const char *kind, struct nlattr *info_data)
{
@ -1555,6 +1626,9 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
case NM_LINK_TYPE_IPIP:
lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data);
break;
case NM_LINK_TYPE_MACSEC:
lnk_data = _parse_lnk_macsec (nl_info_kind, nl_info_data);
break;
case NM_LINK_TYPE_MACVLAN:
case NM_LINK_TYPE_MACVTAP:
lnk_data = _parse_lnk_macvlan (nl_info_kind, nl_info_data);
@ -4812,6 +4886,68 @@ nla_put_failure:
g_return_val_if_reached (FALSE);
}
static int
link_macsec_add (NMPlatform *platform,
const char *name,
int parent,
const NMPlatformLnkMacsec *props,
const NMPlatformLink **out_link)
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
struct nlattr *info;
struct nlattr *data;
_LOGD ("adding macsec '%s' parent %u sci %llx",
name,
parent,
(unsigned long long) props->sci);
nlmsg = _nl_msg_new_link (RTM_NEWLINK,
NLM_F_CREATE | NLM_F_EXCL,
0,
name,
0,
0);
if (!nlmsg)
return FALSE;
NLA_PUT_U32 (nlmsg, IFLA_LINK, parent);
if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
goto nla_put_failure;
NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "macsec");
if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
goto nla_put_failure;
if (props->icv_length)
NLA_PUT_U8 (nlmsg, IFLA_MACSEC_ICV_LEN, 16);
if (props->cipher_suite)
NLA_PUT_U64 (nlmsg, IFLA_MACSEC_CIPHER_SUITE, props->cipher_suite);
if (props->replay_protect)
NLA_PUT_U32 (nlmsg, IFLA_MACSEC_WINDOW, props->window);
NLA_PUT_U64 (nlmsg, IFLA_MACSEC_SCI, htobe64 (props->sci));
NLA_PUT_U8 (nlmsg, IFLA_MACSEC_ENCODING_SA, props->encoding_sa);
NLA_PUT_U8 (nlmsg, IFLA_MACSEC_ENCRYPT, props->encrypt);
NLA_PUT_U8 (nlmsg, IFLA_MACSEC_PROTECT, props->protect);
NLA_PUT_U8 (nlmsg, IFLA_MACSEC_INC_SCI, props->include_sci);
NLA_PUT_U8 (nlmsg, IFLA_MACSEC_ES, props->es);
NLA_PUT_U8 (nlmsg, IFLA_MACSEC_SCB, props->scb);
NLA_PUT_U8 (nlmsg, IFLA_MACSEC_REPLAY_PROTECT, props->replay_protect);
NLA_PUT_U8 (nlmsg, IFLA_MACSEC_VALIDATION, props->validation);
nla_nest_end (nlmsg, data);
nla_nest_end (nlmsg, info);
return do_add_link_with_lookup (platform,
NM_LINK_TYPE_MACSEC,
name, nlmsg, out_link);
nla_put_failure:
g_return_val_if_reached (FALSE);
}
static int
link_macvlan_add (NMPlatform *platform,
const char *name,
@ -6654,6 +6790,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_gre_add = link_gre_add;
platform_class->link_ip6tnl_add = link_ip6tnl_add;
platform_class->link_macsec_add = link_macsec_add;
platform_class->link_macvlan_add = link_macvlan_add;
platform_class->link_ipip_add = link_ipip_add;
platform_class->link_sit_add = link_sit_add;

View file

@ -1527,6 +1527,12 @@ nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLi
return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IPIP, out_link);
}
const NMPlatformLnkMacsec *
nm_platform_link_get_lnk_macsec (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACSEC, out_link);
}
const NMPlatformLnkMacvlan *
nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
@ -2170,6 +2176,43 @@ nm_platform_link_ipip_add (NMPlatform *self,
return NM_PLATFORM_ERROR_SUCCESS;
}
/**
* nm_platform_macsec_add:
* @self: platform instance
* @name: name of the new interface
* @props: interface properties
* @out_link: on success, the link object
*
* Create a MACsec interface.
*/
NMPlatformError
nm_platform_link_macsec_add (NMPlatform *self,
const char *name,
int parent,
const NMPlatformLnkMacsec *props,
const NMPlatformLink **out_link)
{
NMPlatformError plerr;
_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_MACSEC, out_link);
if (plerr != NM_PLATFORM_ERROR_SUCCESS)
return plerr;
_LOGD ("adding macsec '%s' parent %u sci %llx",
name,
parent,
(unsigned long long) props->sci);
if (!klass->link_macsec_add (self, name, parent, props, out_link))
return NM_PLATFORM_ERROR_UNSPECIFIED;
return NM_PLATFORM_ERROR_SUCCESS;
}
/**
* nm_platform_macvlan_add:
* @self: platform instance
@ -3483,6 +3526,39 @@ nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize l
return buf;
}
const char *
nm_platform_lnk_macsec_to_string (const NMPlatformLnkMacsec *lnk, char *buf, gsize len)
{
if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
return buf;
g_snprintf (buf, len,
"macsec "
"sci %016llx "
"protect %s "
"cipher %016llx "
"icvlen %u "
"encodingsa %u "
"validate %u "
"encrypt %s "
"send_sci %s "
"end_station %s "
"scb %s "
"replay %s",
(unsigned long long) lnk->sci,
lnk->protect ? "on" : "off",
(unsigned long long) lnk->cipher_suite,
lnk->icv_length,
lnk->encoding_sa,
lnk->validation,
lnk->encrypt ? "on" : "off",
lnk->include_sci ? "on" : "off",
lnk->es ? "on" : "off",
lnk->scb ? "on" : "off",
lnk->replay_protect ? "on" : "off");
return buf;
}
const char *
nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len)
{
@ -4064,6 +4140,25 @@ nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b
return 0;
}
int
nm_platform_lnk_macsec_cmp (const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *b)
{
_CMP_SELF (a, b);
_CMP_FIELD (a, b, sci);
_CMP_FIELD (a, b, icv_length);
_CMP_FIELD (a, b, cipher_suite);
_CMP_FIELD (a, b, window);
_CMP_FIELD (a, b, encoding_sa);
_CMP_FIELD (a, b, validation);
_CMP_FIELD (a, b, encrypt);
_CMP_FIELD (a, b, protect);
_CMP_FIELD (a, b, include_sci);
_CMP_FIELD (a, b, es);
_CMP_FIELD (a, b, scb);
_CMP_FIELD (a, b, replay_protect);
return 0;
}
int
nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b)
{

View file

@ -426,6 +426,22 @@ typedef struct {
bool path_mtu_discovery:1;
} NMPlatformLnkIpIp;
typedef struct {
int parent_ifindex;
guint64 sci; /* host byte order */
guint64 cipher_suite;
guint32 window;
guint8 icv_length;
guint8 encoding_sa;
guint8 validation;
bool encrypt:1;
bool protect:1;
bool include_sci:1;
bool es:1;
bool scb:1;
bool replay_protect:1;
} NMPlatformLnkMacsec;
typedef struct {
guint mode;
bool no_promisc:1;
@ -588,6 +604,11 @@ typedef struct {
const char *name,
const NMPlatformLnkIpIp *props,
const NMPlatformLink **out_link);
gboolean (*link_macsec_add) (NMPlatform *,
const char *name,
int parent,
const NMPlatformLnkMacsec *props,
const NMPlatformLink **out_link);
gboolean (*link_macvlan_add) (NMPlatform *,
const char *name,
int parent,
@ -818,6 +839,7 @@ const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, in
const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkMacsec *nm_platform_link_get_lnk_macsec (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkMacvtap *nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
@ -902,6 +924,11 @@ NMPlatformError nm_platform_link_ipip_add (NMPlatform *self,
const char *name,
const NMPlatformLnkIpIp *props,
const NMPlatformLink **out_link);
NMPlatformError nm_platform_link_macsec_add (NMPlatform *self,
const char *name,
int parent,
const NMPlatformLnkMacsec *props,
const NMPlatformLink **out_link);
NMPlatformError nm_platform_link_macvlan_add (NMPlatform *self,
const char *name,
int parent,
@ -956,6 +983,7 @@ const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *bu
const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len);
const char *nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len);
const char *nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize len);
const char *nm_platform_lnk_macsec_to_string (const NMPlatformLnkMacsec *lnk, char *buf, gsize len);
const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len);
const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len);
const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len);
@ -976,6 +1004,7 @@ int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *
int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b);
int nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b);
int nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b);
int nm_platform_lnk_macsec_cmp (const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *b);
int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b);
int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b);
int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b);

View file

@ -2230,6 +2230,15 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ipip_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ipip_cmp,
},
[NMP_OBJECT_TYPE_LNK_MACSEC - 1] = {
.obj_type = NMP_OBJECT_TYPE_LNK_MACSEC,
.sizeof_data = sizeof (NMPObjectLnkMacsec),
.sizeof_public = sizeof (NMPlatformLnkMacsec),
.obj_type_name = "macsec",
.lnk_link_type = NM_LINK_TYPE_MACSEC,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macsec_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macsec_cmp,
},
[NMP_OBJECT_TYPE_LNK_MACVLAN - 1] = {
.obj_type = NMP_OBJECT_TYPE_LNK_MACVLAN,
.sizeof_data = sizeof (NMPObjectLnkMacvlan),

View file

@ -206,6 +206,10 @@ typedef struct {
NMPlatformLnkIpIp _public;
} NMPObjectLnkIpIp;
typedef struct {
NMPlatformLnkMacsec _public;
} NMPObjectLnkMacsec;
typedef struct {
NMPlatformLnkMacvlan _public;
} NMPObjectLnkMacvlan;
@ -267,6 +271,9 @@ struct _NMPObject {
NMPlatformLnkIp6Tnl lnk_ip6tnl;
NMPObjectLnkIp6Tnl _lnk_ip6tnl;
NMPlatformLnkMacsec lnk_macsec;
NMPObjectLnkMacsec _lnk_macsec;
NMPlatformLnkMacvlan lnk_macvlan;
NMPObjectLnkMacvlan _lnk_macvlan;