Add wireless simulation to redesigned Mini-NDN using Mininet-wifi.

refs: #4858

Change-Id: If9f7dd069203309c998ab2ff570a6cc8ee362434
This commit is contained in:
Alexander Lane authored and Alex Lane committed 2020-10-08 15:01:18 -05:00
1 parent 5dbf99dd78
commit ea2d5d6802
10 files changed
+354 -9

No files matched your search

+1
View File
@@ -12,6 +12,7 @@ docs/_build
# Misc
.DS_Store
mininet
mn_wifi
ndn-src
openflow
+83
View File
@@ -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
View File
@@ -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
+7 -5
View File
@@ -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)
+1 -1
View File
@@ -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
View File
@@ -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)
+6
View File
@@ -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)
View File
Whitespace-only changes.
+207
View File
@@ -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)
+11
View File
@@ -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