Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel' of ssh://palacios@newskysaw.cs.northwestern.edu/home/palacios...
Jack Lange [Tue, 12 Jan 2010 20:39:21 +0000 (14:39 -0600)]
manual/guest_build/Palacios_Guest_Build.tex
palacios/include/palacios/vmm_vnet.h
palacios/src/devices/netdisk.c
palacios/src/devices/pci_passthrough.c
palacios/src/palacios/vmm_vnet.c

index 8f3e319..d772496 100644 (file)
 
 \section{Getting the guest image build tools}
 
-In order to build the bootable guest iso image, we need to build a Linux kernel
-image from source and an initial file system containing a set of useful binary
-files which will be described in the following text. We will use a new directory
-for demonstration; the root directory for the following examples is
-\verb+test/+:
+In order to build the bootable guest ISO image, we need to build a Linux kernel
+ from source and an initial ramdisk file system containing a set of useful
+tools. We will use a new directory for demonstration; the root directory for the
+following examples is ``\verb+test/+":
 
 \begin{verbatim}
-mkdir test/
-cd test/
+[jdoe@newskysaw ~]$ mkdir test/
 \end{verbatim}
 
-\vspace{10pt}
 \noindent
 There are a set of tools and sources that are useful for the guest image
-building procedure. You can checkout these resources from our git repositories;
-to check them out to your local \verb+test/+ directory use the following
-commands: 
+building procedure. You can obtain these resources from our git repositories.
+Change to the ``\verb+test/+" directory and clone the resources:
 
 \begin{verbatim}
-git clone http://hornet.cs.northwestern.edu:9005/busybox
-git clone http://hornet.cs.northwestern.edu:9005/initrd
-git clone http://hornet.cs.northwestern.edu:9005/linux-2.6.30.y
+[jdoe@newskysaw test]$ git clone http://hornet.cs.northwestern.edu:9005/busybox
+[jdoe@newskysaw test]$ git clone http://hornet.cs.northwestern.edu:9005/initrd
+[jdoe@newskysaw test]$ git clone http://hornet.cs.northwestern.edu:9005/linux-2.6.30.y
 \end{verbatim}
 
 \section{Building the ramdisk filesystem}
+The guest requires an initial ramdisk filesystem. Jack has made one that you can
+leverage; it is temporarily located in his home directory.  You will need sudo
+or root access to create the device files when you unpack the archive:
 
-% Introductory text explaining why a ramdisk filesystem is necessary, and a
-% small blurb about what it is. Mostly this is necessary because the
-% introduction said that the "useful binary files" would be described.
+\begin{verbatim}
+[jdoe@newskysaw test]$ cp /home/jarusl/initrd/disks/v3vee_initramfs.tar.gz .
+[jdoe@newskysaw test]$ sudo tar -C initrd -xzf v3vee_initramfs.tar.gz
+\end{verbatim}
+
+\noindent
+If you require a custom initial ramdisk filesystem, change to the
+``\verb|initrd/initramfs/|" directory and perform the following steps:
 
-Jack has made an initial ramdisk system that you can leverage. The file is
-temporarily in the directory
-\verb|/home/jarusl/initrd/disks/v3vee_initramfs.tar.gz| on the
-newskysaw machine. If you require a custom initial ramdisk, copy the directories
-and files that you require into the \verb+initramfs+/ directory. For minimal
-device support, copy theses devices into the \verb+initramfs/dev/+ directory:
-console, ram, null, tty (you probably need root privilege to copy and make the
-device files).
+\begin{verbatim}
+[jdoe@newskysaw initramfs]$ mkdir -p proc sys var/log
+\end{verbatim}
+
+\noindent
+Edit the ``\verb|init_task|" script and uncomment these lines:
+
+\begin{verbatim}
+#mknod /dev/tty0 c 4 0
+#mknod /dev/tty1 c 4 1
+#mknod /dev/tty2 c 4 2
+\end{verbatim}
+
+\pagebreak
+
+\noindent
+Create the ``\verb|console|" device. If you have sudo or root access it is
+possible to create this device manually:
+
+\begin{verbatim}
+[jdoe@newskysaw initramfs]$ sudo mknod dev/console c 5 1
+[jdoe@newskysaw initramfs]$ sudo chmod 0600 dev/console
+\end{verbatim}
+
+\noindent
+If you do not have sudo or root access it is still possible to create the
+``\verb|console|" device indirectly through the kernel build.  Change to the
+``\verb|initrd/|" directory and create a file called ``\verb|root_files|". Add
+the following line:
+
+\begin{verbatim}
+nod /dev/console 0600 0 0 c 5 1
+\end{verbatim}
+
+\noindent
+The ``\verb|root_files|" file is used when building the Linux kernel in the
+section Configuring and building the Linux kernel. Finally, create any
+additional directories and copy any additional files that you need. Your initial
+ramdisk filesystem is prepped and ready for installation of the BusyBox tools as
+described in the section Configuring and installing BusyBox tools.
 
 
 
@@ -75,7 +111,7 @@ device files).
   \end{center}
 \end{figure}
 
-\begin{figure}[h]
+\begin{figure}[ht]
   \begin{center}
     \colfigsize\epsffile{busyboxConf2.eps}
   \end{center}
@@ -87,37 +123,40 @@ device files).
 
 BusyBox is a software application released as Free software under the GNU GPL
 that provides many standard Unix tools. BusyBox combines tiny versions of many
