
    gR                        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mZmZmZ ddl	m
Z
 ddlm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ej&                  dedefdZdej&                  dee   fdZd Zdej2                  deeef   fdZdej2                  deeef   fdZdej2                  dee   fdZd Zd ZddZ ddZ!y)    N)DictListOptionalSet   )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.path4   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.driverE   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.boundP         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_pfX   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_vf`   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   r3   zPCIDevice.vf_addrsh   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]
        )r3   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_callr1   r   )r   r8   r9   r:   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/r<   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.   listr3   r7   rA   rQ   rS   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   r7   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'   openr1   writer   r0   )r7   r!   	bound_vfsvffs        r   bind_vfsrd      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/{}/unbindr]   Nr^   )r7   r!   unbound_vfsrb   rc   s        r   
unbind_vfsrh      sv    K '886==fEtL 'PQ$""2&' ''
 ' 're   netdef	interfacec                 v    | j                  |t        j                  |      t        j                  |            S )N)
iface_nameiface_driver	iface_mac)_match_interfacer   get_interface_driver_nameget_interface_macaddress)ri   rj   s     r   _interface_matchesrr      s9    ""44Y?00; # = =r   c                 l   t        j                         }| j                  rz| j                  }|r||v r|S t	               }|D ]F  }t        | |      st        |      dkD  rt        d| j                  z        |j                  |       H |rt        |      d   S y| j                  |v r| j                  S y)z
    Try to match a netdef with the real system network interface.
    Throws ConfigurationError if there is more than one match.
    r   z3matched more than one interface for a PF device: %sr   N)r   get_interfaces
_has_matchset_namer>   rr   lenr
   idaddr[   )ri   
interfacesrv   matchesrj   s        r   _get_interface_name_for_netdefr|      s    
 "002JJ. O #G ( '	)&)< w<!#,-bekenen-nooI&' G}Q''  99
"99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RuntimeErrorrX   )netdevuevent_pathrc   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np_statec                    i }| j                   j                         D ]  }|j                  j                  d      x}r+t	        | |j
                           x}s;|||j
                  <   K|j                  rt	        |      x}r|||j
                  <   	 |j                  }|dkD  st	        |      x}s|||j
                  <    |S # 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 matching them with actual network interfaces.
    sriovNr   )	ethernetsvalueslinksrM   r|   rx   _embedded_switch_mode	_vf_countnetplanNetplanExceptionr
   rX   )r   pfsri   linkifacecountr   s          r   _get_physical_functionsr     s    
 C$$++- +<<##G,,4,6x7HIIuI$DGG ++:6BB5B%*C		N1(( qy:6BB5B%*C		N'+* J ++ 1(Q001s   CC0C++C0c                     i }| j                   j                         D ](  }	 |j                  }|dkD  st        |      x}s$|||<   * |S # t        j                  $ r}t        t        |            d}~ww xY w)z
    Go through the list of netplan ethernet devices and identify which ones
    have VFs. netdef._vf_count ultimately calls _netplan_state_get_vf_count_for_def
    from libnetplan which return MAX(sriov_explicit_vf_count, number of VF netdefs).
    Nr   )r   r   r   r   r   r
   rX   r|   )r   	vf_countsri   r   r   r   s         r   _get_vf_number_per_pfr   .  s     I$$++- )	-$$E 196v>>u>#(	% )  '' 	-$SV,,	-s   A

A6A11A6c                     t               }| j                  j                         D ]T  }|j                  j	                  d      x}s!t        | |j                           s:|j                  |j                         V |S )zk
    Go through the list of netplan ethernet devices and identify which ones
    are virtual functions
    r   )r>   r   r   r   rM   r|   rx   ry   )r   r7   ri   r   s       r   _get_virtual_functionsr   A  sk    
 %C$$++- #<<##G,,4,-htww.?@		"	#
 Jr   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 > 256r~   devicer*   sriov_totalvfsNz"failed parsing sriov_totalvfs for r   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   rX   
ValueErrorr`   errnologgingwarning)
pfvf_countdevdirnumvfs_pathtotalvfs_pathrc   vf_maxr   baile_inners
             r   set_numvfs_for_pfr   O  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.
    r~   r   vendorr	   Nz,could not determine vendor and device ID of r   :r   )	r   r   r   r_   r   r   r   r   rX   )r   r   rc   	device_id	vendor_idr   combined_idquirk_devicess           r    perform_hardware_specific_quirksr   ~  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 ipr   r>   r=   rb   vlan)stdoutrE   zJfailed setting SR-IOV VLAN filter for vlan %s (ip link set command failed))r   r   r   r#   r$   listdirr   r?   r@   rX   rI   rJ   )r   rb   	vlan_namevlan_idprefixvf_index	vf_devdir	vf_dev_id	pf_devdirrc   dev_pathdev_ids               r   apply_vlan_filter_for_vfr     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        |      }t        |      }g }|r6|j                         D ]#  \  }}	t        ||	      s|j                  |       % |r&|D ]  }t        |        t        j                         }i }
|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I|j$                  sVt'        j(                  dj+                  ||j,                               |j.                  r!	 t1        |j.                  |j2                         t'        j(                  d| d	| d
|        |j;                  dd|       |j.                  s|j<                  rt?        |j.                  |j2                          tA               }|jB                  j                         D ]  \  }}|jD                  s|jF                  jI                  d      }|jJ                  }|
jI                  |jL                        }|s't'        j6                  d|d|jL                  d       ~|jI                  |jF                  jI                  d      jL                        }||v rt        d|d|jL                  d|d      tO        ||||       |jQ                  |        y# t4        $ r/}t'        j6                  d| dt9        |              Y d}~d}~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.
    )rl   z3matched more than one interface for a VF device: %s)	switchdevlegacyzFound VFs of {}: {}zUnbinding of VFs for z	 failed: NzChanging eswitch mode from z to z for: rC   rG   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 defined))parser   rt   r   r   r   r   itemsr   r0   r   ru   ro   r
   r   r   r   rQ   r+   r   debugr1   r3   r7   rh   r!   	Exceptionr   rX   rA   _delay_virtual_functions_rebindrd   r>   vlans_has_sriov_vlan_filterr   rM   _vlan_idrx   r   ry   )config_managerrootdirrz   r   r   vfs_setr   vf_count_changedr   r   r7   rb   ri   rj   	netdef_idr   eswitch_moder   pcidevcurrent_eswitch_mode_systemr   filtered_vlans_setr   r   r   s                            r   apply_sriov_configr     sz   
 %%'J&&H &h/I %X.G
!(
+C
 %OO- 	(LB$R2##B'		(  # 	1B,R0	1
 ))+
 C "
 ( (	**i*@SySW01fik1kll'CG	( ZB"  IIK @	5)$3322)%0Hx(F*0*E*E*G'::<<MM"7">">vv"WXzzb&vzz6==A MM$?@[?\\`am`nntu~t  #A  B&&y&,Gzz%EE$VZZ?+@.  ,,. 'f ((<<##F+DooG!B eikokrkrsu
 0334B''(dfhlhohoquvx x %RT7;""2&9'  ) b#OO.CI;iX[\]X^W_,`aabs   1 M	N#$NN)/)"rK   r   r   r?   typingr   r   r   r   r    r   configmanagerr
   r   objectr   Iterablerd   rh   NetDefinitionrX   rZ   rr   r|   r   Stater   r   r   r   r   r   r   r   r   r   r   <module>r      s#  &   	   , ,  . Y Yx&//), FOOI. 6??9;U =w44 = = =!7+@+@ !Xc] !HY"gmm S#X <GMM d38n &W]] s3x ,^:$fNs'r   