
    *CeJ                        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 ddl	m
Z
 d dlZd dlZ G d de      Zd	ej                  e   fd
Zd	ej                  e   dej                  e   fdZd Zd Zd Zd Zd ZddZddZy)    N)defaultdict   )utils   )ConfigurationErrorc                      e Zd ZdZdefdZedefd       Zedefd       ZdedefdZ	edefd	       Z
edefd
       Zedefd       Zedefd       Zedefd       Zedefd       ZdededefdZdefdZdefdZy)	PCIDevicez.Helper class for interaction with a PCI devicepci_addrc                     || _         y)znInitialise a new PCI device handler
        :param pci_addr: PCI address of device
        :type: str
        Nr
   )selfr
   s     +/usr/share/netplan/netplan_cli/cli/sriov.py__init__zPCIDevice.__init__(   s    
 !    returnc                      y)zusysfs path (can be overridden for testing)
        :return: full path to /sys filesystem
        :rtype: str
        z/sys r   s    r   syszPCIDevice.sys/   s     r   c                 l    t         j                  j                  | j                  d| j                        S )zq/sys path for PCI device
        :return: full path to PCI device in /sys filesystem
        :rtype: str
        zbus/pci/devices)ospathjoinr   r
   r   s    r   r   zPCIDevice.path7   s$     ww||DHH&7GGr   subpathc                 V    t         j                  j                  | j                  |      S )z/sys subpath helper for PCI device
        :param subpath: subpath to construct path for
        :type: str
        :return: self.path + subpath
        :rtype: str
        )r   r   r   )r   r   s     r   r   zPCIDevice.subpath?   s     ww||DIIw//r   c                     d}t         j                  j                  | j                  d            rAt         j                  j	                  t        j
                  | j                  d                  }|S )zjKernel driver for PCI device
        :return: kernel driver in use for device
        :rtype: str
         driver)r   r   existsr   basenamereadlink)r   r   s     r   r   zPCIDevice.driverH   sM     77>>$,,x01WW%%bkk$,,x2H&IJFr   c                 ^    t         j                  j                  | j                  d            S )zDetermine if device is bound to a kernel driver
        :return: whether device is bound to a kernel driver
        :rtype: bool
        r   r   r   r   r   r   s    r   boundzPCIDevice.boundS         ww~~dll8455r   c                 ^    t         j                  j                  | j                  d            S )zwDetermine if device is a SR-IOV Physical Function
        :return: whether device is a PF
        :rtype: bool
        sriov_numvfsr#   r   s    r   is_pfzPCIDevice.is_pf[   s      ww~~dll>:;;r   c                 ^    t         j                  j                  | j                  d            S )zvDetermine if device is a SR-IOV Virtual Function
        :return: whether device is a VF
        :rtype: bool
        physfnr#   r   s    r   is_vfzPCIDevice.is_vfc   r%   r   c                     g }d}	 	 |j                  t        j                  j                  t        j                  | j                  dj                  |                               |dz  }f# t        $ r Y |S w xY w)zList Virtual Function addresses associated with a Physical Function
        :return: List of PCI addresses of Virtual Functions
        :rtype: list[str]
        r   zvirtfn{}r   )appendr   r   r    r!   r   formatFileNotFoundError)r   vf_addrsis      r   r0   zPCIDevice.vf_addrsk   s}     GG$$DLL1B1B11E$FG FA  % s   AA, ,	A98A9c                 R    | j                   D cg c]  }t        |       c}S c c}w )zList Virtual Function associated with a Physical Function
        :return: List of PCI devices of Virtual Functions
        :rtype: list[PCIDevice]
        )r0   r	   )r   addrs     r   vfszPCIDevice.vfs   s      -1MM:D	$:::s   $obj_namepropvaluec           	      n    t        j                  dd|ddj                  | j                        ||g       y)zSet devlink options for the PCI device
        :param obj_name: devlink object to set options on
        :type: str
        :param prop: property to set
        :type: str
        :param value: value to set for property
        :type: str
        /sbin/devlinkdevsetzpci/{}N)
subprocess
check_callr.   r
   )r   r5   r6   r7   s       r   devlink_setzPCIDevice.devlink_set   s9     	.
	
