Skip to content
Draft
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
76 changes: 76 additions & 0 deletions configdb/configdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ type ConfigDB struct {
PortChannels map[string]PortChannel `json:"PORTCHANNEL,omitempty"`
PortChannelMembers map[string]struct{} `json:"PORTCHANNEL_MEMBER,omitempty"`
SAG *SAG `json:"SAG,omitempty"`
SFLOW map[string]SFLOWGlobal `json:"SFLOW,omitempty"`
SFLOWCollector map[string]SFLOWCollector `json:"SFLOW_COLLECTOR,omitempty"`
SFLOWSession map[string]SFLOWSession `json:"SFLOW_SESSION,omitempty"`
VLANs map[string]VLAN `json:"VLAN,omitempty"`
VLANInterfaces map[string]VLANInterface `json:"VLAN_INTERFACE,omitempty"`
VLANMembers map[string]VLANMember `json:"VLAN_MEMBER,omitempty"`
Expand Down Expand Up @@ -80,6 +83,14 @@ func GenerateConfigDB(input *values.Values, platformFile string, environment *p.
}

features := getFeatures(input.Features)
if input.SFLOW != nil && input.SFLOW.Enabled {
if _, ok := features["sflow"]; !ok {
features["sflow"] = Feature{
AutoRestart: FeatureModeEnabled,
State: FeatureModeEnabled,
}
}
}
rules, tables := getACLRulesAndTables(input.SSHSourceranges)
vxlanevpn, vxlanTunnel, vxlanTunnelMap := getVXLAN(input.VTEP, input.LoopbackAddress)

Expand All @@ -88,6 +99,11 @@ func GenerateConfigDB(input *values.Values, platformFile string, environment *p.
return nil, err
}

sflow, sflowCollectors, sflowSessions, err := getSFLOW(input.SFLOW, version)
if err != nil {
return nil, err
}

vlanInterfaces, err := getVLANInterfaces(input.VLANs, version)
if err != nil {
return nil, err
Expand Down Expand Up @@ -131,6 +147,9 @@ func GenerateConfigDB(input *values.Values, platformFile string, environment *p.
PortChannels: getPortChannels(input.PortChannels),
PortChannelMembers: getPortChannelMembers(input.PortChannels.List),
SAG: sag,
SFLOW: sflow,
SFLOWCollector: sflowCollectors,
SFLOWSession: sflowSessions,
VLANs: getVLANs(input.VLANs),
VLANInterfaces: vlanInterfaces,
VLANMembers: getVLANMembers(input.VLANs),
Expand Down Expand Up @@ -546,6 +565,63 @@ func getSAG(sag *values.SAG, version *v.Version) (*SAG, error) {
}, nil
}

func getSFLOW(sflow *values.SFLOW, version *v.Version) (map[string]SFLOWGlobal, map[string]SFLOWCollector, map[string]SFLOWSession, error) {
if sflow == nil || !sflow.Enabled {
return nil, nil, nil, nil
}

for _, c := range sflow.Collectors {
if c.Name == "" {
return nil, nil, nil, fmt.Errorf("sflow collector name must not be empty")
}
if c.IP == "" {
return nil, nil, nil, fmt.Errorf("sflow collector %q: ip must not be empty", c.Name)
}
if c.VRF != "" && version.Branch == string(v.Branch202111) {
return nil, nil, nil, fmt.Errorf("sflow collector %q: collector_vrf is not supported on the ec202111 branch", c.Name)
}
}

pollingInterval := max(sflow.PollingInterval, minimumSFLOWPollingInterval)

global := map[string]SFLOWGlobal{
"global": {
AdminStatus: defaultAdminStatus,
PollingInterval: strconv.Itoa(pollingInterval),
},
}

collectors := make(map[string]SFLOWCollector, len(sflow.Collectors))
for _, c := range sflow.Collectors {
port := defaultSFLOWCollectorPort
if c.Port != 0 {
port = c.Port
}
collectors[c.Name] = SFLOWCollector{
CollectorIP: c.IP,
CollectorPort: strconv.Itoa(port),
CollectorVRF: c.VRF,
}
}

sessions := make(map[string]SFLOWSession, len(sflow.Sessions))
for _, s := range sflow.Sessions {
status := defaultAdminStatus
if s.Enabled != nil && !*s.Enabled {
status = AdminStatusDown
}

session := SFLOWSession{
AdminStatus: status,
}
if s.SampleRate != 0 {
session.SampleRate = strconv.Itoa(s.SampleRate)
}
sessions[s.Interface] = session
}
return global, collectors, sessions, nil
}

func getVLANs(vlans []values.VLAN) map[string]VLAN {
configVLANs := make(map[string]VLAN)

Expand Down
160 changes: 160 additions & 0 deletions configdb/configdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,3 +609,163 @@ func Test_getSAG(t *testing.T) {
})
}
}

