github.com/vishvananda/netlink@v1.3.1/fou_linux.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package netlink
     5  
     6  import (
     7  	"encoding/binary"
     8  	"errors"
     9  	"log"
    10  	"net"
    11  
    12  	"github.com/vishvananda/netlink/nl"
    13  	"golang.org/x/sys/unix"
    14  )
    15  
    16  const (
    17  	FOU_GENL_NAME = "fou"
    18  )
    19  
    20  const (
    21  	FOU_CMD_UNSPEC uint8 = iota
    22  	FOU_CMD_ADD
    23  	FOU_CMD_DEL
    24  	FOU_CMD_GET
    25  	FOU_CMD_MAX = FOU_CMD_GET
    26  )
    27  
    28  const (
    29  	FOU_ATTR_UNSPEC = iota
    30  	FOU_ATTR_PORT
    31  	FOU_ATTR_AF
    32  	FOU_ATTR_IPPROTO
    33  	FOU_ATTR_TYPE
    34  	FOU_ATTR_REMCSUM_NOPARTIAL
    35  	FOU_ATTR_LOCAL_V4
    36  	FOU_ATTR_LOCAL_V6
    37  	FOU_ATTR_PEER_V4
    38  	FOU_ATTR_PEER_V6
    39  	FOU_ATTR_PEER_PORT
    40  	FOU_ATTR_IFINDEX
    41  	FOU_ATTR_MAX = FOU_ATTR_REMCSUM_NOPARTIAL
    42  )
    43  
    44  const (
    45  	FOU_ENCAP_UNSPEC = iota
    46  	FOU_ENCAP_DIRECT
    47  	FOU_ENCAP_GUE
    48  	FOU_ENCAP_MAX = FOU_ENCAP_GUE
    49  )
    50  
    51  var fouFamilyId int
    52  
    53  func FouFamilyId() (int, error) {
    54  	if fouFamilyId != 0 {
    55  		return fouFamilyId, nil
    56  	}
    57  
    58  	fam, err := GenlFamilyGet(FOU_GENL_NAME)
    59  	if err != nil {
    60  		return -1, err
    61  	}
    62  
    63  	fouFamilyId = int(fam.ID)
    64  	return fouFamilyId, nil
    65  }
    66  
    67  func FouAdd(f Fou) error {
    68  	return pkgHandle.FouAdd(f)
    69  }
    70  
    71  func (h *Handle) FouAdd(f Fou) error {
    72  	fam_id, err := FouFamilyId()
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	// setting ip protocol conflicts with encapsulation type GUE
    78  	if f.EncapType == FOU_ENCAP_GUE && f.Protocol != 0 {
    79  		return errors.New("GUE encapsulation doesn't specify an IP protocol")
    80  	}
    81  
    82  	req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
    83  
    84  	// int to byte for port
    85  	bp := make([]byte, 2)
    86  	binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
    87  
    88  	attrs := []*nl.RtAttr{
    89  		nl.NewRtAttr(FOU_ATTR_PORT, bp),
    90  		nl.NewRtAttr(FOU_ATTR_TYPE, []byte{uint8(f.EncapType)}),
    91  		nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
    92  		nl.NewRtAttr(FOU_ATTR_IPPROTO, []byte{uint8(f.Protocol)}),
    93  	}
    94  	raw := []byte{FOU_CMD_ADD, 1, 0, 0}
    95  	for _, a := range attrs {
    96  		raw = append(raw, a.Serialize()...)
    97  	}
    98  
    99  	req.AddRawData(raw)
   100  
   101  	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
   102  	return err
   103  }
   104  
   105  func FouDel(f Fou) error {
   106  	return pkgHandle.FouDel(f)
   107  }
   108  
   109  func (h *Handle) FouDel(f Fou) error {
   110  	fam_id, err := FouFamilyId()
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
   116  
   117  	// int to byte for port
   118  	bp := make([]byte, 2)
   119  	binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
   120  
   121  	attrs := []*nl.RtAttr{
   122  		nl.NewRtAttr(FOU_ATTR_PORT, bp),
   123  		nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
   124  	}
   125  	raw := []byte{FOU_CMD_DEL, 1, 0, 0}
   126  	for _, a := range attrs {
   127  		raw = append(raw, a.Serialize()...)
   128  	}
   129  
   130  	req.AddRawData(raw)
   131  
   132  	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   141  // or incomplete.
   142  func FouList(fam int) ([]Fou, error) {
   143  	return pkgHandle.FouList(fam)
   144  }
   145  
   146  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   147  // or incomplete.
   148  func (h *Handle) FouList(fam int) ([]Fou, error) {
   149  	fam_id, err := FouFamilyId()
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	req := h.newNetlinkRequest(fam_id, unix.NLM_F_DUMP)
   155  
   156  	attrs := []*nl.RtAttr{
   157  		nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(fam)}),
   158  	}
   159  	raw := []byte{FOU_CMD_GET, 1, 0, 0}
   160  	for _, a := range attrs {
   161  		raw = append(raw, a.Serialize()...)
   162  	}
   163  
   164  	req.AddRawData(raw)
   165  
   166  	msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
   167  	if executeErr != nil && !errors.Is(err, ErrDumpInterrupted) {
   168  		return nil, executeErr
   169  	}
   170  
   171  	fous := make([]Fou, 0, len(msgs))
   172  	for _, m := range msgs {
   173  		f, err := deserializeFouMsg(m)
   174  		if err != nil {
   175  			return fous, err
   176  		}
   177  
   178  		fous = append(fous, f)
   179  	}
   180  
   181  	return fous, executeErr
   182  }
   183  
   184  func deserializeFouMsg(msg []byte) (Fou, error) {
   185  	fou := Fou{}
   186  
   187  	for attr := range nl.ParseAttributes(msg[4:]) {
   188  		switch attr.Type {
   189  		case FOU_ATTR_AF:
   190  			fou.Family = int(attr.Value[0])
   191  		case FOU_ATTR_PORT:
   192  			fou.Port = int(networkOrder.Uint16(attr.Value))
   193  		case FOU_ATTR_IPPROTO:
   194  			fou.Protocol = int(attr.Value[0])
   195  		case FOU_ATTR_TYPE:
   196  			fou.EncapType = int(attr.Value[0])
   197  		case FOU_ATTR_LOCAL_V4, FOU_ATTR_LOCAL_V6:
   198  			fou.Local = net.IP(attr.Value)
   199  		case FOU_ATTR_PEER_V4, FOU_ATTR_PEER_V6:
   200  			fou.Peer = net.IP(attr.Value)
   201  		case FOU_ATTR_PEER_PORT:
   202  			fou.PeerPort = int(networkOrder.Uint16(attr.Value))
   203  		case FOU_ATTR_IFINDEX:
   204  			fou.IfIndex = int(native.Uint16(attr.Value))
   205  		default:
   206  			log.Printf("unknown fou attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
   207  		}
   208  	}
   209  
   210  	return fou, nil
   211  }