r   c                 8   d| j                    }	 t        j                  ddddd|gt        j                        }t        j                  |      }|j                  di       j                  |i       j                  d	d      S # t        j                  $ r Y yw xY w)
zQuery eswitch mode via devlink for the PCI device
        :return: the eswitch mode or '__undetermined' if it can't be retrieved
        :rtype: str
        zpci/r9   z-jr:   eswitchshow)stderr__undeterminedmode)r
   r<   check_outputDEVNULLCalledProcessErrorjsonloadsget)r   pcioutputjson_outputs       r   devlink_eswitch_modezPCIDevice.devlink_eswitch_mode   s    
 T]]O$	$,,# "))
F jj( ub)--c26::6CSTT ,, 	$#	$s   +B BBc                     | j                   S )zbString represenation of object
        :return: PCI address of string
        :rtype: str
        r   r   s    r   __str__zPCIDevice.__str__   s    
 }}r   N)__name__
__module____qualname____doc__strr   propertyr   r   r   r   boolr$   r(   r+   listr0   r4   r>   rN   rP   r   r   r   r	   r	   %   s3   8! ! S   Hc H H0s 0s 0    6t 6 6 <t < < 6t 6 6 $  & ;T ; ;
C 
s 
3 
*Uc U: r   r	   r4   c                     g }| D ]_  }|j                   rt        dj                  |      d      5 }|j                  |j                         |j                  |       ddd       a |S # 1 sw Y   mxY w)zBind unbound VFs to driver.z/sys/bus/pci/drivers/{}/bindwtNr$   openr.   writer
   r-   )r4   r   	bound_vfsvffs        r   bind_vfsra      su    I %xx4;;FCTJ %a$  $% %%
 % %   -A))A2	r   c                     g }| D ]_  }|j                   st        dj                  |      d      5 }|j                  |j                         |j                  |       ddd       a |S # 1 sw Y   mxY w)zUnbind bound VFs from driver.z/sys/bus/pci/drivers/{}/unbindrZ   Nr[   )r4   r   unbound_vfsr_   r`   s        r   
unbind_vfsre      sv    K '886==fEtL 'PQ$""2&' ''
 ' 'rb   c                 F   ||vr||   }|j                   rr|j                  }|r
|| v r|||<   nc| D ]T  }|j                  |t        j                  |      t        j
                  |            s>||v rt        d|z        |||<   V n	|| v r|||<   |j                  |d       S )N)
iface_nameiface_driver	iface_macz3matched more than one interface for a PF device: %s)
_has_matchset_name_match_interfacer   get_interface_driver_nameget_interface_macaddressr   rJ   )
interfacesnp_statepf_linkpfspf_devrk   	interfaces          r   _get_target_interfaceru      s    c'"HH
2  (G!+ -I!22'0).)H)H)S&+&D&DY&O 3 Q ! #~01fip1pqq#,CL- *$&G777D!!r   c           	         t         j                  j                  d| d      }	 t        |      5 }d}|j	                         D ]E  }|j                         }|j                  d      s%|j                  dd      d   }|c cddd       S  	 ddd       y# 1 sw Y   yxY w# t        $ r}t        d| d	t        |            d}~ww xY w)
z5
    Read PCI slot name for given interface name
    /sys/class/netzdevice/ueventNzPCI_SLOT_NAME==r   r   z!failed parsing PCI slot name for : )r   r   r   r\   	readlinesstrip
