blob: 8f80e2a02cae759a6d14ed34a67c6b8e1541d7df [file] [log] [blame]
Ashlesh Gawande6c86e302019-09-17 22:27:05 -05001# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2#
Davide Pesavento82cc17a2025-02-17 18:30:05 -05003# Copyright (C) 2015-2025, 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
awlane1cec2332025-04-24 17:24:47 -050024import re
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050025import sys
26from os.path import isfile
awlane1cec2332025-04-24 17:24:47 -050027from subprocess import call, PIPE
28
dulalsaurab0ed77722020-09-24 22:32:58 +000029from six.moves.urllib.parse import quote
30
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050031from mininet.cli import CLI
awlane21acd052024-06-13 21:12:51 -050032from mininet.log import error
awlane1cec2332025-04-24 17:24:47 -050033from mininet.node import Host
34from mininet.net import Mininet
awlane21acd052024-06-13 21:12:51 -050035
awlane21acd052024-06-13 21:12:51 -050036
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050037sshbase = ['ssh', '-q', '-t', '-i/home/mininet/.ssh/id_rsa']
38scpbase = ['scp', '-i', '/home/mininet/.ssh/id_rsa']
39devnull = open('/dev/null', 'w')
40
dulalsaurab0ed77722020-09-24 22:32:58 +000041def getSafeName(namePrefix):
42 """
43 Check if the prefix/string is safe to use with ndn commands or not.
44 return safe prefix.
45 :param namePrefix: name of the prefix
46 """
47 # remove redundant "/"es, multiple "/"es are an invalid representation for empty name component
Davide Pesavento82cc17a2025-02-17 18:30:05 -050048 namePrefix = "/" + "/".join(filter(None, namePrefix.split("/")))
dulalsaurab0ed77722020-09-24 22:32:58 +000049 return quote(namePrefix, safe='/')
50
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050051def ssh(login, cmd):
52 rcmd = sshbase + [login, cmd]
53 call(rcmd, stdout=devnull, stderr=devnull)
54
55def scp(*args):
56 tmp = []
57 for arg in args:
58 tmp.append(arg)
59 rcmd = scpbase + tmp
60 call(rcmd, stdout=devnull, stderr=devnull)
61
awlane1cec2332025-04-24 17:24:47 -050062def copyExistentFile(host, fileList, destination):
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050063 for f in fileList:
64 if isfile(f):
awlane1cec2332025-04-24 17:24:47 -050065 host.cmd('cp {} {}'.format(f, destination))
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050066 break
67 if not isfile(destination):
68 fileName = destination.split('/')[-1]
69 raise IOError('{} not found in expected directory.'.format(fileName))
70
awlane1cec2332025-04-24 17:24:47 -050071def popenGetEnv(host, envDict=None):
72 '''Helper method to set environment variables for Popen on nodes'''
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050073 env = {}
awlane1cec2332025-04-24 17:24:47 -050074 homeDir = host.params['params']['homeDir']
75 printenv = host.popen('printenv'.split(), cwd=homeDir).communicate()[0].decode('utf-8')
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050076 for var in printenv.split('\n'):
77 if var == '':
78 break
79 p = var.split('=')
80 env[p[0]] = p[1]
81 env['HOME'] = homeDir
82
83 if envDict is not None:
84 for key, value in envDict.items():
85 env[key] = str(value)
86
87 return env
88
89def getPopen(host, cmd, envDict=None, **params):
awlane1cec2332025-04-24 17:24:47 -050090 '''Return Popen object for process on node with correctly set environmental variables'''
Ashlesh Gawande6c86e302019-09-17 22:27:05 -050091 return host.popen(cmd, cwd=host.params['params']['homeDir'],
92 env=popenGetEnv(host, envDict), **params)
93
awlane21acd052024-06-13 21:12:51 -050094def MACToEther(mac):
95 # We use the regex filters from face-uri.cpp in ndn-cxx with minor modifications
96 if re.match('^\[((?:[a-fA-F0-9]{1,2}\:){5}(?:[a-fA-F0-9]{1,2}))\]$', mac):
97 return mac
98 elif re.match('^((?:[a-fA-F0-9]{1,2}\:){5}(?:[a-fA-F0-9]{1,2}))$', mac):
99 # URI syntax requires nfdc to use brackets for MAC and ethernet addresses due
100 # to the use of colons as separators. Incomplete brackets are a code issue.
101 return '[%s]' % mac
102 error('Potentially malformed MAC address, passing without alteration: %s' % mac)
103 return mac
104
Ashlesh Gawande6c86e302019-09-17 22:27:05 -0500105class MiniNDNCLI(CLI):
106 prompt = 'mini-ndn> '
107 def __init__(self, mininet, stdin=sys.stdin, script=None):
108 CLI.__init__(self, mininet, stdin, script)
Alexander Laneea2d5d62019-10-04 16:48:52 -0500109
Junxiao Shi48ada892021-11-04 09:02:21 -0600110try:
111 from mn_wifi.cli import CLI as CLI_wifi
awlane1cec2332025-04-24 17:24:47 -0500112 from mn_wifi.node import Station as mn_wifi_station
113 HAS_WIFI = True
Junxiao Shi48ada892021-11-04 09:02:21 -0600114 class MiniNDNWifiCLI(CLI_wifi):
115 prompt = 'mini-ndn-wifi> '
116 def __init__(self, mininet, stdin=sys.stdin, script=None):
117 CLI_wifi.__init__(self, mininet, stdin, script)
118
119except ImportError:
awlane1cec2332025-04-24 17:24:47 -0500120 HAS_WIFI = False
Junxiao Shi48ada892021-11-04 09:02:21 -0600121 class MiniNDNWifiCLI:
122 def __init__(self):
123 raise ImportError('Mininet-WiFi is not installed')
awlane1cec2332025-04-24 17:24:47 -0500124
125def is_valid_hostid(net: Mininet, host_id: str):
126 """Check if a hostId is a host"""
127 if host_id not in net:
128 return False
129
130 if not isinstance(net[host_id], Host) and \
131 (HAS_WIFI and not isinstance(net[host_id], mn_wifi_station)):
132 return False
133
134 return True
135
136def run_popen(host, cmd):
137 """Helper to run command on node asynchronously and get output (blocking)"""
138 process = getPopen(host, cmd, stdout=PIPE)
139 return process.communicate()[0]
140
141def run_popen_readline(host, cmd):
142 """Helper to run command on node asynchronously and get output line by line (blocking)"""
143 process = getPopen(host, cmd, stdout=PIPE)
144 while True:
145 line: bytes = process.stdout.readline()
146 if not line:
147 break
148 yield line
149
150def host_home(host) -> str | None:
151 """Get home directory for host"""
152 if 'params' not in host.params or 'homeDir' not in host.params['params']:
153 return None
154 return host.params['params']['homeDir']