You are not logged in.

#1 2017-12-04 01:05:12

Dafta
Member
Registered: 2016-02-17
Posts: 10

Qemu networking issue between two guests

Hi everyone!

I have a problem running two guests in qemu and getting them to communicate over a network. The guests are running a homemade i386 OS, to which RTL8139 drivers were added recently. Currently, only a simple ethernet example is implemented, with the guest OSes sending ethernet frames to each other. The code is working correctly, as it has been tested on Ubuntu 16.04 recently, and Arch a while ago. But something must have changed on Arch recently, as currently starting the demo works, but the guests can't communicate with each other.

This is the makefile for the project:

# Building system script (for 'make')

# valid targets: (all), clean, cleanall, qemu, debug_qemu, debug_gdb
# valid command line defines: debug=yes, optimize=yes

#default target
ARCH ?= i386

CONFIG_INI = arch/$(ARCH)/config.ini
THIS_MAKEFILE = Makefile
CONFIG_FILES = $(CONFIG_INI) $(THIS_MAKEFILE)


include $(CONFIG_INI)

KERNEL_FILE_NAME = $(PROJECT).elf
BINFILE = $(BUILDDIR)/$(KERNEL_FILE_NAME)

CMACROS += OS_NAME="\"$(OS_NAME)\"" PROJECT="\"$(PROJECT)\"" 		\
	   NAME_MAJOR="\"$(NAME_MAJOR)\"" NAME_MINOR="\"$(NAME_MINOR)\""\
	   ARCH="\"$(ARCH)\"" AUTHOR="\"$(AUTHOR)\"" 		\
	   VERSION="\"$(VERSION)\""


#------------------------------------------------------------------------------
# Devices

#little "magic" for automatically setting DEV_VARS and DEV_PTRS
#with changes only in DEVICES_DEV (for kernel/devices.c):
# DEV_VARS = vga_text_dev,uart_com1,i8042_dev
# DEV_PTRS = &vga_text_dev,&uart_com1,&i8042_dev
comma := ,
empty :=
space := $(empty) $(empty)
DEV_VARS := $(subst $(space),$(comma),$(DEVICES_DEV))
DEV_PTRS := $(addprefix \&,$(DEVICES_DEV))
DEV_PTRS := $(subst $(space),$(comma),$(DEV_PTRS))

CMACROS += $(DEVICES) DEVICES_DEV=$(DEV_VARS) DEVICES_DEV_PTRS=$(DEV_PTRS)   \
	IC_DEV=$(IC_DEV) TIMER=$(TIMER)					     \
	K_INITIAL_STDOUT=$(K_INITIAL_STDOUT) K_STDOUT="\"$(K_STDOUT)\""      \
	U_STDIN="\"$(U_STDIN)\"" U_STDOUT="\"$(U_STDOUT)\"" 		     \
	U_STDERR="\"$(U_STDERR)\""

CMACROS += MAX_RESOURCES=$(MAX_RESOURCES)

#------------------------------------------------------------------------------
# Threads

CMACROS += SYSTEM_MEMORY=$(SYSTEM_MEMORY)			\
	PRIO_LEVELS=$(PRIO_LEVELS)				\
	THR_DEFAULT_PRIO=$(THR_DEFAULT_PRIO)			\
	KERNEL_STACK_SIZE=$(KERNEL_STACK_SIZE)			\
	DEFAULT_THREAD_STACK_SIZE=$(DEFAULT_THREAD_STACK_SIZE)	\
	PROG_HEAP_SIZE=$(PROG_HEAP_SIZE)			\
	HANDLER_STACK_SIZE=$(HANDLER_STACK_SIZE)		\
	LOAD_ADDR=$(LOAD_ADDR)

#------------------------------------------------------------------------------
CMACROS += $(OPTIONALS)
#------------------------------------------------------------------------------

all: $(BINFILE)

# Create $(BUILDDIR) and ARCH symbolic link for selected platform source
# (used for #include <ARCH/*> purposes)
BDIR_RDY = $(BUILDDIR)/.null
$(BDIR_RDY):
	@mkdir -p $(BUILDDIR)
	@ln -s ../arch/$(ARCH) $(BUILDDIR)/ARCH
	@touch $(BDIR_RDY)


