blob: 36ef97137491a4c6b344a54c9e494780a30ae987 [file] [log] [blame]
# -*- 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))