<commit_before>package rtnetlink

import (
	"errors"
	"fmt"
	"net"

	"github.com/jsimonetti/rtnetlink/internal/unix"

	"github.com/mdlayher/netlink"
)

var (
	// errInvalidLinkMessage is returned when a LinkMessage is malformed.
	errInvalidLinkMessage = errors.New("rtnetlink LinkMessage is invalid or too short")

	// errInvalidLinkMessageAttr is returned when link attributes are malformed.
	errInvalidLinkMessageAttr = errors.New("rtnetlink LinkMessage has a wrong attribute data length")
)

var _ Message = &LinkMessage{}

// A LinkMessage is a route netlink link message.
type LinkMessage struct {
	// Always set to AF_UNSPEC (0)
	Family uint16

	// Device Type
	Type uint16

	// Unique interface index, using a nonzero value with
	// NewLink will instruct the kernel to create a
	// device with the given index (kernel 3.7+ required)
	Index uint32

	// Contains device flags, see netdevice(7)
	Flags uint32

	// Change Flags, specifies which flags will be affected by the Flags field
	Change uint32

	// Attributes List
	Attributes *LinkAttributes
}

// MarshalBinary marshals a LinkMessage into a byte slice.
func (m *LinkMessage) MarshalBinary() ([]byte, error) {
	b := make([]byte, unix.SizeofIfInfomsg)

	b[0] = 0 // Family
	b[1] = 0 // reserved
	nativeEndian.PutUint16(b[2:4], m.Type)
	nativeEndian.PutUint32(b[4:8], m.Index)
	nativeEndian.PutUint32(b[8:12], m.Flags)
	nativeEndian.PutUint32(b[12:16], m.Change)

	if m.Attributes != nil {
		ae := netlink.NewAttributeEncoder()
		ae.ByteOrder = nativeEndian
		err := m.Attributes.encode(ae)
		if err != nil {
			return nil, err
		}

		a, err := ae.Encode()
		if err != nil {
			return nil, err
		}

		return append(b, a...), nil
	}

	return b, nil
}

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (m *LinkMessage) UnmarshalBinary(b []byte) error {
	l := len(b)
	if l < unix.SizeofIfInfomsg {
		return errInvalidLinkMessage
	}

	m.Family = nativeEndian.Uint16(b[0:2])
	m.Type = nativeEndian.Uint16(b[2:4])
	m.Index = nativeEndian.Uint32(b[4:8])
	m.Flags = nativeEndian.Uint32(b[8:12])
	m.Change = nativeEndian.Uint32(b[12:16])

	if l > unix.SizeofIfInfomsg {
		m.Attributes = &LinkAttributes{}
		ad, err := netlink.NewAttributeDecoder(b[16:])
		if err != nil {
			return err
		}
		ad.ByteOrder = nativeEndian
		err = m.Attributes.decode(ad)
		if err != nil {
			return err
		}
	}

	return nil
}

// rtMessage is an empty method to sattisfy the Message interface.
func (*LinkMessage) rtMessage() {}

// LinkService is used to retrieve rtnetlink family information.
type LinkService struct {
	c *Conn
}

// New creates a new interface using the LinkMessage information.
func (l *LinkService) New(req *LinkMessage) error {
	flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
	_, err := l.c.Execute(req, unix.RTM_NEWLINK, flags)
	if err != nil {
		return err
	}

	return nil
}

// Delete removes an interface by index.
func (l *LinkService) Delete(index uint32) error {
	req := &LinkMessage{
		Index: index,
	}

	flags := netlink.Request | netlink.Acknowledge
	_, err := l.c.Execute(req, unix.RTM_DELLINK, flags)
	if err != nil {
		return err
	}

	return nil
}

// Get retrieves interface information by index.
func (l *LinkService) Get(index uint32) (LinkMessage, error) {
	req := &LinkMessage{
		Index: index,
	}

	flags := netlink.Request | netlink.DumpFiltered
	msg, err := l.c.Execute(req, unix.RTM_GETLINK, flags)
	if err != nil {
		return LinkMessage{}, err
	}

	if len(msg) != 1 {
		return LinkMessage{}, fmt.Errorf("too many/little matches, expected 1")
	}

	link := (msg[0]).(*LinkMessage)
	return *link, nil
}

// Set sets interface attributes according to the LinkMessage information.
func (l *LinkService) Set(req *LinkMessage) error {
	flags := netlink.Request | netlink.Acknowledge
	_, err := l.c.Execute(req, unix.RTM_SETLINK, flags)
	if err != nil {
		return err
	}

	return nil
}

