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

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