func Test_getSFLOW(t *testing.T) {
bFalse := false
version202211 := &v.Version{Branch: string(v.Branch202211)}
version202111 := &v.Version{Branch: string(v.Branch202111)}
tests := []struct {
name string
sflow *values.SFLOW
version *v.Version
wantGlobal map[string]SFLOWGlobal
wantCollector map[string]SFLOWCollector
wantSessions map[string]SFLOWSession
wantErr bool
}{
{
name: "nil input",
sflow: nil,
version: version202211,
},
{
name: "disabled",
sflow: &values.SFLOW{Enabled: false},
version: version202211,
},
{
name: "collector with empty name",
sflow: &values.SFLOW{
Enabled: true,
Collectors: []values.SFLOWCollector{{IP: "172.17.0.1" }},
},
version: version202211,
wantErr: true,
},
{
name: "collector with empty ip",
sflow: &values.SFLOW{
Enabled: true,
Collectors: []values.SFLOWCollector{{Name: "goflow2" }},
},
version: version202211,
wantErr: true,
},
{
name: "enabled with default port",
sflow: &values.SFLOW{
Enabled: true,
PollingInterval: 20,
Collectors: []values.SFLOWCollector{
{Name: "goflow2", IP: "172.17.0.1", VRF: "default" },
},
},
version: version202211,
wantGlobal: map[string]SFLOWGlobal{
"global": {AdminStatus: AdminStatusUp, PollingInterval: "20"},
},
wantCollector: map[string]SFLOWCollector{
"goflow2": {CollectorIP: "172.17.0.1", CollectorPort: "6343", CollectorVRF: "default"},
},
wantSessions: map[string]SFLOWSession{},
},
{
name: "enabled with multiple collectors and sessions",
sflow: &values.SFLOW{
Enabled: true,
PollingInterval: 20,
Collectors: []values.SFLOWCollector{
{Name: "primary", IP: "172.17.0.1", Port: 9999},
{Name: "backup", IP: "172.17.0.1", Port: 6343},
},
Sessions: []values.SFLOWSession{
{Interface: "Ethernet0", SampleRate: 1024},
},
},
version: version202211,
wantGlobal: map[string]SFLOWGlobal{
"global": {AdminStatus: AdminStatusUp, PollingInterval: "20"},
},
wantCollector: map[string]SFLOWCollector{
"primary": {CollectorIP: "172.17.0.1", CollectorPort: "9999"},
"backup": {CollectorIP: "172.17.0.1", CollectorPort: "6343"},
},
wantSessions: map[string]SFLOWSession{
"Ethernet0": {AdminStatus: AdminStatusUp, SampleRate: "1024"},
},
},
{
name: "low polling interval and disabled session",
sflow: &values.SFLOW{
Enabled: true,
PollingInterval: 2,
Sessions: []values.SFLOWSession{
{Interface: "Ethernet0", Enabled: &bFalse},
{Interface: "Ethernet4"},
},
},
version: version202211,
wantGlobal: map[string]SFLOWGlobal{
"global": {AdminStatus: AdminStatusUp, PollingInterval: "5"},
},
wantCollector: map[string]SFLOWCollector{},
wantSessions: map[string]SFLOWSession{
"Ethernet0": {AdminStatus: AdminStatusDown},
"Ethernet4": {AdminStatus: AdminStatusUp},
},
},
{
name: "202111 rejects collector_vrf",
sflow: &values.SFLOW{
Enabled: true,
PollingInterval: 20,
Collectors: []values.SFLOWCollector{
{Name: "goflow2", IP: "172.17.0.1", VRF: "default"},
},
},
version: version202111,
wantErr: true,
},
{
name: "202111 without collector_vrf",
sflow: &values.SFLOW{
Enabled: true,
PollingInterval: 20,
Collectors: []values.SFLOWCollector{
{Name: "goflow2", IP: "172.17.0.1"},
},
Sessions: []values.SFLOWSession{
{Interface: "Ethernet0", SampleRate: 1024},
},
},
version: version202111,
wantGlobal: map[string]SFLOWGlobal{
"global": {AdminStatus: AdminStatusUp, PollingInterval: "20"},
},
wantCollector: map[string]SFLOWCollector{
"goflow2": {CollectorIP: "172.17.0.1", CollectorPort: "6343"},
},
wantSessions: map[string]SFLOWSession{
"Ethernet0": {AdminStatus: AdminStatusUp, SampleRate: "1024"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotGlobal, gotCollectors, gotSessions, err := getSFLOW(tt.sflow, tt.version)
if (err != nil) != tt.wantErr {
t.Errorf("getSFLOW() error = %v, wantErr %v", err, tt.wantErr)
return
}
if diff := cmp.Diff(tt.wantGlobal, gotGlobal); diff != "" {
t.Errorf("getSFLOW() global diff = %s", diff)
}
if diff := cmp.Diff(tt.wantCollector, gotCollectors); diff != "" {
t.Errorf("getSFLOW() collector diff = %s", diff)
}
if diff := cmp.Diff(tt.wantSessions, gotSessions); diff != "" {
t.Errorf("getSFLOW() session diff = %s", diff)
}
})
}
}
21 changes: 21 additions & 0 deletions configdb/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,27 @@ type SAGGlobal struct {
GatewayMAC string `json:"gateway_mac,omitempty"`
}

type SFLOWGlobal struct {
AdminStatus AdminStatus `json:"admin_state,omitempty"`
PollingInterval string `json:"polling_interval,omitempty"`
}

type SFLOWCollector struct {
CollectorIP string `json:"collector_ip"`
CollectorPort string `json:"collector_port"`
CollectorVRF string `json:"collector_vrf,omitempty"`
}

type SFLOWSession struct {
AdminStatus AdminStatus `json:"admin_state"`
SampleRate string `json:"sample_rate,omitempty"`
}

const (
defaultSFLOWCollectorPort int = 6343
minimumSFLOWPollingInterval int = 5
)

type TaggingMode string

const (
Expand Down
62 changes: 62 additions & 0 deletions tests/6/expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"DEVICE_METADATA": {
"localhost": {
"frr_mgmt_framework_config": "false",
"hostname": "leaf-sflow",
"hwsku": "Accton-AS7726-32X",
"mac": "aa:aa:aa:aa:aa:aa",
"platform": "x86_64-accton_as7726_32x-r0",
"type": "LeafRouter"
}
},
"FEATURE": {
"sflow": {
"auto_restart": "enabled",
"state": "enabled"
}
},
"MGMT_PORT": {
"eth0": {
"admin_status": "up",
"alias": "eth0",
"description": "Management Port"
}
},
"MGMT_VRF_CONFIG": {
"vrf_global": {
"mgmtVrfEnabled": "false"
}
},
"NTP": {
"global": {
"src_intf": "eth0"
}
},
"SFLOW": {
"global": {
"admin_state": "up",
"polling_interval": "5"
}
},
"SFLOW_COLLECTOR": {
"collector1": {
"collector_ip": "10.0.0.1",
"collector_port": "6343"
},
"collector2": {
"collector_ip": "10.0.0.2",
"collector_port": "6343",
"collector_vrf": "mgmt"
}
},
"SFLOW_SESSION": {
"Ethernet0": {
"admin_state": "down",
"sample_rate": "1024"
},
"Ethernet4": {
"admin_state": "up",
"sample_rate": "2048"
}
}
}
17 changes: 17 additions & 0 deletions tests/6/sonic-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
hostname: leaf-sflow
sflow:
enabled: true
polling_interval: 2
collectors:
- name: collector1
ip: 10.0.0.1
port: 6343
- name: collector2
ip: 10.0.0.2
vrf: mgmt
sessions:
- interface: Ethernet0
enabled: false
sample_rate: 1024
- interface: Ethernet4
sample_rate: 2048
2 changes: 2 additions & 0 deletions tests/6/sonic-environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PLATFORM=x86_64-accton_as7726_32x-r0
HWSKU=Accton-AS7726-32X
2 changes: 2 additions & 0 deletions tests/6/sonic_version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
branch: 'ec202111'
2 changes: 1 addition & 1 deletion tests/test.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

for i in 1 2 3 4 5
for i in 1 2 3 4 5 6

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for i in 1 2 3 4 5 6
for i in {1..6}

do
test_dir=$(pwd)/tests/$i
docker run --rm --mac-address aa:aa:aa:aa:aa:aa -v $test_dir:/etc/sonic -v $(pwd)/tests/device:/usr/share/sonic/device:ro -v $test_dir:/sonic sonic-configdb-utils:local generate -i /sonic/sonic-config.yaml -o /sonic/config_db.json
Expand Down
Loading
Loading