X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fnspawn%2Fnspawn.c;h=588a8ae8ac8c4ff230d704eb25a7ef0342a35184;hb=4bbfe7ad22b0666e82719e39e40be1c6cbb5cc91;hp=e71d9a88ad8867f79a728d240da8a730c6bfefc0;hpb=2fbe4296c5ba5bcce3ac845f196c60a88e3181fe;p=elogind.git diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index e71d9a88a..588a8ae8a 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -180,6 +180,7 @@ static bool arg_register = true; static bool arg_keep_unit = false; static char **arg_network_interfaces = NULL; static char **arg_network_macvlan = NULL; +static char **arg_network_ipvlan = NULL; static bool arg_network_veth = false; static const char *arg_network_bridge = NULL; static unsigned long arg_personality = 0xffffffffLU; @@ -211,6 +212,9 @@ static void help(void) { " --network-macvlan=INTERFACE\n" " Create a macvlan network interface based on an\n" " existing network interface to the container\n" + " --network-ipvlan=INTERFACE\n" + " Create a ipvlan network interface based on an\n" + " existing network interface to the container\n" " -n --network-veth Add a virtual ethernet connection between host\n" " and container\n" " --network-bridge=INTERFACE\n" @@ -285,6 +289,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_KEEP_UNIT, ARG_NETWORK_INTERFACE, ARG_NETWORK_MACVLAN, + ARG_NETWORK_IPVLAN, ARG_NETWORK_BRIDGE, ARG_PERSONALITY, ARG_VOLATILE, @@ -319,6 +324,7 @@ static int parse_argv(int argc, char *argv[]) { { "keep-unit", no_argument, NULL, ARG_KEEP_UNIT }, { "network-interface", required_argument, NULL, ARG_NETWORK_INTERFACE }, { "network-macvlan", required_argument, NULL, ARG_NETWORK_MACVLAN }, + { "network-ipvlan", required_argument, NULL, ARG_NETWORK_IPVLAN }, { "network-veth", no_argument, NULL, 'n' }, { "network-bridge", required_argument, NULL, ARG_NETWORK_BRIDGE }, { "personality", required_argument, NULL, ARG_PERSONALITY }, @@ -401,6 +407,13 @@ static int parse_argv(int argc, char *argv[]) { if (strv_extend(&arg_network_macvlan, optarg) < 0) return log_oom(); + arg_private_network = true; + break; + + case ARG_NETWORK_IPVLAN: + if (strv_extend(&arg_network_ipvlan, optarg) < 0) + return log_oom(); + /* fall through */ case ARG_PRIVATE_NETWORK: @@ -2381,6 +2394,87 @@ static int setup_macvlan(pid_t pid) { return 0; } +static int setup_ipvlan(pid_t pid) { + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + char **i; + int r; + + if (!arg_private_network) + return 0; + + if (strv_isempty(arg_network_ipvlan)) + return 0; + + r = sd_rtnl_open(&rtnl, 0); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + udev = udev_new(); + if (!udev) { + log_error("Failed to connect to udev."); + return -ENOMEM; + } + + STRV_FOREACH(i, arg_network_ipvlan) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; + _cleanup_free_ char *n = NULL; + int ifi; + + ifi = parse_interface(udev, *i); + 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_rtnl_message_append_u32(m, IFLA_LINK, ifi); + if (r < 0) + return log_error_errno(r, "Failed to add netlink interface index: %m"); + + n = strappend("iv-", *i); + if (!n) + return log_oom(); + + strshorten(n, IFNAMSIZ-1); + + r = sd_rtnl_message_append_string(m, IFLA_IFNAME, n); + if (r < 0) + return log_error_errno(r, "Failed to add netlink interface name: %m"); + + r = sd_rtnl_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_rtnl_message_open_container(m, IFLA_LINKINFO); + if (r < 0) + return log_error_errno(r, "Failed to open netlink container: %m"); + + r = sd_rtnl_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_rtnl_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_rtnl_message_close_container(m); + if (r < 0) + return log_error_errno(r, "Failed to close netlink container: %m"); + + r = sd_rtnl_message_close_container(m); + if (r < 0) + return log_error_errno(r, "Failed to close netlink container: %m"); + + r = sd_rtnl_call(rtnl, m, 0, NULL); + if (r < 0) + return log_error_errno(r, "Failed to add new ipvlan interfaces: %m"); + } + + return 0; +} + static int setup_seccomp(void) { #ifdef HAVE_SECCOMP @@ -2618,7 +2712,8 @@ static int wait_for_block_device(struct udev *udev, dev_t devnum, struct udev_de #define PARTITION_TABLE_BLURB \ "Note that the disk image needs to either contain only a single MBR partition of\n" \ - "type 0x83 that is marked bootable, or follow\n" \ + "type 0x83 that is marked bootable, or a sinlge GPT partition of type" \ + "0FC63DAF-8483-4772-8E79-3D69D8477DE4 or follow\n" \ " http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" \ "to be bootable with systemd-nspawn." @@ -2637,19 +2732,18 @@ static int dissect_image( #ifdef GPT_ROOT_SECONDARY int secondary_root_nr = -1; #endif - - _cleanup_free_ char *home = NULL, *root = NULL, *secondary_root = NULL, *srv = NULL; + _cleanup_free_ char *home = NULL, *root = NULL, *secondary_root = NULL, *srv = NULL, *generic = NULL; _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; _cleanup_udev_device_unref_ struct udev_device *d = NULL; _cleanup_blkid_free_probe_ blkid_probe b = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; struct udev_list_entry *first, *item; - bool home_rw = true, root_rw = true, secondary_root_rw = true, srv_rw = true; + bool home_rw = true, root_rw = true, secondary_root_rw = true, srv_rw = true, generic_rw = true; const char *pttype = NULL; blkid_partlist pl; struct stat st; int r; - bool is_gpt, is_mbr; + bool is_gpt, is_mbr, multiple_generic = false; assert(fd >= 0); assert(root_device); @@ -2769,10 +2863,6 @@ static int dissect_image( continue; flags = blkid_partition_get_flags(pp); - if (is_gpt && (flags & GPT_FLAG_NO_AUTO)) - continue; - if (is_mbr && (flags != 0x80)) /* Bootable flag */ - continue; nr = blkid_partition_get_partno(pp); if (nr < 0) @@ -2782,6 +2872,9 @@ static int dissect_image( sd_id128_t type_id; const char *stype; + if (flags & GPT_FLAG_NO_AUTO) + continue; + stype = blkid_partition_get_type_string(pp); if (!stype) continue; @@ -2841,48 +2934,41 @@ static int dissect_image( return log_oom(); } #endif + else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) { + + if (generic) + multiple_generic = true; + else { + generic_rw = !(flags & GPT_FLAG_READ_ONLY); + + r = free_and_strdup(&generic, node); + if (r < 0) + return log_oom(); + } + } } else if (is_mbr) { int type; + if (flags != 0x80) /* Bootable flag */ + continue; + type = blkid_partition_get_type(pp); if (type != 0x83) /* Linux partition */ continue; - /* Note that there's a certain, intended - * asymmetry here: while for GPT we simply - * take the first valid partition and ignore - * all others of the same type, for MBR we - * fail if there are multiple suitable - * partitions. This is because the GPT - * partition types are defined by us, and - * hence we can define their lookup semantics, - * while for the MBR logic we reuse existing - * definitions, and simply don't want to make - * out the situation. */ - - if (root) { - log_error("Identified multiple bootable Linux 0x83 partitions on\n" - " %s\n" - PARTITION_TABLE_BLURB, arg_image); - return -EINVAL; - } - - root_nr = nr; + if (generic) + multiple_generic = true; + else { + generic_rw = true; - r = free_and_strdup(&root, node); - if (r < 0) - return log_oom(); + r = free_and_strdup(&root, node); + if (r < 0) + return log_oom(); + } } } - if (!root && !secondary_root) { - log_error("Failed to identify root partition in disk image\n" - " %s\n" - PARTITION_TABLE_BLURB, arg_image); - return -EINVAL; - } - if (root) { *root_device = root; root = NULL; @@ -2895,6 +2981,31 @@ static int dissect_image( *root_device_rw = secondary_root_rw; *secondary = true; + } else if (generic) { + + /* There were no partitions with precise meanings + * around, but we found generic partitions. In this + * case, if there's only one, we can go ahead and boot + * it, otherwise we bail out, because we really cannot + * make any sense of it. */ + + if (multiple_generic) { + log_error("Identified multiple bootable Linux partitions on\n" + " %s\n" + PARTITION_TABLE_BLURB, arg_image); + return -EINVAL; + } + + *root_device = generic; + generic = NULL; + + *root_device_rw = generic_rw; + *secondary = false; + } else { + log_error("Failed to identify root partition in disk image\n" + " %s\n" + PARTITION_TABLE_BLURB, arg_image); + return -EINVAL; } if (home) { @@ -4027,6 +4138,10 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; + r = setup_ipvlan(pid); + if (r < 0) + goto finish; + r = register_machine(pid, ifi); if (r < 0) goto finish; @@ -4184,6 +4299,7 @@ finish: strv_free(arg_setenv); strv_free(arg_network_interfaces); strv_free(arg_network_macvlan); + strv_free(arg_network_ipvlan); strv_free(arg_bind); strv_free(arg_bind_ro); strv_free(arg_tmpfs);