network: support multiple security associations for macsec channels

This commit is contained in:
Yu Watanabe
2019-04-12 10:12:42 +09:00
parent 81962db798
commit e0fde24c97
2 changed files with 126 additions and 21 deletions
+120 -21
View File
@@ -82,8 +82,13 @@ static void macsec_receive_channel_free(ReceiveChannel *c) {
if (!c)
return;
if (c->macsec && c->section)
ordered_hashmap_remove(c->macsec->receive_channels_by_section, c->section);
if (c->macsec) {
if (c->sci.as_uint64 > 0)
ordered_hashmap_remove(c->macsec->receive_channels, &c->sci.as_uint64);
if (c->section)
ordered_hashmap_remove(c->macsec->receive_channels_by_section, c->section);
}
network_config_section_free(c->section);
@@ -92,6 +97,24 @@ static void macsec_receive_channel_free(ReceiveChannel *c) {
DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveChannel, macsec_receive_channel_free);
static int macsec_receive_channel_new(MACsec *s, uint64_t sci, ReceiveChannel **ret) {
ReceiveChannel *c;
assert(s);
c = new(ReceiveChannel, 1);
if (!c)
return -ENOMEM;
*c = (ReceiveChannel) {
.macsec = s,
.sci.as_uint64 = sci,
};
*ret = c;
return 0;
}
static int macsec_receive_channel_new_static(MACsec *s, const char *filename, unsigned section_line, ReceiveChannel **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(macsec_receive_channel_freep) ReceiveChannel *c = NULL;
@@ -112,14 +135,11 @@ static int macsec_receive_channel_new_static(MACsec *s, const char *filename, un
return 0;
}
c = new(ReceiveChannel, 1);
if (!c)
return -ENOMEM;
r = macsec_receive_channel_new(s, 0, &c);
if (r < 0)
return r;
*c = (ReceiveChannel) {
.macsec = s,
.section = TAKE_PTR(n),
};
c->section = TAKE_PTR(n);
r = ordered_hashmap_ensure_allocated(&s->receive_channels_by_section, &network_config_hash_ops);
if (r < 0)
@@ -324,10 +344,16 @@ static int netdev_macsec_configure_receive_association(NetDev *netdev, ReceiveAs
return 0;
}
static int macsec_receive_channel_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
static int macsec_receive_channel_handler(sd_netlink *rtnl, sd_netlink_message *m, ReceiveChannel *c) {
NetDev *netdev;
unsigned i;
int r;
assert(netdev);
assert(c);
assert(c->macsec);
netdev = NETDEV(c->macsec);
assert(netdev->state != _NETDEV_STATE_INVALID);
r = sd_netlink_message_get_errno(m);
@@ -345,9 +371,26 @@ static int macsec_receive_channel_handler(sd_netlink *rtnl, sd_netlink_message *
log_netdev_debug(netdev, "Receive channel is configured");
for (i = 0; i < c->n_rxsa; i++) {
r = netdev_macsec_configure_receive_association(netdev, c->rxsa[i]);
if (r < 0) {
log_netdev_warning_errno(netdev, r,
"Failed to configure receive security association: %m");
netdev_drop(netdev);
return 1;
}
}
return 1;
}
static void receive_channel_destroy_callback(ReceiveChannel *c) {
assert(c);
assert(c->macsec);
netdev_unref(NETDEV(c->macsec));
}
static int netdev_macsec_configure_receive_channel(NetDev *netdev, ReceiveChannel *c) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
@@ -364,7 +407,7 @@ static int netdev_macsec_configure_receive_channel(NetDev *netdev, ReceiveChanne
return r;
r = netlink_call_async(netdev->manager->genl, NULL, m, macsec_receive_channel_handler,
netdev_destroy_callback, netdev);
receive_channel_destroy_callback, c);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to configure receive channel: %m");
@@ -423,7 +466,6 @@ static int netdev_macsec_configure_transmit_association(NetDev *netdev, Transmit
}
static int netdev_macsec_configure(NetDev *netdev, Link *link, sd_netlink_message *m) {
ReceiveAssociation *n;
TransmitAssociation *a;
ReceiveChannel *c;
Iterator i;
@@ -440,18 +482,12 @@ static int netdev_macsec_configure(NetDev *netdev, Link *link, sd_netlink_messag
return r;
}
ORDERED_HASHMAP_FOREACH(c, s->receive_channels_by_section, i) {
ORDERED_HASHMAP_FOREACH(c, s->receive_channels, i) {
r = netdev_macsec_configure_receive_channel(netdev, c);
if (r < 0)
return r;
}
ORDERED_HASHMAP_FOREACH(n, s->receive_associations_by_section, i) {
r = netdev_macsec_configure_receive_association(netdev, n);
if (r < 0)
return r;
}
return 0;
}
@@ -750,6 +786,7 @@ int config_parse_macsec_key_id(
static int macsec_receive_channel_verify(ReceiveChannel *c) {
NetDev *netdev;
int r;
assert(c);
assert(c->macsec);
@@ -771,6 +808,21 @@ static int macsec_receive_channel_verify(ReceiveChannel *c) {
"Ignoring [MACsecReceiveChannel] section from line %u",
c->section->filename, c->section->line);
r = ordered_hashmap_ensure_allocated(&c->macsec->receive_channels, &uint64_hash_ops);
if (r < 0)
return log_oom();
r = ordered_hashmap_put(c->macsec->receive_channels, &c->sci.as_uint64, c);
if (r == -EEXIST)
return log_netdev_error_errno(netdev, r,
"%s: Multiple [MACsecReceiveChannel] sections have same SCI, "
"Ignoring [MACsecReceiveChannel] section from line %u",
c->section->filename, c->section->line);
if (r < 0)
return log_netdev_error_errno(netdev, r,
"%s: Failed to store [MACsecReceiveChannel] section at hashmap, "
"Ignoring [MACsecReceiveChannel] section from line %u",
c->section->filename, c->section->line);
return 0;
}
@@ -801,7 +853,9 @@ static int macsec_transmit_association_verify(TransmitAssociation *t) {
}
static int macsec_receive_association_verify(ReceiveAssociation *a) {
ReceiveChannel *c;
NetDev *netdev;
int r;
assert(a);
assert(a->macsec);
@@ -829,6 +883,35 @@ static int macsec_receive_association_verify(ReceiveAssociation *a) {
"Ignoring [MACsecReceiveAssociation] section from line %u",
a->section->filename, a->section->line);
c = ordered_hashmap_get(a->macsec->receive_channels, &a->sci.as_uint64);
if (!c) {
_cleanup_(macsec_receive_channel_freep) ReceiveChannel *new_channel = NULL;
r = macsec_receive_channel_new(a->macsec, a->sci.as_uint64, &new_channel);
if (r < 0)
return log_oom();
r = ordered_hashmap_ensure_allocated(&a->macsec->receive_channels, &uint64_hash_ops);
if (r < 0)
return log_oom();
r = ordered_hashmap_put(a->macsec->receive_channels, &new_channel->sci.as_uint64, new_channel);
if (r < 0)
return log_netdev_error_errno(netdev, r,
"%s: Failed to store receive channel at hashmap, "
"Ignoring [MACsecReceiveAssociation] section from line %u",
a->section->filename, a->section->line);
c = TAKE_PTR(new_channel);
}
if (c->n_rxsa >= MACSEC_MAX_ASSOCIATION_NUMBER)
return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(ERANGE),
"%s: Too many [MACsecReceiveAssociation] sections for the same receive channel, "
"Ignoring [MACsecReceiveAssociation] section from line %u",
a->section->filename, a->section->line);
a->sa.association_number = c->n_rxsa;
c->rxsa[c->n_rxsa++] = a;
return 0;
}
@@ -838,6 +921,7 @@ static int netdev_macsec_verify(NetDev *netdev, const char *filename) {
ReceiveAssociation *n;
ReceiveChannel *c;
Iterator i;
uint8_t an;
int r;
assert(netdev);
@@ -850,10 +934,24 @@ static int netdev_macsec_verify(NetDev *netdev, const char *filename) {
macsec_receive_channel_free(c);
}
an = 0;
ORDERED_HASHMAP_FOREACH(a, v->transmit_associations_by_section, i) {
r = macsec_transmit_association_verify(a);
if (r < 0)
if (r < 0) {
macsec_transmit_association_free(a);
continue;
}
if (an >= MACSEC_MAX_ASSOCIATION_NUMBER) {
log_netdev_error(netdev,
"%s: Too many [MACsecTransmitAssociation] sections configured. "
"Ignoring [MACsecTransmitAssociation] section from line %u",
a->section->filename, a->section->line);
macsec_transmit_association_free(a);
continue;
}
a->sa.association_number = an++;
}
ORDERED_HASHMAP_FOREACH(n, v->receive_associations_by_section, i) {
@@ -886,6 +984,7 @@ static void macsec_done(NetDev *netdev) {
assert(t);
ordered_hashmap_free_with_destructor(t->receive_channels, macsec_receive_channel_free);
ordered_hashmap_free_with_destructor(t->receive_channels_by_section, macsec_receive_channel_free);
ordered_hashmap_free_with_destructor(t->transmit_associations_by_section, macsec_transmit_association_free);
ordered_hashmap_free_with_destructor(t->receive_associations_by_section, macsec_receive_association_free);
+6
View File
@@ -8,6 +8,9 @@
#include "networkd-util.h"
#include "sparse-endian.h"
/* See the definition of MACSEC_NUM_AN in kernel's drivers/net/macsec.c */
#define MACSEC_MAX_ASSOCIATION_NUMBER 4
typedef struct MACsec MACsec;
typedef union MACsecSCI {
@@ -49,6 +52,8 @@ typedef struct ReceiveChannel {
NetworkConfigSection *section;
MACsecSCI sci;
ReceiveAssociation *rxsa[MACSEC_MAX_ASSOCIATION_NUMBER];
unsigned n_rxsa;
} ReceiveChannel;
struct MACsec {
@@ -57,6 +62,7 @@ struct MACsec {
uint16_t port;
int encrypt;
OrderedHashmap *receive_channels;
OrderedHashmap *receive_channels_by_section;
OrderedHashmap *transmit_associations_by_section;
OrderedHashmap *receive_associations_by_section;