22import contextlib
33import json
44import subprocess
5+ import time
56
67import attr
78
1011from ..step import step
1112from ..util .helper import processwrapper
1213from ..util .managedfile import ManagedFile
14+ from ..util .timeout import Timeout
1315from ..resource .common import NetworkResource
1416
1517
@@ -25,6 +27,14 @@ def __attrs_post_init__(self):
2527 self ._record_handle = None
2628 self ._replay_handle = None
2729
30+ def on_activate (self ):
31+ self ._set_interface ("up" )
32+ self ._wait_state ("up" )
33+
34+ def on_deactivate (self ):
35+ self ._set_interface ("down" )
36+ self ._wait_state ("down" )
37+
2838 def _wrap_command (self , args ):
2939 wrapper = ["sudo" , "labgrid-raw-interface" ]
3040
@@ -35,6 +45,126 @@ def _wrap_command(self, args):
3545 # keep wrapper and args as-is
3646 return wrapper + args
3747
48+ @step (args = ["state" ])
49+ def _set_interface (self , state ):
50+ """Set interface to given state."""
51+ cmd = ["ip" , self .iface .ifname , state ]
52+ cmd = self ._wrap_command (cmd )
53+ subprocess .check_call (cmd )
54+
55+ @Driver .check_active
56+ def set_interface_up (self ):
57+ """Set bound interface up."""
58+ self ._set_interface ("up" )
59+
60+ @Driver .check_active
61+ def set_interface_down (self ):
62+ """Set bound interface down."""
63+ self ._set_interface ("down" )
64+
65+ def _get_state (self ):
66+ """Returns the bound interface's operstate."""
67+ if_state = self .iface .extra .get ("state" )
68+ if if_state :
69+ return if_state
70+
71+ cmd = self .iface .command_prefix + ["cat" , f"/sys/class/net/{ self .iface .ifname } /operstate" ]
72+ output = processwrapper .check_output (cmd ).decode ("ascii" )
73+ if_state = output .strip ()
74+ return if_state
75+
76+ @Driver .check_active
77+ def get_state (self ):
78+ """Returns the bound interface's operstate."""
79+ return self ._get_state ()
80+
81+ @step (title = "wait_state" , args = ["expected_state" , "timeout" ])
82+ def _wait_state (self , expected_state , timeout = 60 ):
83+ """Wait until the expected state is reached or the timeout expires."""
84+ timeout = Timeout (float (timeout ))
85+
86+ while True :
87+ if self ._get_state () == expected_state :
88+ return
89+ if timeout .expired :
90+ raise TimeoutError (
91+ f"exported interface { self .iface .ifname } did not go { expected_state } within { timeout .timeout } seconds"
92+ )
93+ time .sleep (1 )
94+
95+ @Driver .check_active
96+ def wait_state (self , expected_state , timeout = 60 ):
97+ """Wait until the expected state is reached or the timeout expires."""
98+ self ._wait_state (expected_state , timeout = timeout )
99+
100+ @Driver .check_active
101+ def get_ethtool_settings (self ):
102+ """
103+ Returns settings via ethtool of the bound network interface resource.
104+ """
105+ cmd = self .iface .command_prefix + ["ethtool" , "--json" , self .iface .ifname ]
106+ output = subprocess .check_output (cmd , encoding = "utf-8" )
107+ return json .loads (output )[0 ]
108+
109+ @Driver .check_active
110+ @step (args = ["settings" ])
111+ def ethtool_configure (self , ** settings ):
112+ """
113+ Change settings on interface.
114+
115+ Supported settings are described in ethtool(8) --change (use "_" instead of "-").
116+ """
117+ cmd = ["ethtool" , "change" , self .iface .ifname ]
118+ cmd += [item .replace ("_" , "-" ) for pair in settings .items () for item in pair ]
119+ cmd = self ._wrap_command (cmd )
120+ subprocess .check_call (cmd )
121+
122+ @Driver .check_active
123+ def get_ethtool_eee_settings (self ):
124+ """
125+ Returns Energy-Efficient Ethernet settings via ethtool of the bound network interface
126+ resource.
127+ """
128+ cmd = self .iface .command_prefix + ["ethtool" , "--show-eee" , "--json" , self .iface .ifname ]
129+ output = subprocess .check_output (cmd , encoding = "utf-8" )
130+ return json .loads (output )[0 ]
131+
132+ @Driver .check_active
133+ @step (args = ["settings" ])
134+ def ethtool_configure_eee (self , ** settings ):
135+ """
136+ Change Energy-Efficient Ethernet settings via ethtool of the bound network interface
137+ resource.
138+
139+ Supported settings are described in ethtool(8) --set-eee (use "_" instead of "-").
140+ """
141+ cmd = ["ethtool" , "set-eee" , self .iface .ifname ]
142+ cmd += [item .replace ("_" , "-" ) for pair in settings .items () for item in pair ]
143+ cmd = self ._wrap_command (cmd )
144+ subprocess .check_call (cmd )
145+
146+ @Driver .check_active
147+ def get_ethtool_pause_settings (self ):
148+ """
149+ Returns pause parameters via ethtool of the bound network interface resource.
150+ """
151+ cmd = self .iface .command_prefix + ["ethtool" , "--json" , "--show-pause" , self .iface .ifname ]
152+ output = subprocess .check_output (cmd , encoding = "utf-8" )
153+ return json .loads (output )[0 ]
154+
155+ @Driver .check_active
156+ @step (args = ["settings" ])
157+ def ethtool_configure_pause (self , ** settings ):
158+ """
159+ Change pause parameters via ethtool of the bound network interface resource.
160+
161+ Supported settings are described in ethtool(8) --pause
162+ """
163+ cmd = ["ethtool" , "pause" , self .iface .ifname ]
164+ cmd += [item for pair in settings .items () for item in pair ]
165+ cmd = self ._wrap_command (cmd )
166+ subprocess .check_call (cmd )
167+
38168 def _stop (self , proc , * , timeout = None ):
39169 assert proc is not None
40170
0 commit comments