blob: 9aa38f4eb485e97d76ca2d1fb6be3145b3b2a3f3 [file] [log] [blame]
Alexander Lane6f7a64f2018-05-17 15:01:14 -05001# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2#
Saurab Dulal576a4192020-08-25 00:55:22 -05003# Copyright (C) 2015-2020, The University of Memphis,
Alexander Lane6f7a64f2018-05-17 15:01:14 -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
tylerliu86647792023-03-03 15:18:48 -080024from mininet.log import debug, warn
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050025from minindn.minindn import Minindn
awlane26724712024-07-05 16:18:27 -050026from minindn.util import MACToEther, getPopen
Saurab Dulal8ae870a2018-07-31 05:17:49 +000027
awlane26724712024-07-05 16:18:27 -050028from subprocess import PIPE
29
30# If needed (e.g. to speed up the process), use a smaller (or larger value)
Varun Patil63a330d2022-05-18 14:23:13 -070031# based on your machines resource (CPU, memory)
tylerliu86647792023-03-03 15:18:48 -080032SLEEP_TIME = 0.0015
Alexander Lane6f7a64f2018-05-17 15:01:14 -050033
awlane26724712024-07-05 16:18:27 -050034class _NfdcBase(object):
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050035 STRATEGY_ASF = 'asf'
36 STRATEGY_BEST_ROUTE = 'best-route'
37 STRATEGY_MULTICAST = 'multicast'
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050038 PROTOCOL_UDP = 'udp'
39 PROTOCOL_TCP = 'tcp'
40 PROTOCOL_ETHER = 'ether'
Alexander Lane6f7a64f2018-05-17 15:01:14 -050041
awlane26724712024-07-05 16:18:27 -050042def _registerRoute(namePrefix, remoteNode, protocol=_NfdcBase.PROTOCOL_UDP, origin=255,
43 cost=0, inheritFlag=True, captureFlag=False, expirationInMillis=None):
44 cmd = ""
45 if remoteNode.isdigit() and not protocol == "fd":
46 cmd = f'route add {namePrefix} {remoteNode} origin {origin} cost {cost}'
47 else:
48 if protocol == "ether":
49 remoteNode = MACToEther(remoteNode)
50 cmd = f'route add {namePrefix} {protocol}://{remoteNode} origin {origin} cost {cost}'
51 if not inheritFlag:
52 cmd += " no-inherit"
53 if captureFlag:
54 cmd += " capture"
55 if expirationInMillis:
56 cmd += f" expires {expirationInMillis}"
57 return cmd
58
59def _unregisterRoute(namePrefix, remoteNode, protocol=_NfdcBase.PROTOCOL_UDP, origin=255):
60 cmd = ""
61 if remoteNode.isdigit() and not protocol == "fd":
62 cmd = f'route remove {namePrefix} {remoteNode} origin {origin}'
63 else:
64 if protocol == "ether":
65 remoteNode = MACToEther(remoteNode)
66 cmd = f'route remove {namePrefix} {protocol}://{remoteNode} origin {origin}'
67 return cmd
68
69def _createFace(remoteNodeAddress, protocol=_NfdcBase.PROTOCOL_UDP, isPermanent=False, localInterface=''):
70 '''Create face in node's NFD instance. Returns FaceID of created face or -1 if failed.'''
71 if protocol == "ether" and not localInterface:
72 warn("Cannot create ethernet face without local interface!")
73 return
74 elif protocol != "ether" and localInterface:
75 warn("Cannot create non-ethernet face with local interface specified!")
76 return
77 elif protocol == "ether" and localInterface:
78 remoteNodeAddress = MACToEther(remoteNodeAddress)
79 cmd = (f'face create {protocol}://{remoteNodeAddress} '
80 f'{f"local dev://{localInterface} " if localInterface else ""}'
81 f'{"persistency permanent" if isPermanent else "persistency persistent"}')
82 return cmd
83
84def _destroyFace(remoteNode, protocol=_NfdcBase.PROTOCOL_UDP):
85 cmd = ""
86 if remoteNode.isdigit() and not protocol == "fd":
87 cmd = f'face destroy {remoteNode}'
88 else:
89 if protocol == "ether":
90 remoteNode = MACToEther(remoteNode)
91 cmd = f'face destroy {protocol}://{remoteNode}'
92 return cmd
93
94def _setStrategy(namePrefix, strategy):
95 cmd = f'strategy set {namePrefix} ndn:/localhost/nfd/strategy/{strategy}'
96 return cmd
97
98def _unsetStrategy(namePrefix):
99 cmd = f'strategy unset {namePrefix}'
100 return cmd
101
102class Nfdc(_NfdcBase):
Alexander Lane6f7a64f2018-05-17 15:01:14 -0500103 @staticmethod
awlane26724712024-07-05 16:18:27 -0500104 def registerRoute(node, namePrefix, remoteNode, protocol=_NfdcBase.PROTOCOL_UDP, origin=255,
Ashlesh Gawande6651a742019-01-03 18:13:06 -0600105 cost=0, inheritFlag=True, captureFlag=False, expirationInMillis=None):
awlane26724712024-07-05 16:18:27 -0500106 cmd = "nfdc " + _registerRoute(namePrefix, remoteNode, protocol, origin, cost, inheritFlag, captureFlag, expirationInMillis)
dulalsaurab2b899532018-10-25 18:02:15 +0000107 debug(node.cmd(cmd))
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500108 Minindn.sleep(SLEEP_TIME)
Alexander Lane6f7a64f2018-05-17 15:01:14 -0500109
110 @staticmethod
awlane26724712024-07-05 16:18:27 -0500111 def unregisterRoute(node, namePrefix, remoteNode, protocol=_NfdcBase.PROTOCOL_UDP, origin=255):
112 cmd = "nfdc " + _unregisterRoute(namePrefix, remoteNode, protocol, origin)
dulalsaurab0dcdb322018-08-15 20:39:07 +0000113 debug(node.cmd(cmd))
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500114 Minindn.sleep(SLEEP_TIME)
Alexander Lane6f7a64f2018-05-17 15:01:14 -0500115
116 @staticmethod
awlane26724712024-07-05 16:18:27 -0500117 def createFace(node, remoteNodeAddress, protocol=_NfdcBase.PROTOCOL_UDP, isPermanent=False, localInterface='', allowExisting=True):
Alex Lane1d3c0a82021-07-22 17:28:16 -0500118 '''Create face in node's NFD instance. Returns FaceID of created face or -1 if failed.'''
awlane26724712024-07-05 16:18:27 -0500119 cmd = "nfdc " + _createFace(remoteNodeAddress, protocol, isPermanent, localInterface)
Alex Lane1d3c0a82021-07-22 17:28:16 -0500120 output = node.cmd(cmd)
121 debug(output)
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500122 Minindn.sleep(SLEEP_TIME)
awlanea43c2412024-04-02 14:14:45 -0500123 if "face-created" in output or (allowExisting and ("face-exists" in output or "face-updated" in output)):
Varun Patilc69041f2022-05-18 14:17:54 -0700124 faceID = output.split(" ")[1][3:]
awlanea43c2412024-04-02 14:14:45 -0500125 if "face-exists" in output or "face-updated" in output:
awlane26724712024-07-05 16:18:27 -0500126 debug(f'[{node.name}] Existing face found: {faceID}\n')
Varun Patilc69041f2022-05-18 14:17:54 -0700127 return faceID
awlane26724712024-07-05 16:18:27 -0500128 warn(f'[{node.name}] Face register failed: {output}\n')
Varun Patilc69041f2022-05-18 14:17:54 -0700129 return -1
Alexander Lane6f7a64f2018-05-17 15:01:14 -0500130
131 @staticmethod
awlane26724712024-07-05 16:18:27 -0500132 def destroyFace(node, remoteNode, protocol=_NfdcBase.PROTOCOL_UDP):
133 cmd = "nfdc " + _destroyFace(remoteNode, protocol)
134 debug(node.cmd(cmd))
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500135 Minindn.sleep(SLEEP_TIME)
Alexander Lane6f7a64f2018-05-17 15:01:14 -0500136
137 @staticmethod
138 def setStrategy(node, namePrefix, strategy):
awlane26724712024-07-05 16:18:27 -0500139 cmd = "nfdc " + _setStrategy(namePrefix, strategy)
tylerliu86647792023-03-03 15:18:48 -0800140 out = node.cmd(cmd)
141 if out.find('error') != -1:
awlane26724712024-07-05 16:18:27 -0500142 warn(f'[{node.name}] Error on strategy set out: {out}')
143 debug(out)
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500144 Minindn.sleep(SLEEP_TIME)
Alexander Lane6f7a64f2018-05-17 15:01:14 -0500145
146 @staticmethod
147 def unsetStrategy(node, namePrefix):
awlane26724712024-07-05 16:18:27 -0500148 cmd = "nfdc " + _unsetStrategy(namePrefix)
149 debug(node.cmd(cmd))
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500150 Minindn.sleep(SLEEP_TIME)
Alex Lane1d3c0a82021-07-22 17:28:16 -0500151
152 @staticmethod
awlane26724712024-07-05 16:18:27 -0500153 def getFaceId(node, remoteNodeAddress, localEndpoint=None, protocol=_NfdcBase.PROTOCOL_UDP, portNum="6363"):
Alex Lane1d3c0a82021-07-22 17:28:16 -0500154 '''Returns the faceId for a remote node based on FaceURI, or -1 if a face is not found'''
awlane26724712024-07-05 16:18:27 -0500155 # Because this is an interactive helper method, we don't split this into _NfdcBase.
Alex Lane1d3c0a82021-07-22 17:28:16 -0500156 local = ""
157 if localEndpoint:
awlane26724712024-07-05 16:18:27 -0500158 local = f' local {localEndpoint}'
awlane21acd052024-06-13 21:12:51 -0500159 if protocol == "ether":
160 remoteNodeAddress = MACToEther(remoteNodeAddress)
awlane26724712024-07-05 16:18:27 -0500161 output = node.cmd(f'nfdc face list remote {protocol}://{remoteNodeAddress}{local}')
awlane21acd052024-06-13 21:12:51 -0500162 else:
awlane26724712024-07-05 16:18:27 -0500163 output = node.cmd(f'nfdc face list remote {protocol}://{remoteNodeAddress}:{portNum}{local}')
Alex Lane1d3c0a82021-07-22 17:28:16 -0500164 debug(output)
165 Minindn.sleep(SLEEP_TIME)
166 # This is fragile but we don't have that many better options
167 if "faceid=" not in output:
168 return -1
169 faceId = output.split(" ")[0][7:]
tylerliu86647792023-03-03 15:18:48 -0800170 return faceId
awlane26724712024-07-05 16:18:27 -0500171
172class NfdcBatch(_NfdcBase):
173 '''Helper for writing and passing an Nfdc batch file to Nfd'''
174 def __init__(self):
175 self.batch_commands = []
176
177 def executeBatch(self, node, batch_file_name = None):
178 '''Execute batch file on node given as argument.
179 Optional: batch_file_name is the name of the file that will be created in the node's home dir.'''
180 # The intended use of this method is to either use it for a universal configuration or to use an
181 # individual object for each node.
182 if batch_file_name == None:
183 batch_file_name = "nfdc_helper.batch"
184 batch_str = "\n".join(self.batch_commands)
185 file_path = f'{node.params["params"]["homeDir"]}/{batch_file_name}'
186 with open(file_path, "w") as f:
187 f.write(batch_str)
188 process = getPopen(node, f'nfdc --batch {file_path}')
189 # End user can poll if process has finished if desirable; this is also why we do not clean up the
190 # temporary files.
191 return process
192
193 def registerRoute(self, namePrefix, remoteNode, protocol=_NfdcBase.PROTOCOL_UDP, origin=255,
194 cost=0, inheritFlag=True, captureFlag=False, expirationInMillis=None):
195 self.batch_commands.append(_registerRoute(namePrefix, remoteNode, protocol, origin, cost, inheritFlag, captureFlag, expirationInMillis))
196
197 def unregisterRoute(self, namePrefix, remoteNode, protocol=_NfdcBase.PROTOCOL_UDP, origin=255):
198 self.batch_commands.append(_unregisterRoute(namePrefix, remoteNode, protocol, origin))
199
200 def createFace(self, remoteNodeAddress, protocol=_NfdcBase.PROTOCOL_UDP, isPermanent=False, localInterface=''):
201 self.batch_commands.append(_createFace(remoteNodeAddress, protocol, isPermanent, localInterface))
202
203 def destroyFace(self, remoteNode, protocol=_NfdcBase.PROTOCOL_UDP):
204 self.batch_commands.append(_destroyFace(remoteNode, protocol))
205
206 def setStrategy(self, namePrefix, strategy):
207 self.batch_commands.append(_setStrategy(namePrefix, strategy))
208
209 def unsetStrategy(self, namePrefix):
210 self.batch_commands.append(_unsetStrategy(namePrefix))