networkd: netdev - move to separate subdirectory
This could (and should) be made into a separate daemon, at least move the sourcefiles out for now.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/netdev-gperf.c
|
||||
@@ -0,0 +1,444 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
Copyright 2014 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <netinet/ether.h>
|
||||
#include <linux/if_bonding.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "extract-word.h"
|
||||
#include "missing.h"
|
||||
#include "netdev/bond.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
|
||||
/*
|
||||
* Number of seconds between instances where the bonding
|
||||
* driver sends learning packets to each slaves peer switch
|
||||
*/
|
||||
#define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
|
||||
#define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
|
||||
|
||||
/* Number of IGMP membership reports to be issued after
|
||||
* a failover event.
|
||||
*/
|
||||
#define RESEND_IGMP_MIN 0
|
||||
#define RESEND_IGMP_MAX 255
|
||||
#define RESEND_IGMP_DEFAULT 1
|
||||
|
||||
/*
|
||||
* Number of packets to transmit through a slave before
|
||||
* moving to the next one.
|
||||
*/
|
||||
#define PACKETS_PER_SLAVE_MIN 0
|
||||
#define PACKETS_PER_SLAVE_MAX 65535
|
||||
#define PACKETS_PER_SLAVE_DEFAULT 1
|
||||
|
||||
/*
|
||||
* Number of peer notifications (gratuitous ARPs and
|
||||
* unsolicited IPv6 Neighbor Advertisements) to be issued after a
|
||||
* failover event.
|
||||
*/
|
||||
#define GRATUITOUS_ARP_MIN 0
|
||||
#define GRATUITOUS_ARP_MAX 255
|
||||
#define GRATUITOUS_ARP_DEFAULT 1
|
||||
|
||||
static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
|
||||
[NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
|
||||
[NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
|
||||
[NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor",
|
||||
[NETDEV_BOND_MODE_BROADCAST] = "broadcast",
|
||||
[NETDEV_BOND_MODE_802_3AD] = "802.3ad",
|
||||
[NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb",
|
||||
[NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode, "Failed to parse bond mode");
|
||||
|
||||
static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
|
||||
[NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
|
||||
[NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
|
||||
[NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3",
|
||||
[NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3",
|
||||
[NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy,
|
||||
bond_xmit_hash_policy,
|
||||
BondXmitHashPolicy,
|
||||
"Failed to parse bond transmit hash policy")
|
||||
|
||||
static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
|
||||
[NETDEV_BOND_LACP_RATE_SLOW] = "slow",
|
||||
[NETDEV_BOND_LACP_RATE_FAST] = "fast",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate")
|
||||
|
||||
static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
|
||||
[NETDEV_BOND_AD_SELECT_STABLE] = "stable",
|
||||
[NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
|
||||
[NETDEV_BOND_AD_SELECT_COUNT] = "count",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect, "Failed to parse bond AD select");
|
||||
|
||||
static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
|
||||
[NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
|
||||
[NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
|
||||
[NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac, "Failed to parse bond fail over MAC");
|
||||
|
||||
static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
|
||||
[NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
|
||||
[NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
|
||||
[NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
|
||||
[NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate, "Failed to parse bond arp validate");
|
||||
|
||||
static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
|
||||
[NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
|
||||
[NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets");
|
||||
|
||||
static const char *bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
|
||||
[NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
|
||||
[NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
|
||||
[NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect");
|
||||
|
||||
static uint8_t bond_mode_to_kernel(BondMode mode) {
|
||||
switch (mode) {
|
||||
case NETDEV_BOND_MODE_BALANCE_RR:
|
||||
return BOND_MODE_ROUNDROBIN;
|
||||
case NETDEV_BOND_MODE_ACTIVE_BACKUP:
|
||||
return BOND_MODE_ACTIVEBACKUP;
|
||||
case NETDEV_BOND_MODE_BALANCE_XOR:
|
||||
return BOND_MODE_XOR;
|
||||
case NETDEV_BOND_MODE_BROADCAST:
|
||||
return BOND_MODE_BROADCAST;
|
||||
case NETDEV_BOND_MODE_802_3AD:
|
||||
return BOND_MODE_8023AD;
|
||||
case NETDEV_BOND_MODE_BALANCE_TLB:
|
||||
return BOND_MODE_TLB;
|
||||
case NETDEV_BOND_MODE_BALANCE_ALB:
|
||||
return BOND_MODE_ALB;
|
||||
default:
|
||||
return (uint8_t) -1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) {
|
||||
switch (policy) {
|
||||
case NETDEV_BOND_XMIT_HASH_POLICY_LAYER2:
|
||||
return BOND_XMIT_POLICY_LAYER2;
|
||||
case NETDEV_BOND_XMIT_HASH_POLICY_LAYER34:
|
||||
return BOND_XMIT_POLICY_LAYER34;
|
||||
case NETDEV_BOND_XMIT_HASH_POLICY_LAYER23:
|
||||
return BOND_XMIT_POLICY_LAYER23;
|
||||
case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23:
|
||||
return BOND_XMIT_POLICY_ENCAP23;
|
||||
case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34:
|
||||
return BOND_XMIT_POLICY_ENCAP34;
|
||||
default:
|
||||
return (uint8_t) -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Bond *b;
|
||||
ArpIpTarget *target = NULL;
|
||||
int r, i = 0;
|
||||
|
||||
assert(netdev);
|
||||
assert(!link);
|
||||
assert(m);
|
||||
|
||||
b = BOND(netdev);
|
||||
|
||||
assert(b);
|
||||
|
||||
if (b->mode != _NETDEV_BOND_MODE_INVALID) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE,
|
||||
bond_mode_to_kernel(b->mode));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MODE attribute: %m");
|
||||
}
|
||||
|
||||
if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY,
|
||||
bond_xmit_hash_policy_to_kernel(b->xmit_hash_policy));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
|
||||
}
|
||||
|
||||
if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID &&
|
||||
b->mode == NETDEV_BOND_MODE_802_3AD) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate );
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
|
||||
}
|
||||
|
||||
if (b->miimon != 0) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC);
|
||||
if (r < 0)
|
||||
log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m");
|
||||
}
|
||||
|
||||
if (b->downdelay != 0) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_DOWNDELAY attribute: %m");
|
||||
}
|
||||
|
||||
if (b->updelay != 0) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_UPDELAY attribute: %m");
|
||||
}
|
||||
|
||||
if (b->arp_interval != 0) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
|
||||
|
||||
if ((b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC) &&
|
||||
(b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC)) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
|
||||
}
|
||||
}
|
||||
|
||||
if (b->ad_select != _NETDEV_BOND_AD_SELECT_INVALID &&
|
||||
b->mode == NETDEV_BOND_MODE_802_3AD) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_SELECT attribute: %m");
|
||||
}
|
||||
|
||||
if (b->fail_over_mac != _NETDEV_BOND_FAIL_OVER_MAC_INVALID &&
|
||||
b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m");
|
||||
}
|
||||
|
||||
if (b->arp_validate != _NETDEV_BOND_ARP_VALIDATE_INVALID) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_VALIDATE, b->arp_validate);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
|
||||
}
|
||||
|
||||
if (b->arp_all_targets != _NETDEV_BOND_ARP_ALL_TARGETS_INVALID) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
|
||||
}
|
||||
|
||||
if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_PRIMARY_RESELECT, b->primary_reselect);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_PRIMARY_RESELECT attribute: %m");
|
||||
}
|
||||
|
||||
if (b->resend_igmp <= RESEND_IGMP_MAX) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m");
|
||||
}
|
||||
|
||||
if (b->packets_per_slave <= PACKETS_PER_SLAVE_MAX &&
|
||||
b->mode == NETDEV_BOND_MODE_BALANCE_RR) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
|
||||
}
|
||||
|
||||
if (b->num_grat_arp <= GRATUITOUS_ARP_MAX) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
|
||||
}
|
||||
|
||||
if (b->min_links != 0) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
|
||||
|
||||
if (b->arp_interval > 0) {
|
||||
if (b->n_arp_ip_targets > 0) {
|
||||
|
||||
r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
|
||||
|
||||
LIST_FOREACH(arp_ip_target, target, b->arp_ip_targets) {
|
||||
r = sd_netlink_message_append_u32(m, i++, target->ip.in.s_addr);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_close_container(m);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_arp_ip_target_address(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) {
|
||||
Bond *b = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ ArpIpTarget *buffer = NULL;
|
||||
_cleanup_free_ char *n = NULL;
|
||||
int f;
|
||||
|
||||
r = extract_first_word(&rvalue, &n, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
buffer = new0(ArpIpTarget, 1);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
r = in_addr_from_string_auto(n, &f, &buffer->ip);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (f != AF_INET) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer);
|
||||
b->n_arp_ip_targets++;
|
||||
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX)
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"More than the maximum number of kernel-supported ARP ip targets specified: %d > %d",
|
||||
b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bond_done(NetDev *netdev) {
|
||||
ArpIpTarget *t = NULL, *n = NULL;
|
||||
Bond *b;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
b = BOND(netdev);
|
||||
|
||||
assert(b);
|
||||
|
||||
LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
|
||||
free(t);
|
||||
|
||||
b->arp_ip_targets = NULL;
|
||||
}
|
||||
|
||||
static void bond_init(NetDev *netdev) {
|
||||
Bond *b;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
b = BOND(netdev);
|
||||
|
||||
assert(b);
|
||||
|
||||
b->mode = _NETDEV_BOND_MODE_INVALID;
|
||||
b->xmit_hash_policy = _NETDEV_BOND_XMIT_HASH_POLICY_INVALID;
|
||||
b->lacp_rate = _NETDEV_BOND_LACP_RATE_INVALID;
|
||||
b->ad_select = _NETDEV_BOND_AD_SELECT_INVALID;
|
||||
b->fail_over_mac = _NETDEV_BOND_FAIL_OVER_MAC_INVALID;
|
||||
b->arp_validate = _NETDEV_BOND_ARP_VALIDATE_INVALID;
|
||||
b->arp_all_targets = _NETDEV_BOND_ARP_ALL_TARGETS_INVALID;
|
||||
b->primary_reselect = _NETDEV_BOND_PRIMARY_RESELECT_INVALID;
|
||||
|
||||
b->all_slaves_active = false;
|
||||
|
||||
b->resend_igmp = RESEND_IGMP_DEFAULT;
|
||||
b->packets_per_slave = PACKETS_PER_SLAVE_DEFAULT;
|
||||
b->num_grat_arp = GRATUITOUS_ARP_DEFAULT;
|
||||
b->lp_interval = LEARNING_PACKETS_INTERVAL_MIN_SEC;
|
||||
|
||||
LIST_HEAD_INIT(b->arp_ip_targets);
|
||||
b->n_arp_ip_targets = 0;
|
||||
}
|
||||
|
||||
const NetDevVTable bond_vtable = {
|
||||
.object_size = sizeof(Bond),
|
||||
.init = bond_init,
|
||||
.done = bond_done,
|
||||
.sections = "Match\0NetDev\0Bond\0",
|
||||
.fill_message_create = netdev_bond_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_MASTER,
|
||||
};
|
||||
@@ -0,0 +1,172 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "in-addr-util.h"
|
||||
#include "list.h"
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
/*
|
||||
* Maximum number of targets supported by the kernel for a single
|
||||
* bond netdev.
|
||||
*/
|
||||
#define NETDEV_BOND_ARP_TARGETS_MAX 16
|
||||
|
||||
typedef enum BondMode {
|
||||
NETDEV_BOND_MODE_BALANCE_RR,
|
||||
NETDEV_BOND_MODE_ACTIVE_BACKUP,
|
||||
NETDEV_BOND_MODE_BALANCE_XOR,
|
||||
NETDEV_BOND_MODE_BROADCAST,
|
||||
NETDEV_BOND_MODE_802_3AD,
|
||||
NETDEV_BOND_MODE_BALANCE_TLB,
|
||||
NETDEV_BOND_MODE_BALANCE_ALB,
|
||||
_NETDEV_BOND_MODE_MAX,
|
||||
_NETDEV_BOND_MODE_INVALID = -1
|
||||
} BondMode;
|
||||
|
||||
typedef enum BondXmitHashPolicy {
|
||||
NETDEV_BOND_XMIT_HASH_POLICY_LAYER2,
|
||||
NETDEV_BOND_XMIT_HASH_POLICY_LAYER34,
|
||||
NETDEV_BOND_XMIT_HASH_POLICY_LAYER23,
|
||||
NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23,
|
||||
NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34,
|
||||
_NETDEV_BOND_XMIT_HASH_POLICY_MAX,
|
||||
_NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1
|
||||
} BondXmitHashPolicy;
|
||||
|
||||
typedef enum BondLacpRate {
|
||||
NETDEV_BOND_LACP_RATE_SLOW,
|
||||
NETDEV_BOND_LACP_RATE_FAST,
|
||||
_NETDEV_BOND_LACP_RATE_MAX,
|
||||
_NETDEV_BOND_LACP_RATE_INVALID = -1,
|
||||
} BondLacpRate;
|
||||
|
||||
typedef enum BondAdSelect {
|
||||
NETDEV_BOND_AD_SELECT_STABLE,
|
||||
NETDEV_BOND_AD_SELECT_BANDWIDTH,
|
||||
NETDEV_BOND_AD_SELECT_COUNT,
|
||||
_NETDEV_BOND_AD_SELECT_MAX,
|
||||
_NETDEV_BOND_AD_SELECT_INVALID = -1,
|
||||
} BondAdSelect;
|
||||
|
||||
typedef enum BondFailOverMac {
|
||||
NETDEV_BOND_FAIL_OVER_MAC_NONE,
|
||||
NETDEV_BOND_FAIL_OVER_MAC_ACTIVE,
|
||||
NETDEV_BOND_FAIL_OVER_MAC_FOLLOW,
|
||||
_NETDEV_BOND_FAIL_OVER_MAC_MAX,
|
||||
_NETDEV_BOND_FAIL_OVER_MAC_INVALID = -1,
|
||||
} BondFailOverMac;
|
||||
|
||||
typedef enum BondArpValidate {
|
||||
NETDEV_BOND_ARP_VALIDATE_NONE,
|
||||
NETDEV_BOND_ARP_VALIDATE_ACTIVE,
|
||||
NETDEV_BOND_ARP_VALIDATE_BACKUP,
|
||||
NETDEV_BOND_ARP_VALIDATE_ALL,
|
||||
_NETDEV_BOND_ARP_VALIDATE_MAX,
|
||||
_NETDEV_BOND_ARP_VALIDATE_INVALID = -1,
|
||||
} BondArpValidate;
|
||||
|
||||
typedef enum BondArpAllTargets {
|
||||
NETDEV_BOND_ARP_ALL_TARGETS_ANY,
|
||||
NETDEV_BOND_ARP_ALL_TARGETS_ALL,
|
||||
_NETDEV_BOND_ARP_ALL_TARGETS_MAX,
|
||||
_NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -1,
|
||||
} BondArpAllTargets;
|
||||
|
||||
typedef enum BondPrimaryReselect {
|
||||
NETDEV_BOND_PRIMARY_RESELECT_ALWAYS,
|
||||
NETDEV_BOND_PRIMARY_RESELECT_BETTER,
|
||||
NETDEV_BOND_PRIMARY_RESELECT_FAILURE,
|
||||
_NETDEV_BOND_PRIMARY_RESELECT_MAX,
|
||||
_NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1,
|
||||
} BondPrimaryReselect;
|
||||
|
||||
typedef struct ArpIpTarget {
|
||||
union in_addr_union ip;
|
||||
|
||||
LIST_FIELDS(struct ArpIpTarget, arp_ip_target);
|
||||
} ArpIpTarget;
|
||||
|
||||
typedef struct Bond {
|
||||
NetDev meta;
|
||||
|
||||
BondMode mode;
|
||||
BondXmitHashPolicy xmit_hash_policy;
|
||||
BondLacpRate lacp_rate;
|
||||
BondAdSelect ad_select;
|
||||
BondFailOverMac fail_over_mac;
|
||||
BondArpValidate arp_validate;
|
||||
BondArpAllTargets arp_all_targets;
|
||||
BondPrimaryReselect primary_reselect;
|
||||
|
||||
bool all_slaves_active;
|
||||
|
||||
unsigned resend_igmp;
|
||||
unsigned packets_per_slave;
|
||||
unsigned num_grat_arp;
|
||||
unsigned min_links;
|
||||
|
||||
usec_t miimon;
|
||||
usec_t updelay;
|
||||
usec_t downdelay;
|
||||
usec_t arp_interval;
|
||||
usec_t lp_interval;
|
||||
|
||||
int n_arp_ip_targets;
|
||||
ArpIpTarget *arp_ip_targets;
|
||||
} Bond;
|
||||
|
||||
DEFINE_NETDEV_CAST(BOND, Bond);
|
||||
extern const NetDevVTable bond_vtable;
|
||||
|
||||
const char *bond_mode_to_string(BondMode d) _const_;
|
||||
BondMode bond_mode_from_string(const char *d) _pure_;
|
||||
|
||||
const char *bond_xmit_hash_policy_to_string(BondXmitHashPolicy d) _const_;
|
||||
BondXmitHashPolicy bond_xmit_hash_policy_from_string(const char *d) _pure_;
|
||||
|
||||
const char *bond_lacp_rate_to_string(BondLacpRate d) _const_;
|
||||
BondLacpRate bond_lacp_rate_from_string(const char *d) _pure_;
|
||||
|
||||
const char *bond_fail_over_mac_to_string(BondFailOverMac d) _const_;
|
||||
BondFailOverMac bond_fail_over_mac_from_string(const char *d) _pure_;
|
||||
|
||||
const char *bond_ad_select_to_string(BondAdSelect d) _const_;
|
||||
BondAdSelect bond_ad_select_from_string(const char *d) _pure_;
|
||||
|
||||
const char *bond_arp_validate_to_string(BondArpValidate d) _const_;
|
||||
BondArpValidate bond_arp_validate_from_string(const char *d) _pure_;
|
||||
|
||||
const char *bond_arp_all_targets_to_string(BondArpAllTargets d) _const_;
|
||||
BondArpAllTargets bond_arp_all_targets_from_string(const char *d) _pure_;
|
||||
|
||||
const char *bond_primary_reselect_to_string(BondPrimaryReselect d) _const_;
|
||||
BondPrimaryReselect bond_primary_reselect_from_string(const char *d) _pure_;
|
||||
|
||||
int config_parse_bond_mode(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);
|
||||
int config_parse_bond_xmit_hash_policy(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);
|
||||
int config_parse_bond_lacp_rate(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);
|
||||
int config_parse_bond_ad_select(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);
|
||||
int config_parse_bond_fail_over_mac(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);
|
||||
int config_parse_bond_arp_validate(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);
|
||||
int config_parse_bond_arp_all_targets(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);
|
||||
int config_parse_bond_primary_reselect(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);
|
||||
int config_parse_arp_ip_target_address(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);
|
||||
@@ -0,0 +1,171 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
Copyright 2014 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "missing.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkd.h"
|
||||
#include "netdev/bridge.h"
|
||||
|
||||
/* callback for brige netdev's parameter set */
|
||||
static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
||||
_cleanup_netdev_unref_ NetDev *netdev = userdata;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(m);
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0) {
|
||||
log_netdev_warning_errno(netdev, r, "Bridge parameters could not be set: %m");
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_netdev_debug(netdev, "Bridge parameters set success");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
Bridge *b;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
b = BRIDGE(netdev);
|
||||
|
||||
assert(b);
|
||||
|
||||
r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, netdev->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
|
||||
|
||||
r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not set netlink flags: %m");
|
||||
|
||||
r = sd_netlink_message_open_container(req, IFLA_LINKINFO);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_PROTINFO attribute: %m");
|
||||
|
||||
r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
|
||||
|
||||
/* convert to jiffes */
|
||||
if (b->forward_delay > 0) {
|
||||
r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, usec_to_jiffies(b->forward_delay));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_FORWARD_DELAY attribute: %m");
|
||||
}
|
||||
|
||||
if (b->hello_time > 0) {
|
||||
r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, usec_to_jiffies(b->hello_time));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_HELLO_TIME attribute: %m");
|
||||
}
|
||||
|
||||
if (b->max_age > 0) {
|
||||
r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, usec_to_jiffies(b->max_age));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m");
|
||||
}
|
||||
|
||||
if (b->ageing_time > 0) {
|
||||
r = sd_netlink_message_append_u32(req, IFLA_BR_AGEING_TIME, usec_to_jiffies(b->ageing_time));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_AGEING_TIME attribute: %m");
|
||||
}
|
||||
|
||||
if (b->priority > 0) {
|
||||
r = sd_netlink_message_append_u16(req, IFLA_BR_PRIORITY, b->priority);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_PRIORITY attribute: %m");
|
||||
}
|
||||
|
||||
if (b->default_pvid > 0) {
|
||||
r = sd_netlink_message_append_u16(req, IFLA_BR_VLAN_DEFAULT_PVID, b->default_pvid);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_VLAN_DEFAULT_PVID attribute: %m");
|
||||
}
|
||||
|
||||
if (b->mcast_querier >= 0) {
|
||||
r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_QUERIER, b->mcast_querier);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_QUERIER attribute: %m");
|
||||
}
|
||||
|
||||
if (b->mcast_snooping >= 0) {
|
||||
r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_SNOOPING, b->mcast_snooping);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_SNOOPING attribute: %m");
|
||||
}
|
||||
|
||||
if (b->vlan_filtering >= 0) {
|
||||
r = sd_netlink_message_append_u8(req, IFLA_BR_VLAN_FILTERING, b->vlan_filtering);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_VLAN_FILTERING attribute: %m");
|
||||
}
|
||||
|
||||
if (b->stp >= 0) {
|
||||
r = sd_netlink_message_append_u32(req, IFLA_BR_STP_STATE, b->stp);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_STP_STATE attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
|
||||
|
||||
r = sd_netlink_call_async(netdev->manager->rtnl, req, netdev_bridge_set_handler, netdev, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
|
||||
|
||||
netdev_ref(netdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void bridge_init(NetDev *n) {
|
||||
Bridge *b;
|
||||
|
||||
b = BRIDGE(n);
|
||||
|
||||
assert(b);
|
||||
|
||||
b->mcast_querier = -1;
|
||||
b->mcast_snooping = -1;
|
||||
b->vlan_filtering = -1;
|
||||
b->stp = -1;
|
||||
}
|
||||
|
||||
const NetDevVTable bridge_vtable = {
|
||||
.object_size = sizeof(Bridge),
|
||||
.init = bridge_init,
|
||||
.sections = "Match\0NetDev\0Bridge\0",
|
||||
.post_create = netdev_bridge_post_create,
|
||||
.create_type = NETDEV_CREATE_MASTER,
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
typedef struct Bridge {
|
||||
NetDev meta;
|
||||
|
||||
int mcast_querier;
|
||||
int mcast_snooping;
|
||||
int vlan_filtering;
|
||||
int stp;
|
||||
uint16_t priority;
|
||||
uint16_t default_pvid;
|
||||
|
||||
usec_t forward_delay;
|
||||
usec_t hello_time;
|
||||
usec_t max_age;
|
||||
usec_t ageing_time;
|
||||
} Bridge;
|
||||
|
||||
DEFINE_NETDEV_CAST(BRIDGE, Bridge);
|
||||
extern const NetDevVTable bridge_vtable;
|
||||
@@ -0,0 +1,28 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Susant Sahani <susant@redhat.com>
|
||||
Copyright 2014 Tom Gundersen
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
|
||||
#include "netdev/dummy.h"
|
||||
|
||||
const NetDevVTable dummy_vtable = {
|
||||
.object_size = sizeof(Dummy),
|
||||
.sections = "Match\0NetDev\0",
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
typedef struct Dummy {
|
||||
NetDev meta;
|
||||
} Dummy;
|
||||
|
||||
DEFINE_NETDEV_CAST(DUMMY, Dummy);
|
||||
extern const NetDevVTable dummy_vtable;
|
||||
@@ -0,0 +1,73 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013-2015 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "netdev/ipvlan.h"
|
||||
#include "string-table.h"
|
||||
|
||||
static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
|
||||
[NETDEV_IPVLAN_MODE_L2] = "L2",
|
||||
[NETDEV_IPVLAN_MODE_L3] = "L3",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode");
|
||||
|
||||
static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
|
||||
IPVlan *m;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
assert(netdev->ifname);
|
||||
|
||||
m = IPVLAN(netdev);
|
||||
|
||||
assert(m);
|
||||
|
||||
if (m->mode != _NETDEV_IPVLAN_MODE_INVALID) {
|
||||
r = sd_netlink_message_append_u16(req, IFLA_IPVLAN_MODE, m->mode);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPVLAN_MODE attribute: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipvlan_init(NetDev *n) {
|
||||
IPVlan *m;
|
||||
|
||||
assert(n);
|
||||
|
||||
m = IPVLAN(n);
|
||||
|
||||
assert(m);
|
||||
|
||||
m->mode = _NETDEV_IPVLAN_MODE_INVALID;
|
||||
}
|
||||
|
||||
const NetDevVTable ipvlan_vtable = {
|
||||
.object_size = sizeof(IPVlan),
|
||||
.init = ipvlan_init,
|
||||
.sections = "Match\0NetDev\0IPVLAN\0",
|
||||
.fill_message_create = netdev_ipvlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014-2015 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "missing.h"
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
typedef enum IPVlanMode {
|
||||
NETDEV_IPVLAN_MODE_L2 = IPVLAN_MODE_L2,
|
||||
NETDEV_IPVLAN_MODE_L3 = IPVLAN_MODE_L3,
|
||||
_NETDEV_IPVLAN_MODE_MAX,
|
||||
_NETDEV_IPVLAN_MODE_INVALID = -1
|
||||
} IPVlanMode;
|
||||
|
||||
typedef struct IPVlan {
|
||||
NetDev meta;
|
||||
|
||||
IPVlanMode mode;
|
||||
} IPVlan;
|
||||
|
||||
DEFINE_NETDEV_CAST(IPVLAN, IPVlan);
|
||||
extern const NetDevVTable ipvlan_vtable;
|
||||
|
||||
const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
|
||||
IPVlanMode ipvlan_mode_from_string(const char *d) _pure_;
|
||||
|
||||
int config_parse_ipvlan_mode(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);
|
||||
@@ -0,0 +1,89 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "netdev/macvlan.h"
|
||||
#include "string-table.h"
|
||||
|
||||
static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
|
||||
[NETDEV_MACVLAN_MODE_PRIVATE] = "private",
|
||||
[NETDEV_MACVLAN_MODE_VEPA] = "vepa",
|
||||
[NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
|
||||
[NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
|
||||
|
||||
static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
|
||||
MacVlan *m;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
assert(netdev->ifname);
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_MACVLAN)
|
||||
m = MACVLAN(netdev);
|
||||
else
|
||||
m = MACVTAP(netdev);
|
||||
|
||||
assert(m);
|
||||
|
||||
if (m->mode != _NETDEV_MACVLAN_MODE_INVALID) {
|
||||
r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_MODE, m->mode);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACVLAN_MODE attribute: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void macvlan_init(NetDev *n) {
|
||||
MacVlan *m;
|
||||
|
||||
assert(n);
|
||||
|
||||
if (n->kind == NETDEV_KIND_MACVLAN)
|
||||
m = MACVLAN(n);
|
||||
else
|
||||
m = MACVTAP(n);
|
||||
|
||||
assert(m);
|
||||
|
||||
m->mode = _NETDEV_MACVLAN_MODE_INVALID;
|
||||
}
|
||||
|
||||
const NetDevVTable macvtap_vtable = {
|
||||
.object_size = sizeof(MacVlan),
|
||||
.init = macvlan_init,
|
||||
.sections = "Match\0NetDev\0MACVTAP\0",
|
||||
.fill_message_create = netdev_macvlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
};
|
||||
|
||||
const NetDevVTable macvlan_vtable = {
|
||||
.object_size = sizeof(MacVlan),
|
||||
.init = macvlan_init,
|
||||
.sections = "Match\0NetDev\0MACVLAN\0",
|
||||
.fill_message_create = netdev_macvlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef struct MacVlan MacVlan;
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
typedef enum MacVlanMode {
|
||||
NETDEV_MACVLAN_MODE_PRIVATE = MACVLAN_MODE_PRIVATE,
|
||||
NETDEV_MACVLAN_MODE_VEPA = MACVLAN_MODE_VEPA,
|
||||
NETDEV_MACVLAN_MODE_BRIDGE = MACVLAN_MODE_BRIDGE,
|
||||
NETDEV_MACVLAN_MODE_PASSTHRU = MACVLAN_MODE_PASSTHRU,
|
||||
_NETDEV_MACVLAN_MODE_MAX,
|
||||
_NETDEV_MACVLAN_MODE_INVALID = -1
|
||||
} MacVlanMode;
|
||||
|
||||
struct MacVlan {
|
||||
NetDev meta;
|
||||
|
||||
MacVlanMode mode;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(MACVLAN, MacVlan);
|
||||
DEFINE_NETDEV_CAST(MACVTAP, MacVlan);
|
||||
extern const NetDevVTable macvlan_vtable;
|
||||
extern const NetDevVTable macvtap_vtable;
|
||||
|
||||
const char *macvlan_mode_to_string(MacVlanMode d) _const_;
|
||||
MacVlanMode macvlan_mode_from_string(const char *d) _pure_;
|
||||
|
||||
int config_parse_macvlan_mode(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);
|
||||
@@ -0,0 +1,118 @@
|
||||
%{
|
||||
#include <stddef.h>
|
||||
#include "conf-parser.h"
|
||||
#include "network-internal.h"
|
||||
#include "netdev/bond.h"
|
||||
#include "netdev/bridge.h"
|
||||
#include "netdev/ipvlan.h"
|
||||
#include "netdev/macvlan.h"
|
||||
#include "netdev/tunnel.h"
|
||||
#include "netdev/tuntap.h"
|
||||
#include "netdev/veth.h"
|
||||
#include "netdev/vlan.h"
|
||||
#include "netdev/vxlan.h"
|
||||
#include "netdev/vrf.h"
|
||||
#include "netdev/netdev.h"
|
||||
#include "vlan-util.h"
|
||||
%}
|
||||
struct ConfigPerfItem;
|
||||
%null_strings
|
||||
%language=ANSI-C
|
||||
%define slot-name section_and_lvalue
|
||||
%define hash-function-name network_netdev_gperf_hash
|
||||
%define lookup-function-name network_netdev_gperf_lookup
|
||||
%readonly-tables
|
||||
%omit-struct-type
|
||||
%struct-type
|
||||
%includes
|
||||
%%
|
||||
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(NetDev, match_host)
|
||||
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(NetDev, match_virt)
|
||||
Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel)
|
||||
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(NetDev, match_arch)
|
||||
NetDev.Description, config_parse_string, 0, offsetof(NetDev, description)
|
||||
NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname)
|
||||
NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind)
|
||||
NetDev.MTUBytes, config_parse_iec_size, 0, offsetof(NetDev, mtu)
|
||||
NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac)
|
||||
VLAN.Id, config_parse_vlanid, 0, offsetof(VLan, id)
|
||||
MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
|
||||
MACVTAP.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
|
||||
IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
|
||||
Tunnel.Local, config_parse_tunnel_address, 0, offsetof(Tunnel, local)
|
||||
Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote)
|
||||
Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos)
|
||||
Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl)
|
||||
Tunnel.Key, config_parse_tunnel_key, 0, offsetof(Tunnel, key)
|
||||
Tunnel.InputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, ikey)
|
||||
Tunnel.OutputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, okey)
|
||||
Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc)
|
||||
Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode)
|
||||
Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel)
|
||||
Tunnel.CopyDSCP, config_parse_bool, 0, offsetof(Tunnel, copy_dscp)
|
||||
Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit)
|
||||
Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
|
||||
Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
|
||||
VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id)
|
||||
VXLAN.Group, config_parse_vxlan_group_address, 0, offsetof(VxLan, group)
|
||||
VXLAN.TOS, config_parse_unsigned, 0, offsetof(VxLan, tos)
|
||||
VXLAN.TTL, config_parse_unsigned, 0, offsetof(VxLan, ttl)
|
||||
VXLAN.MacLearning, config_parse_bool, 0, offsetof(VxLan, learning)
|
||||
VXLAN.ARPProxy, config_parse_bool, 0, offsetof(VxLan, arp_proxy)
|
||||
VXLAN.L2MissNotification, config_parse_bool, 0, offsetof(VxLan, l2miss)
|
||||
VXLAN.L3MissNotification, config_parse_bool, 0, offsetof(VxLan, l3miss)
|
||||
VXLAN.RouteShortCircuit, config_parse_bool, 0, offsetof(VxLan, route_short_circuit)
|
||||
VXLAN.UDPCheckSum, config_parse_bool, 0, offsetof(VxLan, udpcsum)
|
||||
VXLAN.UDPChecksum, config_parse_bool, 0, offsetof(VxLan, udpcsum)
|
||||
VXLAN.UDP6ZeroCheckSumRx, config_parse_bool, 0, offsetof(VxLan, udp6zerocsumrx)
|
||||
VXLAN.UDP6ZeroChecksumRx, config_parse_bool, 0, offsetof(VxLan, udp6zerocsumrx)
|
||||
VXLAN.UDP6ZeroCheckSumTx, config_parse_bool, 0, offsetof(VxLan, udp6zerocsumtx)
|
||||
VXLAN.UDP6ZeroChecksumTx, config_parse_bool, 0, offsetof(VxLan, udp6zerocsumtx)
|
||||
VXLAN.RemoteChecksumTx, config_parse_bool, 0, offsetof(VxLan, remote_csum_tx)
|
||||
VXLAN.RemoteChecksumRx, config_parse_bool, 0, offsetof(VxLan, remote_csum_rx)
|
||||
VXLAN.FDBAgeingSec, config_parse_sec, 0, offsetof(VxLan, fdb_ageing)
|
||||
VXLAN.GroupPolicyExtension, config_parse_bool, 0, offsetof(VxLan, group_policy)
|
||||
VXLAN.MaximumFDBEntries, config_parse_unsigned, 0, offsetof(VxLan, max_fdb)
|
||||
VXLAN.PortRange, config_parse_port_range, 0, 0
|
||||
VXLAN.DestinationPort, config_parse_destination_port, 0, offsetof(VxLan, dest_port)
|
||||
Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
|
||||
Tun.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
|
||||
Tun.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
|
||||
Tun.User, config_parse_string, 0, offsetof(TunTap, user_name)
|
||||
Tun.Group, config_parse_string, 0, offsetof(TunTap, group_name)
|
||||
Tap.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
|
||||
Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
|
||||
Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
|
||||
Tap.VNetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr)
|
||||
Tap.User, config_parse_string, 0, offsetof(TunTap, user_name)
|
||||
Tap.Group, config_parse_string, 0, offsetof(TunTap, group_name)
|
||||
Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode)
|
||||
Bond.TransmitHashPolicy, config_parse_bond_xmit_hash_policy, 0, offsetof(Bond, xmit_hash_policy)
|
||||
Bond.LACPTransmitRate, config_parse_bond_lacp_rate, 0, offsetof(Bond, lacp_rate)
|
||||
Bond.AdSelect, config_parse_bond_ad_select, 0, offsetof(Bond, ad_select)
|
||||
Bond.FailOverMACPolicy, config_parse_bond_fail_over_mac, 0, offsetof(Bond, fail_over_mac)
|
||||
Bond.ARPIPTargets, config_parse_arp_ip_target_address, 0, 0
|
||||
Bond.ARPValidate, config_parse_bond_arp_validate, 0, offsetof(Bond, arp_validate)
|
||||
Bond.ARPAllTargets, config_parse_bond_arp_all_targets, 0, offsetof(Bond, arp_all_targets)
|
||||
Bond.PrimaryReselectPolicy, config_parse_bond_primary_reselect, 0, offsetof(Bond, primary_reselect)
|
||||
Bond.ResendIGMP, config_parse_unsigned, 0, offsetof(Bond, resend_igmp)
|
||||
Bond.PacketsPerSlave, config_parse_unsigned, 0, offsetof(Bond, packets_per_slave)
|
||||
Bond.GratuitousARP, config_parse_unsigned, 0, offsetof(Bond, num_grat_arp)
|
||||
Bond.AllSlavesActive, config_parse_unsigned, 0, offsetof(Bond, all_slaves_active)
|
||||
Bond.MinLinks, config_parse_unsigned, 0, offsetof(Bond, min_links)
|
||||
Bond.MIIMonitorSec, config_parse_sec, 0, offsetof(Bond, miimon)
|
||||
Bond.UpDelaySec, config_parse_sec, 0, offsetof(Bond, updelay)
|
||||
Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay)
|
||||
Bond.ARPIntervalSec, config_parse_sec, 0, offsetof(Bond, arp_interval)
|
||||
Bond.LearnPacketIntervalSec, config_parse_sec, 0, offsetof(Bond, lp_interval)
|
||||
Bridge.HelloTimeSec, config_parse_sec, 0, offsetof(Bridge, hello_time)
|
||||
Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age)
|
||||
Bridge.AgeingTimeSec, config_parse_sec, 0, offsetof(Bridge, ageing_time)
|
||||
Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay)
|
||||
Bridge.Priority, config_parse_uint16, 0, offsetof(Bridge, priority)
|
||||
Bridge.DefaultPVID, config_parse_vlanid, 0, offsetof(Bridge, default_pvid)
|
||||
Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier)
|
||||
Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping)
|
||||
Bridge.VLANFiltering, config_parse_tristate, 0, offsetof(Bridge, vlan_filtering)
|
||||
Bridge.STP, config_parse_tristate, 0, offsetof(Bridge, stp)
|
||||
VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table_id)
|
||||
@@ -0,0 +1,717 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-files.h"
|
||||
#include "conf-parser.h"
|
||||
#include "fd-util.h"
|
||||
#include "list.h"
|
||||
#include "netlink-util.h"
|
||||
#include "network-internal.h"
|
||||
#include "netdev/netdev.h"
|
||||
#include "networkd.h"
|
||||
#include "siphash24.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
|
||||
const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
|
||||
[NETDEV_KIND_BRIDGE] = &bridge_vtable,
|
||||
[NETDEV_KIND_BOND] = &bond_vtable,
|
||||
[NETDEV_KIND_VLAN] = &vlan_vtable,
|
||||
[NETDEV_KIND_MACVLAN] = &macvlan_vtable,
|
||||
[NETDEV_KIND_MACVTAP] = &macvtap_vtable,
|
||||
[NETDEV_KIND_IPVLAN] = &ipvlan_vtable,
|
||||
[NETDEV_KIND_VXLAN] = &vxlan_vtable,
|
||||
[NETDEV_KIND_IPIP] = &ipip_vtable,
|
||||
[NETDEV_KIND_GRE] = &gre_vtable,
|
||||
[NETDEV_KIND_GRETAP] = &gretap_vtable,
|
||||
[NETDEV_KIND_IP6GRE] = &ip6gre_vtable,
|
||||
[NETDEV_KIND_IP6GRETAP] = &ip6gretap_vtable,
|
||||
[NETDEV_KIND_SIT] = &sit_vtable,
|
||||
[NETDEV_KIND_VTI] = &vti_vtable,
|
||||
[NETDEV_KIND_VTI6] = &vti6_vtable,
|
||||
[NETDEV_KIND_VETH] = &veth_vtable,
|
||||
[NETDEV_KIND_DUMMY] = &dummy_vtable,
|
||||
[NETDEV_KIND_TUN] = &tun_vtable,
|
||||
[NETDEV_KIND_TAP] = &tap_vtable,
|
||||
[NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
|
||||
[NETDEV_KIND_VRF] = &vrf_vtable,
|
||||
[NETDEV_KIND_VCAN] = &vcan_vtable,
|
||||
};
|
||||
|
||||
static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
|
||||
[NETDEV_KIND_BRIDGE] = "bridge",
|
||||
[NETDEV_KIND_BOND] = "bond",
|
||||
[NETDEV_KIND_VLAN] = "vlan",
|
||||
[NETDEV_KIND_MACVLAN] = "macvlan",
|
||||
[NETDEV_KIND_MACVTAP] = "macvtap",
|
||||
[NETDEV_KIND_IPVLAN] = "ipvlan",
|
||||
[NETDEV_KIND_VXLAN] = "vxlan",
|
||||
[NETDEV_KIND_IPIP] = "ipip",
|
||||
[NETDEV_KIND_GRE] = "gre",
|
||||
[NETDEV_KIND_GRETAP] = "gretap",
|
||||
[NETDEV_KIND_IP6GRE] = "ip6gre",
|
||||
[NETDEV_KIND_IP6GRETAP] = "ip6gretap",
|
||||
[NETDEV_KIND_SIT] = "sit",
|
||||
[NETDEV_KIND_VETH] = "veth",
|
||||
[NETDEV_KIND_VTI] = "vti",
|
||||
[NETDEV_KIND_VTI6] = "vti6",
|
||||
[NETDEV_KIND_DUMMY] = "dummy",
|
||||
[NETDEV_KIND_TUN] = "tun",
|
||||
[NETDEV_KIND_TAP] = "tap",
|
||||
[NETDEV_KIND_IP6TNL] = "ip6tnl",
|
||||
[NETDEV_KIND_VRF] = "vrf",
|
||||
[NETDEV_KIND_VCAN] = "vcan",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
|
||||
|
||||
static void netdev_cancel_callbacks(NetDev *netdev) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
netdev_join_callback *callback;
|
||||
|
||||
if (!netdev)
|
||||
return;
|
||||
|
||||
rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
|
||||
|
||||
while ((callback = netdev->callbacks)) {
|
||||
if (m) {
|
||||
assert(callback->link);
|
||||
assert(callback->callback);
|
||||
assert(netdev->manager);
|
||||
assert(netdev->manager->rtnl);
|
||||
|
||||
callback->callback(netdev->manager->rtnl, m, callback->link);
|
||||
}
|
||||
|
||||
LIST_REMOVE(callbacks, netdev->callbacks, callback);
|
||||
link_unref(callback->link);
|
||||
free(callback);
|
||||
}
|
||||
}
|
||||
|
||||
static void netdev_free(NetDev *netdev) {
|
||||
if (!netdev)
|
||||
return;
|
||||
|
||||
netdev_cancel_callbacks(netdev);
|
||||
|
||||
if (netdev->ifname)
|
||||
hashmap_remove(netdev->manager->netdevs, netdev->ifname);
|
||||
|
||||
free(netdev->filename);
|
||||
|
||||
free(netdev->description);
|
||||
free(netdev->ifname);
|
||||
free(netdev->mac);
|
||||
|
||||
condition_free_list(netdev->match_host);
|
||||
condition_free_list(netdev->match_virt);
|
||||
condition_free_list(netdev->match_kernel);
|
||||
condition_free_list(netdev->match_arch);
|
||||
|
||||
if (NETDEV_VTABLE(netdev) &&
|
||||
NETDEV_VTABLE(netdev)->done)
|
||||
NETDEV_VTABLE(netdev)->done(netdev);
|
||||
|
||||
free(netdev);
|
||||
}
|
||||
|
||||
NetDev *netdev_unref(NetDev *netdev) {
|
||||
if (netdev && (-- netdev->n_ref <= 0))
|
||||
netdev_free(netdev);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NetDev *netdev_ref(NetDev *netdev) {
|
||||
if (netdev)
|
||||
assert_se(++ netdev->n_ref >= 2);
|
||||
|
||||
return netdev;
|
||||
}
|
||||
|
||||
void netdev_drop(NetDev *netdev) {
|
||||
if (!netdev || netdev->state == NETDEV_STATE_LINGER)
|
||||
return;
|
||||
|
||||
netdev->state = NETDEV_STATE_LINGER;
|
||||
|
||||
log_netdev_debug(netdev, "netdev removed");
|
||||
|
||||
netdev_cancel_callbacks(netdev);
|
||||
|
||||
netdev_unref(netdev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int netdev_get(Manager *manager, const char *name, NetDev **ret) {
|
||||
NetDev *netdev;
|
||||
|
||||
assert(manager);
|
||||
assert(name);
|
||||
assert(ret);
|
||||
|
||||
netdev = hashmap_get(manager->netdevs, name);
|
||||
if (!netdev) {
|
||||
*ret = NULL;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
*ret = netdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_enter_failed(NetDev *netdev) {
|
||||
netdev->state = NETDEV_STATE_FAILED;
|
||||
|
||||
netdev_cancel_callbacks(netdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_handler_t callback) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->state == NETDEV_STATE_READY);
|
||||
assert(netdev->manager);
|
||||
assert(netdev->manager->rtnl);
|
||||
assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF));
|
||||
assert(link);
|
||||
assert(callback);
|
||||
|
||||
r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
|
||||
|
||||
r = sd_netlink_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_netdev_error(netdev, "Could not send rtnetlink message: %m");
|
||||
|
||||
link_ref(link);
|
||||
|
||||
log_netdev_debug(netdev, "Enslaving link '%s'", link->ifname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_enter_ready(NetDev *netdev) {
|
||||
netdev_join_callback *callback, *callback_next;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->ifname);
|
||||
|
||||
if (netdev->state != NETDEV_STATE_CREATING)
|
||||
return 0;
|
||||
|
||||
netdev->state = NETDEV_STATE_READY;
|
||||
|
||||
log_netdev_info(netdev, "netdev ready");
|
||||
|
||||
LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
|
||||
/* enslave the links that were attempted to be enslaved before the
|
||||
* link was ready */
|
||||
r = netdev_enslave_ready(netdev, callback->link, callback->callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_REMOVE(callbacks, netdev->callbacks, callback);
|
||||
link_unref(callback->link);
|
||||
free(callback);
|
||||
}
|
||||
|
||||
if (NETDEV_VTABLE(netdev)->post_create)
|
||||
NETDEV_VTABLE(netdev)->post_create(netdev, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* callback for netdev's created without a backing Link */
|
||||
static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
||||
_cleanup_netdev_unref_ NetDev *netdev = userdata;
|
||||
int r;
|
||||
|
||||
assert(netdev->state != _NETDEV_STATE_INVALID);
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r == -EEXIST)
|
||||
log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
|
||||
else if (r < 0) {
|
||||
log_netdev_warning_errno(netdev, r, "netdev could not be created: %m");
|
||||
netdev_drop(netdev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_netdev_debug(netdev, "Created");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
assert(netdev->manager->rtnl);
|
||||
assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF));
|
||||
|
||||
if (netdev->state == NETDEV_STATE_READY) {
|
||||
r = netdev_enslave_ready(netdev, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
|
||||
r = rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
|
||||
if (r >= 0)
|
||||
callback(netdev->manager->rtnl, m, link);
|
||||
} else {
|
||||
/* the netdev is not yet read, save this request for when it is */
|
||||
netdev_join_callback *cb;
|
||||
|
||||
cb = new0(netdev_join_callback, 1);
|
||||
if (!cb)
|
||||
return log_oom();
|
||||
|
||||
cb->callback = callback;
|
||||
cb->link = link;
|
||||
link_ref(link);
|
||||
|
||||
LIST_PREPEND(callbacks, netdev->callbacks, cb);
|
||||
|
||||
log_netdev_debug(netdev, "Will enslave '%s', when ready", link->ifname);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
|
||||
uint16_t type;
|
||||
const char *kind;
|
||||
const char *received_kind;
|
||||
const char *received_name;
|
||||
int r, ifindex;
|
||||
|
||||
assert(netdev);
|
||||
assert(message);
|
||||
|
||||
r = sd_netlink_message_get_type(message, &type);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not get rtnl message type: %m");
|
||||
|
||||
if (type != RTM_NEWLINK) {
|
||||
log_netdev_error(netdev, "Cannot set ifindex from unexpected rtnl message type.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
||||
if (r < 0) {
|
||||
log_netdev_error_errno(netdev, r, "Could not get ifindex: %m");
|
||||
netdev_enter_failed(netdev);
|
||||
return r;
|
||||
} else if (ifindex <= 0) {
|
||||
log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
|
||||
netdev_enter_failed(netdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (netdev->ifindex > 0) {
|
||||
if (netdev->ifindex != ifindex) {
|
||||
log_netdev_error(netdev, "Could not set ifindex to %d, already set to %d",
|
||||
ifindex, netdev->ifindex);
|
||||
netdev_enter_failed(netdev);
|
||||
return -EEXIST;
|
||||
} else
|
||||
/* ifindex already set to the same for this netdev */
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &received_name);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not get IFNAME: %m");
|
||||
|
||||
if (!streq(netdev->ifname, received_name)) {
|
||||
log_netdev_error(netdev, "Received newlink with wrong IFNAME %s", received_name);
|
||||
netdev_enter_failed(netdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not get LINKINFO: %m");
|
||||
|
||||
r = sd_netlink_message_read_string(message, IFLA_INFO_KIND, &received_kind);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not get KIND: %m");
|
||||
|
||||
r = sd_netlink_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not exit container: %m");
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_TAP)
|
||||
/* the kernel does not distinguish between tun and tap */
|
||||
kind = "tun";
|
||||
else {
|
||||
kind = netdev_kind_to_string(netdev->kind);
|
||||
if (!kind) {
|
||||
log_netdev_error(netdev, "Could not get kind");
|
||||
netdev_enter_failed(netdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!streq(kind, received_kind)) {
|
||||
log_netdev_error(netdev,
|
||||
"Received newlink with wrong KIND %s, "
|
||||
"expected %s", received_kind, kind);
|
||||
netdev_enter_failed(netdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
netdev->ifindex = ifindex;
|
||||
|
||||
log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
|
||||
|
||||
netdev_enter_ready(netdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
|
||||
|
||||
int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
|
||||
_cleanup_free_ struct ether_addr *mac = NULL;
|
||||
uint64_t result;
|
||||
size_t l, sz;
|
||||
uint8_t *v;
|
||||
int r;
|
||||
|
||||
assert(ifname);
|
||||
assert(ret);
|
||||
|
||||
mac = new0(struct ether_addr, 1);
|
||||
if (!mac)
|
||||
return -ENOMEM;
|
||||
|
||||
l = strlen(ifname);
|
||||
sz = sizeof(sd_id128_t) + l;
|
||||
v = alloca(sz);
|
||||
|
||||
/* fetch some persistent data unique to the machine */
|
||||
r = sd_id128_get_machine((sd_id128_t*) v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* combine with some data unique (on this machine) to this
|
||||
* netdev */
|
||||
memcpy(v + sizeof(sd_id128_t), ifname, l);
|
||||
|
||||
/* Let's hash the host machine ID plus the container name. We
|
||||
* use a fixed, but originally randomly created hash key here. */
|
||||
result = siphash24(v, sz, HASH_KEY.bytes);
|
||||
|
||||
assert_cc(ETH_ALEN <= sizeof(result));
|
||||
memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
|
||||
|
||||
/* see eth_random_addr in the kernel */
|
||||
mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
|
||||
mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
|
||||
|
||||
*ret = mac;
|
||||
mac = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_create(NetDev *netdev, Link *link,
|
||||
sd_netlink_message_handler_t callback) {
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(!link || callback);
|
||||
|
||||
/* create netdev */
|
||||
if (NETDEV_VTABLE(netdev)->create) {
|
||||
assert(!link);
|
||||
|
||||
r = NETDEV_VTABLE(netdev)->create(netdev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_netdev_debug(netdev, "Created");
|
||||
} else {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
|
||||
r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m");
|
||||
|
||||
r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m");
|
||||
|
||||
if (netdev->mac) {
|
||||
r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
|
||||
}
|
||||
|
||||
if (netdev->mtu) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m");
|
||||
}
|
||||
|
||||
if (link) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_LINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINK attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
|
||||
|
||||
r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
|
||||
|
||||
if (NETDEV_VTABLE(netdev)->fill_message_create) {
|
||||
r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_close_container(m);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
|
||||
|
||||
r = sd_netlink_message_close_container(m);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
|
||||
|
||||
if (link) {
|
||||
r = sd_netlink_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
|
||||
|
||||
link_ref(link);
|
||||
} else {
|
||||
r = sd_netlink_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
|
||||
|
||||
netdev_ref(netdev);
|
||||
}
|
||||
|
||||
netdev->state = NETDEV_STATE_CREATING;
|
||||
|
||||
log_netdev_debug(netdev, "Creating");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
|
||||
int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
assert(netdev->manager->rtnl);
|
||||
assert(NETDEV_VTABLE(netdev));
|
||||
|
||||
switch (NETDEV_VTABLE(netdev)->create_type) {
|
||||
case NETDEV_CREATE_MASTER:
|
||||
r = netdev_enslave(netdev, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
case NETDEV_CREATE_STACKED:
|
||||
r = netdev_create(netdev, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
default:
|
||||
assert_not_reached("Can not join independent netdev");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_load_one(Manager *manager, const char *filename) {
|
||||
_cleanup_netdev_unref_ NetDev *netdev = NULL;
|
||||
_cleanup_free_ NetDev *netdev_raw = NULL;
|
||||
_cleanup_fclose_ FILE *file = NULL;
|
||||
const char *dropin_dirname;
|
||||
int r;
|
||||
|
||||
assert(manager);
|
||||
assert(filename);
|
||||
|
||||
file = fopen(filename, "re");
|
||||
if (!file) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (null_or_empty_fd(fileno(file))) {
|
||||
log_debug("Skipping empty file: %s", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
netdev_raw = new0(NetDev, 1);
|
||||
if (!netdev_raw)
|
||||
return log_oom();
|
||||
|
||||
netdev_raw->kind = _NETDEV_KIND_INVALID;
|
||||
dropin_dirname = strjoina(basename(filename), ".d");
|
||||
|
||||
r = config_parse_many(filename, network_dirs, dropin_dirname,
|
||||
"Match\0NetDev\0",
|
||||
config_item_perf_lookup, network_netdev_gperf_lookup,
|
||||
true, netdev_raw);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = fseek(file, 0, SEEK_SET);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
/* skip out early if configuration does not match the environment */
|
||||
if (net_match_config(NULL, NULL, NULL, NULL, NULL,
|
||||
netdev_raw->match_host, netdev_raw->match_virt,
|
||||
netdev_raw->match_kernel, netdev_raw->match_arch,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
|
||||
return 0;
|
||||
|
||||
if (netdev_raw->kind == _NETDEV_KIND_INVALID) {
|
||||
log_warning("NetDev has no Kind configured in %s. Ignoring", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!netdev_raw->ifname) {
|
||||
log_warning("NetDev without Name configured in %s. Ignoring", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
|
||||
if (!netdev)
|
||||
return log_oom();
|
||||
|
||||
netdev->n_ref = 1;
|
||||
netdev->manager = manager;
|
||||
netdev->state = _NETDEV_STATE_INVALID;
|
||||
netdev->kind = netdev_raw->kind;
|
||||
netdev->ifname = netdev_raw->ifname;
|
||||
|
||||
if (NETDEV_VTABLE(netdev)->init)
|
||||
NETDEV_VTABLE(netdev)->init(netdev);
|
||||
|
||||
r = config_parse(NULL, filename, file,
|
||||
NETDEV_VTABLE(netdev)->sections,
|
||||
config_item_perf_lookup, network_netdev_gperf_lookup,
|
||||
false, false, false, netdev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* verify configuration */
|
||||
if (NETDEV_VTABLE(netdev)->config_verify) {
|
||||
r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
netdev->filename = strdup(filename);
|
||||
if (!netdev->filename)
|
||||
return log_oom();
|
||||
|
||||
if (!netdev->mac && netdev->kind != NETDEV_KIND_VLAN) {
|
||||
r = netdev_get_mac(netdev->ifname, &netdev->mac);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
|
||||
}
|
||||
|
||||
r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_HEAD_INIT(netdev->callbacks);
|
||||
|
||||
log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
|
||||
|
||||
switch (NETDEV_VTABLE(netdev)->create_type) {
|
||||
case NETDEV_CREATE_MASTER:
|
||||
case NETDEV_CREATE_INDEPENDENT:
|
||||
r = netdev_create(netdev, NULL, NULL);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
netdev = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_load(Manager *manager) {
|
||||
_cleanup_strv_free_ char **files = NULL;
|
||||
NetDev *netdev;
|
||||
char **f;
|
||||
int r;
|
||||
|
||||
assert(manager);
|
||||
|
||||
while ((netdev = hashmap_first(manager->netdevs)))
|
||||
netdev_unref(netdev);
|
||||
|
||||
r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate netdev files: %m");
|
||||
|
||||
STRV_FOREACH_BACKWARDS(f, files) {
|
||||
r = netdev_load_one(manager, *f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "list.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct netdev_join_callback netdev_join_callback;
|
||||
typedef struct Link Link;
|
||||
|
||||
struct netdev_join_callback {
|
||||
sd_netlink_message_handler_t callback;
|
||||
Link *link;
|
||||
|
||||
LIST_FIELDS(netdev_join_callback, callbacks);
|
||||
};
|
||||
|
||||
typedef enum NetDevKind {
|
||||
NETDEV_KIND_BRIDGE,
|
||||
NETDEV_KIND_BOND,
|
||||
NETDEV_KIND_VLAN,
|
||||
NETDEV_KIND_MACVLAN,
|
||||
NETDEV_KIND_MACVTAP,
|
||||
NETDEV_KIND_IPVLAN,
|
||||
NETDEV_KIND_VXLAN,
|
||||
NETDEV_KIND_IPIP,
|
||||
NETDEV_KIND_GRE,
|
||||
NETDEV_KIND_GRETAP,
|
||||
NETDEV_KIND_IP6GRE,
|
||||
NETDEV_KIND_IP6GRETAP,
|
||||
NETDEV_KIND_SIT,
|
||||
NETDEV_KIND_VETH,
|
||||
NETDEV_KIND_VTI,
|
||||
NETDEV_KIND_VTI6,
|
||||
NETDEV_KIND_IP6TNL,
|
||||
NETDEV_KIND_DUMMY,
|
||||
NETDEV_KIND_TUN,
|
||||
NETDEV_KIND_TAP,
|
||||
NETDEV_KIND_VRF,
|
||||
NETDEV_KIND_VCAN,
|
||||
_NETDEV_KIND_MAX,
|
||||
_NETDEV_KIND_INVALID = -1
|
||||
} NetDevKind;
|
||||
|
||||
typedef enum NetDevState {
|
||||
NETDEV_STATE_FAILED,
|
||||
NETDEV_STATE_CREATING,
|
||||
NETDEV_STATE_READY,
|
||||
NETDEV_STATE_LINGER,
|
||||
_NETDEV_STATE_MAX,
|
||||
_NETDEV_STATE_INVALID = -1,
|
||||
} NetDevState;
|
||||
|
||||
typedef enum NetDevCreateType {
|
||||
NETDEV_CREATE_INDEPENDENT,
|
||||
NETDEV_CREATE_MASTER,
|
||||
NETDEV_CREATE_STACKED,
|
||||
_NETDEV_CREATE_MAX,
|
||||
_NETDEV_CREATE_INVALID = -1,
|
||||
} NetDevCreateType;
|
||||
|
||||
typedef struct Manager Manager;
|
||||
typedef struct Condition Condition;
|
||||
|
||||
typedef struct NetDev {
|
||||
Manager *manager;
|
||||
|
||||
int n_ref;
|
||||
|
||||
char *filename;
|
||||
|
||||
Condition *match_host;
|
||||
Condition *match_virt;
|
||||
Condition *match_kernel;
|
||||
Condition *match_arch;
|
||||
|
||||
NetDevState state;
|
||||
NetDevKind kind;
|
||||
char *description;
|
||||
char *ifname;
|
||||
struct ether_addr *mac;
|
||||
size_t mtu;
|
||||
int ifindex;
|
||||
|
||||
LIST_HEAD(netdev_join_callback, callbacks);
|
||||
} NetDev;
|
||||
|
||||
typedef struct NetDevVTable {
|
||||
/* How much memory does an object of this unit type need */
|
||||
size_t object_size;
|
||||
|
||||
/* Config file sections this netdev kind understands, separated
|
||||
* by NUL chars */
|
||||
const char *sections;
|
||||
|
||||
/* This should reset all type-specific variables. This should
|
||||
* not allocate memory, and is called with zero-initialized
|
||||
* data. It should hence only initialize variables that need
|
||||
* to be set != 0. */
|
||||
void (*init)(NetDev *n);
|
||||
|
||||
/* This should free all kind-specific variables. It should be
|
||||
* idempotent. */
|
||||
void (*done)(NetDev *n);
|
||||
|
||||
/* fill in message to create netdev */
|
||||
int (*fill_message_create)(NetDev *netdev, Link *link, sd_netlink_message *message);
|
||||
|
||||
/* specifies if netdev is independent, or a master device or a stacked device */
|
||||
NetDevCreateType create_type;
|
||||
|
||||
/* create netdev, if not done via rtnl */
|
||||
int (*create)(NetDev *netdev);
|
||||
|
||||
/* perform additional configuration after netdev has been createad */
|
||||
int (*post_create)(NetDev *netdev, Link *link, sd_netlink_message *message);
|
||||
|
||||
/* verify that compulsory configuration options were specified */
|
||||
int (*config_verify)(NetDev *netdev, const char *filename);
|
||||
} NetDevVTable;
|
||||
|
||||
extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
|
||||
|
||||
#define NETDEV_VTABLE(n) netdev_vtable[(n)->kind]
|
||||
|
||||
/* For casting a netdev into the various netdev kinds */
|
||||
#define DEFINE_NETDEV_CAST(UPPERCASE, MixedCase) \
|
||||
static inline MixedCase* UPPERCASE(NetDev *n) { \
|
||||
if (_unlikely_(!n || n->kind != NETDEV_KIND_##UPPERCASE)) \
|
||||
return NULL; \
|
||||
\
|
||||
return (MixedCase*) n; \
|
||||
}
|
||||
|
||||
/* For casting the various netdev kinds into a netdev */
|
||||
#define NETDEV(n) (&(n)->meta)
|
||||
|
||||
int netdev_load(Manager *manager);
|
||||
void netdev_drop(NetDev *netdev);
|
||||
|
||||
NetDev *netdev_unref(NetDev *netdev);
|
||||
NetDev *netdev_ref(NetDev *netdev);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_unref);
|
||||
#define _cleanup_netdev_unref_ _cleanup_(netdev_unrefp)
|
||||
|
||||
int netdev_get(Manager *manager, const char *name, NetDev **ret);
|
||||
int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink);
|
||||
int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback);
|
||||
int netdev_get_mac(const char *ifname, struct ether_addr **ret);
|
||||
int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t cb);
|
||||
|
||||
const char *netdev_kind_to_string(NetDevKind d) _const_;
|
||||
NetDevKind netdev_kind_from_string(const char *d) _pure_;
|
||||
|
||||
int config_parse_netdev_kind(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);
|
||||
|
||||
/* gperf */
|
||||
const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, unsigned length);
|
||||
|
||||
/* Macros which append INTERFACE= to the message */
|
||||
|
||||
#define log_netdev_full(netdev, level, error, ...) \
|
||||
({ \
|
||||
const NetDev *_n = (netdev); \
|
||||
_n ? log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", _n->ifname, NULL, NULL, ##__VA_ARGS__) : \
|
||||
log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define log_netdev_debug(netdev, ...) log_netdev_full(netdev, LOG_DEBUG, 0, ##__VA_ARGS__)
|
||||
#define log_netdev_info(netdev, ...) log_netdev_full(netdev, LOG_INFO, 0, ##__VA_ARGS__)
|
||||
#define log_netdev_notice(netdev, ...) log_netdev_full(netdev, LOG_NOTICE, 0, ##__VA_ARGS__)
|
||||
#define log_netdev_warning(netdev, ...) log_netdev_full(netdev, LOG_WARNING, 0, ## __VA_ARGS__)
|
||||
#define log_netdev_error(netdev, ...) log_netdev_full(netdev, LOG_ERR, 0, ##__VA_ARGS__)
|
||||
|
||||
#define log_netdev_debug_errno(netdev, error, ...) log_netdev_full(netdev, LOG_DEBUG, error, ##__VA_ARGS__)
|
||||
#define log_netdev_info_errno(netdev, error, ...) log_netdev_full(netdev, LOG_INFO, error, ##__VA_ARGS__)
|
||||
#define log_netdev_notice_errno(netdev, error, ...) log_netdev_full(netdev, LOG_NOTICE, error, ##__VA_ARGS__)
|
||||
#define log_netdev_warning_errno(netdev, error, ...) log_netdev_full(netdev, LOG_WARNING, error, ##__VA_ARGS__)
|
||||
#define log_netdev_error_errno(netdev, error, ...) log_netdev_full(netdev, LOG_ERR, error, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_NETDEV_MESSAGE(netdev, fmt, ...) "MESSAGE=%s: " fmt, (netdev)->ifname, ##__VA_ARGS__
|
||||
#define LOG_NETDEV_INTERFACE(netdev) "INTERFACE=%s", (netdev)->ifname
|
||||
@@ -0,0 +1,731 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/if_tunnel.h>
|
||||
#include <linux/ip6_tunnel.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "missing.h"
|
||||
#include "networkd-link.h"
|
||||
#include "netdev/tunnel.h"
|
||||
#include "parse-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
#define DEFAULT_TNL_HOP_LIMIT 64
|
||||
#define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
|
||||
|
||||
static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
|
||||
[NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6",
|
||||
[NETDEV_IP6_TNL_MODE_IPIP6] = "ipip6",
|
||||
[NETDEV_IP6_TNL_MODE_ANYIP6] = "any",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
|
||||
|
||||
static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Tunnel *t = IPIP(netdev);
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
assert(m);
|
||||
assert(t);
|
||||
assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Tunnel *t = SIT(netdev);
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
assert(m);
|
||||
assert(t);
|
||||
assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Tunnel *t;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_GRE)
|
||||
t = GRE(netdev);
|
||||
else
|
||||
t = GRETAP(netdev);
|
||||
|
||||
assert(t);
|
||||
assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
|
||||
assert(link);
|
||||
assert(m);
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
|
||||
if (r < 0)
|
||||
log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_GRE_TOS, t->tos);
|
||||
if (r < 0)
|
||||
log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TOS attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Tunnel *t;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_IP6GRE)
|
||||
t = IP6GRE(netdev);
|
||||
else
|
||||
t = IP6GRETAP(netdev);
|
||||
|
||||
assert(t);
|
||||
assert(t->family == AF_INET6);
|
||||
assert(link);
|
||||
assert(m);
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
|
||||
|
||||
if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_GRE_FLOWINFO, t->ipv6_flowlabel);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_GRE_FLAGS, t->flags);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLAGS attribute: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netdev_vti_fill_message_key(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
uint32_t ikey, okey;
|
||||
Tunnel *t;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(m);
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_VTI)
|
||||
t = VTI(netdev);
|
||||
else
|
||||
t = VTI6(netdev);
|
||||
|
||||
assert(t);
|
||||
|
||||
if (t->key != 0)
|
||||
ikey = okey = htobe32(t->key);
|
||||
else {
|
||||
ikey = htobe32(t->ikey);
|
||||
okey = htobe32(t->okey);
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_VTI_IKEY, ikey);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_IKEY attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_VTI_OKEY, okey);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Tunnel *t = VTI(netdev);
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
assert(m);
|
||||
assert(t);
|
||||
assert(t->family == AF_INET);
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
|
||||
|
||||
r = netdev_vti_fill_message_key(netdev, link, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Tunnel *t = VTI6(netdev);
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
assert(m);
|
||||
assert(t);
|
||||
assert(t->family == AF_INET6);
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
|
||||
|
||||
r = netdev_vti_fill_message_key(netdev, link, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_REMOTE, &t->remote.in6);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Tunnel *t = IP6TNL(netdev);
|
||||
uint8_t proto;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
assert(m);
|
||||
assert(t);
|
||||
assert(t->family == AF_INET6);
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
|
||||
|
||||
if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLOWINFO, t->ipv6_flowlabel);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
|
||||
}
|
||||
|
||||
if (t->copy_dscp)
|
||||
t->flags |= IP6_TNL_F_RCV_DSCP_COPY;
|
||||
|
||||
if (t->encap_limit != IPV6_DEFAULT_TNL_ENCAP_LIMIT) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
|
||||
|
||||
switch (t->ip6tnl_mode) {
|
||||
case NETDEV_IP6_TNL_MODE_IP6IP6:
|
||||
proto = IPPROTO_IPV6;
|
||||
break;
|
||||
case NETDEV_IP6_TNL_MODE_IPIP6:
|
||||
proto = IPPROTO_IPIP;
|
||||
break;
|
||||
case NETDEV_IP6_TNL_MODE_ANYIP6:
|
||||
default:
|
||||
proto = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_MODE attribute: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
|
||||
Tunnel *t = NULL;
|
||||
|
||||
assert(netdev);
|
||||
assert(filename);
|
||||
|
||||
switch (netdev->kind) {
|
||||
case NETDEV_KIND_IPIP:
|
||||
t = IPIP(netdev);
|
||||
break;
|
||||
case NETDEV_KIND_SIT:
|
||||
t = SIT(netdev);
|
||||
break;
|
||||
case NETDEV_KIND_GRE:
|
||||
t = GRE(netdev);
|
||||
break;
|
||||
case NETDEV_KIND_GRETAP:
|
||||
t = GRETAP(netdev);
|
||||
break;
|
||||
case NETDEV_KIND_IP6GRE:
|
||||
t = IP6GRE(netdev);
|
||||
break;
|
||||
case NETDEV_KIND_IP6GRETAP:
|
||||
t = IP6GRETAP(netdev);
|
||||
break;
|
||||
case NETDEV_KIND_VTI:
|
||||
t = VTI(netdev);
|
||||
break;
|
||||
case NETDEV_KIND_VTI6:
|
||||
t = VTI6(netdev);
|
||||
break;
|
||||
case NETDEV_KIND_IP6TNL:
|
||||
t = IP6TNL(netdev);
|
||||
break;
|
||||
default:
|
||||
assert_not_reached("Invalid tunnel kind");
|
||||
}
|
||||
|
||||
assert(t);
|
||||
|
||||
if (t->family != AF_INET && t->family != AF_INET6 && t->family != 0) {
|
||||
log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_IP6TNL) {
|
||||
if (t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) {
|
||||
log_warning("IP6 Tunnel without mode configured in %s. Ignoring", filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_tunnel_address(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) {
|
||||
Tunnel *t = userdata;
|
||||
union in_addr_union *addr = data, buffer;
|
||||
int r, f;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (streq(rvalue, "any")) {
|
||||
t->family = 0;
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
r = in_addr_from_string_auto(rvalue, &f, &buffer);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (t->family != AF_UNSPEC && t->family != f) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
t->family = f;
|
||||
*addr = buffer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_tunnel_key(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) {
|
||||
union in_addr_union buffer;
|
||||
Tunnel *t = userdata;
|
||||
uint32_t k;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = in_addr_from_string(AF_INET, rvalue, &buffer);
|
||||
if (r < 0) {
|
||||
r = safe_atou32(rvalue, &k);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
k = be32toh(buffer.in.s_addr);
|
||||
|
||||
if (streq(lvalue, "Key"))
|
||||
t->key = k;
|
||||
else if (streq(lvalue, "InputKey"))
|
||||
t->ikey = k;
|
||||
else
|
||||
t->okey = k;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_ipv6_flowlabel(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) {
|
||||
IPv6FlowLabel *ipv6_flowlabel = data;
|
||||
Tunnel *t = userdata;
|
||||
int k = 0;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(ipv6_flowlabel);
|
||||
|
||||
if (streq(rvalue, "inherit")) {
|
||||
*ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL;
|
||||
t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
|
||||
} else {
|
||||
r = config_parse_int(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (k > 0xFFFFF)
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue);
|
||||
else {
|
||||
*ipv6_flowlabel = htobe32(k) & IP6_FLOWINFO_FLOWLABEL;
|
||||
t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_encap_limit(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) {
|
||||
Tunnel *t = userdata;
|
||||
int k = 0;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (streq(rvalue, "none"))
|
||||
t->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
|
||||
else {
|
||||
r = safe_atoi(rvalue, &k);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (k > 255 || k < 0)
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k);
|
||||
else {
|
||||
t->encap_limit = k;
|
||||
t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipip_init(NetDev *n) {
|
||||
Tunnel *t = IPIP(n);
|
||||
|
||||
assert(n);
|
||||
assert(t);
|
||||
|
||||
t->pmtudisc = true;
|
||||
t->family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
static void sit_init(NetDev *n) {
|
||||
Tunnel *t = SIT(n);
|
||||
|
||||
assert(n);
|
||||
assert(t);
|
||||
|
||||
t->pmtudisc = true;
|
||||
t->family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
static void vti_init(NetDev *n) {
|
||||
Tunnel *t;
|
||||
|
||||
assert(n);
|
||||
|
||||
if (n->kind == NETDEV_KIND_VTI)
|
||||
t = VTI(n);
|
||||
else
|
||||
t = VTI6(n);
|
||||
|
||||
assert(t);
|
||||
|
||||
t->pmtudisc = true;
|
||||
}
|
||||
|
||||
static void gre_init(NetDev *n) {
|
||||
Tunnel *t;
|
||||
|
||||
assert(n);
|
||||
|
||||
if (n->kind == NETDEV_KIND_GRE)
|
||||
t = GRE(n);
|
||||
else
|
||||
t = GRETAP(n);
|
||||
|
||||
assert(t);
|
||||
|
||||
t->pmtudisc = true;
|
||||
t->family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
static void ip6gre_init(NetDev *n) {
|
||||
Tunnel *t;
|
||||
|
||||
assert(n);
|
||||
|
||||
if (n->kind == NETDEV_KIND_IP6GRE)
|
||||
t = IP6GRE(n);
|
||||
else
|
||||
t = IP6GRETAP(n);
|
||||
|
||||
assert(t);
|
||||
|
||||
t->ttl = DEFAULT_TNL_HOP_LIMIT;
|
||||
}
|
||||
|
||||
static void ip6tnl_init(NetDev *n) {
|
||||
Tunnel *t = IP6TNL(n);
|
||||
|
||||
assert(n);
|
||||
assert(t);
|
||||
|
||||
t->ttl = DEFAULT_TNL_HOP_LIMIT;
|
||||
t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
|
||||
t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
|
||||
t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID;
|
||||
}
|
||||
|
||||
const NetDevVTable ipip_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = ipip_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.fill_message_create = netdev_ipip_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
};
|
||||
|
||||
const NetDevVTable sit_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = sit_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.fill_message_create = netdev_sit_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
};
|
||||
|
||||
const NetDevVTable vti_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = vti_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.fill_message_create = netdev_vti_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
};
|
||||
|
||||
const NetDevVTable vti6_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = vti_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.fill_message_create = netdev_vti6_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
};
|
||||
|
||||
const NetDevVTable gre_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = gre_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.fill_message_create = netdev_gre_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
};
|
||||
|
||||
const NetDevVTable gretap_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = gre_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.fill_message_create = netdev_gre_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
};
|
||||
|
||||
const NetDevVTable ip6gre_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = ip6gre_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.fill_message_create = netdev_ip6gre_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
};
|
||||
|
||||
const NetDevVTable ip6gretap_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = ip6gre_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.fill_message_create = netdev_ip6gre_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
};
|
||||
|
||||
const NetDevVTable ip6tnl_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = ip6tnl_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.fill_message_create = netdev_ip6tnl_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "in-addr-util.h"
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
typedef enum Ip6TnlMode {
|
||||
NETDEV_IP6_TNL_MODE_IP6IP6,
|
||||
NETDEV_IP6_TNL_MODE_IPIP6,
|
||||
NETDEV_IP6_TNL_MODE_ANYIP6,
|
||||
_NETDEV_IP6_TNL_MODE_MAX,
|
||||
_NETDEV_IP6_TNL_MODE_INVALID = -1,
|
||||
} Ip6TnlMode;
|
||||
|
||||
typedef enum IPv6FlowLabel {
|
||||
NETDEV_IPV6_FLOWLABEL_INHERIT = 0xFFFFF + 1,
|
||||
_NETDEV_IPV6_FLOWLABEL_MAX,
|
||||
_NETDEV_IPV6_FLOWLABEL_INVALID = -1,
|
||||
} IPv6FlowLabel;
|
||||
|
||||
typedef struct Tunnel {
|
||||
NetDev meta;
|
||||
|
||||
uint8_t encap_limit;
|
||||
|
||||
int family;
|
||||
int ipv6_flowlabel;
|
||||
|
||||
unsigned ttl;
|
||||
unsigned tos;
|
||||
unsigned flags;
|
||||
|
||||
uint32_t key;
|
||||
uint32_t ikey;
|
||||
uint32_t okey;
|
||||
|
||||
union in_addr_union local;
|
||||
union in_addr_union remote;
|
||||
|
||||
Ip6TnlMode ip6tnl_mode;
|
||||
|
||||
bool pmtudisc;
|
||||
bool copy_dscp;
|
||||
} Tunnel;
|
||||
|
||||
DEFINE_NETDEV_CAST(IPIP, Tunnel);
|
||||
DEFINE_NETDEV_CAST(GRE, Tunnel);
|
||||
DEFINE_NETDEV_CAST(GRETAP, Tunnel);
|
||||
DEFINE_NETDEV_CAST(IP6GRE, Tunnel);
|
||||
DEFINE_NETDEV_CAST(IP6GRETAP, Tunnel);
|
||||
DEFINE_NETDEV_CAST(SIT, Tunnel);
|
||||
DEFINE_NETDEV_CAST(VTI, Tunnel);
|
||||
DEFINE_NETDEV_CAST(VTI6, Tunnel);
|
||||
DEFINE_NETDEV_CAST(IP6TNL, Tunnel);
|
||||
extern const NetDevVTable ipip_vtable;
|
||||
extern const NetDevVTable sit_vtable;
|
||||
extern const NetDevVTable vti_vtable;
|
||||
extern const NetDevVTable vti6_vtable;
|
||||
extern const NetDevVTable gre_vtable;
|
||||
extern const NetDevVTable gretap_vtable;
|
||||
extern const NetDevVTable ip6gre_vtable;
|
||||
extern const NetDevVTable ip6gretap_vtable;
|
||||
extern const NetDevVTable ip6tnl_vtable;
|
||||
|
||||
const char *ip6tnl_mode_to_string(Ip6TnlMode d) _const_;
|
||||
Ip6TnlMode ip6tnl_mode_from_string(const char *d) _pure_;
|
||||
|
||||
int config_parse_ip6tnl_mode(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);
|
||||
|
||||
int config_parse_tunnel_address(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);
|
||||
|
||||
int config_parse_ipv6_flowlabel(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);
|
||||
|
||||
int config_parse_encap_limit(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);
|
||||
int config_parse_tunnel_key(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);
|
||||
@@ -0,0 +1,183 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Susant Sahani <susant@redhat.com>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "netdev/tuntap.h"
|
||||
#include "user-util.h"
|
||||
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
|
||||
TunTap *t;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->ifname);
|
||||
assert(ifr);
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_TAP) {
|
||||
t = TAP(netdev);
|
||||
ifr->ifr_flags |= IFF_TAP;
|
||||
} else {
|
||||
t = TUN(netdev);
|
||||
ifr->ifr_flags |= IFF_TUN;
|
||||
}
|
||||
|
||||
if (!t->packet_info)
|
||||
ifr->ifr_flags |= IFF_NO_PI;
|
||||
|
||||
if (t->one_queue)
|
||||
ifr->ifr_flags |= IFF_ONE_QUEUE;
|
||||
|
||||
if (t->multi_queue)
|
||||
ifr->ifr_flags |= IFF_MULTI_QUEUE;
|
||||
|
||||
if (t->vnet_hdr)
|
||||
ifr->ifr_flags |= IFF_VNET_HDR;
|
||||
|
||||
strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
|
||||
_cleanup_close_ int fd;
|
||||
TunTap *t = NULL;
|
||||
const char *user;
|
||||
const char *group;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(ifr);
|
||||
|
||||
fd = open(TUN_DEV, O_RDWR);
|
||||
if (fd < 0)
|
||||
return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m");
|
||||
|
||||
r = ioctl(fd, TUNSETIFF, ifr);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m");
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_TAP)
|
||||
t = TAP(netdev);
|
||||
else
|
||||
t = TUN(netdev);
|
||||
|
||||
assert(t);
|
||||
|
||||
if (t->user_name) {
|
||||
|
||||
user = t->user_name;
|
||||
|
||||
r = get_user_creds(&user, &uid, NULL, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
|
||||
|
||||
r = ioctl(fd, TUNSETOWNER, uid);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m");
|
||||
}
|
||||
|
||||
if (t->group_name) {
|
||||
|
||||
group = t->group_name;
|
||||
|
||||
r = get_group_creds(&group, &gid);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
|
||||
|
||||
r = ioctl(fd, TUNSETGROUP, gid);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m");
|
||||
|
||||
}
|
||||
|
||||
r = ioctl(fd, TUNSETPERSIST, 1);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_create_tuntap(NetDev *netdev) {
|
||||
struct ifreq ifr = {};
|
||||
int r;
|
||||
|
||||
r = netdev_fill_tuntap_message(netdev, &ifr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return netdev_tuntap_add(netdev, &ifr);
|
||||
}
|
||||
|
||||
static void tuntap_done(NetDev *netdev) {
|
||||
TunTap *t = NULL;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_TUN)
|
||||
t = TUN(netdev);
|
||||
else
|
||||
t = TAP(netdev);
|
||||
|
||||
assert(t);
|
||||
|
||||
t->user_name = mfree(t->user_name);
|
||||
t->group_name = mfree(t->group_name);
|
||||
}
|
||||
|
||||
static int tuntap_verify(NetDev *netdev, const char *filename) {
|
||||
assert(netdev);
|
||||
|
||||
if (netdev->mtu)
|
||||
log_netdev_warning(netdev, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
|
||||
|
||||
if (netdev->mac)
|
||||
log_netdev_warning(netdev, "MAC configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const NetDevVTable tun_vtable = {
|
||||
.object_size = sizeof(TunTap),
|
||||
.sections = "Match\0NetDev\0Tun\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
};
|
||||
|
||||
const NetDevVTable tap_vtable = {
|
||||
.object_size = sizeof(TunTap),
|
||||
.sections = "Match\0NetDev\0Tap\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef struct TunTap TunTap;
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
struct TunTap {
|
||||
NetDev meta;
|
||||
|
||||
char *user_name;
|
||||
char *group_name;
|
||||
bool one_queue;
|
||||
bool multi_queue;
|
||||
bool packet_info;
|
||||
bool vnet_hdr;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(TUN, TunTap);
|
||||
DEFINE_NETDEV_CAST(TAP, TunTap);
|
||||
extern const NetDevVTable tun_vtable;
|
||||
extern const NetDevVTable tap_vtable;
|
||||
@@ -0,0 +1,25 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "netdev/vcan.h"
|
||||
|
||||
const NetDevVTable vcan_vtable = {
|
||||
.object_size = sizeof(VCan),
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef struct VCan VCan;
|
||||
|
||||
#include <linux/can/netlink.h>
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
struct VCan {
|
||||
NetDev meta;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(VCAN, VCan);
|
||||
|
||||
extern const NetDevVTable vcan_vtable;
|
||||
@@ -0,0 +1,111 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Susant Sahani <susant@redhat.com>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
#include <linux/veth.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "netdev/veth.h"
|
||||
|
||||
static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Veth *v;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(!link);
|
||||
assert(m);
|
||||
|
||||
v = VETH(netdev);
|
||||
|
||||
assert(v);
|
||||
|
||||
r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append VETH_INFO_PEER attribute: %m");
|
||||
|
||||
if (v->ifname_peer) {
|
||||
r = sd_netlink_message_append_string(m, IFLA_IFNAME, v->ifname_peer);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add netlink interface name: %m");
|
||||
}
|
||||
|
||||
if (v->mac_peer) {
|
||||
r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, v->mac_peer);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_close_container(m);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netdev_veth_verify(NetDev *netdev, const char *filename) {
|
||||
Veth *v;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(filename);
|
||||
|
||||
v = VETH(netdev);
|
||||
|
||||
assert(v);
|
||||
|
||||
if (!v->ifname_peer) {
|
||||
log_warning("Veth NetDev without peer name configured in %s. Ignoring",
|
||||
filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!v->mac_peer) {
|
||||
r = netdev_get_mac(v->ifname_peer, &v->mac_peer);
|
||||
if (r < 0) {
|
||||
log_warning("Failed to generate predictable MAC address for %s. Ignoring",
|
||||
v->ifname_peer);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void veth_done(NetDev *n) {
|
||||
Veth *v;
|
||||
|
||||
assert(n);
|
||||
|
||||
v = VETH(n);
|
||||
|
||||
assert(v);
|
||||
|
||||
free(v->ifname_peer);
|
||||
free(v->mac_peer);
|
||||
}
|
||||
|
||||
const NetDevVTable veth_vtable = {
|
||||
.object_size = sizeof(Veth),
|
||||
.sections = "Match\0NetDev\0Peer\0",
|
||||
.done = veth_done,
|
||||
.fill_message_create = netdev_veth_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.config_verify = netdev_veth_verify,
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef struct Veth Veth;
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
struct Veth {
|
||||
NetDev meta;
|
||||
|
||||
char *ifname_peer;
|
||||
struct ether_addr *mac_peer;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(VETH, Veth);
|
||||
extern const NetDevVTable veth_vtable;
|
||||
@@ -0,0 +1,78 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "netdev/vlan.h"
|
||||
#include "vlan-util.h"
|
||||
|
||||
static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
|
||||
VLan *v;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
assert(req);
|
||||
|
||||
v = VLAN(netdev);
|
||||
|
||||
assert(v);
|
||||
|
||||
r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_ID attribute: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
|
||||
VLan *v;
|
||||
|
||||
assert(netdev);
|
||||
assert(filename);
|
||||
|
||||
v = VLAN(netdev);
|
||||
|
||||
assert(v);
|
||||
|
||||
if (v->id == VLANID_INVALID) {
|
||||
log_warning("VLAN without valid Id (%"PRIu16") configured in %s.", v->id, filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vlan_init(NetDev *netdev) {
|
||||
VLan *v = VLAN(netdev);
|
||||
|
||||
assert(netdev);
|
||||
assert(v);
|
||||
|
||||
v->id = VLANID_INVALID;
|
||||
}
|
||||
|
||||
const NetDevVTable vlan_vtable = {
|
||||
.object_size = sizeof(VLan),
|
||||
.init = vlan_init,
|
||||
.sections = "Match\0NetDev\0VLAN\0",
|
||||
.fill_message_create = netdev_vlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_vlan_verify,
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef struct VLan VLan;
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
struct VLan {
|
||||
NetDev meta;
|
||||
|
||||
uint16_t id;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(VLAN, VLan);
|
||||
extern const NetDevVTable vlan_vtable;
|
||||
@@ -0,0 +1,50 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Andreas Rammhold <andreas@rammhold.de>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
#include "missing.h"
|
||||
#include "netdev/vrf.h"
|
||||
|
||||
static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
Vrf *v;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(!link);
|
||||
assert(m);
|
||||
|
||||
v = VRF(netdev);
|
||||
|
||||
assert(v);
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_VRF_TABLE, v->table_id);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IPLA_VRF_TABLE attribute: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const NetDevVTable vrf_vtable = {
|
||||
.object_size = sizeof(Vrf),
|
||||
.sections = "NetDev\0VRF\0",
|
||||
.fill_message_create = netdev_vrf_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_MASTER,
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Andreas Rammhold <andreas@rammhold.de>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef struct Vrf Vrf;
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
struct Vrf {
|
||||
NetDev meta;
|
||||
|
||||
uint32_t table_id;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(VRF, Vrf);
|
||||
extern const NetDevVTable vrf_vtable;
|
||||
@@ -0,0 +1,304 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "alloc-util.h"
|
||||
#include "extract-word.h"
|
||||
#include "parse-util.h"
|
||||
#include "missing.h"
|
||||
|
||||
#include "networkd-link.h"
|
||||
#include "netdev/vxlan.h"
|
||||
|
||||
static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
VxLan *v;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
assert(m);
|
||||
|
||||
v = VXLAN(netdev);
|
||||
|
||||
assert(v);
|
||||
|
||||
if (v->id <= VXLAN_VID_MAX) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_VXLAN_ID, v->id);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_ID attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_in_addr(m, IFLA_VXLAN_GROUP, &v->group.in);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GROUP attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LINK attribute: %m");
|
||||
|
||||
if (v->ttl) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TTL attribute: %m");
|
||||
}
|
||||
|
||||
if (v->tos) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TOS, v->tos);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TOS attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_LEARNING, v->learning);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LEARNING attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_RSC, v->route_short_circuit);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_RSC attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_PROXY, v->arp_proxy);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PROXY attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_L2MISS, v->l2miss);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L2MISS attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_L3MISS, v->l3miss);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L3MISS attribute: %m");
|
||||
|
||||
if (v->fdb_ageing) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m");
|
||||
}
|
||||
|
||||
if (v->max_fdb) {
|
||||
r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LIMIT, v->max_fdb);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LIMIT attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_CSUM, v->udpcsum);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_CSUM attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_TX attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_RX attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_REMCSUM_TX, v->remote_csum_tx);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_REMCSUM_TX attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_REMCSUM_RX, v->remote_csum_rx);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_REMCSUM_RX attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u16(m, IFLA_VXLAN_PORT, htobe16(v->dest_port));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PORT attribute: %m");
|
||||
|
||||
if (v->port_range.low || v->port_range.high) {
|
||||
struct ifla_vxlan_port_range port_range;
|
||||
|
||||
port_range.low = htobe16(v->port_range.low);
|
||||
port_range.high = htobe16(v->port_range.high);
|
||||
|
||||
r = sd_netlink_message_append_data(m, IFLA_VXLAN_PORT_RANGE, &port_range, sizeof(port_range));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PORT_RANGE attribute: %m");
|
||||
}
|
||||
|
||||
if (v->group_policy) {
|
||||
r = sd_netlink_message_append_flag(m, IFLA_VXLAN_GBP);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GBP attribute: %m");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int config_parse_vxlan_group_address(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) {
|
||||
VxLan *v = userdata;
|
||||
union in_addr_union *addr = data, buffer;
|
||||
int r, f;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = in_addr_from_string_auto(rvalue, &f, &buffer);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "vxlan multicast group address is invalid, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v->family != AF_UNSPEC && v->family != f) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan multicast group incompatible, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
v->family = f;
|
||||
*addr = buffer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_port_range(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 *word = NULL;
|
||||
VxLan *v = userdata;
|
||||
unsigned low, high;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = extract_first_word(&rvalue, &word, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract VXLAN port range, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
r = parse_range(word, &low, &high);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VXLAN port range '%s'", word);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (low <= 0 || low > 65535 || high <= 0 || high > 65535) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse VXLAN port range '%s'. Port should be greater than 0 and less than 65535.", word);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (high < low) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse VXLAN port range '%s'. Port range %u .. %u not valid", word, low, high);
|
||||
return 0;
|
||||
}
|
||||
|
||||
v->port_range.low = low;
|
||||
v->port_range.high = high;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_destination_port(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) {
|
||||
VxLan *v = userdata;
|
||||
uint16_t port;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = safe_atou16(rvalue, &port);
|
||||
if (r < 0 || port <= 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VXLAN destination port '%s'.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
v->dest_port = port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_vxlan_verify(NetDev *netdev, const char *filename) {
|
||||
VxLan *v = VXLAN(netdev);
|
||||
|
||||
assert(netdev);
|
||||
assert(v);
|
||||
assert(filename);
|
||||
|
||||
if (v->id > VXLAN_VID_MAX) {
|
||||
log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vxlan_init(NetDev *netdev) {
|
||||
VxLan *v;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
v = VXLAN(netdev);
|
||||
|
||||
assert(v);
|
||||
|
||||
v->id = VXLAN_VID_MAX + 1;
|
||||
v->learning = true;
|
||||
v->udpcsum = false;
|
||||
v->udp6zerocsumtx = false;
|
||||
v->udp6zerocsumrx = false;
|
||||
}
|
||||
|
||||
const NetDevVTable vxlan_vtable = {
|
||||
.object_size = sizeof(VxLan),
|
||||
.init = vxlan_init,
|
||||
.sections = "Match\0NetDev\0VXLAN\0",
|
||||
.fill_message_create = netdev_vxlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_vxlan_verify,
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef struct VxLan VxLan;
|
||||
|
||||
#include "in-addr-util.h"
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
#define VXLAN_VID_MAX (1u << 24) - 1
|
||||
|
||||
struct VxLan {
|
||||
NetDev meta;
|
||||
|
||||
uint64_t id;
|
||||
|
||||
int family;
|
||||
union in_addr_union group;
|
||||
|
||||
unsigned tos;
|
||||
unsigned ttl;
|
||||
unsigned max_fdb;
|
||||
|
||||
uint16_t dest_port;
|
||||
|
||||
usec_t fdb_ageing;
|
||||
|
||||
bool learning;
|
||||
bool arp_proxy;
|
||||
bool route_short_circuit;
|
||||
bool l2miss;
|
||||
bool l3miss;
|
||||
bool udpcsum;
|
||||
bool udp6zerocsumtx;
|
||||
bool udp6zerocsumrx;
|
||||
bool remote_csum_tx;
|
||||
bool remote_csum_rx;
|
||||
bool group_policy;
|
||||
|
||||
struct ifla_vxlan_port_range port_range;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(VXLAN, VxLan);
|
||||
extern const NetDevVTable vxlan_vtable;
|
||||
|
||||
int config_parse_vxlan_group_address(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);
|
||||
int config_parse_port_range(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);
|
||||
|
||||
int config_parse_destination_port(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);
|
||||
Reference in New Issue
Block a user