blob: b5b85467be8b50a2c021829fd1ef042983e42243 [file] [log] [blame]
A R Karthick8cf29ac2016-06-30 16:25:14 -07001#
2# Copyright 2016-present Ciena Corporation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16import unittest
17from nose.tools import *
18from nose.twistedtools import reactor, deferred
19from twisted.internet import defer
20from scapy.all import *
21import time
22import os
23from DHCP import DHCPTest
24from OnosCtrl import OnosCtrl
25from OnosFlowCtrl import get_mac
26from portmaps import g_subscriber_port_map
27log.setLevel('INFO')
28
29class dhcprelay_exchange(unittest.TestCase):
30
31 app = 'org.onosproject.dhcprelay'
32 app_dhcp = 'org.onosproject.dhcp'
33 relay_device_id = 'of:' + get_mac('ovsbr0')
34 relay_interface_port = 100
35 relay_interfaces = (g_subscriber_port_map[relay_interface_port],)
36 interface_to_mac_map = {}
37 dhcp_data_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'setup')
38 default_config = { 'default-lease-time' : 600, 'max-lease-time' : 7200, }
39 default_options = [ ('subnet-mask', '255.255.255.0'),
40 ('broadcast-address', '192.168.1.255'),
41 ('domain-name-servers', '192.168.1.1'),
42 ('domain-name', '"mydomain.cord-tester"'),
43 ]
44 ##specify the IP for the dhcp interface matching the subnet and subnet config
45 ##this is done for each interface dhcpd server would be listening on
46 default_subnet_config = [ ('192.168.1.2',
47'''
48subnet 192.168.1.0 netmask 255.255.255.0 {
49 range 192.168.1.10 192.168.1.100;
50}
51'''), ]
52
53 @classmethod
54 def setUpClass(cls):
55 ''' Activate the dhcprelay app'''
56 OnosCtrl(cls.app_dhcp).deactivate()
57 time.sleep(3)
58 cls.onos_ctrl = OnosCtrl(cls.app)
59 status, _ = cls.onos_ctrl.activate()
60 assert_equal(status, True)
61 time.sleep(3)
62 ##start dhcpd initially with default config
63 cls.dhcpd_start()
64 cls.onos_dhcp_relay_load()
65
66 @classmethod
67 def tearDownClass(cls):
68 '''Deactivate the dhcp relay app'''
69 try:
70 os.unlink('{}/dhcpd.conf'.format(cls.dhcp_data_dir))
71 os.unlink('{}/dhcpd.leases'.format(cls.dhcp_data_dir))
72 except: pass
73 cls.onos_ctrl.deactivate()
74 cls.dhcpd_stop()
75
76 @classmethod
77 def onos_load_config(cls, config):
78 status, code = OnosCtrl.config(config)
79 if status is False:
80 log.info('JSON request returned status %d' %code)
81 assert_equal(status, True)
82 time.sleep(3)
83
84 @classmethod
85 def onos_dhcp_relay_load(cls):
86 relay_device_map = '{}/{}'.format(cls.relay_device_id, cls.relay_interface_port)
87 dhcp_dict = {'apps':{'org.onosproject.dhcp-relay':{'dhcprelay':
88 {'dhcpserverConnectPoint':relay_device_map}}}}
89 cls.onos_load_config(dhcp_dict)
90
91 @classmethod
92 def host_load(cls, iface):
93 '''Have ONOS discover the hosts for dhcp-relay responses'''
94 port = g_subscriber_port_map[iface]
95 host = '173.17.1.{}'.format(port)
96 cmds = ( 'ifconfig {} 0'.format(iface),
97 'ifconfig {0} {1}'.format(iface, host),
98 'arping -I {0} {1} -c 2'.format(iface, host),
99 'ifconfig {} 0'.format(iface), )
100 for c in cmds:
101 os.system(c)
102
103 @classmethod
104 def dhcpd_conf_generate(cls, config = default_config, options = default_options,
105 subnet = default_subnet_config):
106 conf = ''
107 for k, v in config.items():
108 conf += '{} {};\n'.format(k, v)
109
110 opts = ''
111 for k, v in options:
112 opts += 'option {} {};\n'.format(k, v)
113
114 subnet_config = ''
115 for _, v in subnet:
116 subnet_config += '{}\n'.format(v)
117
118 return '{}{}{}'.format(conf, opts, subnet_config)
119
120 @classmethod
121 def dhcpd_start(cls, intf_list = relay_interfaces,
122 config = default_config, options = default_options,
123 subnet = default_subnet_config):
124 '''Start the dhcpd server by generating the conf file'''
125 ##stop dhcpd if already running
126 cls.dhcpd_stop()
127 dhcp_conf = cls.dhcpd_conf_generate(config = config, options = options,
128 subnet = subnet)
129 ##first touch dhcpd.leases if it doesn't exist
130 lease_file = '{}/dhcpd.leases'.format(cls.dhcp_data_dir)
131 if os.access(lease_file, os.F_OK) is False:
132 with open(lease_file, 'w') as fd: pass
133
134 conf_file = '{}/dhcpd.conf'.format(cls.dhcp_data_dir)
135 with open(conf_file, 'w') as fd:
136 fd.write(dhcp_conf)
137
138 #now configure the dhcpd interfaces for various subnets
139 index = 0
140 for ip,_ in subnet:
141 intf = intf_list[index]
142 index += 1
143 os.system('ifconfig {} {}'.format(intf, ip))
144
145 intf_str = ','.join(intf_list)
146 dhcpd_cmd = '/usr/sbin/dhcpd -4 --no-pid -cf {0} -lf {1} {2}'.format(conf_file, lease_file, intf_str)
147 log.info('Starting DHCPD server with command: %s' %dhcpd_cmd)
148 ret = os.system(dhcpd_cmd)
149 assert_equal(ret, 0)
150 time.sleep(3)
151 cls.relay_interfaces = intf_list
152
153 @classmethod
154 def dhcpd_stop(cls):
155 os.system('pkill -9 dhcpd')
156 for intf in cls.relay_interfaces:
157 os.system('ifconfig {} 0'.format(intf))
158
159 def get_mac(self, iface):
160 if self.interface_to_mac_map.has_key(iface):
161 return self.interface_to_mac_map[iface]
162 mac = get_mac(iface, pad = 0)
163 self.interface_to_mac_map[iface] = mac
164 return mac
165
166 def send_recv(self, mac, update_seed = False, validate = True):
167 cip, sip = self.dhcp.discover(mac = mac, update_seed = update_seed)
168 if validate:
169 assert_not_equal(cip, None)
170 assert_not_equal(sip, None)
171 log.info('Got dhcp client IP %s from server %s for mac %s' %
172 (cip, sip, self.dhcp.get_mac(cip)[0]))
173 return cip,sip
174
175 def test_dhcp_1request(self, iface = 'veth0'):
176 mac = self.get_mac(iface)
177 self.host_load(iface)
178 ##we use the defaults for this test that serves as an example for others
179 ##You don't need to restart dhcpd server if retaining default config
180 config = self.default_config
181 options = self.default_options
182 subnet = self.default_subnet_config
183 dhcpd_interface_list = self.relay_interfaces
184 self.dhcpd_start(intf_list = dhcpd_interface_list,
185 config = config,
186 options = options,
187 subnet = subnet)
188 self.dhcp = DHCPTest(seed_ip = '10.10.10.1', iface = iface)
189 self.send_recv(mac)