blob: c6a2c533a4dc616e3aeb6d85cbac36512d5ca2b1 [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,
awlaned8e6b8e2022-05-16 23:49:56 -050044 faceType='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
95 self.neighborIPs = []
96 possibleConfPaths = ['/usr/local/etc/ndn/nlsr.conf.sample', '/etc/ndn/nlsr.conf.sample']
97 copyExistentFile(node, possibleConfPaths, '{}/nlsr.conf'.format(self.homeDir))
98
99 self.createConfigFile()
100
101 if security and not Minindn.ndnSecurityDisabled:
102 self.createKeysAndCertificates()
103
104 def start(self):
105 self.createFaces()
106 Application.start(self, 'nlsr -f {}'.format(self.confFile), self.logFile, self.envDict)
107 Minindn.sleep(1)
108
109 def createFaces(self):
110 for ip in self.neighborIPs:
111 Nfdc.createFace(self.node, ip, self.faceType, isPermanent=True)
112
113 @staticmethod
114 def createKey(host, name, outputFile):
115 host.cmd('ndnsec-keygen {} > {}'.format(name, outputFile))
116
117 @staticmethod
118 def createCertificate(host, signer, keyFile, outputFile):
119 host.cmd('ndnsec-certgen -s {} -r {} > {}'.format(signer, keyFile, outputFile))
120
121 def createKeysAndCertificates(self):
Italo Valcyccd85b12020-07-24 12:35:20 -0500122 securityDir = '{}/security'.format(Minindn.workDir)
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500123
124 if not os.path.exists(securityDir):
125 os.mkdir(securityDir)
126
127 rootName = self.network
128 rootCertFile = '{}/root.cert'.format(securityDir)
129 if not os.path.isfile(rootCertFile):
130 # Create root certificate
131 sh('ndnsec-keygen {}'.format(rootName)) # Installs a self-signed cert into the system
132 sh('ndnsec-cert-dump -i {} > {}'.format(rootName, rootCertFile))
133
134 # Create necessary certificates for each site
135 nodeSecurityFolder = '{}/security'.format(self.homeDir)
136
137 self.node.cmd('mkdir -p {}'.format(nodeSecurityFolder))
138
139 # Create temp folders for remote nodes on this machine (localhost) to store site.key file
140 # from RemoteNodes
141 if not os.path.exists(nodeSecurityFolder) and \
142 isinstance(self.node, RemoteMixin) and self.node.isRemote:
143 os.makedirs(nodeSecurityFolder)
144
145 shutil.copyfile('{}/root.cert'.format(securityDir),
146 '{}/root.cert'.format(nodeSecurityFolder))
147
148 # Create site certificate
149 siteName = '{}{}-site'.format(self.network, self.node.name)
150 siteKeyFile = '{}/site.keys'.format(nodeSecurityFolder)
151 siteCertFile = '{}/site.cert'.format(nodeSecurityFolder)
152 Nlsr.createKey(self.node, siteName, siteKeyFile)
153
154 # Copy siteKeyFile from remote for ndnsec-certgen
155 if isinstance(self.node, RemoteMixin) and self.node.isRemote:
156 login = 'mininet@{}'.format(self.node.server)
157 src = '{}:{}'.format(login, siteKeyFile)
158 dst = siteKeyFile
159 scp(src, dst)
160
161 # Root key is in root namespace, must sign site key and then install on host
162 sh('ndnsec-certgen -s {} -r {} > {}'.format(rootName, siteKeyFile, siteCertFile))
163
164 # Copy root.cert and site.cert from localhost to remote host
165 if isinstance(self.node, RemoteMixin) and self.node.isRemote:
166 login = 'mininet@{}'.format(self.node.server)
167 src = '{}/site.cert'.format(nodeSecurityFolder)
168 src2 = '{}/root.cert'.format(nodeSecurityFolder)
169 dst = '{}:/tmp/'.format(login)
170 scp(src, src2, dst)
171 self.node.cmd('mv /tmp/*.cert {}'.format(nodeSecurityFolder))
172
173 self.node.cmd('ndnsec-cert-install -f {}'.format(siteCertFile))
174
175 # Create and install operator certificate
176 opName = '{}/%C1.Operator/op'.format(siteName)
177 opKeyFile = '{}/op.keys'.format(nodeSecurityFolder)
178 opCertFile = '{}/op.cert'.format(nodeSecurityFolder)
179 Nlsr.createKey(self.node, opName, opKeyFile)
180 Nlsr.createCertificate(self.node, siteName, opKeyFile, opCertFile)
181 self.node.cmd('ndnsec-cert-install -f {}'.format(opCertFile))
182
183 # Create and install router certificate
184 routerName = '{}/%C1.Router/cs/{}'.format(siteName, self.node.name)
185 routerKeyFile = '{}/router.keys'.format(nodeSecurityFolder)
186 routerCertFile = '{}/router.cert'.format(nodeSecurityFolder)
187 Nlsr.createKey(self.node, routerName, routerKeyFile)
188 Nlsr.createCertificate(self.node, opName, routerKeyFile, routerCertFile)
189 self.node.cmd('ndnsec-cert-install -f {}'.format(routerCertFile))
190
191 def createConfigFile(self):
192
193 self.__editGeneralSection()
awlaned8e6b8e2022-05-16 23:49:56 -0500194 if self.faceDict:
195 self.__editNeighborsSectionManual()
196 else:
197 self.__editNeighborsSection()
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500198 self.__editHyperbolicSection()
199 self.__editFibSection()
200 self.__editAdvertisingSection()
201 self.__editSecuritySection()
202
203 def __editGeneralSection(self):
204
205 self.node.cmd('{} -s general.network -v {}'.format(self.infocmd, self.network))
206 self.node.cmd('{} -s general.site -v /{}-site'.format(self.infocmd, self.node.name))
207 self.node.cmd('{} -s general.router -v /%C1.Router/cs/{}'.format(self.infocmd, self.node.name))
208 self.node.cmd('{} -s general.state-dir -v {}/log'.format(self.infocmd, self.homeDir))
209 self.node.cmd('{} -s general.sync-protocol -v {}'.format(self.infocmd, self.sync))
210
211 def __editNeighborsSection(self):
212
213 self.node.cmd('{} -d neighbors.neighbor'.format(self.infocmd))
214 for intf in self.node.intfList():
215 link = intf.link
216 if not link:
217 continue
218
219 node1, node2 = link.intf1.node, link.intf2.node
220
221 # Todo: add some switch support
222 if isinstance(node1, Switch) or isinstance(node2, Switch):
223 continue
224
225 if node1 == self.node:
226 other = node2
227 ip = other.IP(str(link.intf2))
228 else:
229 other = node1
230 ip = other.IP(str(link.intf1))
231
232 linkCost = intf.params.get('delay', '10ms').replace('ms', '')
233
234 self.neighborIPs.append(ip)
235
236 self.node.cmd('{} -a neighbors.neighbor \
237 <<<\'name {}{}-site/%C1.Router/cs/{} face-uri {}://{}\n link-cost {}\''
238 .format(self.infocmd, self.network, other.name, other.name,
239 self.faceType, ip, linkCost))
240
awlaned8e6b8e2022-05-16 23:49:56 -0500241 def __editNeighborsSectionManual(self):
242
243 self.node.cmd('{} -d neighbors.neighbor'.format(self.infocmd))
244 if self.node not in self.faceDict:
245 return
246 for link in self.faceDict[self.node]:
247 nodeName = link[0]
248 nodeIP = link[1]
249 linkCost = link[2]
250
251 self.node.cmd('{} -a neighbors.neighbor \
252 <<<\'name {}{}-site/%C1.Router/cs/{} face-uri {}://{}\n link-cost {}\''
253 .format(self.infocmd, self.network, nodeName, nodeName,
254 self.faceType, nodeIP, linkCost))
255
256
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500257 def __editHyperbolicSection(self):
258
259 self.node.cmd('{} -s hyperbolic.state -v {}'.format(self.infocmd, self.hyperbolicState))
260 self.node.cmd('{} -s hyperbolic.radius -v {}'.format(self.infocmd, self.hyperRadius))
261 self.node.cmd('{} -s hyperbolic.angle -v {}'.format(self.infocmd, self.hyperAngle))
262
263 def __editFibSection(self):
264
265 self.node.cmd('{} -s fib.max-faces-per-prefix -v {}'.format(self.infocmd, self.nFaces))
266
267 def __editAdvertisingSection(self):
268
269 self.node.cmd('{} -d advertising.prefix'.format(self.infocmd))
270 self.node.cmd('{} -s advertising.prefix -v {}{}-site/{}'
271 .format(self.infocmd, self.network, self.node.name, self.node.name))
272
273 def __editSecuritySection(self):
274
275 self.node.cmd('{} -d security.cert-to-publish'.format(self.infocmd))
276 if not self.security:
277 self.node.cmd('{} -s security.validator.trust-anchor.type -v any'.format(self.infocmd))
278 self.node.cmd('{} -d security.validator.trust-anchor.file-name'.format(self.infocmd))
279 self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.type -v any'.format(self.infocmd))
280 self.node.cmd('{} -d security.prefix-update-validator.trust-anchor.file-name'.format(self.infocmd))
281 else:
282 self.node.cmd('{} -s security.validator.trust-anchor.file-name -v security/root.cert'.format(self.infocmd))
283 self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.file-name -v security/site.cert'.format(self.infocmd))
284 self.node.cmd('{} -p security.cert-to-publish -v security/site.cert'.format(self.infocmd))
285 self.node.cmd('{} -p security.cert-to-publish -v security/op.cert'.format(self.infocmd))
awlaned8e6b8e2022-05-16 23:49:56 -0500286 self.node.cmd('{} -p security.cert-to-publish -v security/router.cert'.format(self.infocmd))