blob: 43da64febf735f4eb93558bb714f69cb0613b0ed [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
awlane21acd052024-06-13 21:12:51 -050033from minindn.util import scp, copyExistentFile, MACToEther
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050034from 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,
awlane21acd052024-06-13 21:12:51 -050044 faceType=Nfdc.PROTOCOL_UDP, nFaces=3, routingType=ROUTING_LINK_STATE, faceDict=None):
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050045 Application.__init__(self, node)
awlaned8e6b8e2022-05-16 23:49:56 -050046 try:
47 from mn_wifi.node import Node_wifi
48 if isinstance(node, Node_wifi) and faceDict == None:
49 warn("Wifi nodes need to have faces configured manually. Please see \
50 documentation on provided helper methods.\r\n")
51 sys.exit(1)
52 except ImportError:
53 pass
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050054
55 self.network = '/ndn/'
56 self.node = node
57 self.parameters = self.node.params['params']
58
59 if self.parameters.get('nlsr-log-level', None) != None:
60 logLevel = self.parameters.get('nlsr-log-level')
61
62 if logLevel in ['NONE', 'WARN', 'INFO', 'DEBUG', 'TRACE']:
63 self.envDict = {'NDN_LOG': 'nlsr.*={}'.format(logLevel)}
64 else:
65 self.envDict = {'NDN_LOG': logLevel}
66
67 self.logFile = 'nlsr.log'
68 self.routerName = '/{}C1.Router/cs/{}'.format('%', node.name)
69 self.confFile = '{}/nlsr.conf'.format(self.homeDir)
70 self.security = security
71 self.sync = sync
72 self.faceType = faceType
73 self.infocmd = 'infoedit -f nlsr.conf'
awlaned8e6b8e2022-05-16 23:49:56 -050074 # Expected format- node : tuple (node name, IP, cost)
75 self.faceDict = faceDict
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050076
77 self.parameters = self.node.params['params']
78
79 self.nFaces = nFaces
80 if routingType == Nlsr.ROUTING_HYPERBOLIC:
81 self.hyperbolicState = 'on'
82 elif routingType == Nlsr.ROUTING_DRY_RUN:
83 self.hyperbolicState = 'dry-run'
84 else:
85 self.hyperbolicState = 'off'
86 self.hyperRadius = self.parameters.get('radius', 0.0)
87 self.hyperAngle = self.parameters.get('angle', 0.0)
88
89 if ((self.hyperbolicState == 'on' or self.hyperbolicState == 'dry-run') and
90 (self.hyperRadius == 0.0 or self.hyperAngle == 0.0)):
91 warn('Hyperbolic coordinates in topology file are either missing or misconfigured.')
92 warn('Check that each node has one radius value and one or two angle value(s).')
93 sys.exit(1)
94
awlane21acd052024-06-13 21:12:51 -050095 self.neighborLocations = []
96 self.interfaceForNeighbor = dict()
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050097 possibleConfPaths = ['/usr/local/etc/ndn/nlsr.conf.sample', '/etc/ndn/nlsr.conf.sample']
98 copyExistentFile(node, possibleConfPaths, '{}/nlsr.conf'.format(self.homeDir))
99
100 self.createConfigFile()
101
102 if security and not Minindn.ndnSecurityDisabled:
103 self.createKeysAndCertificates()
104
105 def start(self):
106 self.createFaces()
107 Application.start(self, 'nlsr -f {}'.format(self.confFile), self.logFile, self.envDict)
108 Minindn.sleep(1)
109
110 def createFaces(self):
awlane21acd052024-06-13 21:12:51 -0500111 for location in self.neighborLocations:
112 if self.faceType == Nfdc.PROTOCOL_ETHER:
113 localIntf = self.interfaceForNeighbor[location]
114 Nfdc.createFace(self.node, location, self.faceType, localInterface=localIntf, isPermanent=True)
115 else:
116 Nfdc.createFace(self.node, location, self.faceType, isPermanent=True)
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500117
118 @staticmethod
119 def createKey(host, name, outputFile):
suraviregmi9665f5c2023-11-09 20:05:26 +0000120 host.cmd('ndnsec-key-gen {} > {}'.format(name, outputFile))
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500121
122 @staticmethod
123 def createCertificate(host, signer, keyFile, outputFile):
suraviregmi9665f5c2023-11-09 20:05:26 +0000124 host.cmd('ndnsec-cert-gen -s {} -r {} > {}'.format(signer, keyFile, outputFile))
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500125
126 def createKeysAndCertificates(self):
Italo Valcyccd85b12020-07-24 12:35:20 -0500127 securityDir = '{}/security'.format(Minindn.workDir)
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500128
129 if not os.path.exists(securityDir):
130 os.mkdir(securityDir)
131
132 rootName = self.network
133 rootCertFile = '{}/root.cert'.format(securityDir)
134 if not os.path.isfile(rootCertFile):
135 # Create root certificate
suraviregmi9665f5c2023-11-09 20:05:26 +0000136 sh('ndnsec-key-gen {}'.format(rootName)) # Installs a self-signed cert into the system
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500137 sh('ndnsec-cert-dump -i {} > {}'.format(rootName, rootCertFile))
138
139 # Create necessary certificates for each site
140 nodeSecurityFolder = '{}/security'.format(self.homeDir)
141
142 self.node.cmd('mkdir -p {}'.format(nodeSecurityFolder))
143
144 # Create temp folders for remote nodes on this machine (localhost) to store site.key file
145 # from RemoteNodes
146 if not os.path.exists(nodeSecurityFolder) and \
147 isinstance(self.node, RemoteMixin) and self.node.isRemote:
148 os.makedirs(nodeSecurityFolder)
149
150 shutil.copyfile('{}/root.cert'.format(securityDir),
151 '{}/root.cert'.format(nodeSecurityFolder))
152
153 # Create site certificate
154 siteName = '{}{}-site'.format(self.network, self.node.name)
155 siteKeyFile = '{}/site.keys'.format(nodeSecurityFolder)
156 siteCertFile = '{}/site.cert'.format(nodeSecurityFolder)
157 Nlsr.createKey(self.node, siteName, siteKeyFile)
158
suraviregmi9665f5c2023-11-09 20:05:26 +0000159 # Copy siteKeyFile from remote for ndnsec-cert-gen
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500160 if isinstance(self.node, RemoteMixin) and self.node.isRemote:
161 login = 'mininet@{}'.format(self.node.server)
162 src = '{}:{}'.format(login, siteKeyFile)
163 dst = siteKeyFile
164 scp(src, dst)
165
166 # Root key is in root namespace, must sign site key and then install on host
suraviregmi9665f5c2023-11-09 20:05:26 +0000167 sh('ndnsec-cert-gen -s {} -r {} > {}'.format(rootName, siteKeyFile, siteCertFile))
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500168
169 # Copy root.cert and site.cert from localhost to remote host
170 if isinstance(self.node, RemoteMixin) and self.node.isRemote:
171 login = 'mininet@{}'.format(self.node.server)
172 src = '{}/site.cert'.format(nodeSecurityFolder)
173 src2 = '{}/root.cert'.format(nodeSecurityFolder)
174 dst = '{}:/tmp/'.format(login)
175 scp(src, src2, dst)
176 self.node.cmd('mv /tmp/*.cert {}'.format(nodeSecurityFolder))
177
178 self.node.cmd('ndnsec-cert-install -f {}'.format(siteCertFile))
179
180 # Create and install operator certificate
181 opName = '{}/%C1.Operator/op'.format(siteName)
182 opKeyFile = '{}/op.keys'.format(nodeSecurityFolder)
183 opCertFile = '{}/op.cert'.format(nodeSecurityFolder)
184 Nlsr.createKey(self.node, opName, opKeyFile)
185 Nlsr.createCertificate(self.node, siteName, opKeyFile, opCertFile)
186 self.node.cmd('ndnsec-cert-install -f {}'.format(opCertFile))
187
188 # Create and install router certificate
189 routerName = '{}/%C1.Router/cs/{}'.format(siteName, self.node.name)
190 routerKeyFile = '{}/router.keys'.format(nodeSecurityFolder)
191 routerCertFile = '{}/router.cert'.format(nodeSecurityFolder)
192 Nlsr.createKey(self.node, routerName, routerKeyFile)
193 Nlsr.createCertificate(self.node, opName, routerKeyFile, routerCertFile)
194 self.node.cmd('ndnsec-cert-install -f {}'.format(routerCertFile))
195
196 def createConfigFile(self):
197
198 self.__editGeneralSection()
awlaned8e6b8e2022-05-16 23:49:56 -0500199 if self.faceDict:
200 self.__editNeighborsSectionManual()
201 else:
202 self.__editNeighborsSection()
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500203 self.__editHyperbolicSection()
204 self.__editFibSection()
205 self.__editAdvertisingSection()
206 self.__editSecuritySection()
207
208 def __editGeneralSection(self):
209
210 self.node.cmd('{} -s general.network -v {}'.format(self.infocmd, self.network))
211 self.node.cmd('{} -s general.site -v /{}-site'.format(self.infocmd, self.node.name))
212 self.node.cmd('{} -s general.router -v /%C1.Router/cs/{}'.format(self.infocmd, self.node.name))
213 self.node.cmd('{} -s general.state-dir -v {}/log'.format(self.infocmd, self.homeDir))
214 self.node.cmd('{} -s general.sync-protocol -v {}'.format(self.infocmd, self.sync))
215
216 def __editNeighborsSection(self):
217
218 self.node.cmd('{} -d neighbors.neighbor'.format(self.infocmd))
219 for intf in self.node.intfList():
220 link = intf.link
221 if not link:
222 continue
223
224 node1, node2 = link.intf1.node, link.intf2.node
225
226 # Todo: add some switch support
227 if isinstance(node1, Switch) or isinstance(node2, Switch):
228 continue
229
230 if node1 == self.node:
231 other = node2
awlane21acd052024-06-13 21:12:51 -0500232 if self.faceType == Nfdc.PROTOCOL_ETHER:
233 location = MACToEther(link.intf2.MAC())
234 else:
235 location = link.intf2.IP()
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500236 else:
237 other = node1
awlane21acd052024-06-13 21:12:51 -0500238 if self.faceType == Nfdc.PROTOCOL_ETHER:
239 location = MACToEther(link.intf1.MAC())
240 else:
241 location = link.intf1.IP()
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500242
243 linkCost = intf.params.get('delay', '10ms').replace('ms', '')
244
awlane21acd052024-06-13 21:12:51 -0500245 self.neighborLocations.append(location)
246 if self.faceType == Nfdc.PROTOCOL_ETHER:
247 self.interfaceForNeighbor[location] = intf
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500248
249 self.node.cmd('{} -a neighbors.neighbor \
250 <<<\'name {}{}-site/%C1.Router/cs/{} face-uri {}://{}\n link-cost {}\''
251 .format(self.infocmd, self.network, other.name, other.name,
awlane21acd052024-06-13 21:12:51 -0500252 self.faceType, location, linkCost))
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500253
awlaned8e6b8e2022-05-16 23:49:56 -0500254 def __editNeighborsSectionManual(self):
255
256 self.node.cmd('{} -d neighbors.neighbor'.format(self.infocmd))
257 if self.node not in self.faceDict:
258 return
259 for link in self.faceDict[self.node]:
260 nodeName = link[0]
261 nodeIP = link[1]
262 linkCost = link[2]
263
264 self.node.cmd('{} -a neighbors.neighbor \
265 <<<\'name {}{}-site/%C1.Router/cs/{} face-uri {}://{}\n link-cost {}\''
266 .format(self.infocmd, self.network, nodeName, nodeName,
267 self.faceType, nodeIP, linkCost))
268
269
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500270 def __editHyperbolicSection(self):
271
272 self.node.cmd('{} -s hyperbolic.state -v {}'.format(self.infocmd, self.hyperbolicState))
273 self.node.cmd('{} -s hyperbolic.radius -v {}'.format(self.infocmd, self.hyperRadius))
274 self.node.cmd('{} -s hyperbolic.angle -v {}'.format(self.infocmd, self.hyperAngle))
275
276 def __editFibSection(self):
277
278 self.node.cmd('{} -s fib.max-faces-per-prefix -v {}'.format(self.infocmd, self.nFaces))
279
280 def __editAdvertisingSection(self):
281
282 self.node.cmd('{} -d advertising.prefix'.format(self.infocmd))
283 self.node.cmd('{} -s advertising.prefix -v {}{}-site/{}'
284 .format(self.infocmd, self.network, self.node.name, self.node.name))
285
286 def __editSecuritySection(self):
287
288 self.node.cmd('{} -d security.cert-to-publish'.format(self.infocmd))
289 if not self.security:
290 self.node.cmd('{} -s security.validator.trust-anchor.type -v any'.format(self.infocmd))
291 self.node.cmd('{} -d security.validator.trust-anchor.file-name'.format(self.infocmd))
292 self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.type -v any'.format(self.infocmd))
293 self.node.cmd('{} -d security.prefix-update-validator.trust-anchor.file-name'.format(self.infocmd))
294 else:
295 self.node.cmd('{} -s security.validator.trust-anchor.file-name -v security/root.cert'.format(self.infocmd))
296 self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.file-name -v security/site.cert'.format(self.infocmd))
297 self.node.cmd('{} -p security.cert-to-publish -v security/site.cert'.format(self.infocmd))
298 self.node.cmd('{} -p security.cert-to-publish -v security/op.cert'.format(self.infocmd))
awlaned8e6b8e2022-05-16 23:49:56 -0500299 self.node.cmd('{} -p security.cert-to-publish -v security/router.cert'.format(self.infocmd))