diff --git a/gnmi_server/server_test.go b/gnmi_server/server_test.go index 7286e749..ab5fc735 100644 --- a/gnmi_server/server_test.go +++ b/gnmi_server/server_test.go @@ -675,6 +675,32 @@ func initFullCountersDb(t *testing.T, namespace string) { } mpi_counter = loadConfig(t, "COUNTERS:oid:0x1500000000091f", countersEeth68_4Byte) loadDB(t, rclient, mpi_counter) + + fileName = "../testdata/COUNTERS_FABRIC_PORT_NAME_MAP.txt" + countersFabricPortNameMapByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_fab_name_map := loadConfig(t, "COUNTERS_FABRIC_PORT_NAME_MAP", countersFabricPortNameMapByte) + loadDB(t, rclient, mpi_fab_name_map) + + // "PORT0": "oid:0x1000000000081" : Fabric port counter, for COUNTERS/PORT0 vpath test + fileName = "../testdata/COUNTERS:oid:0x1000000000081.txt" + countersPort0_Byte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_fab_counter_0 := loadConfig(t, "COUNTERS:oid:0x1000000000081", countersPort0_Byte) + loadDB(t, rclient, mpi_fab_counter_0) + + // "PORT1": "oid:0x1000000000082" : Fabric port counter, for COUNTERS/PORT1 vpath test + fileName = "../testdata/COUNTERS:oid:0x1000000000082.txt" + countersPort1_Byte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_fab_counter_1 := loadConfig(t, "COUNTERS:oid:0x1000000000082", countersPort1_Byte) + loadDB(t, rclient, mpi_fab_counter_1) } func prepareConfigDb(t *testing.T, namespace string) { @@ -741,6 +767,14 @@ func prepareDb(t *testing.T, namespace string) { mpi_qname_map := loadConfig(t, "COUNTERS_QUEUE_NAME_MAP", countersQueueNameMapByte) loadDB(t, rclient, mpi_qname_map) + fileName = "../testdata/COUNTERS_FABRIC_PORT_NAME_MAP.txt" + countersFabricPortNameMapByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_fab_name_map := loadConfig(t, "COUNTERS_FABRIC_PORT_NAME_MAP", countersFabricPortNameMapByte) + loadDB(t, rclient, mpi_fab_name_map) + fileName = "../testdata/COUNTERS:Ethernet68.txt" countersEthernet68Byte, err := ioutil.ReadFile(fileName) if err != nil { @@ -795,6 +829,25 @@ func prepareDb(t *testing.T, namespace string) { mpi_counter = loadConfig(t, "COUNTERS:oid:0x1500000000091f", countersEeth68_4Byte) loadDB(t, rclient, mpi_counter) + // "PORT0": "oid:0x1000000000081" : Fabric port counters, for COUNTERS/PORT0 vpath test + fileName = "../testdata/COUNTERS:oid:0x1000000000081.txt" + fileName = "../testdata/COUNTERS:oid:0x1000000000081.txt" + countersPort0, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_counter = loadConfig(t, "COUNTERS:oid:0x1000000000081", countersPort0) + loadDB(t, rclient, mpi_counter) + + // "PORT1": "oid:0x1000000000082" : Fabric port counter, for COUNTERS/PORT1 vpath test + fileName = "../testdata/COUNTERS:oid:0x1000000000082.txt" + countersPort1_Byte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_counter = loadConfig(t, "COUNTERS:oid:0x1000000000082", countersPort1_Byte) + loadDB(t, rclient, mpi_counter) + // Load CONFIG_DB for alias translation prepareConfigDb(t, namespace) @@ -1333,11 +1386,27 @@ func runGnmiTestGet(t *testing.T, namespace string) { t.Fatalf("read file %v err: %v", fileName, err) } + fileName = "../testdata/COUNTERS:PORT0.txt" + countersFabricPort0Byte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + + fileName = "../testdata/COUNTERS:PORT_wildcard" + namespace + ".txt" + countersFabricPortWildcardByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + stateDBPath := "STATE_DB" ns, _ := sdcfg.GetDbDefaultNamespace() + validFabricPortName := "PORT0" + invalidFabricPortName := "PORT0-" + namespace if namespace != ns { stateDBPath = "STATE_DB" + "/" + namespace + validFabricPortName = "PORT0-" + namespace + invalidFabricPortName = "PORT0" } type testCase struct { @@ -1518,6 +1587,35 @@ func runGnmiTestGet(t *testing.T, namespace string) { valTest: true, wantRetCode: codes.OK, wantRespVal: []byte(`{"test_field": "test_value"}`), + }, { + desc: "get COUNTERS:" + validFabricPortName, + pathTarget: "COUNTERS_DB", + textPbPath: ` + elem: + elem: + `, + wantRetCode: codes.OK, + wantRespVal: countersFabricPort0Byte, + valTest: true, + }, { + desc: "get COUNTERS:PORT*", + pathTarget: "COUNTERS_DB", + textPbPath: ` + elem: + elem: + `, + wantRetCode: codes.OK, + wantRespVal: countersFabricPortWildcardByte, + valTest: true, + }, { + desc: "Invalid fabric port key get" + invalidFabricPortName, + pathTarget: "COUNTERS_DB", + textPbPath: ` + elem: + elem: + `, + wantRetCode: codes.NotFound, + valTest: true, }, { desc: "Invalid DBKey of length 1", pathTarget: stateDBPath, @@ -4834,6 +4932,7 @@ func init() { // Inform gNMI server to use redis tcp localhost connection sdc.UseRedisLocalTcpPort = true + os.Setenv("UNIT_TEST", "1") } func TestMain(m *testing.M) { diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index 13fcacbe..5768bf7b 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -609,6 +609,10 @@ func populateDbtablePath(prefix, path *gnmipb.Path, pathG2S *map[*gnmipb.Path][] if err != nil { log.Errorf("Could not create CountersPfcwdNameMap: %v", err) } + err = initCountersFabricPortNameMap() + if err != nil { + log.Errorf("Could not create CountersFabricPortNameMap: %v", err) + } } diff --git a/sonic_data_client/virtual_db.go b/sonic_data_client/virtual_db.go index ff9bcd28..7f52c7a5 100644 --- a/sonic_data_client/virtual_db.go +++ b/sonic_data_client/virtual_db.go @@ -4,6 +4,7 @@ import ( "fmt" log "github.com/golang/glog" "strings" + "os" ) // virtual db is to Handle @@ -44,6 +45,9 @@ var ( // SONiC interface name to their PFC-WD enabled queues, then to oid map countersPfcwdNameMap = make(map[string]map[string]string) + // SONiC interface name to their Fabric port name map, then to oid map + countersFabricPortNameMap = make(map[string]string) + // path2TFuncTbl is used to populate trie tree which is reponsible // for virtual path to real data path translation pathTransFuncTbl = []pathTransFunc{ @@ -59,6 +63,9 @@ var ( }, { // PFC WD stats for one or all Ethernet ports path: []string{"COUNTERS_DB", "COUNTERS", "Ethernet*", "Pfcwd"}, transFunc: v2rTranslate(v2rEthPortPfcwdStats), + }, { // stats for one or all Fabric ports + path: []string{"COUNTERS_DB", "COUNTERS", "PORT*"}, + transFunc: v2rTranslate(v2rFabricPortStats), }, } ) @@ -107,6 +114,7 @@ func initAliasMap() error { } return nil } + func initCountersPfcwdNameMap() error { var err error if len(countersPfcwdNameMap) == 0 { @@ -118,6 +126,20 @@ func initCountersPfcwdNameMap() error { return nil } +func initCountersFabricPortNameMap() error { + var err error + // Reset map for Unit test to ensure that counters db is updated + // after changing from single to multi-asic config + value := os.Getenv("UNIT_TEST") + if len(countersFabricPortNameMap) == 0 || value == "1" { + countersFabricPortNameMap, err = getFabricCountersMap("COUNTERS_FABRIC_PORT_NAME_MAP") + if err != nil { + return err + } + } + return nil +} + // Get the mapping between sonic interface name and oids of their PFC-WD enabled queues in COUNTERS_DB func GetPfcwdMap() (map[string]map[string]string, error) { var pfcwdName_map = make(map[string]map[string]string) @@ -296,6 +318,89 @@ func getCountersMap(tableName string) (map[string]string, error) { return counter_map, nil } + +// Get the mapping between objects in counters DB, Ex. port name to oid in "COUNTERS_FABRIC_PORT_NAME_MAP" table. +// Aussuming static port name to oid map in COUNTERS table +func getFabricCountersMap(tableName string) (map[string]string, error) { + counter_map := make(map[string]string) + dbName := "COUNTERS_DB" + redis_client_map, err := GetRedisClientsForDb(dbName) + if err != nil { + return nil, err + } + for namespace, redisDb := range redis_client_map { + fv, err := redisDb.HGetAll(tableName).Result() + if err != nil { + log.V(2).Infof("redis HGetAll failed for COUNTERS_DB in namespace %v, tableName: %s", namespace, tableName) + return nil, err + } + namespaceFv := make(map[string]string) + for k, v := range fv { + // Fabric port names are not unique across asic namespace + // To make them unique, add asic namesapce to the port name + // For example, PORT0 in asic0 will be PORT0-asic0 + var namespace_str = "" + if len(namespace) != 0 { + namespace_str = string('-') + namespace + } + namespaceFv[k + namespace_str] = v + } + addmap(counter_map, namespaceFv) + log.V(6).Infof("tableName: %s in namespace %v, map %v", tableName, namespace, namespaceFv) + } + return counter_map, nil +} + +// Populate real data paths from paths like +// [COUNTER_DB COUNTERS PORT*] or [COUNTER_DB COUNTERS PORT0] +func v2rFabricPortStats(paths []string) ([]tablePath, error) { + var tblPaths []tablePath + if strings.HasSuffix(paths[KeyIdx], "*") { // All Ethernet ports + for port, oid := range countersFabricPortNameMap { + var namespace string + // Extract namespace from port name + // multi-asic Linecard ex: PORT0-asic0 + if strings.Contains(port, "-"){ + namespace = strings.Split(port, "-")[1] + } else { + namespace = "" + } + separator, _ := GetTableKeySeparator(paths[DbIdx], namespace) + tblPath := tablePath{ + dbNamespace: namespace, + dbName: paths[DbIdx], + tableName: paths[TblIdx], + tableKey: oid, + delimitor: separator, + jsonTableKey: port, + } + tblPaths = append(tblPaths, tblPath) + } + } else { //single port + var port, namespace string + port = paths[KeyIdx] + oid, ok := countersFabricPortNameMap[port] + if !ok { + return nil, fmt.Errorf("%v not a valid sonic fabric interface.", port) + } + if strings.Contains(port, "-"){ + namespace = strings.Split(port, "-")[1] + } else { + namespace = "" + } + separator, _ := GetTableKeySeparator(paths[DbIdx], namespace) + tblPaths = []tablePath{{ + dbNamespace: namespace, + dbName: paths[DbIdx], + tableName: paths[TblIdx], + tableKey: oid, + delimitor: separator, + }} + } + log.V(6).Infof("v2rFabricPortStats: %v", tblPaths) + return tblPaths, nil +} + // Populate real data paths from paths like // [COUNTER_DB COUNTERS Ethernet*] or [COUNTER_DB COUNTERS Ethernet68] func v2rEthPortStats(paths []string) ([]tablePath, error) { diff --git a/testdata/COUNTERS:PORT0.txt b/testdata/COUNTERS:PORT0.txt new file mode 100644 index 00000000..8cf8d596 --- /dev/null +++ b/testdata/COUNTERS:PORT0.txt @@ -0,0 +1,10 @@ +{ + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "6428", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "1007545", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "16807108", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "3747867283" +} diff --git a/testdata/COUNTERS:PORT_wildcard.txt b/testdata/COUNTERS:PORT_wildcard.txt new file mode 100644 index 00000000..f60c99c4 --- /dev/null +++ b/testdata/COUNTERS:PORT_wildcard.txt @@ -0,0 +1,22 @@ +{ + "PORT0": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "6428", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "1007545", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "16807108", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "3747867283" + }, + "PORT1": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0" + } +} diff --git a/testdata/COUNTERS:PORT_wildcardasic0.txt b/testdata/COUNTERS:PORT_wildcardasic0.txt new file mode 100644 index 00000000..c49e1b28 --- /dev/null +++ b/testdata/COUNTERS:PORT_wildcardasic0.txt @@ -0,0 +1,22 @@ +{ + "PORT0-asic0": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "6428", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "1007545", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "16807108", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "3747867283" + }, + "PORT1-asic0": { + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0" + } +} diff --git a/testdata/COUNTERS:oid:0x1000000000081.txt b/testdata/COUNTERS:oid:0x1000000000081.txt new file mode 100644 index 00000000..8cf8d596 --- /dev/null +++ b/testdata/COUNTERS:oid:0x1000000000081.txt @@ -0,0 +1,10 @@ +{ + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "6428", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "1007545", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "16807108", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "3747867283" +} diff --git a/testdata/COUNTERS:oid:0x1000000000082.txt b/testdata/COUNTERS:oid:0x1000000000082.txt new file mode 100644 index 00000000..aa6d5fe8 --- /dev/null +++ b/testdata/COUNTERS:oid:0x1000000000082.txt @@ -0,0 +1,11 @@ +{ + "SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_FABRIC_DATA_UNITS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0" +} + diff --git a/testdata/COUNTERS_FABRIC_PORT_NAME_MAP.txt b/testdata/COUNTERS_FABRIC_PORT_NAME_MAP.txt new file mode 100644 index 00000000..53077214 --- /dev/null +++ b/testdata/COUNTERS_FABRIC_PORT_NAME_MAP.txt @@ -0,0 +1,4 @@ +{ + "PORT0": "oid:0x1000000000081", + "PORT1": "oid:0x1000000000082" +}