diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afaf741 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +*#*# +*.#*# +*.a +*.o +*.orig +*.rej +.#* +.git +.deps +init +build/hyper_daemon +build/hyper-initrd.img +build/root/* +build/daemon +build/.* +src/.* +Makefile +Makefile.in +cscope.files +cscope.in.out +cscope.out +cscope.po.out +stamp-h +stamp-h.in +stamp-h1 +/config.h +/config.h.in +/config.log +/config.status +/configure +/aclocal.m4 +/autoscan.log +/autom4te.cache +/compile +/depcomp +/install-sh +/missing diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..6e23817 --- /dev/null +++ b/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=src build diff --git a/README.md b/README.md new file mode 100644 index 0000000..8ef7698 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +The init task for hyper. +exec ./autogen.sh to compile hyperinit diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..3dc7303 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +srcdir=`dirname $0` +test -z "$srcdir" && srcidr=. + +cd $srcdir +DIE=0 + +test -f src/init.c || { + echo + echo "You must run this script in the top-level hyperint drectory." + echo + DIE=1 +} + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to generate the hyperinit." + echo + DIE=1 +} + +(autoheader --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoheader installed to generate the hypernit." + echo + DIE=1 +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have automake installed to generate the hypernit." + echo + DIE=1 +} +(autoreconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoreconf installed to generate the hypernit." + echo + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +echo +echo "Generating build-system with:" +echo " aclocal: $(aclocal --version | head -1)" +echo " autoconf: $(autoconf --version | head -1)" +echo " autoheader: $(autoheader --version | head -1)" +echo " automake: $(automake --version | head -1)" +echo + +rm -rf autom4te.cache + +aclocal +autoconf +autoheader +automake --add-missing + +echo +echo "type '$srcdir/configure' and 'make' to compile hyperinit." +echo diff --git a/build/Makefile.am b/build/Makefile.am new file mode 100644 index 0000000..d748060 --- /dev/null +++ b/build/Makefile.am @@ -0,0 +1,4 @@ +bin_PROGRAMS=hyper_daemon +hyper_daemon_SOURCES=hyper_daemon.c ../src/net.c +all-local: + bash ./make-initrd.sh diff --git a/build/hyper_daemon.c b/build/hyper_daemon.c new file mode 100644 index 0000000..91671de --- /dev/null +++ b/build/hyper_daemon.c @@ -0,0 +1,168 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../src/hyper.h" +#include "../src/net.h" + +int test_sendmsg(int fd, unsigned int type, unsigned int len, char *message) +{ + uint8_t buf[4096]; + + + /* send hyper info to guest */ + hyper_set_be32(buf, type); + + len += 8; + + fprintf(stdout, "type is %u, len is %u\n", type, len); + hyper_set_be32(buf + 4, len); + + if (message) + memcpy(buf + 8, message, len - 8); + + if (write(fd, buf, len) != len) { + fprintf(stderr, "send SETDVM MESSAGE failed\n"); + return -1; + } + + fprintf(stdout, "finish sending\n"); + return 0; +} + +int test_sendmsg_from_file(int fd, unsigned int type, char *file) +{ + int file_fd = open(file, O_RDONLY); + uint8_t buf[4096]; + unsigned int len = 0; + + if (file_fd < 0) { + perror("fail to open file"); + return -1; + } + + while (len < 4096) { + int size = read(file_fd, buf + len, sizeof(buf) - len); + + fprintf(stdout, "read %d data\n", size); + if (size < 0) { + perror("fail to read data"); + return -1; + } else if (size == 0) { + /* buf[len] = '\0';*/ + fprintf(stdout, "get buf %s, call sendmsg\n", buf); + test_sendmsg(fd, type, len, (char *)buf); + break; + } + + len += size; + } + + close(file_fd); + + if (read(fd, buf, 8) != 8) { + fprintf(stderr, "read response failed\n"); + return -1; + } + + type = hyper_get_be32(buf); + if (type != ACK) { + fprintf(stderr, "incorrect type %d\n", type); + return -1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int sock, fd = -1; + struct sockaddr_un addr; + uint8_t buf[8]; + unsigned int type; + + unlink("/tmp/hyper.sock"); + + sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (sock == -1) { + perror("create unix socket failed"); + return -1; + } + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, "/tmp/hyper.sock", UNIX_PATH_MAX); + addr.sun_path[UNIX_PATH_MAX - 1] = '\0'; + + if (bind(sock, ((struct sockaddr *) &addr), sizeof(addr)) == -1) { + perror("bind failed"); + goto out; + } + + if (listen(sock, 1) == -1) { + perror("bind failed"); + goto out; + } + + while (fd == -1) + fd = accept4(sock, NULL, NULL, SOCK_CLOEXEC); + + fprintf(stdout, "connected\n"); + if (read(fd, buf, 8) != 8) { + fprintf(stderr, "read failed, buf %s\n", buf); + goto out1; + } + + type = hyper_get_be32(buf); + fprintf(stdout, "get type %d\n", type); + + if (type != READY) { + fprintf(stderr, "incorrect type %d\n", type); + goto out1; + } + + fprintf(stdout, "get length %d\n", hyper_get_be32(buf + 4)); + + /* test_sendmsg_from_file(fd, SETDVM, "sethyper.json"); */ + if (test_sendmsg_from_file(fd, STARTPOD, "startpod.json") < 0) { + fprintf(stderr, "send startpod message failed\n"); + goto out1; + } + + if (test_sendmsg_from_file(fd, EXECCMD, "execcmd.json") < 0) { + fprintf(stderr, "send execcmd message failed\n"); + goto out1; + } + + if (test_sendmsg(fd, STOPPOD, 0, NULL) < 0) { + fprintf(stderr, "send stoppod message failed\n"); + goto out1; + } + + if (read(fd, buf, 8) != 8) { + fprintf(stderr, "read response failed\n"); + return -1; + } + + type = hyper_get_be32(buf); + if (type != ACK) { + fprintf(stderr, "incorrect type %d\n", type); + return -1; + } + + if (read(fd, buf, 8) != 8) { + fprintf(stderr, "read response failed\n"); + return -1; + } +out1: + close(fd); +out: + close(sock); + + return 0; +} diff --git a/build/kernel b/build/kernel new file mode 100644 index 0000000..bfa67c4 Binary files /dev/null and b/build/kernel differ diff --git a/build/kernel_config b/build/kernel_config new file mode 100644 index 0000000..29a4599 --- /dev/null +++ b/build/kernel_config @@ -0,0 +1,1691 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86 4.0.0-rc5 Kernel Configuration +# +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_MMU=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_X86_64_SMP=y +CONFIG_X86_HT=y +CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_FHANDLE=y +# CONFIG_USELIB is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_IRQ_DOMAIN=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +# CONFIG_NO_HZ_IDLE is not set +CONFIG_NO_HZ_FULL=y +# CONFIG_NO_HZ_FULL_ALL is not set +# CONFIG_NO_HZ_FULL_SYSIDLE is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set + +# +# CPU/Task time and stats accounting +# +CONFIG_VIRT_CPU_ACCOUNTING=y +CONFIG_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +CONFIG_SRCU=y +# CONFIG_TASKS_RCU is not set +CONFIG_RCU_STALL_COMMON=y +CONFIG_CONTEXT_TRACKING=y +CONFIG_RCU_USER_QS=y +# CONFIG_CONTEXT_TRACKING_FORCE is not set +CONFIG_RCU_FANOUT=64 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_RCU_FAST_NO_HZ=y +# CONFIG_TREE_RCU_TRACE is not set +CONFIG_RCU_KTHREAD_PRIO=0 +CONFIG_RCU_NOCB_CPU=y +# CONFIG_RCU_NOCB_CPU_NONE is not set +# CONFIG_RCU_NOCB_CPU_ZERO is not set +CONFIG_RCU_NOCB_CPU_ALL=y +# CONFIG_BUILD_BIN2C is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_SUPPORTS_INT128=y +# CONFIG_NUMA_BALANCING is not set +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_FREEZER is not set +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +# CONFIG_CGROUP_CPUACCT is not set +# CONFIG_MEMCG is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_SCHED_AUTOGROUP=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +# CONFIG_EXPERT is not set +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_PCSPKR_PLATFORM=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +# CONFIG_BPF_SYSCALL is not set +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_PCI_QUIRKS=y +# CONFIG_EMBEDDED is not set +CONFIG_HAVE_PERF_EVENTS=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_UPROBES is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP_FILTER=y +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_NONE is not set +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y + +# +# GCOV-based kernel profiling +# +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_COMPRESS is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +# CONFIG_BLK_CMDLINE_PARSER is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUE_RWLOCK=y +CONFIG_QUEUE_RWLOCK=y +# CONFIG_FREEZER is not set + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_MPPARSE=y +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +# CONFIG_IOSF_MBI is not set +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +# CONFIG_PARAVIRT_SPINLOCKS is not set +# CONFIG_XEN is not set +CONFIG_KVM_GUEST=y +CONFIG_PARAVIRT_TIME_ACCOUNTING=y +CONFIG_PARAVIRT_CLOCK=y +CONFIG_NO_BOOTMEM=y +# CONFIG_MEMTEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_CENTAUR=y +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_CALGARY_IOMMU is not set +CONFIG_SWIOTLB=y +CONFIG_IOMMU_HELPER=y +CONFIG_NR_CPUS=8 +# CONFIG_SCHED_SMT is not set +CONFIG_SCHED_MC=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_X86_UP_APIC_MSI=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y +# CONFIG_X86_MCE is not set +CONFIG_X86_16BIT=y +CONFIG_X86_ESPFIX64=y +CONFIG_X86_VSYSCALL_EMULATION=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +# CONFIG_MICROCODE_INTEL_EARLY is not set +# CONFIG_MICROCODE_AMD_EARLY is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DIRECT_GBPAGES=y +CONFIG_NUMA=y +# CONFIG_AMD_NUMA is not set +# CONFIG_X86_64_ACPI_NUMA is not set +# CONFIG_NUMA_EMU is not set +CONFIG_NODES_SHIFT=9 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER=y +# CONFIG_SPARSEMEM_VMEMMAP is not set +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_ARCH_DISCARD_MEMBLOCK=y +# CONFIG_MOVABLE_NODE is not set +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y +CONFIG_MEMORY_BALLOON=y +# CONFIG_COMPACTION is not set +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +# CONFIG_ZSMALLOC is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +CONFIG_MTRR_SANITIZER=y +CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=0 +CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 +CONFIG_X86_PAT=y +CONFIG_ARCH_USES_PG_UNCACHED=y +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +# CONFIG_X86_INTEL_MPX is not set +# CONFIG_EFI is not set +CONFIG_SECCOMP=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +# CONFIG_SCHED_HRTICK is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_PHYSICAL_START=0x1000000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_CMDLINE_BOOL is not set +CONFIG_HAVE_LIVEPATCH=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y + +# +# Power management and ACPI options +# +# CONFIG_SUSPEND is not set +# CONFIG_HIBERNATION is not set +# CONFIG_PM is not set +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +# CONFIG_ACPI_PROCFS_POWER is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_DOCK is not set +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_NUMA is not set +CONFIG_ACPI_CUSTOM_DSDT_FILE="" +# CONFIG_ACPI_CUSTOM_DSDT is not set +# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_PCI_SLOT=y +CONFIG_X86_PM_TIMER=y +# CONFIG_ACPI_CONTAINER is not set +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_PMIC_OPREGION is not set +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# CPU Idle +# +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Memory power savings +# +# CONFIG_I7300_IDLE is not set + +# +# Bus options (PCI etc.) +# +CONFIG_PCI=y +CONFIG_PCI_DIRECT=y +# CONFIG_PCI_MMCONFIG is not set +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +# CONFIG_PCIEAER is not set +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEBUG is not set +CONFIG_PCIEASPM_DEFAULT=y +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_PERFORMANCE is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_REALLOC_ENABLE_AUTO=y +CONFIG_PCI_STUB=y +CONFIG_HT_IRQ=y +CONFIG_PCI_ATS=y +CONFIG_PCI_IOV=y +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +CONFIG_PCI_LABEL=y + +# +# PCI host controller drivers +# +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_PCCARD is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +CONFIG_HOTPLUG_PCI_CPCI=y +# CONFIG_HOTPLUG_PCI_CPCI_ZT5550 is not set +# CONFIG_HOTPLUG_PCI_CPCI_GENERIC is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set +# CONFIG_RAPIDIO is not set +# CONFIG_X86_SYSFB is not set + +# +# Executable file formats / Emulations +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# CONFIG_IA32_EMULATION is not set +CONFIG_X86_DEV_DMA_OPS=y +CONFIG_PMC_ATOM=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_XFRM_USER is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_UDP_TUNNEL is not set +# CONFIG_NET_FOU is not set +# CONFIG_GENEVE is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NET_PTP_CLASSIFY is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y +# CONFIG_NET_9P_DEBUG is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_UEVENT_HELPER is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_FW_LOADER=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +# CONFIG_DMA_SHARED_BUFFER is not set + +# +# Bus devices +# +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +CONFIG_PNP_DEBUG_MESSAGES=y + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=0 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_VIRTIO_BLK=y +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_VMWARE_BALLOON is not set +# CONFIG_SRAM is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_93CX6=m +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# + +# +# Altera FPGA firmware download module +# +# CONFIG_VMWARE_VMCI is not set + +# +# Intel MIC Bus Driver +# +# CONFIG_INTEL_MIC_BUS is not set + +# +# Intel MIC Host Driver +# + +# +# Intel MIC Card Driver +# +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_CXL_BASE is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +# CONFIG_SCSI_PROC_FS is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +CONFIG_SCSI_VIRTIO=y +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BCACHE=m +# CONFIG_BCACHE_DEBUG is not set +# CONFIG_BCACHE_CLOSURES_DEBUG is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_CRYPT is not set +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +CONFIG_DM_DELAY=m +CONFIG_DM_UEVENT=y +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +CONFIG_VIRTIO_NET=y +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_ETHERNET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +# CONFIG_PHYLIB is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Host-side USB support is needed for USB Network Adapter support +# +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_FINTEK is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MFD_HSU is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +CONFIG_HVC_DRIVER=y +CONFIG_VIRTIO_CONSOLE=y +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +CONFIG_DEVPORT=y +# CONFIG_XILLYBUS is not set + +# +# I2C support +# +# CONFIG_I2C is not set +# CONFIG_SPI is not set +# CONFIG_SPMI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_AVS is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set + +# +# Direct Rendering Manager +# +# CONFIG_DRM is not set + +# +# Frame buffer Devices +# +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_VGASTATE is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_SOUND is not set + +# +# HID support +# +# CONFIG_HID is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SUPPORT is not set +# CONFIG_UWB is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +CONFIG_VIRT_DRIVERS=y +CONFIG_VIRTIO=y + +# +# Virtio drivers +# +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y + +# +# Microsoft Hyper-V guest support +# +# CONFIG_HYPERV is not set +# CONFIG_STAGING is not set +# CONFIG_X86_PLATFORM_DEVICES is not set +# CONFIG_CHROME_PLATFORMS is not set + +# +# Hardware Spinlock drivers +# + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_I8253_LOCK=y +CONFIG_CLKBLD_I8253=y +# CONFIG_ATMEL_PIT is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_EM_TIMER_STI is not set +# CONFIG_MAILBOX is not set +# CONFIG_IOMMU_SUPPORT is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# + +# +# SOC (System On Chip) specific Drivers +# +# CONFIG_SOC_TI is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_FMC is not set + +# +# PHY Subsystem +# +# CONFIG_GENERIC_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set +# CONFIG_THUNDERBOLT is not set + +# +# Android +# +# CONFIG_ANDROID is not set + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +# CONFIG_DELL_RBU is not set +# CONFIG_DCDBAS is not set +# CONFIG_DMIID is not set +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT_FIND is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_POSIX_ACL=y +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +# CONFIG_OVERLAY_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_9P_FS=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_9P_FS_SECURITY=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=m + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y + +# +# printk and dmesg options +# +# CONFIG_PRINTK_TIME is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 + +# +# Compile-time checks and compiler options +# +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_ARCH_WANT_FRAME_POINTERS=y +# CONFIG_FRAME_POINTER is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_KERNEL is not set + +# +# Memory Debugging +# +# CONFIG_PAGE_EXTENSION is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_HAVE_DEBUG_STACKOVERFLOW=y +CONFIG_HAVE_ARCH_KMEMCHECK=y + +# +# Debug Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +# CONFIG_STACKTRACE is not set +CONFIG_DEBUG_BUGVERBOSE=y + +# +# RCU Debugging +# +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS=y +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set + +# +# Runtime Testing +# +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_X86_VERBOSE_BOOTUP is not set +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_DEBUG_SET_MODULE_RONX is not set +CONFIG_DOUBLEFAULT=y +# CONFIG_IOMMU_STRESS is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=0 +# CONFIG_OPTIMIZE_INLINING is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=m +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=m +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +# CONFIG_CRYPTO_SHA1_MB is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_X86_64 is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SALSA20_X86_64 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_HW is not set +CONFIG_HAVE_KVM=y +# CONFIG_VIRTUALIZATION is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_HAVE_ARCH_BITREVERSE is not set +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=m +CONFIG_CRC8=m +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_POWERPC=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_XZ_DEC_BCJ=y +# CONFIG_XZ_DEC_TEST is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +CONFIG_AVERAGE=y +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_ARCH_HAS_SG_CHAIN=y diff --git a/build/make-initrd.sh b/build/make-initrd.sh new file mode 100755 index 0000000..21bbe76 --- /dev/null +++ b/build/make-initrd.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +rm -rf root +mkdir root + +cp ../src/init ./root + +ldd ./root/init | while read line +do + arr=(${line// / }) + + for lib in ${arr[@]} + do + if [ "${lib:0:1}" = "/" ]; then + dir=root`dirname $lib` + mkdir -p "${dir}" + cp -f $lib $dir + fi + done +done +cd ./root && find . | cpio -H newc -o | gzip -9 > ../hyper-initrd.img diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..1215183 --- /dev/null +++ b/configure.ac @@ -0,0 +1,67 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) +AC_INIT([dvminit], [0.1], [list@getdvm.org]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) +AC_CONFIG_SRCDIR([src/init.c]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CC + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h stddef.h stdint.h stdlib.h string.h sys/mount.h sys/socket.h unistd.h], +[headers_found=yes], +[headers_found=no]) + +if test "x$headers_found" != "xyes"; then + AC_MSG_ERROR(Unable to find necessary headers) +fi + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_UINT32_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_FORK +AC_CHECK_FUNCS([dup2 memmove memset mkdir setenv socket strchr strdup strrchr strtoul], [fail=0], [fail=1]) + +if test "$fail" = "1" ; then + AC_MSG_ERROR(Unable to find necessary functions) +fi + +AC_ARG_WITH([ttys], + [AS_HELP_STRING([--with-ttys], + [use pci serial device as container tty])], + [],[with_ttys=yes]) + +if test "x$with_ttys" != "xno" ; then + AC_DEFINE_UNQUOTED([WITH_TTYS], 1, [where use pci serial device as container tty]) +fi +AM_CONDITIONAL([WITH_TTYS], [test "x$with_ttys" != "xno"]) + +AC_CONFIG_FILES([ + Makefile + src/Makefile + build/Makefile +]) +AC_OUTPUT + +AC_MSG_RESULT([ + ${PACKAGE} ${VERSION} + prefix: ${prefix} + + with-ttys: ${with_ttys} + + compiler: ${CC} + cflags: ${CFLAGS} + suid cflags: ${SUID_CFLAGS} + ldflags: ${LDFLAGS} + suid ldflags: ${SUID_LDFLAGS} +]) diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..42acaef --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,3 @@ +AM_CFLAGS = -Wall +bin_PROGRAMS=init +init_SOURCES=init.c jsmn.c net.c util.c parse.c container.c exec.c event.c diff --git a/src/container.c b/src/container.c new file mode 100644 index 0000000..0e34924 --- /dev/null +++ b/src/container.c @@ -0,0 +1,546 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hyper.h" + +static int container_setup_env(struct hyper_container *container) +{ + int i; + struct env *env; + + for (i = 0; i < container->envs_num; i++) { + env = &container->envs[i]; + + setenv(env->env, env->value, 1); + } + + return 0; +} + +static int container_setup_volume(struct hyper_container *container) +{ + int i; + char dev[512], path[512]; + struct volume *vol; + + for (i = 0; i < container->vols_num; i++) { + vol = &container->vols[i]; + + sprintf(dev, "/.oldroot/dev/%s", vol->device); + sprintf(path, "/tmp/%s", vol->mountpoint); + fprintf(stdout, "mount %s to %s\n", dev, vol->mountpoint); + + if (hyper_mkdir(path) < 0 || hyper_mkdir(vol->mountpoint) < 0) { + fprintf(stdout, "mountpoint %s\n", vol->mountpoint); + perror("create volume dir failed"); + continue; + } + + if (mount(dev, path, vol->fstype, 0, NULL) < 0) { + perror("mount volume device faled"); + continue; + } + + if (mount(path, vol->mountpoint, NULL, MS_BIND, NULL) < 0) { + perror("mount volume device faled"); + continue; + } + + if (vol->readonly && + mount(path, vol->mountpoint, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) < 0) + perror("mount fsmap faled"); + + umount(path); + } + + return 0; +} + +static void container_unmount_oldroot(char *path) +{ + FILE *mtab; + struct mntent *mnt; + char *mntlist[128]; + int i; + int n = 0; + char *filesys; + + mtab = setmntent("/proc/mounts", "r"); + if (mtab == NULL) { + fprintf(stderr, "cannot open /proc/mount"); + return; + } + + while (n < 128 && (mnt = getmntent(mtab))) { + if (strncmp(mnt->mnt_dir, path, strlen(path))) + continue; + mntlist[n++] = strdup(mnt->mnt_dir); + } + + endmntent(mtab); + + for (i = n - 1; i >= 0; i--) { + filesys = mntlist[i]; + fprintf(stdout, "umount %s\n", filesys); + if (umount(mntlist[i]) < 0 && umount2(mntlist[i], + MNT_DETACH) < 0) { + fprintf(stdout, "umount %s: %s failed\n", + filesys, strerror(errno)); + } + } +} + +static int container_setup_mount(struct hyper_container *container) +{ + int i, fd; + char src[512]; + struct fsmap *map; + + if (mount("proc", "/proc", "proc", 0, NULL) < 0 || + mount("sysfs", "/sys", "sysfs", 0, NULL) < 0 || + mount("devtmpfs", "/dev", "devtmpfs", 0, NULL) < 0) { + perror("mount basic filesystem for container failed"); + return -1; + } + + if (hyper_mkdir("/dev/pts") < 0) { + fprintf(stderr, "create /dev/pts failed\n"); + return -1; + } + + if (sprintf(src, "/.oldroot/tmp/hyper/%s/devpts", container->id) < 0) { + fprintf(stderr, "get container devpts failed\n"); + return -1; + } + + if (mount(src, "/dev/pts/", NULL, MS_BIND, NULL) < 0) { + perror("move pts to /dev/pts failed"); + return -1; + } + + unlink("/dev/ptmx"); + link("/dev/pts/ptmx", "/dev/ptmx"); + + for (i = 0; i < container->maps_num; i++) { + struct stat st; + + map = &container->maps[i]; + + sprintf(src, "/.oldroot/tmp/hyper/shared/%s", map->source); + fprintf(stdout, "mount %s to %s\n", src, map->path); + + stat(src, &st); + if (st.st_mode & S_IFDIR) { + if (hyper_mkdir(map->path) < 0) { + perror("create map dir failed"); + continue; + } + } else { + fd = open(map->path, O_CREAT|O_WRONLY, 0755); + if (fd < 0) { + perror("create map file failed"); + continue; + } + close(fd); + } + + if (mount(src, map->path, NULL, MS_BIND, NULL) < 0) { + perror("mount fsmap faled"); + continue; + } + + if (map->readonly == 0) + continue; + + if (mount(src, map->path, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) < 0) + perror("mount fsmap faled"); + } + + return 0; +} + +static int container_setup_workdir(struct hyper_container *container) +{ + if (container->workdir && chdir(container->workdir) < 0) { + perror("change work directory failed"); + return -1; + } + + return 0; +} + +static int container_setup_tty(int fd, struct hyper_container *container) +{ + return hyper_dup_exec_tty(fd, &container->exec); +} + +static int hyper_list_dir(char *path) +{ + struct dirent **list; + struct dirent *dir; + int i, num; + + fprintf(stdout, "list %s\n", path); + num = scandir(path, &list, NULL, NULL); + if (num < 0) { + perror("scan path failed"); + return -1; + } + + for (i = 0; i < num; i++) { + dir = list[i]; + fprintf(stdout, "%s get %s\n", path, dir->d_name); + } + + free(list); + return 0; +} + +static int hyper_rescan_scsi(void) +{ + struct dirent **list; + struct dirent *dir; + int fd = -1, i, num; + char path[256]; + + num = scandir("/sys/class/scsi_host/", &list, NULL, NULL); + if (num < 0) { + perror("scan /sys/calss/virtio-ports/ failed"); + return -1; + } + + memset(path, 0, sizeof(path)); + + for (i = 0; i < num; i++) { + dir = list[i]; + if (dir->d_name[0] == '.') + continue; + + if (snprintf(path, sizeof(path), "/sys/class/scsi_host/%s/scan", + dir->d_name) < 0) { + fprintf(stderr, "get scsi host device %s path failed\n", + dir->d_name); + continue; + } + + fprintf(stdout, "path %s\n", path); + fd = open(path, O_WRONLY); + if (fd < 0) { + perror("open path failed"); + continue; + } + + if (write(fd, "- - - \n", 7) < 0) + perror("write to scan failed"); + + close(fd); + } + + fprintf(stdout, "finish scan scsi\n"); + return 0; + free(list); +} + +struct hyper_container_arg { + struct hyper_container *c; + int pipe[2]; +}; + +static int hyper_container_init(void *data) +{ + struct hyper_container_arg *arg = data; + struct hyper_container *container = arg->c; + char root[512], oldroot[512]; + + fprintf(stdout, "%s in\n", __func__); + if (container->exec.argv == NULL) { + fprintf(stdout, "no cmd!\n"); + goto fail; + } + + if (hyper_rescan_scsi() < 0) { + fprintf(stdout, "rescan scsi failed\n"); + goto fail; + } + + if (container_setup_env(container) < 0) { + fprintf(stdout, "setup env failed\n"); + goto fail; + } + + if (mount("", "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) { + perror("mount SLAVE failed"); + goto fail; + } + + if (mount("", "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) { + perror("mount PRIVATE failed"); + goto fail; + } + + sprintf(root, "/tmp/hyper/%s/root/", container->id); + if (hyper_mkdir(root) < 0) { + perror("make root directroy failed"); + goto fail; + } + + fprintf(stdout, "container root directory %s\n", root); + + if (container->fstype) { + char dev[128]; + + sprintf(dev, "/dev/%s", container->image); + fprintf(stdout, "device %s\n", dev); + + if (mount(dev, root, container->fstype, 0, NULL) < 0) { + perror("mount device failed"); + goto fail; + } + } else { + char path[512]; + + sprintf(path, "/tmp/hyper/shared/%s/", container->image); + fprintf(stdout, "src directory %s\n", path); + + if (mount(path, root, NULL, MS_BIND, NULL) < 0) { + perror("mount src dir failed"); + goto fail; + } + } + + fprintf(stdout, "root directory for container is %s/%s, init task %s\n", + root, container->rootfs, container->exec.argv[0]); + + hyper_list_dir(root); + sprintf(oldroot, "%s/%s/.oldroot", root, container->rootfs); + if (hyper_mkdir(oldroot) < 0) { + perror("make oldroot directroy failed"); + goto fail; + } + + if (mount("/", oldroot, NULL, MS_BIND|MS_REC, NULL) < 0) { + perror("bind oldroot failed"); + goto fail; + } + /* reuse oldroot array */ + sprintf(oldroot, "%s/%s/", root, container->rootfs); + /* pivot_root won't work, see + * Documention/filesystem/ramfs-rootfs-initramfs.txt */ + chroot(oldroot); + + chdir("/"); + + if (container_setup_volume(container) < 0) { + fprintf(stderr, "container sets up voulme failed\n"); + goto fail; + } + + if (container_setup_mount(container) < 0) { + fprintf(stderr, "container sets up mount ns failed\n"); + goto fail; + } + + if (container_setup_workdir(container) < 0) { + fprintf(stderr, "container sets up work directory failed\n"); + goto fail; + } + + container_unmount_oldroot("/.oldroot"); + + fflush(stdout); + + if (container_setup_tty(arg->pipe[1], container) < 0) { + fprintf(stdout, "setup tty failed\n"); + goto fail; + } + + close(arg->pipe[0]); + close(arg->pipe[1]); + + execvp(container->exec.argv[0], container->exec.argv); + + _exit(-1); + +fail: + container->exec.code = -1; + hyper_send_type_block(arg->pipe[1], ERROR, 0); + _exit(-1); +} + +int hyper_start_container(struct hyper_container *container) +{ + int stacksize = getpagesize() * 4; + void *stack = malloc(stacksize); + struct hyper_container_arg arg = { + .c = container, + }; + int flags = CLONE_NEWNS | SIGCHLD; + uint32_t type; + int pid; + + if (container->image == NULL || container->exec.argv == NULL) { + fprintf(stdout, "container root image %s, argv %p\n", + container->image, container->exec.argv); + goto fail; + } + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, arg.pipe) < 0) { + perror("create pipe between pod init execcmd failed"); + goto fail; + } + + pid = clone(hyper_container_init, stack + stacksize, flags, &arg); + free(stack); + if (pid < 0) { + perror("create child process failed"); + goto fail; + } + + /* wait for ready message */ + if (hyper_get_type_block(arg.pipe[0], &type) < 0 || type != READY) { + fprintf(stdout, "wait for container started failed\n"); + goto fail; + } + + close(arg.pipe[0]); + close(arg.pipe[1]); + + container->exec.pid = pid; + fprintf(stdout, "container %s init pid is %d\n", container->id, pid); + return 0; + +fail: + fprintf(stdout, "container %s init exit code %d\n", container->id, -1); + container->exec.code = -1; + return -1; +} + +int hyper_start_containers(struct hyper_pod *pod) +{ + int i; + + /* mount new proc directory */ + if (umount("/proc") < 0) { + perror("umount proc filesystem failed\n"); + return -1; + } + + if (mount("proc", "/proc", "proc", 0, NULL) < 0) { + perror("mount proc filesystem failed\n"); + return -1; + } + + if (sethostname(pod->hostname, strlen(pod->hostname)) < 0) { + perror("set host name failed"); + return -1; + } + + for (i = 0; i < pod->c_num; i++) + hyper_start_container(&pod->c[i]); + + return 0; +} + +int hyper_restart_containers(struct hyper_pod *pod) +{ + int i; + struct hyper_container *c; + + for (i = 0; i < pod->c_num; i++) { + c = &pod->c[i]; + + if (hyper_start_container(c) < 0) { + fprintf(stderr, "restart container %s failed\n", c->id); + hyper_send_type(pod->ctl.fd, ERROR); + return -1; + } + } + + if (hyper_send_type(pod->ctl.fd, ACK) < 0) + return -1; + + return 0; +} + +struct hyper_container *hyper_find_container(struct hyper_pod *pod, char *id) +{ + int i; + struct hyper_container *container; + + for (i = 0; i < pod->c_num; i++) { + container = &pod->c[i]; + + if (strlen(container->id) != strlen(id)) + continue; + + if (strncmp(container->id, id, strlen(id))) + continue; + + return container; + } + + return NULL; +} + +void hyper_cleanup_container(struct hyper_pod *pod) +{ + int i, j; + struct hyper_container *c; + struct volume *vol; + struct env *env; + struct fsmap *map; + char root[512]; + + for (i = 0; i < pod->c_num; i++) { + c = &pod->c[i]; + + sprintf(root, "/tmp/hyper/%s/devpts/", c->id); + if (umount(root) < 0 && umount2(root, MNT_DETACH)) + perror("umount devpts failed"); + + free(c->id); + free(c->rootfs); + free(c->image); + free(c->workdir); + free(c->fstype); + + for (j = 0; j < c->vols_num; j++) { + vol = &(c->vols[j]); + free(vol->device); + free(vol->mountpoint); + free(vol->fstype); + } + free(c->vols); + + for (j = 0; j < c->envs_num; j++) { + env = &(c->envs[j]); + free(env->env); + free(env->value); + } + free(c->envs); + + for (j = 0; j < c->maps_num; j++) { + map = &(c->maps[j]); + free(map->source); + free(map->path); + } + free(c->maps); + } + + free(pod->c); + pod->c = NULL; + pod->c_num = 0; +} diff --git a/src/container.h b/src/container.h new file mode 100644 index 0000000..dc95f8c --- /dev/null +++ b/src/container.h @@ -0,0 +1,47 @@ +#ifndef _CONTAINER_H_ +#define _CONTAINER_H_ + +#include "exec.h" + +struct env { + char *env; + char *value; +}; + +struct volume { + char *device; + char *mountpoint; + char *fstype; + int readonly; +}; + +struct fsmap { + char *source; + char *path; + int readonly; +}; + +struct hyper_container { + char *id; + char *rootfs; + char *image; + char *workdir; + char *fstype; + struct volume *vols; + struct env *envs; + struct fsmap *maps; + int vols_num; + int envs_num; + int maps_num; + uint32_t code; + struct hyper_exec exec; +}; + +struct hyper_pod; + +int hyper_start_containers(struct hyper_pod *pod); +struct hyper_container *hyper_find_container(struct hyper_pod *pod, char *id); +int hyper_restart_containers(struct hyper_pod *pod); +void hyper_cleanup_container(struct hyper_pod *pod); + +#endif diff --git a/src/event.c b/src/event.c new file mode 100644 index 0000000..dcc3895 --- /dev/null +++ b/src/event.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "event.h" + +void hyper_reset_event(struct hyper_event *de) +{ + free(de->buf.data); + de->buf.data = NULL; + memset(de, 0, sizeof(*de)); +} + +int hyper_init_event(struct hyper_event *de, + struct hyper_event_ops *ops, + uint32_t size, int to, void *arg) +{ + struct hyper_buf *buf = &de->buf; + + memset(buf, 0, sizeof(*buf)); + + de->ops = ops; + de->ptr = arg; + de->to = to; + buf->size = size; + + if (size) { + buf->data = malloc(size); + if (buf->data == NULL) { + fprintf(stderr, "allocate data for event failed\n"); + return -1; + } + } + + return 0; +} + +int hyper_add_event(int efd, struct hyper_event *de) +{ + struct epoll_event event = { + .events = EPOLLIN, + .data.ptr = de, + }; + + if (hyper_setfd_nonblock(de->fd) < 0) { + perror("set fd nonblock failed"); + return -1; + } + + fprintf(stdout, "%s add event fd %d, %p\n", __func__, de->fd, de->ops); + + if (epoll_ctl(efd, EPOLL_CTL_ADD, de->fd, &event) < 0) { + perror("epoll_ctl fd failed"); + return -1; + } + + return 0; +} + +void hyper_event_hup(struct hyper_event *de, int efd) +{ + if (epoll_ctl(efd, EPOLL_CTL_DEL, de->fd, NULL) < 0) + perror("epoll_ctl del epoll event failed"); + close(de->fd); + hyper_reset_event(de); +} + +int hyper_handle_event(int efd, struct epoll_event *event) +{ + struct hyper_event *de = event->data.ptr; + + if (event->events & EPOLLHUP) { + fprintf(stdout, "%s event EPOLLHUP, de %p, fd %d, %p\n", + __func__, de, de->fd, de->ops); + if (de->ops->hup) + de->ops->hup(de, efd); + return 0; + } else if (event->events & EPOLLIN) { + return de->ops->read(de); + } else if (event->events & EPOLLERR) { + fprintf(stderr, "get epoll err of not epool in event\n"); + return -1; + } + + fprintf(stdout, "%s get unknown event %d\n", __func__, event->events); + return -1; +} diff --git a/src/event.h b/src/event.h new file mode 100644 index 0000000..d0a8a7b --- /dev/null +++ b/src/event.h @@ -0,0 +1,36 @@ +#ifndef _EVENT_H +#define _EVENT_H + +#include +#include + +struct hyper_event; + +struct hyper_event_ops { + int (*read)(struct hyper_event *e); + int (*getlen)(struct hyper_event *e, uint32_t *len); + int (*handle)(struct hyper_event *e, uint32_t len); + void (*hup)(struct hyper_event *e, int efd); +}; + +struct hyper_buf { + uint32_t get; + uint32_t size; + uint8_t *data; +}; + +struct hyper_event { + int fd; + int to; + struct hyper_buf buf; + struct hyper_event_ops *ops; + void *ptr; +}; + +int hyper_add_event(int efd, struct hyper_event *de); +int hyper_init_event(struct hyper_event *de, struct hyper_event_ops *ops, + uint32_t size, int to, void *arg); +int hyper_handle_event(int efd, struct epoll_event *event); +void hyper_reset_event(struct hyper_event *de); +void hyper_event_hup(struct hyper_event *de, int efd); +#endif diff --git a/src/exec.c b/src/exec.c new file mode 100644 index 0000000..85cc927 --- /dev/null +++ b/src/exec.c @@ -0,0 +1,558 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hyper.h" +#include "util.h" +#include "parse.h" + +static int pts_loop(struct hyper_event *de) +{ + int size = 0; + uint8_t buf[512]; + uint8_t seq[12]; + struct hyper_exec *exec = container_of(de, struct hyper_exec, e); + + fprintf(stdout, "%s\n", __func__); + while (1) { + size = read(de->fd, buf, sizeof(buf)); + if (size <= 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN || errno == EIO) + break; + + perror("fail to read tty fd"); + return -1; + } + + hyper_set_be64(seq, exec->seq); + hyper_set_be32(seq + 8, size + 12); + + if (hyper_send_data(de->to, seq, 12) < 0) + continue; + + hyper_send_data(de->to, buf, size); + } + + return 0; +} + +struct hyper_event_ops pts_ops = { + .read = pts_loop, + .hup = hyper_event_hup, +}; + +int hyper_setup_exec_tty(struct hyper_exec *e) +{ + int unlock = 0; + char ptmx[512], path[512]; + + if (e->seq == 0) + return 0; + + if (e->id) { + if (sprintf(path, "/tmp/hyper/%s/devpts/", e->id) < 0) { + fprintf(stderr, "get ptmx path failed\n"); + return -1; + } + } else { + if (sprintf(path, "/dev/pts/") < 0) { + fprintf(stderr, "get ptmx path failed\n"); + return -1; + } + } + + if (sprintf(ptmx, "%s/ptmx", path) < 0) { + fprintf(stderr, "get ptmx path failed\n"); + return -1; + } + + e->e.fd = open(ptmx, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC); + if (e->e.fd < 0) { + perror("open ptmx device for execcmd failed"); + return -1; + } + + if (ioctl(e->e.fd, TIOCSPTLCK, &unlock) < 0) { + perror("ioctl unlock ptmx device failed"); + return -1; + } + + if (ioctl(e->e.fd, TIOCGPTN, &e->ptyno) < 0) { + perror("ioctl get execcmd pty device failed"); + return -1; + } + + if (sprintf(ptmx, "%s/%d", path, e->ptyno) < 0) { + fprintf(stderr, "get ptmx path failed\n"); + return -1; + } + + e->pty = strdup(ptmx); + fprintf(stdout, "get pty device for exec %s\n", e->pty); + + return 0; +} + +int hyper_dup_exec_tty(int to, struct hyper_exec *e) +{ + int fd; + char pty[128]; + + setsid(); + + if (e->seq) { + if (sprintf(pty, "/dev/pts/%d", e->ptyno) < 0) { + perror("get pts device name failed"); + return -1; + } + } else { + if (sprintf(pty, "/dev/null") < 0) { + perror("get pts device name failed"); + return -1; + } + } + + fprintf(stdout, "setup pty device %s for exec\n", pty); + + fd = open(pty, O_RDWR | O_NOCTTY); + if (fd < 0) { + perror("open pty device for execcmd failed"); + return -1; + } + + if (ioctl(fd, TIOCSCTTY, NULL) < 0) { + perror("ioctl pty device for execcmd failed"); + return -1; + } + + if (hyper_send_type_block(to, READY, 0) < 0) { + fprintf(stderr, "send ready message to hyper init failed\n"); + return -1; + } + + fflush(stdout); + + if (dup2(fd, STDIN_FILENO) < 0) { + perror("dup tty device to stdin failed"); + close(fd); + return -1; + } + + if (dup2(fd, STDOUT_FILENO) < 0) { + perror("dup tty device to stdout failed"); + close(fd); + return -1; + } + + if (dup2(fd, STDERR_FILENO) < 0) { + perror("dup tty device to stderr failed"); + close(fd); + return -1; + } + + close(fd); + + return 0; +} + +int hyper_exec_in_container(struct hyper_pod *pod, + struct hyper_exec *exec) +{ + global_exec = exec; + + if (hyper_send_type_block(ctl.ctl.fd, EXECCMD, 1) < 0) { + global_exec = NULL; + fprintf(stderr, "tell pod init EXECCMD failed\n"); + return -1; + } + + list_add_tail(&exec->list, &pod->ce_head); + if (exec->seq == 0) + return 0; + + fprintf(stdout, "init container exec pts event %p, ops %p, fd %d\n", + &exec->e, &pts_ops, exec->e.fd); + + if (hyper_init_event(&exec->e, &pts_ops, 0, ctl.tty.fd, NULL) < 0 || + hyper_add_event(ctl.efd, &exec->e) < 0) { + fprintf(stderr, "add pts master event failed\n"); + return -1; + } + + return 0; +} + +int hyper_request_restart_containers(struct hyper_pod *pod) +{ + int i; + struct hyper_exec *exec; + + pod->code = 0; + pod->remains = pod->c_num; + + for (i = 0; i < pod->c_num; i++) { + exec = &pod->c[i].exec; + + if (hyper_setup_exec_tty(exec) < 0) { + fprintf(stdout, "restart setup container tty failed\n"); + return -1; + } + } + + if (hyper_send_type_block(ctl.ctl.fd, RESTARTCONTAINER, 1) < 0) { + fprintf(stderr, "tell container init RESTARTCONTAINER failed\n"); + return -1; + } + + for (i = 0; i < pod->c_num; i++) { + exec = &pod->c[i].exec; + + list_add_tail(&exec->list, &pod->ce_head); + if (exec->seq == 0) + continue; + + if (hyper_init_event(&exec->e, &pts_ops, 0, ctl.tty.fd, NULL) < 0 || + hyper_add_event(ctl.efd, &exec->e) < 0) { + fprintf(stderr, "add pts master event failed\n"); + return -1; + } + } + + return 0; +} + +int hyper_exec_cmd(char *json, int length) +{ + struct hyper_exec *exec; + struct hyper_pod *pod = &global_pod; + int pid, pipe[2]; + + fprintf(stdout, "call hyper_exec_cmd, json %s, len %d\n", json, length); + + exec = hyper_parse_execcmd(json, length); + if (exec == NULL) { + fprintf(stderr, "parse exec cmd failed\n"); + return -1; + } + + if (exec->argv == NULL) { + fprintf(stderr, "cmd is %p, seq %" PRIu64 ", container %s\n", + exec->argv, exec->seq, exec->id); + return -1; + } + + if (hyper_setup_exec_tty(exec) < 0) { + fprintf(stderr, "setup exec tty failed\n"); + return -1; + } + + if (exec->id) { + if (hyper_exec_in_container(pod, exec) < 0) { + fprintf(stderr, "notify container exec failed\n"); + return -1; + } + + return 0; + } + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, pipe) < 0) { + perror("create pipe between pod init execcmd failed"); + return -1; + } + + pid = fork(); + if (pid < 0) { + fprintf(stderr, "fork failed\n"); + return -1; + } else if (pid > 0) { + uint32_t type; + + if (hyper_get_type_block(pipe[0], &type) < 0 || type != READY) { + fprintf(stderr, "hyper init doesn't get execcmd ready message\n"); + return -1; + } + + close(pipe[0]); + close(pipe[1]); + fprintf(stdout, "hyper init get ready message\n"); + exec->pid = pid; + fprintf(stdout, "create exec cmd %s pid %d\n", exec->argv[0], pid); + + list_add_tail(&exec->list, &pod->pe_head); + if (exec->seq == 0) + return 0; + + fprintf(stdout, "init pod exec pts event %p, ops %p, fd %d\n", + &exec->e, &pts_ops, exec->e.fd); + if (hyper_init_event(&exec->e, &pts_ops, 0, ctl.tty.fd, NULL) < 0 || + hyper_add_event(ctl.efd, &exec->e) < 0) { + fprintf(stderr, "add pts master event failed\n"); + return -1; + } + + return 0; + } + + if (hyper_dup_exec_tty(pipe[1], exec) < 0) { + fprintf(stderr, "dup pts to exec stdio failed\n"); + _exit(-1); + } + + close(pipe[0]); + close(pipe[1]); + + if (execvp(exec->argv[0], exec->argv) < 0) { + perror("exec failed"); + _exit(-1); + } + + _exit(0); +} + +int hyper_container_execcmd(struct hyper_pod *pod) +{ + struct hyper_exec *exec = global_exec; + struct hyper_container *container = NULL; + int fd, pid, sock = pod->ctl.fd; + char root[512]; int pipe[2]; + + global_exec = NULL; + + container = hyper_find_container(pod, exec->id); + if (container == NULL) { + fprintf(stderr, "can not find container %s\n", exec->id); + return -1; + } + + if (sprintf(root, "/tmp/hyper/%s/devpts/", exec->id) < 0) { + fprintf(stderr, "get container %s pts path failed\n", exec->id); + return -1; + } + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, pipe) < 0) { + perror("create pipe between pod init execcmd failed"); + return -1; + } + + pid = fork(); + if (pid < 0) { + fprintf(stderr, "container init fork failed\n"); + return -1; + } else if (pid > 0) { + uint32_t type; + + if (hyper_get_type_block(pipe[0], &type) < 0 || type != READY) { + fprintf(stderr, "pod init get execcmd ready message failed\n"); + hyper_send_type_block(sock, ERROR, 0); + return 0; + } + + close(pipe[0]); + close(pipe[1]); + fprintf(stdout, "pod init get ready message\n"); + + exec->pid = pid; + fprintf(stdout, "create exec cmd %s pid %d\n", exec->argv[0], pid); + + if (hyper_send_type_block(sock, ACK, 0) < 0) + return -1; + + return 0; + } + + close(pipe[0]); + sprintf(root, "/proc/%d/ns/mnt", container->exec.pid); + + fprintf(stdout, "container %s, init pid %d\n", + exec->id, container->exec.pid); + + fd = open(root, O_RDONLY); + if (fd < 0) { + perror("fail to open container mnt ns\n"); + goto fail; + } + + if (setns(fd, CLONE_NEWNS) < 0) { + perror("enter mnt ns failed"); + goto fail; + } + + close(fd); + + sprintf(root, "/tmp/hyper/%s/root/%s/", + container->id, container->rootfs); + + fprintf(stdout, "root directory for container is %s, exec %s\n", + root, exec->argv[0]); + + /* TODO: wait for container finishing setup root */ + if (chroot(root) < 0) { + perror("chroot for exec command failed"); + goto fail; + } + + chdir("/"); + + if (hyper_dup_exec_tty(pipe[1], exec)) { + fprintf(stderr, "dup pts to stdio failed\n"); + goto fail; + } + + close(pipe[1]); + if (execvp(exec->argv[0], exec->argv) < 0) + perror("exec failed"); + + _exit(-1); +fail: + hyper_send_type_block(pipe[1], ERROR, 0); + _exit(-1); +} + +int hyper_release_exec(struct hyper_exec *exec, + struct hyper_pod *pod) +{ + int i; + + close(exec->e.fd); + free(exec->pty); + + list_del_init(&exec->list); + + fprintf(stdout, "%s exit code %" PRIu8"\n", __func__, exec->code); + if (exec->init) { + fprintf(stdout, "%s container init exited, type %d, remains %d, policy %d\n", + __func__, pod->type, pod->remains, pod->policy); + + /* stop pod, should not restart container */ + if (pod->type == STOPPOD) + return 0; + + if (exec->code) + pod->code = exec->code; + + if (--pod->remains > 0) + return 0; + + /* should shutdown? */ + if (pod->policy == POLICY_NEVER || + ((pod->policy == POLICY_ONFAILURE) && pod->code == 0)) { + hyper_shutdown(pod); + return 0; + } + + if (hyper_request_restart_containers(pod) < 0) { + fprintf(stderr, "restart container failed\n"); + return -1; + } + + return 0; + } + + free(exec->id); + + for (i = 0; i < exec->argc; i++) { + fprintf(stdout, "argv %d %s\n", i, exec->argv[i]); + free(exec->argv[i]); + } + + free(exec->argv); + free(exec); + + return 0; +} + +struct hyper_exec *hyper_find_exec_by_pid(struct list_head *head, int pid) +{ + struct hyper_exec *exec; + + list_for_each_entry(exec, head, list) { + fprintf(stdout, "exec pid %d, pid %d\n", exec->pid, pid); + if (exec->pid != pid) + continue; + + return exec; + } + + return NULL; +} + +struct hyper_exec *hyper_find_exec_by_seq(struct hyper_pod *pod, uint64_t seq) +{ + struct hyper_exec *exec; + + list_for_each_entry(exec, &pod->ce_head, list) { + fprintf(stdout, "container exec seq %" PRIu64 ", seq %" PRIu64 "\n", + exec->seq, seq); + if (exec->seq != seq) + continue; + + return exec; + } + + list_for_each_entry(exec, &pod->pe_head, list) { + fprintf(stdout, "pod exec seq %" PRIu64 ", seq %" PRIu64 "\n", + exec->seq, seq); + if (exec->seq != seq) + continue; + + return exec; + } + + return NULL; +} + +int hyper_send_exec_eof(int to, struct hyper_pod *pod, + struct list_head *head, int pid, + uint8_t code) +{ + struct hyper_exec *exec; + uint8_t seq[12]; + + exec = hyper_find_exec_by_pid(head, pid); + if (exec == NULL) { + fprintf(stdout, "can not find exec whose pid is %d\n", + pid); + return 0; + } + + fprintf(stdout, "%s exec pid %d, seq %" PRIu64 ", container %s\n", + __func__, exec->pid, exec->seq, exec->id ? exec->id : "pod"); + + exec->code = code; + + if (exec->seq == 0) + goto out; + + hyper_set_be64(seq, exec->seq); + hyper_set_be32(seq + 8, 12); + if (hyper_send_data(to, seq, 12) < 0) { + fprintf(stderr, "pod signal_loop send finishcmd failed\n"); + return -1; + } +out: + hyper_release_exec(exec, pod); + + return 0; +} + +void hyper_cleanup_exec(struct hyper_pod *pod) +{ + struct hyper_exec *exec, *next; + + list_for_each_entry_safe(exec, next, &pod->ce_head, list) { + fprintf(stdout, "cleanup container exec seq %" PRIu64 "\n", exec->seq); + hyper_release_exec(exec, pod); + } +} diff --git a/src/exec.h b/src/exec.h new file mode 100644 index 0000000..ed9d60a --- /dev/null +++ b/src/exec.h @@ -0,0 +1,36 @@ +#ifndef _EXEC_H +#define _EXEC_H + +#include "list.h" +#include "event.h" + +struct hyper_exec { + struct list_head list; + struct hyper_event e; + char *id; + char *pty; + char **argv; + int argc; + uint64_t seq; + int pid; + int ptyno; + int init; + uint8_t code; +}; + +struct hyper_pod; + +int hyper_exec_cmd(char *json, int length); +int hyper_release_exec(struct hyper_exec *, struct hyper_pod *); +int hyper_container_execcmd(struct hyper_pod *pod); +int hyper_setup_exec_tty(struct hyper_exec *e); +int hyper_dup_exec_tty(int fd, struct hyper_exec *e); +struct hyper_exec *hyper_find_exec_by_pid(struct list_head *head, int pid); +struct hyper_exec *hyper_find_exec_by_seq(struct hyper_pod *pod, uint64_t seq); +int hyper_send_exec_eof(int to, struct hyper_pod *pod, + struct list_head *head, int pid, + uint8_t code); +void hyper_cleanup_exec(struct hyper_pod *pod); + +extern struct hyper_event_ops pts_ops; +#endif diff --git a/src/hyper.h b/src/hyper.h new file mode 100644 index 0000000..833dc5c --- /dev/null +++ b/src/hyper.h @@ -0,0 +1,80 @@ +#ifndef _DVM_H_ +#define _DVM_H_ + +#include + +#include "net.h" +#include "list.h" +#include "exec.h" +#include "event.h" +#include "container.h" + +enum { + SETDVM, + STARTPOD, + GETPOD, + STOPPOD, + DESTROYPOD, + RESTARTCONTAINER, + EXECCMD, + FINISHCMD, + READY, + ACK, + ERROR, + WINSIZE, + PING, + FINISH, +}; + +enum { + POLICY_NEVER, + POLICY_ALWAYS, + POLICY_ONFAILURE, +}; + +struct hyper_pod { + struct hyper_container *c; + struct hyper_interface *iface; + struct hyper_route *rt; + struct list_head pe_head; + struct list_head ce_head; + char *hostname; + char *tag; + char *channel; + int init_pid; + uint32_t c_num; + uint32_t i_num; + uint32_t r_num; + uint32_t e_num; + uint32_t type; + uint32_t code; + uint32_t remains; + uint8_t policy; + int efd; + struct hyper_event sig; + struct hyper_event ctl; +}; + +struct hyper_win_size { + char *tty; + int row; + int column; + uint64_t seq; +}; + +struct hyper_ctl { + int efd; + struct hyper_event sig; + struct hyper_event tty; + struct hyper_event chan; + struct hyper_event ctl; +}; + +int hyper_mkdir(char *hyper_path); +int hyper_open_serial(char *tty); +struct hyper_container *hyper_find_container(struct hyper_pod *pod, char *id); + +extern struct hyper_pod global_pod; +extern struct hyper_ctl ctl; +extern struct hyper_exec *global_exec; +#endif diff --git a/src/init.c b/src/init.c new file mode 100644 index 0000000..c2e7409 --- /dev/null +++ b/src/init.c @@ -0,0 +1,1025 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../config.h" +#include "hyper.h" +#include "net.h" +#include "util.h" +#include "exec.h" +#include "event.h" +#include "parse.h" +#include "container.h" + +struct hyper_pod global_pod = { + .ce_head = LIST_HEAD_INIT(global_pod.ce_head), + .pe_head = LIST_HEAD_INIT(global_pod.pe_head), +}; +struct hyper_exec *global_exec; + +#define MAXEVENTS 10 + +struct hyper_ctl ctl; + +static void hyper_cleanup_pod(struct hyper_pod *pod); +static int hyper_handle_exit(struct hyper_pod *pod, int to, + int container, int option); +static int hyper_event_read(struct hyper_event *de); +static int hyper_type_getlen(struct hyper_event *de, uint32_t *len); +static int hyper_seq_getlen(struct hyper_event *de, uint32_t *len); + +static int hyper_set_win_size(char *json, int length) +{ + struct hyper_win_size ws = { + .tty = NULL, + }; + struct winsize size; + struct hyper_exec *exec; + char *name, path[128]; + int fd, ret; + + fprintf(stdout, "call hyper_win_size, json %s, len %d\n", json, length); + if (hyper_parse_winsize(&ws, json, length) < 0) { + fprintf(stderr, "set term size failed\n"); + return -1; + } + + name = ws.tty; + if (!ws.tty) { + exec = hyper_find_exec_by_seq(&global_pod, ws.seq); + if (exec == NULL) { + fprintf(stdout, "can not find exec whose seq is %" PRIu64"\n", ws.seq); + return 0; + } + + fprintf(stdout, "find exec %s, pts %s, pid is %d, seq is %" PRIu64"\n", + exec->id ? exec->id : "pod", exec->pty, exec->pid, ws.seq); + name = exec->pty; + } else { + if (sprintf(path, "/dev/%s", ws.tty) < 0) { + fprintf(stderr, "get tty device failed\n"); + return -1; + } + name = path; + } + + fprintf(stdout, "try to open %s\n", name); + ret = hyper_open_serial_dev(name); + if (ret < 0) { + fprintf(stderr, "cannot open %s to set term size\n", name); + goto out; + } + + size.ws_row = ws.row; + size.ws_col = ws.column; + fd = ret; + + ret = ioctl(fd, TIOCSWINSZ, &size); + if (ret < 0) + fprintf(stderr, "cannot ioctl to set %s term size\n", name); + + close(fd); +out: + free(ws.tty); + return ret; +} + +static int pod_ctl_pipe_handle(struct hyper_event *de, uint32_t len) +{ + struct hyper_buf *buf = &de->buf; + struct hyper_pod *pod = de->ptr; + uint32_t type; + + fprintf(stdout, "%s\n", __func__); + + type = hyper_get_be32(buf->data); + + switch (type) { + case STOPPOD: + fprintf(stdout, "get type STOPPOD, exit\n"); + hyper_cleanup_pod(pod); + case RESTARTCONTAINER: + fprintf(stdout, "%s get type RESTARTCONTAINER\n", __func__); + if (hyper_restart_containers(pod) < 0) + return -1; + break; + case EXECCMD: + if (hyper_container_execcmd(pod) < 0) + return -1; + break; + default: + break; + } + + return 0; +} + +static int hyper_handle_exit(struct hyper_pod *pod, int to, + int container, int option) +{ + int pid, status; + /* pid + exit code */ + uint8_t data[5]; + + while ((pid = waitpid(-1, &status, option)) > 0) { + data[4] = 0; + + if (WIFEXITED(status)) { + data[4] = WEXITSTATUS(status); + fprintf(stdout, "pid %d exit normally, status %" PRIu8 "\n", + pid, data[4]); + + } else if (WIFSIGNALED(status)) { + fprintf(stdout, "pid %d exit by signal, status %d\n", + pid, WTERMSIG(status)); + } + + if (container) { + hyper_set_be32(data, pid); + if (hyper_send_msg(to, FINISHCMD, 5, data) < 0) { + fprintf(stderr, "pod signal_loop send finishcmd failed\n"); + return -1; + } + + continue; + } + + if (hyper_send_exec_eof(to, pod, &pod->pe_head, pid, data[4]) < 0) + fprintf(stderr, "signal_loop send eof failed\n"); + } + + if (option == WNOHANG) + return 0; + + /* send ack message to hyper init. */ + if (hyper_send_type(to, ACK) < 0) { + fprintf(stderr, "send ACK of STOPPOD to hyper init failed\n"); + return -1; + } + + return 0; +} + +static int signal_loop(struct hyper_event *de, int container) +{ + int size, to; + struct signalfd_siginfo sinfo; + struct hyper_pod *pod = de->ptr; + + to = de->to; + + fprintf(stdout, "%s write to %d\n", __func__, to); + + while (1) { + size = read(de->fd, &sinfo, sizeof(struct signalfd_siginfo)); + if (size <= 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + break; + + perror("fail to read signal fd"); + return -1; + } else if (size != sizeof(struct signalfd_siginfo)) { + perror("read signalfd siginfo failed"); + return -1; + } + + if (sinfo.ssi_signo != SIGCHLD) { + fprintf(stderr, "why give me signal %d?\n", sinfo.ssi_signo); + return 0; + } + + hyper_handle_exit(pod, to, container, WNOHANG); + } + + return 0; +} + +static int pod_signal_loop(struct hyper_event *de) +{ + return signal_loop(de, 1); +} + +static int hyper_signal_loop(struct hyper_event *de) +{ + return signal_loop(de, 0); +} + +static struct hyper_event_ops pod_ctl_pipe_ops = { + .read = hyper_event_read, + .getlen = hyper_type_getlen, + .handle = pod_ctl_pipe_handle, + .hup = hyper_event_hup, +}; + +static struct hyper_event_ops pod_signal_ops = { + .read = pod_signal_loop, + .hup = hyper_event_hup, +}; + +static int pod_init_loop(struct hyper_pod *pod) +{ + int i, n; + struct epoll_event *events; + + pod->efd = epoll_create1(EPOLL_CLOEXEC); + if (pod->efd < 0) { + perror("epoll_create failed"); + return -1; + } + + fprintf(stdout, "hyper_init_event pod ctl pipe event %p, ops %p, fd %d\n", + &pod->ctl, &pod_ctl_pipe_ops, pod->ctl.fd); + if (hyper_init_event(&pod->ctl, &pod_ctl_pipe_ops, 8, -1, pod) < 0 || + hyper_add_event(pod->efd, &pod->ctl) < 0) { + fprintf(stderr, "hyper add pod ctl pipe event failed\n"); + return -1; + } + + fprintf(stdout, "hyper_init_event pod signal event %p, ops %p, fd %d\n", + &pod->sig, &pod_signal_ops, pod->sig.fd); + if (hyper_init_event(&pod->sig, &pod_signal_ops, 0, pod->ctl.fd, pod) < 0 || + hyper_add_event(pod->efd, &pod->sig) < 0) { + fprintf(stderr, "hyper add pod tty pipe event failed\n"); + return -1; + } + + events = calloc(MAXEVENTS, sizeof(*events)); + + while (1) { + n = epoll_wait(pod->efd, events, MAXEVENTS, -1); + fprintf(stdout, "%s epoll_wait %d\n", __func__, n); + + if (n < 0) { + if (errno == EINTR) + continue; + perror("pod wait event failed"); + return -1; + } + + for (i = 0; i < n; i++) { + if (hyper_handle_event(pod->efd, &events[i]) < 0) + return -1; + } + } + + close(pod->efd); + return 0; +} + +struct hyper_pod_arg { + struct hyper_pod *pod; + int ctl_pipe[2]; +}; + +static int hyper_pod_init(void *data) +{ + struct hyper_pod_arg *arg = data; + struct hyper_pod *pod = arg->pod; + sigset_t mask; + + close(arg->ctl_pipe[0]); + close(ctl.sig.fd); + close(ctl.efd); + close(ctl.chan.fd); + close(ctl.tty.fd); + + pod->ctl.fd = arg->ctl_pipe[1]; + if (hyper_setfd_cloexec(pod->ctl.fd) < 0) { + perror("set pod init ctl pipe fd FD_CLOEXEC failed"); + goto fail; + } + + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { + perror("sigprocmask SIGCHLD failed"); + goto fail; + } + + pod->sig.fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC); + if (pod->sig.fd < 0) { + perror("create signalfd failed"); + goto fail; + } + + if (hyper_start_containers(pod) < 0) + goto fail; + + fprintf(stdout, "pod ctl_pipe %d\n", arg->ctl_pipe[1]); + if (hyper_send_type(arg->ctl_pipe[1], READY) < 0) { + fprintf(stderr, "container init send ready message failed\n"); + goto fail; + } +loop: + pod_init_loop(pod); + _exit(-1); + +fail: + hyper_send_type(arg->ctl_pipe[1], ERROR); + goto loop; +} + +static int hyper_ctl_pipe_handle(struct hyper_event *de, uint32_t len) +{ + struct hyper_buf *buf = &de->buf; + struct hyper_pod *pod = de->ptr; + uint32_t type, pid = 0; + uint8_t code; + + /* container exec finish message */ + fprintf(stdout, "%s\n", __func__); + + type = hyper_get_be32(buf->data); + + switch (type) { + case ACK: + /* ACK only being sent on stoppod, in this case, ctl pipe + * fd is block, and ACK is the last message, exit loop. */ + fprintf(stdout, "hyper_ctl_pipe_loop get ack\n"); + return 1; + case FINISHCMD: + pid = hyper_get_be32(buf->data + 8); + code = buf->data[12]; + if (hyper_send_exec_eof(de->to, pod, &pod->ce_head, pid, code) < 0) { + fprintf(stderr, "hyper_ctl_pipe_loop send eof failed\n"); + return -1; + } + break; + default: + fprintf(stdout, "get unknown type %" PRIu32"\n", type); + break; + } + + return 0; +} + +static int hyper_setup_pty(struct hyper_pod *pod) +{ + int i; + char root[512]; + struct hyper_container *c; + + for (i = 0; i < pod->c_num; i++) { + c = &pod->c[i]; + + sprintf(root, "/tmp/hyper/%s/devpts/", c->id); + + if (hyper_mkdir(root) < 0) { + perror("make container pts directroy failed"); + return -1; + } + + if (mount("devpts", root, "devpts", MS_NOSUID, + "newinstance,ptmxmode=0666,mode=0620") < 0) { + perror("mount devpts failed"); + return -1; + } + + list_add_tail(&c->exec.list, &pod->ce_head); + + if (hyper_setup_exec_tty(&c->exec) < 0) { + fprintf(stderr, "setup container pts failed\n"); + return -1; + } + } + + return 0; +} + +static int hyper_watch_pty(struct hyper_pod *pod) +{ + int i; + struct hyper_container *c; + + for (i = 0; i < pod->c_num; i++) { + c = &pod->c[i]; + + fprintf(stdout, "hyper_init_event container pts event %p, ops %p, fd %d\n", + &c->exec.e, &pts_ops, c->exec.e.fd); + if (hyper_init_event(&c->exec.e, &pts_ops, 0, ctl.tty.fd, NULL) < 0 || + hyper_add_event(ctl.efd, &c->exec.e) < 0) { + fprintf(stderr, "add container pts master event failed\n"); + return -1; + } + } + + return 0; +} + +static struct hyper_event_ops hyper_ctl_pipe_ops = { + .read = hyper_event_read, + .getlen = hyper_type_getlen, + .handle = hyper_ctl_pipe_handle, + .hup = hyper_event_hup, +}; + +static int hyper_setup_container(struct hyper_pod *pod) +{ + int stacksize = getpagesize() * 4; + int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | + CLONE_NEWUTS | CLONE_VM | SIGCHLD; + + struct hyper_pod_arg arg = { + .pod = NULL, + .ctl_pipe = {-1, -1}, + }; + + uint32_t type; + void *stack; + + if (hyper_setup_pty(pod) < 0) { + fprintf(stderr, "setup pty failed\n"); + return -1; + } + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, arg.ctl_pipe) < 0) { + perror("create pipe between hyper init and pod init failed"); + return -1; + } + + stack = malloc(stacksize); + if (stack == NULL) { + perror("fail to allocate stack for container init"); + return -1; + } + + arg.pod = pod; + + pod->init_pid = clone(hyper_pod_init, stack + stacksize, flags, &arg); + free(stack); + if (pod->init_pid < 0) { + perror("create container init process failed"); + return -1; + } + + close(arg.ctl_pipe[1]); + ctl.ctl.fd = arg.ctl_pipe[0]; + fprintf(stdout, "pod init pid %d\n", pod->init_pid); + + /* Wait for container start */ + if (hyper_get_type_block(ctl.ctl.fd, &type) < 0) { + perror("get container init ready message failed"); + return -1; + } + + if (type != READY) { + fprintf(stderr, "get incorrect message type %d, expect READY\n", type); + return -1; + } + + if (hyper_watch_pty(pod) < 0) { + fprintf(stderr, "watch pty failed\n"); + return -1; + } + + if (hyper_setfd_cloexec(ctl.ctl.fd) < 0) { + perror("set ctl pipe fd FD_CLOEXEC failed"); + return -1; + } + + fprintf(stdout, "hyper_init_event hyper ctl pipe fd %d\n", ctl.ctl.fd); + if (hyper_init_event(&ctl.ctl, &hyper_ctl_pipe_ops, 256, ctl.tty.fd, pod) < 0 || + hyper_add_event(ctl.efd, &ctl.ctl) < 0) { + return -1; + } + + return 0; +} + +static int hyper_setup_shared(struct hyper_pod *pod) +{ + if (pod->tag == NULL) { + fprintf(stdout, "no shared directroy\n"); + return 0; + } + + if (hyper_mkdir("/tmp/hyper/shared") < 0) { + perror("fail to create /tmp/hyper/shared"); + return -1; + } + + if (mount(pod->tag, "/tmp/hyper/shared", "9p", MS_MGC_VAL, "trans=virtio") < 0) { + perror("fail to mount 9p shared dir"); + return -1; + } + + return 0; +} + +static int hyper_setup_pod(struct hyper_pod *pod) +{ + /* create tmp proc directroy */ + if (hyper_mkdir("/tmp/hyper/proc") < 0) { + perror("create tmp proc failed"); + return -1; + } + + if (hyper_setup_network(pod) < 0) { + fprintf(stderr, "setup network failed\n"); + return -1; + } + + if (hyper_setup_shared(pod) < 0) { + fprintf(stderr, "setup shared directory failed\n"); + return -1; + } + + if (hyper_setup_container(pod) < 0) { + fprintf(stderr, "start container failed\n"); + return -1; + } + + return 0; +} + +static void hyper_print_uptime(void) +{ + char buf[128]; + int fd = open("/proc/uptime", O_RDONLY); + + if (fd < 0) + return; + memset(buf, 0, sizeof(buf)); + if (read(fd, buf, sizeof(buf))) + fprintf(stdout, "uptime %s\n", buf); + + close(fd); +} + +static void hyper_cleanup_pod(struct hyper_pod *pod) +{ + close(pod->sig.fd); + hyper_reset_event(&pod->sig); + + hyper_kill_all(); + hyper_handle_exit(pod, pod->ctl.fd, 1, 0); + + pod->init_pid = 0; + + close(pod->ctl.fd); + hyper_reset_event(&pod->ctl); + + hyper_unmount_all(); + + _exit(0); +} + +static int hyper_start_pod(char *json, int length) +{ + struct hyper_pod *pod = &global_pod; + + fprintf(stdout, "call hyper_start_pod, json %s, len %d\n", json, length); + + if (pod->init_pid) + fprintf(stdout, "pod init_pid exist %d\n", pod->init_pid); + + if (hyper_parse_pod(pod, json, length) < 0) { + fprintf(stderr, "parse pod json failed\n"); + return -1; + } + + if (hyper_setup_pod(pod) < 0) { + hyper_shutdown(pod); + return -1; + } + + return 0; +} + +static void hyper_cleanup_shared(struct hyper_pod *pod) +{ + if (pod->tag == NULL) { + fprintf(stdout, "no shared directroy\n"); + return; + } + + free(pod->tag); + if (umount("/tmp/hyper/shared") < 0 && + umount2("/tmp/hyper/shared", MNT_DETACH)) { + perror("fail to umount 9p dir"); + return; + } + + if (rmdir("/tmp/hyper/shared") < 0) + perror("fail to delete /tmp/hyper/shared"); +} + +static int hyper_send_stoppod(int fd) +{ + if (hyper_setfd_block(fd) < 0) { + perror("set fd BLOCK failed"); + return -1; + } + + if (hyper_send_type(fd, STOPPOD) < 0) { + fprintf(stderr, "send STOPPOD message failed\n"); + return -1; + } + + hyper_event_read(&ctl.ctl); + + return 0; +} + +static int hyper_stop_pod(struct hyper_pod *pod) +{ + fprintf(stdout, "hyper_stop_pod init_pid %d\n", pod->init_pid); + if (pod->init_pid == 0) { + fprintf(stdout, "container init pid is already exit\n"); + return 0; + } + + /* Make hyper ctl_pipe blocked */ + hyper_send_stoppod(ctl.ctl.fd); + + hyper_cleanup_exec(pod); + hyper_cleanup_container(pod); + hyper_cleanup_network(pod); + hyper_cleanup_shared(pod); + + free(pod->channel); + free(pod->hostname); + + sync(); + /* Wait for pod init ack */ + close(ctl.ctl.fd); + hyper_reset_event(&ctl.ctl); + return 0; +} + +static int hyper_setup_channel(char *name) +{ + int ret = hyper_open_channel(name, 0); + + if (ret < 0) + return ret; + + fprintf(stdout, "send ready message\n"); + if (hyper_send_type(ret, READY) < 0) { + perror("send READY MESSAGE failed\n"); + goto out; + } + + if (hyper_setfd_nonblock(ret) < 0) { + perror("set hyper channel O_NONBLOCK failed"); + goto out; + } + + return ret; +out: + close(ret); + return -1; +} + +static int hyper_ttyfd_handle(struct hyper_event *de, uint32_t len) +{ + struct hyper_buf *buf = &de->buf; + struct hyper_pod *pod = de->ptr; + struct hyper_exec *exec; + uint64_t seq = 0; + + fprintf(stdout, "%s\n", __func__); + + seq = hyper_get_be64(buf->data); + + exec = hyper_find_exec_by_seq(pod, seq); + if (exec == NULL) { + uint8_t data[12]; + + fprintf(stderr, "can't find exec whose seq is %" PRIu64 "\n", seq); + + /* goodbye */ + hyper_set_be64(data, seq); + hyper_set_be32(data + 8, 12); + hyper_send_data(de->fd, data, 12); + + return 0; + } + + fprintf(stdout, "find exec %s pid %d, seq is %" PRIu64 "\n", + exec->id ? exec->id : "pod", exec->pid, exec->seq); + + if (hyper_send_data(exec->e.fd, buf->data + 12, len - 12) < 0) { + fprintf(stderr, "send data to exec tty failed\n"); + return -1; + } + + return 0; +} + +static int hyper_channel_handle(struct hyper_event *de, uint32_t len) +{ + struct hyper_buf *buf = &de->buf; + struct hyper_pod *pod = de->ptr; + uint32_t type = 0; + int i, ret = 0; + + for (i = 0; i < buf->get; i++) + fprintf(stdout, "%0x ", buf->data[i]); + + type = hyper_get_be32(buf->data); + + fprintf(stdout, "\n %s, type %" PRIu32 ", len %" PRIu32 "\n", + __func__, type, len); + + pod->type = type; + switch (type) { + case STARTPOD: + ret = hyper_start_pod((char *)buf->data + 8, len - 8); + hyper_print_uptime(); + break; + case STOPPOD: + ret = hyper_stop_pod(pod); + break; + case DESTROYPOD: + fprintf(stdout, "get DESTROYPOD message\n"); + hyper_shutdown(pod); + return 0; + case EXECCMD: + ret = hyper_exec_cmd((char *)buf->data + 8, len - 8); + break; + case PING: + case GETPOD: + break; + case READY: + ret = hyper_rescan(); + break; + case WINSIZE: + ret = hyper_set_win_size((char *)buf->data + 8, len - 8); + break; + default: + ret = -1; + break; + } + + if (ret < 0) + hyper_send_type(de->fd, ERROR); + else + hyper_send_type(de->fd, ACK); + + return 0; +} + +static int hyper_type_getlen(struct hyper_event *de, uint32_t *len) +{ + struct hyper_buf *buf = &de->buf; + + if (buf->get < 8) + return -1; + + *len = hyper_get_be32(buf->data + 4); + + return 0; +} + +static int hyper_seq_getlen(struct hyper_event *de, uint32_t *len) +{ + struct hyper_buf *buf = &de->buf; + + if (buf->get < 12) + return -1; + + *len = hyper_get_be32(buf->data + 8); + + return 0; +} + +static int hyper_event_read(struct hyper_event *de) +{ + struct hyper_buf *buf = &de->buf; + uint32_t len = 0; + int size; + + fprintf(stdout, "%s\n", __func__); + + if (de->ops->getlen(de, &len) == 0) { + fprintf(stdout, "get length %" PRIu32"\n", len); + goto again; + } + + while (1) { + size = read(de->fd, buf->data + buf->get, buf->size - buf->get); + if (size < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + return 0; + perror("fail to read"); + break; + } else if (size == 0) { + /* No one connect to qemu socket */ + return 0; + } + + fprintf(stdout, "read %d bytes data, total data %" PRIu32 "\n", + size, buf->get); + buf->get += size; +again: + if (len == 0) { + if (de->ops->getlen(de, &len) < 0) { + /* Need type & length fields */ + continue; + } + + fprintf(stdout, "get length %" PRIu32"\n", len); + if (len > buf->size || len == 0) { + fprintf(stderr, "message incorrect\n"); + break; + } + } + + /* check if get the whole data */ + if (buf->get >= len) { + if (de->ops->handle(de, len) != 0) + break; + + /* len: length of the already get new data */ + buf->get -= len; + memmove(buf->data, buf->data + len, buf->get); + len = 0; + + goto again; + } + } + + return -1; +} + +static struct hyper_event_ops hyper_channel_ops = { + .read = hyper_event_read, + .getlen = hyper_type_getlen, + .handle = hyper_channel_handle, +}; + +static struct hyper_event_ops hyper_ttyfd_ops = { + .read = hyper_event_read, + .getlen = hyper_seq_getlen, + .handle = hyper_ttyfd_handle, +}; + +static struct hyper_event_ops hyper_signal_ops = { + .read = hyper_signal_loop, + .hup = hyper_event_hup, +}; + +static int hyper_loop(void) +{ + int i, n; + struct epoll_event *events; + struct hyper_pod *pod = &global_pod; + + ctl.efd = epoll_create1(EPOLL_CLOEXEC); + if (ctl.efd < 0) { + perror("epoll_create failed"); + return -1; + } + + fprintf(stdout, "hyper_init_event hyper channel event %p, ops %p, fd %d\n", + &ctl.chan, &hyper_channel_ops, ctl.chan.fd); + if (hyper_init_event(&ctl.chan, &hyper_channel_ops, 4096, -1, pod) < 0 || + hyper_add_event(ctl.efd, &ctl.chan) < 0) { + return -1; + } + + fprintf(stdout, "hyper_init_event hyper ttyfd event %p, ops %p, fd %d\n", + &ctl.tty, &hyper_ttyfd_ops, ctl.tty.fd); + if (hyper_init_event(&ctl.tty, &hyper_ttyfd_ops, 4096, -1, pod) < 0 || + hyper_add_event(ctl.efd, &ctl.tty) < 0) { + return -1; + } + + fprintf(stdout, "hyper_init_event hyper signal event %p, ops %p, fd %d\n", + &ctl.sig, &hyper_signal_ops, ctl.sig.fd); + if (hyper_init_event(&ctl.sig, &hyper_signal_ops, 0, ctl.tty.fd, pod) < 0 || + hyper_add_event(ctl.efd, &ctl.sig) < 0) { + return -1; + } + + events = calloc(MAXEVENTS, sizeof(*events)); + + while (1) { + n = epoll_wait(ctl.efd, events, MAXEVENTS, -1); + fprintf(stdout, "%s epoll_wait %d\n", __func__, n); + + if (n < 0) { + if (errno == EINTR) + continue; + perror("hyper wait event failed"); + return -1; + } + for (i = 0; i < n; i++) { + if (hyper_handle_event(ctl.efd, &events[i]) < 0) + return -1; + } + } + + free(events); + close(ctl.efd); + return 0; +} + +int main(int argc, char *argv[]) +{ + char *cmdline; + sigset_t mask; + + if (hyper_mkdir("/dev") < 0 || + hyper_mkdir("/sys") < 0 || + hyper_mkdir("/proc") < 0) { + perror("create basic directroy failed"); + return -1; + } + + if (mount("proc", "/proc", "proc", 0, NULL) == -1) { + perror("mount proc failed"); + return -1; + } + + hyper_print_uptime(); + + if (mount("sysfs", "/sys", "sysfs", 0, NULL) == -1) { + perror("mount sysfs failed"); + return -1; + } + + if (mount("dev", "/dev", "devtmpfs", 0, NULL) == -1) { + perror("mount sysfs failed"); + return -1; + } + + if (hyper_mkdir("/dev/pts") < 0) { + perror("create basic directroy failed"); + return -1; + } + + if (mount("devpts", "/dev/pts", "devpts", 0, NULL) == -1) { + perror("mount devpts failed"); + return -1; + } + + cmdline = read_cmdline(); + + setsid(); + + ioctl(STDIN_FILENO, TIOCSCTTY, 1); + + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { + perror("sigprocmask SIGCHLD failed"); + return -1; + } + + ctl.sig.fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC); + if (ctl.sig.fd < 0) { + perror("create signalfd failed"); + return -1; + } + + setenv("PATH", "/bin:/sbin/:/usr/bin/:/usr/sbin/", 1); + + ctl.chan.fd = hyper_setup_channel("sh.hyper.channel.0"); + if (ctl.chan.fd < 0) { + fprintf(stderr, "fail to setup hyper virtio serial port\n"); + goto out1; + } + + ctl.tty.fd = hyper_open_channel("sh.hyper.channel.1", O_NONBLOCK); + if (ctl.tty.fd < 0) { + fprintf(stderr, "fail to setup hyper virtio serial port\n"); + goto out2; + } + + hyper_loop(); + + close(ctl.tty.fd); +out2: + close(ctl.chan.fd); +out1: + close(ctl.sig.fd); + + free(cmdline); + + return 0; +} diff --git a/src/jsmn.c b/src/jsmn.c new file mode 100644 index 0000000..b1c3ebb --- /dev/null +++ b/src/jsmn.c @@ -0,0 +1,321 @@ +#include + +#include "jsmn.h" + +/** + * Allocates a fresh unused token from the token pull. + */ +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, + jsmntok_t *tokens, + size_t num_tokens) +{ + jsmntok_t *tok; + + if (parser->toknext >= num_tokens) + return NULL; + + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + return tok; +} + +/** + * Fills token type and boundaries. + */ +static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, + int start, int end) +{ + token->type = type; + token->start = start; + token->end = end; + token->size = 0; +} + +/** + * Fills next available token with JSON primitive. + */ +static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, + size_t num_tokens) { + jsmntok_t *token; + int start; + + start = parser->pos; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + case '\t': case '\r': case '\n': case ' ': + case ',': case ']': case '}': + goto found; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** + * Filsl next token with JSON string. + */ +static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, + size_t num_tokens) +{ + jsmntok_t *token; + int start = parser->pos; + + parser->pos++; + + /* Skip starting quote */ + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) + return 0; + + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': case '/': case '\\': case 'b': + case 'f': case 'r': case 'n': case 't': + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { + /* If it isn't a hex character we have an error */ + if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; +} + +/** + * Parse JSON string and fill tokens. + */ +jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens) +{ + jsmnerr_t r; + int i; + jsmntok_t *token; + int count = 0; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; + + c = js[parser->pos]; + switch (c) { + case '{': case '[': + count++; + if (tokens == NULL) + break; + + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + return JSMN_ERROR_NOMEM; + if (parser->toksuper != -1) { + tokens[parser->toksuper].size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': case ']': + if (tokens == NULL) + break; + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + if (parser->toknext < 1) + return JSMN_ERROR_INVAL; + + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) + return JSMN_ERROR_INVAL; + + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) + break; + + token = &tokens[token->parent]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) + return JSMN_ERROR_INVAL; + + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) + return JSMN_ERROR_INVAL; + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) + return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + case '\t': case '\r': case '\n': case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 't': case 'f': case 'n': + /* And they must not be keys of the object */ + if (tokens != NULL) { + jsmntok_t *t = &tokens[parser->toksuper]; + + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) + return JSMN_ERROR_INVAL; + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) + return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) + return JSMN_ERROR_PART; + } + + return count; +} + +/** + * Creates a new parser based over a given buffer with an array of tokens + * available. + */ +void jsmn_init(jsmn_parser *parser) +{ + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; +} diff --git a/src/jsmn.h b/src/jsmn.h new file mode 100644 index 0000000..13c7835 --- /dev/null +++ b/src/jsmn.h @@ -0,0 +1,67 @@ +#ifndef __JSMN_H_ +#define __JSMN_H_ + +#include + +/** + * JSON type identifier. Basic types are: + * o Object + * o Array + * o String + * o Other primitive: number, boolean (true/false) or null + */ +typedef enum { + JSMN_PRIMITIVE = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3 +} jsmntype_t; + +typedef enum { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 +} jsmnerr_t; + +/** + * JSON token description. + * @param type type (object, array, string etc.) + * @param start start position in JSON data string + * @param end end position in JSON data string + */ +typedef struct { + jsmntype_t type; + int start; + int end; + int size; +#ifdef JSMN_PARENT_LINKS + int parent; +#endif +} jsmntok_t; + +/** + * JSON parser. Contains an array of token blocks available. Also stores + * the string being parsed now and current position in that string + */ +typedef struct { + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g parent object or array */ +} jsmn_parser; + +/** + * Create JSON parser over an array of tokens + */ +void jsmn_init(jsmn_parser *parser); + +/** + * Run JSON parser. It parses a JSON data string into and array of tokens, each describing + * a single JSON object. + */ +jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens); + +#endif /* __JSMN_H_ */ diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..17b316a --- /dev/null +++ b/src/list.h @@ -0,0 +1,191 @@ +#ifndef _LIST_H_ +#define _LIST_H_ + +#include + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof(((type *)0)->member) * __mptr = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + list_del(entry); + INIT_LIST_HEAD(entry); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +/** + * list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) +#endif diff --git a/src/net.c b/src/net.c new file mode 100644 index 0000000..7cc6de2 --- /dev/null +++ b/src/net.c @@ -0,0 +1,793 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hyper.h" + +void hyper_set_be32(uint8_t *buf, uint32_t val) +{ + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; +} + +uint32_t hyper_get_be32(uint8_t *buf) +{ + return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; +} + +void hyper_set_be64(uint8_t *buf, uint64_t val) +{ + hyper_set_be32(buf, val >> 32); + hyper_set_be32(buf + 4, val); +} + +uint64_t hyper_get_be64(uint8_t *buf) +{ + uint64_t v; + + v = (uint64_t) hyper_get_be32(buf) << 32; + v |= hyper_get_be32(buf + 4); + return v; +} + +int hyper_send_data(int fd, uint8_t *data, uint32_t len) +{ + int length = 0, size; + + while (length < len) { + size = write(fd, data + length, len - length); + + if (size <= 0) { + if (errno == EINTR) + continue; + /* EAGAIN means unblock and the peer of virtio-ports is disappear */ + if (errno == EAGAIN) + return 0; + + perror("send hyper data failed"); + return -1; + } + + length += size; + } + + return 0; +} + +int hyper_send_msg(int fd, uint32_t type, uint32_t len, + uint8_t *message) +{ + uint8_t buf[8]; + + fprintf(stdout, "hyper send type %d, len %d\n", type, len); + + hyper_set_be32(buf, type); + hyper_set_be32(buf + 4, len + 8); + + if (hyper_send_data(fd, buf, 8) < 0) + return -1; + + if (message && hyper_send_data(fd, message, len) < 0) + return -1; + + return 0; +} + +int hyper_send_type(int fd, uint32_t type) +{ + return hyper_send_msg(fd, type, 0, NULL); +} + +int hyper_get_type_block(int fd, uint32_t *type) +{ + int len = 0, size; + uint8_t buf[8]; + + while (len < 8) { + size = read(fd, buf + len, 8 - len); + + if (size <= 0) { + if (errno == EINTR) + continue; + perror("wait for ack failed"); + return -1; + } + len += size; + } + + *type = hyper_get_be32(buf); + return 0; +} + +int hyper_send_type_block(int fd, uint32_t type, int need_ack) +{ + int ret = 0, flags; + uint32_t t; + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) { + fprintf(stderr, "get fd flag failed\n"); + return -1; + } + + if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0) { + perror("set fd BLOCK failed"); + return -1; + } + + ret = hyper_send_msg(fd, type, 0, NULL); + if (ret < 0) + goto out; + + if (need_ack == 0) + goto out; + + ret = hyper_get_type_block(fd, &t); + if (ret < 0) { + fprintf(stderr, "can not get type\n"); + goto out; + } + + fprintf(stdout, "get type %" PRIu32"\n", type); + + if (t != ACK) + ret = -1; +out: + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("set fd BLOCK failed"); + return -1; + } + + return ret; +} + +static int get_addr_ipv4(uint8_t *ap, const char *cp) +{ + int i; + + for (i = 0; i < 4; i++) { + unsigned long n; + char *endp; + + n = strtoul(cp, &endp, 0); + if (n > 255) + return -1; /* bogus network value */ + + if (endp == cp) /* no digits */ + return -1; + ap[i] = n; + + if (*endp == '\0') + break; + + if (i == 3 || *endp != '.') + return -1; /* extra characters */ + + cp = endp + 1; + } + + return 1; +} + +static int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) + return -1; + rta = (struct rtattr *)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; + return 0; +} + +static int hyper_get_ifindex(char *nic) +{ + int fd, ifindex = -1; + char path[512], buf[4]; + + fprintf(stdout, "net device %s\n", nic); + sprintf(path, "/sys/class/net/%s/ifindex", nic); + fprintf(stdout, "net device sys path is %s\n", path); + + fd = open(path, O_RDONLY); + if (fd < 0) { + perror("can not open file"); + return -1; + } + + memset(buf, 0, sizeof(buf)); + if (read(fd, buf, sizeof(buf)) <= 0) { + perror("can read open file"); + goto out; + } + + ifindex = atoi(buf); + fprintf(stdout, "get ifindex %d\n", ifindex); +out: + close(fd); + return ifindex; +} + +static int netlink_open(struct rtnl_handle *rth) +{ + memset(rth, 0, sizeof(*rth)); + + rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (rth->fd < 0) { + perror("cannot open netlink socket"); + return -1; + } + + rth->local.nl_family = AF_NETLINK; + rth->local.nl_groups = 0; + + if (bind(rth->fd, (struct sockaddr *)&rth->local, sizeof(rth->local)) < 0) { + perror("cannot bind netlink socket"); + goto out; + } + + rth->seq = 0; + return 0; +out: + close(rth->fd); + return -1; +} + +static void netlink_close(struct rtnl_handle *rth) +{ + if (rth->fd > 0) + close(rth->fd); + rth->fd = -1; +} + +static int rtnl_talk(struct rtnl_handle *rtnl, + struct nlmsghdr *n, pid_t peer, + unsigned groups, struct nlmsghdr *answer) +{ + int status; + struct sockaddr_nl nladdr; + struct iovec iov = { (void *)n, n->nlmsg_len }; + struct msghdr msg = { (void *)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = peer; + nladdr.nl_groups = groups; + n->nlmsg_seq = ++rtnl->seq; + if (answer == NULL) + n->nlmsg_flags |= NLM_F_ACK; + + status = sendmsg(rtnl->fd, &msg, 0); + if (status < 0) + return -1; + + return 0; +} + +static int hyper_up_nic(struct rtnl_handle *rth, int ifindex) +{ + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; + } req; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = AF_UNSPEC; + req.i.ifi_change |= IFF_UP; + req.i.ifi_flags |= IFF_UP; + req.i.ifi_index = ifindex; + + if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) + return -1; + + return 0; +} + +static int hyper_remove_nic(char *device) +{ + char path[256], real[128]; + int fd; + + sprintf(path, "/sys/class/net/%s", device); + + if (readlink(path, real, 128) < 0) { + perror("fail to read link directory"); + return -1; + } + + sprintf(path, "/sys/%s/../../../remove", real + 5); + + fprintf(stdout, "get net sys path %s\n", path); + + fd = open(path, O_WRONLY); + if (fd < 0) { + perror("open file failed"); + return -1; + } + + if (write(fd, "1\n", 2) < 0) { + perror("write 1 to file failed"); + close(fd); + return 1; + } + + close(fd); + return 0; +} + +static int hyper_down_nic(struct rtnl_handle *rth, int ifindex) +{ + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; + } req; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = AF_UNSPEC; + req.i.ifi_change |= IFF_UP; + req.i.ifi_flags &= ~IFF_UP; + req.i.ifi_index = ifindex; + + if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) + return -1; + + return 0; +} + +static int mask2bits(uint32_t netmask) +{ + unsigned bits = 0; + uint32_t mask = ntohl(netmask); + uint32_t host = ~mask; + + /* a valid netmask must be 2^n - 1 */ + if ((host & (host + 1)) != 0) + return -1; + + for (; mask; mask <<= 1) + ++bits; + + return bits; +} + +static int get_netmask(unsigned *val, const char *addr) +{ + char *ptr; + unsigned long res; + uint32_t data; + int b; + + res = strtoul(addr, &ptr, 0); + + if (!ptr || ptr == addr || *ptr) + goto get_addr; + + if (res == ULONG_MAX && errno == ERANGE) + goto get_addr; + + if (res > UINT_MAX) + goto get_addr; + + *val = res; + return 0; + +get_addr: + if (get_addr_ipv4((uint8_t *)&data, addr) <= 0) + return -1; + + b = mask2bits(data); + if (b < 0) + return -1; + + *val = b; + return 0; +} + +static int hyper_setup_route(struct rtnl_handle *rth, + struct hyper_route *rt) +{ + uint32_t data; + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + + if (!rt->dst) { + fprintf(stderr, "route dest is null\n"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST; + req.n.nlmsg_type = RTM_NEWROUTE; + + req.r.rtm_family = AF_INET; + req.r.rtm_table = RT_TABLE_MAIN; + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + req.r.rtm_type = RTN_UNICAST; + req.r.rtm_protocol = RTPROT_BOOT; + req.r.rtm_dst_len = 0; + + if (rt->gw) { + if (get_addr_ipv4((uint8_t *)&data, rt->gw) <= 0) { + fprintf(stderr, "get gw failed\n"); + return -1; + } + + if (addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &data, 4)) { + fprintf(stderr, "setup gateway attr failed\n"); + return -1; + } + } + + if (rt->device) { + rt->ifindex = hyper_get_ifindex(rt->device); + if (addattr_l(&req.n, sizeof(req), RTA_OIF, &rt->ifindex, 4)) { + fprintf(stderr, "setup oif attr failed\n"); + return -1; + } + } + + if (strcmp(rt->dst, "default") && strcmp(rt->dst, "any") && strcmp(rt->dst, "all")) { + unsigned mask; + char *slash = strchr(rt->dst, '/'); + + req.r.rtm_dst_len = 32; + + if (slash) + *slash = 0; + + if (get_addr_ipv4((uint8_t *)&data, rt->dst) <= 0) { + fprintf(stderr, "get dst failed\n"); + return -1; + } + + if (addattr_l(&req.n, sizeof(req), RTA_DST, &data, 4)) { + fprintf(stderr, "setup gateway attr failed\n"); + return -1; + } + + if (slash) { + if (get_netmask(&mask, slash + 1) < 0) { + fprintf(stderr, "get netmask failed\n"); + return -1; + } + req.r.rtm_dst_len = mask; + *slash = '/'; + } + } + + if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) { + fprintf(stderr, "rtnl talk failed\n"); + return -1; + } + + return 0; +} + +static int hyper_cleanup_route(struct rtnl_handle *rth, struct hyper_route *rt) +{ + uint32_t data; + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + + if (!rt->dst) { + fprintf(stderr, "route dest is null\n"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_DELROUTE; + + req.r.rtm_family = AF_INET; + req.r.rtm_table = RT_TABLE_MAIN; + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + req.r.rtm_type = RTN_UNICAST; + req.r.rtm_protocol = RTPROT_BOOT; + req.r.rtm_dst_len = 0; + + if (rt->gw) { + if (get_addr_ipv4((uint8_t *)&data, rt->gw) <= 0) { + fprintf(stderr, "get gw failed\n"); + return -1; + } + + if (addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &data, 4)) { + fprintf(stderr, "setup gateway attr failed\n"); + return -1; + } + } + + if (rt->device) { + if (addattr_l(&req.n, sizeof(req), RTA_OIF, &rt->ifindex, 4)) { + fprintf(stderr, "setup oif attr failed\n"); + return -1; + } + } + + if (strcmp(rt->dst, "default") && strcmp(rt->dst, "any") && strcmp(rt->dst, "all")) { + unsigned mask; + char *slash = strchr(rt->dst, '/'); + + req.r.rtm_dst_len = 32; + + if (slash) + *slash = 0; + + if (get_addr_ipv4((uint8_t *)&data, rt->dst) <= 0) { + fprintf(stderr, "get dst failed\n"); + return -1; + } + + if (addattr_l(&req.n, sizeof(req), RTA_DST, &data, 4)) { + fprintf(stderr, "setup gateway attr failed\n"); + return -1; + } + + if (slash) { + if (get_netmask(&mask, slash + 1) < 0) { + fprintf(stderr, "get netmask failed\n"); + return -1; + } + req.r.rtm_dst_len = mask; + *slash = '/'; + } + } + + if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) { + fprintf(stderr, "rtnl talk failed\n"); + return -1; + } + + return 0; +} + +static int hyper_setup_interface(struct rtnl_handle *rth, + struct hyper_interface *iface) +{ + uint8_t data[4]; + unsigned mask; + struct { + struct nlmsghdr n; + struct ifaddrmsg ifa; + char buf[256]; + } req; + + if (!(iface->device && iface->ipaddr && iface->mask)) { + fprintf(stderr, "interface information incorrect\n"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; + req.n.nlmsg_type = RTM_NEWADDR; + req.ifa.ifa_family = AF_INET; + + iface->ifindex = hyper_get_ifindex(iface->device); + req.ifa.ifa_index = iface->ifindex; + req.ifa.ifa_scope = 0; + + if (get_addr_ipv4((uint8_t *)&data, iface->ipaddr) <= 0) { + fprintf(stderr, "get addr failed\n"); + return -1; + } + + if (addattr_l(&req.n, sizeof(req), IFA_LOCAL, &data, 4)) { + fprintf(stderr, "setup attr failed\n"); + return -1; + } + + if (get_netmask(&mask, iface->mask) < 0) { + fprintf(stderr, "get netamsk failed\n"); + return -1; + } + + req.ifa.ifa_prefixlen = mask; + fprintf(stdout, "interface get netamsk %d %s\n", req.ifa.ifa_prefixlen, iface->mask); + if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) { + perror("rtnl_talk failed"); + return -1; + } + + if (hyper_up_nic(rth, iface->ifindex) < 0) { + fprintf(stderr, "up device %d failed\n", iface->ifindex); + return -1; + } + + return 0; +} + +static int hyper_cleanup_interface(struct rtnl_handle *rth, + struct hyper_interface *iface) +{ + uint8_t data[4]; + unsigned mask; + struct { + struct nlmsghdr n; + struct ifaddrmsg ifa; + char buf[256]; + } req; + + if (!(iface->device && iface->ipaddr && iface->mask)) { + fprintf(stderr, "interface information incorrect\n"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_DELADDR; + req.ifa.ifa_family = AF_INET; + + req.ifa.ifa_index = iface->ifindex; + req.ifa.ifa_scope = 0; + + if (get_addr_ipv4((uint8_t *)&data, iface->ipaddr) <= 0) { + fprintf(stderr, "get addr failed\n"); + return -1; + } + + if (addattr_l(&req.n, sizeof(req), IFA_LOCAL, &data, 4)) { + fprintf(stderr, "setup attr failed\n"); + return -1; + } + + if (get_netmask(&mask, iface->mask) < 0) { + fprintf(stderr, "get netamsk failed\n"); + return -1; + } + + req.ifa.ifa_prefixlen = mask; + fprintf(stdout, "interface get netamsk %d %s\n", req.ifa.ifa_prefixlen, iface->mask); + if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) { + perror("rtnl_talk failed"); + return -1; + } + + if (hyper_down_nic(rth, iface->ifindex) < 0) { + fprintf(stderr, "up device %d failed\n", iface->ifindex); + return -1; + } + + if (hyper_remove_nic(iface->device) < 0) { + fprintf(stderr, "remove device %s failed\n", iface->device); + return -1; + } + + return 0; +} + +int hyper_rescan(void) +{ + int fd = open("/sys/bus/pci/rescan", O_WRONLY); + + if (fd < 0) { + perror("can not open rescan file"); + return -1; + } + + if (write(fd, "1\n", 2) < 0) { + perror("can not open rescan file"); + close(fd); + return -1; + } + fprintf(stdout, "finish rescan\n"); + close(fd); + return 0; +} + +int hyper_setup_network(struct hyper_pod *pod) +{ + int i, ret = 0; + struct hyper_interface *iface; + struct hyper_route *rt; + struct rtnl_handle rth; + + if (hyper_rescan() < 0) + return -1; + + if (netlink_open(&rth) < 0) + return -1; + + for (i = 0; i < pod->i_num; i++) { + iface = &pod->iface[i]; + + ret = hyper_setup_interface(&rth, iface); + if (ret < 0) { + fprintf(stderr, "link up device %s failed\n", iface->device); + goto out; + } + } + + ret = hyper_up_nic(&rth, 1); + if (ret < 0) { + fprintf(stderr, "link up lo device failed\n"); + goto out; + } + + for (i = 0; i < pod->r_num; i++) { + rt = &pod->rt[i]; + + ret = hyper_setup_route(&rth, rt); + if (ret < 0) { + fprintf(stderr, "setup route failed\n"); + goto out; + } + } + +out: + netlink_close(&rth); + return ret; +} + +void hyper_cleanup_network(struct hyper_pod *pod) +{ + int i; + struct rtnl_handle rth; + struct hyper_interface *iface; + struct hyper_route *rt; + + if (netlink_open(&rth) < 0) { + fprintf(stdout, "open netlink failed\n"); + return; + } + + for (i = 0; i < pod->r_num; i++) { + rt = &pod->rt[i]; + + if (hyper_cleanup_route(&rth, rt) < 0) + fprintf(stderr, "cleanup route failed\n"); + + free(rt->dst); + free(rt->gw); + free(rt->device); + } + + free(pod->rt); + pod->rt = NULL; + pod->r_num = 0; + + for (i = 0; i < pod->i_num; i++) { + iface = &pod->iface[i]; + + if (hyper_cleanup_interface(&rth, iface) < 0) + fprintf(stderr, "link down device %s failed\n", iface->device); + + free(iface->device); + free(iface->ipaddr); + free(iface->mask); + } + + free(pod->iface); + pod->iface = NULL; + pod->i_num = 0; + netlink_close(&rth); +} diff --git a/src/net.h b/src/net.h new file mode 100644 index 0000000..8b95a95 --- /dev/null +++ b/src/net.h @@ -0,0 +1,57 @@ +#ifndef _NET_H_ +#define _NET_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct rtnl_handle { + int fd; + struct sockaddr_nl local; + struct sockaddr_nl peer; + __u32 seq; + __u32 dump; +}; + +typedef struct { + __u8 family; + __u8 bytelen; + __s16 bitlen; + __u32 flags; + __u32 data[8]; +} inet_prefix; + +struct hyper_interface { + char *device; + int ifindex; + char *ipaddr; + char *mask; +}; + +struct hyper_route { + char *dst; + char *gw; + char *device; + int ifindex; +}; + +struct hyper_pod; +int hyper_rescan(void); +void hyper_set_be32(uint8_t *buf, uint32_t val); +uint32_t hyper_get_be32(uint8_t *buf); +void hyper_set_be64(uint8_t *buf, uint64_t val); +uint64_t hyper_get_be64(uint8_t *buf); +int hyper_setup_network(struct hyper_pod *pod); +void hyper_cleanup_network(struct hyper_pod *pod); +int hyper_get_type_block(int fd, uint32_t *type); +int hyper_send_type(int fd, uint32_t type); +int hyper_send_type_block(int fd, uint32_t type, int need_ack); +int hyper_send_msg(int fd, uint32_t type, uint32_t len, + uint8_t *message); +int hyper_send_data(int fd, uint8_t *data, uint32_t len); +#endif diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..160b034 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,605 @@ +#include +#include +#include +#include + +#include "list.h" +#include "parse.h" + +char *json_token_str(char *js, jsmntok_t *t) +{ + js[t->end] = '\0'; + return js + t->start; +} + +int json_token_int(char *js, jsmntok_t *t) +{ + return strtol(json_token_str(js, t), 0, 10); +} + +uint64_t json_token_ll(char *js, jsmntok_t *t) +{ + return strtoll(json_token_str(js, t), 0, 10); +} + +int json_token_streq(char *js, jsmntok_t *t, char *s) +{ + return (strncmp(js + t->start, s, t->end - t->start) == 0 && + strlen(s) == (size_t)(t->end - t->start)); +} + +static int container_parse_cmd(struct hyper_container *c, char *json, jsmntok_t *toks) +{ + int i = 1, j; + + if (toks[i].type != JSMN_ARRAY) { + fprintf(stdout, "cmd need array"); + return -1; + } + + c->exec.argc = toks[i].size; + + c->exec.argv = calloc(c->exec.argc + 1, sizeof(*c->exec.argv)); + c->exec.argv[c->exec.argc] = NULL; + + for (j = 0; j < c->exec.argc; j++) { + i++; + c->exec.argv[j] = strdup(json_token_str(json, &toks[i])); + fprintf(stdout, "container init arg %d %s\n", j, c->exec.argv[j]); + } + + return i; +} + +static int container_parse_volumes(struct hyper_container *c, char *json, jsmntok_t *toks) +{ + int i = 1, j; + + if (toks[i].type != JSMN_ARRAY) { + fprintf(stdout, "volume need array\n"); + return -1; + } + c->vols_num = toks[i].size; + fprintf(stdout, "volumes num %d\n", c->vols_num); + c->vols = calloc(c->vols_num, sizeof(*c->vols)); + + for (j = 0; j < c->vols_num; j++) { + int i_volume, next_volume; + + i++; + if (toks[i].type != JSMN_OBJECT) { + fprintf(stdout, "volume array need object\n"); + return -1; + } + next_volume = toks[i].size; + for (i_volume = 0; i_volume < next_volume; i_volume++) { + i++; + if (json_token_streq(json, &toks[i], "device")) { + c->vols[j].device = + strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "volume %d device %s\n", j, c->vols[j].device); + } else if (json_token_streq(json, &toks[i], "mount")) { + c->vols[j].mountpoint = + strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "volume %d mp %s\n", j, c->vols[j].mountpoint); + } else if (json_token_streq(json, &toks[i], "fstype")) { + c->vols[j].fstype = + strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "volume %d fstype %s\n", j, c->vols[j].fstype); + } else if (json_token_streq(json, &toks[i], "readOnly")) { + if (!json_token_streq(json, &toks[++i], "false")) + c->vols[j].readonly = 1; + fprintf(stdout, "volume %d readonly %d\n", j, c->vols[j].readonly); + } else { + fprintf(stdout, "in voulmes incorrect %s\n", json_token_str(json, &toks[i])); + } + } + } + + return i; +} + +static int container_parse_fsmap(struct hyper_container *c, char *json, jsmntok_t *toks) +{ + int i = 1, j; + + if (toks[i].type != JSMN_ARRAY) { + fprintf(stdout, "envs need array\n"); + return -1; + } + + c->maps_num = toks[i].size; + fprintf(stdout, "fsmap num %d\n", c->maps_num); + c->maps = calloc(c->maps_num, sizeof(*c->maps)); + + for (j = 0; j < c->maps_num; j++) { + int i_map, next_map; + + i++; + if (toks[i].type != JSMN_OBJECT) { + fprintf(stdout, "fsmap array need object\n"); + return -1; + } + next_map = toks[i].size; + for (i_map = 0; i_map < next_map; i_map++) { + i++; + if (json_token_streq(json, &toks[i], "source")) { + c->maps[j].source = + strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "maps %d source %s\n", j, c->maps[j].source); + } else if (json_token_streq(json, &toks[i], "path")) { + c->maps[j].path = + strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "maps %d path %s\n", j, c->maps[j].path); + } else if (json_token_streq(json, &toks[i], "readOnly")) { + if (!json_token_streq(json, &toks[++i], "false")) + c->maps[j].readonly = 1; + fprintf(stdout, "maps %d readonly %d\n", j, c->maps[j].readonly); + } else { + fprintf(stdout, "in maps incorrect %s\n", + json_token_str(json, &toks[i])); + } + } + } + + return i; +} + +static int container_parse_envs(struct hyper_container *c, char *json, jsmntok_t *toks) +{ + int i = 1, j; + + if (toks[i].type != JSMN_ARRAY) { + fprintf(stdout, "encs need array\n"); + return -1; + } + + c->envs_num = toks[i].size; + fprintf(stdout, "envs num %d\n", c->envs_num); + c->envs = calloc(c->envs_num, sizeof(*c->envs)); + + for (j = 0; j < c->envs_num; j++) { + int i_env, next_env; + + i++; + if (toks[i].type != JSMN_OBJECT) { + fprintf(stdout, "env array need object\n"); + return -1; + } + next_env = toks[i].size; + for (i_env = 0; i_env < next_env; i_env++) { + i++; + if (json_token_streq(json, &toks[i], "env")) { + c->envs[j].env = + strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "envs %d env %s\n", j, c->envs[j].env); + } else if (json_token_streq(json, &toks[i], "value")) { + c->envs[j].value = + strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "envs %d value %s\n", j, c->envs[j].value); + } else { + fprintf(stdout, "in envs incorrect %s\n", json_token_str(json, &toks[i])); + } + } + } + + return i; +} + +static int hyper_parse_container(struct hyper_pod *pod, struct hyper_container *c, + char *json, jsmntok_t *toks) +{ + int i = 1, j, next, next_container; + jsmntok_t *t; + + if (toks[i].type != JSMN_OBJECT) { + fprintf(stderr, "format incorrect\n"); + return -1; + } + + c->exec.init = 1; + c->exec.code = -1; + + next_container = toks[i].size; + fprintf(stdout, "next container %d\n", next_container); + + for (j = 0; j < next_container; j++) { + i++; + t = &toks[i]; + fprintf(stdout, "%d name %s\n", i, json_token_str(json, t)); + if (json_token_streq(json, t, "id") && t->size == 1) { + i++; + c->id = strdup(json_token_str(json, &toks[i])); + c->exec.id = strdup(c->id); + fprintf(stdout, "container id %s\n", c->id); + } else if (json_token_streq(json, t, "cmd") && t->size == 1) { + next = container_parse_cmd(c, json, &toks[i]); + if (next < 0) + return -1; + i += next; + } else if (json_token_streq(json, t, "rootfs") && t->size == 1) { + i++; + c->rootfs = strdup(json_token_str(json, &toks[i])); + fprintf(stdout, "container rootfs %s\n", c->rootfs); + } else if (json_token_streq(json, t, "tty") && t->size == 1) { + i++; + c->exec.seq = json_token_ll(json, &toks[i]); + fprintf(stdout, "container seq %" PRIu64 "\n", c->exec.seq); + } else if (json_token_streq(json, t, "workdir") && t->size == 1) { + i++; + c->workdir = strdup(json_token_str(json, &toks[i])); + fprintf(stdout, "container workdir %s\n", c->workdir); + } else if (json_token_streq(json, t, "image") && t->size == 1) { + i++; + c->image = strdup(json_token_str(json, &toks[i])); + fprintf(stdout, "container image %s\n", c->image); + } else if (json_token_streq(json, t, "fstype") && t->size == 1) { + i++; + c->fstype = strdup(json_token_str(json, &toks[i])); + fprintf(stdout, "container fstype %s\n", c->fstype); + } else if (json_token_streq(json, t, "volumes") && t->size == 1) { + next = container_parse_volumes(c, json, &toks[i]); + if (next < 0) + return -1; + i += next; + } else if (json_token_streq(json, t, "fsmap") && t->size == 1) { + next = container_parse_fsmap(c, json, &toks[i]); + if (next < 0) + return -1; + i += next; + } else if (json_token_streq(json, t, "envs") && t->size == 1) { + next = container_parse_envs(c, json, &toks[i]); + if (next < 0) + return -1; + i += next; + } else if (json_token_streq(json, t, "restartPolicy") && t->size == 1) { + i++; +/* + if (json_token_streq(json, &toks[i], "always") && t->size == 1) + c->exec.flags = POLICY_ALWAYS; + else if (json_token_streq(json, &toks[i], "onFailure") && t->size == 1) + c->exec.flags = POLICY_ONFAILURE; + else + c->exec.flags = POLICY_NEVER; +*/ + fprintf(stdout, "restartPolicy %s\n", json_token_str(json, &toks[i])); + } + } + + return i; +} + +static int hyper_parse_containers(struct hyper_pod *pod, char *json, jsmntok_t *toks) +{ + int i = 1, j, next; + + if (toks[i].type != JSMN_ARRAY) { + fprintf(stdout, "format incorrect\n"); + return -1; + } + + pod->remains = pod->c_num = toks[i].size; + fprintf(stdout, "container count %d\n", pod->c_num); + pod->c = calloc(pod->c_num, sizeof(*pod->c)); + + if (pod->c == NULL) { + fprintf(stdout, "alloc memory for container failed\n"); + return -1; + } + + for (j = 0; j < pod->c_num; j++) { + next = hyper_parse_container(pod, &pod->c[j], json, toks + i); + if (next < 0) + return -1; + + i += next; + } + + return i; +} + +static int hyper_parse_interfaces(struct hyper_pod *pod, char *json, jsmntok_t *toks) +{ + int i = 1, j, next_if; + struct hyper_interface *iface; + + if (toks[i].type != JSMN_ARRAY) { + fprintf(stdout, "interfaces need array\n"); + return -1; + } + + pod->i_num = toks[i].size; + fprintf(stdout, "network interfaces num %d\n", pod->i_num); + pod->iface = calloc(pod->i_num, sizeof(*iface)); + + for (j = 0; j < pod->i_num; j++) { + int i_if; + + iface = &pod->iface[j]; + i++; + if (toks[i].type != JSMN_OBJECT) { + fprintf(stdout, "network array need object\n"); + return -1; + } + next_if = toks[i].size; + + for (i_if = 0; i_if < next_if; i_if++) { + i++; + if (json_token_streq(json, &toks[i], "device")) { + iface->device = strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "net device is %s\n", iface->device); + } else if (json_token_streq(json, &toks[i], "ipAddress")) { + iface->ipaddr = strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "net ipaddress is %s\n", iface->ipaddr); + } else if (json_token_streq(json, &toks[i], "netMask")) { + iface->mask = strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "net mask is %s\n", iface->mask); + } + } + } + + return i; +} + +static int hyper_parse_routes(struct hyper_pod *pod, char *json, jsmntok_t *toks) +{ + int i = 1, j, next_rt; + struct hyper_route *rt; + + if (toks[i].type != JSMN_ARRAY) { + fprintf(stdout, "routes need array\n"); + return -1; + } + + pod->r_num = toks[i].size; + fprintf(stdout, "network routes num %d\n", pod->r_num); + pod->rt = calloc(pod->r_num, sizeof(*rt)); + + for (j = 0; j < pod->r_num; j++) { + int i_rt; + + rt = &pod->rt[j]; + i++; + if (toks[i].type != JSMN_OBJECT) { + fprintf(stdout, "routes array need object\n"); + return -1; + } + next_rt = toks[i].size; + + for (i_rt = 0; i_rt < next_rt; i_rt++) { + i++; + if (json_token_streq(json, &toks[i], "dest")) { + rt->dst = strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "route %d dest is %s\n", j, rt->dst); + } else if (json_token_streq(json, &toks[i], "gateway")) { + rt->gw = strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "route %d gateway is %s\n", j, rt->gw); + } else if (json_token_streq(json, &toks[i], "device")) { + rt->device = strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "route %d device is %s\n", j, rt->device); + } + } + } + + return i; +} + +int hyper_parse_pod(struct hyper_pod *pod, char *json, int length) +{ + int i, n, next = -1; + jsmn_parser p; + int toks_num = 100; + jsmntok_t *toks = NULL; + +realloc: + toks = realloc(toks, toks_num * sizeof(jsmntok_t)); + + fprintf(stdout, "call hyper_start_pod, json %s, len %d\n", json, length); + jsmn_init(&p); + n = jsmn_parse(&p, json, length, toks, toks_num); + if (n < 0) { + fprintf(stdout, "jsmn parse failed, n is %d\n", n); + if (n == JSMN_ERROR_NOMEM) { + toks_num *= 2; + goto realloc; + } + + goto out; + } + + pod->policy = POLICY_NEVER; + + fprintf(stdout, "jsmn parse successed, n is %d\n", n); + next = 0; + for (i = 0; i < n; i++) { + jsmntok_t *t = &toks[i]; + + fprintf(stdout, "token %d, type is %d, size is %d\n", i, t->type, t->size); + + if (t->type != JSMN_STRING) + continue; + + if (json_token_streq(json, t, "containers") && t->size == 1) { + next = hyper_parse_containers(pod, json, t); + if (next < 0) + goto out; + + i += next; + } else if (json_token_streq(json, t, "interfaces") && t->size == 1) { + next = hyper_parse_interfaces(pod, json, t); + if (next < 0) + goto out; + + i += next; + } else if (json_token_streq(json, t, "routes") && t->size == 1) { + next = hyper_parse_routes(pod, json, t); + if (next < 0) + goto out; + + i += next; + } else if (json_token_streq(json, t, "socket") && t->size == 1) { + pod->channel = strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "channel is %s\n", pod->channel); + } else if (json_token_streq(json, t, "shareDir") && t->size == 1) { + pod->tag = strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "9p tag is %s\n", pod->tag); + } else if (json_token_streq(json, t, "hostname") && t->size == 1) { + pod->hostname = strdup(json_token_str(json, &toks[++i])); + fprintf(stdout, "hostname is %s\n", pod->hostname); + } else if (json_token_streq(json, t, "restartPolicy") && t->size == 1) { + i++; + if (json_token_streq(json, &toks[i], "always") && t->size == 1) + pod->policy = POLICY_ALWAYS; + else if (json_token_streq(json, &toks[i], "onFailure") && t->size == 1) + pod->policy = POLICY_ONFAILURE; + fprintf(stdout, "restartPolicy is %" PRIu8 "\n", pod->policy); + } + } + +out: + free(toks); + return next; +} + +int hyper_parse_winsize(struct hyper_win_size *ws, char *json, int length) +{ + int i, n, ret = 0; + jsmn_parser p; + int toks_num = 10; + jsmntok_t *toks = NULL; + +realloc: + toks = realloc(toks, toks_num * sizeof(jsmntok_t)); + + jsmn_init(&p); + + n = jsmn_parse(&p, json, length, toks, toks_num); + if (n < 0) { + fprintf(stdout, "jsmn parse failed, n is %d\n", n); + if (n == JSMN_ERROR_NOMEM) { + toks_num *= 2; + goto realloc; + } + + goto fail; + } + + for (i = 0; i < n; i++) { + jsmntok_t *t = &toks[i]; + + if (t->type != JSMN_STRING) + continue; + + if (i++ == n) + goto fail; + if (json_token_streq(json, t, "tty")) { + if (toks[i].type != JSMN_STRING) + goto fail; + ws->tty = strdup(json_token_str(json, &toks[i])); + } else if (json_token_streq(json, t, "seq")) { + if (toks[i].type != JSMN_PRIMITIVE) + goto fail; + ws->seq = json_token_ll(json, &toks[i]); + } else if (json_token_streq(json, t, "row")) { + if (toks[i].type != JSMN_PRIMITIVE) + goto fail; + ws->row = json_token_int(json, &toks[i]); + } else if (json_token_streq(json, t, "column")) { + if (toks[i].type != JSMN_PRIMITIVE) + goto fail; + ws->column = json_token_int(json, &toks[i]); + } + } +out: + free(toks); + return ret; +fail: + ret = -1; + goto out; +} + +struct hyper_exec *hyper_parse_execcmd(char *json, int length) +{ + int i, j, n, has_seq = 0; + struct hyper_exec *exec = NULL; + char **argv = NULL; + + jsmn_parser p; + int toks_num = 10; + jsmntok_t *toks = NULL; + +realloc: + toks = realloc(toks, toks_num * sizeof(jsmntok_t)); + + jsmn_init(&p); + n = jsmn_parse(&p, json, length, toks, toks_num); + if (n < 0) { + fprintf(stdout, "jsmn parse failed, n is %d\n", n); + if (n == JSMN_ERROR_NOMEM) { + toks_num *= 2; + goto realloc; + } + goto out; + } + + exec = calloc(1, sizeof(*exec)); + if (exec == NULL) + goto out; + + INIT_LIST_HEAD(&exec->list); + + for (i = 0, j = 0; i < n; i++) { + jsmntok_t *t = &toks[i]; + + if (t->type != JSMN_STRING) + continue; + + if (json_token_streq(json, t, "container")) { + if (i++ == n) + goto fail; + + exec->id = strdup(json_token_str(json, &toks[i])); + fprintf(stdout, "get container %s\n", exec->id); + } else if (json_token_streq(json, t, "seq")) { + if (i++ == n) + goto fail; + has_seq = 1; + exec->seq = json_token_ll(json, &toks[i]); + fprintf(stdout, "get seq %"PRIu64"\n", exec->seq); + } else if (json_token_streq(json, t, "cmd")) { + if (i++ == n) + goto fail; + + if (toks[i].type != JSMN_ARRAY) { + fprintf(stdout, "execcmd need array\n"); + goto fail; + } + + exec->argc = toks[i].size; + argv = calloc(exec->argc + 1, sizeof(*argv)); + argv[exec->argc] = NULL; + } else if (j < exec->argc) { + argv[j++] = strdup(json_token_str(json, &toks[i])); + fprintf(stdout, "argv %d, %s\n", j - 1, argv[j - 1]); + } + } + + if (!has_seq) { + fprintf(stderr, "execcmd format error, has no seq\n"); + goto fail; + } + exec->argv = argv; +out: + free(toks); + return exec; +fail: + free(exec->id); + for (i = 0; i < exec->argc; i++) + free(argv[i]); + + free(exec->argv); + free(exec); + + exec = NULL; + goto out; +} diff --git a/src/parse.h b/src/parse.h new file mode 100644 index 0000000..7b41ba0 --- /dev/null +++ b/src/parse.h @@ -0,0 +1,13 @@ +#ifndef _DVM_JSON_H_ +#define _DVM_JSON_H_ + +#include "hyper.h" +#include "jsmn.h" + +int hyper_parse_pod(struct hyper_pod *pod, char *json, int length); +struct hyper_exec *hyper_parse_execcmd(char *json, int length); +char *json_token_str(char *js, jsmntok_t *t); +int json_token_streq(char *js, jsmntok_t *t, char *s); +int hyper_parse_winsize(struct hyper_win_size *ws, char *json, int length); + +#endif diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..adf0a0c --- /dev/null +++ b/src/util.c @@ -0,0 +1,300 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "net.h" +#include "util.h" + +char *read_cmdline(void) +{ + return NULL; +} + +int hyper_mkdir(char *hyper_path) +{ + struct stat st; + char *p, *path = strdup(hyper_path); + + if (path == NULL) { + errno = ENOMEM; + return -1; + } + + fprintf(stdout, "create directory %s\n", path); + if (stat(path, &st) >= 0) { + if (S_ISDIR(st.st_mode)) + return 0; + errno = ENOTDIR; + return -1; + } + + if (errno != ENOENT) + return -1; + + p = strrchr(path, '/'); + if (p == NULL) { + errno = EINVAL; + return -1; + } + + if (p != path) { + *p = '\0'; + + if (hyper_mkdir(path) < 0) + return -1; + + *p = '/'; + } + + if (mkdir(path, 0755) < 0 && errno != EEXIST) + return -1; + + return 0; +} + +int hyper_open_channel(char *channel, int mode) +{ + struct dirent **list; + struct dirent *dir; + int fd = -1, i, num; + char path[256], name[128]; + + num = scandir("/sys/class/virtio-ports/", &list, NULL, NULL); + if (num < 0) { + perror("scan /sys/calss/virtio-ports/ failed"); + return -1; + } + + memset(path, 0, sizeof(path)); + + for (i = 0; i < num; i++) { + dir = list[i]; + if (dir->d_name[0] == '.') + continue; + + if (snprintf(path, sizeof(path), "/sys/class/virtio-ports/%s/name", dir->d_name) < 0) { + fprintf(stderr, "get channel device %s path failed\n", dir->d_name); + continue; + } + + fd = open(path, O_RDONLY); + + memset(name, 0, sizeof(name)); + if (fd < 0 || read(fd, name, sizeof(name)) < 0) + continue; + + close(fd); + fd = -1; + + if (strncmp(name, channel, strlen(channel))) { + fprintf(stderr, "channel %s, directory %s\n", channel, name); + continue; + } + + if (snprintf(path, sizeof(path), "/dev/%s", dir->d_name) < 0) { + fprintf(stderr, "get channel device %s path failed\n", dir->d_name); + continue; + } + + fprintf(stdout, "open hyper channel %s\n", path); + fd = open(path, O_RDWR | O_CLOEXEC | mode); + if (fd < 0) + perror("fail to open channel deice"); + + break; + } + + free(list); + return fd; +} + +int hyper_open_serial_dev(char *tty) +{ + int fd = open(tty, O_RDWR | O_CLOEXEC | O_NOCTTY); + + if (fd < 0) { + perror("fail to open tty device"); + return -1; + } + + return fd; +} + +int hyper_open_serial(char *tty) +{ + char path[256]; + + memset(path, 0, sizeof(path)); + + if (snprintf(path, sizeof(path), "/dev/%s", tty) < 0) { + fprintf(stderr, "get channel device %s path failed\n", tty); + return -1; + } + + fprintf(stdout, "open hyper tty %s\n", path); + + return hyper_open_serial_dev(path); +} + +int hyper_setfd_cloexec(int fd) +{ + int flags = fcntl(fd, F_GETFD); + + if (flags < 0) { + perror("fcntl F_GETFD failed"); + return -1; + } + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { + perror("fcntl F_SETFD failed"); + return -1; + } + + return 0; +} + +int hyper_setfd_block(int fd) +{ + int flags = fcntl(fd, F_GETFL); + + if (flags < 0) { + perror("fcntl F_GETFL failed"); + return -1; + } + + if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0) { + perror("fcntl F_SETFD failed"); + return -1; + } + + return 0; +} + +int hyper_setfd_nonblock(int fd) +{ + int flags = fcntl(fd, F_GETFL); + + if (flags < 0) { + perror("fcntl F_GETFL failed"); + return -1; + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl F_SETFD failed"); + return -1; + } + + return 0; +} + +void hyper_unmount_all(void) +{ + FILE *mtab; + struct mntent *mnt; + char *mntlist[128]; + int i, n = 0; + char *filesys; + + mtab = setmntent("/proc/mounts", "r"); + if (mtab == NULL) { + fprintf(stderr, "cannot open /proc/mount"); + return; + } + + while (n < 128) { + mnt = getmntent(mtab); + if (mnt == NULL) + break; + + if (strcmp(mnt->mnt_type, "devtmpfs") == 0 || + strcmp(mnt->mnt_type, "proc") == 0 || + strcmp(mnt->mnt_type, "sysfs") == 0 || + strcmp(mnt->mnt_type, "ramfs") == 0 || + strcmp(mnt->mnt_type, "tmpfs") == 0 || + strcmp(mnt->mnt_type, "rootfs") == 0 || + strcmp(mnt->mnt_type, "devpts") == 0) + continue; + + mntlist[n++] = strdup(mnt->mnt_dir); + } + + endmntent(mtab); + + for (i = n - 1; i >= 0; i--) { + filesys = mntlist[i]; + fprintf(stdout, "umount %s\n", filesys); + if ((umount(mntlist[i]) < 0) && (umount2(mntlist[i], MNT_DETACH) < 0)) { + fprintf(stdout, ("umount %s: %s failed\n"), + filesys, strerror(errno)); + } + } + + sync(); +} + +void hyper_kill_all(void) +{ + int npids = 0; + int index = 0; + int pid; + DIR *dp; + struct dirent *de; + pid_t *pids = NULL; + + dp = opendir("/proc"); + if (dp == NULL) + return; + + while ((de = readdir(dp)) && de != NULL) { + if (!isdigit(de->d_name[0])) + continue; + pid = atoi(de->d_name); + if (pid == 1) + continue; + if (index <= npids) { + pids = realloc(pids, npids + 16384); + if (pids == NULL) + return; + npids += 16384; + } + + pids[index++] = pid; + } + + fprintf(stdout, "Sending SIGTERM\n"); + + for (--index; index >= 0; --index) { + fprintf(stdout, "kill process %d\n", pids[index]); + kill(pids[index], SIGTERM); + } + + free(pids); + closedir(dp); +} + +void hyper_shutdown(struct hyper_pod *pod) +{ + int i; + uint8_t *data = calloc(pod->c_num, 4); + + for (i = 0; i < pod->c_num; i++) + hyper_set_be32(data + (i * 4), pod->c[i].exec.code); + + hyper_send_msg(ctl.chan.fd, FINISH, pod->c_num * 4, data); + + hyper_unmount_all(); + hyper_kill_all(); + reboot(LINUX_REBOOT_CMD_POWER_OFF); +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..9f7708a --- /dev/null +++ b/src/util.h @@ -0,0 +1,17 @@ +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include "hyper.h" + +char *read_cmdline(void); +int hyper_mkdir(char *path); +int hyper_open_channel(char *channel, int mode); +int hyper_open_serial_dev(char *tty); +int hyper_open_serial(char *tty); +int hyper_setfd_cloexec(int fd); +int hyper_setfd_block(int fd); +int hyper_setfd_nonblock(int fd); +void hyper_shutdown(struct hyper_pod *pod); +void hyper_kill_all(void); +void hyper_unmount_all(void); +#endif