blob: 6ff939038e708d126bfea9f2d17d20ba65145997 [file] [log] [blame]
Jon Halla4a79312022-01-25 17:16:53 -08001"""
2Copyright 2022 Open Networking Foundation (ONF)
3
4Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
5the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
6or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
7
8"""
9
10import pexpect
11import os
12from drivers.common.clidriver import CLI
13
14
15class MockSMFDriver( CLI ):
16 """
17 Runs commands using the mock smf program to send messages to a UPF.
18
19 """
20
21 def __init__( self ):
22 """
23 Initialize client
24 """
25 super( MockSMFDriver, self ).__init__()
26 self.name = None
27 self.handle = None
28 self.prompt = "\$"
29 self.mock_smf_path = None
30
31 def connect( self, **connectargs ):
32 """
33 Creates the ssh handle for the mock smf
34 """
35 try:
36 for key in connectargs:
37 vars( self )[ key ] = connectargs[ key ]
38 self.name = self.options.get( "name", "" )
39 self.mock_smf_path = self.options.get( "mock_smf_path", None )
40 try:
41 if os.getenv( str( self.ip_address ) ) is not None:
42 self.ip_address = os.getenv( str( self.ip_address ) )
43 else:
44 main.log.info( self.name + ": ip set to " + self.ip_address )
45 except KeyError:
46 main.log.info( self.name + ": Invalid host name," +
47 "defaulting to 'localhost' instead" )
48 self.ip_address = 'localhost'
49 except Exception as e:
50 main.log.error( "Uncaught exception: " + str( e ) )
51
52 self.handle = super( MockSMFDriver, self ).connect(
53 user_name=self.user_name,
54 ip_address=self.ip_address,
55 port=None,
56 pwd=self.pwd )
57 if self.handle:
58 main.log.info( "Connection successful to the host " +
59 self.user_name +
60 "@" +
61 self.ip_address )
62 self.handle.sendline( "" )
63 self.handle.expect( self.prompt )
64 return main.TRUE
65 else:
66 main.log.error( "Connection failed to " +
67 self.user_name +
68 "@" +
69 self.ip_address )
70 return main.FALSE
71 except pexpect.EOF:
72 main.log.error( self.name + ": EOF exception found" )
73 main.log.error( self.name + ": " + self.handle.before )
74 main.cleanAndExit()
75 except Exception:
76 main.log.exception( self.name + ": Uncaught exception!" )
77 main.cleanAndExit()
78
79 def startSMF( self, pcap_file="mock_smf.pcap", timeout=10 ):
80 """
81 Start Mock SMF and connect to the given UPF address.
82 """
83 #TODO: add interface option?
84 try:
85 main.log.debug( self.name + ": Starting Mock SMF CLI" )
86 # TODO: Add pcap logging folder and other options
87 cmd = "pfcpsim &"
88 #if pcap_file:
89 # TODO: Start pcap separately for go based mock smf
90 if self.mock_smf_path:
91 self.handle.sendline( "cd " + self.mock_smf_path )
92 self.handle.expect( self.prompt )
93 main.log.debug( self.handle.before )
94 self.handle.sendline( cmd )
95 i = self.handle.expect( [ "command not found",
96 "unknown",
97 "password for",
98 self.prompt,
99 pexpect.TIMEOUT ], timeout )
100 #TODO refactor this
101 if i == 2:
102 main.log.debug( "%s: Sudo asking for password" % self.name )
103 self.handle.sendline( self.pwd if self.pwd else "jenkins" )
104 j = self.handle.expect( [ "not found", self.prompt ] )
105 if j == 0:
106 main.log.error( "%s: Error starting mock smf" % self.name )
107 main.log.debug( self.handle.before + str( self.handle.after ) )
108 main.cleanAndExit()
109 elif i == 3:
110 # Exit backgrounded pcfpsim, even if test aborts early
111 self.preDisconnect = self.stop
112 else:
113 main.log.error( "%s: Error starting mock smf" % self.name )
114 main.log.debug( self.handle.before + str( self.handle.after ) )
115 main.cleanAndExit()
116 return main.TRUE
117 except pexpect.EOF:
118 main.log.error( self.name + ": EOF exception found" )
119 main.log.error( self.name + ": " + self.handle.before )
120 main.cleanAndExit()
121 except Exception:
122 main.log.exception( self.name + ": Uncaught exception!" )
123 main.cleanAndExit()
124
125 def sendline( self, cmd, timeout=10 ):
126 """
127 Handles the cli output from the mock smf. Returns main.TRUE if no error, else main.FALSE
128 """
129 try:
130 main.log.debug( "%s: Sending %s" % ( self.name, cmd ) )
131 self.handle.sendline( "pfcpctl %s" % cmd )
132 i = self.handle.expect( [ "command not found",
133 "unknown",
134 "ERRO",
135 "FATA",
136 self.prompt,
137 pexpect.TIMEOUT ], timeout )
138 if i == 4:
139 return main.TRUE
140 else:
141 main.log.error( "%s: Error with mock smf cmd: %s" % ( self.name, cmd ) )
142 output = self.handle.before + str( self.handle.after )
143 if i < 3:
144 # If not timeout, make sure we get rest of prompt from buffer
145 self.handle.expect( [ self.prompt, pexpect.TIMEOUT ], timeout )
146 output += self.handle.before
147 main.log.debug( "%s:%s" % ( self.name, output ) )
148 return main.FALSE
149 except pexpect.EOF:
150 main.log.error( self.name + ": EOF exception found" )
151 main.log.error( self.name + ": " + self.handle.before )
152 main.cleanAndExit()
153 except Exception:
154 main.log.exception( self.name + ": Uncaught exception!" )
155 main.cleanAndExit()
156
157 def configure( self, n3_addr, upf_addr, upf_port=None ):
158 """
159 Configure pfcpsim to connect to upf
160 """
161 try:
162 cmd = "service configure --n3-addr %s --remote-peer-addr %s%s" % (n3_addr,
163 upf_addr,
164 "" if not upf_port else ":%s" % upf_port)
165 return self.sendline( cmd )
166 except Exception:
167 main.log.exception( self.name + ": Uncaught exception!" )
168 main.cleanAndExit()
169
170 def associate( self ):
171 """
172 Setup PFCP Association
173 """
174 try:
175 cmd = "service associate"
176 return self.sendline( cmd )
177 except Exception:
178 main.log.exception( self.name + ": Uncaught exception!" )
179 main.cleanAndExit()
180
181 def disassociate( self ):
182 """
183 Teardown PFCP Association
184 """
185 try:
186 cmd = "service disassociate"
187 return self.sendline( cmd )
188 except Exception:
189 main.log.exception( self.name + ": Uncaught exception!" )
190 main.cleanAndExit()
191
192 def create( self, ue_pool, gnb_addr, session_count=1,
193 base_id=1, sdf=[] ):
194 """
195 Create PFCP Session(s)
196
197 Arguements:
198 - ue_pool: The IPv4 prefix from which UE addresses will be drawn
199 - gnb_addr: The IPv4 address of the eNodeB
200 Optional Arguments:
201 - session_count: The number of sessions for which UE flows should be
202 created. Defaults to 1
203 - base_id: The first id to use for the IDs. Further IDs will be
204 generated by incrementing. Defaults to 1
205 - sdf: The sdf filter string to pass to pfcpctl
206 """
207 try:
208 cmd = "session create --count %s --ue-pool %s --gnb-addr %s --baseID %s %s" % (
209 session_count, ue_pool, gnb_addr, base_id,
210 " ".join( sdf ) )
211 return self.sendline( cmd )
212 except Exception:
213 main.log.exception( self.name + ": Uncaught exception!" )
214 main.cleanAndExit()
215
216 def modify( self, ue_pool, gnb_addr, session_count=1,
217 base_id=1, buffering=False, notifycp=False ):
218 """
219 Modify PFCP Sessions(s)
220
221 Arguements:
222 - ue_pool: The IPv4 prefix from which UE addresses will be drawn
223 - gnb_addr: The IPv4 address of the eNodeB
224 Optional Arguments:
225 - session_count: The number of sessions for which UE flows should be
226 created. Defaults to 1
227 - base_id: The first id to use for the IDs. Further IDs will be
228 generated by incrementing. Defaults to 1
229 - buffering: If this argument is present, downlink FARs will have the
230 buffering flag set to true. Defaults to False
231 - notifycp: If this argument is present, downlink FARs will have the notify
232 CP flag set to true. Defaults to False
233 """
234 try:
235 cmd = "session modify --count %s --ue-pool %s --gnb-addr %s --baseID %s %s %s" % (
236 session_count, ue_pool, gnb_addr, base_id,
237 "--buffer" if buffering else "",
238 "--notifycp" if notifycp else "" )
239 return self.sendline( cmd )
240 except Exception:
241 main.log.exception( self.name + ": Uncaught exception!" )
242 main.cleanAndExit()
243
244 def delete( self, session_count=1, base_id=1 ):
245 """
246 Delete PFPC Session(s)
247
248 Arguements:
249 - session_count: The number of sessions for which UE flows should be
250 created. Defaults to 1
251 - base_id: The first id to use for the IDs. Further IDs will be
252 generated by incrementing. Defaults to 1
253 """
254 try:
255 cmd = "session delete --count %s --baseID %s" % (
256 session_count, base_id )
257 return self.sendline( cmd )
258 except Exception:
259 main.log.exception( self.name + ": Uncaught exception!" )
260 main.cleanAndExit()
261
262 def stop( self ):
263 """
264 Exits Mock SMF
265 """
266 try:
267 self.handle.sendline( "fg" )
268 self.handle.send( "\x03" )
269 self.clearBuffer()
270 except pexpect.EOF:
271 main.log.error( self.name + ": EOF exception found" )
272 main.log.error( self.name + ": " + self.handle.before )
273 main.cleanAndExit()
274 except Exception:
275 main.log.exception( self.name + ": Uncaught exception!" )
276 main.cleanAndExit()
277