Fast and Lightweight Network Function Virtualization




You need to have the following packages installed (in Debian):


Export the following environment variables (replace with the Xen version you are running):

$ export XEN_ROOT=/path-to-xen-sources


To build ClickOS, we first need to build a cross-compilation toolchain. Since the toolchain is rather big and takes a while to buildm we provide prebuilt binaries so you can start building ClickOS right away. For this you will need the Xen sources, though you won’t need to build these since only the header files are necessary. The steps are as follows:

  $ git clone
  $ export MINIOS_ROOT=`pwd`/mini-os
  $ git clone
  $ cd toolchain
  $ make

  $ cd -
  $ export NEWLIB_ROOT=`pwd`/toolchain/x86_64-root/x86_64-xen-elf
  $ export LWIP_ROOT=`pwd`/toolchain/x86_64-root/x86_64-xen-elf

  # or the upstream
  $ git clone

  $ cd clickos
  $ ./configure --enable-minios --with-xen=$XEN_ROOT
  $ make minios

Thats it! You should be able to find the ClickOS image at:

  $ ls -lah /path-to-clickos/clickos/minios/build/clickos_x86_64{,.gz}
  -rwxr-xr-x 1 root root 6.8M Mar 18 01:06 clickos_x86_64*
  -rw-r--r-- 1 root root 1.6M Mar 18 01:07 clickos_x86_64.gz

We tend to prefer the uncompressed image since uncompression takes about 40 msecs at boot time, a significant portion of time when the rest of the boot process takes about 30 msecs. Once we have the image, all that remains is to build the ClickOS toolstack, called cosmos. If you’re installing with the Xen sources you do not need any additional libraries; if not, you’ll need to install the libxen-dev (on Debian-based systems).

For the toolstack, just clone the toolstack and run make.


To run ClickOS you need two things: a Xen configuration and a Click configuration.

Here’s a sample Xen configuration file for ClickOS :

	name   = 'clickos'
        kernel = 'path-to-clickos/minios/build/clickos_x86_64'
        vcpus  = '1'
        # pinning your VCPU helps performance
        #cpus   = '3'
        memory = '8'

        # uncoment this line if you wish to use our backend
        #vif    = ['bridge=vale0,script=vif-vale']
        vif    = ['mac=00:15:17:15:5d:74,bridge=xenbr0']

        on_poweroff = 'destroy'
        on_reboot   = 'restart'
        on_crash    = 'preserve'
        click       = ''

        # uncomment this line to enable PVH mode for ClickOS

The Click configuration could be something really simple that just grabs packets, swaps src and dst MAC addresses, and sends them back to the bridge:

	FromDevice -> EtherMirror -> ToDevice

Save the click config as and the Xen config as example.cfg.

You can either use xl to boot the ClickOS guest, and later on cosmos to start the click config within that guest:

	$ xl create example.cfg
        $ DOMID=`xl list | grep clickos | awk -F' ' '{ print $2 }'`
        $ cosmos start $DOMID

You can choose a DOMLIB cosmos will be able to manage domains on its own. You have tree options available:

  • DOMLIB=xcl enables our toolstack to manage MiniOS-based domains. It is made for MiniOS, and should not be used for other types. Attaching block devices are not supported at the moment.

  • DOMLIB=xl enables the standart libxl toolstack to manage domains.

  • DOMLIB=none is the default option and disables domain management in cosmos toolstack

If you intend to orchestrate the booting process in a more high-level language, or rather simplicity of the deployment, you definitely should enable these options.

To build cosmos with our domain library (libxcl):

        cd tools
        make -C include
        cd /path/to/cosmos
        make DOMLIB=xcl

If you built cosmos with a Dom library you will be able to boot ClickOS VMs with the following command:

	$ cosmos create example.cfg

After booting the VM, the output from the console will look like the following:

