
    x[h.                        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 ej,                  e      Z ej,                  e      Zeez   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g d      Z% edddg      Z& edg d      Z' G d de(      Z)d Z*d Z+d$dZ,d Z-d Z.d  Z/d! Z0d" Z1d# Z2y)%    N)
namedtuple)util               i  <   IHHIIBHiII               RTAAttr)lengthrta_typedataInterfaceOperstateifname	operstateNetlinkHeader)r   typeflagsseqpidc                       e Zd ZdZy)NetlinkCreateSocketErrorz5Raised if netlink socket fails during create or bind.N)__name__
__module____qualname____doc__     C/usr/lib/python3/dist-packages/cloudinit/sources/helpers/netlink.pyr   r   5   s    ?r%   r   c                     	 t        j                   t         j                  t         j                  t         j                        } | j	                  t        j                         t        f       | j                  d       t        j                  d       | S # t         j                  $ r}d|z  }t        |      |d}~ww xY w)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)socket
AF_NETLINKSOCK_RAWNETLINK_ROUTEbindosgetpidRTMGRP_LINKsetblockingerrorr   LOGdebug)netlink_socketemsgs      r&   create_bound_netlink_socketr7   9   s    3v0D0D
 	RYY[+67""1% II&'	 << 3:Q>&s+23s   A;B B='B88B=c                     | J d       t        |       t        k\  sJ d       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 */
    };
    Ndata is nonez+data is smaller than netlink message headerzGot netlink msg of type %d)	lenNLMSGHDR_SIZEstructunpackNLMSGHDR_FMTMSG_TYPE_OFFSETr2   r3   r   )r   msg_lenmsg_typer   r   r   s         r&   get_netlink_msg_headerrB   O   s{     +^+D	]"545")/d+O,*&GXuc3 II*H5(E3<<r%   c                     | J d       t        j                   | gg g |      \  }}}| |vryt        j                  d       | j                  t              }|t        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
    Nnetlink socket is noneznetlink socket ready for readz,Reading from Netlink socket returned no data)selectr2   r3   recvMAX_SIZEr1   )r4   timeoutread_set_r   s        r&   read_netlink_socketrK   h   st     %?'??%]]N#3RWENHa X%II-.x(D|		@AKr%   c                 L   | J d       t        |t              sJ d       |t        k\  sJ d       dx}}d}	 t        j                  d| |      d   }t        j                  d| |dz         d   }| |t        z   ||z    }t        |||      S # t        j
                  $ r Y yw xY w)	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.
    Nr9   zoffset is not integerz'rta offset is less than expected lengthr   H)offsetr   )
isinstanceintRTATTR_START_OFFSETr<   unpack_fromr1   RTA_DATA_START_OFFSETr   )r   rN   r   r   	attr_datas        r&   unpack_rta_attrrU      s     +^+fc";$;;"%%101%FXI##Cf=a@%%c4
CAF
 V33fvoFI68Y// << s   9B B#"B#c                 `   | J d       t        |       t        kD  sJ d       dx}}t        }|t        |       k  rt        | |      }|r|j                  dk(  rnt        |j                  t        z  z
  t        z  }||j                  |z   z  }|j
                  t        k(  rt        |j                        }nD|j
                  t        k(  r1t        j                  |j                  d      }|j                  d      }|t        |       k  r|r|y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.
    Nr9   z2length of data is smaller than RTATTR_START_OFFSETr   zutf-8 z!rta attrs: ifname %s operstate %d)r:   rQ   rU   r   PAD_ALIGNMENTr   IFLA_OPERSTATEordr   IFLA_IFNAMEr   decode_binarystripr2   r3   r   )r   r   r   rN   attrpadleninterface_names          r&   read_rta_oper_statera      s     +^+D	''<;<'FY F
CI
tV,t{{a' T[[=89 	$++&&==N*DIII]]k)!//		7CN#))$/F CI
 Y&II169Efi00r%   c                     t         j                  d       df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                     | v ry| y)NTFr$   )inamecarrierprevCarrierexisting_nicsr   s      r&   should_continue_cbz5wait_for_nic_attach_event.<locals>.should_continue_cb   s    M!r%   )r2   r3   read_netlink_messagesRTM_NEWLINKOPER_UP	OPER_DOWN)r4   rg   rh   r   s    ` @r&   wait_for_nic_attach_eventrm      sC     II12F 		) Mr%   c                 r    t         j                  d       df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                 
    | y)NFr$   )rd   re   rf   r   s      r&   rh   z5wait_for_nic_detach_event.<locals>.should_continue_cb   s    r%   )r2   r3   ri   RTM_DELLINKrl   )r4   rh   r   s     @r&   wait_for_nic_detach_eventrq      s=    
 II12F
 {mi[:L Mr%   c                     | J d       J d       t              dkD  sJ d       fd}t        j                  d       t        | t        t
        gt        t        g|       y)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.
    NrD   zinterface name is noner   zinterface name cannot be emptyc                 `    |t         k(  xr	 |t        k(  }|rt        j                  d       yy)NzMedia switch happened on %s.FT)rl   rk   r2   r3   )rd   re   rf   isVnetSwitchr   s       r&   rh   z=wait_for_media_disconnect_connect.<locals>.should_continue_cb   s/    #y0Jw'7III4f=r%   z1Wait for media disconnect and reconnect to happen)r:   r2   r3   ri   rj   rp   rk   rl   )r4   r   rh   s    ` r&   !wait_for_media_disconnect_connectru      st     %?'??%777v;?<<<? IIAB	k"	)r%   c                    | t        d      t               }t        }t        }	 t        | t              }|t
        j                  dt        |             ||z  }t
        j                  dt        |             d}	t        |      }
|	|
k  rD||	d }t        |      t        k  rt
        j                  d       nt        |      }t        |      |j                  k  rt
        j                  d       n|j                  t        z   dz
  t        dz
   z  }|	|z   }	t
        j                  d	|	       |j                  |vrt        |      }|t
        j                  d
|       |2|j                  |k7  r#t
        j                  d|j                  |       |j                  |vr |}|j                  } ||j                  ||      sy|	|
k  rD||	d })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bytesrk   rK   SELECT_TIMEOUTr2   r3   r:   r;   rB   r   rX   r   ra   r   r   )r4   ifname_filter	rtm_types
operstatesshould_continue_callbackr   re   rf   	recv_datarN   datalennl_msgnlheaderr_   interface_states                  r&   ri   ri     s     3447DGK
'G			-s9~>			2CI>d)w&']F6{]*		?@-f5H6{X__,		FGoo59!> F f_FII:FC}}I-1&9O&		=O)#**m;		L#**!
 ((
:!K%//G+&& M wN FG}a r%   )N)3loggingr-   rE   r(   r<   collectionsr   	cloudinitr   	getLoggerr    r2   r/   rj   rp   RTM_GETLINKRTM_SETLINKrG   r?   ry   r>   IFINFOMSG_FMTcalcsizer;   IFINFOMSG_SIZErQ   rS   rX   r[   rY   OPER_UNKNOWNOPER_NOTPRESENTrl   OPER_LOWERLAYERDOWNOPER_TESTINGOPER_DORMANTrk   r   r   r   rw   r   r7   rB   rK   rU   ra   rm   rq   ru   ri   r$   r%   r&   <module>r      s6  
  	    " g! - /#n4   	 

Y >
? 4x6MN >
@| @,=2.04"1J:&@Er%   