From 4a21d975ccd424ea8487ac013ca9d674a3914ab9 Mon Sep 17 00:00:00 2001 From: Birol Bilgin Date: Mon, 4 Mar 2024 12:16:26 +0100 Subject: [PATCH] Add link netkit This commit introduces the LinkNetkit type into LinkAttributes, facilitating Netkit data's encoding to and decoding from the LinkInfo.Data field. This addition prioritizes backward compatibility and introduces necessary condition checks. For decoding, if the LinkInfo kind is netkit, the data within LinkInfo.Data is decoded to the Netkit field. During encoding, Netkit data is encoded into LinkInfo.Data with LinkInfo.Kind set as netkit. Concurrent settings of LinkInfo and Netkit during encoding trigger an error to maintain integrity. Signed-off-by: Birol Bilgin --- internal/unix/types_linux.go | 12 ++++++ internal/unix/types_other.go | 12 ++++++ link.go | 82 ++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/internal/unix/types_linux.go b/internal/unix/types_linux.go index ad3659c..c385820 100644 --- a/internal/unix/types_linux.go +++ b/internal/unix/types_linux.go @@ -71,6 +71,12 @@ const ( IFLA_INFO_SLAVE_KIND = linux.IFLA_INFO_SLAVE_KIND IFLA_INFO_DATA = linux.IFLA_INFO_DATA IFLA_INFO_SLAVE_DATA = linux.IFLA_INFO_SLAVE_DATA + IFLA_NETKIT_UNSPEC = linux.IFLA_NETKIT_UNSPEC + IFLA_NETKIT_PEER_INFO = linux.IFLA_NETKIT_PEER_INFO + IFLA_NETKIT_PRIMARY = linux.IFLA_NETKIT_PRIMARY + IFLA_NETKIT_POLICY = linux.IFLA_NETKIT_POLICY + IFLA_NETKIT_PEER_POLICY = linux.IFLA_NETKIT_PEER_POLICY + IFLA_NETKIT_MODE = linux.IFLA_NETKIT_MODE IFLA_XDP = linux.IFLA_XDP IFLA_XDP_FD = linux.IFLA_XDP_FD IFLA_XDP_ATTACHED = linux.IFLA_XDP_ATTACHED @@ -147,4 +153,10 @@ const ( FRA_IP_PROTO = linux.FRA_IP_PROTO FRA_SPORT_RANGE = linux.FRA_SPORT_RANGE FRA_DPORT_RANGE = linux.FRA_DPORT_RANGE + NETKIT_NEXT = linux.NETKIT_NEXT + NETKIT_PASS = linux.NETKIT_PASS + NETKIT_DROP = linux.NETKIT_DROP + NETKIT_REDIRECT = linux.NETKIT_REDIRECT + NETKIT_L2 = linux.NETKIT_L2 + NETKIT_L3 = linux.NETKIT_L3 ) diff --git a/internal/unix/types_other.go b/internal/unix/types_other.go index 1d4bdee..632f9ae 100644 --- a/internal/unix/types_other.go +++ b/internal/unix/types_other.go @@ -67,6 +67,12 @@ const ( IFLA_INFO_SLAVE_KIND = 0x4 IFLA_INFO_DATA = 0x2 IFLA_INFO_SLAVE_DATA = 0x5 + IFLA_NETKIT_UNSPEC = 0x0 + IFLA_NETKIT_PEER_INFO = 0x1 + IFLA_NETKIT_PRIMARY = 0x2 + IFLA_NETKIT_POLICY = 0x3 + IFLA_NETKIT_PEER_POLICY = 0x4 + IFLA_NETKIT_MODE = 0x5 IFLA_XDP = 0x2b IFLA_XDP_FD = 0x1 IFLA_XDP_ATTACHED = 0x2 @@ -143,4 +149,10 @@ const ( FRA_IP_PROTO = 0x16 FRA_SPORT_RANGE = 0x17 FRA_DPORT_RANGE = 0x18 + NETKIT_NEXT = -0x1 + NETKIT_PASS = 0x0 + NETKIT_DROP = 0x2 + NETKIT_REDIRECT = 0x7 + NETKIT_L2 = 0x0 + NETKIT_L3 = 0x1 ) diff --git a/link.go b/link.go index 751c099..b2d6ff2 100644 --- a/link.go +++ b/link.go @@ -222,6 +222,7 @@ type LinkAttributes struct { TxQueueLen *uint32 // Interface transmit queue len in number of packets Type uint32 // Link type XDP *LinkXDP // Express Data Patch Information + Netkit *LinkNetkit // Netkit link Information } // OperationalState represents an interface's operational state. @@ -285,6 +286,18 @@ func (a *LinkAttributes) decode(ad *netlink.AttributeDecoder) error { case unix.IFLA_LINKINFO: a.Info = &LinkInfo{} ad.Nested(a.Info.decode) + switch a.Info.Kind { + case "netkit": + a.Netkit = &LinkNetkit{} + dec, err := netlink.NewAttributeDecoder(a.Info.Data) + if err != nil { + return err + } + dec.ByteOrder = ad.ByteOrder + if err := a.Netkit.decode(dec); err != nil { + return err + } + } case unix.IFLA_LINKMODE: v := ad.Uint8() a.LinkMode = &v @@ -351,6 +364,33 @@ func (a *LinkAttributes) encode(ae *netlink.AttributeEncoder) error { ae.Uint8(unix.IFLA_OPERSTATE, uint8(a.OperationalState)) } + if a.Netkit != nil { + if a.Info != nil { + return errors.New("fields Netkit and Info cannot be set at the same time") + } + + if a.Address != nil || a.Netkit.PeerInfo.Attributes.Address != nil { + return errors.New("netkit does not support setting Ethernet address") + } + + nae := netlink.NewAttributeEncoder() + nae.ByteOrder = ae.ByteOrder + + err := a.Netkit.encode(nae) + if err != nil { + return err + } + b, err := nae.Encode() + if err != nil { + return err + } + + a.Info = &LinkInfo{ + Kind: "netkit", + Data: b, + } + } + if a.Info != nil { nae := netlink.NewAttributeEncoder() nae.ByteOrder = ae.ByteOrder @@ -584,6 +624,48 @@ func (i *LinkInfo) encode(ae *netlink.AttributeEncoder) error { return nil } +// LinkNetkit holds netkit link specific information +type LinkNetkit struct { + Mode uint32 + Policy int32 + PeerPolicy int32 + Primary bool + PeerInfo *LinkMessage +} + +func (n *LinkNetkit) decode(ad *netlink.AttributeDecoder) error { + for ad.Next() { + switch ad.Type() { + case unix.IFLA_NETKIT_MODE: + n.Mode = ad.Uint32() + case unix.IFLA_NETKIT_POLICY: + n.Policy = ad.Int32() + case unix.IFLA_NETKIT_PEER_POLICY: + n.PeerPolicy = ad.Int32() + case unix.IFLA_NETKIT_PRIMARY: + n.Primary = ad.Uint8() != 0 + } + } + return nil +} + +func (n *LinkNetkit) encode(ae *netlink.AttributeEncoder) error { + ae.Uint32(unix.IFLA_NETKIT_MODE, n.Mode) + ae.Int32(unix.IFLA_NETKIT_POLICY, n.Policy) + ae.Int32(unix.IFLA_NETKIT_PEER_POLICY, n.PeerPolicy) + if n.PeerInfo != nil { + n.PeerInfo.Family = unix.AF_UNSPEC + // we need to set the netkit.peerInfo.Flags and .Change according to primary link + // however we do not have this information here + b, err := n.PeerInfo.MarshalBinary() + if err != nil { + return err + } + ae.Bytes(unix.IFLA_NETKIT_PEER_INFO, b) + } + return nil +} + // LinkXDP holds Express Data Path specific information type LinkXDP struct { FD int32