$xl console clickos
 Xen Minimal OS!
     start_info: 0x232000(VA)
       nr_pages: 0x800
     shared_inf: 0x5f76c000(MA)
        pt_base: 0x235000(VA)
   nr_pt_frames: 0x5
       mfn_list: 0x22e000(VA)
      mod_start: 0x0(VA)
        mod_len: 0
          flags: 0x0
       cmd_line: -d standard
     stack:      0x1ebce0-0x20bce0
  MM: Init
      _text: 0x0(VA)
     _etext: 0x173a7b(VA)
   _erodata: 0x1d1000(VA)
     _edata: 0x1d2ec0(VA)
stack start: 0x1ebce0(VA)
       _end: 0x22c518(VA)
  start_pfn: 23d
    max_pfn: 800
 Mapping memory range 0x400000 - 0x800000
 setting 0x0-0x1d1000 readonly
 skipped 0x1000
 MM: Initialise page allocator for 23f000(23f000)-800000(800000)
 MM: done
 Demand map pfns at 801000-2000801000.
 Heap resides at 2000802000-4000802000.
 Initialising timer interface
 Initialising console ... done.
 gnttab_table mapped at 0x801000.
 Initialising scheduler
 Thread "Idle": pointer: 0x2000802050, stack: 0x250000
 Thread "xenstore": pointer: 0x2000802800, stack: 0x260000
 xenbus initialised on irq 1 mfn 0x5ef6b
 Thread "shutdown": pointer: 0x2000802fb0, stack: 0x270000
 Dummy main: start_info=0x20bce0
 Thread "main": pointer: 0x2000803760, stack: 0x280000
 sparsing 0MB at 1ea000
 "main" "-d" "standard"
 [on:82] * 18 for clickos/0/elements*
 [on:82] * 17 for clickos/0/control*
 [on_status:247] status change to Running
 Thread "click": pointer: 0x2000804c60, stack: 0x290000
 ************************ NETFRONT for device/vif/0 **********

 net TX ring size 256
 net RX ring size 256
 backend at /local/domain/0/backend/vif/5/0
 mac is 00:15:17:15:5d:74

Example Configurations

Using Click is pretty much like building legos. The basic module is called an element, which is a basic unit that performs an action on packets such as modifying MAC addresses, verying IP checksums, decreasing TTLs or rate limiting traffic, to name a few. Here are a couple of more examples of Click configurations to get you started.


A stateless firewall:

    // WAN Interface
    wani :: FromDevice(0);
    wano :: ToDevice(0);

    // LAN Interface
    lani :: FromDevice(1);
    lano :: ToDevice(1);

    // Classifier element
    cw :: Classifier(
        12/0806, // ARP Packets
        12/0800, // IP Packets
        -        // Other

    // IP Filter element
    f :: IPFilter(
        0 dst host,
        1 all

    wani -> cw;

    cw[0] -> CheckARPHeader(14) -> lano;                  // ARP Packets
    cw[1] -> CheckIPHeader(14) -> f;                      // IP Packets
    cw[2] -> Print("Drop (Blocked protocol)") -> Discard; // Other

    f[0] -> lano;                                         // allow
    f[1] -> Print("Drop (Blocked by filter)") -> Discard; // drop

    lani -> wano;


A Click configuration to process ARP/ICMP requests:

    define($MAC 00:15:17:15:5d:75);

    source :: FromDevice;
    sink   :: ToDevice;
    // classifies packets 
    c :: Classifier(
        12/0806 20/0001, // ARP Requests goes to output 0
        12/0806 20/0002, // ARP Replies to output 1
        12/0800, // ICMP Requests to output 2
        -); // without a match to output 3

    arpq :: ARPQuerier($IP, $MAC);
    arpr :: ARPResponder($IP $MAC);

    source -> c;
    c[0] -> ARPPrint -> arpr -> sink;
    c[1] -> [1]arpq;
    Idle -> [0]arpq;
    arpq -> ARPPrint -> sink;
    c[2] -> CheckIPHeader(14) -> ICMPPingResponder() -> EtherMirror() -> sink;
    c[3] -> Discard;

For information about how to run ClickOS with these click configurations check the previous section. Once it is up and running, configure the dom0 bridge as follows and test your ponger configuration:

 $ ifconfig xenbr0 netmask up
 $ ping
 # On another console you will the output corresponding to the elements
 $ xl console clickos