-common UNIX utilities into a single small executable. For more details on
-BusyBox, visiting \url{http://busybox.net}. To configure BusyBox, in the
-\verb+busybox/+ directory, type the following:
+common UNIX utilities into a single, small executable. For more details on
+BusyBox visit \url{http://busybox.net}. To configure BusyBox, in the
+``\verb+busybox/+" directory, type the following:
 
 \begin{verbatim}
-make menuconfig
+[jdoe@newskysaw busybox]$ make menuconfig
 \end{verbatim}
 
+\noindent
 or
 
 \begin{verbatim}
-make xconfig (X version)
+[jdoe@newskysaw busybox]$ make xconfig
 \end{verbatim}
 
-\vspace{10pt}
 \noindent
-You can add the tools you need into the guest image. There are two required
-configuration options: in ``\verb|BusyBox settings->Build Options|", check the 
-``\verb|Build BusyBox as a static binary|" option, and in
-``\verb|BusyBox settings->Installation Options|", set the
-``\verb|Busybox installation prefix|" to the path of your \verb|initramfs|
-directory, as shown in figure \ref{fig:busyboxcf2}. After you finish configuring
-BusyBox, save your configuration and quit the window. Then, to make the BusyBox
-tools, type the following:
+The BusyBox tools will be installed in the guest's initial ramdisk filesystem;
+you can add any tools that you need. There are two required configuration
+options. In the
+``\verb|BusyBox settings->Build Options|" menu check the
+``\verb|Build BusyBox as a static binary (no shared libs)|" option, as shown in
+figure \ref{fig:busyboxcf1}, and in the
+``\verb|BusyBox settings->Installation Options|" menu set the
+``\verb|Busybox installation prefix|" to the path of the
+``\verb|initrd/initramfs|" directory, as shown in figure \ref{fig:busyboxcf2}.
+After you finish configuring BusyBox, save your configuration and quit the
+window. Then, to make the BusyBox tools, type the following:
 
 \begin{verbatim}
-make
+[jdoe@newskysaw busybox]$ make
 \end{verbatim}
-Install the tools to your initial ramdisk directory:
+Install the tools to the guest's initial ramdisk filesystem directory:
 \begin{verbatim}
-make install
+[jdoe@newskysaw busybox]$ make install
 \end{verbatim}
 
 \begin{figure}[ht]
@@ -129,74 +168,159 @@ make install
 \end{figure}
 
 
-\section{Configuring and compiling the Linux kernel}
+\section{Configuring and building the Linux kernel}
 
-Change to the \verb|linux-2.6.30.y/| directory (or whatever your Linux kernel
-source directory is named) and type the following:
+The following procedure demonstrates how to configure and build a 32-bit Linux
+kernel. Change to the ``\verb|linux-2.6.30.y/|" directory. There is a custom
+configuration file ``\verb|jrl-default-config|" which is configured with minimal
+kernel options (all unnecessary options are removed to keep the guest booting
+process fast). If you are using the custom configuration file type the
+following:
 
 \begin{verbatim}
-make menuconfig
+[jdoe@newskysaw linux-2.6.30.y]$ cp jrl-default-config .config
 \end{verbatim}
-or
+
+\noindent
+Configure the kernel to meet your requirements. For more on configuring and
+building Linux kernels, check online. Type the following:
+
 \begin{verbatim}
-make xconfig (X version)
+[jdoe@newskysaw linux-2.6.30.y]$ make ARCH=i386 menuconfig
 \end{verbatim}
 
-\vspace{10pt}
 \noindent
-Configure the kernel to meet your requirements. There is a custom configuration
-file \verb|jrl-default-config| which is configured with minimal kernel options
-(all unnecessary options are removed to keep the guest booting process fast).
-For more on configuring and compiling Linux kernel images, check online.
+or
+
+\begin{verbatim}
+[jdoe@newskysaw linux-2.6.30.y]$ make ARCH=i386 xconfig
+\end{verbatim}
 
-\vspace{5pt}
 \noindent
 The kernel must be configured with the initial ramdisk file system directory
-(e.g. \verb|initrd/initramfs|): in the ``\verb|General setup|" menu under
+(e.g. ``\verb|initrd/initramfs/|"): in the ``\verb|General setup|" menu under
 option
 ``\verb|Initial RAM filesystem and RAM disk support|" set the
-``\verb|Initramfs source file(s)|" option to the path of your \verb|initramfs|
-directory as shown in figure \ref{fig:linuxcf}. When you are finished
-configuring the kernel, save your configuration, and type the following:
+``\verb|Initramfs source file(s)|" option to the path of the
+``\verb|initrd/initramfs/|" directory, as shown in figure \ref{fig:linuxcf}.
+Additionally, if you are using the ``\verb|root_files|" file to create devices
+files, add the ``\verb|root_files|" file path, separated by a space, after the
+initial ramdisk filesystem directory. When you are finished configuring the
+kernel, save your configuration, and type the following:
+
 \begin{verbatim}
-make
+[jdoe@newskysaw linux-2.6.30.y]$ make ARCH=i386
 \end{verbatim}
-Some blurb about where the kernel image is...
 
+\noindent
+The Linux kernel can be found here: ``\verb|arch/x86/boot/bzImage|". The initial
+ramdisk filesystem can be found here: ``\verb|usr/initramfs_data.cpio|". The
+Linux kernel and initial ramdisk filesystem are used to build the Linux ISO
+image in the section Building the Linux ISO image.
 
-\section{Configuring guest devices}
 
-Checkout the updated Palacios repository to \verb|palacios/|.  (You can find
-instructions for checking out the Palacios and Kitten repositories at
-\url{http://www.v3vee.org/palacios/}). To build the guest VM creator tool,
-change to the \verb|palacios/utils/guest_creator| directory and type the
-following:
+\section{Building the Linux ISO image}
+
+The Linux ISO image is a bootable image containing the Linux kernel, initial
+ramdisk filesystem, a boot loader, and a boot loader configuration file. For
+this procedure, we'll use the ``\verb|test/iso/|" directory as the Linux ISO
+build directory:
+
+\begin{verbatim}
+[jdoe@newskysaw test]$ mkdir iso
+\end{verbatim}
+
+\noindent
+Change to the ``\verb|iso/|" directory and copy the required files:
 
 \begin{verbatim}
-make
+[jdoe@newskysaw iso]$ cp ../linux-2.6.30.y/arch/x86/boot/bzImage vmlinuz
+[jdoe@newskysaw iso]$ cp ../linux-2.6.30.y/usr/initramfs_data.cpio initramfs
+[jdoe@newskysaw iso]$ cp /usr/lib/syslinux/isolinux.bin .
 \end{verbatim}
 
-\vspace{10pt}
 \noindent
-You will get the \verb|build_vm| executable. The guest configuration file uses
-XML. A sample configuration file is provided: \verb|default.xml|.
+Create a file called ``\verb|isolinux.cfg|" and add the following lines:
+
+\begin{verbatim}
+default linux
+prompt 0
+
+label linux
+  kernel vmlinuz
+  append initrd=initrd
+\end{verbatim}
 
-\vspace{5pt}
 \noindent
-***Various information about how to configure the VM.***
+Change back to the ``\verb|test/|" directory and build the Linux ISO image:
+
+\begin{verbatim}
+[jdoe@newskysaw test]$ mkisofs -o linux.iso -b isolinux.bin -no-emul-boot \
+-boot-load-size 4 -boot-info-table -iso-level 2 -input-charset UTF-8 iso/
+\end{verbatim}
 
-\vspace{5pt}
 \noindent
-Once you have configured the VM, type the following to build the full guest VM
-image:
+The ``\verb|linux.iso|'' file is the Linux ISO image and is used to build the
+guest image in the section Configuring and building the guest image:
+
 \begin{verbatim}
-./build_vm myconfig.xml -o guest.iso
+[jdoe@newskysaw test]$ file linux.iso
+linux.iso: ISO 9660 CD-ROM filesystem data 'CDROM                          ' (bootable)
 \end{verbatim}
-where \verb+myconfig.xml+ is your guest configuration file, and \verb+guest.iso+
-is the output image file that will be used to configure kitten in the next
-section.
 
 
+\section{Configuring and building the guest image}
+
+Checkout the updated Palacios repository to the ``\verb|palacios/|" directory.
+(You can find instructions for checking out the Palacios repository at
+\url{http://www.v3vee.org/palacios/}). The guest creator utility is required for
+building the guest image. Change to the ``\verb|palacios/utils/guest_creator|"
+directory and build the guest creator utility:
+
+\begin{verbatim}
+[jdoe@newskysaw guest_creator]$ make
+\end{verbatim}
+
+\noindent
+You will get the ``\verb|build_vm|" utility:
+\begin{verbatim}
+[jdoe@newskysaw guest_creator]$ file build_vm
+build_vm: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked
+(uses shared libs), for GNU/Linux 2.6.9, not stripped
+\end{verbatim}
+
+\noindent
+The guest configuration file is written in XML. A sample configuration file is
+provided: ``\verb|default.xml|". Make a copy of the default configuration file
+named ``\verb|myconfig.xml|" and edit the configuration elements that you are
+interested in (if a device is included in the guest configuration file, it
+must be configured in the section Configuring and building Palacios or the guest
+will not boot). Of particular importance is the ``\verb|files|" element. Comment
+out this attribute:
+
+\begin{verbatim}
+<file id="boot-cd" filename="/home/jarusl/image.iso" />
+\end{verbatim}
+
+\noindent
+Add an attribute that specifies the location of the Linux ISO image:
+
+\begin{verbatim}
+<file id="boot-cd" filename="../../../linux.iso" />
+\end{verbatim}
+
+\noindent
+When you are finished editing the guest configuration save the configuration
+file. The guest image consists of the guest configuration file and the Linux
+ISO image. Build the guest image with the guest creator utility:
+
+\begin{verbatim}
+[jdoe@newskysaw guest_creator]$ ./build_vm myconfig.xml -o guest.iso
+\end{verbatim}
+
+\noindent
+The guest image, ``\verb+guest.iso+", is embedded in Kitten's
+``\verb|init_task|" in the section Configuring and building Kitten.
 
 
 \pagebreak
@@ -208,7 +332,7 @@ section.
   \label{fig:kittencf}
 \end{figure}
 
-\begin{figure}[h]
+\begin{figure}[ht]
   \begin{center}
     \colfigsize\epsffile{kittenConf2.eps}
   \end{center}
@@ -222,78 +346,79 @@ section.
 
 You can find the detailed manual of getting and building Palacios and Kitten 
 from scratch in the Palacios website (\url{http://www.v3vee.org/palacios}). Here
-we only give the specific requirements related to the booting guest procedure.
-To configure Palacios, in the Palacios root directory (i.e. \verb+palacios/+)
-type the following:
+we only give the specific requirements related to the procedure of booting the
+guest. To configure Palacios, change to the ``\verb|test/palacios/|" directory
+and type the following:
 
 \begin{verbatim}
-make config
+[jdoe@newskysaw palacios]$ make menuconfig
 \end{verbatim}
+
+\noindent
 or
+
 \begin{verbatim}
-make xconfig
+[jdoe@newskysaw palacios]$ make xconfig
 \end{verbatim}
 
-\vspace{10pt}
 \noindent
-When you have configured the components you want to build into Palacios type
-the following:
+Don't forget to include the devices that your guest image requires. When you
+have configured the components you want to build into Palacios, save the
+configuration and close the window. To build Palacios type the following:
 
 \begin{verbatim}
-make
+[jdoe@newskysaw palacios]$ make
 \end{verbatim}
 or
 \begin{verbatim}
-make all
+[jdoe@newskysaw palacios]$ make all
 \end{verbatim}
 
-\vspace{10pt}
 \noindent
-Once the Palacios static library has been built you can find the library file
-\verb+libv3vee.a+ in the Palacios root directory.
+Once the Palacios static library has been built you can find the library file,
+``\verb+libv3vee.a+", in the Palacios root directory.
 
 \subsection*{Configuring and building Kitten}
 
-To build Kitten, first configure it in as you did Palacios. Change to the
-\verb+kitten/+ directory and type the following:
+Configure Kitten. Change to the ``\verb+test/kitten/+" directory and type the
+following:
 
 \begin{verbatim}
-make config
+[jdoe@newskysaw kitten]$ make menuconfig
 \end{verbatim}
+
+\noindent
 or
+
 \begin{verbatim}
-make xconfig
+[jdoe@newskysaw kitten]$ make xconfig
 \end{verbatim}
 
-\vspace{10pt}
 \noindent
 Under the ``\verb|Virtualization|" menu select the
 ``\verb|Include Palacios virtual machine monitor|" option. Set the
-``\verb|Path to pre-built Palacios tree|" option to the path of your Palacios
-build, and set the ``\verb|Path to guest ISO image|" option to the path
-containing the guest image that was built in the Configuring guest devices
-section of this manual.
-
-\vspace{10pt}
-\noindent
-After configuring Kitten, to build Kitten, type the following:
+``\verb|Path to pre-built Palacios tree|" option to the Palacios build tree
+path, ``\verb|..\palacios|", as shown in figure \ref{fig:kittencf}. Set the
+``\verb|Path to guest OS ISO image|" option to the guest image path,\\
+''\verb|../palacios/utils/guest_creator/guest.iso|'', as shown in figure
+\ref{fig:kittencf2}.  When you have finished configuring Kitten, save the
+configuration and close the window. To build Kitten type the following:
 
 \begin{verbatim}
-make isoimage
+[jdoe@newskysaw kitten]$ make isoimage
 \end{verbatim}
 
-\vspace{10pt}
 \noindent
-This builds the bootable ISO image file with guest OS, Palacios and Kitten.
-The ISO file is located in \verb+kitten/arch/x86_64/boot/image.iso+.
+This builds the bootable ISO image file with guest image, Palacios, and Kitten.
+The ISO file is located in ``\verb+kitten/arch/x86_64/boot/image.iso+".
 
 \pagebreak
 \noindent
-You have successfully created a guest CD image file that can be booted on a
-machine. You can boot the file on Qemu using the following sample command:
+You have successfully created an ISO image file that can be booted on a machine.
+You can boot the file on Qemu using the following sample command:
 
 \begin{verbatim}
-/opt/vmm-tools/qemu/bin/qemu-system-x86_64 \
+[jdoe@newskysaw test]$ /opt/vmm-tools/qemu/bin/qemu-system-x86_64 \
         -smp 1 \
         -m 2047 \
         -serial file:./serial.out \
@@ -301,7 +426,6 @@ machine. You can boot the file on Qemu using the following sample command:
         < /dev/null
 \end{verbatim}
 
-\vspace{10pt}
 \noindent
 We have finished the entire procedure for building a guest image and booting it
 on the Palacios VMM. For more updated details, check the Palacios website
index 51d99c4..c94c6c6 100644 (file)
@@ -56,8 +56,43 @@ struct routing_entry{
 }__attribute__((packed));
 
 
+struct eth_header {
+    uchar_t dest[6];
+    uchar_t src[6];
+    uint16_t type; // indicates layer 3 protocol type
+}__attribute__((packed));
+
+struct ip_header {
+    uint8_t version: 4;
+    uint8_t hdr_len: 4;
+    uchar_t tos;
+    uint16_t total_len;
+    uint16_t id;
+    uint8_t flags:     3;
+    uint16_t offset: 13;
+    uchar_t ttl;
+    uchar_t proto;
+    uint16_t cksum;
+    uint32_t src_addr;
+    uint32_t dst_addr;
+}__attribute__((packed));
+
+struct udp_header {
+    uint16_t src_port;
+    uint16_t dst_port;
+    uint16_t len;
+    uint16_t csum;//set to zero, disable the xsum
+}__attribute__((packed));
+
+struct udp_link_header {
+    struct eth_header eth_hdr;
+    struct ip_header ip_hdr;
+    struct udp_header udp_hdr;
+}__attribute__((packed));
+
+#define DEVICE_NAME_LEN 20
 struct vnet_if_device {
-    char name[50];
+    char name[DEVICE_NAME_LEN];
     uchar_t mac_addr[6];
     struct vm_device *dev;
     
@@ -67,14 +102,12 @@ struct vnet_if_device {
 }__attribute__((packed));
 
 
-#define VNET_HEADER_LEN  64
 struct vnet_if_link {
     prot_type_t pro_type; //protocal type of this link
     unsigned long dest_ip;
     uint16_t dest_port;
 
-    uchar_t vnet_header[VNET_HEADER_LEN]; //header applied to the packet in/out from this link
-    uint16_t hdr_len; 
+    struct udp_link_header vnet_header; //header applied to the packet in/out from this link
 
     int (*input)(uchar_t *data, uint32_t len, void *private_data);
     
@@ -95,7 +128,8 @@ struct link_entry {
 }__attribute__((packed));
 
 
-int v3_vnet_send_pkt(uchar_t *buf, int length);
+int v3_vnet_send_rawpkt(uchar_t *buf, int len, void *private_data);
+int v3_vnet_send_udppkt(uchar_t *buf, int len, void *private_data);
 //int vnet_register_device(struct vm_device *vdev, 
 //                      char *dev_name, 
 //                      uchar_t mac[6], 
index 552de56..3052a9b 100644 (file)
@@ -132,7 +132,7 @@ static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_
     }
 
     if (ret_len != length) {
-       PrintError("Read length mismatch (req=%d) (result=%d)\n", length, ret_len);
+       PrintError("Read length mismatch (req=%llu) (result=%u)\n", length, ret_len);
        return -1;
     }
 
index 18e4ef4..a799e1f 100644 (file)
@@ -331,7 +331,11 @@ static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
     struct pt_bar * pbar = &(state->phys_bars[bar_num]);
     struct pt_bar * vbar = &(state->virt_bars[bar_num]);
 
-    PrintDebug("Bar update src=0x%x\n", *src);
+    PrintDebug("Bar update: bar_num=%d, src=0x%x\n", bar_num,*src);
+    PrintDebug("vbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",vbar->size, vbar->type, vbar->addr, vbar->val);
+    PrintDebug("pbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",pbar->size, pbar->type, pbar->addr, pbar->val);
+
+
 
     if (vbar->type == PT_BAR_NONE) {
        return 0;
index 72d4049..bf3b2c6 100644 (file)
@@ -34,8 +34,9 @@
 
 
 struct ethernet_pkt {
-    uint32_t size;
+    uint32_t size; //size of data
     uint16_t type;
+    struct udp_link_header ext_hdr; //possible externel header to applied to data before sent
     char data[ETHERNET_PACKET_LEN];
 };
 
@@ -44,7 +45,7 @@ struct ethernet_pkt {
 struct in_pkt_header {
     char ethernetdest[6];
     char ethernetsrc[6];
-    unsigned char ethernettype[2]; // indicates layer 3 protocol type
+    unsigned char ethernettype[2]; //layer 3 protocol type
     char ip[20];
 };
 
@@ -88,7 +89,7 @@ struct route_cache_entry {
 static struct hashtable * g_route_cache; 
 
 
-static void print_packet(char * pkt, int size) {
+static void print_packet(uchar_t *pkt, int size) {
     PrintDebug("Vnet: print_data_packet: size: %d\n", size);
     v3_hexdump(pkt, size, NULL, 0);
 }
@@ -108,9 +109,27 @@ static void print_device_addr(char * ethaddr) {
 } 
 #endif
 
+static uint16_t ip_xsum(struct ip_header *ip_hdr, int hdr_len){
+    long sum = 0;
 
-// network connection functions 
-static inline void ethernet_packet_init(struct ethernet_pkt * pt, const char * data, const size_t size) {
+    uint16_t *p = (uint16_t*) ip_hdr;
+    while(hdr_len > 1){
+        sum += *(p++);
+        if(sum & 0x80000000)
+            sum = (sum & 0xFFFF) + (sum >> 16);
+            hdr_len -= 2;
+        }
+    if(hdr_len) 
+        sum += (uint16_t) *(uchar_t *)p;
+          
+    while(sum>>16)
+        sum = (sum & 0xFFFF) + (sum >> 16);
+
+    return (uint16_t)~sum;
+}
+
+static inline void ethernet_packet_init(struct ethernet_pkt *pt, uchar_t *data, const size_t size) {
     pt->size = size;
     memcpy(pt->data, data, size);
 }
@@ -218,6 +237,7 @@ static int look_into_cache(route_hashkey_t hashkey, int * matches) {
     return n_matches;
 }
 
+#ifdef CONFIG_DEBUG_VNET
 static inline uint8_t hex_nybble_to_nybble(const uint8_t hexnybble) {
     uint8_t x = toupper(hexnybble);
 
@@ -246,8 +266,9 @@ static inline void mac_to_string(char mac[6], char * buf) {
             mac[0], mac[1], mac[2],
             mac[3], mac[4], mac[5]);
 }
+#endif
 
-static int add_link_entry(struct link_entry * link) {
+static int __add_link_entry(struct link_entry * link) {
     int idx;
     
     for (idx = 0; idx < MAX_LINKS; idx++) {
@@ -263,7 +284,7 @@ static int add_link_entry(struct link_entry * link) {
     return -1;
 }
 
-static int add_route_entry(struct routing_entry * route) {
+static int __add_route_entry(struct routing_entry * route) {
     int idx;
     
     for (idx = 0; idx < MAX_ROUTES; idx++) {
@@ -308,7 +329,7 @@ static int vnet_add_route_entry(char src_mac[6],
     new_route->src_link_idx = src;
     new_route->src_type = src_type;
 
-    if ((idx = add_route_entry(new_route)) == -1) {
+    if ((idx = __add_route_entry(new_route)) == -1) {
        PrintError("Could not add route entry\n");
         return -1;
     }
@@ -318,7 +339,7 @@ static int vnet_add_route_entry(char src_mac[6],
     return idx;
 }
 
-static void * delete_link_entry(int index) {
+static void * __delete_link_entry(int index) {
     struct link_entry * link = NULL;
     void * ret = NULL;
     link_type_t type;
@@ -386,11 +407,11 @@ static int find_route_entry(char src_mac[6],
     return -1;
 }
 
-static int delete_route_entry(int index) {
+static int __delete_route_entry(int index) {
     struct routing_entry * route;
 
     if ((index >= MAX_ROUTES) || (g_routes.routes[index] == NULL)) {
-       PrintError("Could not find route entry %d\n", index);
+       PrintDebug("VNET: wrong index in delete route entry %d\n", index);
        return -1;
     }
 
@@ -417,11 +438,11 @@ static int vnet_delete_route_entry_by_addr(char src_mac[6],
                                 dest_mac_qual, link_idx, type, src, src_type);
     
     if (index == -1) {
-       PrintError("Error deleting route entry by addr\n");
+       PrintDebug("VNET: wrong in delete route entry %d\n", index);
        return -1;
     }
     
-    return delete_route_entry(index);
+    return __delete_route_entry(index);
 }
 
 static int match_route(uint8_t * src_mac, 
@@ -559,102 +580,7 @@ static int match_route(uint8_t * src_mac,
     return no;
 }
 
-#if 0
-// TODO: To be removed
-static int process_udpdata() 
-{
-    struct ethernet_pkt * pt;
-
-    uint32_t dest = 0;
-    uint16_t remote_port = 0;
-    SOCK link_sock = g_udp_sockfd;
-    int length = sizeof(struct ethernet_pkt) - (2 * sizeof(int));   //minus the "size" and "type" 
-
-    //run in a loop to get packets from outside network, adding them to the incoming packet queue
-    while (1) {
-       pt = (struct ethernet_pkt *)V3_Malloc(sizeof(struct ethernet_pkt));
-
-       if (pt == NULL){
-           PrintError("Vnet: process_udp: Malloc fails\n");
-           continue;
-       }
-       
-       PrintDebug("Vnet: route_thread: socket: [%d]. ready to receive from ip [%x], port [%d] or from VMs\n", link_sock, (uint_t)dest, remote_port);
-       pt->size = V3_RecvFrom_IP( link_sock, dest, remote_port, pt->data, length);
-       PrintDebug("Vnet: route_thread: socket: [%d] receive from ip [%x], port [%d]\n", link_sock, (uint_t)dest, remote_port);
-       
-       if (pt->size <= 0) {
-           PrintDebug("Vnet: process_udp: receiving packet from UDP fails\n");
-           V3_Free(pt);
-           return -1;
-       }
-       
-       PrintDebug("Vnet: process_udp: get packet\n");
-       print_packet(pt->data, pt->size);
-    }
-}
-
-// TODO: To be removed
-static int indata_handler( )
-{
-    if (!use_tcp) {
-       process_udpdata();        
-    }
-
-    return 0;   
-}
-
-// TODO: To be removed
-static int start_recv_data()
-{
-    if (use_tcp){
-       
-    } else {
-       SOCK udp_data_socket;
-       
-       if ((udp_data_socket = V3_Create_UDP_Socket()) < 0){
-           PrintError("VNET: Can't setup udp socket\n");
-           return -1; 
-       }
-       PrintDebug("Vnet: vnet_setup_udp: get socket: %d\n", udp_data_socket);
-       g_udp_sockfd = udp_data_socket;
-       
-       store_topologies(udp_data_socket);
-       
-       if (V3_Bind_Socket(udp_data_socket, vnet_udp_port) < 0){ 
-           PrintError("VNET: Can't bind socket\n");
-           return -1;
-       }
-       PrintDebug("VNET: vnet_setup_udp: bind socket successful\n");
-    }
-    
-    V3_CREATE_THREAD(&indata_handler, NULL, "VNET_DATA_HANDLER");
-    return 0;
-}
-
-static void store_test_topologies(SOCK fd) 
-{
-    int i;
-    int src_mac_qual = MAC_ANY;
-    int dest_mac_qual = MAC_ANY;
-    uint_t dest;
-#ifndef VNET_SERVER
-    dest = (0 | 172 << 24 | 23 << 16 | 1 );
-    PrintDebug("VNET: store_topologies. NOT VNET_SERVER, dest = %x\n", dest);
-#else
-    dest = (0 | 172 << 24 | 23 << 16 | 2 );
-    PrintDebug("VNET: store_topologies. VNET_SERVER, dest = %x\n", dest);
-#endif
-
-    int type = UDP_TYPE;
-    int src = 0;
-    int src_type= LINK_ANY; //ANY_SRC_TYPE
-    int data_port = 22;
-}
-
-#endif
-
-static int handle_one_pkt(struct ethernet_pkt * pkt) {
+static int handle_one_pkt(struct ethernet_pkt *pkt) {
     int src_link_index = -1;   //the value of src_link_index of udp always is 0
     int i;
     char src_mac[6];
@@ -687,81 +613,109 @@ static int handle_one_pkt(struct ethernet_pkt * pkt) {
     
     num_matched_routes = look_into_cache((route_hashkey_t)hash_key, matches);
     
-
     if (num_matched_routes == -1) {  
-       // no match
-
+    // no match in the cache
         num_matched_routes = match_route(src_mac, dst_mac, LINK_ANY, src_link_index, matches);
        
-       if (num_matched_routes > 0) {
-           add_route_to_cache(hash_key, num_matched_routes,matches);      
-       }
+        if (num_matched_routes > 0) {
+            add_route_to_cache(hash_key, num_matched_routes,matches);      
+        }
     }
     
     PrintDebug("Vnet: HandleDataOverLink: Matches=%d\n", num_matched_routes);
     
-    for (i = 0; i < num_matched_routes; i++) {
+    for (i = 0; i < num_matched_routes; i++) {//send packet to all destinations
         int route_index = -1;
         int link_index = -1;
-       int pkt_len = 0;
-       struct link_entry * link = NULL;
+        int pkt_len = 0;
+        struct link_entry * link = NULL;
 
         route_index = matches[i];
        
         PrintDebug("Vnet: HandleDataOverLink: Forward packet from link according to Route entry %d\n", route_index);
        
-       link_index = g_routes.routes[route_index]->link_idx;
+        link_index = g_routes.routes[route_index]->link_idx;
 
-       if ( (link_index < 0) || 
+        if ((link_index < 0) || 
             (link_index > MAX_LINKS) || 
             (g_links.links[link_index] == NULL)) {
-           continue;
-       }
-       
-       link = g_links.links[link_index];
-
+            continue;
+        }
        
-       pkt_len = pkt->size;
-
+        link = g_links.links[link_index];
+        pkt_len = pkt->size;
         if (g_routes.routes[route_index]->link_type == LINK_EDGE) {
-           
-            // TODO: apply the header in the beginning of the packet to be sent
-           if ((link->dst_link->input(pkt->data, pkt_len, NULL)) != pkt_len) {
-               PrintError("LEI --  WHAT IS THE ERROR HERE?\n");
-               return -1;
-           }
+
+             //apply the header in the beginning of the packet to be sent
+            if (link->dst_link->pro_type == UDP_TYPE) {
+                struct udp_link_header *hdr = &(link->dst_link->vnet_header);
+                struct ip_header *ip = &hdr->ip_hdr;
+                struct udp_header *udp = &hdr->udp_hdr;
+                  udp->len = pkt_len + sizeof(struct udp_header);
+                  ip->total_len = pkt_len + sizeof(struct udp_header) + sizeof(struct ip_header);
+                  ip->cksum = ip_xsum(ip, sizeof(struct ip_header));
+               
+                int hdr_size = sizeof(struct udp_link_header);
+                memcpy(&pkt->ext_hdr, hdr, hdr_size);
+
+                pkt_len += hdr_size;
+                if ((link->dst_link->input((uchar_t *)&pkt->ext_hdr, pkt_len, link->dst_link->private_data)) != pkt_len) {
+                    PrintDebug("VNET: Packet not sent properly\n");
+                    return -1;
+                }
+            }else {
+                PrintDebug("VNET: Link protocol type not support\n");
+                return -1;
+            }
         } else if (g_routes.routes[route_index]->link_type == LINK_INTERFACE) {
-            if ((link->dst_link->input(pkt->data, pkt_len, NULL)) != pkt_len) {
-               PrintError("LEI --  WHAT IS THE ERROR HERE?\n");
-               return -1;
-           }
+            if ((link->dst_dev->input(pkt->data, pkt_len, link->dst_dev->private_data)) != pkt_len) {
+                  PrintDebug("VNET: Packet not sent properly\n");
+                  return -1;
+            }
         } else {
-            PrintError("Vnet: Wrong Edge type\n");
-           return -1;
+            PrintDebug("Vnet: Wrong Edge type\n");
+            return -1;
         }
     }
     
     return 0;
 }
 
-static int send_ethernet_pkt(char * buf, int length) {
-    struct ethernet_pkt * pkt;
+static int send_ethernet_pkt(uchar_t *data, int len) {
+    struct ethernet_pkt *pkt;
 
     pkt = (struct ethernet_pkt *)V3_Malloc(sizeof(struct ethernet_pkt));
-    ethernet_packet_init(pkt, buf, length);  //====here we copy sending data once 
+    memset(pkt, 0, sizeof(struct ethernet_pkt));
+
+    if(pkt == NULL){
+        PrintError("VNET: Memory allocate fails\n");
+        return -1;
+    }
+       
+    ethernet_packet_init(pkt, data, len);  //====here we copy sending data once 
        
     PrintDebug("VNET: vm_send_pkt: transmitting packet: (size:%d)\n", (int)pkt->size);
-    print_packet((char *)buf, length);
+    print_packet((char *)data, len);
     
     v3_enqueue(g_inpkt_q, (addr_t)pkt);
 
     return 0;
 }
 
-int v3_vnet_send_pkt(uchar_t * buf, int length) {
-    PrintDebug("VNET: In V3_Send_pkt: pkt length %d\n", length);
+//send raw ethernet packet
+int v3_vnet_send_rawpkt(uchar_t * buf, int len, void *private_data) {
+    PrintDebug("VNET: In V3_Send_pkt: pkt length %d\n", len);
     
-    return send_ethernet_pkt((char *)buf, length);
+    return send_ethernet_pkt(buf, len);
+}
+
+//sending the packet from Dom0, should remove the link header
+int v3_vnet_send_udppkt(uchar_t * buf, int len, void *private_data) {
+    PrintDebug("VNET: In V3_Send_pkt: pkt length %d\n", len);
+
+    uint_t hdr_len = sizeof(struct udp_link_header);
+   
+    return send_ethernet_pkt((uchar_t *)(buf+hdr_len), len - hdr_len);
 }
 
 static int search_device(char * device_name) {
@@ -774,12 +728,11 @@ static int search_device(char * device_name) {
            }
         }
     }
-    
-    PrintError("LEI --  WHAT IS THE ERROR HERE?\n");
+
     return -1;
 }
 
-static int vnet_register_device(struct vm_device * vdev, 
+int vnet_register_device(struct vm_device * vdev, 
                         char * dev_name, 
                         uchar_t mac[6], 
                         int (*netif_input)(uchar_t * pkt, uint_t size, void * private_data), 
@@ -789,11 +742,11 @@ static int vnet_register_device(struct vm_device * vdev,
     int idx = search_device(dev_name);
 
     if (idx != -1) {
-       PrintError("LEI --  WHAT IS THE ERROR HERE?\n");
+       PrintDebug("VNET: register device: Already has device with the name %s\n", dev_name);
        return -1;
     }
     
-    if_dev = (struct vnet_if_device *)V3_Malloc(sizeof(struct vnet_if_device));
+    if_dev = (struct vnet_if_device *)(sizeof(struct vnet_if_device));
     
     if (if_dev == NULL) {
        PrintError("VNET: Malloc fails\n");
@@ -806,29 +759,32 @@ static int vnet_register_device(struct vm_device * vdev,
     if_dev->input = netif_input;
     if_dev->private_data = data;
 
-    struct link_entry * link = (struct link_entry *)V3_Malloc(sizeof(struct link_entry));
+    struct link_entry * link = (struct link_entry *)(sizeof(struct link_entry));
 
     link->type = LINK_INTERFACE;
     link->dst_dev = if_dev;
 
-    idx = add_link_entry(link);
+    idx = __add_link_entry(link);
+
+    PrintDebug("VNET: Add device %s to link table, idx %d", dev_name, idx);
     
     return idx;
 }
 
+#if 0
 static int vnet_unregister_device(char * dev_name) {
     int idx;
 
     idx = search_device(dev_name);
     
     if (idx == -1) {
-       PrintError("LEI --  WHAT IS THE ERROR HERE?\n");
+       PrintDebug("VNET: No device with name %s found\n", dev_name);
         return -1;
     }
 
-    struct vnet_if_device * device = (struct vnet_if_device *)delete_link_entry(idx);
+    struct vnet_if_device * device = (struct vnet_if_device *)__delete_link_entry(idx);
     if (device == NULL) {
-       PrintError("LEI --  WHAT IS THE ERROR HERE?\n");
+       PrintError("VNET: Device %s not in the link table %d, something may be wrong in link table\n", dev_name, idx);
        return -1;
     }
 
@@ -837,6 +793,8 @@ static int vnet_unregister_device(char * dev_name) {
     return idx;
 }
 
+#endif
+
 int v3_vnet_pkt_process() {
     struct ethernet_pkt * pkt;
 
@@ -892,27 +850,118 @@ static void init_pkt_queue() {
     v3_init_queue(g_inpkt_q);
 }
 
-#if 0
-// TODO: 
-static int init_routing_tables(struct routing_entry *route_tab, uint16_t size)
-{
-    //struct routing_entry *route;
+static void free_link_mem(struct link_entry *link){
+    V3_Free(link->dst_dev);
+    V3_Free(link);
+}
 
+// TODO:
+static int addto_routing_link_tables(struct routing_entry *route_tab, 
+                                                       uint16_t num_routes,
+                                                       struct link_entry *link_tab,
+                                                       uint16_t num_links){
+    struct routing_entry *route, *new_route;
+    struct link_entry *link, *new_link;
+    int new_idx;
+    int i;
+    int link_idxs[MAX_LINKS];
 
-    return 0;
-}
+    //add all of the links first, record their new indexs
+    for (i = 0; i < num_links; i++) {
+       link_idxs[i] = -1;
+       link = &link_tab[i];
+       new_link = (struct link_entry *)V3_Malloc(sizeof(struct link_entry));
 
+       if (new_link == NULL){
+           PrintError("VNET: Memory allocate error\n");
+           return -1;
+       }
+
+       new_link->type = link->type;
+       
+       //TODO: how to set the input parameters here
+       if (link->type == LINK_EDGE){
+           struct vnet_if_device *ifdev = (struct vnet_if_device *)V3_Malloc(sizeof(struct vnet_if_device));
+
+           if (ifdev == NULL){
+               PrintError("VNET: Memory allocate fails\n");
+               return -1;
+           }
+           
+           memcpy(ifdev->name, link->dst_dev->name, DEVICE_NAME_LEN);
+
+           // TODO:
+           //ifdev->mac_addr
+           //ifdev->input
+           //ifdev->private_data
+
+           new_link->dst_dev = ifdev;    
+       }else if (link->type == LINK_INTERFACE){
+           struct vnet_if_link *iflink = (struct vnet_if_link *)V3_Malloc(sizeof(struct vnet_if_link));
+
+           if (iflink == NULL){
+               PrintError("VNET: Memory allocate fails\n");
+               return -1;
+           }
+           iflink->pro_type = link->dst_link->pro_type;
+           iflink->dest_ip = link->dst_link->dest_ip;
+           iflink->dest_port = link->dst_link->dest_port;
+           memcpy(&iflink->vnet_header, &link->dst_link->vnet_header, sizeof(struct udp_link_header));
+
+           // TODO:
+           //iflink->input = 
+           //iflink->private_data = 
+           
+           new_link->dst_link = iflink;
+       }else{
+           PrintDebug("VNET: invalid link type\n");
+           V3_Free(new_link);
+           continue;
+       }
+       
+       new_idx = __add_link_entry(new_link);
+       if (new_idx < 0) {
+           PrintError("VNET: Adding link fails\n");
+           free_link_mem(new_link);
+           continue;
+       }       
+       link_idxs[i] = new_idx;
+    }
+
+    //add all of routes, replace with new link indexs
+    for (i = 0; i < num_routes; i++) {
+       route = &route_tab[i];
+       if (route->link_idx < 0 || route->link_idx >= num_links || 
+           ((route->src_link_idx != -1) && 
+             (route->src_link_idx < 0 || route->src_link_idx >= num_links))){
+           PrintError("VNET: There is error in the intial tables data from guest\n");
+           continue;
+       }
+
+       new_route = (struct routing_entry *)V3_Malloc(sizeof(struct routing_entry));
+
+       if (new_route == NULL){
+           PrintError("VNET: Memory allocate fails\n");
+           return -1;
+       }
+       memcpy(new_route, route, sizeof(struct routing_entry));
+       
+       new_route->link_idx = link_idxs[new_route->link_idx];
+               
+       if (route->src_link_idx != -1)
+           new_route->src_link_idx = link_idxs[new_route->src_link_idx];
+
+       if((__add_route_entry(new_route)) == -1){
+           PrintDebug("VNET: Adding route fails");
+           V3_Free(new_route);
+       }
+       new_route = NULL;       
+    }
 
-// TODO: 
-static int init_link_tables(struct link_entry *link_tab, uint16_t size)
-{
-    //struct link_entry *link;
 
     return 0;
 }
 
-#endif
-
 struct table_init_info {
     addr_t routing_table_start;
     uint16_t routing_table_size;
@@ -920,16 +969,34 @@ struct table_init_info {
     uint16_t link_table_size;
 };
 
+//add the guest specified routes and links to the tables
 static int handle_init_tables_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
-    uint8_t * buf = NULL;
-    addr_t info_addr = (addr_t)info->vm_regs.rcx;
+    addr_t guest_addr = (addr_t)info->vm_regs.rcx;
+    addr_t info_addr, route_addr, link_addr;
+    struct table_init_info *init_info;
+    struct link_entry *link_array;
+    struct routing_entry *route_array;   
+
+    if (guest_va_to_host_va(info, guest_addr, &info_addr) == -1) {
+       PrintError("VNET: Could not translate guest address\n");
+       return -1;
+    }
+
+    init_info = (struct table_init_info *)info_addr;
 
-    if (guest_va_to_host_va(info, info_addr, (addr_t *)&(buf)) == -1) {
-       PrintError("Could not translate buffer address\n");
+    if (guest_va_to_host_va(info, init_info->routing_table_start, &route_addr) == -1) {
+       PrintError("VNET: Could not translate guest address\n");
        return -1;
     }
+    route_array = (struct routing_entry *)route_addr;
 
-    //struct table_init_info *init_info = (struct table_init_info *)buf;
+    if (guest_va_to_host_va(info, init_info->link_table_start, &link_addr) == -1) {
+       PrintError("VNET: Could not translate guest address\n");
+       return -1;
+    }  
+    link_array = (struct link_entry *)link_addr;
+
+    addto_routing_link_tables(route_array, init_info->routing_table_size, link_array, init_info->link_table_size);
     
     return 0;
 }
@@ -941,8 +1008,6 @@ void v3_vnet_init(struct guest_info * vm) {
        
     v3_register_hypercall(vm, VNET_INITAB_HCALL, handle_init_tables_hcall, NULL);
 
-    //store_test_topologies(udp_data_socket); 
-
     PrintDebug("VNET Initialized\n");
 }