// List retrieves all interfaces.
func (l *LinkService) List() ([]LinkMessage, error) {
	req := &LinkMessage{}<commit_msg>fix: Use correct message type for Set (#64)<commit_after>package rtnetlink

import (
	"errors"
	"fmt"
	"net"

	"github.com/jsimonetti/rtnetlink/internal/unix"

	"github.com/mdlayher/netlink"
)

var (
	// errInvalidLinkMessage is returned when a LinkMessage is malformed.
	errInvalidLinkMessage = errors.New("rtnetlink LinkMessage is invalid or too short")

	// errInvalidLinkMessageAttr is returned when link attributes are malformed.
	errInvalidLinkMessageAttr = errors.New("rtnetlink LinkMessage has a wrong attribute data length")
)

var _ Message = &LinkMessage{}

// A LinkMessage is a route netlink link message.
type LinkMessage struct {
	// Always set to AF_UNSPEC (0)
	Family uint16

	// Device Type
	Type uint16

	// Unique interface index, using a nonzero value with
	// NewLink will instruct the kernel to create a
	// device with the given index (kernel 3.7+ required)
	Index uint32

	// Contains device flags, see netdevice(7)
	Flags uint32

	// Change Flags, specifies which flags will be affected by the Flags field
	Change uint32

	// Attributes List
	Attributes *LinkAttributes
}

// MarshalBinary marshals a LinkMessage into a byte slice.
func (m *LinkMessage) MarshalBinary() ([]byte, error) {
	b := make([]byte, unix.SizeofIfInfomsg)

	b[0] = 0 // Family
	b[1] = 0 // reserved
	nativeEndian.PutUint16(b[2:4], m.Type)
	nativeEndian.PutUint32(b[4:8], m.Index)
	nativeEndian.PutUint32(b[8:12], m.Flags)
	nativeEndian.PutUint32(b[12:16], m.Change)

	if m.Attributes != nil {
		ae := netlink.NewAttributeEncoder()
		ae.ByteOrder = nativeEndian
		err := m.Attributes.encode(ae)
		if err != nil {
			return nil, err
		}

		a, err := ae.Encode()
		if err != nil {
			return nil, err
		}

		return append(b, a...), nil
	}

	return b, nil
}

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (m *LinkMessage) UnmarshalBinary(b []byte) error {
	l := len(b)
	if l < unix.SizeofIfInfomsg {
		return errInvalidLinkMessage
	}

	m.Family = nativeEndian.Uint16(b[0:2])
	m.Type = nativeEndian.Uint16(b[2:4])
	m.Index = nativeEndian.Uint32(b[4:8])
	m.Flags = nativeEndian.Uint32(b[8:12])
	m.Change = nativeEndian.Uint32(b[12:16])

	if l > unix.SizeofIfInfomsg {
		m.Attributes = &LinkAttributes{}
		ad, err := netlink.NewAttributeDecoder(b[16:])
		if err != nil {
			return err
		}
		ad.ByteOrder = nativeEndian
		err = m.Attributes.decode(ad)
		if err != nil {
			return err
		}
	}

	return nil
}

// rtMessage is an empty method to sattisfy the Message interface.
func (*LinkMessage) rtMessage() {}

// LinkService is used to retrieve rtnetlink family information.
type LinkService struct {
	c *Conn
}

// New creates a new interface using the LinkMessage information.
func (l *LinkService) New(req *LinkMessage) error {
	flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
	_, err := l.c.Execute(req, unix.RTM_NEWLINK, flags)
	if err != nil {
		return err
	}

	return nil
}

// Delete removes an interface by index.
func (l *LinkService) Delete(index uint32) error {
	req := &LinkMessage{
		Index: index,
	}

	flags := netlink.Request | netlink.Acknowledge
	_, err := l.c.Execute(req, unix.RTM_DELLINK, flags)
	if err != nil {
		return err
	}

	return nil
}

// Get retrieves interface information by index.
func (l *LinkService) Get(index uint32) (LinkMessage, error) {
	req := &LinkMessage{
		Index: index,
	}

	flags := netlink.Request | netlink.DumpFiltered
	msg, err := l.c.Execute(req, unix.RTM_GETLINK, flags)
	if err != nil {
		return LinkMessage{}, err
	}

	if len(msg) != 1 {
		return LinkMessage{}, fmt.Errorf("too many/little matches, expected 1")
	}

	link := (msg[0]).(*LinkMessage)
	return *link, nil
}

// Set sets interface attributes according to the LinkMessage information.
//
// ref: https://lwn.net/Articles/236919/
// We explicitly use RTM_NEWLINK to set link attributes instead of
// RTM_SETLINK because:
// - using RTM_SETLINK is actually an old rtnetlink API, not supporting most
//   attributes common today
// - using RTM_NEWLINK is the prefered way to create AND update links
// - RTM_NEWLINK is backward compatible to RTM_SETLINK
func (l *LinkService) Set(req *LinkMessage) error {
	flags := netlink.Request | netlink.Acknowledge
	_, err := l.c.Execute(req, unix.RTM_NEWLINK, flags)
	if err != nil {
		return err
	}

	return nil
}

// List retrieves all interfaces.
func (l *LinkService) List() ([]LinkMessage, error) {
	req := &LinkMessage{}
{'fraction_non_alphanumeric': 0.11827830188679245, 'fraction_numerical': 0.01721698113207547, 'mean_word_length': 3.8269778030734205, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6102776', 'n_tokens_mistral': 3084, 'n_tokens_neox': 2893, 'n_words': 875}