startswithsplitIOErrorRuntimeErrorrU   )netdevuevent_pathr`   pci_slot_namelinees         r   _get_pci_slot_namer      s     '',,/IK	Y+ 	)! M )zz|??#34$(JJsA$6q$9M((	) 	))	) 	) 	)  YPSTUPVWXXYsF   B 7B&B>	B B
B BB B 	C(CCc                    |j                   j                         D ]  \  }}|j                  j                  d      r6t	        | ||j                  j                  d      j
                  |      rd||<   	 |j                  }|dk(  rjt	        | |||      }	|	s{|||	<    y# t        j                  $ r}t        t        |            d}~ww xY w)z
    Go through the list of netplan ethernet devices and identify which are
    PFs and VFs, matching the former with actual networking interfaces.
    Count how many VFs each PF will need.
    sriovNr   )	ethernetsitemslinksrJ   ru   id	_vf_countnetplanNetplanExceptionr   rU   )
ro   rp   	vf_countsr4   rr   nidnetdefcountr   pfs
             r   get_vf_count_and_functionsr   	  s      ))//1 "V<<G$)>z8U[UaUaUeUefmUnUqUqsv)wCH	-$$E A:":xcB!IbM" '' 	-$SV,,	-s   3BC
1CC
c                    |dkD  rt        d| d|d      t        j                  j                  d| d      }t        j                  j                  |d      }t        j                  j                  |d      }	 t	        |      5 }t        |j                         j                               }d	d	d	       |kD  rt        d| d|d|d      	 t	        |d      5 }|j                  t        |             d	d	d	       y# 1 sw Y   TxY w# t        $ r}t        d
| dt        |            d	}~wt        $ r t        d| z        w xY w# 1 sw Y   yxY w# t        $ r}d}|j                  dk(  rt        j                  d| z         	 t	        |d      5 }|j                  d       d	d	d	       n# 1 sw Y   nxY wt	        |d      5 }|j                  t        |             d	d	d	       n# 1 sw Y   nxY wd}n# t        $ r}	|	}Y d	}	~	nd	}	~	ww xY w|rt        d|d| dt        |            Y d	}~yd	}~ww xY w)zB
    Allocate the required number of VFs for the selected PF.
       z cannot allocate more VFs for PF z than the SR-IOV maximum: z > 256rw   devicer'   sriov_totalvfsNz"failed parsing sriov_totalvfs for ry   z#invalid sriov_totalvfs value for %sz than supported: z > z (sriov_totalvfs)wT   zLdevice or resource busy while setting sriov_numvfs for %s, trying workaround0Fzfailed setting sriov_numvfs to z for )r   r   r   r   r\   intreadr{   r~   r   rU   
ValueErrorr]   errnologgingwarning)
r   vf_countdevdirnumvfs_pathtotalvfs_pathr`   vf_maxr   baile_inners
             r   set_numvfs_for_pfr      s%    #~ VXZbce 	e WW\\*B9F'',,v~6KGGLL)9:MG-  	+A)*F	+ & ]_aikqrt 	th+s# 	#qGGCM"	#( A	+ 	+ VSQRVTUU G@2EFFG	#( %  h77b=OOjmoop
 +s+ !qGGCL! ! !+s+ +qGGCM*+ + +
    QY[]_bcd_efgg  %hs   :D (D -D E E7E  D	D 	E
D//E
EE E 	H?")H:G>F3*	G>3F<	8G>G/&	G>/G8	4G>;H:>	HH	H:H"H::H?c           	      N   t         j                  j                  d| d      }	 t        t         j                  j                  |d            5 }|j	                         j                         dd }ddd       t        t         j                  j                  |d            5 }|j	                         j                         dd }ddd       dj                  g      }d	}||v ryy# 1 sw Y   wxY w# 1 sw Y   0xY w# t        $ r}t        d| dt        |            d}~ww xY w)
z
    Perform any hardware-specific quirks for the given SR-IOV device to make
    sure all the VF-count changes are applied.
    rw   r   vendorr   Nz,could not determine vendor and device ID of ry   :r   )	r   r   r   r\   r   r{   r~   r   rU   )r   r   r`   	device_id	vendor_idr   combined_idquirk_devicess           r    perform_hardware_specific_quirksr   O  s   
 WW\\*B9F`"'',,vx01 	-Q(,I	-"'',,vx01 	-Q(,I	-
 ((Iy12KMm# 	 $	- 	-	- 	- `SUWZ[\W]^__`sG   )C< "C$.1C< "C0C< $C-)C< 0C95C< <	D$DD$c                    d}t         j                  j                  |d|d      }t         j                  j                  t        j                  |            }t         j                  j                  |d| d      }t        j
                  |      D ]e  }	d|	v st         j                  j                  ||	      }
