Home | History | Annotate | Download | only in net
      1 """Convenience functions for use by network tests or whomever.
      2 
      3 This library is to release in the public repository.
      4 """
      5 
      6 import commands, os, re, socket, sys, time, struct
      7 from autotest_lib.client.common_lib import error
      8 from autotest_lib.client.bin import utils as client_utils
      9 import utils
     10 
     11 TIMEOUT = 10 # Used for socket timeout and barrier timeout
     12 
     13 
     14 class network_utils(object):
     15     def reset(self, ignore_status=False):
     16         utils.system('service network restart', ignore_status=ignore_status)
     17 
     18 
     19     def start(self, ignore_status=False):
     20         utils.system('service network start', ignore_status=ignore_status)
     21 
     22 
     23     def stop(self, ignore_status=False):
     24         utils.system('service network stop', ignore_status=ignore_status)
     25 
     26 
     27     def list(self):
     28         utils.system('ifconfig -a')
     29 
     30 
     31     def get_ip_local(self, query_ip, netmask="24"):
     32         """
     33         Get ip address in local system which can communicate with query_ip.
     34 
     35         @param query_ip: IP of client which wants to communicate with
     36                 autotest machine.
     37         @return: IP address which can communicate with query_ip
     38         """
     39         ip = client_utils.system_output("ip addr show to %s/%s" %
     40                                         (query_ip, netmask))
     41         ip = re.search(r"inet ([0-9.]*)/",ip)
     42         if ip is None:
     43             return ip
     44         return ip.group(1)
     45 
     46 
     47     def disable_ip_local_loopback(self, ignore_status=False):
     48         utils.system("echo '1' > /proc/sys/net/ipv4/route/no_local_loopback",
     49                      ignore_status=ignore_status)
     50         utils.system('echo 1 > /proc/sys/net/ipv4/route/flush',
     51                      ignore_status=ignore_status)
     52 
     53 
     54     def enable_ip_local_loopback(self, ignore_status=False):
     55         utils.system("echo '0' > /proc/sys/net/ipv4/route/no_local_loopback",
     56                      ignore_status=ignore_status)
     57         utils.system('echo 1 > /proc/sys/net/ipv4/route/flush',
     58                      ignore_status=ignore_status)
     59 
     60 
     61     def process_mpstat(self, mpstat_out, sample_count, loud = True):
     62         """Parses mpstat output of the following two forms:
     63         02:10:17     0    0.00    0.00    0.00    0.00    0.00    0.00   \
     64         0.00  100.00   1012.87
     65         02:10:13 PM    0    0.00    0.00    0.00    0.00    0.00    0.00 \
     66         0.00  100.00   1019.00
     67         """
     68         mpstat_keys = ['time', 'CPU', 'user', 'nice', 'sys', 'iowait', 'irq',
     69                        'soft', 'steal', 'idle', 'intr/s']
     70         if loud:
     71             print mpstat_out
     72 
     73         # Remove the optional AM/PM appearing in time format
     74         mpstat_out = mpstat_out.replace('AM', '')
     75         mpstat_out = mpstat_out.replace('PM', '')
     76 
     77         regex = re.compile('(\S+)')
     78         stats = []
     79         for line in mpstat_out.splitlines()[3:]:
     80             match = regex.findall(line)
     81             # Skip the "Average" computed by mpstat. We are gonna compute the
     82             # average ourself.  Pick only the aggregate 'all' CPU results
     83             if match and match[0] != 'Average:' and match[1] == 'all':
     84                 stats.append(dict(zip(mpstat_keys, match)))
     85 
     86         if sample_count >= 5:
     87             # Throw away first and last sample
     88             stats = stats[1:-1]
     89 
     90         cpu_stats = {}
     91         for key in ['user', 'nice', 'sys', 'iowait', 'irq', 'soft', 'steal',
     92                     'idle', 'intr/s']:
     93             x = [float(row[key]) for row in stats]
     94             if len(x):
     95                 count = len(x)
     96             else:
     97                 print 'net_utils.network_utils.process_mpstat: count is 0!!!\n'
     98                 count = 1
     99             cpu_stats[key] = sum(x) / count
    100 
    101         return cpu_stats
    102 
    103 
    104 def network():
    105     try:
    106         from autotest_lib.client.bin.net import site_net_utils
    107         return site_net_utils.network_utils()
    108     except:
    109         return network_utils()
    110 
    111 
    112 class network_interface(object):
    113 
    114     ENABLE, DISABLE = (True, False)
    115 
    116     def __init__(self, name):
    117         autodir = os.environ['AUTODIR']
    118         self.ethtool = 'ethtool'
    119         self._name = name
    120         self.was_down = self.is_down()
    121         self.orig_ipaddr = self.get_ipaddr()
    122         self.was_loopback_enabled = self.is_loopback_enabled()
    123         self._socket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
    124         self._socket.settimeout(TIMEOUT)
    125         self._socket.bind((name, raw_socket.ETH_P_ALL))
    126 
    127 
    128     def restore(self):
    129         self.set_ipaddr(self.orig_ipaddr)
    130         # TODO (msb): The additional conditional guard needs cleanup:
    131         #             Underlying driver should simply perform a noop
    132         #             for disabling loopback on an already-disabled device,
    133         #             instead of returning non-zero exit code.
    134 
    135         # To avoid sending a RST to the autoserv ssh connection
    136         # don't disable loopback until the IP address is restored.
    137         if not self.was_loopback_enabled and self.is_loopback_enabled():
    138             self.disable_loopback()
    139         if self.was_down:
    140             self.down()
    141 
    142 
    143     def get_name(self):
    144         return self._name
    145 
    146 
    147     def parse_ethtool(self, field, match, option='', next_field=''):
    148         output = utils.system_output('%s %s %s' % (self.ethtool,
    149                                                    option, self._name))
    150         if output:
    151             match = re.search('\n\s*%s:\s*(%s)%s' %
    152                               (field, match, next_field), output, re.S)
    153             if match:
    154                 return match.group(1)
    155 
    156         return ''
    157 
    158 
    159     def get_stats(self):
    160         stats = {}
    161         stats_path = '/sys/class/net/%s/statistics/' % self._name
    162         for stat in os.listdir(stats_path):
    163             f = open(stats_path + stat, 'r')
    164             if f:
    165                 stats[stat] = int(f.read())
    166                 f.close()
    167         return stats
    168 
    169 
    170     def get_stats_diff(self, orig_stats):
    171         stats = self.get_stats()
    172         for stat in stats.keys():
    173             if stat in orig_stats:
    174                 stats[stat] = stats[stat] - orig_stats[stat]
    175             else:
    176                 stats[stat] = stats[stat]
    177         return stats
    178 
    179 
    180     def get_driver(self):
    181         driver_path = os.readlink('/sys/class/net/%s/device/driver' %
    182                                   self._name)
    183         return os.path.basename(driver_path)
    184 
    185 
    186     def get_carrier(self):
    187         f = open('/sys/class/net/%s/carrier' % self._name)
    188         if not f:
    189             return ''
    190         carrier = f.read().strip()
    191         f.close()
    192         return carrier
    193 
    194 
    195     def get_supported_link_modes(self):
    196         result = self.parse_ethtool('Supported link modes', '.*',
    197                                     next_field='Supports auto-negotiation')
    198         return result.split()
    199 
    200 
    201     def get_advertised_link_modes(self):
    202         result = self.parse_ethtool('Advertised link modes', '.*',
    203                                     next_field='Advertised auto-negotiation')
    204         return result.split()
    205 
    206 
    207     def is_autoneg_advertised(self):
    208         result = self.parse_ethtool('Advertised auto-negotiation',
    209                                         'Yes|No')
    210         return result == 'Yes'
    211 
    212 
    213     def get_speed(self):
    214         return int(self.parse_ethtool('Speed', '\d+'))
    215 
    216 
    217     def is_full_duplex(self):
    218         result = self.parse_ethtool('Duplex', 'Full|Half')
    219         return result == 'Full'
    220 
    221 
    222     def is_autoneg_on(self):
    223         result = self.parse_ethtool('Auto-negotiation', 'on|off')
    224         return result == 'on'
    225 
    226 
    227     def get_wakeon(self):
    228         return self.parse_ethtool('Wake-on', '\w+')
    229 
    230 
    231     def is_rx_summing_on(self):
    232         result = self.parse_ethtool('rx-checksumming', 'on|off', '-k')
    233         return result == 'on'
    234 
    235 
    236     def is_tx_summing_on(self):
    237         result = self.parse_ethtool('tx-checksumming', 'on|off', '-k')
    238         return result == 'on'
    239 
    240 
    241     def is_scatter_gather_on(self):
    242         result = self.parse_ethtool('scatter-gather', 'on|off', '-k')
    243         return result == 'on'
    244 
    245 
    246     def is_tso_on(self):
    247         result = self.parse_ethtool('tcp segmentation offload',
    248                                     'on|off', '-k')
    249         return result == 'on'
    250 
    251 
    252     def is_pause_autoneg_on(self):
    253         result = self.parse_ethtool('Autonegotiate', 'on|off', '-a')
    254         return result == 'on'
    255 
    256 
    257     def is_tx_pause_on(self):
    258         result = self.parse_ethtool('TX', 'on|off', '-a')
    259         return result == 'on'
    260 
    261 
    262     def is_rx_pause_on(self):
    263         result = self.parse_ethtool('RX', 'on|off', '-a')
    264         return result == 'on'
    265 
    266 
    267     def _set_loopback(self, mode, enable_disable):
    268         return utils.system('%s -L %s %s %s' %
    269                       (self.ethtool, self._name, mode, enable_disable),
    270                       ignore_status=True)
    271 
    272 
    273     def enable_loopback(self):
    274         # If bonded do not set loopback mode.
    275         # Try mac loopback first then phy loopback
    276         # If both fail, raise an error
    277         if bond().is_enabled():
    278             raise error.TestError('Unable to enable loopback while '
    279                                   'bonding is enabled.')
    280         if (self._set_loopback('phyint', 'enable') > 0 and
    281             self._set_loopback('mac', 'enable') > 0):
    282             raise error.TestError('Unable to enable loopback')
    283         # Add a 1 second wait for drivers which do not have
    284         # a synchronous loopback enable
    285         # TODO (msb); Remove this wait once the drivers are fixed
    286         if self.get_driver() in ['tg3', 'bnx2x']:
    287             time.sleep(1)
    288         self.wait_for_carrier(timeout=30)
    289 
    290 
    291     def disable_loopback(self):
    292         # Try mac loopback first then phy loopback
    293         # If both fail, raise an error
    294         if (self._set_loopback('phyint', 'disable') > 0 and
    295             self._set_loopback('mac', 'disable') > 0):
    296             raise error.TestError('Unable to disable loopback')
    297 
    298 
    299     def is_loopback_enabled(self):
    300         # Don't try ethtool -l on a bonded host
    301         if bond().is_enabled():
    302             return False
    303         output = utils.system_output('%s -l %s' % (self.ethtool, self._name))
    304         if output:
    305             return 'enabled' in output
    306         return False
    307 
    308 
    309     def enable_promisc(self):
    310         utils.system('ifconfig %s promisc' % self._name)
    311 
    312 
    313     def disable_promisc(self):
    314         utils.system('ifconfig %s -promisc' % self._name)
    315 
    316 
    317     def get_hwaddr(self):
    318         f = open('/sys/class/net/%s/address' % self._name)
    319         hwaddr = f.read().strip()
    320         f.close()
    321         return hwaddr
    322 
    323 
    324     def set_hwaddr(self, hwaddr):
    325         utils.system('ifconfig %s hw ether %s' % (self._name, hwaddr))
    326 
    327 
    328     def add_maddr(self, maddr):
    329         utils.system('ip maddr add %s dev %s' % (maddr, self._name))
    330 
    331 
    332     def del_maddr(self, maddr):
    333         utils.system('ip maddr del %s dev %s' % (maddr, self._name))
    334 
    335 
    336     def get_ipaddr(self):
    337         ipaddr = "0.0.0.0"
    338         output = utils.system_output('ifconfig %s' % self._name)
    339         if output:
    340             match = re.search("inet addr:([\d\.]+)", output)
    341             if match:
    342                 ipaddr = match.group(1)
    343         return ipaddr
    344 
    345 
    346     def set_ipaddr(self, ipaddr):
    347         utils.system('ifconfig %s %s' % (self._name, ipaddr))
    348 
    349 
    350     def is_down(self):
    351         output = utils.system_output('ifconfig %s' % self._name)
    352         if output:
    353             return 'UP' not in output
    354         return False
    355 
    356     def up(self):
    357         utils.system('ifconfig %s up' % self._name)
    358 
    359 
    360     def down(self):
    361         utils.system('ifconfig %s down' % self._name)
    362 
    363 
    364     def wait_for_carrier(self, timeout=60):
    365         while timeout and self.get_carrier() != '1':
    366             timeout -= 1
    367             time.sleep(1)
    368         if timeout == 0:
    369             raise error.TestError('Timed out waiting for carrier.')
    370 
    371 
    372     def send(self, buf):
    373         self._socket.send(buf)
    374 
    375 
    376     def recv(self, len):
    377         return self._socket.recv(len)
    378 
    379 
    380     def flush(self):
    381         self._socket.close()
    382         self._socket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
    383         self._socket.settimeout(TIMEOUT)
    384         self._socket.bind((self._name, raw_socket.ETH_P_ALL))
    385 
    386 
    387 def netif(name):
    388     try:
    389         from autotest_lib.client.bin.net import site_net_utils
    390         return site_net_utils.network_interface(name)
    391     except:
    392         return network_interface(name)
    393 
    394 
    395 class bonding(object):
    396     """This class implements bonding interface abstraction."""
    397 
    398     NO_MODE = 0
    399     AB_MODE = 1
    400     AD_MODE = 2
    401 
    402     def is_enabled(self):
    403         raise error.TestError('Undefined')
    404 
    405 
    406     def is_bondable(self):
    407         raise error.TestError('Undefined')
    408 
    409 
    410     def enable(self):
    411         raise error.TestError('Undefined')
    412 
    413 
    414     def disable(self):
    415         raise error.TestError('Undefined')
    416 
    417 
    418     def get_mii_status(self):
    419         return {}
    420 
    421 
    422     def get_mode(self):
    423         return bonding.NO_MODE
    424 
    425 
    426     def wait_for_state_change(self):
    427         """Wait for bonding state change.
    428 
    429         Wait up to 90 seconds to successfully ping the gateway.
    430         This is to know when LACP state change has converged.
    431         (0 seconds is 3x lacp timeout, use by protocol)
    432         """
    433 
    434         netif('eth0').wait_for_carrier(timeout=60)
    435         wait_time = 0
    436         while wait_time < 100:
    437             time.sleep(10)
    438             if not utils.ping_default_gateway():
    439                 return True
    440             wait_time += 10
    441         return False
    442 
    443 
    444     def get_active_interfaces(self):
    445         return []
    446 
    447 
    448     def get_slave_interfaces(self):
    449         return []
    450 
    451 
    452 def bond():
    453     try:
    454         from autotest_lib.client.bin.net import site_net_utils
    455         return site_net_utils.bonding()
    456     except:
    457         return bonding()
    458 
    459 
    460 class raw_socket(object):
    461     """This class implements an raw socket abstraction."""
    462     ETH_P_ALL = 0x0003 # Use for binding a RAW Socket to all protocols
    463     SOCKET_TIMEOUT = 1
    464     def __init__(self, iface_name):
    465         """Initialize an interface for use.
    466 
    467         Args:
    468           iface_name: 'eth0'  interface name ('eth0, eth1,...')
    469         """
    470         self._name = iface_name
    471         self._socket = None
    472         self._socket_timeout = raw_socket.SOCKET_TIMEOUT
    473         socket.setdefaulttimeout(self._socket_timeout)
    474         if self._name is None:
    475             raise error.TestError('Invalid interface name')
    476 
    477 
    478     def socket(self):
    479         return self._socket
    480 
    481 
    482     def socket_timeout(self):
    483         """Get the timeout use by recv_from"""
    484         return self._socket_timeout
    485 
    486 
    487     def set_socket_timeout(self, timeout):
    488         """Set the timeout use by recv_from.
    489 
    490         Args:
    491           timeout: time in seconds
    492         """
    493         self._socket_timeout = timeout
    494 
    495     def open(self, protocol=None):
    496         """Opens the raw socket to send and receive.
    497 
    498         Args:
    499           protocol : short in host byte order. None if ALL
    500         """
    501         if self._socket is not None:
    502             raise error.TestError('Raw socket already open')
    503 
    504         if protocol is None:
    505             self._socket = socket.socket(socket.PF_PACKET,
    506                                          socket.SOCK_RAW)
    507 
    508             self._socket.bind((self._name, self.ETH_P_ALL))
    509         else:
    510             self._socket = socket.socket(socket.PF_PACKET,
    511                                          socket.SOCK_RAW,
    512                                          socket.htons(protocol))
    513             self._socket.bind((self._name, self.ETH_P_ALL))
    514 
    515         self._socket.settimeout(1) # always running with 1 second timeout
    516 
    517     def close(self):
    518         """ Close the raw socket"""
    519         if self._socket is not None:
    520             self._socket.close()
    521             self._socket = None
    522         else:
    523             raise error.TestError('Raw socket not open')
    524 
    525 
    526     def recv(self, timeout):
    527         """Synchroneous receive.
    528 
    529         Receives one packet from the interface and returns its content
    530         in a string. Wait up to timeout for the packet if timeout is
    531         not 0. This function filters out all the packets that are
    532         less than the minimum ethernet packet size (60+crc).
    533 
    534         Args:
    535           timeout: max time in seconds to wait for the read to complete.
    536                    '0', wait for ever until a valid packet is received
    537 
    538         Returns:
    539           packet:    None no packet was received
    540                      a binary string containing the received packet.
    541           time_left: amount of time left in timeout
    542         """
    543         if self._socket is None:
    544             raise error.TestError('Raw socket not open')
    545 
    546         time_left = timeout
    547         packet = None
    548         while time_left or (timeout == 0):
    549             try:
    550                 packet = self._socket.recv(ethernet.ETH_PACKET_MAX_SIZE)
    551                 if len(packet) >= (ethernet.ETH_PACKET_MIN_SIZE-4):
    552                     break
    553                 packet = None
    554                 if timeout and time_left:
    555                     time_left -= raw_socket.SOCKET_TIMEOUT
    556             except socket.timeout:
    557                 packet = None
    558                 if timeout and time_left:
    559                     time_left -= raw_socket.SOCKET_TIMEOUT
    560 
    561         return packet, time_left
    562 
    563 
    564     def send(self, packet):
    565         """Send an ethernet packet."""
    566         if self._socket is None:
    567             raise error.TestError('Raw socket not open')
    568 
    569         self._socket.send(packet)
    570 
    571 
    572     def send_to(self, dst_mac, src_mac, protocol, payload):
    573         """Send an ethernet frame.
    574 
    575         Send an ethernet frame, formating the header.
    576 
    577         Args:
    578           dst_mac: 'byte string'
    579           src_mac: 'byte string'
    580           protocol: short in host byte order
    581           payload: 'byte string'
    582         """
    583         if self._socket is None:
    584             raise error.TestError('Raw socket not open')
    585         try:
    586             packet = ethernet.pack(dst_mac, src_mac, protocol, payload)
    587         except:
    588             raise error.TestError('Invalid Packet')
    589         self.send(packet)
    590 
    591 
    592     def recv_from(self, dst_mac, src_mac, protocol):
    593         """Receive an ethernet frame that matches the dst, src and proto.
    594 
    595         Filters all received packet to find a matching one, then unpack
    596         it and present it to the caller as a frame.
    597 
    598         Waits up to self._socket_timeout for a matching frame before
    599         returning.
    600 
    601         Args:
    602           dst_mac: 'byte string'. None do not use in filter.
    603           src_mac: 'byte string'. None do not use in filter.
    604           protocol: short in host byte order. None do not use in filter.
    605 
    606         Returns:
    607           ethernet frame: { 'dst' : byte string,
    608                             'src' : byte string,
    609                             'proto' : short in host byte order,
    610                             'payload' : byte string
    611                           }
    612         """
    613         start_time = time.clock()
    614         timeout = self._socket_timeout
    615         while 1:
    616             frame = None
    617             packet, timeout = self.recv(timeout)
    618             if packet is not None:
    619                 frame = ethernet.unpack(packet)
    620                 if ((src_mac is None or frame['src'] == src_mac) and
    621                     (dst_mac is None or frame['dst'] == dst_mac) and
    622                     (protocol is None or frame['proto'] == protocol)):
    623                     break;
    624                 elif (timeout == 0 or
    625                       time.clock() - start_time > float(self._socket_timeout)):
    626                     frame = None
    627                     break
    628             else:
    629                 if (timeout == 0 or
    630                     time.clock() - start_time > float(self._socket_timeout)):
    631                     frame = None
    632                     break
    633                 continue
    634 
    635         return frame
    636 
    637 
    638 class ethernet(object):
    639     """Provide ethernet packet manipulation methods."""
    640     HDR_LEN = 14     # frame header length
    641     CHECKSUM_LEN = 4 # frame checksum length
    642 
    643     # Ethernet payload types - http://standards.ieee.org/regauth/ethertype
    644     ETH_TYPE_IP        = 0x0800 # IP protocol
    645     ETH_TYPE_ARP       = 0x0806 # address resolution protocol
    646     ETH_TYPE_CDP       = 0x2000 # Cisco Discovery Protocol
    647     ETH_TYPE_8021Q     = 0x8100 # IEEE 802.1Q VLAN tagging
    648     ETH_TYPE_IP6       = 0x86DD # IPv6 protocol
    649     ETH_TYPE_LOOPBACK  = 0x9000 # used to test interfaces
    650     ETH_TYPE_LLDP      = 0x88CC # LLDP frame type
    651 
    652     ETH_PACKET_MAX_SIZE = 1518  # maximum ethernet frane size
    653     ETH_PACKET_MIN_SIZE = 64    # minimum ethernet frane size
    654 
    655     ETH_LLDP_DST_MAC = '01:80:C2:00:00:0E' # LLDP destination mac
    656 
    657     FRAME_KEY_DST_MAC = 'dst' # frame destination mac address
    658     FRAME_KEY_SRC_MAC = 'src' # frame source mac address
    659     FRAME_KEY_PROTO = 'proto' # frame protocol
    660     FRAME_KEY_PAYLOAD = 'payload' # frame payload
    661 
    662 
    663     def __init__(self):
    664         pass;
    665 
    666 
    667     @staticmethod
    668     def mac_string_to_binary(hwaddr):
    669         """Converts a MAC address text string to byte string.
    670 
    671         Converts a MAC text string from a text string 'aa:aa:aa:aa:aa:aa'
    672         to a byte string 'xxxxxxxxxxxx'
    673 
    674         Args:
    675           hwaddr: a text string containing the MAC address to convert.
    676 
    677         Returns:
    678           A byte string.
    679         """
    680         val = ''.join([chr(b) for b in [int(c, 16) \
    681                                         for c in hwaddr.split(':',6)]])
    682         return val
    683 
    684 
    685     @staticmethod
    686     def mac_binary_to_string(hwaddr):
    687         """Converts a MAC address byte string to text string.
    688 
    689         Converts a MAC byte string 'xxxxxxxxxxxx' to a text string
    690         'aa:aa:aa:aa:aa:aa'
    691 
    692         Args:
    693           hwaddr: a byte string containing the MAC address to convert.
    694 
    695         Returns:
    696          A text string.
    697         """
    698         return "%02x:%02x:%02x:%02x:%02x:%02x" % tuple(map(ord,hwaddr))
    699 
    700 
    701     @staticmethod
    702     def pack(dst, src, protocol, payload):
    703         """Pack a frame in a byte string.
    704 
    705         Args:
    706           dst: destination mac in byte string format
    707           src: src mac address in byte string format
    708           protocol: short in network byte order
    709           payload: byte string payload data
    710 
    711         Returns:
    712           An ethernet frame with header and payload in a byte string.
    713         """
    714         # numbers are converted to network byte order (!)
    715         frame = struct.pack("!6s6sH", dst, src, protocol) + payload
    716         return frame
    717 
    718 
    719     @staticmethod
    720     def unpack(raw_frame):
    721         """Unpack a raw ethernet frame.
    722 
    723         Returns:
    724           None on error
    725             { 'dst' : byte string,
    726               'src' : byte string,
    727               'proto' : short in host byte order,
    728               'payload' : byte string
    729             }
    730         """
    731         packet_len = len(raw_frame)
    732         if packet_len < ethernet.HDR_LEN:
    733             return None
    734 
    735         payload_len = packet_len - ethernet.HDR_LEN
    736         frame = {}
    737         frame[ethernet.FRAME_KEY_DST_MAC], \
    738         frame[ethernet.FRAME_KEY_SRC_MAC], \
    739         frame[ethernet.FRAME_KEY_PROTO] = \
    740             struct.unpack("!6s6sH", raw_frame[:ethernet.HDR_LEN])
    741         frame[ethernet.FRAME_KEY_PAYLOAD] = \
    742             raw_frame[ethernet.HDR_LEN:ethernet.HDR_LEN+payload_len]
    743         return frame
    744 
    745 
    746 def ethernet_packet():
    747     try:
    748         from autotest_lib.client.bin.net import site_net_utils
    749         return site_net_utils.ethernet()
    750     except:
    751         return ethernet()
    752