Provider network and dnsmaq conf improvment
When dhcp server is launch, now dns servers and default routes can be progated to a vm.
A qrouter is created inside a namespace allowing connections with a provider network and a openvim tenant network.
Change-Id: If2becc010b2886493396c9f6b363980a846a04da
Signed-off-by: mirabal <leonardo.mirabal@altran.com>
diff --git a/osm_openvim/host_thread.py b/osm_openvim/host_thread.py
index b8f051c..6fe8331 100644
--- a/osm_openvim/host_thread.py
+++ b/osm_openvim/host_thread.py
@@ -813,16 +813,16 @@
if not self.is_dhcp_port_free(vlan, net_uuid):
return True
try:
- net_namespace = 'ovim-' + str(vlan)
- dhcp_path = os.path.join(dhcp_path, net_namespace)
+ dhcp_namespace = str(vlan) + '-dnsmasq'
+ dhcp_path = os.path.join(dhcp_path, dhcp_namespace)
pid_file = os.path.join(dhcp_path, 'dnsmasq.pid')
- command = 'sudo ip netns exec ' + net_namespace + ' cat ' + pid_file
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' cat ' + pid_file
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip netns exec ' + net_namespace + ' kill -9 ' + content
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' kill -9 ' + content
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
@@ -944,7 +944,7 @@
return True
try:
port_name = 'ovim-' + str(vlan)
- command = 'sudo ip link set dev veth0-' + str(vlan) + ' down'
+ command = 'sudo ip link set dev ovim-' + str(vlan) + ' down'
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
# content = stdout.read()
@@ -965,6 +965,59 @@
self.ssh_connect()
return False
+ def remove_link_bridge_to_ovs(self, vlan, link):
+ """
+ Delete a linux provider net connection to tenatn net
+ :param vlan: vlan port id
+ :param link: link name
+ :return: True if success
+ """
+
+ if self.test:
+ return True
+ try:
+ br_tap_name = str(vlan) + '-vethBO'
+ br_ovs_name = str(vlan) + '-vethOB'
+
+ # Delete ovs veth pair
+ command = 'sudo ip link set dev {} down'.format(br_ovs_name)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ovs-vsctl del-port br-int {}'.format(br_ovs_name)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # Delete br veth pair
+ command = 'sudo ip link set dev {} down'.format(br_tap_name)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # Delete br veth interface form bridge
+ command = 'sudo brctl delif {} {}'.format(link, br_tap_name)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # Delete br veth pair
+ command = 'sudo ip link set dev {} down'.format(link)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ if len(content) == 0:
+ return True
+ else:
+ return False
+ except paramiko.ssh_exception.SSHException as e:
+ self.logger.error("delete_linux_bridge ssh Exception: " + str(e))
+ if "SSH session not active" in str(e):
+ self.ssh_connect()
+ return False
+
def create_ovs_bridge_port(self, vlan):
"""
Generate a linux bridge and attache the port to a OVS bridge
@@ -1030,7 +1083,7 @@
self.ssh_connect()
return False
- def set_mac_dhcp_server(self, ip, mac, vlan, netmask, dhcp_path):
+ def set_mac_dhcp_server(self, ip, mac, vlan, netmask, first_ip, dhcp_path):
"""
Write into dhcp conf file a rule to assigned a fixed ip given to an specific MAC address
:param ip: IP address asigned to a VM
@@ -1044,21 +1097,43 @@
if self.test:
return True
- net_namespace = 'ovim-' + str(vlan)
- dhcp_path = os.path.join(dhcp_path, net_namespace)
- dhcp_hostsdir = os.path.join(dhcp_path, net_namespace)
+ dhcp_namespace = str(vlan) + '-dnsmasq'
+ dhcp_path = os.path.join(dhcp_path, dhcp_namespace)
+ dhcp_hostsdir = os.path.join(dhcp_path, dhcp_namespace)
if not ip:
return False
try:
+
+ ns_interface = str(vlan) + '-vethDO'
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' cat /sys/class/net/{}/address'.format(ns_interface)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ iface_listen_mac = stdout.read()
+
+ if iface_listen_mac > 0:
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' cat {} | grep {}'.format(dhcp_hostsdir, dhcp_hostsdir)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ if content > 0:
+ ip_data = iface_listen_mac.upper().replace('\n', '') + ',' + first_ip
+ dhcp_hostsdir = os.path.join(dhcp_path, dhcp_namespace)
+
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' sudo bash -ec "echo ' + ip_data + ' >> ' + dhcp_hostsdir + '"'
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+
ip_data = mac.upper() + ',' + ip
- command = 'sudo ip netns exec ' + net_namespace + ' touch ' + dhcp_hostsdir
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' touch ' + dhcp_hostsdir
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip netns exec ' + net_namespace + ' sudo bash -ec "echo ' + ip_data + ' >> ' + dhcp_hostsdir + '"'
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' sudo bash -ec "echo ' + ip_data + ' >> ' + dhcp_hostsdir + '"'
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
@@ -1088,16 +1163,16 @@
if self.test:
return False
try:
- net_namespace = 'ovim-' + str(vlan)
- dhcp_path = os.path.join(dhcp_path, net_namespace)
- dhcp_hostsdir = os.path.join(dhcp_path, net_namespace)
+ dhcp_namespace = str(vlan) + '-dnsmasq'
+ dhcp_path = os.path.join(dhcp_path, dhcp_namespace)
+ dhcp_hostsdir = os.path.join(dhcp_path, dhcp_namespace)
if not ip:
return False
ip_data = mac.upper() + ',' + ip
- command = 'sudo ip netns exec ' + net_namespace + ' sudo sed -i \'/' + ip_data + '/d\' ' + dhcp_hostsdir
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' sudo sed -i \'/' + ip_data + '/d\' ' + dhcp_hostsdir
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
@@ -1113,7 +1188,7 @@
self.ssh_connect()
return False
- def launch_dhcp_server(self, vlan, ip_range, netmask, dhcp_path, gateway):
+ def launch_dhcp_server(self, vlan, ip_range, netmask, dhcp_path, gateway, dns_list=None, routes=None):
"""
Generate a linux bridge and attache the port to a OVS bridge
:param self:
@@ -1122,30 +1197,34 @@
:param netmask: network netmask
:param dhcp_path: dhcp conf file path that live in namespace side
:param gateway: Gateway address for dhcp net
+ :param dns_list: dns list for dhcp server
+ :param routes: routes list for dhcp server
:return: True if success
"""
if self.test:
return True
try:
- interface = 'tap-' + str(vlan)
- net_namespace = 'ovim-' + str(vlan)
- dhcp_path = os.path.join(dhcp_path, net_namespace)
+ ns_interface = str(vlan) + '-vethDO'
+ dhcp_namespace = str(vlan) + '-dnsmasq'
+ dhcp_path = os.path.join(dhcp_path, dhcp_namespace, '')
leases_path = os.path.join(dhcp_path, "dnsmasq.leases")
pid_file = os.path.join(dhcp_path, 'dnsmasq.pid')
+
dhcp_range = ip_range[0] + ',' + ip_range[1] + ',' + netmask
- command = 'sudo ip netns exec ' + net_namespace + ' mkdir -p ' + dhcp_path
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' mkdir -p ' + dhcp_path
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
pid_path = os.path.join(dhcp_path, 'dnsmasq.pid')
- command = 'sudo ip netns exec ' + net_namespace + ' cat ' + pid_path
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' cat ' + pid_path
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
+
# check if pid is runing
pid_status_path = content
if content:
@@ -1153,11 +1232,34 @@
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
+
+ gateway_option = ' --dhcp-option=3,' + gateway
+
+ dhcp_route_option = ''
+ if routes:
+ dhcp_route_option = ' --dhcp-option=121'
+ for key, value in routes.iteritems():
+ if 'default' == key:
+ gateway_option = ' --dhcp-option=3,' + value
+ else:
+ dhcp_route_option += ',' + key + ',' + value
+ dns_data = ''
+ if dns_list:
+ dns_data = ' --dhcp-option=6'
+ for dns in dns_list:
+ dns_data += ',' + dns
+
if not content:
- command = 'sudo ip netns exec ' + net_namespace + ' /usr/sbin/dnsmasq --strict-order --except-interface=lo ' \
- '--interface=' + interface + ' --bind-interfaces --dhcp-hostsdir=' + dhcp_path + \
- ' --dhcp-range ' + dhcp_range + ' --pid-file=' + pid_file + ' --dhcp-leasefile=' + leases_path + \
- ' --listen-address ' + gateway
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' /usr/sbin/dnsmasq --strict-order --except-interface=lo ' \
+ '--interface=' + ns_interface + \
+ ' --bind-interfaces --dhcp-hostsdir=' + dhcp_path + \
+ ' --dhcp-range ' + dhcp_range + \
+ ' --pid-file=' + pid_file + \
+ ' --dhcp-leasefile=' + leases_path + \
+ ' --listen-address ' + ip_range[0] + \
+ gateway_option + \
+ dhcp_route_option + \
+ dns_data
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
@@ -1183,21 +1285,35 @@
if self.test:
return True
try:
- net_namespace = 'ovim-' + str(vlan)
- command = 'sudo ovs-vsctl del-port br-int ovs-tap-' + str(vlan)
+ br_veth_name = str(vlan) + '-vethDO'
+ ovs_veth_name = str(vlan) + '-vethOD'
+ dhcp_namespace = str(vlan) + '-dnsmasq'
+
+ command = 'sudo ovs-vsctl del-port br-int ' + ovs_veth_name
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip netns exec ' + net_namespace + ' ip link set dev tap-' + str(vlan) + ' down'
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' ip link set dev ' + br_veth_name + ' down'
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip link set dev ovs-tap-' + str(vlan) + ' down'
+ command = 'sudo ip link set dev ' + dhcp_namespace + ' down'
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
+
+ command = 'sudo brctl delbr ' + dhcp_namespace
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip netns del ' + dhcp_namespace
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
except paramiko.ssh_exception.SSHException as e:
self.logger.error("delete_dhcp_interfaces ssh Exception: " + str(e))
if "SSH session not active" in str(e):
@@ -1216,50 +1332,50 @@
if self.test:
return True
try:
- net_namespace = 'ovim-' + str(vlan)
- namespace_interface = 'tap-' + str(vlan)
+ ovs_veth_name = str(vlan) + '-vethOD'
+ ns_veth = str(vlan) + '-vethDO'
+ dhcp_namespace = str(vlan) + '-dnsmasq'
- command = 'sudo ip netns add ' + net_namespace
+ command = 'sudo ip netns add ' + dhcp_namespace
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip link add tap-' + str(vlan) + ' type veth peer name ovs-tap-' + str(vlan)
+ command = 'sudo ip link add ' + ns_veth + ' type veth peer name ' + ovs_veth_name
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ovs-vsctl add-port br-int ovs-tap-' + str(vlan) + ' tag=' + str(vlan)
+ command = 'sudo ip link set ' + ns_veth + ' netns ' + dhcp_namespace
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip link set tap-' + str(vlan) + ' netns ' + net_namespace
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' ip link set dev ' + ns_veth + ' up'
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip netns exec ' + net_namespace + ' ip link set dev tap-' + str(vlan) + ' up'
+ command = 'sudo ovs-vsctl add-port br-int ' + ovs_veth_name + ' tag=' + str(vlan)
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip link set dev ovs-tap-' + str(vlan) + ' up'
+ command = 'sudo ip link set dev ' + ovs_veth_name + ' up'
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip netns exec ' + net_namespace + ' ip link set dev lo up'
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' ip link set dev lo up'
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
- command = 'sudo ip netns exec ' + net_namespace + ' ' + ' ifconfig ' + namespace_interface \
+ command = 'sudo ip netns exec ' + dhcp_namespace + ' ' + ' ifconfig ' + ns_veth \
+ ' ' + ip_listen_address + ' netmask ' + netmask
self.logger.debug("command: " + command)
(_, stdout, _) = self.ssh_conn.exec_command(command)
content = stdout.read()
-
if len(content) == 0:
return True
else:
@@ -1270,6 +1386,266 @@
self.ssh_connect()
return False
+ def delete_qrouter_connection(self, vlan, link):
+ """
+ Delete qrouter Namesapce with all veth interfaces need it
+ :param vlan:
+ :param link:
+ :return:
+ """
+
+ ns_qouter = str(vlan) + '-qrouter'
+ qrouter_ovs_veth = str(vlan) + '-vethOQ'
+ qrouter_ns_veth = str(vlan) + '-vethQO'
+
+ qrouter_br_veth = str(vlan) + '-vethBQ'
+ qrouter_ns_router_veth = str(vlan) + '-vethQB'
+
+ # delete ovs veth to ovs br-int
+ command = 'sudo ovs-vsctl del-port br-int {}'.format(qrouter_ovs_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # down ns veth
+ command = 'sudo ip netns exec {} ip link set dev {} down'.format(ns_qouter, qrouter_ns_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # down ovs veth interface
+ command = 'sudo ip link set dev {} down'.format(qrouter_br_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # down br veth interface
+ command = 'sudo ip link set dev {} down'.format(qrouter_ovs_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # down br veth interface
+ command = 'sudo ip link set dev {} down'.format(qrouter_ns_router_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # down br veth interface
+ command = 'sudo brctl delif {} {}'.format(link, qrouter_br_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+
+ # delete NS
+ command = 'sudo ip netns del ' + ns_qouter
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ def create_qrouter_ovs_connection(self, vlan, gateway, dhcp_cidr):
+ """
+ Create qrouter Namesapce with all veth interfaces need it between NS and OVS
+ :param vlan:
+ :param gateway:
+ :return:
+ """
+
+ ns_qouter = str(vlan) + '-qrouter'
+ qrouter_ovs_veth = str(vlan) + '-vethOQ'
+ qrouter_ns_veth = str(vlan) + '-vethQO'
+
+ # Create NS
+ command = 'sudo ip netns add ' + ns_qouter
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # Create pait veth
+ command = 'sudo ip link add {} type veth peer name {}'.format(qrouter_ns_veth, qrouter_ovs_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # up ovs veth interface
+ command = 'sudo ip link set dev {} up'.format(qrouter_ovs_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # add ovs veth to ovs br-int
+ command = 'sudo ovs-vsctl add-port br-int {} tag={}'.format(qrouter_ovs_veth, vlan)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # add veth to ns
+ command = 'sudo ip link set {} netns {}'.format(qrouter_ns_veth, ns_qouter)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # up ns loopback
+ command = 'sudo ip netns exec {} ip link set dev lo up'.format(ns_qouter)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # up ns veth
+ command = 'sudo ip netns exec {} ip link set dev {} up'.format(ns_qouter, qrouter_ns_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ from netaddr import IPNetwork
+ ip_tools = IPNetwork(dhcp_cidr)
+ cidr_len = ip_tools.prefixlen
+
+ # set gw to ns veth
+ command = 'sudo ip netns exec {} ip address add {}/{} dev {}'.format(ns_qouter, gateway, cidr_len, qrouter_ns_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ def add_ns_routes(self, vlan, routes):
+
+ for key, value in routes.iteritems():
+ ns_qouter = str(vlan) + '-qrouter'
+ qrouter_ns_router_veth = str(vlan) + '-vethQB'
+ # up ns veth
+ if key == 'default':
+ command = 'sudo ip netns exec {} ip route add {} via {} '.format(ns_qouter, key, value)
+ else:
+ command = 'sudo ip netns exec {} ip route add {} via {} dev {}'.format(ns_qouter, key, value,
+ qrouter_ns_router_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ def create_qrouter_br_connection(self, vlan, cidr, link):
+ """
+ Create veth interfaces between user bridge (link) and OVS
+ :param vlan:
+ :param link:
+ :return:
+ """
+
+ ns_qouter = str(vlan) + '-qrouter'
+ qrouter_ns_router_veth = str(vlan) + '-vethQB'
+ qrouter_br_veth = str(vlan) + '-vethBQ'
+
+ # Create pait veth
+ command = 'sudo ip link add {} type veth peer name {}'.format(qrouter_br_veth, qrouter_ns_router_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # up ovs veth interface
+ command = 'sudo ip link set dev {} up'.format(qrouter_br_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # add veth to ns
+ command = 'sudo ip link set {} netns {}'.format(qrouter_ns_router_veth, ns_qouter)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # up ns veth
+ command = 'sudo ip netns exec {} ip link set dev {} up'.format(ns_qouter, qrouter_ns_router_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip netns exec {} ip address add {} dev {}'.format(ns_qouter, link['nat'], qrouter_ns_router_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo brctl show | grep {}'.format(link['iface'])
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ if content > '':
+ # up ns veth
+ command = 'sudo brctl addif {} {}'.format(link['iface'], qrouter_br_veth)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # up ns veth
+ command = 'sudo ip netns exec {} iptables -t nat -A POSTROUTING -o {} -s {} -d {} -j MASQUERADE' \
+ .format(ns_qouter, qrouter_ns_router_veth, link['nat'], cidr)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+
+ else:
+ self.logger.error('Bridge {} given by user not exist'.format(qrouter_br_veth))
+
+
+
+ def create_link_bridge_to_ovs(self, vlan, link):
+ """
+ Create interfaces to connect a linux bridge with tenant net
+ :param vlan: segmentation id
+ :return: True if success
+ """
+ if self.test:
+ return True
+ try:
+
+ br_tap_name = str(vlan) + '-vethBO'
+ br_ovs_name = str(vlan) + '-vethOB'
+
+ # is a bridge or a interface
+ command = 'sudo brctl show | grep {}'.format(link)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ if content > '':
+ command = 'sudo ip link add {} type veth peer name {}'.format(br_tap_name, br_ovs_name)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip link set dev {} up'.format(br_tap_name)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip link set dev {} up'.format(br_ovs_name)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ovs-vsctl add-port br-int {} tag={}'.format(br_ovs_name, str(vlan))
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo brctl addif ' + link + ' {}'.format(br_tap_name)
+ self.logger.debug("command: " + command)
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ if len(content) == 0:
+ return True
+ else:
+ return False
+ else:
+ self.logger.error('Link is not present, please check {}'.format(link))
+ return False
+ except paramiko.ssh_exception.SSHException as e:
+ self.logger.error("create_dhcp_interfaces ssh Exception: " + str(e))
+ if "SSH session not active" in str(e):
+ self.ssh_connect()
+ return False
def create_ovs_vxlan_tunnel(self, vxlan_interface, remote_ip):
"""
@@ -2344,8 +2720,8 @@
#Get the brifge name
db_lock.acquire()
result, content = db.get_table(FROM='nets',
- SELECT=('name', 'type', 'vlan', 'provider', 'enable_dhcp',
- 'dhcp_first_ip', 'dhcp_last_ip', 'cidr'),
+ SELECT=('name', 'type', 'vlan', 'provider', 'enable_dhcp','dhcp_first_ip',
+ 'dhcp_last_ip', 'cidr', 'gateway_ip', 'dns', 'links', 'routes'),
WHERE={'uuid': control_iface['net_id']})
db_lock.release()
if result < 0:
@@ -2370,6 +2746,13 @@
control_iface["dhcp_first_ip"] = network["dhcp_first_ip"]
control_iface["dhcp_last_ip"] = network["dhcp_last_ip"]
control_iface["cidr"] = network["cidr"]
+
+ if network.get("dns"):
+ control_iface["dns"] = yaml.safe_load(network.get("dns"))
+ if network.get("links"):
+ control_iface["links"] = yaml.safe_load(network.get("links"))
+ if network.get("routes"):
+ control_iface["routes"] = yaml.safe_load(network.get("routes"))
else:
if network['type']!='data' and network['type']!='ptp':
return -1, "Error at field netwoks: network uuid %s for dataplane interface is not of type data or ptp" % control_iface['net_id']
diff --git a/osm_openvim/httpserver.py b/osm_openvim/httpserver.py
index 7126e21..e95c820 100644
--- a/osm_openvim/httpserver.py
+++ b/osm_openvim/httpserver.py
@@ -157,15 +157,25 @@
http2db_ofc = {'id': 'uuid'}
http2db_port={'id':'uuid', 'network_id':'net_id', 'mac_address':'mac', 'device_owner':'type','device_id':'instance_id','binding:switch_port':'switch_port','binding:vlan':'vlan', 'bandwidth':'Mbps'}
+
def remove_extra_items(data, schema):
+ import re
+
deleted=[]
if type(data) is tuple or type(data) is list:
for d in data:
a= remove_extra_items(d, schema['items'])
if a is not None: deleted.append(a)
elif type(data) is dict:
+
for k in data.keys():
- if 'properties' not in schema or k not in schema['properties'].keys():
+ if 'patternProperties' in schema and k not in schema['properties'].keys():
+ reg_ex_list = schema['patternProperties'].keys()
+ for reg_ex in reg_ex_list:
+ if not re.match(reg_ex, k):
+ del data[k]
+ deleted.append(k)
+ elif 'properties' not in schema or k not in schema['properties'].keys(): # or k not in schema['patternProperties'].keys():
del data[k]
deleted.append(k)
else:
@@ -174,7 +184,8 @@
if len(deleted) == 0: return None
elif len(deleted) == 1: return deleted[0]
else: return deleted
-
+
+
def delete_nulls(var):
if type(var) is dict:
for k in var.keys():
@@ -648,7 +659,7 @@
# create bridge
create_dhcp_ovs_bridge()
config_dic['host_threads'][content['uuid']].insert_task("new-ovsbridge")
- # check if more host exist
+ # create vlxan bwt OVS controller and computes
create_vxlan_mesh(content['uuid'])
# return host data
@@ -674,8 +685,8 @@
http_controller = config_dic['http_threads'][threading.current_thread().name]
dhcp_controller = http_controller.ovim.get_dhcp_controller()
- dhcp_controller.delete_dhcp_port(vlan, net_uuid)
dhcp_controller.delete_dhcp_server(vlan, net_uuid, dhcp_path)
+ dhcp_controller.delete_dhcp_port(vlan, net_uuid)
def create_dhcp_ovs_bridge():
@@ -713,7 +724,7 @@
http_controller = config_dic['http_threads'][threading.current_thread().name]
dhcp_controller = http_controller.ovim.get_dhcp_controller()
- dhcp_controller.set_mac_dhcp_server(vm_ip, mac, vlan, dhcp_netmask, dhcp_path)
+ dhcp_controller.set_mac_dhcp_server(vm_ip, mac, vlan, dhcp_netmask, first_ip, dhcp_path)
def delete_mac_dhcp(vm_ip, vlan, mac):
@@ -1614,7 +1625,7 @@
if net['type'] == 'instance:ovs':
dhcp_nets_id.append(get_network_id(net['net_id']))
- ports_to_free=[]
+ ports_to_free = []
new_instance_result, new_instance = my.db.new_instance(content, nets, ports_to_free)
if new_instance_result < 0:
print "Error http_post_servers() :", new_instance_result, new_instance
@@ -1623,6 +1634,8 @@
print
print "inserted at DB"
print
+
+
for port in ports_to_free:
r,c = config_dic['host_threads'][ server['host_id'] ].insert_task( 'restore-iface',*port )
if r < 0:
@@ -1652,14 +1665,24 @@
dhcp_enable = bool(server_net['network']['enable_dhcp'])
vm_dhcp_ip = c2[0]["ip_address"]
config_dic['host_threads'][server['host_id']].insert_task("create-ovs-bridge-port", vlan)
+
+ dns = yaml.safe_load(server_net['network'].get("dns"))
+ routes = yaml.safe_load(server_net['network'].get("routes"))
+ links = yaml.safe_load(server_net['network'].get("links"))
if dhcp_enable:
dhcp_firt_ip = str(server_net['network']['dhcp_first_ip'])
dhcp_last_ip = str(server_net['network']['dhcp_last_ip'])
dhcp_cidr = str(server_net['network']['cidr'])
gateway = str(server_net['network']['gateway_ip'])
- set_mac_dhcp(vm_dhcp_ip, vlan, dhcp_firt_ip, dhcp_last_ip, dhcp_cidr, c2[0]['mac'])
+
http_controller = config_dic['http_threads'][threading.current_thread().name]
- http_controller.ovim.launch_dhcp_server(vlan, dhcp_firt_ip, dhcp_last_ip, dhcp_cidr, gateway)
+ http_controller.ovim.launch_dhcp_server(vlan, dhcp_firt_ip, dhcp_last_ip,
+ dhcp_cidr, gateway, dns, routes)
+ set_mac_dhcp(vm_dhcp_ip, vlan, dhcp_firt_ip, dhcp_last_ip, dhcp_cidr, c2[0]['mac'])
+
+ if links:
+ http_controller.ovim.launch_link_bridge_to_ovs(vlan, gateway, dhcp_cidr, links, routes)
+
#Start server
server['uuid'] = new_instance
@@ -1679,6 +1702,7 @@
bottle.abort(HTTP_Bad_Request, content)
return
+
def http_server_action(server_id, tenant_id, action):
'''Perform actions over a server as resume, reboot, terminate, ...'''
my = config_dic['http_threads'][ threading.current_thread().name ]
@@ -1830,14 +1854,22 @@
#print "dhcp insert del task"
if r < 0:
print ':http_post_servers ERROR UPDATING dhcp_server !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c
- # delete ovs-port and linux bridge, contains a list of tuple (net_id,vlan)
+ # delete ovs-port and linux bridge, contains a list of tuple (net_id,vlan, vm_ip, mac)
+
for net in net_ovs_list:
mac = str(net[3])
vm_ip = str(net[2])
vlan = str(net[1])
net_id = net[0]
+
delete_dhcp_ovs_bridge(vlan, net_id)
delete_mac_dhcp(vm_ip, vlan, mac)
+
+ net_data = my.ovim.show_network(net_id)
+ if net_data.get('links'):
+ links = yaml.load(net_data.get('links'))
+ my.ovim.delete_link_bridge_to_ovs(vlan, links)
+
config_dic['host_threads'][server['host_id']].insert_task('del-ovs-port', vlan, net_id)
if warn_text:
data["result"] += warn_text
@@ -1956,7 +1988,7 @@
try:
# parse input data
- http_content = format_in(network_new_schema )
+ http_content = format_in(network_new_schema)
r = remove_extra_items(http_content, network_new_schema)
if r is not None:
print "http_post_networks: Warning: remove extra items ", r
diff --git a/osm_openvim/ovim.py b/osm_openvim/ovim.py
index 6472cc1..2fca38f 100755
--- a/osm_openvim/ovim.py
+++ b/osm_openvim/ovim.py
@@ -28,6 +28,7 @@
"""
import threading
+import yaml
import vim_db
import logging
# import imp
@@ -42,9 +43,9 @@
__author__ = "Alfonso Tierno, Leonardo Mirabal"
__date__ = "$06-Feb-2017 12:07:15$"
-__version__ = "0.5.17-r533"
+__version__ = "0.5.18-r534"
version_date = "Jun 2017"
-database_version = 20 #needed database schema version
+database_version = 21 #needed database schema version
HTTP_Bad_Request = 400
HTTP_Unauthorized = 401
@@ -146,7 +147,7 @@
if "dhcp_last_ip" not in network:
network["dhcp_last_ip"] = str(ips[-2])
if "gateway_ip" not in network:
- network["gateway_ip"] = str(ips[2])
+ network["gateway_ip"] = str(ips[1])
return True
else:
@@ -285,11 +286,16 @@
if (net_type == 'bridge_data' or net_type == 'bridge_man') and \
net["provider"][:4] == 'OVS:' and net["enable_dhcp"] == "true":
try:
- self.launch_dhcp_server(net['vlan'],
- net['dhcp_first_ip'],
- net['dhcp_last_ip'],
- net['cidr'],
- net['gateway_ip'])
+ routes = yaml.safe_load(net.get('routes'))
+ dns = yaml.safe_load(net.get('dns'))
+ self.launch_dhcp_server(net.get('vlan'),
+ net.get('dhcp_first_ip'),
+ net.get('dhcp_last_ip'),
+ net.get('cidr'),
+ net.get('gateway_ip'),
+ dns,
+ routes)
+ self.launch_link_bridge_to_ovs(net['vlan'], net.get('links'), net.get('routes'))
except Exception as e:
self.logger.error("Fail at launching dhcp server for net_id='%s' net_name='%s': %s",
net["uuid"], net["name"], str(e))
@@ -640,6 +646,13 @@
dhcp_integrity = True
if 'enable_dhcp' in network and network['enable_dhcp']:
dhcp_integrity = self._check_dhcp_data_integrity(network)
+
+ if network.get('links'):
+ network['links'] = yaml.safe_dump(network['links'], default_flow_style=True, width=256)
+ if network.get('dns'):
+ network['dns'] = yaml.safe_dump(network['dns'], default_flow_style=True, width=256)
+ if network.get('routes'):
+ network['routes'] = yaml.safe_dump(network['routes'], default_flow_style=True, width=256)
result, content = self.db.new_row('nets', network, True, True)
@@ -1392,7 +1405,7 @@
return dhcp_host
- def launch_dhcp_server(self, vlan, first_ip, last_ip, cidr, gateway):
+ def launch_dhcp_server(self, vlan, first_ip, last_ip, cidr, gateway, dns, routes):
"""
Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
:param vlan: vlan identifier
@@ -1409,9 +1422,49 @@
dhcp_path = self.config['ovs_controller_file_path']
controller_host = self.get_dhcp_controller()
- controller_host.create_linux_bridge(vlan)
- controller_host.create_dhcp_interfaces(vlan, gateway, dhcp_netmask)
- controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path, gateway)
+ # TODO leo check if is need ti to create an ovim-vlan bridge, looks like not
+ # controller_host.create_linux_bridge(vlan)
+ controller_host.create_dhcp_interfaces(vlan, first_ip, dhcp_netmask)
+ dhcp_path = self.config['ovs_controller_file_path']
+ controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path, gateway, dns, routes)
+
+ def launch_link_bridge_to_ovs(self, vlan, gateway, dhcp_cidr, links=None, routes=None):
+ """
+ Launch creating of connections (veth) between user bridge (link) and OVS
+ :param vlan:
+ :param gateway:
+ :param links:
+ :return:
+ """
+
+ if links:
+ controller_host = self.get_dhcp_controller()
+ for link in links:
+ if 'iface' in link and 'nat' not in link:
+ controller_host.create_link_bridge_to_ovs(vlan, link['iface'])
+ elif 'nat' in link:
+ controller_host.create_qrouter_ovs_connection(vlan, gateway, dhcp_cidr)
+ controller_host.create_qrouter_br_connection(vlan, dhcp_cidr, link)
+
+ if len(routes):
+ controller_host.add_ns_routes(vlan, routes)
+
+ def delete_link_bridge_to_ovs(self, vlan, links=None):
+ """
+ Delete connections (veth) between user bridge (link) and OVS
+ :param vlan:
+ :param links:
+ :return:
+ """
+ if links:
+ controller_host = self.get_dhcp_controller()
+
+ for link in links:
+ if 'iface' in link and 'nat' not in link:
+ controller_host.remove_link_bridge_to_ovs(vlan, link['iface'])
+ elif 'nat' in link:
+ controller_host.delete_qrouter_connection(vlan, link['iface'])
+
if __name__ == "__main__":
diff --git a/osm_openvim/vim_db.py b/osm_openvim/vim_db.py
index 5fc7c91..0c2d9f1 100644
--- a/osm_openvim/vim_db.py
+++ b/osm_openvim/vim_db.py
@@ -1428,6 +1428,9 @@
used_dhcp_ips = self._get_dhcp_ip_used_list(iface["net_id"])
iface["ip_address"] = self.get_free_ip_from_range(dhcp_first_ip, dhcp_last_ip,
dhcp_cidr, used_dhcp_ips)
+ del iface['links']
+ del iface['dns']
+ del iface['routes']
iface['uuid'] = str(myUuid.uuid1()) # create_uuid
cmd = "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface['uuid'], uuid)
@@ -1443,6 +1446,7 @@
else:
iface['mac'] = iface['mac_address']
del iface['mac_address']
+
#iface['mac']=iface.pop('mac_address', None) #for leaving mac generation to libvirt
keys = ",".join(iface.keys())
values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", iface.values() ) )
@@ -1552,6 +1556,7 @@
ip_used_list.append(str(ips[1])) # gw ip
ip_used_list.append(str(ips[-1])) # broadcast ip
+ ip_used_list.append(first_ip)
for vm_ip in ips:
if str(vm_ip) not in ip_used_list and IPAddress(first_ip) <= IPAddress(vm_ip) <= IPAddress(last_ip):
diff --git a/osm_openvim/vim_schema.py b/osm_openvim/vim_schema.py
index 1925f05..4689a89 100644
--- a/osm_openvim/vim_schema.py
+++ b/osm_openvim/vim_schema.py
@@ -603,10 +603,26 @@
"enable_dhcp": {"type": "boolean"},
"dhcp_first_ip": ip_schema,
"dhcp_last_ip": ip_schema,
+ "dns": {"type": "array", "items": [ip_schema]},
+ "links": {"type": "array", "items": {"type": "object", "properties": {
+ "nat": cidr_schema,
+ "iface": name_schema,
+ "vlan": vlan_schema},
+ "required": ["iface"],
+ "additionalProperties": False
+ },
+
+ },
+ "routes": {"type": "object", "properties": {"default": ip_schema}, "patternProperties": {
+ "^([0-9]{1,3}.){3}[0-9]{1,3}/[0-9]{1,2}$": ip_schema,
+ },
+ "additionalProperties": False
+ },
+
"bind_net": name_schema, # can be name, or uuid
"bind_type": {"oneOf": [{"type": "null"}, {"type": "string", "pattern": "^vlan:[0-9]{1,4}$"}]}
},
- "required": ["name"]
+ "required": ["name"]
}
},
"required": ["network"],