
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
3
\me.                 @   sZ  d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZ e j	e
ZdZdZdZdZdZdZd	Zd
ZdZdZdZdZdZdZejeZejeZee ZdZdZdZ dZ!d Z"dZ#dZ$dZ%dZ&dZ'dZ(eddddgZ)edddgZ*eddddddgZ+G dd  d e,Z-d!d" Z.d#d$ Z/d3d%d&Z0d'd( Z1d)d* Z2d+d, Z3d-d. Z4d/d0 Z5d1d2 Z6dS )4    N)
namedtuple)util                     i      <   ZIHHIIZBHiII         RTAAttrlengthrta_typedataInterfaceOperstateifname	operstateNetlinkHeadertypeflagsseqpidc               @   s   e Zd ZdZdS )NetlinkCreateSocketErrorz5Raised if netlink socket fails during create or bind.N)__name__
__module____qualname____doc__ r!   r!   /usr/lib/python3.6/netlink.pyr   9   s   r   c              C   sz   y4t j t jt jt j} | jtj tf | jd W n6 t j	k
rj } zd| }t
||W Y dd}~X nX tjd | S )au  Creates netlink socket and bind on netlink group to catch interface
    down/up events. The socket will bound only on RTMGRP_LINK (which only
    includes RTM_NEWLINK/RTM_DELLINK/RTM_GETLINK events). The socket is set to
    non-blocking mode since we're only receiving messages.

    :returns: netlink socket in non-blocking mode
    :raises: NetlinkCreateSocketError
    r   z*Exception during netlink socket create: %sNzCreated netlink socket)socketZ
AF_NETLINKZSOCK_RAWZNETLINK_ROUTEZbindosgetpidRTMGRP_LINKZsetblockingerrorr   LOGdebug)netlink_socketemsgr!   r!   r"   create_bound_netlink_socket=   s    	
r-   c             C   s:   t jt| dt \}}}}}tjd| t|||||S )a  Gets netlink message type and length

    :param: data read from netlink socket
    :returns: netlink message type
    :raises: AssertionError if data is None or data is not >= NLMSGHDR_SIZE
    struct nlmsghdr {
               __u32 nlmsg_len;    /* Length of message including header */
               __u16 nlmsg_type;   /* Type of message content */
               __u16 nlmsg_flags;  /* Additional flags */
               __u32 nlmsg_seq;    /* Sequence number */
               __u32 nlmsg_pid;    /* Sender port ID */
    };
    NzGot netlink msg of type %d)structunpackNLMSGHDR_FMTMSG_TYPE_OFFSETr(   r)   r   )r   Zmsg_lenZmsg_typer   r   r   r!   r!   r"   get_netlink_msg_headerS   s    r2   c             C   sN   t j | gg g |\}}}| |kr$dS tjd | jt}|dkrJtjd |S )a  Select and read from the netlink socket if ready.

    :param: netlink_socket: specify which socket object to read from
    :param: timeout: specify a timeout value (integer) to wait while reading,
            if none, it will block indefinitely until socket ready for read
    :returns: string of data read (max length = <MAX_SIZE>) from socket,
              if no data read, returns None
    :raises: AssertionError if netlink_socket is None
    Nznetlink socket ready for readz,Reading from Netlink socket returned no data)selectr(   r)   ZrecvMAX_SIZEr'   )r*   ZtimeoutZread_set_r   r!   r!   r"   read_netlink_socketl   s    


r6   c             C   st   d }}d}y0t jd| |dd }t jd| |d dd }W n t jk
rR   dS X | |t ||  }t|||S )a(  Unpack a single rta attribute.

    :param: data: string of data read from netlink socket
    :param: offset: starting offset of RTA Attribute
    :return: RTAAttr object with length, type and data. On error, return None.
    :raises: AssertionError if data is None or offset is not integer.
    r   NH)offsetr   )r.   unpack_fromr'   RTA_DATA_START_OFFSETr   )r   r8   r   r   Z	attr_datar!   r!   r"   unpack_rta_attr   s    r;   c             C   s   d }}t }x|t| krt| |}| s4|jdkr6P t|jt  t }||j| 7 }|jtkrlt|j}q|jt	krt
j|jd}|jd}qW | s|dkrdS tjd|| t||S )a  Reads Interface name and operational state from RTA Data.

    :param: data: string of data read from netlink socket
    :returns: InterfaceOperstate object containing if_name and oper_state.
              None if data does not contain valid IFLA_OPERSTATE and
              IFLA_IFNAME messages.
    :raises: AssertionError if data is None or length of data is
             smaller than RTATTR_START_OFFSET.
    Nr   zutf-8 z!rta attrs: ifname %s operstate %d)RTATTR_START_OFFSETlenr;   r   PAD_ALIGNMENTr   IFLA_OPERSTATEordr   IFLA_IFNAMEr   Zdecode_binarystripr(   r)   r   )r   r   r   r8   attrpadlenZinterface_namer!   r!   r"   read_rta_oper_state   s$    


