2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2015-09-07 17:43:45 +02:00
|
|
|
|
2020-01-04 21:35:13 +01:00
|
|
|
#include <net/if.h>
|
|
|
|
#include <linux/if.h>
|
2015-09-07 17:43:45 +02:00
|
|
|
#include <linux/veth.h>
|
2017-05-19 16:01:35 +02:00
|
|
|
#include <sys/file.h>
|
2015-09-07 17:43:45 +02:00
|
|
|
|
2018-08-22 07:07:59 +02:00
|
|
|
#include "sd-device.h"
|
2015-09-07 17:43:45 +02:00
|
|
|
#include "sd-id128.h"
|
|
|
|
#include "sd-netlink.h"
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-09-07 17:43:45 +02:00
|
|
|
#include "ether-addr-util.h"
|
2016-05-06 21:00:27 +02:00
|
|
|
#include "lockfile-util.h"
|
2018-12-06 07:30:35 +01:00
|
|
|
#include "missing_network.h"
|
2019-06-24 00:24:18 +02:00
|
|
|
#include "netif-naming-scheme.h"
|
2015-09-07 17:43:45 +02:00
|
|
|
#include "netlink-util.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "nspawn-network.h"
|
2019-05-30 03:22:18 +02:00
|
|
|
#include "parse-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "siphash24.h"
|
2020-01-11 11:21:01 +01:00
|
|
|
#include "socket-netlink.h"
|
2016-05-06 20:58:32 +02:00
|
|
|
#include "socket-util.h"
|
|
|
|
#include "stat-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2018-08-22 07:07:59 +02:00
|
|
|
#include "strv.h"
|
2019-12-02 16:51:44 +01:00
|
|
|
#include "udev-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "util.h"
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
#define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
|
|
|
|
#define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
|
2015-11-12 21:54:28 +01:00
|
|
|
#define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66)
|
|
|
|
#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
|
2015-09-07 17:43:45 +02:00
|
|
|
#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
|
2019-06-24 00:24:18 +02:00
|
|
|
#define SHORTEN_IFNAME_HASH_KEY SD_ID128_MAKE(e1,90,a4,04,a8,ef,4b,51,8c,cc,c3,3a,9f,11,fc,a2)
|
2015-09-07 17:43:45 +02:00
|
|
|
|
2016-05-06 21:00:27 +02:00
|
|
|
static int remove_one_link(sd_netlink *rtnl, const char *name) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (isempty(name))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate netlink message: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink interface name: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, m, 0, NULL);
|
|
|
|
if (r == -ENODEV) /* Already gone */
|
|
|
|
return 0;
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to remove interface %s: %m", name);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-09-07 17:43:45 +02:00
|
|
|
static int generate_mac(
|
|
|
|
const char *machine_name,
|
|
|
|
struct ether_addr *mac,
|
|
|
|
sd_id128_t hash_key,
|
|
|
|
uint64_t idx) {
|
|
|
|
|
2015-11-16 09:21:20 +01:00
|
|
|
uint64_t result;
|
2015-09-07 17:43:45 +02:00
|
|
|
size_t l, sz;
|
|
|
|
uint8_t *v, *i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
l = strlen(machine_name);
|
|
|
|
sz = sizeof(sd_id128_t) + l;
|
|
|
|
if (idx > 0)
|
|
|
|
sz += sizeof(idx);
|
|
|
|
|
2019-01-26 15:52:18 +01:00
|
|
|
v = newa(uint8_t, sz);
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
/* fetch some persistent data unique to the host */
|
|
|
|
r = sd_id128_get_machine((sd_id128_t*) v);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
/* combine with some data unique (on this host) to this
|
|
|
|
* container instance */
|
|
|
|
i = mempcpy(v + sizeof(sd_id128_t), machine_name, l);
|
|
|
|
if (idx > 0) {
|
|
|
|
idx = htole64(idx);
|
|
|
|
memcpy(i, &idx, sizeof(idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let's hash the host machine ID plus the container name. We
|
|
|
|
* use a fixed, but originally randomly created hash key here. */
|
2015-11-16 23:17:52 +01:00
|
|
|
result = htole64(siphash24(v, sz, hash_key.bytes));
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
assert_cc(ETH_ALEN <= sizeof(result));
|
2015-11-16 09:21:20 +01:00
|
|
|
memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
/* 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) */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-04 21:35:13 +01:00
|
|
|
static int set_alternative_ifname(sd_netlink *rtnl, const char *ifname, const char *altifname) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(ifname);
|
|
|
|
|
|
|
|
if (!altifname)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (strlen(altifname) >= ALTIFNAMSIZ)
|
|
|
|
return log_warning_errno(SYNTHETIC_ERRNO(ERANGE),
|
|
|
|
"Alternative interface name '%s' for '%s' is too long, ignoring",
|
|
|
|
altifname, ifname);
|
|
|
|
|
|
|
|
r = rtnl_set_link_alternative_names_by_ifname(&rtnl, ifname, STRV_MAKE(altifname));
|
|
|
|
if (r < 0)
|
|
|
|
return log_warning_errno(r,
|
|
|
|
"Failed to set alternative interface name '%s' to '%s', ignoring: %m",
|
|
|
|
altifname, ifname);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-12 21:54:28 +01:00
|
|
|
static int add_veth(
|
|
|
|
sd_netlink *rtnl,
|
|
|
|
pid_t pid,
|
|
|
|
const char *ifname_host,
|
2020-01-04 21:35:13 +01:00
|
|
|
const char *altifname_host,
|
2015-11-12 21:54:28 +01:00
|
|
|
const struct ether_addr *mac_host,
|
|
|
|
const char *ifname_container,
|
|
|
|
const struct ether_addr *mac_container) {
|
2015-09-07 17:43:45 +02:00
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
2015-11-12 21:54:28 +01:00
|
|
|
int r;
|
2015-09-07 17:43:45 +02:00
|
|
|
|
2015-11-12 21:54:28 +01:00
|
|
|
assert(rtnl);
|
|
|
|
assert(ifname_host);
|
|
|
|
assert(mac_host);
|
|
|
|
assert(ifname_container);
|
|
|
|
assert(mac_container);
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate netlink message: %m");
|
|
|
|
|
2015-11-12 21:54:28 +01:00
|
|
|
r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_host);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink interface name: %m");
|
|
|
|
|
2015-11-12 21:54:28 +01:00
|
|
|
r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_host);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink MAC address: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth");
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open netlink container: %m");
|
|
|
|
|
2015-11-12 21:54:28 +01:00
|
|
|
r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_container);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink interface name: %m");
|
|
|
|
|
2015-11-12 21:54:28 +01:00
|
|
|
r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_container);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink MAC address: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink namespace field: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to close netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to close netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to close netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, m, 0, NULL);
|
|
|
|
if (r < 0)
|
2015-11-12 21:54:28 +01:00
|
|
|
return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container);
|
|
|
|
|
2020-01-04 21:35:13 +01:00
|
|
|
(void) set_alternative_ifname(rtnl, ifname_host, altifname_host);
|
|
|
|
|
2015-11-12 21:54:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-24 00:24:18 +02:00
|
|
|
/* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet, since we
|
|
|
|
* don't want "/" appear in interface names (since interfaces appear in sysfs as filenames). See section #5
|
|
|
|
* of RFC 4648. */
|
|
|
|
static char urlsafe_base64char(int x) {
|
|
|
|
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
|
|
"0123456789-_";
|
|
|
|
return table[x & 63];
|
|
|
|
}
|
|
|
|
|
2020-01-04 21:35:13 +01:00
|
|
|
static int shorten_ifname(char *ifname) {
|
2019-06-24 00:24:18 +02:00
|
|
|
char new_ifname[IFNAMSIZ];
|
|
|
|
|
|
|
|
assert(ifname);
|
|
|
|
|
|
|
|
if (strlen(ifname) < IFNAMSIZ) /* Name is short enough */
|
2020-01-04 21:35:13 +01:00
|
|
|
return 0;
|
2019-06-24 00:24:18 +02:00
|
|
|
|
|
|
|
if (naming_scheme_has(NAMING_NSPAWN_LONG_HASH)) {
|
|
|
|
uint64_t h;
|
|
|
|
|
|
|
|
/* Calculate 64bit hash value */
|
|
|
|
h = siphash24(ifname, strlen(ifname), SHORTEN_IFNAME_HASH_KEY.bytes);
|
|
|
|
|
|
|
|
/* Set the final four bytes (i.e. 32bit) to the lower 24bit of the hash, encoded in url-safe base64 */
|
|
|
|
memcpy(new_ifname, ifname, IFNAMSIZ - 5);
|
|
|
|
new_ifname[IFNAMSIZ - 5] = urlsafe_base64char(h >> 18);
|
|
|
|
new_ifname[IFNAMSIZ - 4] = urlsafe_base64char(h >> 12);
|
|
|
|
new_ifname[IFNAMSIZ - 3] = urlsafe_base64char(h >> 6);
|
|
|
|
new_ifname[IFNAMSIZ - 2] = urlsafe_base64char(h);
|
|
|
|
} else
|
|
|
|
/* On old nspawn versions we just truncated the name, provide compatibility */
|
|
|
|
memcpy(new_ifname, ifname, IFNAMSIZ-1);
|
|
|
|
|
|
|
|
new_ifname[IFNAMSIZ - 1] = 0;
|
|
|
|
|
|
|
|
/* Log the incident to make it more discoverable */
|
|
|
|
log_warning("Network interface name '%s' has been changed to '%s' to fit length constraints.", ifname, new_ifname);
|
|
|
|
|
|
|
|
strcpy(ifname, new_ifname);
|
2020-01-04 21:35:13 +01:00
|
|
|
return 1;
|
2019-06-24 00:24:18 +02:00
|
|
|
}
|
|
|
|
|
2015-11-12 21:54:28 +01:00
|
|
|
int setup_veth(const char *machine_name,
|
|
|
|
pid_t pid,
|
|
|
|
char iface_name[IFNAMSIZ],
|
|
|
|
bool bridge) {
|
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2015-11-12 21:54:28 +01:00
|
|
|
struct ether_addr mac_host, mac_container;
|
2019-06-24 00:24:18 +02:00
|
|
|
unsigned u;
|
2020-01-04 21:35:13 +01:00
|
|
|
char *n, *a = NULL;
|
2019-06-24 00:24:18 +02:00
|
|
|
int r;
|
2015-11-12 21:54:28 +01:00
|
|
|
|
|
|
|
assert(machine_name);
|
|
|
|
assert(pid > 0);
|
|
|
|
assert(iface_name);
|
|
|
|
|
|
|
|
/* Use two different interface name prefixes depending whether
|
|
|
|
* we are in bridge mode or not. */
|
2019-06-24 00:24:18 +02:00
|
|
|
n = strjoina(bridge ? "vb-" : "ve-", machine_name);
|
2020-01-04 21:35:13 +01:00
|
|
|
r = shorten_ifname(n);
|
|
|
|
if (r > 0)
|
|
|
|
a = strjoina(bridge ? "vb-" : "ve-", machine_name);
|
2015-11-12 21:54:28 +01:00
|
|
|
|
|
|
|
r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m");
|
|
|
|
|
|
|
|
r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
2020-01-04 21:35:13 +01:00
|
|
|
r = add_veth(rtnl, pid, n, a, &mac_host, "host0", &mac_container);
|
2015-11-12 21:54:28 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-09-07 17:43:45 +02:00
|
|
|
|
2020-01-11 11:21:01 +01:00
|
|
|
u = if_nametoindex(n); /* We don't need to use resolve_ifname() here because the
|
|
|
|
* name we assigned is always the main name. */
|
2019-06-24 00:24:18 +02:00
|
|
|
if (u == 0)
|
|
|
|
return log_error_errno(errno, "Failed to resolve interface %s: %m", n);
|
2015-09-07 17:43:45 +02:00
|
|
|
|
2019-06-24 00:24:18 +02:00
|
|
|
strcpy(iface_name, n);
|
|
|
|
return (int) u;
|
2015-09-07 17:43:45 +02:00
|
|
|
}
|
|
|
|
|
2015-11-12 21:54:28 +01:00
|
|
|
int setup_veth_extra(
|
|
|
|
const char *machine_name,
|
|
|
|
pid_t pid,
|
|
|
|
char **pairs) {
|
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2015-11-12 21:54:28 +01:00
|
|
|
uint64_t idx = 0;
|
|
|
|
char **a, **b;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(machine_name);
|
|
|
|
assert(pid > 0);
|
|
|
|
|
|
|
|
if (strv_isempty(pairs))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
STRV_FOREACH_PAIR(a, b, pairs) {
|
|
|
|
struct ether_addr mac_host, mac_container;
|
|
|
|
|
|
|
|
r = generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
|
|
|
|
|
|
|
|
r = generate_mac(machine_name, &mac_host, VETH_EXTRA_HOST_HASH_KEY, idx);
|
|
|
|
if (r < 0)
|
2020-01-11 00:08:00 +01:00
|
|
|
return log_error_errno(r, "Failed to generate predictable MAC address for host side of extra veth link: %m");
|
2015-11-12 21:54:28 +01:00
|
|
|
|
2020-01-04 21:35:13 +01:00
|
|
|
r = add_veth(rtnl, pid, *a, NULL, &mac_host, *b, &mac_container);
|
2015-11-12 21:54:28 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-02-23 05:32:04 +01:00
|
|
|
idx++;
|
2015-11-12 21:54:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-05-06 21:00:27 +02:00
|
|
|
static int join_bridge(sd_netlink *rtnl, const char *veth_name, const char *bridge_name) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
2015-09-07 17:43:45 +02:00
|
|
|
int r, bridge_ifi;
|
|
|
|
|
2016-05-06 21:00:27 +02:00
|
|
|
assert(rtnl);
|
2015-09-07 17:43:45 +02:00
|
|
|
assert(veth_name);
|
|
|
|
assert(bridge_name);
|
|
|
|
|
2020-01-11 11:21:01 +01:00
|
|
|
bridge_ifi = resolve_interface(&rtnl, bridge_name);
|
2019-12-18 13:54:13 +01:00
|
|
|
if (bridge_ifi < 0)
|
|
|
|
return bridge_ifi;
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
|
|
|
|
if (r < 0)
|
2016-05-06 21:00:27 +02:00
|
|
|
return r;
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
|
|
|
|
if (r < 0)
|
2016-05-06 21:00:27 +02:00
|
|
|
return r;
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
|
|
|
|
if (r < 0)
|
2016-05-06 21:00:27 +02:00
|
|
|
return r;
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi);
|
|
|
|
if (r < 0)
|
2016-05-06 21:00:27 +02:00
|
|
|
return r;
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, m, 0, NULL);
|
|
|
|
if (r < 0)
|
2016-05-06 21:00:27 +02:00
|
|
|
return r;
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
return bridge_ifi;
|
|
|
|
}
|
|
|
|
|
2016-05-06 21:00:27 +02:00
|
|
|
static int create_bridge(sd_netlink *rtnl, const char *bridge_name) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_string(m, IFLA_IFNAME, bridge_name);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "bridge");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, m, 0, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int setup_bridge(const char *veth_name, const char *bridge_name, bool create) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(release_lock_file) LockFile bridge_lock = LOCK_FILE_INIT;
|
2016-05-06 21:00:27 +02:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
|
|
|
int r, bridge_ifi;
|
|
|
|
unsigned n = 0;
|
|
|
|
|
|
|
|
assert(veth_name);
|
|
|
|
assert(bridge_name);
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
if (create) {
|
|
|
|
/* We take a system-wide lock here, so that we can safely check whether there's still a member in the
|
2016-05-12 11:23:35 +02:00
|
|
|
* bridge before removing it, without risking interference from other nspawn instances. */
|
2016-05-06 21:00:27 +02:00
|
|
|
|
|
|
|
r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to take network zone lock: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
bridge_ifi = join_bridge(rtnl, veth_name, bridge_name);
|
|
|
|
if (bridge_ifi >= 0)
|
|
|
|
return bridge_ifi;
|
|
|
|
if (bridge_ifi != -ENODEV || !create || n > 10)
|
|
|
|
return log_error_errno(bridge_ifi, "Failed to add interface %s to bridge %s: %m", veth_name, bridge_name);
|
|
|
|
|
|
|
|
/* Count attempts, so that we don't enter an endless loop here. */
|
|
|
|
n++;
|
|
|
|
|
|
|
|
/* The bridge doesn't exist yet. Let's create it */
|
|
|
|
r = create_bridge(rtnl, bridge_name);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to create bridge interface %s: %m", bridge_name);
|
|
|
|
|
|
|
|
/* Try again, now that the bridge exists */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int remove_bridge(const char *bridge_name) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(release_lock_file) LockFile bridge_lock = LOCK_FILE_INIT;
|
2016-05-06 21:00:27 +02:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
|
|
|
const char *path;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Removes the specified bridge, but only if it is currently empty */
|
|
|
|
|
|
|
|
if (isempty(bridge_name))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to take network zone lock: %m");
|
|
|
|
|
|
|
|
path = strjoina("/sys/class/net/", bridge_name, "/brif");
|
|
|
|
|
|
|
|
r = dir_is_empty(path);
|
|
|
|
if (r == -ENOENT) /* Already gone? */
|
|
|
|
return 0;
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Can't detect if bridge %s is empty: %m", bridge_name);
|
|
|
|
if (r == 0) /* Still populated, leave it around */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
return remove_one_link(rtnl, bridge_name);
|
|
|
|
}
|
|
|
|
|
2019-12-19 21:16:30 +01:00
|
|
|
int test_network_interface_initialized(const char *name) {
|
|
|
|
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
|
|
|
|
int ifi, r;
|
|
|
|
char ifi_str[2 + DECIMAL_STR_MAX(int)];
|
2019-12-02 16:51:44 +01:00
|
|
|
|
2019-12-19 21:16:30 +01:00
|
|
|
if (path_is_read_only_fs("/sys"))
|
|
|
|
return 0;
|
2019-12-02 16:51:44 +01:00
|
|
|
|
2019-12-19 21:16:30 +01:00
|
|
|
/* udev should be around. */
|
2019-12-02 16:51:44 +01:00
|
|
|
|
2020-01-11 11:21:01 +01:00
|
|
|
ifi = resolve_interface_or_warn(NULL, name);
|
2019-12-19 21:16:30 +01:00
|
|
|
if (ifi < 0)
|
|
|
|
return ifi;
|
2015-09-07 17:43:45 +02:00
|
|
|
|
2019-12-19 21:16:30 +01:00
|
|
|
sprintf(ifi_str, "n%i", ifi);
|
|
|
|
r = sd_device_new_from_device_id(&d, ifi_str);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get device %s: %m", name);
|
|
|
|
|
|
|
|
r = sd_device_get_is_initialized(d);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to determine whether interface %s is initialized: %m", name);
|
|
|
|
if (r == 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Network interface %s is not initialized yet.", name);
|
|
|
|
|
|
|
|
r = device_is_renaming(d);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to determine the interface %s is being renamed: %m", name);
|
|
|
|
if (r > 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Interface %s is being renamed.", name);
|
|
|
|
|
|
|
|
return 0;
|
2015-09-07 17:43:45 +02:00
|
|
|
}
|
|
|
|
|
2019-12-19 21:17:57 +01:00
|
|
|
int move_network_interfaces(int netns_fd, char **ifaces) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2015-09-07 17:43:45 +02:00
|
|
|
char **i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (strv_isempty(ifaces))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
STRV_FOREACH(i, ifaces) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
2015-09-07 17:43:45 +02:00
|
|
|
int ifi;
|
|
|
|
|
2020-01-11 11:21:01 +01:00
|
|
|
ifi = resolve_interface_or_warn(&rtnl, *i);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (ifi < 0)
|
|
|
|
return ifi;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate netlink message: %m");
|
|
|
|
|
2019-12-19 21:17:57 +01:00
|
|
|
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_FD, netns_fd);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (r < 0)
|
2019-12-19 21:17:57 +01:00
|
|
|
return log_error_errno(r, "Failed to append namespace fd to netlink message: %m");
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, m, 0, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2015-09-07 17:43:45 +02:00
|
|
|
unsigned idx = 0;
|
|
|
|
char **i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (strv_isempty(ifaces))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
STRV_FOREACH(i, ifaces) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
2020-01-04 21:35:13 +01:00
|
|
|
_cleanup_free_ char *n = NULL, *a = NULL;
|
2015-09-07 17:43:45 +02:00
|
|
|
struct ether_addr mac;
|
|
|
|
int ifi;
|
|
|
|
|
2020-01-11 11:21:01 +01:00
|
|
|
ifi = resolve_interface_or_warn(&rtnl, *i);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (ifi < 0)
|
|
|
|
return ifi;
|
|
|
|
|
|
|
|
r = generate_mac(machine_name, &mac, MACVLAN_HASH_KEY, idx++);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to create MACVLAN MAC address: %m");
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate netlink message: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink interface index: %m");
|
|
|
|
|
2019-07-11 19:14:16 +02:00
|
|
|
n = strjoin("mv-", *i);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (!n)
|
|
|
|
return log_oom();
|
|
|
|
|
2020-01-04 21:35:13 +01:00
|
|
|
r = shorten_ifname(n);
|
|
|
|
if (r > 0) {
|
|
|
|
a = strjoin("mv-", *i);
|
|
|
|
if (!a)
|
|
|
|
return log_oom();
|
|
|
|
}
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink interface name: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink MAC address: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink namespace field: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "macvlan");
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, IFLA_MACVLAN_MODE, MACVLAN_MODE_BRIDGE);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to append macvlan mode: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to close netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to close netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, m, 0, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
|
2020-01-04 21:35:13 +01:00
|
|
|
|
|
|
|
(void) set_alternative_ifname(rtnl, n, a);
|
2015-09-07 17:43:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2015-09-07 17:43:45 +02:00
|
|
|
char **i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (strv_isempty(ifaces))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
STRV_FOREACH(i, ifaces) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
2020-01-04 21:35:13 +01:00
|
|
|
_cleanup_free_ char *n = NULL, *a = NULL;
|
2015-09-07 17:43:45 +02:00
|
|
|
int ifi;
|
|
|
|
|
2020-01-11 11:21:01 +01:00
|
|
|
ifi = resolve_interface_or_warn(&rtnl, *i);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (ifi < 0)
|
|
|
|
return ifi;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate netlink message: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink interface index: %m");
|
|
|
|
|
2019-07-11 19:14:16 +02:00
|
|
|
n = strjoin("iv-", *i);
|
2015-09-07 17:43:45 +02:00
|
|
|
if (!n)
|
|
|
|
return log_oom();
|
|
|
|
|
2020-01-04 21:35:13 +01:00
|
|
|
r = shorten_ifname(n);
|
|
|
|
if (r > 0) {
|
|
|
|
a = strjoin("iv-", *i);
|
|
|
|
if (!a)
|
|
|
|
return log_oom();
|
|
|
|
}
|
2015-09-07 17:43:45 +02:00
|
|
|
|
|
|
|
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink interface name: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add netlink namespace field: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "ipvlan");
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u16(m, IFLA_IPVLAN_MODE, IPVLAN_MODE_L2);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add ipvlan mode: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to close netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to close netlink container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, m, 0, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
|
2020-01-04 21:35:13 +01:00
|
|
|
|
|
|
|
(void) set_alternative_ifname(rtnl, n, a);
|
2015-09-07 17:43:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-11-12 21:54:28 +01:00
|
|
|
|
|
|
|
int veth_extra_parse(char ***l, const char *p) {
|
|
|
|
_cleanup_free_ char *a = NULL, *b = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-05-06 20:58:32 +02:00
|
|
|
if (r == 0 || !ifname_valid(a))
|
2015-11-12 21:54:28 +01:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-05-06 20:58:32 +02:00
|
|
|
if (r == 0 || !ifname_valid(b)) {
|
2015-11-12 21:54:28 +01:00
|
|
|
free(b);
|
|
|
|
b = strdup(a);
|
|
|
|
if (!b)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
r = strv_push_pair(l, a, b);
|
|
|
|
if (r < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
a = b = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
2016-04-25 13:42:20 +02:00
|
|
|
|
|
|
|
int remove_veth_links(const char *primary, char **pairs) {
|
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
|
|
|
char **a, **b;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* In some cases the kernel might pin the veth links between host and container even after the namespace
|
|
|
|
* died. Hence, let's better remove them explicitly too. */
|
|
|
|
|
|
|
|
if (isempty(primary) && strv_isempty(pairs))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
2016-05-06 21:00:27 +02:00
|
|
|
remove_one_link(rtnl, primary);
|
2016-04-25 13:42:20 +02:00
|
|
|
|
|
|
|
STRV_FOREACH_PAIR(a, b, pairs)
|
2016-05-06 21:00:27 +02:00
|
|
|
remove_one_link(rtnl, *a);
|
2016-04-25 13:42:20 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|