Alexander Lane | ea2d5d6 | 2019-10-04 16:48:52 -0500 | [diff] [blame^] | 1 | # -*- 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 | |
| 24 | import argparse |
| 25 | import sys |
| 26 | import time |
| 27 | import os |
| 28 | import configparser |
| 29 | from subprocess import call, check_output, Popen |
| 30 | from sys import exit |
| 31 | |
| 32 | from mininet.link import TCLink |
| 33 | from mininet.node import Switch |
| 34 | from mininet.util import ipStr, ipParse |
| 35 | from mininet.log import info, debug |
| 36 | |
| 37 | from mn_wifi.topo import Topo as Topo_WiFi |
| 38 | from mn_wifi.net import Mininet_wifi |
| 39 | from mn_wifi.node import OVSKernelAP |
| 40 | from mn_wifi.link import WirelessLink |
| 41 | |
| 42 | from minindn.minindn import Minindn |
| 43 | |
| 44 | class 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) |