xref: /openbmc/openbmc-test-automation/lib/bmc_network_utils.robot (revision 6ba6b22f371ca82aadeca7b2eec6d59955fbe7e3)
1*** Settings ***
2Resource                ../lib/utils.robot
3Resource                ../lib/connection_client.robot
4Resource                ../lib/boot_utils.robot
5Library                 ../lib/gen_misc.py
6Library                 ../lib/utils.py
7Library                 ../lib/bmc_network_utils.py
8
9*** Variables ***
10# MAC input from user.
11${MAC_ADDRESS}          ${EMPTY}
12
13
14*** Keywords ***
15
16Check And Reset MAC
17    [Documentation]  Update BMC with user input MAC address.
18    [Arguments]  ${mac_address}=${MAC_ADDRESS}
19
20    # Description of argument(s):
21    # mac_address  The mac address (e.g. 00:01:6c:80:02:28).
22
23    ${active_channel_config}=  Get Active Channel Config
24    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
25
26    Should Not Be Empty  ${mac_address}
27    Open Connection And Log In
28    ${bmc_mac_addr}  ${stderr}  ${rc}=  BMC Execute Command
29    ...  cat /sys/class/net/${ethernet_interface}/address
30    Run Keyword If  '${mac_address.lower()}' != '${bmc_mac_addr.lower()}'
31    ...  Set MAC Address
32
33
34Set MAC Address
35    [Documentation]  Update eth0 with input MAC address.
36    [Arguments]  ${mac_address}=${MAC_ADDRESS}
37
38    # Description of argument(s):
39    # mac_address  The mac address (e.g. 00:01:6c:80:02:28).
40
41    ${active_channel_config}=  Get Active Channel Config
42    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
43
44    Write  fw_setenv ethaddr ${mac_address}
45    OBMC Reboot (off)
46
47    # Take SSH session post BMC reboot.
48    Open Connection And Log In
49    ${bmc_mac_addr}  ${stderr}  ${rc}=  BMC Execute Command
50    ...  cat /sys/class/net/${ethernet_interface}/address
51    Should Be Equal  ${bmc_mac_addr}  ${mac_address}  ignore_case=True
52
53
54Get BMC IP Info
55    [Documentation]  Get system IP address and prefix length.
56
57
58    # Get system IP address and prefix length details using "ip addr"
59    # Sample Output of "ip addr":
60    # 1: eth0: <BROADCAST,MULTIAST> mtu 1500 qdisc mq state UP qlen 1000
61    #     link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
62    #     inet xx.xx.xx.xx/24 brd xx.xx.xx.xx scope global eth0
63
64    ${active_channel_config}=  Get Active Channel Config
65    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
66    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
67    ...  /sbin/ip addr | grep ${ethernet_interface}
68
69    # Get line having IP address details.
70    ${lines}=  Get Lines Containing String  ${cmd_output}  inet
71
72    # List IP address details.
73    @{ip_components}=  Split To Lines  ${lines}
74
75    @{ip_data}=  Create List
76
77    # Get all IP addresses and prefix lengths on system.
78    FOR  ${ip_component}  IN  @{ip_components}
79      @{if_info}=  Split String  ${ip_component}
80      ${ip_n_prefix}=  Get From List  ${if_info}  1
81      Append To List  ${ip_data}  ${ip_n_prefix}
82    END
83
84    RETURN  ${ip_data}
85
86Get BMC Route Info
87    [Documentation]  Get system route info.
88
89    # Sample output of "ip route":
90    # default via xx.xx.xx.x dev eth0
91    # xx.xx.xx.0/23 dev eth0  src xx.xx.xx.xx
92    # xx.xx.xx.0/24 dev eth0  src xx.xx.xx.xx
93
94    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
95    ...  /sbin/ip route
96
97    RETURN  ${cmd_output}
98
99Get BMC MAC Address
100    [Documentation]  Get system MAC address.
101
102    # Sample output of "ip addr | grep ether":
103    # link/ether xx.xx.xx.xx.xx.xx brd ff:ff:ff:ff:ff:ff
104
105    ${active_channel_config}=  Get Active Channel Config
106    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
107
108    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
109    ...  /sbin/ip addr | grep ${ethernet_interface} -A 1 | grep ether
110
111    # Split the line and return MAC address.
112    # Split list data:
113    # link/ether | xx:xx:xx:xx:xx:xx | brd | ff:ff:ff:ff:ff:ff
114
115    @{words}=  Split String  ${cmd_output}
116
117    RETURN  ${words[1]}
118
119
120Get BMC MAC Address List
121    [Documentation]  Get system MAC address
122
123    # Sample output of "ip addr | grep ether":
124    # link/ether xx.xx.xx.xx.xx.xx brd ff:ff:ff:ff:ff:ff
125
126    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
127    ...  /sbin/ip addr | grep ether
128
129    # Split the line and return MAC address.
130    # Split list data:
131    # link/ether | xx:xx:xx:xx:xx:xx | brd | ff:ff:ff:ff:ff:ff
132    # link/ether | xx:xx:xx:xx:xx:xx | brd | ff:ff:ff:ff:ff:ff
133
134    ${mac_list}=  Create List
135    @{lines}=  Split To Lines  ${cmd_output}
136    FOR  ${line}  IN  @{lines}
137      @{words}=  Split String  ${line}
138      Append To List  ${mac_list}  ${words[1]}
139    END
140
141    RETURN  ${mac_list}
142
143Get BMC Hostname
144    [Documentation]  Get BMC hostname.
145
146    # Sample output of  "hostname":
147    # test_hostname
148
149    ${output}  ${stderr}  ${rc}=  BMC Execute Command  hostname
150
151    RETURN  ${output}
152
153Get FW_Env MAC Address
154    [Documentation]  Get FW_Env MAC address.
155
156    # Sample output of "fw_printenv | grep ethaddr"
157    # ethaddr=xx:xx:xx:xx:xx:xx:xx
158
159    ${active_channel_config}=  Get Active Channel Config
160    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
161
162    ${ethernet_interface}=  Set Variable If
163    ...  "${ethernet_interface}"=="eth0"  ethaddr  eth1addr
164
165    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command  /sbin/fw_printenv | grep ${ethernet_interface}
166
167    # Split the line and return MAC address.
168    # Split list data:
169    # ethaddr | xx:xx:xx:xx:xx:xx:xx
170
171    @{words}=  Split String  ${cmd_output}  =
172
173    RETURN  ${words[1]}
174
175
176Get List Of IP Address Via REST
177    [Documentation]  Get list of IP address via REST.
178    [Arguments]  @{ip_uri_list}
179
180    # Description of argument(s):
181    # ip_uri_list  List of IP objects.
182    # Example:
183    #   "data": [
184    #     "/xyz/openbmc_project/network/eth0/ipv4/e9767624",
185    #     "/xyz/openbmc_project/network/eth0/ipv4/31f4ce8b"
186    #   ],
187
188    ${ip_list}=  Create List
189
190    FOR  ${ip_uri}  IN  @{ip_uri_list}
191      ${ip_addr}=  Read Attribute  ${ip_uri}  Address
192      Append To List  ${ip_list}  ${ip_addr}
193    END
194
195    RETURN  @{ip_list}
196
197Delete IP And Object
198    [Documentation]  Delete IP and object.
199    [Arguments]  ${ip_addr}  @{ip_uri_list}
200
201    # Description of argument(s):
202    # ip_addr      IP address to be deleted.
203    # ip_uri_list  List of IP object URIs.
204
205    # Find IP object having this IP address.
206
207     FOR  ${ip_uri}  IN  @{ip_uri_list}
208       ${ip_addr1}=  Read Attribute  ${ip_uri}  Address
209       Run Keyword If  '${ip_addr}' == '${ip_addr1}'  Exit For Loop
210     END
211
212    # If the given IP address is not configured, return.
213    # Otherwise, delete the IP and object.
214
215    Run Keyword And Return If  '${ip_addr}' != '${ip_addr1}'
216    ...  Pass Execution  IP address to be deleted is not configured.
217
218    Run Keyword And Ignore Error  OpenBMC Delete Request  ${ip_uri}
219
220    # After any modification on network interface, BMC restarts network
221    # module, wait until it is reachable. Then wait 15 seconds for new
222    # configuration to be updated on BMC.
223
224    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
225    ...  ${NETWORK_RETRY_TIME}
226    Sleep  15s
227
228    # Verify whether deleted IP address is removed from BMC system.
229
230    ${ip_data}=  Get BMC IP Info
231    Should Not Contain Match  ${ip_data}  ${ip_addr}*
232    ...  msg=IP address not deleted.
233
234Get First Non Pingable IP From Subnet
235    [Documentation]  Find first non-pingable IP from the subnet and return it.
236    [Arguments]  ${host}=${OPENBMC_HOST}
237
238    # Description of argument(s):
239    # host  Any valid host name or IP address
240    #       (e.g. "machine1" or "9.xx.xx.31").
241
242    # Non-pingable IP is unused IP address in the subnet.
243    ${host_name}  ${ip_addr}=  Get Host Name IP  ${host}
244
245    # Split IP address into network part and host part.
246    # IP address will have 4 octets xx.xx.xx.xx.
247    # Sample output after split:
248    # split_ip  [xx.xx.xx, xx]
249
250    ${split_ip}=  Split String From Right  ${ip_addr}  .  1
251    # First element in list is Network part.
252    ${network_part}=  Get From List  ${split_ip}  0
253
254    FOR  ${octet4}  IN RANGE  1  255
255      ${new_ip}=  Catenate  ${network_part}.${octet4}
256      ${status}=  Run Keyword And Return Status  Ping Host  ${new_ip}
257      # If IP is non-pingable, return it.
258      Return From Keyword If  '${status}' == 'False'  ${new_ip}
259    END
260
261    Fail  msg=No non-pingable IP could be found in subnet ${network_part}.
262
263
264Validate MAC On BMC
265    [Documentation]  Validate MAC on BMC.
266    [Arguments]  ${mac_addr}
267
268    # Description of argument(s):
269    # mac_addr  MAC address of the BMC.
270
271    ${system_mac}=  Get BMC MAC Address
272    ${mac_new_addr}=  Truncate MAC Address  ${system_mac}  ${mac_addr}
273
274    ${status}=  Compare MAC Address  ${system_mac}  ${mac_new_addr}
275    Should Be True  ${status}
276    ...  msg=MAC address ${system_mac} does not match ${mac_new_addr}.
277
278Validate MAC On FW_Env
279    [Documentation]  Validate MAC on FW_Env.
280    [Arguments]  ${mac_addr}
281
282    # Description of argument(s):
283    # mac_addr  MAC address of the BMC.
284
285    ${fw_env_addr}=  Get FW_Env MAC Address
286    ${mac_new_addr}=  Truncate MAC Address  ${fw_env_addr}  ${mac_addr}
287
288    ${status}=  Compare MAC Address  ${fw_env_addr}  ${mac_new_addr}
289    Should Be True  ${status}
290    ...  msg=MAC address ${fw_env_addr} does not match ${mac_new_addr}.
291
292Truncate MAC Address
293    [Documentation]  Truncates and returns user provided MAC address.
294    [Arguments]    ${sys_mac_addr}  ${user_mac_addr}
295
296    # Description of argument(s):
297    # sys_mac_addr  MAC address of the BMC.
298    # user_mac_addr user provided MAC address.
299
300    ${mac_byte}=  Set Variable  ${0}
301    @{user_mac_list}=  Split String  ${user_mac_addr}  :
302    @{sys_mac_list}=  Split String  ${sys_mac_addr}  :
303    ${user_new_mac_list}  Create List
304
305    # Truncate extra bytes and bits from MAC address
306    FOR  ${mac_item}  IN  @{sys_mac_list}
307        ${invalid_mac_byte} =  Get Regexp Matches  ${user_mac_list}[${mac_byte}]  [^A-Za-z0-9]+
308        Return From Keyword If  ${invalid_mac_byte}  ${user_mac_addr}
309        ${mac_int} =    Convert To Integer      ${user_mac_list}[${mac_byte}]   16
310        ${user_mac_len} =  Get Length  ${user_mac_list}
311        ${user_mac_byte}=  Run Keyword IF
312        ...  ${mac_int} >= ${256}  Truncate MAC Bits  ${user_mac_list}[${mac_byte}]
313        ...  ELSE  Set Variable  ${user_mac_list}[${mac_byte}]
314
315        Append To List  ${user_new_mac_list}  ${user_mac_byte}
316        ${mac_byte} =    Set Variable    ${mac_byte + 1}
317        Exit For Loop If  '${mac_byte}' == '${user_mac_len}'
318
319    END
320    ${user_new_mac_string}=   Evaluate  ":".join(${user_new_mac_list})
321    RETURN  ${user_new_mac_string}
322
323Truncate MAC Bits
324    [Documentation]  Truncates user provided MAC address byte to bits.
325    [Arguments]    ${user_mac_addr_byte}
326
327    # Description of argument(s):
328    # user_mac_addr_byte user provided MAC address byte to truncate bits
329
330    ${user_mac_addr_int}=   Convert To List  ${user_mac_addr_byte}
331    ${user_mac_addr_byte}=  Get Slice From List  ${user_mac_addr_int}  0  2
332    ${user_mac_addr_byte_string}=  Evaluate  "".join(${user_mac_addr_byte})
333    RETURN  ${user_mac_addr_byte_string}
334
335
336Run Build Net
337    [Documentation]  Run build_net to preconfigure the ethernet interfaces.
338
339    OS Execute Command  build_net help y y
340    # Run pingum to check if the "build_net" was run correctly done.
341    ${output}  ${stderr}  ${rc}=  OS Execute Command  pingum
342    Should Contain  ${output}  All networks ping Ok
343
344
345Configure Hostname
346    [Documentation]  Configure hostname on BMC via Redfish.
347    [Arguments]  ${hostname}  ${status_code}=[${HTTP_OK}, ${HTTP_NO_CONTENT}]
348
349    # Description of argument(s):
350    # hostname  A hostname value which is to be configured on BMC.
351
352    ${active_channel_config}=  Get Active Channel Config
353    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
354
355    ${data}=  Create Dictionary  HostName=${hostname}
356    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  body=&{data}
357    ...  valid_status_codes=${status_code}
358
359
360Verify IP On BMC
361    [Documentation]  Verify IP on BMC.
362    [Arguments]  ${ip}
363
364    # Description of argument(s):
365    # ip  IP address to be verified (e.g. "10.7.7.7").
366
367    # Get IP address details on BMC using IP command.
368    @{ip_data}=  Get BMC IP Info
369    Should Contain Match  ${ip_data}  ${ip}/*
370    ...  msg=IP address does not exist.
371
372
373Verify Gateway On BMC
374    [Documentation]  Verify gateway on BMC.
375    [Arguments]  ${gateway_ip}=0.0.0.0
376
377    # Description of argument(s):
378    # gateway_ip  Gateway IP address.
379
380    ${route_info}=  Get BMC Route Info
381
382    # If gateway IP is empty or 0.0.0.0 it will not have route entry.
383
384    Run Keyword If  '${gateway_ip}' == '0.0.0.0'
385    ...      Pass Execution  Gateway IP is "0.0.0.0".
386    ...  ELSE
387    ...      Should Contain  ${route_info}  ${gateway_ip}
388    ...      msg=Gateway IP address not matching.
389
390
391Get BMC DNS Info
392    [Documentation]  Get system DNS info.
393
394
395    # Sample output of "resolv.conf":
396    # ### Generated manually via dbus settings ###
397    # nameserver 8.8.8.8
398
399    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command
400    ...  cat /etc/resolv.conf
401
402    RETURN  ${cmd_output}
403
404
405CLI Get Nameservers
406    [Documentation]  Get the nameserver IPs from /etc/resolv.conf and return as a list.
407
408    # Example of /etc/resolv.conf data:
409    # nameserver x.x.x.x
410    # nameserver y.y.y.y
411
412    ${stdout}  ${stderr}  ${rc}=  BMC Execute Command
413    ...  egrep nameserver /etc/resolv.conf | cut -f2- -d ' '
414    ${nameservers}=  Split String  ${stdout}
415
416    RETURN  ${nameservers}
417
418CLI Get and Verify Name Servers
419    [Documentation]    Get and Verify the nameserver IPs from /etc/resolv.conf and compare with redfish nameserver.
420    [Arguments]     ${static_name_servers}
421    ...  ${valid_status_codes}=${HTTP_OK}
422
423    # Description of Argument(s):
424    # static_name_servers:   Address for static name server
425
426    ${cli_nameservers}=  CLI Get Nameservers
427    ${cmd_status}=  Run Keyword And Return Status
428    ...  List Should Contain Sub List  ${cli_nameservers}  ${static_name_servers}
429
430    Run Keyword If  '${valid_status_codes}' == '${HTTP_OK}'
431    ...  Should Be True  ${cmd_status}
432    ...  ELSE  Should Not Be True  ${cmd_status}
433
434Get Network Configuration
435    [Documentation]  Get network configuration.
436    # Sample output:
437    #{
438    #  "@odata.context": "/redfish/v1/$metadata#EthernetInterface.EthernetInterface",
439    #  "@odata.id": "/redfish/v1/Managers/${MANAGER_ID}/EthernetInterfaces/eth0",
440    #  "@odata.type": "#EthernetInterface.v1_2_0.EthernetInterface",
441    #  "Description": "Management Network Interface",
442    #  "IPv4Addresses": [
443    #    {
444    #      "Address": "169.254.xx.xx",
445    #      "AddressOrigin": "IPv4LinkLocal",
446    #      "Gateway": "0.0.0.0",
447    #      "SubnetMask": "255.255.0.0"
448    #    },
449    #    {
450    #      "Address": "xx.xx.xx.xx",
451    #      "AddressOrigin": "Static",
452    #      "Gateway": "xx.xx.xx.1",
453    #      "SubnetMask": "xx.xx.xx.xx"
454    #    }
455    #  ],
456    #  "Id": "eth0",
457    #  "MACAddress": "xx:xx:xx:xx:xx:xx",
458    #  "Name": "Manager Ethernet Interface",
459    #  "SpeedMbps": 0,
460    #  "VLAN": {
461    #    "VLANEnable": false,
462    #    "VLANId": 0
463    #  }
464    [Arguments]  ${network_active_channel}=${CHANNEL_NUMBER}
465
466    # Description of argument(s):
467    # network_active_channel   Ethernet channel number (eg. 1 or 2)
468
469    ${active_channel_config}=  Get Active Channel Config
470    ${resp}=  Redfish.Get
471    ...  ${REDFISH_NW_ETH_IFACE}${active_channel_config['${network_active_channel}']['name']}
472
473    @{network_configurations}=  Get From Dictionary  ${resp.dict}  IPv4StaticAddresses
474    RETURN  @{network_configurations}
475
476
477Add IP Address
478    [Documentation]  Add IP Address To BMC.
479    [Arguments]  ${ip}  ${subnet_mask}  ${gateway}
480    ...  ${valid_status_codes}=${HTTP_OK}
481
482    # Description of argument(s):
483    # ip                  IP address to be added (e.g. "10.7.7.7").
484    # subnet_mask         Subnet mask for the IP to be added
485    #                     (e.g. "255.255.0.0").
486    # gateway             Gateway for the IP to be added (e.g. "10.7.7.1").
487    # valid_status_codes  Expected return code from patch operation
488    #                     (e.g. "200").  See prolog of rest_request
489    #                     method in redfish_plus.py for details.
490
491    ${empty_dict}=  Create Dictionary
492    ${ip_data}=  Create Dictionary  Address=${ip}
493    ...  SubnetMask=${subnet_mask}  Gateway=${gateway}
494
495    ${patch_list}=  Create List
496    ${network_configurations}=  Get Network Configuration
497    ${num_entries}=  Get Length  ${network_configurations}
498
499    FOR  ${INDEX}  IN RANGE  0  ${num_entries}
500      Append To List  ${patch_list}  ${empty_dict}
501    END
502
503    ${valid_status_codes}=  Run Keyword If  '${valid_status_codes}' == '${HTTP_OK}'
504    ...  Set Variable   ${HTTP_OK},${HTTP_NO_CONTENT}
505    ...  ELSE  Set Variable  ${valid_status_codes}
506
507    # We need not check for existence of IP on BMC while adding.
508    Append To List  ${patch_list}  ${ip_data}
509    ${data}=  Create Dictionary  IPv4StaticAddresses=${patch_list}
510
511    ${active_channel_config}=  Get Active Channel Config
512    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
513
514    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  body=&{data}
515    ...  valid_status_codes=[${valid_status_codes}]
516
517    Return From Keyword If  '${valid_status_codes}' != '${HTTP_OK},${HTTP_NO_CONTENT}'
518
519    # Note: Network restart takes around 15-18s after patch request processing.
520    Sleep  ${NETWORK_TIMEOUT}s
521    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
522
523    Verify IP On BMC  ${ip}
524    Validate Network Config On BMC
525
526
527Delete IP Address
528    [Documentation]  Delete IP Address Of BMC.
529    [Arguments]  ${ip}  ${valid_status_codes}=${HTTP_OK}
530
531    # Description of argument(s):
532    # ip                  IP address to be deleted (e.g. "10.7.7.7").
533    # valid_status_codes  Expected return code from patch operation
534    #                     (e.g. "200").  See prolog of rest_request
535    #                     method in redfish_plus.py for details.
536
537    ${empty_dict}=  Create Dictionary
538    ${patch_list}=  Create List
539
540    @{network_configurations}=  Get Network Configuration
541    FOR  ${network_configuration}  IN  @{network_configurations}
542      Run Keyword If  '${network_configuration['Address']}' == '${ip}'
543      ...  Append To List  ${patch_list}  ${null}
544      ...  ELSE  Append To List  ${patch_list}  ${empty_dict}
545    END
546
547    ${ip_found}=  Run Keyword And Return Status  List Should Contain Value
548    ...  ${patch_list}  ${null}  msg=${ip} does not exist on BMC
549    Pass Execution If  ${ip_found} == ${False}  ${ip} does not exist on BMC
550
551    # Run patch command only if given IP is found on BMC
552    ${data}=  Create Dictionary  IPv4StaticAddresses=${patch_list}
553
554    ${active_channel_config}=  Get Active Channel Config
555    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
556
557    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  body=&{data}
558    ...  valid_status_codes=[${valid_status_codes}]
559
560    # Note: Network restart takes around 15-18s after patch request processing
561    Sleep  ${NETWORK_TIMEOUT}s
562    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
563
564    ${delete_status}=  Run Keyword And Return Status  Verify IP On BMC  ${ip}
565    Run Keyword If  '${valid_status_codes}' == '${HTTP_OK}'
566    ...  Should Be True  '${delete_status}' == '${False}'
567    ...  ELSE  Should Be True  '${delete_status}' == '${True}'
568
569    Validate Network Config On BMC
570
571
572Validate Network Config On BMC
573    [Documentation]  Check that network info obtained via redfish matches info
574    ...              obtained via CLI.
575
576    @{network_configurations}=  Get Network Configuration
577    ${ip_data}=  Get BMC IP Info
578    FOR  ${network_configuration}  IN  @{network_configurations}
579      Should Contain Match  ${ip_data}  ${network_configuration['Address']}/*
580      ...  msg=IP address does not exist.
581    END
582
583
584Create VLAN
585    [Documentation]  Create a VLAN.
586    [Arguments]  ${id}  ${interface}=eth0  ${expected_result}=valid
587
588    # Description of argument(s):
589    # id  The VLAN ID (e.g. '53').
590    # interface  The physical interface for the VLAN(e.g. 'eth0').
591    # expected_result  Expected status of VLAN configuration.
592
593    @{data_vlan_id}=  Create List  ${interface}  ${id}
594    ${data}=  Create Dictionary   data=@{data_vlan_id}
595    ${resp}=  OpenBMC Post Request  ${vlan_resource}  data=${data}
596    ${resp.status_code}=  Convert To String  ${resp.status_code}
597    ${status}=  Run Keyword And Return Status
598    ...  Valid Value  resp.status_code  ["${HTTP_OK}"]
599
600    Run Keyword If  '${expected_result}' == 'error'
601    ...      Should Be Equal  ${status}  ${False}
602    ...      msg=Configuration of an invalid VLAN ID Failed.
603    ...  ELSE
604    ...      Should Be Equal  ${status}  ${True}
605    ...      msg=Configuration of a valid VLAN ID Failed.
606
607    Sleep  ${NETWORK_TIMEOUT}s
608
609
610Configure Network Settings On VLAN
611    [Documentation]  Configure network settings.
612    [Arguments]  ${id}  ${ip_addr}  ${prefix_len}  ${gateway_ip}=${gateway}
613    ...  ${expected_result}=valid  ${interface}=eth0
614
615    # Description of argument(s):
616    # id               The VLAN ID (e.g. '53').
617    # ip_addr          IP address of VLAN Interface.
618    # prefix_len       Prefix length of VLAN Interface.
619    # gateway_ip       Gateway IP address of VLAN Interface.
620    # expected_result  Expected status of network setting configuration.
621    # interface        Physical Interface on which the VLAN is defined.
622
623    @{ip_parm_list}=  Create List  ${network_resource}
624    ...  ${ip_addr}  ${prefix_len}  ${gateway_ip}
625
626    ${data}=  Create Dictionary  data=@{ip_parm_list}
627
628    Run Keyword And Ignore Error  OpenBMC Post Request
629    ...  ${NETWORK_MANAGER}${interface}_${id}/action/IP  data=${data}
630
631    # After any modification on network interface, BMC restarts network
632    # module, wait until it is reachable. Then wait 15 seconds for new
633    # configuration to be updated on BMC.
634
635    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
636    ...  ${NETWORK_RETRY_TIME}
637    Sleep  ${NETWORK_TIMEOUT}s
638
639    # Verify whether new IP address is populated on BMC system.
640    # It should not allow to configure invalid settings.
641    ${status}=  Run Keyword And Return Status
642    ...  Verify IP On BMC  ${ip_addr}
643
644    Run Keyword If  '${expected_result}' == 'error'
645    ...      Should Be Equal  ${status}  ${False}
646    ...      msg=Configuration of invalid IP Failed.
647    ...  ELSE
648    ...      Should Be Equal  ${status}  ${True}
649    ...      msg=Configuration of valid IP Failed.
650
651
652Get BMC Default Gateway
653    [Documentation]  Get system default gateway.
654
655    ${route_info}=  Get BMC Route Info
656
657    ${lines}=  Get Lines Containing String  ${route_info}  default via
658
659    ${active_channel_config}=  Get Active Channel Config
660    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
661
662    # Extract the corresponding default gateway for eth0 and eth1
663    ${default_gw_line}=  Get Lines Containing String  ${lines}  ${ethernet_interface}
664    ${default_gw}=  Split String  ${default_gw_line}
665
666    # Example of the output
667    # default_gw:
668    #   [0]:   default
669    #   [1]:   via
670    #   [2]:   xx.xx.xx.1
671    #   [3]:   dev
672    #   [4]:   eth1
673
674    RETURN  ${default_gw[2]}
675
676
677Validate Hostname On BMC
678    [Documentation]  Verify that the hostname read via Redfish is the same as the
679    ...  hostname configured on system.
680    [Arguments]  ${hostname}
681
682    # Description of argument(s):
683    # hostname  A hostname value which is to be compared to the hostname
684    #           configured on system.
685
686    ${sys_hostname}=  Get BMC Hostname
687    Should Be Equal  ${sys_hostname}  ${hostname}
688    ...  ignore_case=True  msg=Hostname does not exist.
689
690Get Channel Number For All Interface
691    [Documentation]  Gets the Interface name and returns the channel number for the given interface.
692
693    ${valid_channel_number_interface_names}=  Get Channel Config
694
695    ${valid_channel_number_interface_names}=  Convert To Dictionary  ${valid_channel_number_interface_names}
696
697    RETURN  ${valid_channel_number_interface_names}
698
699Get Valid Channel Number
700    [Documentation]  Get Valid Channel Number.
701    [Arguments]  ${valid_channel_number_interface_names}
702
703    #Description of argument(s):
704    #valid_channel_number_interface_names   Contains channel names in dict.
705
706    &{valid_channel_number_interface_name}=  Create Dictionary
707
708    FOR  ${key}  ${values}  IN  &{valid_channel_number_interface_names}
709      Run Keyword If  '${values['is_valid']}' == 'True'
710      ...  Set To Dictionary  ${valid_channel_number_interface_name}  ${key}  ${values}
711    END
712
713    RETURN  ${valid_channel_number_interface_name}
714
715Get Invalid Channel Number List
716    [Documentation]  Get Invalid Channel and return as list.
717
718    ${available_channels}=  Get Channel Number For All Interface
719    # Get the channel which medium_type as 'reserved' and append it to a list.
720    @{invalid_channel_number_list}=  Create List
721
722    FOR  ${channel_number}  ${values}  IN  &{available_channels}
723       Run Keyword If  '${values['channel_info']['medium_type']}' == 'reserved'
724       ...  Append To List  ${invalid_channel_number_list}  ${channel_number}
725    END
726
727    RETURN  ${invalid_channel_number_list}
728
729
730Get Channel Number For Valid Ethernet Interface
731    [Documentation]  Get channel number for all ethernet interface.
732    [Arguments]  ${valid_channel_number_interface_name}
733
734    # Description of argument(s):
735    # channel_number_list  Contains channel names in list.
736
737    @{channel_number_list}=  Create List
738
739    FOR  ${channel_number}  ${values}  IN  &{valid_channel_number_interface_name}
740      ${usb_interface_status}=  Run Keyword And Return Status  Should Not Contain  ${values['name']}  usb
741      Continue For Loop IF  ${usb_interface_status} == False
742      Run Keyword If  '${values['channel_info']['medium_type']}' == 'lan-802.3'
743      ...  Append To List  ${channel_number_list}  ${channel_number}
744    END
745
746    RETURN  ${channel_number_list}
747
748
749Get Current Channel Name List
750    [Documentation]  Get Current Channel name and append it to active channel list.
751    [Arguments]  ${channel_list}  ${channel_config_json}
752
753    # Description of Arguments
754    # ${channel_list}        - list Contains all available active channels.
755    # ${channel_config_json} - output of /usr/share/ipmi-providers/channel_config.json file.
756
757    FOR  ${channel_number}  ${values}  IN  &{channel_config_json}
758        Run Keyword If  '${values['name']}' == 'SELF'
759        ...  Run Keyword  Append To List  ${channel_list}  ${channel_number}
760    END
761
762    RETURN  ${channel_list}
763
764
765Get Active Ethernet Channel List
766    [Documentation]  Get Available channels from channel_config.json file and return as list.
767    [Arguments]  ${current_channel}=${0}
768
769    ${valid_channel_number_interface_names}=  Get Channel Number For All Interface
770
771    ${valid_channel_number_interface_name}=  Get Valid Channel Number  ${valid_channel_number_interface_names}
772
773    ${channel_number_list}=  Get Channel Number For Valid Ethernet Interface
774    ...  ${valid_channel_number_interface_name}
775
776    Return From Keyword If  ${current_channel} == 0  ${channel_number_list}
777    ${channel_number_list}=  Get Current Channel Name List
778    ...  ${channel_number_list}  ${valid_channel_number_interface_names}
779
780    RETURN  ${channel_number_list}
781
782Update IP Address
783    [Documentation]  Update and verify IP address of BMC.
784    [Arguments]  ${ip}  ${new_ip}  ${netmask}  ${gw_ip}
785    ...  ${valid_status_codes}=[${HTTP_OK}, ${HTTP_NO_CONTENT}]
786
787    # Description of argument(s):
788    # ip                  IP address to be replaced (e.g. "10.7.7.7").
789    # new_ip              New IP address to be configured.
790    # netmask             Netmask value.
791    # gw_ip               Gateway IP address.
792    # valid_status_codes  Expected return code from patch operation
793    #                     (e.g. "200").  See prolog of rest_request
794    #                     method in redfish_plus.py for details.
795
796    ${empty_dict}=  Create Dictionary
797    ${patch_list}=  Create List
798    ${ip_data}=  Create Dictionary
799    ...  Address=${new_ip}  SubnetMask=${netmask}  Gateway=${gw_ip}
800
801    # Find the position of IP address to be modified.
802    @{network_configurations}=  Get Network Configuration
803    FOR  ${network_configuration}  IN  @{network_configurations}
804      Run Keyword If  '${network_configuration['Address']}' == '${ip}'
805      ...  Append To List  ${patch_list}  ${ip_data}
806      ...  ELSE  Append To List  ${patch_list}  ${empty_dict}
807    END
808
809    # Modify the IP address only if given IP is found
810    ${ip_found}=  Run Keyword And Return Status  List Should Contain Value
811    ...  ${patch_list}  ${ip_data}  msg=${ip} does not exist on BMC
812    Pass Execution If  ${ip_found} == ${False}  ${ip} does not exist on BMC
813
814    ${data}=  Create Dictionary  IPv4StaticAddresses=${patch_list}
815
816    ${active_channel_config}=  Get Active Channel Config
817    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
818
819    Redfish.patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}
820    ...  body=&{data}  valid_status_codes=${valid_status_codes}
821
822    # Note: Network restart takes around 15-18s after patch request processing.
823    Sleep  ${NETWORK_TIMEOUT}s
824    Wait For Host To Ping  ${OPENBMC_HOST}  ${NETWORK_TIMEOUT}
825
826    Verify IP On BMC  ${new_ip}
827    Validate Network Config On BMC
828
829Get IPv4 DHCP Enabled Status
830    [Documentation]  Return IPv4 DHCP enabled status from redfish URI.
831    [Arguments]  ${channel_number}=${1}
832
833    # Description of argument(s):
834    # channel_number   Ethernet channel number, 1 is for eth0 and 2 is for eth1 (e.g. "1").
835
836    ${active_channel_config}=  Get Active Channel Config
837    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
838    ${resp}=  Redfish.Get Attribute  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  DHCPv4
839    Return From Keyword  ${resp['DHCPEnabled']}
840
841Get DHCP IP Info
842    [Documentation]  Return DHCP IP address, gateway and subnetmask from redfish URI.
843
844    ${active_channel_config}=  Get Active Channel Config
845    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
846    ${resp_list}=  Redfish.Get Attribute  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  IPv4Addresses
847    FOR  ${resp}  IN  @{resp_list}
848        Continue For Loop If  '${resp['AddressOrigin']}' != 'DHCP'
849        ${ip_addr}=  Set Variable  ${resp['Address']}
850        ${gateway}=  Set Variable  ${resp['Gateway']}
851        ${subnetmask}=  Set Variable  ${resp['SubnetMask']}
852        Return From Keyword  ${ip_addr}  ${gateway}  ${subnetmask}
853    END
854
855
856DNS Test Setup Execution
857    [Documentation]  Do DNS test setup execution.
858
859    Redfish.Login
860
861    ${active_channel_config}=  Get Active Channel Config
862    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
863
864    ${original_nameservers}=  Redfish.Get Attribute
865    ...  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}  StaticNameServers
866
867    Rprint Vars  original_nameservers
868    # Set suite variables to trigger restoration during teardown.
869    Set Suite Variable  ${original_nameservers}
870
871
872Delete Static Name Servers
873    [Documentation]  Delete static name servers.
874
875    DNS Test Setup Execution
876    Configure Static Name Servers  static_name_servers=@{EMPTY}
877
878    # Check if all name servers deleted on BMC.
879    ${nameservers}=  CLI Get Nameservers
880    Should Not Contain  ${nameservers}  ${original_nameservers}
881
882    DNS Test Setup Execution
883
884    Should Be Empty  ${original_nameservers}
885
886
887Configure Static Name Servers
888    [Documentation]  Configure DNS server on BMC.
889    [Arguments]  ${static_name_servers}=${original_nameservers}
890     ...  ${valid_status_codes}=${HTTP_OK}
891
892    # Description of the argument(s):
893    # static_name_servers  A list of static name server IPs to be
894    #                      configured on the BMC.
895
896    ${active_channel_config}=  Get Active Channel Config
897    ${ethernet_interface}=  Set Variable  ${active_channel_config['${CHANNEL_NUMBER}']['name']}
898
899    ${type} =  Evaluate  type($static_name_servers).__name__
900    ${static_name_servers}=  Set Variable If  '${type}'=='str'
901    ...  '${static_name_servers}'  ${static_name_servers}
902
903    # Currently BMC is sending 500 response code instead of 400 for invalid scenarios.
904    Redfish.Patch  ${REDFISH_NW_ETH_IFACE}${ethernet_interface}
905    ...  body={'StaticNameServers': ${static_name_servers}}
906    ...  valid_status_codes=[${valid_status_codes}, ${HTTP_INTERNAL_SERVER_ERROR}]
907
908    # Patch operation takes 1 to 3 seconds to set new value.
909    Sleep  3s
910
911    # Check if newly added DNS server is configured on BMC.
912    CLI Get and Verify Name Servers  ${static_name_servers}  ${valid_status_codes}
913