blob: b2ca7f4f470c2d137b13e475cb4e4753b88d3984 [file] [log] [blame]
Alexander Laneea2d5d62019-10-04 16:48:52 -05001# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2#
3# Copyright (C) 2015-2020, The University of Memphis,
4# Arizona Board of Regents,
5# Regents of the University of California.
6#
7# This file is part of Mini-NDN.
8# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
9#
10# Mini-NDN is free software: you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation, either version 3 of the License, or
13# (at your option) any later version.
14#
15# Mini-NDN is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with Mini-NDN, e.g., in COPYING.md file.
22# If not, see <http://www.gnu.org/licenses/>.
23
24import argparse
25import sys
26import time
27import os
28import configparser
29from subprocess import call, check_output, Popen
30from sys import exit
31
32from mininet.link import TCLink
33from mininet.node import Switch
34from mininet.util import ipStr, ipParse
35from mininet.log import info, debug
36
37from mn_wifi.topo import Topo as Topo_WiFi
38from mn_wifi.net import Mininet_wifi
39from mn_wifi.node import OVSKernelAP
40from mn_wifi.link import WirelessLink
41
42from minindn.minindn import Minindn
43
44class MinindnWifi(Minindn):
45 """ Class for handling default args, Mininet object and home directories """
46 def __init__(self, parser=argparse.ArgumentParser(), topo=None, topoFile=None, **mininetParams):
47 """Create Mini-NDN-Wifi object
48 parser: Parent parser of Mini-NDN-Wifi parser (use to specify experiment arguments)
49 topo: Mininet topo object (optional)
50 topoFile: topology file location (optional)
51 mininetParams: Any params to pass to Mininet-WiFi
52 """
53 self.parser = self.parseArgs(parser)
54 self.args = self.parser.parse_args()
55
56 Minindn.workDir = self.args.workDir
57 Minindn.resultDir = self.args.resultDir
58
59 self.topoFile = None
60 if not topoFile:
61 # Args has default topology if none specified
62 self.topoFile = self.args.topoFile
63 else:
64 self.topoFile = topoFile
65
66 if topo is None:
67 try:
68 info('Using topology file {}\n'.format(self.topoFile))
69 self.topo = self.processTopo(self.topoFile)
70 except configparser.NoSectionError as e:
71 info('Error reading config file: {}\n'.format(e))
72 sys.exit(1)
73 else:
74 self.topo = topo
75
76 self.net = Mininet_wifi(topo=self.topo, ifb=self.args.ifb, link=WirelessLink, **mininetParams)
77
78 for host in self.net.stations:
79 if 'params' not in host.params:
80 host.params['params'] = {}
81 host.params['params']['workDir'] = Minindn.workDir
82 homeDir = "{}/{}".format(Minindn.workDir, host.name)
83 host.params['params']['homeDir'] = homeDir
84 debug(host.cmd("mkdir -p {}".format(homeDir)))
85 debug(host.cmd('export HOME={} && cd ~'.format(homeDir)))
86 try:
87 process = Popen(['ndnsec-get-default', '-k'], stdout=PIPE, stderr=PIPE)
88 output, error = process.communicate()
89 if process.returncode == 0:
90 Minindn.ndnSecurityDisabled = '/dummy/KEY/-%9C%28r%B8%AA%3B%60' in output
91 info('Dummy key chain patch is installed in ndn-cxx. Security will be disabled.\n')
92 else:
93 debug(error)
94 except:
95 pass
96
97 self.cleanups = []
98
99 @staticmethod
100 def parseArgs(parent):
101 parser = argparse.ArgumentParser(prog='minindn-wifi', parents=[parent], add_help=False)
102
103 # nargs='?' required here since optional argument
104 parser.add_argument('topoFile', nargs='?', default='/usr/local/etc/mini-ndn/singleap-topology.conf',
105 help='If no template_file is given, topologies/wifi/singleap-topology.conf will be used.')
106
107 parser.add_argument('--work-dir', action='store', dest='workDir', default='/tmp/minindn',
108 help='Specify the working directory; default is /tmp/minindn')
109
110 parser.add_argument('--result-dir', action='store', dest='resultDir', default=None,
111 help='Specify the full path destination folder where experiment results will be moved')
112
113 parser.add_argument('--mobility',action='store_true',dest='mobility',default=False,
114 help='Enable custom mobility for topology (defined in topology file)')
115
116 parser.add_argument('--model-mob',action='store_true',dest='modelMob',default=False,
117 help='Enable model mobility for topology (defined in topology file)')
118
119 parser.add_argument('--ifb',action='store_true',dest='ifb',default=False,
120 help='Simulate delay on receiver-side by use of virtual IFB devices (see docs)')
121
122 return parser
123
124 @staticmethod
125 def processTopo(topoFile):
126 config = configparser.ConfigParser(delimiters=' ')
127 config.read(topoFile)
128 topo = Topo_WiFi()
129
130 items = config.items('stations')
131 debug("Stations")
132 for item in items:
133 debug(item[0].split(':'))
134 name = item[0].split(':')[0]
135 params = {}
136 for param in item[1].split(' '):
137 if param == "_":
138 continue
139 key = param.split('=')[0]
140 value = param.split('=')[1]
141 if key in ['range']:
142 value = int(value)
143 params[key] = value
144
145 topo.addStation(name, **params)
146
147 try:
148 debug("Switches")
149 items = config.items('switches')
150 for item in items:
151 debug(item[0].split(':'))
152 name = item[0].split(':')[0]
153 topo.addSwitch(name)
154 except configparser.NoSectionError:
155 debug("Switches are optional")
156 pass
157
158 try:
159 debug("APs")
160 items = config.items('accessPoints')
161 for item in items:
162 debug(item[0].split(':'))
163 name = item[0].split(':')[0]
164 ap_params = {}
165 for param in item[1].split(' '):
166 if param == "_":
167 continue
168 key = param.split('=')[0]
169 value = param.split('=')[1]
170 if key in ['range']:
171 value = int(value)
172 ap_params[key] = value
173 topo.addAccessPoint(name, **ap_params)
174 except configparser.NoSectionError:
175 debug("APs are optional")
176 pass
177
178 items = config.items('links')
179 debug("Links")
180 for item in items:
181 link = item[0].split(':')
182 debug(link)
183 params = {}
184 for param in item[1].split(' '):
185 if param == "_":
186 continue
187 key = param.split('=')[0]
188 value = param.split('=')[1]
189 if key in ['bw', 'jitter', 'max_queue_size']:
190 value = int(value)
191 if key == 'loss':
192 value = float(value)
193 params[key] = value
194
195 topo.addLink(link[0], link[1], **params)
196
197 return topo
198
199 def startMobility(self, max_x=1000, max_y=1000, **kwargs):
200 """ Method to run a basic mobility setup on your net"""
201 self.net.plotGraph(max_x=max_x, max_y=max_y)
202 self.net.startMobility(**kwargs)
203
204 def startMobilityModel(self, max_x=1000, max_y=1000, **kwargs):
205 """ Method to run a mobility model on your net until exited"""
206 self.net.plotGraph(max_x=max_x, max_y=max_y)
207 self.net.setMobilityModel(**kwargs)