mirror of
https://github.com/jsimonetti/rtnetlink.git
synced 2026-03-29 17:01:08 +02:00
Add drivers for bridge, macvlan, vlan, vxlan and add helpers to LinkService to use them (SetMaster, RemoveMaster) Signed-off-by: Jeroen Simonetti <jeroen@simonetti.nl>
206 lines
4.7 KiB
Go
206 lines
4.7 KiB
Go
package driver
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/jsimonetti/rtnetlink/v2"
|
|
"github.com/jsimonetti/rtnetlink/v2/internal/unix"
|
|
|
|
"github.com/mdlayher/netlink"
|
|
)
|
|
|
|
// VlanProtocol represents the VLAN protocol type.
|
|
type VlanProtocol uint16
|
|
|
|
// VLAN protocols.
|
|
const (
|
|
// VlanProtocol8021Q represents 802.1Q VLAN tagging (standard VLAN).
|
|
VlanProtocol8021Q VlanProtocol = 0x0081
|
|
|
|
// VlanProtocol8021AD represents 802.1ad QinQ (VLAN stacking).
|
|
VlanProtocol8021AD VlanProtocol = 0xA888
|
|
)
|
|
|
|
// String returns a string representation of the VlanProtocol.
|
|
func (p VlanProtocol) String() string {
|
|
switch p {
|
|
case VlanProtocol8021Q:
|
|
return "802.1Q"
|
|
case VlanProtocol8021AD:
|
|
return "802.1ad"
|
|
default:
|
|
return fmt.Sprintf("unknown VlanProtocol value (0x%x)", uint16(p))
|
|
}
|
|
}
|
|
|
|
// VlanFlag represents VLAN flags.
|
|
type VlanFlag uint32
|
|
|
|
// VLAN flags.
|
|
const (
|
|
VlanFlagReorderHdr VlanFlag = 0x1
|
|
VlanFlagGVRP VlanFlag = 0x2
|
|
VlanFlagLooseBinding VlanFlag = 0x4
|
|
VlanFlagMVRP VlanFlag = 0x8
|
|
VlanFlagBridgeBinding VlanFlag = 0x10
|
|
)
|
|
|
|
// VlanQosMapping represents a QoS priority mapping.
|
|
type VlanQosMapping struct {
|
|
From uint32
|
|
To uint32
|
|
}
|
|
|
|
// Vlan represents a VLAN device configuration.
|
|
type Vlan struct {
|
|
// ID specifies the VLAN ID (1-4094).
|
|
ID *uint16
|
|
|
|
// Protocol specifies the VLAN protocol (802.1Q or 802.1ad).
|
|
Protocol *VlanProtocol
|
|
|
|
// Flags specifies VLAN flags.
|
|
Flags *VlanFlag
|
|
|
|
// EgressQos specifies egress QoS mappings.
|
|
EgressQos []VlanQosMapping
|
|
|
|
// IngressQos specifies ingress QoS mappings.
|
|
IngressQos []VlanQosMapping
|
|
}
|
|
|
|
var _ rtnetlink.LinkDriver = &Vlan{}
|
|
|
|
// New creates a new Vlan instance.
|
|
func (v *Vlan) New() rtnetlink.LinkDriver {
|
|
return &Vlan{}
|
|
}
|
|
|
|
// Kind returns the VLAN interface kind.
|
|
func (v *Vlan) Kind() string {
|
|
return "vlan"
|
|
}
|
|
|
|
// Encode encodes a Vlan into netlink attributes.
|
|
func (v *Vlan) Encode(ae *netlink.AttributeEncoder) error {
|
|
if v.ID != nil {
|
|
ae.Uint16(unix.IFLA_VLAN_ID, *v.ID)
|
|
}
|
|
|
|
if v.Protocol != nil {
|
|
ae.Uint16(unix.IFLA_VLAN_PROTOCOL, uint16(*v.Protocol))
|
|
}
|
|
|
|
if v.Flags != nil {
|
|
// VLAN flags are encoded as a nested attribute with flags and mask
|
|
ae.Nested(unix.IFLA_VLAN_FLAGS, func(nae *netlink.AttributeEncoder) error {
|
|
nae.Uint32(1, uint32(*v.Flags)) // flags
|
|
nae.Uint32(2, uint32(*v.Flags)) // mask (same as flags)
|
|
return nil
|
|
})
|
|
}
|
|
|
|
if len(v.EgressQos) > 0 {
|
|
ae.Nested(unix.IFLA_VLAN_EGRESS_QOS, func(nae *netlink.AttributeEncoder) error {
|
|
for _, mapping := range v.EgressQos {
|
|
nae.Nested(unix.IFLA_VLAN_QOS_MAPPING, func(mae *netlink.AttributeEncoder) error {
|
|
mae.Uint32(1, mapping.From)
|
|
mae.Uint32(2, mapping.To)
|
|
return nil
|
|
})
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
if len(v.IngressQos) > 0 {
|
|
ae.Nested(unix.IFLA_VLAN_INGRESS_QOS, func(nae *netlink.AttributeEncoder) error {
|
|
for _, mapping := range v.IngressQos {
|
|
nae.Nested(unix.IFLA_VLAN_QOS_MAPPING, func(mae *netlink.AttributeEncoder) error {
|
|
mae.Uint32(1, mapping.From)
|
|
mae.Uint32(2, mapping.To)
|
|
return nil
|
|
})
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Decode decodes netlink attributes into a Vlan.
|
|
func (v *Vlan) Decode(ad *netlink.AttributeDecoder) error {
|
|
for ad.Next() {
|
|
switch ad.Type() {
|
|
case unix.IFLA_VLAN_ID:
|
|
id := ad.Uint16()
|
|
v.ID = &id
|
|
|
|
case unix.IFLA_VLAN_PROTOCOL:
|
|
protocol := VlanProtocol(ad.Uint16())
|
|
v.Protocol = &protocol
|
|
|
|
case unix.IFLA_VLAN_FLAGS:
|
|
ad.Nested(func(nad *netlink.AttributeDecoder) error {
|
|
for nad.Next() {
|
|
switch nad.Type() {
|
|
case 1: // flags
|
|
flags := VlanFlag(nad.Uint32())
|
|
v.Flags = &flags
|
|
case 2: // mask (we don't need to store this)
|
|
nad.Uint32()
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
case unix.IFLA_VLAN_EGRESS_QOS:
|
|
ad.Nested(func(nad *netlink.AttributeDecoder) error {
|
|
for nad.Next() {
|
|
if nad.Type() == unix.IFLA_VLAN_QOS_MAPPING {
|
|
var mapping VlanQosMapping
|
|
nad.Nested(func(mad *netlink.AttributeDecoder) error {
|
|
for mad.Next() {
|
|
switch mad.Type() {
|
|
case 1: // from
|
|
mapping.From = mad.Uint32()
|
|
case 2: // to
|
|
mapping.To = mad.Uint32()
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
v.EgressQos = append(v.EgressQos, mapping)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
case unix.IFLA_VLAN_INGRESS_QOS:
|
|
ad.Nested(func(nad *netlink.AttributeDecoder) error {
|
|
for nad.Next() {
|
|
if nad.Type() == unix.IFLA_VLAN_QOS_MAPPING {
|
|
var mapping VlanQosMapping
|
|
nad.Nested(func(mad *netlink.AttributeDecoder) error {
|
|
for mad.Next() {
|
|
switch mad.Type() {
|
|
case 1: // from
|
|
mapping.From = mad.Uint32()
|
|
case 2: // to
|
|
mapping.To = mad.Uint32()
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
v.IngressQos = append(v.IngressQos, mapping)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
}
|
|
|
|
return ad.Err()
|
|
}
|