Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 83 additions & 4 deletions internal/provider/cisco/nxos/intf.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package nxos

import (
"context"
"encoding/json"
"errors"
"fmt"
"slices"
Expand Down Expand Up @@ -71,7 +72,7 @@ type PhysIf struct {
Mode SwitchportMode `json:"mode"`
NativeVlan string `json:"nativeVlan"`
TrunkVlans string `json:"trunkVlans"`
UserCfgdFlags string `json:"userCfgdFlags"`
UserCfgdFlags UserFlags `json:"userCfgdFlags"`
RtvrfMbrItems *VrfMember `json:"rtvrfMbr-items,omitempty"`
}

Expand All @@ -90,14 +91,12 @@ func (p *PhysIf) Validate() error {

func (p *PhysIf) Default() {
p.AccessVlan = DefaultVLAN
p.AdminSt = AdminStDown
p.Layer = Layer2
p.MTU = DefaultMTU
p.Medium = MediumBroadcast
p.Mode = SwitchportModeAccess
p.NativeVlan = DefaultVLAN
p.TrunkVlans = DefaultVLANRange
p.UserCfgdFlags = "admin_state"
}

type PhysIfOperItems struct {
Expand Down Expand Up @@ -157,7 +156,7 @@ type PortChannel struct {
PcMode PortChannelMode `json:"pcMode"`
NativeVlan string `json:"nativeVlan"`
TrunkVlans string `json:"trunkVlans"`
UserCfgdFlags string `json:"userCfgdFlags"`
UserCfgdFlags UserFlags `json:"userCfgdFlags"`
RsmbrIfsItems struct {
RsMbrIfsList gnmiext.List[string, *PortChannelMember] `json:"RsMbrIfs-list,omitzero"`
} `json:"rsmbrIfs-items,omitzero"`
Expand Down Expand Up @@ -472,3 +471,83 @@ const (
PortChannelModeActive PortChannelMode = "active"
PortChannelModePassive PortChannelMode = "passive"
)

// UserFlags represents the user configured flags for an interface.
// It supports a combination of the following flags:
// 1 - admin_state
// 2 - admin_layer
// 4 - admin_router_mac
// 8 - admin_dce_mode
// 16 - admin_mtu
type UserFlags uint8

const (
UserFlagAdminState UserFlags = 1 << iota
UserFlagAdminLayer
UserFlagAdminRouterMac
UserFlagAdminDceMode
UserFlagAdminMTU
)

var (
_ fmt.Stringer = UserFlags(0)
_ json.Marshaler = UserFlags(0)
_ json.Unmarshaler = (*UserFlags)(nil)
)

// UnmarshalJSON implements json.Unmarshaler.
func (f *UserFlags) UnmarshalJSON([]byte) error {
var s string
if err := json.Unmarshal([]byte(s), &s); err != nil {
return err
}

var flags UserFlags
for flag := range strings.SplitSeq(s, ",") {
switch strings.TrimSpace(flag) {
case "admin_state":
flags |= UserFlagAdminState
case "admin_layer":
flags |= UserFlagAdminLayer
case "admin_router_mac":
flags |= UserFlagAdminRouterMac
case "admin_dce_mode":
flags |= UserFlagAdminDceMode
case "admin_mtu":
flags |= UserFlagAdminMTU
case "":
// ignore empty flag
default:
return fmt.Errorf("interface: unknown user flag %q", flag)
}
}
*f = flags
return nil
}

// MarshalJSON implements json.Marshaler.
func (f UserFlags) MarshalJSON() ([]byte, error) {
return json.Marshal(f.String())
}

// String implements fmt.Stringer.
func (f UserFlags) String() string {
var flags []string
if f&UserFlagAdminState != 0 {
flags = append(flags, "admin_state")
}
if f&UserFlagAdminLayer != 0 {
flags = append(flags, "admin_layer")
}
if f&UserFlagAdminRouterMac != 0 {
flags = append(flags, "admin_router_mac")
}
if f&UserFlagAdminDceMode != 0 {
flags = append(flags, "admin_dce_mode")
}
if f&UserFlagAdminMTU != 0 {
flags = append(flags, "admin_mtu")
}
slices.Sort(flags)
return strings.Join(flags, ",")
}
6 changes: 3 additions & 3 deletions internal/provider/cisco/nxos/intf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func init() {
AccessVlan: DefaultVLAN,
NativeVlan: DefaultVLAN,
TrunkVlans: DefaultVLANRange,
UserCfgdFlags: "admin_layer,admin_mtu,admin_state",
UserCfgdFlags: UserFlagAdminState | UserFlagAdminLayer | UserFlagAdminMTU,
})

Register("physif_switchport", &PhysIf{
Expand All @@ -35,7 +35,7 @@ func init() {
AccessVlan: DefaultVLAN,
NativeVlan: DefaultVLAN,
TrunkVlans: "10",
UserCfgdFlags: "admin_state",
UserCfgdFlags: UserFlagAdminState,
})

intfAddr4 := &AddrItem{ID: "lo0", Vrf: DefaultVRFName}
Expand All @@ -57,7 +57,7 @@ func init() {
PcMode: PortChannelModeActive,
NativeVlan: DefaultVLAN,
TrunkVlans: "10",
UserCfgdFlags: "admin_state",
UserCfgdFlags: UserFlagAdminState,
}
pc.RsmbrIfsItems.RsMbrIfsList.Set(NewPortChannelMember("eth1/10"))
Register("pc", pc)
Expand Down
10 changes: 4 additions & 6 deletions internal/provider/cisco/nxos/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -641,15 +641,15 @@ func (p *Provider) EnsureInterface(ctx context.Context, req *provider.EnsureInte
if req.Interface.Spec.AdminState == v1alpha1.AdminStateUp {
p.AdminSt = AdminStUp
}
p.UserCfgdFlags = UserFlagAdminState | UserFlagAdminLayer
// TODO: If the interface is a member of a port-channel, do the following:
// 1) If the mtu has been explicitly configured on the port-channel and matches the mtu on the physical interface, adopt the "admin_mtu" flag.
// 2) If the mtu on the port-channel differs from the mtu on the physical interface, return an error.
// 3) If the mtu has not been explicitly configured on the port-channel, do not adopt the "admin_mtu" flag.
if req.Interface.Spec.MTU != 0 {
p.MTU = req.Interface.Spec.MTU
p.UserCfgdFlags = "admin_mtu," + p.UserCfgdFlags
p.UserCfgdFlags |= UserFlagAdminMTU
}
p.UserCfgdFlags = "admin_layer," + p.UserCfgdFlags
if req.IPv4 != nil {
p.Layer = Layer3
}
Expand Down Expand Up @@ -723,16 +723,14 @@ func (p *Provider) EnsureInterface(ctx context.Context, req *provider.EnsureInte
pc.AccessVlan = DefaultVLAN
pc.NativeVlan = DefaultVLAN
pc.TrunkVlans = DefaultVLANRange
pc.UserCfgdFlags = "admin_state"
pc.UserCfgdFlags = UserFlagAdminState | UserFlagAdminLayer

pc.MTU = DefaultMTU
if req.Interface.Spec.MTU != 0 {
pc.MTU = req.Interface.Spec.MTU
pc.UserCfgdFlags = "admin_mtu," + pc.UserCfgdFlags
pc.UserCfgdFlags |= UserFlagAdminMTU
}

pc.UserCfgdFlags = "admin_layer," + pc.UserCfgdFlags

pc.PcMode = PortChannelModeActive
switch m := req.Interface.Spec.Aggregation.ControlProtocol.Mode; m {
case v1alpha1.LACPModeActive:
Expand Down
Loading