rF   c                s6   t jd d fdd}t| dtgttg| S )zBlock until a single nic is attached.

    :param: netlink_socket: netlink_socket to receive events
    :param: existing_nics: List of existing nics so that we can skip them.
    :raises: AssertionError if netlink_socket is none.
    z!Preparing to wait for nic attach.Nc                s   |  krdS | dS )NTFr!   )inamecarrierprevCarrier)existing_nicsr   r!   r"   should_continue_cb   s    z5wait_for_nic_attach_event.<locals>.should_continue_cb)r(   r)   read_netlink_messagesRTM_NEWLINKOPER_UP	OPER_DOWN)r*   rJ   rK   r!   )rJ   r   r"   wait_for_nic_attach_event   s    
	rP   c                s2   t jd d  fdd}t| dtgtg|  S )zBlock until a single nic is detached and its operational state is down.

    :param: netlink_socket: netlink_socket to receive events.
    z!Preparing to wait for nic detach.Nc                s   |  dS )NFr!   )rG   rH   rI   )r   r!   r"   rK      s    z5wait_for_nic_detach_event.<locals>.should_continue_cb)r(   r)   rL   RTM_DELLINKrO   )r*   rK   r!   )r   r"   wait_for_nic_detach_event   s    
rR   c                s2    fdd}t jd t|  ttgttg| dS )a  Block until media disconnect and connect has happened on an interface.
    Listens on netlink socket to receive netlink events and when the carrier
    changes from 0 to 1, it considers event has happened and
    return from this function

    :param: netlink_socket: netlink_socket to receive events
    :param: ifname: Interface name to lookout for netlink events
    :raises: AssertionError if netlink_socket is None or ifname is None.
    c                s(   |t ko|tk}|r$tjd  dS dS )NzMedia switch happened on %s.FT)rO   rN   r(   r)   )rG   rH   rI   ZisVnetSwitch)r   r!   r"   rK      s
    z=wait_for_media_disconnect_connect.<locals>.should_continue_cbz1Wait for media disconnect and reconnect to happenN)r(   r)   rL   rM   rQ   rN   rO   )r*   r   rK   r!   )r   r"   !wait_for_media_disconnect_connect   s    
rS   c             C   s  | dkrt dt }t}t}xZt| t}|dkr6q"tjdt| ||7 }tjdt| d}	t|}
 x|	|
k rj||	d }t|tk rtjd P t	|}t||j
k rtjd P |j
t d td  @ }|	| }	tjd	|	 |j|krqnt|}|dkrtjd
| qn|dk	r>|j|kr>tjd|j| qn|j|krLqn|}|j}||j||sndS qnW ||	d }q"W dS )a  Reads from the netlink socket until the condition specified by
    the continuation callback is met.

    :param: netlink_socket: netlink_socket to receive events.
    :param: ifname_filter: if not None, will only listen for this interface.
    :param: rtm_types: Type of netlink events to listen for.
    :param: operstates: Operational states to listen.
    :param: should_continue_callback: Specifies when to stop listening.
    NzNetlink socket is nonezread %d bytes from socketzLength of data after concat %dr   z#Data is smaller than netlink headerz*Partial data. Smaller than netlink messager   z"offset to next netlink message: %dz!Failed to read rta attributes: %sz6Ignored netlink event on interface %s. Waiting for %s.)RuntimeErrorbytesrN   r6   SELECT_TIMEOUTr(   r)   r>   NLMSGHDR_SIZEr2   r   r?   r   rF   r   r   )r*   Zifname_filterZ	rtm_typesZ
operstatesZshould_continue_callbackr   rH   rI   Z	recv_datar8   ZdatalenZnl_msgZnlheaderrE   Zinterface_stater!   r!   r"   rL     s`    





rL   )N)7Zloggingr$   r3   r#   r.   collectionsr   Z	cloudinitr   Z	getLoggerr   r(   r&   Z
NLMSG_NOOPZNLMSG_ERRORZ
NLMSG_DONErM   rQ   ZRTM_GETLINKZRTM_SETLINKr4   ZRTA_DATA_OFFSETr1   rV   r0   ZIFINFOMSG_FMTcalcsizerW   ZIFINFOMSG_SIZEr=   r:   r?   rB   r@   ZOPER_UNKNOWNZOPER_NOTPRESENTrO   ZOPER_LOWERLAYERDOWNZOPER_TESTINGZOPER_DORMANTrN   r   r   r   rT   r   r-   r2   r6   r;   rF   rP   rR   rS   rL   r!   r!   r!   r"   <module>   sb   



% 