**breaking** mini-ndn: re-design
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
diff --git a/minindn/apps/nlsr.py b/minindn/apps/nlsr.py
new file mode 100644
index 0000000..36ef971
--- /dev/null
+++ b/minindn/apps/nlsr.py
@@ -0,0 +1,258 @@
+# -*- 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))