| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- package rtnetlink
- import (
- "encoding"
- "time"
- "github.com/jsimonetti/rtnetlink/internal/unix"
- "github.com/mdlayher/netlink"
- )
- // A Conn is a route netlink connection. A Conn can be used to send and
- // receive route netlink messages to and from netlink.
- type Conn struct {
- c conn
- Link *LinkService
- Address *AddressService
- Route *RouteService
- Neigh *NeighService
- Rule *RuleService
- }
- var _ conn = &netlink.Conn{}
- // A conn is a netlink connection, which can be swapped for tests.
- type conn interface {
- Close() error
- Send(m netlink.Message) (netlink.Message, error)
- Receive() ([]netlink.Message, error)
- Execute(m netlink.Message) ([]netlink.Message, error)
- SetOption(option netlink.ConnOption, enable bool) error
- SetReadDeadline(t time.Time) error
- }
- // Dial dials a route netlink connection. Config specifies optional
- // configuration for the underlying netlink connection. If config is
- // nil, a default configuration will be used.
- func Dial(config *netlink.Config) (*Conn, error) {
- c, err := netlink.Dial(unix.NETLINK_ROUTE, config)
- if err != nil {
- return nil, err
- }
- return newConn(c), nil
- }
- // newConn creates a Conn that wraps an existing *netlink.Conn for
- // rtnetlink communications. It is used for testing.
- func newConn(c conn) *Conn {
- rtc := &Conn{
- c: c,
- }
- rtc.Link = &LinkService{c: rtc}
- rtc.Address = &AddressService{c: rtc}
- rtc.Route = &RouteService{c: rtc}
- rtc.Neigh = &NeighService{c: rtc}
- rtc.Rule = &RuleService{c: rtc}
- return rtc
- }
- // Close closes the connection.
- func (c *Conn) Close() error {
- return c.c.Close()
- }
- // SetOption enables or disables a netlink socket option for the Conn.
- func (c *Conn) SetOption(option netlink.ConnOption, enable bool) error {
- return c.c.SetOption(option, enable)
- }
- // SetReadDeadline sets the read deadline associated with the connection.
- func (c *Conn) SetReadDeadline(t time.Time) error {
- return c.c.SetReadDeadline(t)
- }
- // Send sends a single Message to netlink, wrapping it in a netlink.Message
- // using the specified generic netlink family and flags. On success, Send
- // returns a copy of the netlink.Message with all parameters populated, for
- // later validation.
- func (c *Conn) Send(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
- nm := netlink.Message{
- Header: netlink.Header{
- Type: netlink.HeaderType(family),
- Flags: flags,
- },
- }
- mb, err := m.MarshalBinary()
- if err != nil {
- return netlink.Message{}, err
- }
- nm.Data = mb
- reqnm, err := c.c.Send(nm)
- if err != nil {
- return netlink.Message{}, err
- }
- return reqnm, nil
- }
- // Receive receives one or more Messages from netlink. The netlink.Messages
- // used to wrap each Message are available for later validation.
- func (c *Conn) Receive() ([]Message, []netlink.Message, error) {
- msgs, err := c.c.Receive()
- if err != nil {
- return nil, nil, err
- }
- rtmsgs, err := unpackMessages(msgs)
- if err != nil {
- return nil, nil, err
- }
- return rtmsgs, msgs, nil
- }
- // Execute sends a single Message to netlink using Send, receives one or more
- // replies using Receive, and then checks the validity of the replies against
- // the request using netlink.Validate.
- //
- // Execute acquires a lock for the duration of the function call which blocks
- // concurrent calls to Send and Receive, in order to ensure consistency between
- // generic netlink request/reply messages.
- //
- // See the documentation of Send, Receive, and netlink.Validate for details
- // about each function.
- func (c *Conn) Execute(m Message, family uint16, flags netlink.HeaderFlags) ([]Message, error) {
- nm, err := packMessage(m, family, flags)
- if err != nil {
- return nil, err
- }
- msgs, err := c.c.Execute(nm)
- if err != nil {
- return nil, err
- }
- return unpackMessages(msgs)
- }
- // Message is the interface used for passing around different kinds of rtnetlink messages
- type Message interface {
- encoding.BinaryMarshaler
- encoding.BinaryUnmarshaler
- rtMessage()
- }
- // packMessage packs a rtnetlink Message into a netlink.Message with the
- // appropriate rtnetlink family and netlink flags.
- func packMessage(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
- nm := netlink.Message{
- Header: netlink.Header{
- Type: netlink.HeaderType(family),
- Flags: flags,
- },
- }
- mb, err := m.MarshalBinary()
- if err != nil {
- return netlink.Message{}, err
- }
- nm.Data = mb
- return nm, nil
- }
- // unpackMessages unpacks rtnetlink Messages from a slice of netlink.Messages.
- func unpackMessages(msgs []netlink.Message) ([]Message, error) {
- lmsgs := make([]Message, 0, len(msgs))
- for _, nm := range msgs {
- var m Message
- switch nm.Header.Type {
- case unix.RTM_GETLINK, unix.RTM_NEWLINK, unix.RTM_DELLINK:
- m = &LinkMessage{}
- case unix.RTM_GETADDR, unix.RTM_NEWADDR, unix.RTM_DELADDR:
- m = &AddressMessage{}
- case unix.RTM_GETROUTE, unix.RTM_NEWROUTE, unix.RTM_DELROUTE:
- m = &RouteMessage{}
- case unix.RTM_GETNEIGH, unix.RTM_NEWNEIGH, unix.RTM_DELNEIGH:
- m = &NeighMessage{}
- case unix.RTM_GETRULE, unix.RTM_NEWRULE, unix.RTM_DELRULE:
- m = &RuleMessage{}
- default:
- continue
- }
- if err := (m).UnmarshalBinary(nm.Data); err != nil {
- return nil, err
- }
- lmsgs = append(lmsgs, m)
- }
- return lmsgs, nil
- }
|