refs: #5062 Everything is now done through examples like Mininet. bin/minindn no longer provided as a binary installed in the system bin/minindnedit GUI: will no longer be maintained Remove cluster edition, will be re-introduced later Change-Id: Id4ef137cb2a04d1b0dd24d01941757363bbf7d26
259 lines
11 KiB
Python
259 lines
11 KiB
Python
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
|
|
#
|
|
# Copyright (C) 2015-2019, 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 shutil
|
|
import os, sys
|
|
|
|
from mininet.clean import sh
|
|
from mininet.examples.cluster import RemoteMixin
|
|
from mininet.log import warn
|
|
from mininet.node import Switch
|
|
|
|
from minindn.apps.application import Application
|
|
from minindn.util import scp, copyExistentFile
|
|
from minindn.helpers.nfdc import Nfdc
|
|
from minindn.minindn import Minindn
|
|
|
|
class Nlsr(Application):
|
|
ROUTING_LINK_STATE = 'link-state'
|
|
ROUTING_HYPERBOLIC = 'hr'
|
|
ROUTING_DRY_RUN = 'dry'
|
|
SYNC_PSYNC = 'psync'
|
|
SYNC_CHRONOSYNC = 'chronosync'
|
|
|
|
def __init__(self, node, logLevel='NONE', security=False, sync=SYNC_PSYNC,
|
|
faceType='udp', nFaces=3, routingType=ROUTING_LINK_STATE):
|
|
Application.__init__(self, node)
|
|
|
|
self.network = '/ndn/'
|
|
self.node = node
|
|
self.parameters = self.node.params['params']
|
|
|
|
if self.parameters.get('nlsr-log-level', None) != None:
|
|
logLevel = self.parameters.get('nlsr-log-level')
|
|
|
|
if logLevel in ['NONE', 'WARN', 'INFO', 'DEBUG', 'TRACE']:
|
|
self.envDict = {'NDN_LOG': 'nlsr.*={}'.format(logLevel)}
|
|
else:
|
|
self.envDict = {'NDN_LOG': logLevel}
|
|
|
|
self.logFile = 'nlsr.log'
|
|
self.routerName = '/{}C1.Router/cs/{}'.format('%', node.name)
|
|
self.confFile = '{}/nlsr.conf'.format(self.homeDir)
|
|
self.security = security
|
|
self.sync = sync
|
|
self.faceType = faceType
|
|
self.infocmd = 'infoedit -f nlsr.conf'
|
|
|
|
self.parameters = self.node.params['params']
|
|
|
|
self.nFaces = nFaces
|
|
if routingType == Nlsr.ROUTING_HYPERBOLIC:
|
|
self.hyperbolicState = 'on'
|
|
elif routingType == Nlsr.ROUTING_DRY_RUN:
|
|
self.hyperbolicState = 'dry-run'
|
|
else:
|
|
self.hyperbolicState = 'off'
|
|
self.hyperRadius = self.parameters.get('radius', 0.0)
|
|
self.hyperAngle = self.parameters.get('angle', 0.0)
|
|
|
|
if ((self.hyperbolicState == 'on' or self.hyperbolicState == 'dry-run') and
|
|
(self.hyperRadius == 0.0 or self.hyperAngle == 0.0)):
|
|
warn('Hyperbolic coordinates in topology file are either missing or misconfigured.')
|
|
warn('Check that each node has one radius value and one or two angle value(s).')
|
|
sys.exit(1)
|
|
|
|
self.neighborIPs = []
|
|
possibleConfPaths = ['/usr/local/etc/ndn/nlsr.conf.sample', '/etc/ndn/nlsr.conf.sample']
|
|
copyExistentFile(node, possibleConfPaths, '{}/nlsr.conf'.format(self.homeDir))
|
|
|
|
self.createConfigFile()
|
|
|
|
if security and not Minindn.ndnSecurityDisabled:
|
|
self.createKeysAndCertificates()
|
|
|
|
def start(self):
|
|
self.createFaces()
|
|
Application.start(self, 'nlsr -f {}'.format(self.confFile), self.logFile, self.envDict)
|
|
Minindn.sleep(1)
|
|
|
|
def createFaces(self):
|
|
for ip in self.neighborIPs:
|
|
Nfdc.createFace(self.node, ip, self.faceType, isPermanent=True)
|
|
|
|
@staticmethod
|
|
def createKey(host, name, outputFile):
|
|
host.cmd('ndnsec-keygen {} > {}'.format(name, outputFile))
|
|
|
|
@staticmethod
|
|
def createCertificate(host, signer, keyFile, outputFile):
|
|
host.cmd('ndnsec-certgen -s {} -r {} > {}'.format(signer, keyFile, outputFile))
|
|
|
|
def createKeysAndCertificates(self):
|
|
securityDir = '{}/security'.format(self.parameters['workDir'])
|
|
|
|
if not os.path.exists(securityDir):
|
|
os.mkdir(securityDir)
|
|
|
|
rootName = self.network
|
|
rootCertFile = '{}/root.cert'.format(securityDir)
|
|
if not os.path.isfile(rootCertFile):
|
|
# Create root certificate
|
|
sh('ndnsec-keygen {}'.format(rootName)) # Installs a self-signed cert into the system
|
|
sh('ndnsec-cert-dump -i {} > {}'.format(rootName, rootCertFile))
|
|
|
|
# Create necessary certificates for each site
|
|
nodeSecurityFolder = '{}/security'.format(self.homeDir)
|
|
|
|
self.node.cmd('mkdir -p {}'.format(nodeSecurityFolder))
|
|
|
|
# Create temp folders for remote nodes on this machine (localhost) to store site.key file
|
|
# from RemoteNodes
|
|
if not os.path.exists(nodeSecurityFolder) and \
|
|
isinstance(self.node, RemoteMixin) and self.node.isRemote:
|
|
os.makedirs(nodeSecurityFolder)
|
|
|
|
shutil.copyfile('{}/root.cert'.format(securityDir),
|
|
'{}/root.cert'.format(nodeSecurityFolder))
|
|
|
|
# Create site certificate
|
|
siteName = '{}{}-site'.format(self.network, self.node.name)
|
|
siteKeyFile = '{}/site.keys'.format(nodeSecurityFolder)
|
|
siteCertFile = '{}/site.cert'.format(nodeSecurityFolder)
|
|
Nlsr.createKey(self.node, siteName, siteKeyFile)
|
|
|
|
# Copy siteKeyFile from remote for ndnsec-certgen
|
|
if isinstance(self.node, RemoteMixin) and self.node.isRemote:
|
|
login = 'mininet@{}'.format(self.node.server)
|
|
src = '{}:{}'.format(login, siteKeyFile)
|
|
dst = siteKeyFile
|
|
scp(src, dst)
|
|
|
|
# Root key is in root namespace, must sign site key and then install on host
|
|
sh('ndnsec-certgen -s {} -r {} > {}'.format(rootName, siteKeyFile, siteCertFile))
|
|
|
|
# Copy root.cert and site.cert from localhost to remote host
|
|
if isinstance(self.node, RemoteMixin) and self.node.isRemote:
|
|
login = 'mininet@{}'.format(self.node.server)
|
|
src = '{}/site.cert'.format(nodeSecurityFolder)
|
|
src2 = '{}/root.cert'.format(nodeSecurityFolder)
|
|
dst = '{}:/tmp/'.format(login)
|
|
scp(src, src2, dst)
|
|
self.node.cmd('mv /tmp/*.cert {}'.format(nodeSecurityFolder))
|
|
|
|
self.node.cmd('ndnsec-cert-install -f {}'.format(siteCertFile))
|
|
|
|
# Create and install operator certificate
|
|
opName = '{}/%C1.Operator/op'.format(siteName)
|
|
opKeyFile = '{}/op.keys'.format(nodeSecurityFolder)
|
|
opCertFile = '{}/op.cert'.format(nodeSecurityFolder)
|
|
Nlsr.createKey(self.node, opName, opKeyFile)
|
|
Nlsr.createCertificate(self.node, siteName, opKeyFile, opCertFile)
|
|
self.node.cmd('ndnsec-cert-install -f {}'.format(opCertFile))
|
|
|
|
# Create and install router certificate
|
|
routerName = '{}/%C1.Router/cs/{}'.format(siteName, self.node.name)
|
|
routerKeyFile = '{}/router.keys'.format(nodeSecurityFolder)
|
|
routerCertFile = '{}/router.cert'.format(nodeSecurityFolder)
|
|
Nlsr.createKey(self.node, routerName, routerKeyFile)
|
|
Nlsr.createCertificate(self.node, opName, routerKeyFile, routerCertFile)
|
|
self.node.cmd('ndnsec-cert-install -f {}'.format(routerCertFile))
|
|
|
|
def createConfigFile(self):
|
|
|
|
self.__editGeneralSection()
|
|
self.__editNeighborsSection()
|
|
self.__editHyperbolicSection()
|
|
self.__editFibSection()
|
|
self.__editAdvertisingSection()
|
|
self.__editSecuritySection()
|
|
|
|
def __editGeneralSection(self):
|
|
|
|
self.node.cmd('{} -s general.network -v {}'.format(self.infocmd, self.network))
|
|
self.node.cmd('{} -s general.site -v /{}-site'.format(self.infocmd, self.node.name))
|
|
self.node.cmd('{} -s general.router -v /%C1.Router/cs/{}'.format(self.infocmd, self.node.name))
|
|
self.node.cmd('{} -s general.state-dir -v {}/log'.format(self.infocmd, self.homeDir))
|
|
self.node.cmd('{} -s general.sync-protocol -v {}'.format(self.infocmd, self.sync))
|
|
|
|
def __editNeighborsSection(self):
|
|
|
|
self.node.cmd('{} -d neighbors.neighbor'.format(self.infocmd))
|
|
for intf in self.node.intfList():
|
|
link = intf.link
|
|
if not link:
|
|
continue
|
|
|
|
node1, node2 = link.intf1.node, link.intf2.node
|
|
|
|
# Todo: add some switch support
|
|
if isinstance(node1, Switch) or isinstance(node2, Switch):
|
|
continue
|
|
|
|
if node1 == self.node:
|
|
other = node2
|
|
ip = other.IP(str(link.intf2))
|
|
else:
|
|
other = node1
|
|
ip = other.IP(str(link.intf1))
|
|
|
|
linkCost = intf.params.get('delay', '10ms').replace('ms', '')
|
|
|
|
self.neighborIPs.append(ip)
|
|
|
|
self.node.cmd('{} -a neighbors.neighbor \
|
|
<<<\'name {}{}-site/%C1.Router/cs/{} face-uri {}://{}\n link-cost {}\''
|
|
.format(self.infocmd, self.network, other.name, other.name,
|
|
self.faceType, ip, linkCost))
|
|
|
|
def __editHyperbolicSection(self):
|
|
|
|
self.node.cmd('{} -s hyperbolic.state -v {}'.format(self.infocmd, self.hyperbolicState))
|
|
self.node.cmd('{} -s hyperbolic.radius -v {}'.format(self.infocmd, self.hyperRadius))
|
|
self.node.cmd('{} -s hyperbolic.angle -v {}'.format(self.infocmd, self.hyperAngle))
|
|
|
|
def __editFibSection(self):
|
|
|
|
self.node.cmd('{} -s fib.max-faces-per-prefix -v {}'.format(self.infocmd, self.nFaces))
|
|
|
|
def __editAdvertisingSection(self):
|
|
|
|
self.node.cmd('{} -d advertising.prefix'.format(self.infocmd))
|
|
self.node.cmd('{} -s advertising.prefix -v {}{}-site/{}'
|
|
.format(self.infocmd, self.network, self.node.name, self.node.name))
|
|
|
|
def __editSecuritySection(self):
|
|
|
|
self.node.cmd('{} -d security.cert-to-publish'.format(self.infocmd))
|
|
if not self.security:
|
|
self.node.cmd('{} -s security.validator.trust-anchor.type -v any'.format(self.infocmd))
|
|
self.node.cmd('{} -d security.validator.trust-anchor.file-name'.format(self.infocmd))
|
|
self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.type -v any'.format(self.infocmd))
|
|
self.node.cmd('{} -d security.prefix-update-validator.trust-anchor.file-name'.format(self.infocmd))
|
|
else:
|
|
self.node.cmd('{} -s security.validator.trust-anchor.file-name -v security/root.cert'.format(self.infocmd))
|
|
self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.file-name -v security/site.cert'.format(self.infocmd))
|
|
self.node.cmd('{} -p security.cert-to-publish -v security/site.cert'.format(self.infocmd))
|
|
self.node.cmd('{} -p security.cert-to-publish -v security/op.cert'.format(self.infocmd))
|
|
self.node.cmd('{} -p security.cert-to-publish -v security/router.cert'.format(self.infocmd))
|