@@ -247,6 +247,107 @@ func (dlrs *DevlinkResources) parseAttributes(attrs map[uint16]syscall.NetlinkRo
247247 return nil
248248}
249249
250+ // DevlinkParam represents parameter of the device
251+ type DevlinkParam struct {
252+ Name string
253+ IsGeneric bool
254+ Type uint8 // possible values are in nl.DEVLINK_PARAM_TYPE_* constants
255+ Values []DevlinkParamValue
256+ }
257+
258+ // DevlinkParamValue contains values of the parameter
259+ // Data field contains specific type which can be casted by unsing info from the DevlinkParam.Type field
260+ type DevlinkParamValue struct {
261+ rawData []byte
262+ Data interface {}
263+ CMODE uint8 // possible values are in nl.DEVLINK_PARAM_CMODE_* constants
264+ }
265+
266+ // parseAttributes parses provided Netlink Attributes and populates DevlinkParam, returns error if occured
267+ func (dlp * DevlinkParam ) parseAttributes (attrs []syscall.NetlinkRouteAttr ) error {
268+ var valuesList [][]syscall.NetlinkRouteAttr
269+ for _ , attr := range attrs {
270+ switch attr .Attr .Type {
271+ case nl .DEVLINK_ATTR_PARAM :
272+ nattrs , err := nl .ParseRouteAttr (attr .Value )
273+ if err != nil {
274+ return err
275+ }
276+ for _ , nattr := range nattrs {
277+ switch nattr .Attr .Type {
278+ case nl .DEVLINK_ATTR_PARAM_NAME :
279+ dlp .Name = nl .BytesToString (nattr .Value )
280+ case nl .DEVLINK_ATTR_PARAM_GENERIC :
281+ dlp .IsGeneric = true
282+ case nl .DEVLINK_ATTR_PARAM_TYPE :
283+ if len (nattr .Value ) == 1 {
284+ dlp .Type = nattr .Value [0 ]
285+ }
286+ case nl .DEVLINK_ATTR_PARAM_VALUES_LIST :
287+ nnattrs , err := nl .ParseRouteAttr (nattr .Value )
288+ if err != nil {
289+ return err
290+ }
291+ valuesList = append (valuesList , nnattrs )
292+ }
293+ }
294+ }
295+ }
296+ for _ , valAttr := range valuesList {
297+ v := DevlinkParamValue {}
298+ if err := v .parseAttributes (valAttr , dlp .Type ); err != nil {
299+ return err
300+ }
301+ dlp .Values = append (dlp .Values , v )
302+ }
303+ return nil
304+ }
305+
306+ func (dlpv * DevlinkParamValue ) parseAttributes (attrs []syscall.NetlinkRouteAttr , paramType uint8 ) error {
307+ for _ , attr := range attrs {
308+ nattrs , err := nl .ParseRouteAttr (attr .Value )
309+ if err != nil {
310+ return err
311+ }
312+ var rawData []byte
313+ for _ , nattr := range nattrs {
314+ switch nattr .Attr .Type {
315+ case nl .DEVLINK_ATTR_PARAM_VALUE_DATA :
316+ rawData = nattr .Value
317+ case nl .DEVLINK_ATTR_PARAM_VALUE_CMODE :
318+ if len (nattr .Value ) == 1 {
319+ dlpv .CMODE = nattr .Value [0 ]
320+ }
321+ }
322+ }
323+ switch paramType {
324+ case nl .DEVLINK_PARAM_TYPE_U8 :
325+ dlpv .Data = uint8 (0 )
326+ if rawData != nil && len (rawData ) == 1 {
327+ dlpv .Data = uint8 (rawData [0 ])
328+ }
329+ case nl .DEVLINK_PARAM_TYPE_U16 :
330+ dlpv .Data = uint16 (0 )
331+ if rawData != nil {
332+ dlpv .Data = native .Uint16 (rawData )
333+ }
334+ case nl .DEVLINK_PARAM_TYPE_U32 :
335+ dlpv .Data = uint32 (0 )
336+ if rawData != nil {
337+ dlpv .Data = native .Uint32 (rawData )
338+ }
339+ case nl .DEVLINK_PARAM_TYPE_STRING :
340+ dlpv .Data = ""
341+ if rawData != nil {
342+ dlpv .Data = nl .BytesToString (rawData )
343+ }
344+ case nl .DEVLINK_PARAM_TYPE_BOOL :
345+ dlpv .Data = rawData != nil
346+ }
347+ }
348+ return nil
349+ }
350+
250351func parseDevLinkDeviceList (msgs [][]byte ) ([]* DevlinkDevice , error ) {
251352 devices := make ([]* DevlinkDevice , 0 , len (msgs ))
252353 for _ , m := range msgs {
@@ -635,6 +736,144 @@ func (h *Handle) DevlinkGetDeviceResources(bus string, device string) (*DevlinkR
635736 return & resources , nil
636737}
637738
739+ // DevlinkGetDeviceParams returns parameters for devlink device
740+ // Equivalent to: `devlink dev param show <bus>/<device>`
741+ func (h * Handle ) DevlinkGetDeviceParams (bus string , device string ) ([]* DevlinkParam , error ) {
742+ _ , req , err := h .createCmdReq (nl .DEVLINK_CMD_PARAM_GET , bus , device )
743+ if err != nil {
744+ return nil , err
745+ }
746+ req .Flags |= unix .NLM_F_DUMP
747+ respmsg , err := req .Execute (unix .NETLINK_GENERIC , 0 )
748+ if err != nil {
749+ return nil , err
750+ }
751+ var params []* DevlinkParam
752+ for _ , m := range respmsg {
753+ attrs , err := nl .ParseRouteAttr (m [nl .SizeofGenlmsg :])
754+ if err != nil {
755+ return nil , err
756+ }
757+ p := & DevlinkParam {}
758+ if err := p .parseAttributes (attrs ); err != nil {
759+ return nil , err
760+ }
761+ params = append (params , p )
762+ }
763+
764+ return params , nil
765+ }
766+
767+ // DevlinkGetDeviceParams returns parameters for devlink device
768+ // Equivalent to: `devlink dev param show <bus>/<device>`
769+ func DevlinkGetDeviceParams (bus string , device string ) ([]* DevlinkParam , error ) {
770+ return pkgHandle .DevlinkGetDeviceParams (bus , device )
771+ }
772+
773+ // DevlinkGetDeviceParamByName returns specific parameter for devlink device
774+ // Equivalent to: `devlink dev param show <bus>/<device> name <param>`
775+ func (h * Handle ) DevlinkGetDeviceParamByName (bus string , device string , param string ) (* DevlinkParam , error ) {
776+ _ , req , err := h .createCmdReq (nl .DEVLINK_CMD_PARAM_GET , bus , device )
777+ if err != nil {
778+ return nil , err
779+ }
780+ req .AddData (nl .NewRtAttr (nl .DEVLINK_ATTR_PARAM_NAME , nl .ZeroTerminated (param )))
781+ respmsg , err := req .Execute (unix .NETLINK_GENERIC , 0 )
782+ if err != nil {
783+ return nil , err
784+ }
785+ if len (respmsg ) == 0 {
786+ return nil , fmt .Errorf ("unexpected response" )
787+ }
788+ attrs , err := nl .ParseRouteAttr (respmsg [0 ][nl .SizeofGenlmsg :])
789+ if err != nil {
790+ return nil , err
791+ }
792+ p := & DevlinkParam {}
793+ if err := p .parseAttributes (attrs ); err != nil {
794+ return nil , err
795+ }
796+ return p , nil
797+ }
798+
799+ // DevlinkGetDeviceParamByName returns specific parameter for devlink device
800+ // Equivalent to: `devlink dev param show <bus>/<device> name <param>`
801+ func DevlinkGetDeviceParamByName (bus string , device string , param string ) (* DevlinkParam , error ) {
802+ return pkgHandle .DevlinkGetDeviceParamByName (bus , device , param )
803+ }
804+
805+ // DevlinkSetDeviceParam set specific parameter for devlink device
806+ // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>`
807+ // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants
808+ // value argument should have one of the following types: uint8, uint16, uint32, string, bool
809+ func (h * Handle ) DevlinkSetDeviceParam (bus string , device string , param string , cmode uint8 , value interface {}) error {
810+ // retrive the param type
811+ p , err := h .DevlinkGetDeviceParamByName (bus , device , param )
812+ if err != nil {
813+ return fmt .Errorf ("failed to get device param: %v" , err )
814+ }
815+ paramType := p .Type
816+
817+ _ , req , err := h .createCmdReq (nl .DEVLINK_CMD_PARAM_SET , bus , device )
818+ if err != nil {
819+ return err
820+ }
821+ req .AddData (nl .NewRtAttr (nl .DEVLINK_ATTR_PARAM_TYPE , nl .Uint8Attr (paramType )))
822+ req .AddData (nl .NewRtAttr (nl .DEVLINK_ATTR_PARAM_NAME , nl .ZeroTerminated (param )))
823+ req .AddData (nl .NewRtAttr (nl .DEVLINK_ATTR_PARAM_VALUE_CMODE , nl .Uint8Attr (cmode )))
824+
825+ var valueAsBytes []byte
826+ switch paramType {
827+ case nl .DEVLINK_PARAM_TYPE_U8 :
828+ v , ok := value .(uint8 )
829+ if ! ok {
830+ return fmt .Errorf ("unepected value type required: uint8, actual: %T" , value )
831+ }
832+ valueAsBytes = nl .Uint8Attr (v )
833+ case nl .DEVLINK_PARAM_TYPE_U16 :
834+ v , ok := value .(uint16 )
835+ if ! ok {
836+ return fmt .Errorf ("unepected value type required: uint16, actual: %T" , value )
837+ }
838+ valueAsBytes = nl .Uint16Attr (v )
839+ case nl .DEVLINK_PARAM_TYPE_U32 :
840+ v , ok := value .(uint32 )
841+ if ! ok {
842+ return fmt .Errorf ("unepected value type required: uint32, actual: %T" , value )
843+ }
844+ valueAsBytes = nl .Uint32Attr (v )
845+ case nl .DEVLINK_PARAM_TYPE_STRING :
846+ v , ok := value .(string )
847+ if ! ok {
848+ return fmt .Errorf ("unepected value type required: string, actual: %T" , value )
849+ }
850+ valueAsBytes = nl .ZeroTerminated (v )
851+ case nl .DEVLINK_PARAM_TYPE_BOOL :
852+ v , ok := value .(bool )
853+ if ! ok {
854+ return fmt .Errorf ("unepected value type required: bool, actual: %T" , value )
855+ }
856+ if v {
857+ valueAsBytes = []byte {}
858+ }
859+ default :
860+ return fmt .Errorf ("unsupported parameter type: %d" , paramType )
861+ }
862+ if valueAsBytes != nil {
863+ req .AddData (nl .NewRtAttr (nl .DEVLINK_ATTR_PARAM_VALUE_DATA , valueAsBytes ))
864+ }
865+ _ , err = req .Execute (unix .NETLINK_GENERIC , 0 )
866+ return err
867+ }
868+
869+ // DevlinkSetDeviceParam set specific parameter for devlink device
870+ // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>`
871+ // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants
872+ // value argument should have one of the following types: uint8, uint16, uint32, string, bool
873+ func DevlinkSetDeviceParam (bus string , device string , param string , cmode uint8 , value interface {}) error {
874+ return pkgHandle .DevlinkSetDeviceParam (bus , device , param , cmode , value )
875+ }
876+
638877// DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
639878// otherwise returns an error code.
640879func DevLinkGetPortByIndex (Bus string , Device string , PortIndex uint32 ) (* DevlinkPort , error ) {
0 commit comments