
    f.                        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j4                  e      Z ej4                  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Z0d Z1d  Z2d! Z3d" Z4d# Z5d$ Z6y)&    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    9   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_socketr8   =   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_OFFSETr3   r4   r   )r   msg_lenmsg_typer   r   r   s         r'   get_netlink_msg_headerrC   S   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)selectr3   r4   recvMAX_SIZEr2   )r5   timeoutread_set_r   s        r'   read_netlink_socketrL   l   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.
    Nr:   zoffset is not integerz'rta offset is less than expected lengthr   H)offsetr   )
isinstanceintRTATTR_START_OFFSETr=   unpack_fromr2   RTA_DATA_START_OFFSETr   )r   rO   r   r   	attr_datas        r'   unpack_rta_attrrV      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.
    Nr:   z2length of data is smaller than RTATTR_START_OFFSETr   zutf-8 z!rta attrs: ifname %s operstate %d)r;   rR   rV   r   PAD_ALIGNMENTr   IFLA_OPERSTATEordr   IFLA_IFNAMEr   decode_binarystripr3   r4   r   )r   r   r   rO   attrpadleninterface_names          r'   read_rta_oper_staterb      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&   )r3   r4   read_netlink_messagesRTM_NEWLINKOPER_UP	OPER_DOWN)r5   rh   ri   r   s    ` @r'   wait_for_nic_attach_eventrn      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%   )re   rf   rg   r   s      r'   ri   z5wait_for_nic_detach_event.<locals>.should_continue_cb   s    r&   )r3   r4   rj   RTM_DELLINKrm   )r5   ri   r   s     @r'   wait_for_nic_detach_eventrr      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.
    NrE   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)rm   rl   r3   r4   )re   rf   rg   isVnetSwitchr   s       r'   ri   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;   r3   r4   rj   rk   rq   rl   rm   )r5   r   ri   s    ` r'   !wait_for_media_disconnect_connectrv      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bytesrl   rL   SELECT_TIMEOUTr3   r4   r;   r<   rC   r   rY   r   rb   r   r   )r5   ifname_filter	rtm_types
operstatesshould_continue_callbackr   rf   rg   	recv_datarO   datalennl_msgnlheaderr`   interface_states                  r'   rj   rj     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)7loggingr.   rF   r)   r=   collectionsr   	cloudinitr   	getLoggerr!   r3   r0   
NLMSG_NOOPNLMSG_ERROR
NLMSG_DONErk   rq   RTM_GETLINKRTM_SETLINKrH   RTA_DATA_OFFSETr@   rz   r?   IFINFOMSG_FMTcalcsizer<   IFINFOMSG_SIZErR   rT   rY   r\   rZ   OPER_UNKNOWNOPER_NOTPRESENTrm   OPER_LOWERLAYERDOWNOPER_TESTINGOPER_DORMANTrl   r   r   r   rx   r    r8   rC   rL   rV   rb   rn   rr   rv   rj   r%   r&   r'   <module>r      sJ  
  	    " g! 

- /#n4   	 

Y >
? 4x6MN >
@| @,=2.04"1J:&@Er&   