Skip to content

Commit 9dc65df

Browse files
[NX-OS] Define UserCfgdFlags as Bitmask
This change introduces a formal type for the `UserCfgdFlags` used on interface configuration which corresponds to the Bitmask that is used internally to represent this value. Possible options and it's structure can be obtained from: https://pubhub.devnetcloud.com/media/dme-docs-10-4-3/docs/System/l1:PhysIf/
1 parent a174a40 commit 9dc65df

File tree

3 files changed

+91
-14
lines changed

3 files changed

+91
-14
lines changed

internal/provider/cisco/nxos/intf.go

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package nxos
55

66
import (
77
"context"
8+
"encoding/json"
89
"errors"
910
"fmt"
1011
"slices"
@@ -62,7 +63,7 @@ const (
6263
// PhysIf represents a physical (ethernet) interface on a NX-OS device.
6364
type PhysIf struct {
6465
AccessVlan string `json:"accessVlan"`
65-
AdminSt AdminSt2 `json:"adminSt"`
66+
AdminSt AdminSt2 `json:"adminSt,omitempty"`
6667
Descr string `json:"descr"`
6768
ID string `json:"id"`
6869
Layer Layer `json:"layer"`
@@ -71,7 +72,7 @@ type PhysIf struct {
7172
Mode SwitchportMode `json:"mode"`
7273
NativeVlan string `json:"nativeVlan"`
7374
TrunkVlans string `json:"trunkVlans"`
74-
UserCfgdFlags string `json:"userCfgdFlags"`
75+
UserCfgdFlags UserFlags `json:"userCfgdFlags"`
7576
RtvrfMbrItems *VrfMember `json:"rtvrfMbr-items,omitempty"`
7677
}
7778

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

9192
func (p *PhysIf) Default() {
9293
p.AccessVlan = DefaultVLAN
93-
p.AdminSt = AdminStDown
9494
p.Layer = Layer2
9595
p.MTU = DefaultMTU
9696
p.Medium = MediumBroadcast
9797
p.Mode = SwitchportModeAccess
9898
p.NativeVlan = DefaultVLAN
9999
p.TrunkVlans = DefaultVLANRange
100-
p.UserCfgdFlags = "admin_state"
101100
}
102101

103102
type PhysIfOperItems struct {
@@ -157,7 +156,7 @@ type PortChannel struct {
157156
PcMode PortChannelMode `json:"pcMode"`
158157
NativeVlan string `json:"nativeVlan"`
159158
TrunkVlans string `json:"trunkVlans"`
160-
UserCfgdFlags string `json:"userCfgdFlags"`
159+
UserCfgdFlags UserFlags `json:"userCfgdFlags"`
161160
RsmbrIfsItems struct {
162161
RsMbrIfsList gnmiext.List[string, *PortChannelMember] `json:"RsMbrIfs-list,omitzero"`
163162
} `json:"rsmbrIfs-items,omitzero"`
@@ -478,3 +477,83 @@ const (
478477
PortChannelModeActive PortChannelMode = "active"
479478
PortChannelModePassive PortChannelMode = "passive"
480479
)
480+
481+
// UserFlags represents the user configured flags for an interface.
482+
// It supports a combination of the following flags:
483+
// 1 - admin_state
484+
// 2 - admin_layer
485+
// 4 - admin_router_mac
486+
// 8 - admin_dce_mode
487+
// 16 - admin_mtu
488+
type UserFlags uint8
489+
490+
const (
491+
UserFlagAdminState UserFlags = 1 << iota
492+
UserFlagAdminLayer
493+
UserFlagAdminRouterMac
494+
UserFlagAdminDceMode
495+
UserFlagAdminMTU
496+
)
497+
498+
var (
499+
_ fmt.Stringer = UserFlags(0)
500+
_ json.Marshaler = UserFlags(0)
501+
_ json.Unmarshaler = (*UserFlags)(nil)
502+
)
503+
504+
// UnmarshalJSON implements json.Unmarshaler.
505+
func (f *UserFlags) UnmarshalJSON([]byte) error {
506+
var s string
507+
if err := json.Unmarshal([]byte(s), &s); err != nil {
508+
return err
509+
}
510+
511+
var flags UserFlags
512+
for flag := range strings.SplitSeq(s, ",") {
513+
switch strings.TrimSpace(flag) {
514+
case "admin_state":
515+
flags |= UserFlagAdminState
516+
case "admin_layer":
517+
flags |= UserFlagAdminLayer
518+
case "admin_router_mac":
519+
flags |= UserFlagAdminRouterMac
520+
case "admin_dce_mode":
521+
flags |= UserFlagAdminDceMode
522+
case "admin_mtu":
523+
flags |= UserFlagAdminMTU
524+
case "":
525+
// ignore empty flag
526+
default:
527+
return fmt.Errorf("interface: unknown user flag %q", flag)
528+
}
529+
}
530+
*f = flags
531+
return nil
532+
}
533+
534+
// MarshalJSON implements json.Marshaler.
535+
func (f UserFlags) MarshalJSON() ([]byte, error) {
536+
return json.Marshal(f.String())
537+
}
538+
539+
// String implements fmt.Stringer.
540+
func (f UserFlags) String() string {
541+
var flags []string
542+
if f&UserFlagAdminState != 0 {
543+
flags = append(flags, "admin_state")
544+
}
545+
if f&UserFlagAdminLayer != 0 {
546+
flags = append(flags, "admin_layer")
547+
}
548+
if f&UserFlagAdminRouterMac != 0 {
549+
flags = append(flags, "admin_router_mac")
550+
}
551+
if f&UserFlagAdminDceMode != 0 {
552+
flags = append(flags, "admin_dce_mode")
553+
}
554+
if f&UserFlagAdminMTU != 0 {
555+
flags = append(flags, "admin_mtu")
556+
}
557+
slices.Sort(flags)
558+
return strings.Join(flags, ",")
559+
}

internal/provider/cisco/nxos/intf_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func init() {
2222
AccessVlan: DefaultVLAN,
2323
NativeVlan: DefaultVLAN,
2424
TrunkVlans: DefaultVLANRange,
25-
UserCfgdFlags: "admin_layer,admin_mtu,admin_state",
25+
UserCfgdFlags: UserFlagAdminState | UserFlagAdminLayer | UserFlagAdminMTU,
2626
})
2727

2828
Register("physif_switchport", &PhysIf{
@@ -35,7 +35,7 @@ func init() {
3535
AccessVlan: DefaultVLAN,
3636
NativeVlan: DefaultVLAN,
3737
TrunkVlans: "10",
38-
UserCfgdFlags: "admin_state",
38+
UserCfgdFlags: UserFlagAdminState,
3939
})
4040

4141
intfAddr4 := &AddrItem{ID: "lo0", Vrf: DefaultVRFName}
@@ -57,7 +57,7 @@ func init() {
5757
PcMode: PortChannelModeActive,
5858
NativeVlan: DefaultVLAN,
5959
TrunkVlans: "10",
60-
UserCfgdFlags: "admin_state",
60+
UserCfgdFlags: UserFlagAdminState,
6161
}
6262
pc.RsmbrIfsItems.RsMbrIfsList.Set(NewPortChannelMember("eth1/10"))
6363
Register("pc", pc)

internal/provider/cisco/nxos/provider.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -641,15 +641,15 @@ func (p *Provider) EnsureInterface(ctx context.Context, req *provider.EnsureInte
641641
if req.Interface.Spec.AdminState == v1alpha1.AdminStateUp {
642642
p.AdminSt = AdminStUp
643643
}
644+
p.UserCfgdFlags = UserFlagAdminState | UserFlagAdminLayer
644645
// TODO: If the interface is a member of a port-channel, do the following:
645646
// 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.
646647
// 2) If the mtu on the port-channel differs from the mtu on the physical interface, return an error.
647648
// 3) If the mtu has not been explicitly configured on the port-channel, do not adopt the "admin_mtu" flag.
648649
if req.Interface.Spec.MTU != 0 {
649650
p.MTU = req.Interface.Spec.MTU
650-
p.UserCfgdFlags = "admin_mtu," + p.UserCfgdFlags
651+
p.UserCfgdFlags |= UserFlagAdminMTU
651652
}
652-
p.UserCfgdFlags = "admin_layer," + p.UserCfgdFlags
653653
if req.IPv4 != nil {
654654
p.Layer = Layer3
655655
}
@@ -723,16 +723,14 @@ func (p *Provider) EnsureInterface(ctx context.Context, req *provider.EnsureInte
723723
pc.AccessVlan = DefaultVLAN
724724
pc.NativeVlan = DefaultVLAN
725725
pc.TrunkVlans = DefaultVLANRange
726-
pc.UserCfgdFlags = "admin_state"
726+
pc.UserCfgdFlags = UserFlagAdminState | UserFlagAdminLayer
727727

728728
pc.MTU = DefaultMTU
729729
if req.Interface.Spec.MTU != 0 {
730730
pc.MTU = req.Interface.Spec.MTU
731-
pc.UserCfgdFlags = "admin_mtu," + pc.UserCfgdFlags
731+
pc.UserCfgdFlags |= UserFlagAdminMTU
732732
}
733733

734-
pc.UserCfgdFlags = "admin_layer," + pc.UserCfgdFlags
735-
736734
pc.PcMode = PortChannelModeActive
737735
switch m := req.Interface.Spec.Aggregation.ControlProtocol.Mode; m {
738736
case v1alpha1.LACPModeActive:

0 commit comments

Comments
 (0)