blob: c644f01c621da25671da1a02a27b0059bbc37f02 [file] [log] [blame]
Ashlesh Gawande6c86e302019-09-17 22:27:05 -05001# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2#
3# Copyright (C) 2015-2019, The University of Memphis,
4# 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'
42 SYNC_CHRONOSYNC = 'chronosync'
43
44 def __init__(self, node, logLevel='NONE', security=False, sync=SYNC_PSYNC,
45 faceType='udp', nFaces=3, routingType=ROUTING_LINK_STATE):
46 Application.__init__(self, node)
47
48 self.network = '/ndn/'
49 self.node = node
50 self.parameters = self.node.params['params']
51
52 if self.parameters.get('nlsr-log-level', None) != None:
53 logLevel = self.parameters.get('nlsr-log-level')
54
55 if logLevel in ['NONE', 'WARN', 'INFO', 'DEBUG', 'TRACE']:
56 self.envDict = {'NDN_LOG': 'nlsr.*={}'.format(logLevel)}
57 else:
58 self.envDict = {'NDN_LOG': logLevel}
59
60 self.logFile = 'nlsr.log'
61 self.routerName = '/{}C1.Router/cs/{}'.format('%', node.name)
62 self.confFile = '{}/nlsr.conf'.format(self.homeDir)
63 self.security = security
64 self.sync = sync
65 self.faceType = faceType
66 self.infocmd = 'infoedit -f nlsr.conf'
67
68 self.parameters = self.node.params['params']
69
70 self.nFaces = nFaces
71 if routingType == Nlsr.ROUTING_HYPERBOLIC:
72 self.hyperbolicState = 'on'
73 elif routingType == Nlsr.ROUTING_DRY_RUN:
74 self.hyperbolicState = 'dry-run'
75 else:
76 self.hyperbolicState = 'off'
77 self.hyperRadius = self.parameters.get('radius', 0.0)
78 self.hyperAngle = self.parameters.get('angle', 0.0)
79
80 if ((self.hyperbolicState == 'on' or self.hyperbolicState == 'dry-run') and
81 (self.hyperRadius == 0.0 or self.hyperAngle == 0.0)):
82 warn('Hyperbolic coordinates in topology file are either missing or misconfigured.')
83 warn('Check that each node has one radius value and one or two angle value(s).')
84 sys.exit(1)
85
86 self.neighborIPs = []
87 possibleConfPaths = ['/usr/local/etc/ndn/nlsr.conf.sample', '/etc/ndn/nlsr.conf.sample']
88 copyExistentFile(node, possibleConfPaths, '{}/nlsr.conf'.format(self.homeDir))
89
90 self.createConfigFile()
91
92 if security and not Minindn.ndnSecurityDisabled:
93 self.createKeysAndCertificates()
94
95 def start(self):
96 self.createFaces()
97 Application.start(self, 'nlsr -f {}'.format(self.confFile), self.logFile, self.envDict)
98 Minindn.sleep(1)
99
100 def createFaces(self):
101 for ip in self.neighborIPs:
102 Nfdc.createFace(self.node, ip, self.faceType, isPermanent=True)
103
104 @staticmethod
105 def createKey(host, name, outputFile):
106 host.cmd('ndnsec-keygen {} > {}'.format(name, outputFile))
107
108 @staticmethod
109 def createCertificate(host, signer, keyFile, outputFile):
110 host.cmd('ndnsec-certgen -s {} -r {} > {}'.format(signer, keyFile, outputFile))
111
112 def createKeysAndCertificates(self):
Italo Valcyccd85b12020-07-24 12:35:20 -0500113 securityDir = '{}/security'.format(Minindn.workDir)
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500114
115 if not os.path.exists(securityDir):
116 os.mkdir(securityDir)
117
118 rootName = self.network
119 rootCertFile = '{}/root.cert'.format(securityDir)
120 if not os.path.isfile(rootCertFile):
121 # Create root certificate
122 sh('ndnsec-keygen {}'.format(rootName)) # Installs a self-signed cert into the system
123 sh('ndnsec-cert-dump -i {} > {}'.format(rootName, rootCertFile))
124
125 # Create necessary certificates for each site
126 nodeSecurityFolder = '{}/security'.format(self.homeDir)
127
128 self.node.cmd('mkdir -p {}'.format(nodeSecurityFolder))
129
130 # Create temp folders for remote nodes on this machine (localhost) to store site.key file
131 # from RemoteNodes
132 if not os.path.exists(nodeSecurityFolder) and \
133 isinstance(self.node, RemoteMixin) and self.node.isRemote:
134 os.makedirs(nodeSecurityFolder)
135
136 shutil.copyfile('{}/root.cert'.format(securityDir),
137 '{}/root.cert'.format(nodeSecurityFolder))
138
139 # Create site certificate
140 siteName = '{}{}-site'.format(self.network, self.node.name)
141 siteKeyFile = '{}/site.keys'.format(nodeSecurityFolder)
142 siteCertFile = '{}/site.cert'.format(nodeSecurityFolder)
143 Nlsr.createKey(self.node, siteName, siteKeyFile)
144
145 # Copy siteKeyFile from remote for ndnsec-certgen
146 if isinstance(self.node, RemoteMixin) and self.node.isRemote:
147 login = 'mininet@{}'.format(self.node.server)
148 src = '{}:{}'.format(login, siteKeyFile)
149 dst = siteKeyFile
150 scp(src, dst)
151
152 # Root key is in root namespace, must sign site key and then install on host
153 sh('ndnsec-certgen -s {} -r {} > {}'.format(rootName, siteKeyFile, siteCertFile))
154
155 # Copy root.cert and site.cert from localhost to remote host
156 if isinstance(self.node, RemoteMixin) and self.node.isRemote:
157 login = 'mininet@{}'.format(self.node.server)
158 src = '{}/site.cert'.format(nodeSecurityFolder)
159 src2 = '{}/root.cert'.format(nodeSecurityFolder)
160 dst = '{}:/tmp/'.format(login)
161 scp(src, src2, dst)
162 self.node.cmd('mv /tmp/*.cert {}'.format(nodeSecurityFolder))
163
164 self.node.cmd('ndnsec-cert-install -f {}'.format(siteCertFile))
165
166 # Create and install operator certificate
167 opName = '{}/%C1.Operator/op'.format(siteName)
168 opKeyFile = '{}/op.keys'.format(nodeSecurityFolder)
169 opCertFile = '{}/op.cert'.format(nodeSecurityFolder)
170 Nlsr.createKey(self.node, opName, opKeyFile)
171 Nlsr.createCertificate(self.node, siteName, opKeyFile, opCertFile)
172 self.node.cmd('ndnsec-cert-install -f {}'.format(opCertFile))
173
174 # Create and install router certificate
175 routerName = '{}/%C1.Router/cs/{}'.format(siteName, self.node.name)
176 routerKeyFile = '{}/router.keys'.format(nodeSecurityFolder)
177 routerCertFile = '{}/router.cert'.format(nodeSecurityFolder)
178 Nlsr.createKey(self.node, routerName, routerKeyFile)
179 Nlsr.createCertificate(self.node, opName, routerKeyFile, routerCertFile)
180 self.node.cmd('ndnsec-cert-install -f {}'.format(routerCertFile))
181
182 def createConfigFile(self):
183
184 self.__editGeneralSection()
185 self.__editNeighborsSection()
186 self.__editHyperbolicSection()
187 self.__editFibSection()
188 self.__editAdvertisingSection()
189 self.__editSecuritySection()
190
191 def __editGeneralSection(self):
192
193 self.node.cmd('{} -s general.network -v {}'.format(self.infocmd, self.network))
194 self.node.cmd('{} -s general.site -v /{}-site'.format(self.infocmd, self.node.name))
195 self.node.cmd('{} -s general.router -v /%C1.Router/cs/{}'.format(self.infocmd, self.node.name))
196 self.node.cmd('{} -s general.state-dir -v {}/log'.format(self.infocmd, self.homeDir))
197 self.node.cmd('{} -s general.sync-protocol -v {}'.format(self.infocmd, self.sync))
198
199 def __editNeighborsSection(self):
200
201 self.node.cmd('{} -d neighbors.neighbor'.format(self.infocmd))
202 for intf in self.node.intfList():
203 link = intf.link
204 if not link:
205 continue
206
207 node1, node2 = link.intf1.node, link.intf2.node
208
209 # Todo: add some switch support
210 if isinstance(node1, Switch) or isinstance(node2, Switch):
211 continue
212
213 if node1 == self.node:
214 other = node2
215 ip = other.IP(str(link.intf2))
216 else:
217 other = node1
218 ip = other.IP(str(link.intf1))
219
220 linkCost = intf.params.get('delay', '10ms').replace('ms', '')
221
222 self.neighborIPs.append(ip)
223
224 self.node.cmd('{} -a neighbors.neighbor \
225 <<<\'name {}{}-site/%C1.Router/cs/{} face-uri {}://{}\n link-cost {}\''
226 .format(self.infocmd, self.network, other.name, other.name,
227 self.faceType, ip, linkCost))
228
229 def __editHyperbolicSection(self):
230
231 self.node.cmd('{} -s hyperbolic.state -v {}'.format(self.infocmd, self.hyperbolicState))
232 self.node.cmd('{} -s hyperbolic.radius -v {}'.format(self.infocmd, self.hyperRadius))
233 self.node.cmd('{} -s hyperbolic.angle -v {}'.format(self.infocmd, self.hyperAngle))
234
235 def __editFibSection(self):
236
237 self.node.cmd('{} -s fib.max-faces-per-prefix -v {}'.format(self.infocmd, self.nFaces))
238
239 def __editAdvertisingSection(self):
240
241 self.node.cmd('{} -d advertising.prefix'.format(self.infocmd))
242 self.node.cmd('{} -s advertising.prefix -v {}{}-site/{}'
243 .format(self.infocmd, self.network, self.node.name, self.node.name))
244
245 def __editSecuritySection(self):
246
247 self.node.cmd('{} -d security.cert-to-publish'.format(self.infocmd))
248 if not self.security:
249 self.node.cmd('{} -s security.validator.trust-anchor.type -v any'.format(self.infocmd))
250 self.node.cmd('{} -d security.validator.trust-anchor.file-name'.format(self.infocmd))
251 self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.type -v any'.format(self.infocmd))
252 self.node.cmd('{} -d security.prefix-update-validator.trust-anchor.file-name'.format(self.infocmd))
253 else:
254 self.node.cmd('{} -s security.validator.trust-anchor.file-name -v security/root.cert'.format(self.infocmd))
255 self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.file-name -v security/site.cert'.format(self.infocmd))
256 self.node.cmd('{} -p security.cert-to-publish -v security/site.cert'.format(self.infocmd))
257 self.node.cmd('{} -p security.cert-to-publish -v security/op.cert'.format(self.infocmd))
258 self.node.cmd('{} -p security.cert-to-publish -v security/router.cert'.format(self.infocmd))