################################################################################ ### SDN-VPN: a prototype SDN controller to set up VPN services. ### ### This software has been developed by Gabriele Lospoto and Benedetto Gabriele ### Vignoli within the research line described at ### http://www.dia.uniroma3.it/~compunet/www/view/topic.php?id=sdn ### ### Last update: 17 Oct 2014 ################################################################################ This file explains how to implement a custom network topology and custom VPN configurations that can be experimented with our SDN VPN controller. Shorter instructions to run ready-to-use examples provided with the virtual machine are available in the separate README.txt file. === DIRECTORY STRUCTURE === Our controller implementation resides inside path SDN-VPN-controller. Besides several files and directories that are part of this software, the controller directory contains two relevant subdirectories: - SDN-VPN-controller/bin contains scripts used to set up network topologies with Mininet. - SDN-VPN-controller/conf contains system-wide and VPN-specific configurations. Creating a custom network with a custom VPN configuration requires placing suitable files inside these two subdirectories. In the following of this documentation we describe how to create these files. === CREATING A CUSTOM NETWORK TOPOLOGY === A network topology is implemented in Mininet by preparing a suitable script that adds the required nodes and links. Such scripts are located in SDN-VPN-controller/bin. A Mininet topology configuration script takes advantage of a Python API. The example topology scripts provided with the SDN VPN controller virtual machine also define additional methods to make the network setup more convenient. In the following, we describe the basic usage of the Python API and how to create a custom topology script by variation of the existing example scripts. In principle, it is also possible to start from scratch, but several useful operations (e.g., automatic invocation of the Mininet CLI after the network setup is completed) would then have to be explicitly implemented. Before specifying the topology, we must instruct Mininet to use a customized switch implementation. This is required because only the userspace mode of operation of Open vSwitch is capable of correctly handling MPLS label stacks at the moment. In order to do this, we have defined the following class, which can be arbitrarily modified to adopt alternative switch implementations: # Modify this class if you want to use a different switch implementation class CustomSwitch(OVSSwitch): def __init__(self, name, **params): OVSSwitch.__init__(self, name=name, datapath='user', **params) In particular, changing the superclass of CustomSwitch (and, consequently, the constructor of the class), you can force Mininet to use another switch. Available switches are: OVSSwitch (Open vSwitch), UserSwitch (user-space switch, tipically the CPqD switch - if installed), and IVSSwitch (Indigo Switch from the Floodlight project - if installed). For further information, refer to file mininet/mininet/node.py. After the preliminary step of choosing the switch implementation, we need to initialize Mininet. This is achieved by the following code: # This class creates topology class TopologyGenerator(object): def __init__(self): self.net = Mininet( controller=None, switch=CustomSwitch, listenPort=6634, inNamespace=False, autoSetMacs=True) # Add controller to the network self.net.addController('c0', controller=RemoteController, ip='127.0.0.1', port=6633) In particular, we are communicating to Mininet that it has to use CustomSwitch as a switch implementation, that the first switch will listen for OpenFlow control packets on TCP port 6634, and that MAC addresses should be automatically assigned in a progressive fashion instead of being randomly generated (i.e., with autoSetMacs=True every host will have a MAC address with the form 00:00:00:00:00:0X, where X depends on the order in which hosts are added to the network). Additionally, we are instructing switch instances created by Mininet about the fact that the SDN controller is reachable via a TCP connection (this is indicated by the usage of class RemoteController), is running on the same machine hosting Mininet, and can be contacted on port 6633. Any other IP address and port can be used here, in case the controller is running on a different host. At this point it is possible to specify the actual network topology. This is achieved by implementing the method a method called "create_topology(self)". Inside this method, it is possible to invoke primitives to add all the nodes (hosts and switches) that make up the network and to add links among them. For example: def create_topology(self): # Switches s1 = self.net.addSwitch("s1", dpid=self.dpid(1)) s2 = self.net.addSwitch("s2", dpid=self.dpid(2)) # Hosts h1 = self.net.addHost("h1") h2 = self.net.addHost("h2") # Links between hosts and switches self.net.addLink(h1, s1) self.net.addLink(h2, s2) # Links between switches self.net.addLink(s1, s2) Switches are added to the network by invoking method "addSwitch()" on the "net" object. This method takes two arguments: a string specifying the name of the switch and, optionally, a datapath ID specified by setting the "dpid" parameter as shown above. Although specifying datapath IDs is not mandatory in Mininet, in our VPN setting it is required in order to be able to correctly reference each switch in VPN configurations. Hosts are added to the network by using method "addHost()", and they are also identified by a name specified as a string argument to this method. When "autoSetMacs" is specified as an option in the Mininet initialization (see above), the order in which hosts are added to the network is significant, because it influences the assignment of the MAC addresses. Finally, links between network nodes are added by using method "addLink()" as shown above. As a general rule of thumb, which may be convenient for preparing VPN configuration files, links between hosts and switches should be added before all the links between switches: in this way, multiple hosts connected to the same switch are attached to progressively numbered interfaces (eth1, eth2, etc.) of that switch. After the topology has been defined, each host requires additional configuration. This step is accomplished by the "configure_host(self)" method, as shown below: def configure_host(self): ### Host h1 h1 = self.net.get("h1") h1.setIP("10.0.0.1/24") # Add default route h1.cmd("route add default h1-eth0") # Add static entry in the ARP cache h1.cmd("arp -s 20.0.0.1 00:00:00:00:00:02") ### Host h2 h2 = self.net.get("h2") h2.setIP("20.0.0.1/24") # Add default route h2.cmd("route add default h2-eth0") # Add static entry in the ARP cache h2.cmd("arp -s 10.0.0.1 00:00:00:00:00:01") For each host, we need to set: 1. an IP address; 2. a default route; 3. static entries in the ARP cache for every other remote host that can be contacted by the host under consideration (this is required because ARP traffic is not handled by our SDN controller). Other methods or functions are not relevant in our network setup. At this point it is possible to save the obtained script in the SDN-VPN-controller/bin folder, mark it as executable by executing "chmod +x network_file_name.py", and run it to launch the corresponding network: sudo ./network_file_name.py An instance of Mininet is immediately started and launched and its CLI is activated. === SYSTEM-WIDE CONFIGURATION === System-wide configuration settings for our SDN VPN controller are located inside file "SDN-VPN-controller/conf/system.conf" and have a very simple structure. First of all, we need to declare the location of the VPN configuration file, by setting a parameter called "vpn-config-file" in section "[System]". By convention, VPN configuration files are located inside folder "SDN-VPN-controller/conf/vpns" so, assuming that our SDN VPN controller is invoked from inside directory "SDN-VPN-controller", it is possible to specify a relative path like "conf/vpns/custom-topology.py" as a "vpn-config-file". After that, for each VPN defined in the VPN configuration file, a PE-to-PE path composition policy must be specified in a separate section called "[Policies]". At present, the one admitted value is "ShortestPath", so an entry like the following one must be added for every used VPN: vpn1 = ShortestPath === VPN CONFIGURATIONS === VPN configuration files are placed inside folder "SDN-VPN-controller/conf/vpns". All the parameters specified in a VPN configuration file must be enclosed in the tag. The first part of a VPN configuration file contains a listing of datapaths, which is used to build an inventory of all the OpenFlow switches in the network and to associate a name to every switch in order to conveniently reference it in the rest of the configuration. Each datapath is identified by its datapath ID as assigned in the Mininet network setup script. VPN configurations immediately follow. Each VPN is specified using the tag, which has a "name" attribute corresponding to the symbolic name associated with that VPN. Within a VPN, the participating sites are declared by using the tag, which has 4 attributes: - "subnet", used to declare an IP subnet hosted by a customer attached to the current VPN (note: in the current implementation, only one IP subnet can be specified for each customer site in each VPN); - "pe", used to declare the name of the PE router (actually, an OpenFlow switch) to which the customer site being declared is attached; - "port", used to declare the port of the PE router to which the customer is attached; - "nat", used to specify the name of a PE router that acts as an egress point towards the Internet for the current customer site; if this site requires no Internet access, this attribute can be set to an empty string (but must not be omitted). Finally, any NAT address translation rules are specified by using an additional tag . This tag has two attributes: - "name", which specifies the name of a PE router that performs NAT (note: in the current implementation, only egress NAT is supported). The value of this attribute matches the value of the "nat" attribute in the tag used for VPN specifications; - "port", which specifies the port of the PE router that is connected to the Internet. Every PE router that performs NAT may apply different mapping rules for each VPN. Mapping rules are specified by using a tag, which has 3 attributes: - "vpn" used to declare the VPN to which the following mapping rules are applied; - "pe", used to declare the PE router to which the customer site that undergoes NAT is attached; - "type", used to specify the type of address translation; this attribute can assume 3 different values: "static" (every IP address is statically mapped to an explicitly specified IP address), "dynamic" (every IP address within a subnet is mapped to an automatically determined address within another IP subnet of equal size), "full" (every IP address belonging to the specified customer site and VPN is automatically mapped to an available IP address taken from a specified pool). Inside each statement, the actual address translation rules must be specified by using the tag. This tag has 2 attributes: - "ip", which specifies a piece of private IP address space of a customer that is subject to NATting; - "gr", which specifies a piece of public IP address space to which the private space is to be mapped. Note that, in the case of static NAT, "ip" and "gr" are single IP addresses, whereas in the case of dynamic NAT, they are IP subnets of equal size. Finally, in the case of full NAT, attribute "ip" must be assigned the wildcard value "*". === CONTROLLER STARTUP === Once all the configurations are made, move into directory "SDN-VPN-controller" and execute the following command: ./start_controller.sh === NETWORK TESTING === After both the controller and the network have been started, it is possible to interact with Mininet to check the operation of the network (for further information about Mininet visit http://mininet.org). For a more convenient exploration of the control packets exchanged between the controller and each OpenFlow switch, the provided virtual machine includes a release of the Wireshark network sniffer that is capable of dissecting OpenFlow packets.