blob: 280a5a42571b93a0ef4283ff94375601662e46d5 [file] [log] [blame]
Ashlesh Gawande6c86e302019-09-17 22:27:05 -05001# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2#
dulalsaurab20855442021-05-21 20:37:03 +00003# Copyright (C) 2015-2021, The University of Memphis,
Ashlesh Gawande6c86e302019-09-17 22:27:05 -05004# Arizona Board of Regents,
5# Regents of the University of California.
6#
7# This file is part of Mini-NDN.
8# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
9#
10# Mini-NDN is free software: you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation, either version 3 of the License, or
13# (at your option) any later version.
14#
15# Mini-NDN is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with Mini-NDN, e.g., in COPYING.md file.
22# If not, see <http://www.gnu.org/licenses/>.
23
24import shutil
25import os, sys
26
27from mininet.clean import sh
28from mininet.examples.cluster import RemoteMixin
29from mininet.log import warn
30from mininet.node import Switch
31
32from minindn.apps.application import Application
33from minindn.util import scp, copyExistentFile
34from minindn.helpers.nfdc import Nfdc
35from minindn.minindn import Minindn
36
37class Nlsr(Application):
38 ROUTING_LINK_STATE = 'link-state'
39 ROUTING_HYPERBOLIC = 'hr'
40 ROUTING_DRY_RUN = 'dry'
41 SYNC_PSYNC = 'psync'
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050042
43 def __init__(self, node, logLevel='NONE', security=False, sync=SYNC_PSYNC,
44 faceType='udp', nFaces=3, routingType=ROUTING_LINK_STATE):
45 Application.__init__(self, node)
46
47 self.network = '/ndn/'
48 self.node = node
49 self.parameters = self.node.params['params']
50
51 if self.parameters.get('nlsr-log-level', None) != None:
52 logLevel = self.parameters.get('nlsr-log-level')
53
54 if logLevel in ['NONE', 'WARN', 'INFO', 'DEBUG', 'TRACE']:
55 self.envDict = {'NDN_LOG': 'nlsr.*={}'.format(logLevel)}
56 else:
57 self.envDict = {'NDN_LOG': logLevel}
58
59 self.logFile = 'nlsr.log'
60 self.routerName = '/{}C1.Router/cs/{}'.format('%', node.name)
61 self.confFile = '{}/nlsr.conf'.format(self.homeDir)
62 self.security = security
63 self.sync = sync
64 self.faceType = faceType
65 self.infocmd = 'infoedit -f nlsr.conf'
66
67 self.parameters = self.node.params['params']
68
69 self.nFaces = nFaces
70 if routingType == Nlsr.ROUTING_HYPERBOLIC:
71 self.hyperbolicState = 'on'
72 elif routingType == Nlsr.ROUTING_DRY_RUN:
73 self.hyperbolicState = 'dry-run'
74 else:
75 self.hyperbolicState = 'off'
76 self.hyperRadius = self.parameters.get('radius', 0.0)
77 self.hyperAngle = self.parameters.get('angle', 0.0)
78
79 if ((self.hyperbolicState == 'on' or self.hyperbolicState == 'dry-run') and
80 (self.hyperRadius == 0.0 or self.hyperAngle == 0.0)):
81 warn('Hyperbolic coordinates in topology file are either missing or misconfigured.')
82 warn('Check that each node has one radius value and one or two angle value(s).')
83 sys.exit(1)
84
85 self.neighborIPs = []
86 possibleConfPaths = ['/usr/local/etc/ndn/nlsr.conf.sample', '/etc/ndn/nlsr.conf.sample']
87 copyExistentFile(node, possibleConfPaths, '{}/nlsr.conf'.format(self.homeDir))
88
89 self.createConfigFile()
90
91 if security and not Minindn.ndnSecurityDisabled:
92 self.createKeysAndCertificates()
93
94 def start(self):
95 self.createFaces()
96 Application.start(self, 'nlsr -f {}'.format(self.confFile), self.logFile, self.envDict)
97 Minindn.sleep(1)
98
99 def createFaces(self):
100 for ip in self.neighborIPs:
101 Nfdc.createFace(self.node, ip, self.faceType, isPermanent=True)
102
103 @staticmethod
104 def createKey(host, name, outputFile):
105 host.cmd('ndnsec-keygen {} > {}'.format(name, outputFile))
106
107 @staticmethod
108 def createCertificate(host, signer, keyFile, outputFile):
109 host.cmd('ndnsec-certgen -s {} -r {} > {}'.format(signer, keyFile, outputFile))
110
111 def createKeysAndCertificates(self):
Italo Valcyccd85b12020-07-24 12:35:20 -0500112 securityDir = '{}/security'.format(Minindn.workDir)
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500113
114 if not os.path.exists(securityDir):
115 os.mkdir(securityDir)
116
117 rootName = self.network
118 rootCertFile = '{}/root.cert'.format(securityDir)
119 if not os.path.isfile(rootCertFile):
120 # Create root certificate
121 sh('ndnsec-keygen {}'.format(rootName)) # Installs a self-signed cert into the system
122 sh('ndnsec-cert-dump -i {} > {}'.format(rootName, rootCertFile))
123
124 # Create necessary certificates for each site
125 nodeSecurityFolder = '{}/security'.format(self.homeDir)
126
127 self.node.cmd('mkdir -p {}'.format(nodeSecurityFolder))
128
129 # Create temp folders for remote nodes on this machine (localhost) to store site.key file
130 # from RemoteNodes
131 if not os.path.exists(nodeSecurityFolder) and \
132 isinstance(self.node, RemoteMixin) and self.node.isRemote:
133 os.makedirs(nodeSecurityFolder)
134
135 shutil.copyfile('{}/root.cert'.format(securityDir),
136 '{}/root.cert'.format(nodeSecurityFolder))
137
138 # Create site certificate
139 siteName = '{}{}-site'.format(self.network, self.node.name)
140 siteKeyFile = '{}/site.keys'.format(nodeSecurityFolder)
141 siteCertFile = '{}/site.cert'.format(nodeSecurityFolder)
142 Nlsr.createKey(self.node, siteName, siteKeyFile)
143
144 # Copy siteKeyFile from remote for ndnsec-certgen
145 if isinstance(self.node, RemoteMixin) and self.node.isRemote:
146 login = 'mininet@{}'.format(self.node.server)
147 src = '{}:{}'.format(login, siteKeyFile)
148 dst = siteKeyFile
149 scp(src, dst)
150
151 # Root key is in root namespace, must sign site key and then install on host
152 sh('ndnsec-certgen -s {} -r {} > {}'.format(rootName, siteKeyFile, siteCertFile))
153
154 # Copy root.cert and site.cert from localhost to remote host
155 if isinstance(self.node, RemoteMixin) and self.node.isRemote:
156 login = 'mininet@{}'.format(self.node.server)
157 src = '{}/site.cert'.format(nodeSecurityFolder)
158 src2 = '{}/root.cert'.format(nodeSecurityFolder)
159 dst = '{}:/tmp/'.format(login)
160 scp(src, src2, dst)
161 self.node.cmd('mv /tmp/*.cert {}'.format(nodeSecurityFolder))
162
163 self.node.cmd('ndnsec-cert-install -f {}'.format(siteCertFile))
164
165 # Create and install operator certificate
166 opName = '{}/%C1.Operator/op'.format(siteName)
167 opKeyFile = '{}/op.keys'.format(nodeSecurityFolder)
168 opCertFile = '{}/op.cert'.format(nodeSecurityFolder)
169 Nlsr.createKey(self.node, opName, opKeyFile)
170 Nlsr.createCertificate(self.node, siteName, opKeyFile, opCertFile)
171 self.node.cmd('ndnsec-cert-install -f {}'.format(opCertFile))
172
173 # Create and install router certificate
174 routerName = '{}/%C1.Router/cs/{}'.format(siteName, self.node.name)
175 routerKeyFile = '{}/router.keys'.format(nodeSecurityFolder)
176 routerCertFile = '{}/router.cert'.format(nodeSecurityFolder)
177 Nlsr.createKey(self.node, routerName, routerKeyFile)
178 Nlsr.createCertificate(self.node, opName, routerKeyFile, routerCertFile)
179 self.node.cmd('ndnsec-cert-install -f {}'.format(routerCertFile))
180
181 def createConfigFile(self):
182
183 self.__editGeneralSection()
184 self.__editNeighborsSection()
185 self.__editHyperbolicSection()
186 self.__editFibSection()
187 self.__editAdvertisingSection()
188 self.__editSecuritySection()
189
190 def __editGeneralSection(self):
191
192 self.node.cmd('{} -s general.network -v {}'.format(self.infocmd, self.network))
193 self.node.cmd('{} -s general.site -v /{}-site'.format(self.infocmd, self.node.name))
194 self.node.cmd('{} -s general.router -v /%C1.Router/cs/{}'.format(self.infocmd, self.node.name))
195 self.node.cmd('{} -s general.state-dir -v {}/log'.format(self.infocmd, self.homeDir))
196 self.node.cmd('{} -s general.sync-protocol -v {}'.format(self.infocmd, self.sync))
197
198 def __editNeighborsSection(self):
199
200 self.node.cmd('{} -d neighbors.neighbor'.format(self.infocmd))
201 for intf in self.node.intfList():
202 link = intf.link
203 if not link:
204 continue
205
206 node1, node2 = link.intf1.node, link.intf2.node
207
208 # Todo: add some switch support
209 if isinstance(node1, Switch) or isinstance(node2, Switch):
210 continue
211
212 if node1 == self.node:
213 other = node2
214 ip = other.IP(str(link.intf2))
215 else:
216 other = node1
217 ip = other.IP(str(link.intf1))
218
219 linkCost = intf.params.get('delay', '10ms').replace('ms', '')
220
221 self.neighborIPs.append(ip)
222
223 self.node.cmd('{} -a neighbors.neighbor \
224 <<<\'name {}{}-site/%C1.Router/cs/{} face-uri {}://{}\n link-cost {}\''
225 .format(self.infocmd, self.network, other.name, other.name,
226 self.faceType, ip, linkCost))
227
228 def __editHyperbolicSection(self):
229
230 self.node.cmd('{} -s hyperbolic.state -v {}'.format(self.infocmd, self.hyperbolicState))
231 self.node.cmd('{} -s hyperbolic.radius -v {}'.format(self.infocmd, self.hyperRadius))
232 self.node.cmd('{} -s hyperbolic.angle -v {}'.format(self.infocmd, self.hyperAngle))
233
234 def __editFibSection(self):
235
236 self.node.cmd('{} -s fib.max-faces-per-prefix -v {}'.format(self.infocmd, self.nFaces))
237
238 def __editAdvertisingSection(self):
239
240 self.node.cmd('{} -d advertising.prefix'.format(self.infocmd))
241 self.node.cmd('{} -s advertising.prefix -v {}{}-site/{}'
242 .format(self.infocmd, self.network, self.node.name, self.node.name))
243
244 def __editSecuritySection(self):
245
246 self.node.cmd('{} -d security.cert-to-publish'.format(self.infocmd))
247 if not self.security:
248 self.node.cmd('{} -s security.validator.trust-anchor.type -v any'.format(self.infocmd))
249 self.node.cmd('{} -d security.validator.trust-anchor.file-name'.format(self.infocmd))
250 self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.type -v any'.format(self.infocmd))
251 self.node.cmd('{} -d security.prefix-update-validator.trust-anchor.file-name'.format(self.infocmd))
252 else:
253 self.node.cmd('{} -s security.validator.trust-anchor.file-name -v security/root.cert'.format(self.infocmd))
254 self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.file-name -v security/site.cert'.format(self.infocmd))
255 self.node.cmd('{} -p security.cert-to-publish -v security/site.cert'.format(self.infocmd))
256 self.node.cmd('{} -p security.cert-to-publish -v security/op.cert'.format(self.infocmd))
257 self.node.cmd('{} -p security.cert-to-publish -v security/router.cert'.format(self.infocmd))