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