#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Compiling and linking kernel
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BUILD_K = $(BUILDDIR)/kernel

CMACROS_K += $(CMACROS) ASSERT_H=\<kernel/errno.h\>

#------------------------------------------------------------------------------
# Memory allocators: 'gma' and/or 'first_fit'
CMACROS_K += MEM_ALLOCATOR_FOR_KERNEL=$(MEM_ALLOCATOR_FOR_KERNEL)

#------------------------------------------------------------------------------
FILES_K := $(foreach DIR,$(DIRS_K),$(wildcard $(DIR)/*.c $(DIR)/*.S))
OBJS_K := $(addprefix $(BUILD_K)/,$(FILES_K:.c=.o))
OBJS_K := $(OBJS_K:.S=.asm.o)
DEPS_K := $(OBJS_K:.o=.d)

# dummy file that indicate directories for kernel objects are created
KDIRS_CREATED = $(BUILD_K)/.null

# create required directories in $(BUILD_K) directory (including $(BUILD_K))
$(KDIRS_CREATED): $(BDIR_RDY)
	@-if [ ! -e $(BUILD_K) ]; then mkdir -p $(BUILD_K); fi;
	@-$(foreach DIR,$(DIRS_K), if [ ! -e $(BUILD_K)/$(DIR) ]; \
		then mkdir -p $(BUILD_K)/$(DIR); fi; )
	@touch $(KDIRS_CREATED)

# define how to compile .c files
$(BUILD_K)/%.o: %.c $(CONFIG_FILES) $(KDIRS_CREATED)
	@echo [compiling 'kernel'] $< ...
	@$(CC_K) -c $< -o $@ -MMD $(CFLAGS_K) \
		$(foreach INC,$(INCLUDES_K),-I $(INC)) \
		$(foreach MACRO,$(CMACROS_K),-D $(MACRO))

# define how to compile .S files (assembler)
$(BUILD_K)/%.asm.o: %.S $(CONFIG_FILES) $(KDIRS_CREATED)
	@echo [compiling 'kernel'] $< ...
	@$(CC_K) -c $< -o $@ -MMD $(CFLAGS_K) \
		$(foreach INC,$(INCLUDES_K),-I$(INC)) \
		$(foreach MACRO,$(CMACROS_K),-D $(MACRO))

# preprocessed linker script (constants)
LDSCRIPT_PP := $(BUILD_K)/ldscript.ld
$(LDSCRIPT_PP): $(LDSCRIPT) $(CONFIG_FILES) $(KDIRS_CREATED)
	@$(CC_K) -E -P -x c -o $@ $< $(CFLAGS_K)		\
		$(foreach INC,$(INCLUDES_K),-I$(INC)) 		\
		$(foreach MACRO,$(CMACROS_K),-D $(MACRO))


#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Compiling and linking programs
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

PROG := progs
BUILD_U := $(BUILDDIR)/$(PROG)

PROG_HEADERS := $(PROG)/programs.h

CMACROS_U += $(CMACROS) ASSERT_H=\<api/errno.h\>		\
	     PROGRAMS=\<$(PROG_HEADERS)\>			\
	     PROG_START_FUNC=$(PROG_START_FUNC)			\
	     MEM_ALLOCATOR_FOR_USER=$(MEM_ALLOCATOR_FOR_USER)	\
	     MAX_USER_DESCRIPTORS=$(MAX_USER_DESCRIPTORS)

PROGRAM_HEADERS := $(BUILDDIR)/$(PROG_HEADERS)

#------------------------------------------------------------------------------

UDIR_RDY = $(BUILD_U)/.null
$(UDIR_RDY): $(BDIR_RDY)
	@-if [ ! -e $(BUILD_U) ]; then mkdir -p $(BUILD_U); fi;
	@touch $(UDIR_RDY)

# Programs compilation through template ----------------------------------------

# Template is parsed twice:
# 1) when "called" - when expanded on every "call" location;
#    all "simple" variables and functions are evaluated
#    (variables and functions defined with single $ character)
#    Other ("complex") variables and function are left (but one $ is removed)
# 2) when "final" makefile is parsed


# Template is called with: $(call PROGRAM_TEMPLATE,prog_name)
# for example: $(call PROGRAM_TEMPLATE,hello) => $(1) is hello
define PROGRAM_TEMPLATE

$(1)_MACROS := $(CMACROS_U) PROG_HELP=$(1)_prog_help_msg

$(1)_DIRS := $(wordlist 2,$(words $($(1))),$($(1)))

$(1)_FILES := $$(foreach DIR,$$($(1)_DIRS),$$(wildcard $$(DIR)/*.c $$(DIR)/*.S))
$(1)_BUILDDIR := $(BUILD_U)/$(1)
$(1)_BDIRS    := $$(addprefix $$($(1)_BUILDDIR)/,$$($(1)_DIRS))
$(1)_OBJS     := $$(addprefix $$($(1)_BUILDDIR)/,$$($(1)_FILES))
$(1)_OBJS     := $$($(1)_OBJS:.c=.o)
$(1)_OBJS     := $$($(1)_OBJS:.S=.asm.o)
$(1)_DEPS     := $$($(1)_OBJS:.o=.d)

FILES_U += $$($(1)_FILES)
OBJS_U	+= $$($(1)_OBJS)
DEPS_U	+= $$($(1)_DEPS)

# dummy file that indicate directories are created
$(1)_DIRS_CREATED := $$($(1)_BUILDDIR)/.null

#create directories for objects
$$($(1)_DIRS_CREATED): $(UDIR_RDY)
	@if [ ! -e $$($(1)_BUILDDIR) ]; then mkdir -p $$($(1)_BUILDDIR); fi;
	@$$(foreach DIR,$$($(1)_BDIRS), if [ ! -e $$(DIR) ]; \
		then mkdir -p $$(DIR); fi; )
	@touch $$($(1)_DIRS_CREATED)

#define how to compile .c files
$$($(1)_BUILDDIR)/%.o: %.c $(CONFIG_FILES) $$($(1)_DIRS_CREATED) $(PROGRAM_HEADERS)
	@echo [compiling '$(1)'] $$< ...
	@$$(CC_U) -c $$< -o $$@ -MMD $$(CFLAGS_U) \
		$$(foreach INC,$$(INCLUDES_U),-I $$(INC)) \
		$$(foreach MACRO,$$($(1)_MACROS),-D $$(MACRO))

#define how to compile .S files (assembler)
$$($(1)_BUILDDIR)/%.asm.o: %.S $(CONFIG_FILES) $$($(1)_DIRS_CREATED) $(PROGRAM_HEADERS)
	@echo [compiling '$(1)'] $$< ...
	@$$(CC_U) -c $$< -o $$@ -MMD $$(CFLAGS_U) \
		$$(foreach INC,$$(INCLUDES_U),-I$$(INC)) \
		$$(foreach MACRO,$$($(1)_MACROS),-D $$(MACRO))

endef

# "Call" above template for each program to be included
$(foreach prog,$(CCPROGRAMS),$(eval $(call PROGRAM_TEMPLATE,$(prog))))

$(PROGRAM_HEADERS): $(FILES_U) $(UDIR_RDY)
	@-if [ ! -e $(BUILD_U) ]; then mkdir -p $(BUILD_U); fi;
	@-rm -f $(PROGRAM_HEADERS)
	@$(foreach prog,$(PROGRAMS), \
		echo "int $(word 1,$($(prog))) ( char *args[] );" \
		>> $(PROGRAM_HEADERS); )
	@echo "#define PROGRAMS_FOR_SHELL { \\" >> $(PROGRAM_HEADERS)
	@$(foreach prog,$(PROGRAMS), \
		echo "{ $(word 1,$($(prog))), \"$(prog)\", \" \" }, \\" \
		>> $(PROGRAM_HEADERS); )
	@echo "{NULL,NULL,NULL} }" >> $(PROGRAM_HEADERS)

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


OBJECTS = $(OBJS_K) $(OBJS_U)
DEPS = $(DEPS_K) $(DEPS_U)

# OS image
$(BINFILE): $(OBJECTS) $(LDSCRIPT_PP)
	@echo [linking $@]
	@$(LINK) -o $@ $(OBJECTS) -T $(LDSCRIPT_PP) $(LDFLAGS)


# starting compiled system in 'qemu' emulator
qemu: all
	@echo $(QMSG)
	@$(QEMU) $(QFLAGS) -kernel $(BINFILE)

# DEBUGGING
# For debugging to work: include '-g' in CFLAGS and omit -s and -S from LDFLAGS
# Best if -O3 flag is also omitted from CFLAGS and LDFLAGS (or some variables
# may be optimized away)
# Start debugging from two consoles:
#	1st: make debug_qemu
#	2nd: make debug_gdb
debug_qemu: all
	@echo $(QMSG)
	@$(QEMU) $(QFLAGS) -kernel $(BINFILE) -s -S
debug_gdb: all
	@echo Starting gdb ...
	@$(DEBUG_GDB) -s $(BINFILE) -ex 'target remote localhost:1234'

net_qemu: all
	@echo Starting qemu and network $(QEMU_MEM)
	@xterm -fg black -bg white -e $(QEMU) $(QFLAGS) -kernel $(BINFILE) -device rtl8139,netdev=vlan,mac=52:54:00:12:34:56 -netdev socket,id=vlan,listen=localhost:1234 &
	@xterm -fg black -bg white -e $(QEMU) $(QFLAGS) -kernel $(BINFILE) -device rtl8139,netdev=vlan,mac=52:54:00:12:34:57 -netdev socket,id=vlan,connect=localhost:1234 &

clean:
	@echo Cleaning.
	@-rm -f $(OBJECTS) $(DEPS) $(BINFILE)

clean_all cleanall:
	@echo Removing build directory!
	@-rm -rf $(BUILDDIR)

-include $(DEPS)

And this is the config.ini file included in the makefile:

# Configuration file (included from Makefile)


# Common configuration
#------------------------------------------------------------------------------
OS_NAME = "Benu"
NAME_MAJOR := $(shell basename "`cd ..; pwd -P`")
NAME_MINOR := $(shell basename "`pwd -P`")
PROJECT := $(NAME_MINOR)

ARCH ?= i386
VERSION = 1.0
AUTHOR = leonardo@zemris.fer.hr

# Intermediate and output files are placed into BUILDDIR
BUILDDIR = build


# Where will system be loaded when started (for which address to prepare it)
LOAD_ADDR = 0x100000

OPTIONALS =

# Devices
#------------------------------------------------------------------------------
#"defines" (which device drivers to compile)
DEVICES = VGA_TEXT I8042 I8259 I8253 UART RTL_8139

#devices interface (variables implementing device_t interface)
DEVICES_DEV = dev_null vga_text_dev uart_com1 i8042_dev rtl_8139_dev

#interrupt controller device
IC_DEV = i8259

#timer device
TIMER = i8253

#initial standard output device (while "booting up")
K_INITIAL_STDOUT = uart_com1
#K_INITIAL_STDOUT = vga_text_dev

#standard output for kernel function (for kprint) - device name
K_STDOUT = COM1
#K_STDOUT = VGA_TXT

#standard output and input devices for programs
U_STDIN = COM1
U_STDOUT = COM1
U_STDERR = COM1
#U_STDIN = i8042
#U_STDOUT = VGA_TXT
#U_STDERR = VGA_TXT


# System resources
#------------------------------------------------------------------------------
MAX_RESOURCES = 1000
PRIO_LEVELS = 64
THR_DEFAULT_PRIO = 20
KERNEL_STACK_SIZE = 0x1000
DEFAULT_THREAD_STACK_SIZE = 0x1000
PROG_HEAP_SIZE = 0x10000
HANDLER_STACK_SIZE = 0x400


# System memory (in Bytes)
SYSTEM_MEMORY = 0x800000

# Memory allocators to compile
#------------------------------------------------------------------------------
FIRST_FIT = 1
GMA = 2

#define which to compile
OPTIONALS += FIRST_FIT=$(FIRST_FIT) GMA=$(GMA)

# If using FPU/SSE/MMX, extended context must be saved (uncomment following)
# OPTIONALS += USE_SSE

# Use simple round robin scheduler?
OPTIONALS += SCHED_RR_SIMPLE
OPTIONALS += SCHED_RR_TICK=10000000 #10 ms tick

# Library with utility functions (strings, lists, ...)
#------------------------------------------------------------------------------
LIBS = lib lib/mm


# Compiling and linking: common parameters
#------------------------------------------------------------------------------
LINK = ld
LDSCRIPT = $(BUILDDIR)/ARCH/boot/ldscript.ld
LDFLAGS = -melf_i386
LDFLAGS_OPT = -O3 --gc-sections -s
LDFLAGS_OPTD = -O3 --gc-sections

# Compiling and linking: kernel
#------------------------------------------------------------------------------
CC_K = gcc

CFLAGS_K = -m32 -march=i386 -Wall -Werror -nostdinc -ffreestanding -nostdlib -fno-stack-protector

# additional optimization flags
CFLAGS_KOPT = -O3 -fdata-sections -ffunction-sections

#optimization with debug information
CFLAGS_KOPTD = -O3 -fdata-sections -ffunction-sections -g

#if in command line given: debug=yes or/and optimize=yes
ifeq ($(optimize),yes)
ifeq ($(debug),yes) #if both are set!
CFLAGS_K += $(CFLAGS_KOPTD)
LDFLAGS += $(LDFLAGS_OPTD)
CMACROS += DEBUG
else
CFLAGS_K += $(CFLAGS_KOPT)
LDFLAGS += $(LDFLAGS_OPT)
endif
else #debug set by default
CFLAGS_K += -g
CMACROS += DEBUG
endif

# directories to include while compiling kernel
DIRS_K := arch/$(ARCH)/boot arch/$(ARCH) arch/$(ARCH)/drivers \
	  kernel $(LIBS)

# include dirs for kernel ($(BUILDDIR) for ARCH layer)
INCLUDES_K := include $(BUILDDIR)

# Memory allocator for kernel: 'GMA' or 'FIRST_FIT'
MEM_ALLOCATOR_FOR_KERNEL = $(FIRST_FIT)

CMACROS_K += _KERNEL_

# Compiling and linking: programs
#------------------------------------------------------------------------------
CC_U = gcc

CFLAGS_U = -m32 -march=i386 -Wall -Werror -nostdinc -ffreestanding -nostdlib -fno-stack-protector

# additional optimization flags
CFLAGS_UOPT = -O3 -fdata-sections -ffunction-sections

#optimization with debug information
CFLAGS_UOPTD = -O3 -fdata-sections -ffunction-sections -g

#if in command line given: debug=yes or/and optimize=yes
ifeq ($(optimize),yes)
ifeq ($(debug),yes) #if both are set!
CFLAGS_U += $(CFLAGS_UOPTD)
else
CFLAGS_U += $(CFLAGS_UOPT)
endif
else #debug set by default
CFLAGS_U += -g
endif

DIRS_U := api
INCLUDES_U := include/api include $(BUILDDIR)

# Memory allocator for programs: 'GMA' or 'FIRST_FIT'
MEM_ALLOCATOR_FOR_USER = $(GMA)

MAX_USER_DESCRIPTORS = 10

# Programs to include in compilation
PROGRAMS = pci_enumeration

# Define each program with:
# prog_name =	1_starting-routine	2_directories
hello		= hello_world		programs/hello_world
timer		= timer			programs/timer
signals		= signals		programs/signals
keyboard	= keyboard		programs/keyboard
shell		= shell			programs/shell
args		= arguments		programs/arguments
uthreads	= user_threads		programs/user_threads
threads		= threads		programs/threads
semaphores	= semaphores		programs/semaphores
monitors	= monitors		programs/monitors
messages	= messages		programs/messages
sse_test	= sse_test		programs/sse_test
segm_fault	= segm_fault		programs/segm_fault
rr		= round_robin		programs/round_robin
run_all		= run_all		programs/run_all
pci_enumeration	= pci_enumeration	programs/pci_enumeration
eth_example	= eth_example	programs/eth_example

common		= null			api

CCPROGRAMS = common $(PROGRAMS)

#initial program to be started at end of kernel initialization
START_WITH ?= pci_enumeration
PROG_START_FUNC = $(START_WITH)

QEMU_MEM = $(shell echo $$(( ($(SYSTEM_MEMORY)-1)/1048576+1 )) )
QEMU = qemu-system-$(ARCH)
QFLAGS = -m $(QEMU_MEM)M -no-kvm-irqchip -no-kvm -serial stdio -display none
# If using VGA_TXT output remove "-display none" from qemu arguments
QMSG = "Starting qemu"

DEBUG_GDB = gdb

Now, it's a bit of a mess, from people who have worked on the project before me, so here's the relevant part, where the guests are run, with the variables expanded to their values:

net_qemu: all
	@echo Starting qemu and network $(shell echo $$(( (0x800000-1)/1048576+1 )) )
	@xterm -fg black -bg white -e qemu-system-i386 -m $(shell echo $$(( (0x800000-1)/1048576+1 )) )M -no-kvm-irqchip -no-kvm -serial stdio -display none -kernel $(BUILDDIR)/$(KERNEL_FILE_NAME) -device rtl8139,netdev=vlan,mac=52:54:00:12:34:56 -netdev socket,id=vlan,listen=localhost:1234 &
	@xterm -fg black -bg white -e qemu-system-i386 -m $(shell echo $$(( (0x800000-1)/1048576+1 )) )M -no-kvm-irqchip -no-kvm -serial stdio -display none -kernel $(BUILDDIR)/$(KERNEL_FILE_NAME) -device rtl8139,netdev=vlan,mac=52:54:00:12:34:57 -netdev socket,id=vlan,connect=localhost:1234 &

All the files were the same when trying both on Ubuntu and on Arch. Ubuntu qemu version is 2.5, while the Arch version is 2.10.1. Did I miss something? Did qemu remove support for this?

Offline

#2 2017-12-04 06:40:02

nesk
Member
Registered: 2011-03-31
Posts: 181

Re: Qemu networking issue between two guests

Dafta wrote:

Hi everyone!
Did qemu remove support for this?

Looks like they've changed syntax for "-netdev socket" - there's no listen/connect directives now. Check man qemu on 2.10.1.

Offline

#3 2017-12-04 16:15:06

Dafta
Member
Registered: 2016-02-17
Posts: 10

Re: Qemu networking issue between two guests

Well, from what I can see in man, the listen and connect directives are still there. But I've tried without them, and now both guests don't even start, saying:

net_init_socket: Assertion 'sock->has_udp' has failed.

This was the previous qemu directive, which also works on Ubuntu but not on arch:

net_qemu: all
	@echo Starting qemu and network $(shell echo $$(( (0x800000-1)/1048576+1 )) )
	@xterm -fg black -bg white -e qemu-system-i386 -m $(shell echo $$(( (0x800000-1)/1048576+1 )) )M -no-kvm-irqchip -no-kvm -serial stdio -display none -kernel $(BUILDDIR)/$(KERNEL_FILE_NAME) -net nic,vlan=1,model=rtl8139,macaddr=52:54:00:12:34:56 -net socket,vlan=1,listen=localhost:1234 &
	@xterm -fg black -bg white -e qemu-system-i386 -m $(shell echo $$(( (0x800000-1)/1048576+1 )) )M -no-kvm-irqchip -no-kvm -serial stdio -display none -kernel $(BUILDDIR)/$(KERNEL_FILE_NAME) -net nic,vlan=1,model=rtl8139,macaddr=52:54:00:12:34:57 -net socket,vlan=1,connect=localhost:1234 &

EDIT: I have confirmed it to be an Arch issue, as it works on Ubuntu 17.10 with the same qemu version, 2.10.1.

Last edited by Dafta (2017-12-04 16:46:08)

Offline

Board footer

Powered by FluxBB