t         j                  j                  t        j                  |
            }||k(  s`|	dd } n |st        d|d|      	 t        j                  dd	d
d| d|dt        |      g	t        j                  t        j                         y# t        j                  $ r t        d|z        w xY w)z@
    Apply the hardware VLAN filtering for the selected VF.
    Nzsys/class/netr   virtfn   z%could not determine the VF index for z while configuring vlan iplinkr;   r:   r_   vlan)stdoutrB   zJfailed setting SR-IOV VLAN filter for vlan %s (ip link set command failed))r   r   r   r    r!   listdirr   r<   r=   rU   rF   rG   )r   r_   	vlan_namevlan_idprefixvf_index	vf_devdir	vf_dev_id	pf_devdirr`   dev_pathdev_ids               r   apply_vlan_filter_for_vfr   l  sP    HV_b(CI  Y!78IV_b(CIZZ	" q=ww||Iq1HWW%%bkk(&;<F"QR5 SUW`ac 	c	ftVU$b#X%s7|5 &0%7%7%/%7%7	9 (( fX[ddf 	ffs   
AE "E3c           
         | j                          t        j                         }| j                  }t	        t
              }i }i }t        |||||       g }|r6|j                         D ]#  \  }}	t        ||	      s|j                  |       % |r&|D ]  }t        |        t        j                         }|D ]T  }
||
   }|j                  r7|D ]1  }|j                  |      s|
|v r||
   rt        d|
z        |||
<   3 K|
|v sP|
||
<   V |j                         D ]  \  }}||   }|j                  }|dv st        |      }t!        |      }|j#                         }||k7  sH|j$                  sUt'        j(                  dj+                  ||j,                               |j.                  s|j0                  }	 t3        |j.                  |j4                         |j7                  dd|       |rt9        |j.                  |j4                          t;               }|j<                  j                         D ]  \  }}|j>                  s|j@                  jC                  d      }|jD                  }|jC                  |jF                        }
|
s't'        jH                  d|d	|jF                  d
       ~|jC                  |j@                  jC                  d      jF                        }|
|v rt        d|
d|jF                  d|d      tK        ||
||       |jM                  |
        y# |s!t9        |j.                  |j4                         w w xY w)z
    Go through all interfaces, identify which ones are SR-IOV VFs, create
    them and perform all other necessary setup.
    )rg   z3matched more than one interface for a VF device: %s)	switchdevlegacyzFound VFs of {}: {}r@   rD   r   zSR-IOV vlan defined for z
 but link z% is either not a VF or has no matchesr   z
interface z for netplan device z (z$) already has an SR-IOV vlan definedN)'parse	netifacesro   rp   r   r   r   r   r   r-   r   rj   rl   r   _embedded_switch_moder   r	   rN   r(   r   debugr.   r0   r4   _delay_virtual_functions_rebindre   r   r>   ra   r;   vlans_has_sriov_vlan_filterr   rJ   _vlan_idr   r   r   add)config_managerrootdirro   rp   r   r4   rr   vf_count_changedr   r   r_   r   rt   	netdef_idifaceeswitch_moder
   pcidevcurrent_eswitch_mode_systemrebind_delayedfiltered_vlans_setr   r   r   s                           r   apply_sriov_configr     s1   
 %%'J&&H C I C
CHic3 %OO- 	(LB$R2##B'		(  # 	1B,R0	1
 ))+
  "
 ( (	**i*@SySW01fik1kll'CG	( ZB"  IIK D	5)$3322)%0Hx(F*0*E*E*G'::<<MM"7">">vv"WXzz)/)O)OD&vzz6==A"..y&,O#1 (V]] C#D&  ,,. 'f ((<<##F+DooG!B eikokrkrsu
 0334B''(dfhlhohoquvx x %RT7;""2&9'	 $2 (V]] C $2s   <3L//%M)/)rH   r   r   r<   typingcollectionsr   r   r   configmanagerr   r   r   objectr	   Iterablera   re   ru   r   r   r   r   r   r   r   r   r   <module>r      s   &   	   #  .  Y Yx&//), FOOI. 6??9;U "BY"".,^:$fNq'r   