Add wireless simulation to redesigned Mini-NDN using Mininet-wifi.
refs: #4858 Change-Id: If9f7dd069203309c998ab2ff570a6cc8ee362434
This commit is contained in:
1 parent
5dbf99dd78
commit
ea2d5d6802
10 files changed
+354
-9
No files matched your search
@@ -12,6 +12,7 @@ docs/_build
|
||||
# Misc
|
||||
.DS_Store
|
||||
mininet
|
||||
mn_wifi
|
||||
ndn-src
|
||||
openflow
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
|
||||
#
|
||||
# Copyright (C) 2015-2020, The University of Memphis,
|
||||
# Arizona Board of Regents,
|
||||
# Regents of the University of California.
|
||||
#
|
||||
# This file is part of Mini-NDN.
|
||||
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
|
||||
#
|
||||
# Mini-NDN is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Mini-NDN is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Mini-NDN, e.g., in COPYING.md file.
|
||||
# If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from mininet.log import setLogLevel, info
|
||||
from minindn.wifi.minindnwifi import MinindnWifi
|
||||
from minindn.util import MiniNDNWifiCLI, getPopen
|
||||
from minindn.apps.app_manager import AppManager
|
||||
from minindn.apps.nfd import Nfd
|
||||
from minindn.helpers.nfdc import Nfdc
|
||||
from minindn.helpers.ndnpingclient import NDNPingClient
|
||||
from time import sleep
|
||||
# This experiment uses the singleap topology and is intended to be a basic
|
||||
# test case where we see if two nodes can send interests to each other.
|
||||
def runExperiment():
|
||||
setLogLevel('info')
|
||||
|
||||
info("Starting network")
|
||||
ndnwifi = MinindnWifi()
|
||||
a = ndnwifi.net["sta1"]
|
||||
b = ndnwifi.net["sta2"]
|
||||
# Test for model-based mobility
|
||||
if ndnwifi.args.modelMob:
|
||||
ndnwifi.startMobilityModel(model='GaussMarkov')
|
||||
#Test for replay based mobility
|
||||
if ndnwifi.args.mobility:
|
||||
info("Running with mobility...")
|
||||
|
||||
p1, p2, p3, p4 = dict(), dict(), dict(), dict()
|
||||
p1 = {'position': '40.0,30.0,0.0'}
|
||||
p2 = {'position': '40.0,40.0,0.0'}
|
||||
p3 = {'position': '31.0,10.0,0.0'}
|
||||
p4 = {'position': '200.0,200.0,0.0'}
|
||||
|
||||
ndnwifi.net.mobility(a, 'start', time=1, **p1)
|
||||
ndnwifi.net.mobility(b, 'start', time=2, **p2)
|
||||
ndnwifi.net.mobility(a, 'stop', time=12, **p3)
|
||||
ndnwifi.net.mobility(b, 'stop', time=22, **p4)
|
||||
ndnwifi.net.stopMobility(time=23)
|
||||
ndnwifi.startMobility(time=0, mob_rep=1, reverse=False)
|
||||
|
||||
ndnwifi.start()
|
||||
info("Starting NFD")
|
||||
sleep(2)
|
||||
nfds = AppManager(ndnwifi, ndnwifi.net.stations, Nfd)
|
||||
|
||||
info("Starting pingserver...")
|
||||
ping_server_proc = getPopen(b, "ndnpingserver /example")
|
||||
Nfdc.createFace(a, b.IP())
|
||||
Nfdc.registerRoute(a, "/example", b.IP())
|
||||
|
||||
info("Starting ping...")
|
||||
NDNPingClient.ping(a, "/example", 10)
|
||||
|
||||
# Start the CLI
|
||||
MiniNDNWifiCLI(ndnwifi.net)
|
||||
ndnwifi.net.stop()
|
||||
ndnwifi.cleanUp()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
runExperiment()
|
||||
except Exception as e:
|
||||
MinindnWifi.handleException()
|
||||
+29
-2
@@ -192,6 +192,22 @@ function mininet {
|
||||
popd
|
||||
}
|
||||
|
||||
function wifi {
|
||||
if [[ updated != true ]]; then
|
||||
$update
|
||||
updated="true"
|
||||
fi
|
||||
|
||||
if [[ $pysetup != true ]]; then
|
||||
pysetup="true"
|
||||
fi
|
||||
|
||||
git clone --depth 1 https://github.com/intrig-unicamp/mininet-wifi.git
|
||||
pushd mininet-wifi
|
||||
sudo ./util/install.sh -Wlfnv
|
||||
popd
|
||||
}
|
||||
|
||||
function infoedit {
|
||||
git clone --depth 1 https://github.com/NDN-Routing/infoedit.git $NDN_SRC/infoedit
|
||||
pushd $NDN_SRC/infoedit
|
||||
@@ -225,6 +241,7 @@ function minindn {
|
||||
sudo cp topologies/current-testbed.conf "$install_dir"
|
||||
sudo cp topologies/geo_hyperbolic_test.conf "$install_dir"
|
||||
sudo cp topologies/geant.conf "$install_dir"
|
||||
sudo cp topologies/wifi/singleap-topology.conf "$install_dir"
|
||||
sudo python setup.py develop
|
||||
}
|
||||
|
||||
@@ -347,25 +364,34 @@ function usage {
|
||||
|
||||
printf 'options:\n' >&2
|
||||
printf -- ' -a: install all the required dependencies\n' >&2
|
||||
printf -- ' -A: install all the required dependencies (wired only)\n' >&2
|
||||
printf -- ' -c: install Common Client Libraries\n' >&2
|
||||
printf -- ' -d: build documentation\n' >&2
|
||||
printf -- ' -h: print this (H)elp message\n' >&2
|
||||
printf -- ' -i: install mini-ndn\n' >&2
|
||||
printf -- ' -m: install mininet and dependencies\n' >&2
|
||||
printf -- ' -m: install mininet and dependencies (for wired-only installation)\n' >&2
|
||||
printf -- ' -n: install NDN dependencies of mini-ndn including infoedit\n' >&2
|
||||
printf -- ' -p: patch ndn-cxx with dummy key chain\n' >&2
|
||||
printf -- ' -q: quiet install (must be specified first)\n' >&2
|
||||
printf -- ' -w: install mininet-wifi and dependencies\n' >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
usage
|
||||
else
|
||||
while getopts 'acdhimnpq' OPTION
|
||||
while getopts 'aAcdhimnpqw' OPTION
|
||||
do
|
||||
case $OPTION in
|
||||
a)
|
||||
ndn
|
||||
wifi
|
||||
minindn
|
||||
commonClientLibraries
|
||||
break
|
||||
;;
|
||||
A)
|
||||
ndn
|
||||
mininet
|
||||
minindn
|
||||
commonClientLibraries
|
||||
@@ -379,6 +405,7 @@ else
|
||||
n) ndn;;
|
||||
p) patchDummy;;
|
||||
q) quiet_install;;
|
||||
w) wifi ;;
|
||||
?) usage;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -27,19 +27,21 @@ import time
|
||||
|
||||
class NDNPingClient(object):
|
||||
@staticmethod
|
||||
def ping(source, dest, nPings=1, interval=None, timeout=None, starting_seq_num=None,
|
||||
def ping(source, prefix, nPings=1, interval=None, timeout=None, starting_seq_num=None,
|
||||
identifier=None, allow_stale_data=False, print_timestamp=True, sleepTime=0.2):
|
||||
print('Scheduling ping(s) from {} to {}'.format(source.name, dest.name))
|
||||
print('Scheduling ping(s) from {} for {}'.format(source.name, prefix))
|
||||
# Use '&' to run in background and perform parallel pings
|
||||
source.cmd('ndnping{1}{2}{3}{4}{5}{6}{7} /ndn/{0}-site/{0} >> ping-data/{0}.txt &'
|
||||
source.cmd("mkdir ping-data")
|
||||
source.cmd('ndnping{1}{2}{3}{4}{5}{6}{7} {0} >> ping-data/{8}.txt &'
|
||||
.format(
|
||||
dest,
|
||||
prefix,
|
||||
' -c {}'.format(nPings),
|
||||
' -i {}'.format(interval) if interval else '',
|
||||
' -o {}'.format(timeout) if timeout else '',
|
||||
' -n {}'.format(starting_seq_num) if starting_seq_num else '',
|
||||
' -p {}'.format(identifier) if identifier else '',
|
||||
' -a' if allow_stale_data else '',
|
||||
' -t' if print_timestamp else ''
|
||||
' -t' if print_timestamp else '',
|
||||
str.replace(prefix[1:], "/", "-")
|
||||
))
|
||||
time.sleep(sleepTime)
|
||||
@@ -38,7 +38,7 @@ class Nfdc(object):
|
||||
@staticmethod
|
||||
def registerRoute(node, namePrefix, remoteNodeAddress, protocol=PROTOCOL_UDP, origin=255,
|
||||
cost=0, inheritFlag=True, captureFlag=False, expirationInMillis=None):
|
||||
cmd = ('nfdc route add {} {}://{} origin {} cost {} {}{}').format(
|
||||
cmd = ('nfdc route add {} {}://{} origin {} cost {} {}{}{}').format(
|
||||
namePrefix,
|
||||
protocol,
|
||||
remoteNodeAddress,
|
||||
|
||||
+9
-1
@@ -29,13 +29,14 @@ import configparser
|
||||
from subprocess import call, Popen, PIPE
|
||||
import shutil
|
||||
import glob
|
||||
from traceback import format_exc
|
||||
|
||||
from mininet.topo import Topo
|
||||
from mininet.net import Mininet
|
||||
from mininet.link import TCLink
|
||||
from mininet.node import Switch
|
||||
from mininet.util import ipStr, ipParse
|
||||
from mininet.log import info, error
|
||||
from mininet.log import info, debug, error
|
||||
|
||||
|
||||
class Minindn(object):
|
||||
@@ -232,3 +233,10 @@ class Minindn(object):
|
||||
# sleep is not required if ndn-cxx is using in-memory keychain
|
||||
if not Minindn.ndnSecurityDisabled:
|
||||
time.sleep(seconds)
|
||||
|
||||
@staticmethod
|
||||
def handleException():
|
||||
'Utility method to perform cleanup steps and exit after catching exception'
|
||||
Minindn.cleanUp()
|
||||
info(format_exc())
|
||||
exit(1)
|
||||
@@ -25,6 +25,7 @@ import sys
|
||||
from os.path import isfile
|
||||
from subprocess import call
|
||||
from mininet.cli import CLI
|
||||
from mn_wifi.cli import CLI as CLI_wifi
|
||||
|
||||
sshbase = ['ssh', '-q', '-t', '-i/home/mininet/.ssh/id_rsa']
|
||||
scpbase = ['scp', '-i', '/home/mininet/.ssh/id_rsa']
|
||||
@@ -75,3 +76,8 @@ class MiniNDNCLI(CLI):
|
||||
prompt = 'mini-ndn> '
|
||||
def __init__(self, mininet, stdin=sys.stdin, script=None):
|
||||
CLI.__init__(self, mininet, stdin, script)
|
||||
|
||||
class MiniNDNWifiCLI(CLI_wifi):
|
||||
prompt = 'mini-ndn-wifi> '
|
||||
def __init__(self, mininet, stdin=sys.stdin, script=None):
|
||||
CLI_wifi.__init__(self, mininet, stdin, script)
|
||||
Whitespace-only changes.
@@ -0,0 +1,207 @@
|
||||
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
|
||||
#
|
||||
# Copyright (C) 2015-2020, The University of Memphis,
|
||||
# Arizona Board of Regents,
|
||||
# Regents of the University of California.
|
||||
#
|
||||
# This file is part of Mini-NDN.
|
||||
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
|
||||
#
|
||||
# Mini-NDN is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Mini-NDN is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Mini-NDN, e.g., in COPYING.md file.
|
||||
# If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
import configparser
|
||||
from subprocess import call, check_output, Popen
|
||||
from sys import exit
|
||||
|
||||
from mininet.link import TCLink
|
||||
from mininet.node import Switch
|
||||
from mininet.util import ipStr, ipParse
|
||||
from mininet.log import info, debug
|
||||
|
||||
from mn_wifi.topo import Topo as Topo_WiFi
|
||||
from mn_wifi.net import Mininet_wifi
|
||||
from mn_wifi.node import OVSKernelAP
|
||||
from mn_wifi.link import WirelessLink
|
||||
|
||||
from minindn.minindn import Minindn
|
||||
|
||||
class MinindnWifi(Minindn):
|
||||
""" Class for handling default args, Mininet object and home directories """
|
||||
def __init__(self, parser=argparse.ArgumentParser(), topo=None, topoFile=None, **mininetParams):
|
||||
"""Create Mini-NDN-Wifi object
|
||||
parser: Parent parser of Mini-NDN-Wifi parser (use to specify experiment arguments)
|
||||
topo: Mininet topo object (optional)
|
||||
topoFile: topology file location (optional)
|
||||
mininetParams: Any params to pass to Mininet-WiFi
|
||||
"""
|
||||
self.parser = self.parseArgs(parser)
|
||||
self.args = self.parser.parse_args()
|
||||
|
||||
Minindn.workDir = self.args.workDir
|
||||
Minindn.resultDir = self.args.resultDir
|
||||
|
||||
self.topoFile = None
|
||||
if not topoFile:
|
||||
# Args has default topology if none specified
|
||||
self.topoFile = self.args.topoFile
|
||||
else:
|
||||
self.topoFile = topoFile
|
||||
|
||||
if topo is None:
|
||||
try:
|
||||
info('Using topology file {}\n'.format(self.topoFile))
|
||||
self.topo = self.processTopo(self.topoFile)
|
||||
except configparser.NoSectionError as e:
|
||||
info('Error reading config file: {}\n'.format(e))
|
||||
sys.exit(1)
|
||||
else:
|
||||
self.topo = topo
|
||||
|
||||
self.net = Mininet_wifi(topo=self.topo, ifb=self.args.ifb, link=WirelessLink, **mininetParams)
|
||||
|
||||
for host in self.net.stations:
|
||||
if 'params' not in host.params:
|
||||
host.params['params'] = {}
|
||||
host.params['params']['workDir'] = Minindn.workDir
|
||||
homeDir = "{}/{}".format(Minindn.workDir, host.name)
|
||||
host.params['params']['homeDir'] = homeDir
|
||||
debug(host.cmd("mkdir -p {}".format(homeDir)))
|
||||
debug(host.cmd('export HOME={} && cd ~'.format(homeDir)))
|
||||
try:
|
||||
process = Popen(['ndnsec-get-default', '-k'], stdout=PIPE, stderr=PIPE)
|
||||
output, error = process.communicate()
|
||||
if process.returncode == 0:
|
||||
Minindn.ndnSecurityDisabled = '/dummy/KEY/-%9C%28r%B8%AA%3B%60' in output
|
||||
info('Dummy key chain patch is installed in ndn-cxx. Security will be disabled.\n')
|
||||
else:
|
||||
debug(error)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.cleanups = []
|
||||
|
||||
@staticmethod
|
||||
def parseArgs(parent):
|
||||
parser = argparse.ArgumentParser(prog='minindn-wifi', parents=[parent], add_help=False)
|
||||
|
||||
# nargs='?' required here since optional argument
|
||||
parser.add_argument('topoFile', nargs='?', default='/usr/local/etc/mini-ndn/singleap-topology.conf',
|
||||
help='If no template_file is given, topologies/wifi/singleap-topology.conf will be used.')
|
||||
|
||||
parser.add_argument('--work-dir', action='store', dest='workDir', default='/tmp/minindn',
|
||||
help='Specify the working directory; default is /tmp/minindn')
|
||||
|
||||
parser.add_argument('--result-dir', action='store', dest='resultDir', default=None,
|
||||
help='Specify the full path destination folder where experiment results will be moved')
|
||||
|
||||
parser.add_argument('--mobility',action='store_true',dest='mobility',default=False,
|
||||
help='Enable custom mobility for topology (defined in topology file)')
|
||||
|
||||
parser.add_argument('--model-mob',action='store_true',dest='modelMob',default=False,
|
||||
help='Enable model mobility for topology (defined in topology file)')
|
||||
|
||||
parser.add_argument('--ifb',action='store_true',dest='ifb',default=False,
|
||||
help='Simulate delay on receiver-side by use of virtual IFB devices (see docs)')
|
||||
|
||||
return parser
|
||||
|
||||
@staticmethod
|
||||
def processTopo(topoFile):
|
||||
config = configparser.ConfigParser(delimiters=' ')
|
||||
config.read(topoFile)
|
||||
topo = Topo_WiFi()
|
||||
|
||||
items = config.items('stations')
|
||||
debug("Stations")
|
||||
for item in items:
|
||||
debug(item[0].split(':'))
|
||||
name = item[0].split(':')[0]
|
||||
params = {}
|
||||
for param in item[1].split(' '):
|
||||
if param == "_":
|
||||
continue
|
||||
key = param.split('=')[0]
|
||||
value = param.split('=')[1]
|
||||
if key in ['range']:
|
||||
value = int(value)
|
||||
params[key] = value
|
||||
|
||||
topo.addStation(name, **params)
|
||||
|
||||
try:
|
||||
debug("Switches")
|
||||
items = config.items('switches')
|
||||
for item in items:
|
||||
debug(item[0].split(':'))
|
||||
name = item[0].split(':')[0]
|
||||
topo.addSwitch(name)
|
||||
except configparser.NoSectionError:
|
||||
debug("Switches are optional")
|
||||
pass
|
||||
|
||||
try:
|
||||
debug("APs")
|
||||
items = config.items('accessPoints')
|
||||
for item in items:
|
||||
debug(item[0].split(':'))
|
||||
name = item[0].split(':')[0]
|
||||
ap_params = {}
|
||||
for param in item[1].split(' '):
|
||||
if param == "_":
|
||||
continue
|
||||
key = param.split('=')[0]
|
||||
value = param.split('=')[1]
|
||||
if key in ['range']:
|
||||
value = int(value)
|
||||
ap_params[key] = value
|
||||
topo.addAccessPoint(name, **ap_params)
|
||||
except configparser.NoSectionError:
|
||||
debug("APs are optional")
|
||||
pass
|
||||
|
||||
items = config.items('links')
|
||||
debug("Links")
|
||||
for item in items:
|
||||
link = item[0].split(':')
|
||||
debug(link)
|
||||
params = {}
|
||||
for param in item[1].split(' '):
|
||||
if param == "_":
|
||||
continue
|
||||
key = param.split('=')[0]
|
||||
value = param.split('=')[1]
|
||||
if key in ['bw', 'jitter', 'max_queue_size']:
|
||||
value = int(value)
|
||||
if key == 'loss':
|
||||
value = float(value)
|
||||
params[key] = value
|
||||
|
||||
topo.addLink(link[0], link[1], **params)
|
||||
|
||||
return topo
|
||||
|
||||
def startMobility(self, max_x=1000, max_y=1000, **kwargs):
|
||||
""" Method to run a basic mobility setup on your net"""
|
||||
self.net.plotGraph(max_x=max_x, max_y=max_y)
|
||||
self.net.startMobility(**kwargs)
|
||||
|
||||
def startMobilityModel(self, max_x=1000, max_y=1000, **kwargs):
|
||||
""" Method to run a mobility model on your net until exited"""
|
||||
self.net.plotGraph(max_x=max_x, max_y=max_y)
|
||||
self.net.setMobilityModel(**kwargs)
|
||||
@@ -0,0 +1,11 @@
|
||||
[stations]
|
||||
sta1: range=10 speed=5
|
||||
sta2: range=50
|
||||
[cars]
|
||||
|
||||
[accessPoints]
|
||||
ap1: position=50,50,50 range=50
|
||||
|
||||
[links]
|
||||
sta1:ap1 delay=10ms
|
||||
sta2:ap1 delay=10ms
|
||||
Reference in new issue
Block a user