From 43a8fcde53203efa3c0002dea04e45b674fd1a5b Mon Sep 17 00:00:00 2001 From: Chang Liu Date: Wed, 5 Sep 2018 13:24:34 -0700 Subject: [PATCH 01/20] Add feature to support query for PFC watchdog --- dialout/dialout_client/dialout_client_test.go | 8 + gnmi_server/server_test.go | 866 ++++++++++++------ sonic_data_client/db_client.go | 4 + sonic_data_client/virtual_db.go | 173 +++- testdata/CONFIG_PFCWD_PORTS.txt | 171 ++++ testdata/COUNTERS:Ethernet68:Pfcwd.txt | 36 + testdata/COUNTERS:Ethernet68:Pfcwd_alias.txt | 36 + testdata/COUNTERS:Ethernet68:Queues.txt | 84 +- testdata/COUNTERS:Ethernet68:Queues_alias.txt | 36 +- ...COUNTERS:Ethernet_wildcard_Pfcwd_alias.txt | 142 +++ ...OUNTERS:Ethernet_wildcard_Queues_alias.txt | 36 +- testdata/COUNTERS:oid:0x1500000000091e.txt | 17 + testdata/COUNTERS:oid:0x1500000000091f.txt | 17 + 13 files changed, 1295 insertions(+), 331 deletions(-) create mode 100644 testdata/CONFIG_PFCWD_PORTS.txt create mode 100644 testdata/COUNTERS:Ethernet68:Pfcwd.txt create mode 100644 testdata/COUNTERS:Ethernet68:Pfcwd_alias.txt create mode 100644 testdata/COUNTERS:Ethernet_wildcard_Pfcwd_alias.txt create mode 100644 testdata/COUNTERS:oid:0x1500000000091e.txt create mode 100644 testdata/COUNTERS:oid:0x1500000000091f.txt diff --git a/dialout/dialout_client/dialout_client_test.go b/dialout/dialout_client/dialout_client_test.go index 22c857b57..b94963be0 100644 --- a/dialout/dialout_client/dialout_client_test.go +++ b/dialout/dialout_client/dialout_client_test.go @@ -166,6 +166,14 @@ func prepareConfigDb(t *testing.T) { } mpi_alias_map := loadConfig(t, "", countersPortAliasMapByte) loadConfigDB(t, rclient, mpi_alias_map) + + fileName = "../../testdata/CONFIG_PFCWD_PORTS.txt" + configPfcwdByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_pfcwd_map := loadConfig(t, "", configPfcwdByte) + loadConfigDB(t, rclient, mpi_pfcwd_map) } func prepareDb(t *testing.T) { diff --git a/gnmi_server/server_test.go b/gnmi_server/server_test.go index 8858a2efc..100df8c6e 100644 --- a/gnmi_server/server_test.go +++ b/gnmi_server/server_test.go @@ -212,6 +212,14 @@ func prepareConfigDb(t *testing.T) { } mpi_alias_map := loadConfig(t, "", countersPortAliasMapByte) loadConfigDB(t, rclient, mpi_alias_map) + + fileName = "../testdata/CONFIG_PFCWD_PORTS.txt" + configPfcwdByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_pfcwd_map := loadConfig(t, "", configPfcwdByte) + loadConfigDB(t, rclient, mpi_pfcwd_map) } func prepareDb(t *testing.T) { @@ -278,6 +286,24 @@ func prepareDb(t *testing.T) { mpi_counter = loadConfig(t, "COUNTERS:oid:0x1500000000091c", countersEeth68_1Byte) loadDB(t, rclient, mpi_counter) + // "Ethernet68:3": "oid:0x1500000000091e" : lossless queue counter, for COUNTERS/Ethernet68/Pfcwd vpath test + fileName = "../testdata/COUNTERS:oid:0x1500000000091e.txt" + countersEeth68_3Byte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_counter = loadConfig(t, "COUNTERS:oid:0x1500000000091e", countersEeth68_3Byte) + loadDB(t, rclient, mpi_counter) + + // "Ethernet68:4": "oid:0x1500000000091f" : lossless queue counter, for COUNTERS/Ethernet68/Pfcwd vpath test + fileName = "../testdata/COUNTERS:oid:0x1500000000091f.txt" + countersEeth68_4Byte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + mpi_counter = loadConfig(t, "COUNTERS:oid:0x1500000000091f", countersEeth68_4Byte) + loadDB(t, rclient, mpi_counter) + // Load CONFIG_DB for alias translation prepareConfigDb(t) } @@ -317,6 +343,18 @@ func TestGnmiGet(t *testing.T) { t.Fatalf("read file %v err: %v", fileName, err) } + fileName = "../testdata/COUNTERS:Ethernet68:Pfcwd.txt" + countersEthernet68PfcwdByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + + fileName = "../testdata/COUNTERS:Ethernet68:Pfcwd_alias.txt" + countersEthernet68PfcwdAliasByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + fileName = "../testdata/COUNTERS:Ethernet_wildcard_alias.txt" countersEthernetWildcardByte, err := ioutil.ReadFile(fileName) if err != nil { @@ -329,6 +367,12 @@ func TestGnmiGet(t *testing.T) { t.Fatalf("read file %v err: %v", fileName, err) } + fileName = "../testdata/COUNTERS:Ethernet_wildcard_Pfcwd_alias.txt" + countersEthernetWildcardPfcwdByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + tds := []struct { desc string pathTarget string @@ -383,6 +427,16 @@ func TestGnmiGet(t *testing.T) { `, wantRetCode: codes.OK, wantRespVal: "2", + }, { + desc: "get COUNTERS:Ethernet68 Pfcwd", + pathTarget: "COUNTERS_DB", + textPbPath: ` + elem: + elem: + elem: + `, + wantRetCode: codes.OK, + wantRespVal: countersEthernet68PfcwdByte, }, { desc: "get COUNTERS (use vendor alias):Ethernet68/1", pathTarget: "COUNTERS_DB", @@ -402,6 +456,16 @@ func TestGnmiGet(t *testing.T) { `, wantRetCode: codes.OK, wantRespVal: "2", + }, { + desc: "get COUNTERS (use vendor alias):Ethernet68/1 Pfcwd", + pathTarget: "COUNTERS_DB", + textPbPath: ` + elem: + elem: + elem: + `, + wantRetCode: codes.OK, + wantRespVal: countersEthernet68PfcwdAliasByte, }, { desc: "get COUNTERS:Ethernet*", pathTarget: "COUNTERS_DB", @@ -421,6 +485,16 @@ func TestGnmiGet(t *testing.T) { `, wantRetCode: codes.OK, wantRespVal: countersEthernetWildcardPfcByte, + }, { + desc: "get COUNTERS:Ethernet* Pfcwd", + pathTarget: "COUNTERS_DB", + textPbPath: ` + elem: + elem: + elem: + `, + wantRetCode: codes.OK, + wantRespVal: countersEthernetWildcardPfcwdByte, }} for _, td := range tds { @@ -476,6 +550,42 @@ func runTestSubscribe(t *testing.T) { // field SAI_PORT_STAT_PFC_7_RX_PKTS has new value of 4 countersEthernet68JsonPfcUpdate["SAI_PORT_STAT_PFC_7_RX_PKTS"] = "4" + // for Ethernet68/Pfcwd subscription + fileName = "../testdata/COUNTERS:Ethernet68:Pfcwd.txt" + countersEthernet68PfcwdByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + var countersEthernet68PfcwdJson interface{} + json.Unmarshal(countersEthernet68PfcwdByte, &countersEthernet68PfcwdJson) + + var tmp4 interface{} + json.Unmarshal(countersEthernet68PfcwdByte, &tmp4) + countersEthernet68PfcwdJsonUpdate := map[string]interface{}{} + countersEthernet68PfcwdJsonUpdate["Ethernet68:3"] = tmp4.(map[string]interface{})["Ethernet68:3"] + countersEthernet68PfcwdJsonUpdate["Ethernet68:3"].(map[string]interface{})["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "1" + + tmp4.(map[string]interface{})["Ethernet68:3"].(map[string]interface{})["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "1" + countersEthernet68PfcwdPollUpdate := tmp4 + + // (use vendor alias) for Ethernet68/1 Pfcwd subscription + fileName = "../testdata/COUNTERS:Ethernet68:Pfcwd_alias.txt" + countersEthernet68PfcwdAliasByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + var countersEthernet68PfcwdAliasJson interface{} + json.Unmarshal(countersEthernet68PfcwdAliasByte, &countersEthernet68PfcwdAliasJson) + + var tmp5 interface{} + json.Unmarshal(countersEthernet68PfcwdAliasByte, &tmp5) + countersEthernet68PfcwdAliasJsonUpdate := map[string]interface{}{} + countersEthernet68PfcwdAliasJsonUpdate["Ethernet68/1:3"] = tmp5.(map[string]interface{})["Ethernet68/1:3"] + countersEthernet68PfcwdAliasJsonUpdate["Ethernet68/1:3"].(map[string]interface{})["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "1" + + tmp5.(map[string]interface{})["Ethernet68/1:3"].(map[string]interface{})["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "1" + countersEthernet68PfcwdAliasPollUpdate := tmp5 + fileName = "../testdata/COUNTERS:Ethernet_wildcard_alias.txt" countersEthernetWildcardByte, err := ioutil.ReadFile(fileName) if err != nil { @@ -508,6 +618,21 @@ func runTestSubscribe(t *testing.T) { //allPortPfcJsonUpdate := countersEthernetWildcardPfcJson.(map[string]interface{}) allPortPfcJsonUpdate["Ethernet68/1"] = pfc7Map + // for Ethernet*/Pfcwd subscription + fileName = "../testdata/COUNTERS:Ethernet_wildcard_Pfcwd_alias.txt" + countersEthernetWildPfcwdByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + + var countersEthernetWildPfcwdJson interface{} + json.Unmarshal(countersEthernetWildPfcwdByte, &countersEthernetWildPfcwdJson) + + var tmp6 interface{} + json.Unmarshal(countersEthernetWildPfcwdByte, &tmp6) + tmp6.(map[string]interface{})["Ethernet68/1:3"].(map[string]interface{})["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "1" + countersEthernetWildPfcwdUpdate := tmp6 + fileName = "../testdata/COUNTERS:Ethernet_wildcard_Queues_alias.txt" countersEthernetWildQueuesByte, err := ioutil.ReadFile(fileName) if err != nil { @@ -694,331 +819,498 @@ func runTestSubscribe(t *testing.T) { client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, TS: time.Unix(0, 200), Val: "3"}, }, }, { - desc: "stream query for table key Ethernet* with new test_field field on Ethernet68", + desc: "stream query for COUNTERS/Ethernet68/Pfcwd with update of filed value", q: client.Query{ Target: "COUNTERS_DB", Type: client.Stream, - Queries: []client.Path{{"COUNTERS", "Ethernet*"}}, + Queries: []client.Path{{"COUNTERS", "Ethernet68", "Pfcwd"}}, TLS: &tls.Config{InsecureSkipVerify: true}, }, updates: []tablePathValue{{ dbName: "COUNTERS_DB", tableName: "COUNTERS", - tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + tableKey: "oid:0x1500000000091e", // "Ethernet68:3": "oid:0x1500000000091e", delimitor: ":", - field: "test_field", - value: "test_value", + field: "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", + value: "1", // be changed to 1 from 0 }, { //Same value set should not trigger multiple updates dbName: "COUNTERS_DB", tableName: "COUNTERS", - tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + tableKey: "oid:0x1500000000091e", // "Ethernet68:3": "oid:0x1500000000091e" delimitor: ":", - field: "test_field", - value: "test_value", + field: "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", + value: "1", // be changed to 1 from 1 }}, wantNoti: []client.Notification{ client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*"}, - TS: time.Unix(0, 200), Val: countersEthernetWildcardJson}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdJson}, client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*"}, - TS: time.Unix(0, 200), Val: countersEtherneWildcardJsonUpdate}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdJsonUpdate}, }, }, { - desc: "stream query for table key Ethernet*/SAI_PORT_STAT_PFC_7_RX_PKTS with field value update", + desc: "(use vendor alias) stream query for COUNTERS/[Ethernet68/1]/Pfcwd with update of filed value", q: client.Query{ Target: "COUNTERS_DB", Type: client.Stream, - Queries: []client.Path{{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}}, - TLS: &tls.Config{InsecureSkipVerify: true}, - }, - updates: []tablePathValue{{ - dbName: "COUNTERS_DB", - tableName: "COUNTERS", - tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", - delimitor: ":", - field: "SAI_PORT_STAT_PFC_7_RX_PKTS", - value: "4", // being changed to 4 from 2 - }}, - wantNoti: []client.Notification{ - client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: countersEthernetWildcardPfcJson}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: singlePortPfcJsonUpdate}, - }, - }, { - desc: "poll query for table COUNTERS_PORT_NAME_MAP with new field test_field", - poll: 3, - q: client.Query{ - Target: "COUNTERS_DB", - Type: client.Poll, - Queries: []client.Path{{"COUNTERS_PORT_NAME_MAP"}}, - TLS: &tls.Config{InsecureSkipVerify: true}, - }, - updates: []tablePathValue{{ - dbName: "COUNTERS_DB", - tableName: "COUNTERS_PORT_NAME_MAP", - field: "test_field", - value: "test_value", - }}, - wantNoti: []client.Notification{ - client.Connected{}, - // We are starting from the result data of "stream query for table with update of new field", - client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJson}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJsonUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJsonUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJsonUpdate}, - client.Sync{}, - }, - }, { - desc: "poll query for table COUNTERS_PORT_NAME_MAP with test_field delete", - poll: 3, - q: client.Query{ - Target: "COUNTERS_DB", - Type: client.Poll, - Queries: []client.Path{{"COUNTERS_PORT_NAME_MAP"}}, - TLS: &tls.Config{InsecureSkipVerify: true}, - }, - prepares: []tablePathValue{{ - dbName: "COUNTERS_DB", - tableName: "COUNTERS_PORT_NAME_MAP", - field: "test_field", - value: "test_value", - }}, - updates: []tablePathValue{{ - dbName: "COUNTERS_DB", - tableName: "COUNTERS_PORT_NAME_MAP", - field: "test_field", - op: "hdel", - }}, - wantNoti: []client.Notification{ - client.Connected{}, - // We are starting from the result data of "stream query for table with update of new field", - client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJsonUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJson}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJson}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJson}, - client.Sync{}, - }, - }, { - desc: "poll query for COUNTERS/Ethernet68/SAI_PORT_STAT_PFC_7_RX_PKTS with field value change", - poll: 3, - q: client.Query{ - Target: "COUNTERS_DB", - Type: client.Poll, - Queries: []client.Path{{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}}, + Queries: []client.Path{{"COUNTERS", "Ethernet68/1", "Pfcwd"}}, TLS: &tls.Config{InsecureSkipVerify: true}, }, updates: []tablePathValue{{ dbName: "COUNTERS_DB", tableName: "COUNTERS", - tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + tableKey: "oid:0x1500000000091e", // "Ethernet68:3": "oid:0x1500000000091e", delimitor: ":", - field: "SAI_PORT_STAT_PFC_7_RX_PKTS", - value: "4", // being changed to 4 from 2 - }}, - wantNoti: []client.Notification{ - client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: "2"}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: "4"}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: "4"}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: "4"}, - client.Sync{}, - }, - }, { - desc: "(use vendor alias) poll query for COUNTERS/[Ethernet68/1]/SAI_PORT_STAT_PFC_7_RX_PKTS with field value change", - poll: 3, - q: client.Query{ - Target: "COUNTERS_DB", - Type: client.Poll, - Queries: []client.Path{{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}}, - TLS: &tls.Config{InsecureSkipVerify: true}, - }, - updates: []tablePathValue{{ - dbName: "COUNTERS_DB", - tableName: "COUNTERS", - tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", - delimitor: ":", - field: "SAI_PORT_STAT_PFC_7_RX_PKTS", - value: "4", // being changed to 4 from 2 - }}, - wantNoti: []client.Notification{ - client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: "2"}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: "4"}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: "4"}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: "4"}, - client.Sync{}, - }, - }, { - desc: "poll query for table key Ethernet* with Ethernet68/SAI_PORT_STAT_PFC_7_RX_PKTS field value change", - poll: 3, - q: client.Query{ - Target: "COUNTERS_DB", - Type: client.Poll, - Queries: []client.Path{{"COUNTERS", "Ethernet*"}}, - TLS: &tls.Config{InsecureSkipVerify: true}, - }, - updates: []tablePathValue{{ - dbName: "COUNTERS_DB", - tableName: "COUNTERS", - tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", - delimitor: ":", - field: "SAI_PORT_STAT_PFC_7_RX_PKTS", - value: "4", // being changed to 4 from 2 - }}, - wantNoti: []client.Notification{ - client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*"}, - TS: time.Unix(0, 200), Val: countersEthernetWildcardJson}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*"}, - TS: time.Unix(0, 200), Val: countersFieldUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*"}, - TS: time.Unix(0, 200), Val: countersFieldUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*"}, - TS: time.Unix(0, 200), Val: countersFieldUpdate}, - client.Sync{}, - }, - }, { - desc: "poll query for table key field Ethernet*/SAI_PORT_STAT_PFC_7_RX_PKTS with Ethernet68/SAI_PORT_STAT_PFC_7_RX_PKTS field value change", - poll: 3, - q: client.Query{ - Target: "COUNTERS_DB", - Type: client.Poll, - Queries: []client.Path{{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}}, - TLS: &tls.Config{InsecureSkipVerify: true}, - }, - updates: []tablePathValue{{ - dbName: "COUNTERS_DB", - tableName: "COUNTERS", - tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", - delimitor: ":", - field: "SAI_PORT_STAT_PFC_7_RX_PKTS", - value: "4", // being changed to 4 from 2 - }}, - wantNoti: []client.Notification{ - client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: countersEthernetWildcardPfcJson}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: allPortPfcJsonUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: allPortPfcJsonUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, - TS: time.Unix(0, 200), Val: allPortPfcJsonUpdate}, - client.Sync{}, - }, - }, { - desc: "poll query for COUNTERS/Ethernet*/Queues", - poll: 1, - q: client.Query{ - Target: "COUNTERS_DB", - Type: client.Poll, - Queries: []client.Path{{"COUNTERS", "Ethernet*", "Queues"}}, - TLS: &tls.Config{InsecureSkipVerify: true}, - }, - wantNoti: []client.Notification{ - client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernetWildQueuesJson}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet*", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernetWildQueuesJson}, - client.Sync{}, - }, - }, { - desc: "poll query for COUNTERS/Ethernet68/Queues with field value change", - poll: 3, - q: client.Query{ - Target: "COUNTERS_DB", - Type: client.Poll, - Queries: []client.Path{{"COUNTERS", "Ethernet68", "Queues"}}, - TLS: &tls.Config{InsecureSkipVerify: true}, - }, - updates: []tablePathValue{{ + field: "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", + value: "1", // be changed to 1 from 0 + }, { //Same value set should not trigger multiple updates dbName: "COUNTERS_DB", tableName: "COUNTERS", - tableKey: "oid:0x1500000000091c", // "Ethernet68:1": "oid:0x1500000000091c", + tableKey: "oid:0x1500000000091e", // "Ethernet68:3": "oid:0x1500000000091e" delimitor: ":", - field: "SAI_QUEUE_STAT_DROPPED_PACKETS", - value: "4", // being changed to 0 from 4 + field: "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", + value: "1", // be changed to 1 from 1 }}, wantNoti: []client.Notification{ client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernet68QueuesJson}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernet68QueuesJsonUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernet68QueuesJsonUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernet68QueuesJsonUpdate}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdAliasJson}, client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdAliasJsonUpdate}, }, - }, { - desc: "(use vendor alias) poll query for COUNTERS/Ethernet68/Queues with field value change", - poll: 3, - q: client.Query{ - Target: "COUNTERS_DB", - Type: client.Poll, - Queries: []client.Path{{"COUNTERS", "Ethernet68/1", "Queues"}}, - TLS: &tls.Config{InsecureSkipVerify: true}, + }, + { + desc: "stream query for table key Ethernet* with new test_field field on Ethernet68", + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Stream, + Queries: []client.Path{{"COUNTERS", "Ethernet*"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + delimitor: ":", + field: "test_field", + value: "test_value", + }, { //Same value set should not trigger multiple updates + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + delimitor: ":", + field: "test_field", + value: "test_value", + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*"}, + TS: time.Unix(0, 200), Val: countersEthernetWildcardJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*"}, + TS: time.Unix(0, 200), Val: countersEtherneWildcardJsonUpdate}, + }, + }, { + desc: "stream query for table key Ethernet*/SAI_PORT_STAT_PFC_7_RX_PKTS with field value update", + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Stream, + Queries: []client.Path{{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + delimitor: ":", + field: "SAI_PORT_STAT_PFC_7_RX_PKTS", + value: "4", // being changed to 4 from 2 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: countersEthernetWildcardPfcJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: singlePortPfcJsonUpdate}, + }, + }, { + desc: "stream query for table key Ethernet*/Pfcwd with field value update", + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Stream, + Queries: []client.Path{{"COUNTERS", "Ethernet*", "Pfcwd"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1500000000091e", // "Ethernet68:3": "oid:0x1500000000091e", + delimitor: ":", + field: "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", + value: "1", // being changed to 1 from 0 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernetWildPfcwdJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdAliasJsonUpdate}, + }, + }, { + desc: "poll query for table COUNTERS_PORT_NAME_MAP with new field test_field", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS_PORT_NAME_MAP"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS_PORT_NAME_MAP", + field: "test_field", + value: "test_value", + }}, + wantNoti: []client.Notification{ + client.Connected{}, + // We are starting from the result data of "stream query for table with update of new field", + client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJsonUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJsonUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJsonUpdate}, + client.Sync{}, + }, + }, { + desc: "poll query for table COUNTERS_PORT_NAME_MAP with test_field delete", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS_PORT_NAME_MAP"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + prepares: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS_PORT_NAME_MAP", + field: "test_field", + value: "test_value", + }}, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS_PORT_NAME_MAP", + field: "test_field", + op: "hdel", + }}, + wantNoti: []client.Notification{ + client.Connected{}, + // We are starting from the result data of "stream query for table with update of new field", + client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJsonUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS_PORT_NAME_MAP"}, TS: time.Unix(0, 200), Val: countersPortNameMapJson}, + client.Sync{}, + }, + }, { + desc: "poll query for COUNTERS/Ethernet68/SAI_PORT_STAT_PFC_7_RX_PKTS with field value change", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + delimitor: ":", + field: "SAI_PORT_STAT_PFC_7_RX_PKTS", + value: "4", // being changed to 4 from 2 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: "2"}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: "4"}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: "4"}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: "4"}, + client.Sync{}, + }, + }, { + desc: "(use vendor alias) poll query for COUNTERS/[Ethernet68/1]/SAI_PORT_STAT_PFC_7_RX_PKTS with field value change", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + delimitor: ":", + field: "SAI_PORT_STAT_PFC_7_RX_PKTS", + value: "4", // being changed to 4 from 2 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: "2"}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: "4"}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: "4"}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: "4"}, + client.Sync{}, + }, + }, { + desc: "poll query for COUNTERS/Ethernet68/Pfcwd with field value change", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet68", "Pfcwd"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1500000000091e", // "Ethernet68:3": "oid:0x1500000000091e", + delimitor: ":", + field: "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", + value: "1", // be changed to 1 from 0 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdPollUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdPollUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdPollUpdate}, + client.Sync{}, + }, + }, { + desc: "(use vendor alias) poll query for COUNTERS/[Ethernet68/1]/Pfcwd with field value change", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet68/1", "Pfcwd"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1500000000091e", // "Ethernet68:3": "oid:0x1500000000091e", + delimitor: ":", + field: "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", + value: "1", // be changed to 1 from 0 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdAliasJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdAliasPollUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdAliasPollUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdAliasPollUpdate}, + client.Sync{}, + }, }, - updates: []tablePathValue{{ - dbName: "COUNTERS_DB", - tableName: "COUNTERS", - tableKey: "oid:0x1500000000091c", // "Ethernet68:1": "oid:0x1500000000091c", - delimitor: ":", - field: "SAI_QUEUE_STAT_DROPPED_PACKETS", - value: "4", // being changed to 0 from 4 - }}, - wantNoti: []client.Notification{ - client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernet68QueuesAliasJson}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernet68QueuesAliasJsonUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernet68QueuesAliasJsonUpdate}, - client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Queues"}, - TS: time.Unix(0, 200), Val: countersEthernet68QueuesAliasJsonUpdate}, - client.Sync{}, + { + desc: "poll query for table key Ethernet* with Ethernet68/SAI_PORT_STAT_PFC_7_RX_PKTS field value change", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet*"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + delimitor: ":", + field: "SAI_PORT_STAT_PFC_7_RX_PKTS", + value: "4", // being changed to 4 from 2 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*"}, + TS: time.Unix(0, 200), Val: countersEthernetWildcardJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*"}, + TS: time.Unix(0, 200), Val: countersFieldUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*"}, + TS: time.Unix(0, 200), Val: countersFieldUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*"}, + TS: time.Unix(0, 200), Val: countersFieldUpdate}, + client.Sync{}, + }, + }, { + desc: "poll query for table key field Ethernet*/SAI_PORT_STAT_PFC_7_RX_PKTS with Ethernet68/SAI_PORT_STAT_PFC_7_RX_PKTS field value change", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1000000000039", // "Ethernet68": "oid:0x1000000000039", + delimitor: ":", + field: "SAI_PORT_STAT_PFC_7_RX_PKTS", + value: "4", // being changed to 4 from 2 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: countersEthernetWildcardPfcJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: allPortPfcJsonUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: allPortPfcJsonUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, + TS: time.Unix(0, 200), Val: allPortPfcJsonUpdate}, + client.Sync{}, + }, + }, { + desc: "poll query for table key filed Etherenet*/Pfcwd with Ethernet68:3/PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED field value change", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet*", "Pfcwd"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1500000000091e", // "Ethernet68:3": "oid:0x1500000000091e", + delimitor: ":", + field: "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", + value: "1", // being changed to 1 from 0 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernetWildPfcwdJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernetWildPfcwdUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernetWildPfcwdUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernetWildPfcwdUpdate}, + client.Sync{}, + }, }, - }} + { + desc: "poll query for COUNTERS/Ethernet*/Queues", + poll: 1, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet*", "Queues"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernetWildQueuesJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet*", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernetWildQueuesJson}, + client.Sync{}, + }, + }, { + desc: "poll query for COUNTERS/Ethernet68/Queues with field value change", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet68", "Queues"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1500000000091c", // "Ethernet68:1": "oid:0x1500000000091c", + delimitor: ":", + field: "SAI_QUEUE_STAT_DROPPED_PACKETS", + value: "4", // being changed to 0 from 4 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernet68QueuesJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernet68QueuesJsonUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernet68QueuesJsonUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernet68QueuesJsonUpdate}, + client.Sync{}, + }, + }, { + desc: "(use vendor alias) poll query for COUNTERS/Ethernet68/Queues with field value change", + poll: 3, + q: client.Query{ + Target: "COUNTERS_DB", + Type: client.Poll, + Queries: []client.Path{{"COUNTERS", "Ethernet68/1", "Queues"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + updates: []tablePathValue{{ + dbName: "COUNTERS_DB", + tableName: "COUNTERS", + tableKey: "oid:0x1500000000091c", // "Ethernet68:1": "oid:0x1500000000091c", + delimitor: ":", + field: "SAI_QUEUE_STAT_DROPPED_PACKETS", + value: "4", // being changed to 0 from 4 + }}, + wantNoti: []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernet68QueuesAliasJson}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernet68QueuesAliasJsonUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernet68QueuesAliasJsonUpdate}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "Queues"}, + TS: time.Unix(0, 200), Val: countersEthernet68QueuesAliasJsonUpdate}, + client.Sync{}, + }, + }} rclient := getRedisClient(t) defer rclient.Close() diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index 96f168124..f2b93a5b0 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -125,6 +125,10 @@ func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { if err != nil { return nil, err } + err = initCountersPfcwdNameMap() + if err != nil { + return nil, err + } } client.prefix = prefix diff --git a/sonic_data_client/virtual_db.go b/sonic_data_client/virtual_db.go index 15f1c52b1..fac701a5a 100644 --- a/sonic_data_client/virtual_db.go +++ b/sonic_data_client/virtual_db.go @@ -39,6 +39,9 @@ var ( // Alias translation: from sonic interface name to vendor port name name2aliasMap = make(map[string]string) + // SONiC interface name to their PFC-WD enabled queues, then to oid map + countersPfcwdNameMap = make(map[string]map[string]string) + // path2TFuncTbl is used to populate trie tree which is reponsible // for virtual path to real data path translation pathTransFuncTbl = []pathTransFunc{ @@ -51,6 +54,9 @@ var ( }, { // Queue stats for one or all Ethernet ports path: []string{"COUNTERS_DB", "COUNTERS", "Ethernet*", "Queues"}, transFunc: v2rTranslate(v2rEthPortQueStats), + }, { // PFC WD stats for one or all Ethernet ports + path: []string{"COUNTERS_DB", "COUNTERS", "Ethernet*", "Pfcwd"}, + transFunc: v2rTranslate(v2rEthPortPfcwdStats), }, } ) @@ -100,6 +106,85 @@ func initAliasMap() error { return nil } +func initCountersPfcwdNameMap() error { + var err error + if len(countersPfcwdNameMap) == 0 { + countersPfcwdNameMap, err = getPfcwdMap() + 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) + + redisDb, _ := Target2RedisDb["CONFIG_DB"] + _, err := redisDb.Ping().Result() + if err != nil { + log.V(1).Infof("Can not connect to CONFIG_DB, %v", err) + return nil, err + } + + resp, err := redisDb.Keys("PFC_WD_TABLE|*").Result() + if err != nil { + log.V(1).Infof("redis get keys failed for CONFIG_DB, %v", err) + return nil, err + } + + for _, key := range resp { + name := key[13:] + pfcwdName_map[name] = make(map[string]string) + } + + // Get Queue indexes that are enabled with PFC-WD + resp, err = redisDb.Keys("PORT_QOS_MAP*").Result() + if err != nil { + log.V(1).Infof("redis get keys failed for CONFIG_DB, %v", err) + return nil, err + } + qos_key := resp[0] + + priorities, err := redisDb.HGet(qos_key, "pfc_enable").Result() + if err != nil { + log.V(1).Infof("redis get field failed for CONFIG_DB, key = %v, field = pfc_enable, %v", qos_key, err) + return nil, err + } + + pfc_queue_map, err := redisDb.HGetAll("MAP_PFC_PRIORITY_TO_QUEUE|AZURE").Result() + if err != nil { + log.V(1).Infof("redis get fields failed for CONFIG_DB, key = MAP_PFC_PRIORITY_TO_QUEUE|AZURE") + return nil, err + } + + var indices []string + for _, p := range strings.Split(priorities, ",") { + indices = append(indices, pfc_queue_map[p]) + } + + if len(countersQueueNameMap) == 0 { + log.V(1).Infof("COUNTERS_QUEUE_NAME_MAP is empty") + return nil, nil + } + + var queue_key string + for port, _ := range pfcwdName_map { + for _, indice := range indices { + queue_key = port + ":" + indice + oid, ok := countersQueueNameMap[queue_key] + if !ok { + return nil, fmt.Errorf("key %v not exists in COUNTERS_QUEUE_NAME_MAP") + } + pfcwdName_map[port][queue_key] = oid + } + } + + log.V(6).Infof("countersPfcwdNameMap: %v", pfcwdName_map) + return pfcwdName_map, nil +} + // Get the mapping between sonic interface name and vendor alias func getAliasMap() (map[string]string, map[string]string, error) { var alias2name_map = make(map[string]string) @@ -162,10 +247,10 @@ func v2rEthPortStats(paths []string) ([]tablePath, error) { } tblPath := tablePath{ - dbName: paths[DbIdx], - tableName: paths[TblIdx], - tableKey: oid, - delimitor: separator, + dbName: paths[DbIdx], + tableName: paths[TblIdx], + tableKey: oid, + delimitor: separator, jsonTableKey: oport, } tblPaths = append(tblPaths, tblPath) @@ -179,7 +264,7 @@ func v2rEthPortStats(paths []string) ([]tablePath, error) { } oid, ok := countersPortNameMap[name] if !ok { - return nil, fmt.Errorf("%v not a valid sonic interface port, vendor alias is %v", name, alias) + return nil, fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", name, alias) } tblPaths = []tablePath{{ dbName: paths[DbIdx], @@ -212,11 +297,11 @@ func v2rEthPortFieldStats(paths []string) ([]tablePath, error) { } tblPath := tablePath{ - dbName: paths[DbIdx], - tableName: paths[TblIdx], - tableKey: oid, - field: paths[FieldIdx], - delimitor: separator, + dbName: paths[DbIdx], + tableName: paths[TblIdx], + tableKey: oid, + field: paths[FieldIdx], + delimitor: separator, jsonTableKey: oport, jsonField: paths[FieldIdx], } @@ -231,7 +316,7 @@ func v2rEthPortFieldStats(paths []string) ([]tablePath, error) { } oid, ok := countersPortNameMap[name] if !ok { - return nil, fmt.Errorf(" %v not a valid sonic interface port, vendor alias is %v ", name, alias) + return nil, fmt.Errorf(" %v not a valid sonic interface. Vendor alias is %v ", name, alias) } tblPaths = []tablePath{{ dbName: paths[DbIdx], @@ -245,6 +330,66 @@ func v2rEthPortFieldStats(paths []string) ([]tablePath, error) { return tblPaths, nil } +// Populate real data paths from paths like +// [COUNTER_DB COUNTERS Ethernet* Pfcwd] or [COUNTER_DB COUNTERS Ethernet68 Pfcwd] +func v2rEthPortPfcwdStats(paths []string) ([]tablePath, error) { + separator, _ := GetTableKeySeparator(paths[DbIdx]) + var tblPaths []tablePath + if strings.HasSuffix(paths[KeyIdx], "*") { // Pfcwd on all Ethernet ports + for _, pfcqueues := range countersPfcwdNameMap { + for pfcque, oid := range pfcqueues { + // pfcque is in format of "Interface:12" + names := strings.Split(pfcque, ":") + var oname string + if alias, ok := name2aliasMap[names[0]]; ok { + oname = alias + } else { + log.V(2).Infof(" %v does not have a vendor alias", names[0]) + oname = names[0] + } + que := strings.Join([]string{oname, names[1]}, ":") + tblPath := tablePath{ + dbName: paths[DbIdx], + tableName: paths[TblIdx], + tableKey: oid, + delimitor: separator, + jsonTableKey: que, + } + tblPaths = append(tblPaths, tblPath) + } + } + } else { // pfcwd counters on single port + alias := paths[KeyIdx] + name := alias + if val, ok := alias2nameMap[alias]; ok { + name = val + } + _, ok := countersPortNameMap[name] + if !ok { + return nil, fmt.Errorf("%v not a valid SONiC interface. Vendor alias is %v", name, alias) + } + + pfcqueues, ok := countersPfcwdNameMap[name] + if ok { + for pfcque, oid := range pfcqueues { + // pfcque is in format of Ethernet64:12 + names := strings.Split(pfcque, ":") + que := strings.Join([]string{alias, names[1]}, ":") + tblPath := tablePath{ + dbName: paths[DbIdx], + tableName: paths[TblIdx], + tableKey: oid, + delimitor: separator, + jsonTableKey: que, + } + tblPaths = append(tblPaths, tblPath) + } + } + } + log.V(6).Infof("v2rEthPortPfcwdStats: %v", tblPaths) + return tblPaths, nil +} + // Populate real data paths from paths like // [COUNTER_DB COUNTERS Ethernet* Queues] or [COUNTER_DB COUNTERS Ethernet68 Queues] func v2rEthPortQueStats(paths []string) ([]tablePath, error) { @@ -253,7 +398,7 @@ func v2rEthPortQueStats(paths []string) ([]tablePath, error) { if strings.HasSuffix(paths[KeyIdx], "*") { // queues on all Ethernet ports for que, oid := range countersQueueNameMap { // que is in format of "Internal_Ethernet:12" - names := strings.Split(que, separator) + names := strings.Split(que, ":") var oname string if alias, ok := name2aliasMap[names[0]]; ok { oname = alias @@ -278,8 +423,8 @@ func v2rEthPortQueStats(paths []string) ([]tablePath, error) { name = val } for que, oid := range countersQueueNameMap { - //que is in formate of "Ethernet64:12" - names := strings.Split(que, separator) + //que is in format of "Ethernet64:12" + names := strings.Split(que, ":") if name != names[0] { continue } diff --git a/testdata/CONFIG_PFCWD_PORTS.txt b/testdata/CONFIG_PFCWD_PORTS.txt new file mode 100644 index 000000000..acb894a0a --- /dev/null +++ b/testdata/CONFIG_PFCWD_PORTS.txt @@ -0,0 +1,171 @@ +{ + "MAP_PFC_PRIORITY_TO_QUEUE|AZURE": { + "3": "3", + "4": "4" + }, + "PFC_WD_TABLE|Ethernet0": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet1": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet10": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet11": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet12": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet13": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet14": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet15": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet16": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet17": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet18": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet19": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet2": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet20": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet21": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet22": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet23": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet24": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet25": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet26": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet27": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet28": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet29": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet3": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet30": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet31": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet32": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet33": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet34": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet35": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet36": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet37": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet38": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet39": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet4": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet40": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet41": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet42": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet43": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet44": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet45": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet46": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet47": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet48": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet5": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet52": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet56": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet6": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet60": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet64": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet68": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet7": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet8": { + "action": "drop" + }, + "PFC_WD_TABLE|Ethernet9": { + "action": "drop" + }, + "PORT_QOS_MAP|Ethernet0,Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet52,Ethernet56,Ethernet60,Ethernet64,Ethernet68": { + "pfc_enable": "3,4" + } +} \ No newline at end of file diff --git a/testdata/COUNTERS:Ethernet68:Pfcwd.txt b/testdata/COUNTERS:Ethernet68:Pfcwd.txt new file mode 100644 index 000000000..130dbce47 --- /dev/null +++ b/testdata/COUNTERS:Ethernet68:Pfcwd.txt @@ -0,0 +1,36 @@ +{ + "Ethernet68:3": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, + "Ethernet68:4": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + } +} \ No newline at end of file diff --git a/testdata/COUNTERS:Ethernet68:Pfcwd_alias.txt b/testdata/COUNTERS:Ethernet68:Pfcwd_alias.txt new file mode 100644 index 000000000..063f4fad2 --- /dev/null +++ b/testdata/COUNTERS:Ethernet68:Pfcwd_alias.txt @@ -0,0 +1,36 @@ +{ + "Ethernet68/1:3": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, + "Ethernet68/1:4": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + } +} \ No newline at end of file diff --git a/testdata/COUNTERS:Ethernet68:Queues.txt b/testdata/COUNTERS:Ethernet68:Queues.txt index 5ad54e6a0..23bda1894 100644 --- a/testdata/COUNTERS:Ethernet68:Queues.txt +++ b/testdata/COUNTERS:Ethernet68:Queues.txt @@ -1,27 +1,59 @@ { - "Ethernet68:0": {}, - "Ethernet68:1": { - "SAI_QUEUE_STAT_BYTES": "0", - "SAI_QUEUE_STAT_DROPPED_BYTES": "0", - "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", - "SAI_QUEUE_STAT_PACKETS": "0" - }, - "Ethernet68:10": {}, - "Ethernet68:11": {}, - "Ethernet68:12": {}, - "Ethernet68:13": {}, - "Ethernet68:14": {}, - "Ethernet68:15": {}, - "Ethernet68:16": {}, - "Ethernet68:17": {}, - "Ethernet68:18": {}, - "Ethernet68:19": {}, - "Ethernet68:2": {}, - "Ethernet68:3": {}, - "Ethernet68:4": {}, - "Ethernet68:5": {}, - "Ethernet68:6": {}, - "Ethernet68:7": {}, - "Ethernet68:8": {}, - "Ethernet68:9": {} -} + "Ethernet68:0": {}, + "Ethernet68:1": { + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0" + }, + "Ethernet68:10": {}, + "Ethernet68:11": {}, + "Ethernet68:12": {}, + "Ethernet68:13": {}, + "Ethernet68:14": {}, + "Ethernet68:15": {}, + "Ethernet68:16": {}, + "Ethernet68:17": {}, + "Ethernet68:18": {}, + "Ethernet68:19": {}, + "Ethernet68:2": {}, + "Ethernet68:3": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, + "Ethernet68:4": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, + "Ethernet68:5": {}, + "Ethernet68:6": {}, + "Ethernet68:7": {}, + "Ethernet68:8": {}, + "Ethernet68:9": {} +} \ No newline at end of file diff --git a/testdata/COUNTERS:Ethernet68:Queues_alias.txt b/testdata/COUNTERS:Ethernet68:Queues_alias.txt index 764c08553..279f07992 100644 --- a/testdata/COUNTERS:Ethernet68:Queues_alias.txt +++ b/testdata/COUNTERS:Ethernet68:Queues_alias.txt @@ -17,8 +17,40 @@ "Ethernet68/1:18": {}, "Ethernet68/1:19": {}, "Ethernet68/1:2": {}, - "Ethernet68/1:3": {}, - "Ethernet68/1:4": {}, + "Ethernet68/1:3": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, + "Ethernet68/1:4": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, "Ethernet68/1:5": {}, "Ethernet68/1:6": {}, "Ethernet68/1:7": {}, diff --git a/testdata/COUNTERS:Ethernet_wildcard_Pfcwd_alias.txt b/testdata/COUNTERS:Ethernet_wildcard_Pfcwd_alias.txt new file mode 100644 index 000000000..9b4912b48 --- /dev/null +++ b/testdata/COUNTERS:Ethernet_wildcard_Pfcwd_alias.txt @@ -0,0 +1,142 @@ +{ + "Ethernet0/1:3": {}, + "Ethernet0/1:4": {}, + "Ethernet1/1:3": {}, + "Ethernet1/1:4": {}, + "Ethernet10/1:3": {}, + "Ethernet10/1:4": {}, + "Ethernet11/1:3": {}, + "Ethernet11/1:4": {}, + "Ethernet12/1:3": {}, + "Ethernet12/1:4": {}, + "Ethernet13/1:3": {}, + "Ethernet13/1:4": {}, + "Ethernet14/1:3": {}, + "Ethernet14/1:4": {}, + "Ethernet15/1:3": {}, + "Ethernet15/1:4": {}, + "Ethernet16/1:3": {}, + "Ethernet16/1:4": {}, + "Ethernet17/1:3": {}, + "Ethernet17/1:4": {}, + "Ethernet18/1:3": {}, + "Ethernet18/1:4": {}, + "Ethernet19/1:3": {}, + "Ethernet19/1:4": {}, + "Ethernet2/1:3": {}, + "Ethernet2/1:4": {}, + "Ethernet20/1:3": {}, + "Ethernet20/1:4": {}, + "Ethernet21/1:3": {}, + "Ethernet21/1:4": {}, + "Ethernet22/1:3": {}, + "Ethernet22/1:4": {}, + "Ethernet23/1:3": {}, + "Ethernet23/1:4": {}, + "Ethernet24/1:3": {}, + "Ethernet24/1:4": {}, + "Ethernet25/1:3": {}, + "Ethernet25/1:4": {}, + "Ethernet26/1:3": {}, + "Ethernet26/1:4": {}, + "Ethernet27/1:3": {}, + "Ethernet27/1:4": {}, + "Ethernet28/1:3": {}, + "Ethernet28/1:4": {}, + "Ethernet29/1:3": {}, + "Ethernet29/1:4": {}, + "Ethernet3/1:3": {}, + "Ethernet3/1:4": {}, + "Ethernet30/1:3": {}, + "Ethernet30/1:4": {}, + "Ethernet31/1:3": {}, + "Ethernet31/1:4": {}, + "Ethernet32/1:3": {}, + "Ethernet32/1:4": {}, + "Ethernet33/1:3": {}, + "Ethernet33/1:4": {}, + "Ethernet34/1:3": {}, + "Ethernet34/1:4": {}, + "Ethernet35/1:3": {}, + "Ethernet35/1:4": {}, + "Ethernet36/1:3": {}, + "Ethernet36/1:4": {}, + "Ethernet37/1:3": {}, + "Ethernet37/1:4": {}, + "Ethernet38/1:3": {}, + "Ethernet38/1:4": {}, + "Ethernet39/1:3": {}, + "Ethernet39/1:4": {}, + "Ethernet4/1:3": {}, + "Ethernet4/1:4": {}, + "Ethernet40/1:3": {}, + "Ethernet40/1:4": {}, + "Ethernet41/1:3": {}, + "Ethernet41/1:4": {}, + "Ethernet42/1:3": {}, + "Ethernet42/1:4": {}, + "Ethernet43/1:3": {}, + "Ethernet43/1:4": {}, + "Ethernet44/1:3": {}, + "Ethernet44/1:4": {}, + "Ethernet45/1:3": {}, + "Ethernet45/1:4": {}, + "Ethernet46/1:3": {}, + "Ethernet46/1:4": {}, + "Ethernet47/1:3": {}, + "Ethernet47/1:4": {}, + "Ethernet48/1:3": {}, + "Ethernet48/1:4": {}, + "Ethernet5/1:3": {}, + "Ethernet5/1:4": {}, + "Ethernet52/1:3": {}, + "Ethernet52/1:4": {}, + "Ethernet56/1:3": {}, + "Ethernet56/1:4": {}, + "Ethernet6/1:3": {}, + "Ethernet6/1:4": {}, + "Ethernet60/1:3": {}, + "Ethernet60/1:4": {}, + "Ethernet64/1:3": {}, + "Ethernet64/1:4": {}, + "Ethernet68/1:3": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, + "Ethernet68/1:4": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, + "Ethernet7/1:3": {}, + "Ethernet7/1:4": {}, + "Ethernet8/1:3": {}, + "Ethernet8/1:4": {}, + "Ethernet9/1:3": {}, + "Ethernet9/1:4": {} +} \ No newline at end of file diff --git a/testdata/COUNTERS:Ethernet_wildcard_Queues_alias.txt b/testdata/COUNTERS:Ethernet_wildcard_Queues_alias.txt index 3daff25f0..42f6428fd 100644 --- a/testdata/COUNTERS:Ethernet_wildcard_Queues_alias.txt +++ b/testdata/COUNTERS:Ethernet_wildcard_Queues_alias.txt @@ -1017,8 +1017,40 @@ "Ethernet68/1:18": {}, "Ethernet68/1:19": {}, "Ethernet68/1:2": {}, - "Ethernet68/1:3": {}, - "Ethernet68/1:4": {}, + "Ethernet68/1:3": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, + "Ethernet68/1:4": { + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" + }, "Ethernet68/1:5": {}, "Ethernet68/1:6": {}, "Ethernet68/1:7": {}, diff --git a/testdata/COUNTERS:oid:0x1500000000091e.txt b/testdata/COUNTERS:oid:0x1500000000091e.txt new file mode 100644 index 000000000..4e6e7d833 --- /dev/null +++ b/testdata/COUNTERS:oid:0x1500000000091e.txt @@ -0,0 +1,17 @@ +{ + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" +} \ No newline at end of file diff --git a/testdata/COUNTERS:oid:0x1500000000091f.txt b/testdata/COUNTERS:oid:0x1500000000091f.txt new file mode 100644 index 000000000..4e6e7d833 --- /dev/null +++ b/testdata/COUNTERS:oid:0x1500000000091f.txt @@ -0,0 +1,17 @@ +{ + "PFC_WD_ACTION": "drop", + "PFC_WD_DETECTION_TIME": "200000", + "PFC_WD_DETECTION_TIME_LEFT": "200000", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_RESTORATION_TIME": "200000", + "PFC_WD_STATUS": "operational", + "SAI_QUEUE_ATTR_PAUSE_STATUS": "false", + "SAI_QUEUE_ATTR_PAUSE_STATUS_last": "false", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS_last": "0" +} \ No newline at end of file From 3908994c00203ba26cb3f08e45258b06afa68cb0 Mon Sep 17 00:00:00 2001 From: Chang Liu Date: Wed, 5 Sep 2018 16:38:04 -0700 Subject: [PATCH 02/20] fix typos;rewrite log messeages; replace hard-coded : with database separator --- gnmi_server/server_test.go | 10 ++--- sonic_data_client/virtual_db.go | 73 ++++++++++++++++++++++----------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/gnmi_server/server_test.go b/gnmi_server/server_test.go index 100df8c6e..262d12017 100644 --- a/gnmi_server/server_test.go +++ b/gnmi_server/server_test.go @@ -761,7 +761,7 @@ func runTestSubscribe(t *testing.T) { client.Update{Path: []string{"COUNTERS", "Ethernet68/1"}, TS: time.Unix(0, 200), Val: countersEthernet68JsonUpdate}, }, }, { - desc: "stream query for COUNTERS/Ethernet68/SAI_PORT_STAT_PFC_7_RX_PKTS with update of filed value", + desc: "stream query for COUNTERS/Ethernet68/SAI_PORT_STAT_PFC_7_RX_PKTS with update of field value", q: client.Query{ Target: "COUNTERS_DB", Type: client.Stream, @@ -790,7 +790,7 @@ func runTestSubscribe(t *testing.T) { client.Update{Path: []string{"COUNTERS", "Ethernet68", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, TS: time.Unix(0, 200), Val: "3"}, }, }, { - desc: "(use vendor alias) stream query for COUNTERS/[Ethernet68/1]/SAI_PORT_STAT_PFC_7_RX_PKTS with update of filed value", + desc: "(use vendor alias) stream query for COUNTERS/[Ethernet68/1]/SAI_PORT_STAT_PFC_7_RX_PKTS with update of field value", q: client.Query{ Target: "COUNTERS_DB", Type: client.Stream, @@ -819,7 +819,7 @@ func runTestSubscribe(t *testing.T) { client.Update{Path: []string{"COUNTERS", "Ethernet68/1", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, TS: time.Unix(0, 200), Val: "3"}, }, }, { - desc: "stream query for COUNTERS/Ethernet68/Pfcwd with update of filed value", + desc: "stream query for COUNTERS/Ethernet68/Pfcwd with update of field value", q: client.Query{ Target: "COUNTERS_DB", Type: client.Stream, @@ -848,7 +848,7 @@ func runTestSubscribe(t *testing.T) { client.Update{Path: []string{"COUNTERS", "Ethernet68", "Pfcwd"}, TS: time.Unix(0, 200), Val: countersEthernet68PfcwdJsonUpdate}, }, }, { - desc: "(use vendor alias) stream query for COUNTERS/[Ethernet68/1]/Pfcwd with update of filed value", + desc: "(use vendor alias) stream query for COUNTERS/[Ethernet68/1]/Pfcwd with update of field value", q: client.Query{ Target: "COUNTERS_DB", Type: client.Stream, @@ -1200,7 +1200,7 @@ func runTestSubscribe(t *testing.T) { client.Sync{}, }, }, { - desc: "poll query for table key filed Etherenet*/Pfcwd with Ethernet68:3/PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED field value change", + desc: "poll query for table key field Etherenet*/Pfcwd with Ethernet68:3/PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED field value change", poll: 3, q: client.Query{ Target: "COUNTERS_DB", diff --git a/sonic_data_client/virtual_db.go b/sonic_data_client/virtual_db.go index fac701a5a..2c038ba19 100644 --- a/sonic_data_client/virtual_db.go +++ b/sonic_data_client/virtual_db.go @@ -121,47 +121,67 @@ func initCountersPfcwdNameMap() error { func getPfcwdMap() (map[string]map[string]string, error) { var pfcwdName_map = make(map[string]map[string]string) - redisDb, _ := Target2RedisDb["CONFIG_DB"] + dbName := "CONFIG_DB" + redisDb, _ := Target2RedisDb[dbName] _, err := redisDb.Ping().Result() if err != nil { - log.V(1).Infof("Can not connect to CONFIG_DB, %v", err) + log.V(1).Infof("Can not connect to %v, err: %v", dbName, err) return nil, err } - resp, err := redisDb.Keys("PFC_WD_TABLE|*").Result() + keyName := "PFC_WD_TABLE|*" + resp, err := redisDb.Keys(keyName).Result() if err != nil { - log.V(1).Infof("redis get keys failed for CONFIG_DB, %v", err) + log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) return nil, err } + if len(resp) == 0 { + // PFC WD service not enabled on device + log.V(1).Infof("PFC WD not enabled on device") + return nil, nil + } + for _, key := range resp { name := key[13:] pfcwdName_map[name] = make(map[string]string) } // Get Queue indexes that are enabled with PFC-WD - resp, err = redisDb.Keys("PORT_QOS_MAP*").Result() + keyName = "PORT_QOS_MAP*" + resp, err = redisDb.Keys(keyName).Result() if err != nil { - log.V(1).Infof("redis get keys failed for CONFIG_DB, %v", err) + log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) return nil, err } + if len(resp) == 0 { + log.V(1).Infof("PFC WD not enabled on device") + return nil, nil + } qos_key := resp[0] - priorities, err := redisDb.HGet(qos_key, "pfc_enable").Result() + fieldName := "pfc_enable" + priorities, err := redisDb.HGet(qos_key, fieldName).Result() if err != nil { - log.V(1).Infof("redis get field failed for CONFIG_DB, key = %v, field = pfc_enable, %v", qos_key, err) + log.V(1).Infof("redis get field failed for %v, key = %v, field = %v, err: %v", dbName, qos_key, fieldName, err) return nil, err } - pfc_queue_map, err := redisDb.HGetAll("MAP_PFC_PRIORITY_TO_QUEUE|AZURE").Result() + keyName = "MAP_PFC_PRIORITY_TO_QUEUE|AZURE" + pfc_queue_map, err := redisDb.HGetAll(keyName).Result() if err != nil { - log.V(1).Infof("redis get fields failed for CONFIG_DB, key = MAP_PFC_PRIORITY_TO_QUEUE|AZURE") + log.V(1).Infof("redis get fields failed for %v, key = %v, err: %v", dbName, keyName, err) return nil, err } var indices []string for _, p := range strings.Split(priorities, ",") { - indices = append(indices, pfc_queue_map[p]) + _, ok := pfc_queue_map[p] + if !ok { + log.V(1).Infof("Missing mapping between PFC priority %v to queue", p) + } else { + indices = append(indices, pfc_queue_map[p]) + } } if len(countersQueueNameMap) == 0 { @@ -175,7 +195,7 @@ func getPfcwdMap() (map[string]map[string]string, error) { queue_key = port + ":" + indice oid, ok := countersQueueNameMap[queue_key] if !ok { - return nil, fmt.Errorf("key %v not exists in COUNTERS_QUEUE_NAME_MAP") + return nil, fmt.Errorf("key %v not exists in COUNTERS_QUEUE_NAME_MAP", queue_key) } pfcwdName_map[port][queue_key] = oid } @@ -190,21 +210,24 @@ func getAliasMap() (map[string]string, map[string]string, error) { var alias2name_map = make(map[string]string) var name2alias_map = make(map[string]string) - redisDb, _ := Target2RedisDb["CONFIG_DB"] + dbName := "CONFIG_DB" + redisDb, _ := Target2RedisDb[dbName] _, err := redisDb.Ping().Result() if err != nil { - log.V(1).Infof("Can not connect to CONFIG_DB, %v", err) + log.V(1).Infof("Can not connect to %v, err: %v", dbName, err) return nil, nil, err } - resp, err := redisDb.Keys("PORT|*").Result() + + keyName := "PORT|*" + resp, err := redisDb.Keys(keyName).Result() if err != nil { - log.V(1).Infof("redis get keys failed for CONFIG_DB, %v", err) + log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) return nil, nil, err } for _, key := range resp { alias, err := redisDb.HGet(key, "alias").Result() if err != nil { - log.V(1).Infof("redis get field failes for CONFIG_DB, key = %v, %v", key, err) + log.V(1).Infof("redis get field alias failed for %v, key = %v, err: %v", dbName, key, err) // clear aliasMap alias2name_map = make(map[string]string) name2alias_map = make(map[string]string) @@ -339,7 +362,7 @@ func v2rEthPortPfcwdStats(paths []string) ([]tablePath, error) { for _, pfcqueues := range countersPfcwdNameMap { for pfcque, oid := range pfcqueues { // pfcque is in format of "Interface:12" - names := strings.Split(pfcque, ":") + names := strings.Split(pfcque, separator) var oname string if alias, ok := name2aliasMap[names[0]]; ok { oname = alias @@ -347,7 +370,7 @@ func v2rEthPortPfcwdStats(paths []string) ([]tablePath, error) { log.V(2).Infof(" %v does not have a vendor alias", names[0]) oname = names[0] } - que := strings.Join([]string{oname, names[1]}, ":") + que := strings.Join([]string{oname, names[1]}, separator) tblPath := tablePath{ dbName: paths[DbIdx], tableName: paths[TblIdx], @@ -373,8 +396,8 @@ func v2rEthPortPfcwdStats(paths []string) ([]tablePath, error) { if ok { for pfcque, oid := range pfcqueues { // pfcque is in format of Ethernet64:12 - names := strings.Split(pfcque, ":") - que := strings.Join([]string{alias, names[1]}, ":") + names := strings.Split(pfcque, separator) + que := strings.Join([]string{alias, names[1]}, separator) tblPath := tablePath{ dbName: paths[DbIdx], tableName: paths[TblIdx], @@ -398,7 +421,7 @@ func v2rEthPortQueStats(paths []string) ([]tablePath, error) { if strings.HasSuffix(paths[KeyIdx], "*") { // queues on all Ethernet ports for que, oid := range countersQueueNameMap { // que is in format of "Internal_Ethernet:12" - names := strings.Split(que, ":") + names := strings.Split(que, separator) var oname string if alias, ok := name2aliasMap[names[0]]; ok { oname = alias @@ -406,7 +429,7 @@ func v2rEthPortQueStats(paths []string) ([]tablePath, error) { log.V(2).Infof(" %v dose not have a vendor alias", names[0]) oname = names[0] } - que = strings.Join([]string{oname, names[1]}, ":") + que = strings.Join([]string{oname, names[1]}, separator) tblPath := tablePath{ dbName: paths[DbIdx], tableName: paths[TblIdx], @@ -424,11 +447,11 @@ func v2rEthPortQueStats(paths []string) ([]tablePath, error) { } for que, oid := range countersQueueNameMap { //que is in format of "Ethernet64:12" - names := strings.Split(que, ":") + names := strings.Split(que, separator) if name != names[0] { continue } - que = strings.Join([]string{alias, names[1]}, ":") + que = strings.Join([]string{alias, names[1]}, separator) tblPath := tablePath{ dbName: paths[DbIdx], tableName: paths[TblIdx], From cca4c306463175f74b598345973bb454f6138320 Mon Sep 17 00:00:00 2001 From: Chang Liu Date: Thu, 6 Sep 2018 10:21:47 -0700 Subject: [PATCH 03/20] replace hardcoded table separator | --- sonic_data_client/virtual_db.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sonic_data_client/virtual_db.go b/sonic_data_client/virtual_db.go index 2c038ba19..7b1592cf7 100644 --- a/sonic_data_client/virtual_db.go +++ b/sonic_data_client/virtual_db.go @@ -122,6 +122,7 @@ func getPfcwdMap() (map[string]map[string]string, error) { var pfcwdName_map = make(map[string]map[string]string) dbName := "CONFIG_DB" + separator, _ := GetTableKeySeparator(dbName) redisDb, _ := Target2RedisDb[dbName] _, err := redisDb.Ping().Result() if err != nil { @@ -129,7 +130,7 @@ func getPfcwdMap() (map[string]map[string]string, error) { return nil, err } - keyName := "PFC_WD_TABLE|*" + keyName := fmt.Sprintf("PFC_WD_TABLE%v*", separator) resp, err := redisDb.Keys(keyName).Result() if err != nil { log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) @@ -167,7 +168,7 @@ func getPfcwdMap() (map[string]map[string]string, error) { return nil, err } - keyName = "MAP_PFC_PRIORITY_TO_QUEUE|AZURE" + keyName = fmt.Sprintf("MAP_PFC_PRIORITY_TO_QUEUE%vAZURE", separator) pfc_queue_map, err := redisDb.HGetAll(keyName).Result() if err != nil { log.V(1).Infof("redis get fields failed for %v, key = %v, err: %v", dbName, keyName, err) @@ -190,9 +191,10 @@ func getPfcwdMap() (map[string]map[string]string, error) { } var queue_key string + queue_separator, _ := GetTableKeySeparator("COUNTERS_DB") for port, _ := range pfcwdName_map { for _, indice := range indices { - queue_key = port + ":" + indice + queue_key = port + queue_separator + indice oid, ok := countersQueueNameMap[queue_key] if !ok { return nil, fmt.Errorf("key %v not exists in COUNTERS_QUEUE_NAME_MAP", queue_key) @@ -211,6 +213,7 @@ func getAliasMap() (map[string]string, map[string]string, error) { var name2alias_map = make(map[string]string) dbName := "CONFIG_DB" + separator, _ := GetTableKeySeparator(dbName) redisDb, _ := Target2RedisDb[dbName] _, err := redisDb.Ping().Result() if err != nil { @@ -218,7 +221,7 @@ func getAliasMap() (map[string]string, map[string]string, error) { return nil, nil, err } - keyName := "PORT|*" + keyName := fmt.Sprintf("PORT%v*", separator) resp, err := redisDb.Keys(keyName).Result() if err != nil { log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) From 750133e5e481ce0ef16455d33aab53311bd2ba45 Mon Sep 17 00:00:00 2001 From: Chang Liu Date: Tue, 25 Sep 2018 17:10:36 -0700 Subject: [PATCH 04/20] Implement new virtual path for pfcwd --- README.md | 7 - dialout/dialout_client/dialout_client.go | 3 +- dialout/dialout_client/dialout_client_test.go | 6 +- .../dialout_server_cli/dialout_server_cli.go | 3 +- gnmi_server/client_subscribe.go | 12 +- gnmi_server/server.go | 9 +- gnmi_server/server_test.go | 3 +- new_sonic_data_client/db_client.go | 316 +++++++++++++++++ new_sonic_data_client/handler_func.go | 71 ++++ new_sonic_data_client/handler_pfc_counter.go | 113 ++++++ new_sonic_data_client/handler_pfcwd.go | 262 ++++++++++++++ new_sonic_data_client/handler_port_counter.go | 112 ++++++ .../handler_queue_counter.go | 156 +++++++++ new_sonic_data_client/map_init.go | 219 ++++++++++++ new_sonic_data_client/path.go | 330 ++++++++++++++++++ new_sonic_data_client/trie.go | 114 ++++++ new_vpath.go | 68 ++++ sonic_data_client/db_client.go | 99 ++++-- 18 files changed, 1853 insertions(+), 50 deletions(-) create mode 100644 new_sonic_data_client/db_client.go create mode 100644 new_sonic_data_client/handler_func.go create mode 100644 new_sonic_data_client/handler_pfc_counter.go create mode 100644 new_sonic_data_client/handler_pfcwd.go create mode 100644 new_sonic_data_client/handler_port_counter.go create mode 100644 new_sonic_data_client/handler_queue_counter.go create mode 100644 new_sonic_data_client/map_init.go create mode 100644 new_sonic_data_client/path.go create mode 100644 new_sonic_data_client/trie.go create mode 100644 new_vpath.go diff --git a/README.md b/README.md index 887fb5ed5..416f30b1b 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,6 @@ There is also a test program dialout_server_cli for collecting data from dial-ou The binaries will be installed under $GOPATH/bin/, they may be copied to any SONiC switch and run there. -You can also build a debian package and install it: - - git clone https://github.com/Azure/sonic-telemetry.git - pushd sonic-telemetry - dpkg-buildpackage -rfakeroot -b -us -uc - popd - ### Running * See [SONiC gRPC telemetry](./doc/grpc_telemetry.md) for how to run dial-in mode system telemetry server * See [SONiC telemetry in dial-out mode](./doc/dialout.md) for how to run dial-out mode system telemetry client diff --git a/dialout/dialout_client/dialout_client.go b/dialout/dialout_client/dialout_client.go index ed4cfd009..b9b6ca323 100644 --- a/dialout/dialout_client/dialout_client.go +++ b/dialout/dialout_client/dialout_client.go @@ -6,7 +6,7 @@ import ( "errors" "fmt" spb "github.com/Azure/sonic-telemetry/proto" - sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" "github.com/go-redis/redis" log "github.com/golang/glog" gpb "github.com/openconfig/gnmi/proto/gnmi" @@ -16,6 +16,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" "net" + sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" //"reflect" "strconv" "strings" diff --git a/dialout/dialout_client/dialout_client_test.go b/dialout/dialout_client/dialout_client_test.go index b94963be0..11cd040fc 100644 --- a/dialout/dialout_client/dialout_client_test.go +++ b/dialout/dialout_client/dialout_client_test.go @@ -28,10 +28,12 @@ import ( "testing" "time" - sds "github.com/Azure/sonic-telemetry/dialout/dialout_server" + //sds "github.com/Azure/sonic-telemetry/dialout/dialout_server" spb "github.com/Azure/sonic-telemetry/proto" - sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + sds "test/sonic-telemetry-pfcwd/dialout/dialout_server" + //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" gclient "github.com/openconfig/gnmi/client/gnmi" + sdc "test/sonic-telemetry-pfcwd/sonic_data_client" ) var clientTypes = []string{gclient.Type} diff --git a/dialout/dialout_server_cli/dialout_server_cli.go b/dialout/dialout_server_cli/dialout_server_cli.go index 02b9cee06..f2106e249 100644 --- a/dialout/dialout_server_cli/dialout_server_cli.go +++ b/dialout/dialout_server_cli/dialout_server_cli.go @@ -10,8 +10,9 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" - ds "github.com/Azure/sonic-telemetry/dialout/dialout_server" + //ds "github.com/Azure/sonic-telemetry/dialout/dialout_server" testcert "github.com/Azure/sonic-telemetry/testdata/tls" + ds "test/sonic-telemetry-new-pfcwd/dialout/dialout_server" ) var ( diff --git a/gnmi_server/client_subscribe.go b/gnmi_server/client_subscribe.go index b814a7d5b..b55357240 100644 --- a/gnmi_server/client_subscribe.go +++ b/gnmi_server/client_subscribe.go @@ -12,8 +12,10 @@ import ( "google.golang.org/grpc/codes" //spb "github.com/Azure/sonic-telemetry/proto" - sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" gnmipb "github.com/openconfig/gnmi/proto/gnmi" + sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" + newdc "test/sonic-telemetry-new-pfcwd/new_sonic_data_client" ) // Client contains information about a subscribe client that has connected to the server. @@ -101,6 +103,7 @@ func (c *Client) Run(stream gnmipb.GNMI_SubscribeServer) (err error) { } var target string + fmt.Printf("Subscribe Prefix: %v\n", target) prefix := c.subscribe.GetPrefix() if prefix == nil { return grpc.Errorf(codes.Unimplemented, "No target specified in prefix") @@ -119,6 +122,8 @@ func (c *Client) Run(stream gnmipb.GNMI_SubscribeServer) (err error) { var dc sdc.Client if target == "OTHERS" { dc, err = sdc.NewNonDbClient(paths, prefix) + } else if target == "SONiC_DB" { + dc, err = newdc.NewDbClient(paths, prefix) } else { dc, err = sdc.NewDbClient(paths, prefix) } @@ -226,6 +231,11 @@ func (c *Client) send(stream gnmipb.GNMI_SubscribeServer) error { c.errors++ return err } + case newdc.Value: + if resp, err = newdc.ValToResp(v); err != nil { + c.errors++ + return err + } default: log.V(1).Infof("Unknown data type %v for %s in queue", items[0], c) c.errors++ diff --git a/gnmi_server/server.go b/gnmi_server/server.go index a52353dea..d032364e8 100644 --- a/gnmi_server/server.go +++ b/gnmi_server/server.go @@ -15,8 +15,9 @@ import ( "google.golang.org/grpc/reflection" "google.golang.org/grpc/status" - sdc "github.com/Azure/sonic-telemetry/sonic_data_client" gnmipb "github.com/openconfig/gnmi/proto/gnmi" + sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" + newdc "test/sonic-telemetry-new-pfcwd/new_sonic_data_client" ) var ( @@ -174,6 +175,8 @@ func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetRe var dc sdc.Client if target == "OTHERS" { dc, err = sdc.NewNonDbClient(paths, prefix) + } else if target == "SONiC_DB" { + dc, err = newdc.NewDbClient(paths, prefix) } else { dc, err = sdc.NewDbClient(paths, prefix) } @@ -186,6 +189,10 @@ func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetRe return nil, status.Error(codes.NotFound, err.Error()) } + if target == "SONiC_DB" { + notifications = make([]*gnmipb.Notification, len(spbValues)) + } + for index, spbValue := range spbValues { update := &gnmipb.Update{ Path: spbValue.GetPath(), diff --git a/gnmi_server/server_test.go b/gnmi_server/server_test.go index 262d12017..59222b28a 100644 --- a/gnmi_server/server_test.go +++ b/gnmi_server/server_test.go @@ -27,8 +27,9 @@ import ( "time" // Register supported client types. spb "github.com/Azure/sonic-telemetry/proto" - sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" gclient "github.com/jipanyang/gnmi/client/gnmi" + sdc "test/sonic-telemetry-pfcwd/sonic_data_client" ) var clientTypes = []string{gclient.Type} diff --git a/new_sonic_data_client/db_client.go b/new_sonic_data_client/db_client.go new file mode 100644 index 000000000..5368b3eaf --- /dev/null +++ b/new_sonic_data_client/db_client.go @@ -0,0 +1,316 @@ +// Data client for new Virtual Path + +package client + +import ( + //"bytes" + //"encoding/json" + "fmt" + //"net" + //"reflect" + //"strconv" + //"strings" + "sync" + "time" + + log "github.com/golang/glog" + + spb "github.com/Azure/sonic-telemetry/proto" + "github.com/go-redis/redis" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" + "github.com/workiva/go-datastructures/queue" +) + +const ( + // indentString represents the default indentation string used for JSON. + // Two spaces are used here. + indentString string = " " + Default_REDIS_UNIXSOCKET string = "/var/run/redis/redis.sock" + Default_REDIS_LOCAL_TCP_PORT string = "localhost:6379" +) + +// Client defines a set of methods which every client must implement. +// This package provides one implmentation for now: the DbClient +// +type Client interface { + // StreamRun will start watching service on data source + // and enqueue data change to the priority queue. + // It stops all activities upon receiving signal on stop channel + // It should run as a go routine + StreamRun(q *queue.PriorityQueue, stop chan struct{}, w *sync.WaitGroup) + // Poll will start service to respond poll signal received on poll channel. + // data read from data source will be enqueued on to the priority queue + // The service will stop upon detection of poll channel closing. + // It should run as a go routine + PollRun(q *queue.PriorityQueue, poll chan struct{}, w *sync.WaitGroup) + // Get return data from the data source in format of *spb.Value + Get(w *sync.WaitGroup) ([]*spb.Value, error) + // Close provides implemenation for explicit cleanup of Client + Close() error +} + +var ( + // Let it be variable visible to other packages for now. + // May add an interface function for it. + UseRedisLocalTcpPort bool = false + + // Redis client connected to each DB + Target2RedisDb = make(map[string]*redis.Client) +) + +type tablePath struct { + dbName string + keyName string + delimitor string + fields []string // fields listed in list are returned + patterns []string // fields matched with patterns are returned +} + +type Value struct { + *spb.Value +} + +// Implement Compare method for priority queue +func (val Value) Compare(other queue.Item) int { + oval := other.(Value) + if val.GetTimestamp() > oval.GetTimestamp() { + return 1 + } else if val.GetTimestamp() == oval.GetTimestamp() { + return 0 + } + return -1 +} + +type DbClient struct { + prefix *gnmipb.Path + // Used by Get server + paths []*gnmipb.Path + //pathG2S map[*gnmipb.Path][]tablePath + + q *queue.PriorityQueue + channel chan struct{} + + synced sync.WaitGroup // Control when to send gNMI sync_response + w *sync.WaitGroup // wait for all sub go routines to finish + mu sync.RWMutex // Mutex for data protection among routines for DbClient + + sendMsg int64 + recvMsg int64 + errors int64 +} + +func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { + var client DbClient + var err error + // Testing program may ask to use redis local tcp connection + if UseRedisLocalTcpPort { + useRedisTcpClient() + } + + err = initCountersPortNameMap() + if err != nil { + return nil, err + } + err = initCountersQueueNameMap() + if err != nil { + return nil, err + } + err = initAliasMap() + if err != nil { + return nil, err + } + err = initCountersPfcwdNameMap() + if err != nil { + return nil, err + } + + client.prefix = prefix + client.paths = paths + return &client, nil + /* + client.pathG2S = make(map[*gnmipb.Path][]tablePath) + err = populateAlltablePaths(prefix, paths, &client.pathG2S) + + if err != nil { + return nil, err + } else { + return &client, nil + } + */ +} + + +func (c *DbClient) StreamRun(q *queue.PriorityQueue, stop chan struct{}, w *sync.WaitGroup) { + c.w = w + defer c.w.Done() + c.q = q + c.channel = stop + + pathG2S := make(map[*gnmipb.Path][]tablePath) + err := populateAlltablePaths(c.prefix, c.paths, &pathG2S) + if err != nil { + enqueFatalMsg(c, err.Error()) + return + } + + if len(pathG2S) == 0 { + enqueFatalMsg(c, fmt.Sprintf("Prefix:%v, path: %v not valid paths", c.prefix, c.paths)) + return + } + + // Assume all ON_CHANGE mode + for gnmiPath, tblPaths := range pathG2S { + c.w.Add(1) + c.synced.Add(1) + go dbPathSubscribe(gnmiPath, tblPaths, c) + } + + // Wait until all data values corresponding to the paths specified + // in the SubscriptionList has been transmitted at least once + c.synced.Wait() + // Inject sync message + c.q.Put(Value{ + &spb.Value{ + Timestamp: time.Now().UnixNano(), + SyncResponse: true, + }, + }) + log.V(2).Infof("%v Synced", pathG2S) + return +} + + +func (c *DbClient) PollRun(q *queue.PriorityQueue, poll chan struct{}, w *sync.WaitGroup) { + return +} + + +func (c *DbClient) Get(w *sync.WaitGroup) ([]*spb.Value, error) { + // wait sync for Get, not used for now + c.w = w + + pathG2S := make(map[*gnmipb.Path][]tablePath) + err := populateAlltablePaths(c.prefix, c.paths, &pathG2S) + if err != nil { + return nil, err + } + + if len(pathG2S) == 0 { + return nil, fmt.Errorf("Failed to map to real db paths. Prefix: %v, paths: %v not valid paths", c.prefix, c.paths) + } + + var values []*spb.Value + ts := time.Now() + for gnmiPath, tblPaths := range pathG2S { + val, err := tableData2TypedValue(tblPaths) + if err != nil { + return nil, err + } + + values = append(values, &spb.Value{ + Prefix: c.prefix, + Path: gnmiPath, + Timestamp: ts.UnixNano(), + Val: val, + }) + } + log.V(5).Infof("Getting #%v", values) + log.V(4).Infof("Get done, total time taken: %v ms", int64(time.Since(ts)/time.Millisecond)) + return values, nil +} + +// TODO: Log data related to this session +func (c *DbClient) Close() error { + return nil +} + +func GetTableKeySeparator(target string) (string, error) { + _, ok := spb.Target_value[target] + if !ok { + log.V(1).Infof(" %v not a valid path target", target) + return "", fmt.Errorf("%v not a valid path target", target) + } + + var separator string + switch target { + case "CONFIG_DB": + separator = "|" + case "STATE_DB": + separator = "|" + default: + separator = ":" + } + return separator, nil +} + +// For testing only +func useRedisTcpClient() { + for dbName, dbn := range spb.Target_value { + if dbName != "OTHERS" { + // DB connector for direct redis operation + var redisDb *redis.Client + if UseRedisLocalTcpPort { + redisDb = redis.NewClient(&redis.Options{ + Network: "tcp", + Addr: Default_REDIS_LOCAL_TCP_PORT, + Password: "", // no password set + DB: int(dbn), + DialTimeout: 0, + }) + } + Target2RedisDb[dbName] = redisDb + } + } +} + +// Client package prepare redis clients to all DBs automatically +func init() { + for dbName, dbn := range spb.Target_value { + if dbName != "OTHERS" { + // DB connector for direct redis operation + var redisDb *redis.Client + + redisDb = redis.NewClient(&redis.Options{ + Network: "unix", + Addr: Default_REDIS_UNIXSOCKET, + Password: "", // no password set + DB: int(dbn), + DialTimeout: 0, + }) + Target2RedisDb[dbName] = redisDb + } + } +} + +// Convert from SONiC Value to its corresponding gNMI proto stream +// response type +func ValToResp(val Value) (*gnmipb.SubscribeResponse, error) { + switch val.GetSyncResponse() { + case true: + return &gnmipb.SubscribeResponse{ + Response: &gnmipb.SubscribeResponse_SyncResponse{ + SyncResponse: true, + }, + }, nil + default: + // In case the subscribe/poll routines encountered fatal error + if fatal := val.GetFatal(); fatal != "" { + return nil, fmt.Errorf("%s", fatal) + } + + return &gnmipb.SubscribeResponse{ + Response: &gnmipb.SubscribeResponse_Update{ + Update: &gnmipb.Notification{ + Timestamp: val.GetTimestamp(), + Prefix: val.GetPrefix(), + Update: []*gnmipb.Update{ + { + Path: val.GetPath(), + Val: val.GetVal(), + }, + }, + }, + }, + }, nil + } +} diff --git a/new_sonic_data_client/handler_func.go b/new_sonic_data_client/handler_func.go new file mode 100644 index 000000000..40024b744 --- /dev/null +++ b/new_sonic_data_client/handler_func.go @@ -0,0 +1,71 @@ +package client + +import ( + //"fmt" + log "github.com/golang/glog" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" +) + +type handlerFunc func(*gnmipb.Path, *map[*gnmipb.Path][]tablePath) error + +type pathHdlrFunc struct { + path []string + handler handlerFunc +} + +var ( + pathTrie *PathTrie + + // path2HdlrFuncTbl is used to populate trie tree which is used to + // map gNMI path to real database paths. + path2HdlrFuncTbl = []pathHdlrFunc{ + { + // new virtual path for PFC WD stats + path: []string{"SONiC_DB", "Interfaces", "Port", "Queue", "Pfcwd"}, + handler: handlerFunc(v2rPortQueuePfcwdStats), + }, { + // new virtual path for Queue counters + path: []string{"SONiC_DB", "Interfaces", "Port", "Queue", "QueueCounter"}, + handler: handlerFunc(v2rPortQueueCounterStats), + }, { + // new virtual path for Port PFC counters + path: []string{"SONiC_DB", "Interfaces", "Port", "PfcCounter"}, + handler: handlerFunc(v2rPortPfcCounterStats), + }, { + // new virtual path for Port Base Counters + path: []string{"SONiC_DB", "Interfaces", "Port", "BaseCounter"}, + handler: handlerFunc(v2rPortBaseCounterStats), + }, + } +) + +func (t *PathTrie) TriePopulate() { + for _, pf := range path2HdlrFuncTbl { + n := t.Add(pf.path, pf.handler) + if n.meta.(handlerFunc) == nil { + log.V(1).Infof("Failed to add trie node for path %v with handler func %v", pf.path, pf.handler) + } else { + log.V(2).Infof("Add trie node for path %v with handler func %v", pf.path, pf.handler) + } + } +} + +func searchPathTrie(keys []string, path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { + var nodes = []*PathNode{} + root := pathTrie.root + findPathNode(root, keys, &nodes) + + for _, node := range nodes { + handler := node.meta.(handlerFunc) + err := handler(path, pathG2S) + if err != nil { + return err + } + } + return nil +} + +func init() { + pathTrie = NewPathTrie() + pathTrie.TriePopulate() +} diff --git a/new_sonic_data_client/handler_pfc_counter.go b/new_sonic_data_client/handler_pfc_counter.go new file mode 100644 index 000000000..d660d6569 --- /dev/null +++ b/new_sonic_data_client/handler_pfc_counter.go @@ -0,0 +1,113 @@ +package client + +import ( + "fmt" + "strings" + + log "github.com/golang/glog" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" +) + +// Return template path +func GetTmpl_PortPfcCounterStats(path *gnmipb.Path) { + path.Elem = []*gnmipb.PathElem{} + + var name string + name = "Interfaces" + path.Elem = append(path.Elem, &gnmipb.PathElem{Name: name}) + + name = "Port" + path.Elem = append(path.Elem, &gnmipb.PathElem{ + Name: name, + Key: map[string]string{"name": "*"}, + }) + + name = "PfcCounter" + path.Elem = append(path.Elem, &gnmipb.PathElem{Name: name}) +} + +// gNMI paths are like +// [Interfaces Port[name= PfcCounter] +func v2rPortPfcCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { + var tmpl = gnmipb.Path{} + GetTmpl_PortPfcCounterStats(&tmpl) + + parentConfig := map[int]string{1: "Port"} + + leaf := leafConfig { + idx: 2, + name: "PfcCounter", + } + + target_fields := []string{} + updatePath(path, &tmpl, parentConfig, leaf, &target_fields) + + // Populate tabelPaths + err := pop_PortPfcCounterStats(&tmpl, pathG2S, target_fields) + if err != nil { + return err + } + return nil +} + +// Populate redis key and fields +func pop_PortPfcCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath, target_fields []string) error { + dbName := "COUNTERS_DB" + separator, _ := GetTableKeySeparator(dbName) + + elems := path.GetElem() + + // Populate port level + var idx_port = 1 + portName := elems[idx_port].GetKey()["name"] + if portName == "*" { + // Wildcard port name + for port, _ := range countersPortNameMap { + // Alias translation + var oport string + if alias, ok := name2aliasMap[port]; ok { + oport = alias + } else { + log.V(2).Infof("%v does not have a vendor alias", port) + oport = port + } + // Create a gNMI path for each port + var copyPath = gnmipb.Path{} + deepcopy(path, ©Path) + copyPath.Elem[idx_port].Key["name"] = oport + err := pop_PortPfcCounterStats(©Path, pathG2S, target_fields) + if err != nil { + return err + } + } + return nil + } + + // Alias translation + var alias, _name string + alias = portName + _name = alias + if val, ok := alias2nameMap[alias]; ok { + _name = val + } + + oid_port, ok := countersPortNameMap[_name] + if !ok { + return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) + } + + // TODO: Subscribe to only particular fields + if len(target_fields) > 0 { + return fmt.Errorf("Subscribe to field of Path: %v not supported", path) + } + + tblPath_port := tablePath { + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_port}, separator), + delimitor: separator, + patterns: []string{"SAI_PORT_STAT_PFC_._RX_PKTS$", "SAI_PORT_STAT_PFC_._TX_PKTS$"}, + } + + (*pathG2S)[path] = []tablePath{tblPath_port} + return nil +} diff --git a/new_sonic_data_client/handler_pfcwd.go b/new_sonic_data_client/handler_pfcwd.go new file mode 100644 index 000000000..ac6623ffb --- /dev/null +++ b/new_sonic_data_client/handler_pfcwd.go @@ -0,0 +1,262 @@ +package client + +import ( + "fmt" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" + log "github.com/golang/glog" + "strings" + //proto "github.com/golang/protobuf/proto" +) + +//func (m *tablePath) String() string { +// return proto.CompactTextString(m) +//} + +func deepcopy(path, copyPath *gnmipb.Path) { + copyPath.Elem = []*gnmipb.PathElem{} + + for _, elem := range path.GetElem() { + var copyElem = gnmipb.PathElem{} + copyElem.Name = elem.GetName() + copyElem.Key = map[string]string{} + for k, v := range elem.Key { + copyElem.Key[k] = v + } + copyPath.Elem = append(copyPath.Elem, ©Elem) + } +} + +// Contains tell whether array contains X +func contains(a []string, x string) bool { + for _, n := range(a) { + if x == n { + return true + } + } + return false +} + +type leafConfig struct { + idx int + name string +} + +func updatePath(path, tmpl *gnmipb.Path, parentConfig map[int]string, leaf leafConfig, target_fields *[]string) { + // Update parent node + for idx, name := range parentConfig { + for _, elem := range path.GetElem() { + if elem.GetName() == name { + (*tmpl).Elem[idx].Key["name"] = elem.Key["name"] + break + } + } + } + + // Update fields: if subscribe to particular fields + for _, elem := range path.GetElem() { + if elem.GetName() == leaf.name { + if fieldStr, ok := elem.GetKey()["field"]; ok { + (*target_fields) = strings.Split(fieldStr, ",") + } + } + } +} + +// Return template path +func GetTmpl_PortQueuePfcwdStats(path *gnmipb.Path) { + path.Elem = []*gnmipb.PathElem{} + + var name string + name = "Interfaces" + path.Elem = append(path.Elem, &gnmipb.PathElem{Name: name}) + + name = "Port" + path.Elem = append(path.Elem, &gnmipb.PathElem{ + Name: name, + Key: map[string]string{"name": "*"}, + }) + + name = "Queue" + path.Elem = append(path.Elem, &gnmipb.PathElem{ + Name: name, + Key: map[string]string{"name": "*"}, + }) + + name = "Pfcwd" + path.Elem = append(path.Elem, &gnmipb.PathElem{Name: name}) +} + +// Translate gNMI path into a list of unique root-to-leaf vpaths +// then map each unique vpath to a list of real DB tablePaths +// gNMI paths are like +// [Inerfaces Port[name=] Queue[name=] Pfcwd] +func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error{ + var tmpl = gnmipb.Path{} + GetTmpl_PortQueuePfcwdStats(&tmpl) + fmt.Printf("tmpl: %v\n", &tmpl) + + parentConfig := map[int]string{1: "Port", 2: "Queue"} + + leaf := leafConfig { + idx: 3, + name: "Pfcwd", + } + + target_fields := []string{} + updatePath(path, &tmpl, parentConfig, leaf, &target_fields) + + // Populate tablePaths + fmt.Printf("path passed in populate: %v\n", &tmpl) + err := pop_PortQueuePfcwdStats(&tmpl, pathG2S, target_fields) + if err != nil { + return err + } + return nil +} + +// Populate +func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath, target_fields []string) error{ + dbName := "COUNTERS_DB" + separator, _ := GetTableKeySeparator(dbName) + + elems := path.GetElem() + //fmt.Printf("path: %v\n\n", path) + + // Populate port level + var idx_port = 1 + portName := elems[idx_port].GetKey()["name"] + if portName == "*" { + // wildcard port name + for port, _ := range countersPortNameMap { + // Alias translation + var oport string + if alias, ok := name2aliasMap[port]; ok { + oport = alias + } else { + log.V(2).Infof("%v does not have a vendor alias", port) + oport = port + } + // Create a gNMI path for each port + var copyPath = gnmipb.Path{} + deepcopy(path, ©Path) + copyPath.Elem[idx_port].Key["name"] = oport + err := pop_PortQueuePfcwdStats(©Path, pathG2S, target_fields) + if err != nil { + return err + } + } + return nil + } + + // Alias translation + var alias, _name string + alias = portName + _name = alias + if val, ok := alias2nameMap[alias]; ok { + _name = val + } + + oid_port, ok := countersPortNameMap[_name] + if !ok { + return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) + } + + // Populate queue level + var idx_que = 2 + queName := elems[idx_que].GetKey()["name"] + if queName == "*" { + // wildcard queue name + for pfcque, _ := range countersPfcwdNameMap[_name] { + // pfcque is in format of "Interface:12" + // Alias translation + stringSlice := strings.Split(pfcque, separator) + //new_queName := strings.Join([]string{"Queue", stringSlice[1]}, separator) + new_queName := "Queue" + stringSlice[1] + // Create a gNMI path for each PFC WD enabled queue + var copyPath = gnmipb.Path{} + deepcopy(path, ©Path) + copyPath.Elem[idx_que].Key["name"] = new_queName + err := pop_PortQueuePfcwdStats(©Path, pathG2S, target_fields) + if err != nil { + return err + } + } + return nil + } + + // Alias translation + //stringSlice := strings.Split(queName, separator) + if !strings.HasPrefix(queName, "Queue") { + return fmt.Errorf("%v not a vaild queue name. Use format 'Queue'", queName) + } + queNum := strings.TrimPrefix(queName, "Queue") + pfcque := strings.Join([]string{_name, queNum}, separator) + if _, ok := countersPfcwdNameMap[_name]; ok{ + if oid_que, ok := countersPfcwdNameMap[_name][pfcque]; ok{ + // PFC WD is enabled for port:queue + out_tblPaths := []tablePath{} + // Fields under the queue oid + full_fields := []string { + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", + "PFC_WD_QUEUE_STATS_TX_DROPPED_PACKETS", + "PFC_WD_QUEUE_STATS_RX_DROPPED_PACKETS", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED", + "PFC_wD_QUEUE_STATS_TX_PACKETS", + "PFC_WD_QUEUE_STATS_RX_PACKETS", + "PFC_WD_STATUS", + } + + if len(target_fields) > 0 { + // Subscirbe to only particular fields + key_target_fields := []string{} + for _, targetField := range(target_fields) { + if contains(full_fields, targetField) { + key_target_fields = append(key_target_fields, targetField) + } + } + full_fields = key_target_fields + } + + if len(full_fields) > 0 { + tblPath_que := tablePath { + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_que}, separator), + delimitor: separator, + fields: full_fields, + } + out_tblPaths = append(out_tblPaths, tblPath_que) + } + + // Fields under the port oid + full_fields = []string{fmt.Sprintf("SAI_PORT_STAT_PFC_%v_RX_PKTS", queNum)} + + if len(target_fields) > 0 { + // Subscirbe to only particular fields + key_target_fields := []string{} + for _, targetField := range(target_fields) { + if contains(full_fields, targetField) { + key_target_fields = append(key_target_fields, targetField) + } + } + full_fields = key_target_fields + } + + if len(full_fields) > 0 { + tblPath_port := tablePath { + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_port}, separator), + delimitor: separator, + fields: full_fields, + } + out_tblPaths = append(out_tblPaths, tblPath_port) + } + + //fmt.Printf("tablePath: %v\n", &tblPath_que) + //fmt.Printf("tablePath: %v\n", &tblPath_port) + if len(out_tblPaths) > 0 { + (*pathG2S)[path] = out_tblPaths + } + } + } + return nil +} diff --git a/new_sonic_data_client/handler_port_counter.go b/new_sonic_data_client/handler_port_counter.go new file mode 100644 index 000000000..8d9c815ff --- /dev/null +++ b/new_sonic_data_client/handler_port_counter.go @@ -0,0 +1,112 @@ +package client + +import ( + "fmt" + "strings" + + log "github.com/golang/glog" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" +) + +// Return template path +func GetTmpl_PortBaseCounterStats(path *gnmipb.Path) { + path.Elem = []*gnmipb.PathElem{} + + var name string + name = "Interfaces" + path.Elem = append(path.Elem, &gnmipb.PathElem{Name: name}) + + name = "Port" + path.Elem = append(path.Elem, &gnmipb.PathElem{ + Name: name, + Key: map[string]string{"name": "*"}, + }) + + name = "BaseCounter" + path.Elem = append(path.Elem, &gnmipb.PathElem{Name: name}) +} + +// gNMI paths are like +// [Interfaces Port[name= PfcCounter] +func v2rPortBaseCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { + var tmpl = gnmipb.Path{} + GetTmpl_PortBaseCounterStats(&tmpl) + + parentConfig := map[int]string{1: "Port"} + + leaf := leafConfig { + idx: 2, + name: "BaseCounter", + } + + target_fields := []string{} + updatePath(path, &tmpl, parentConfig, leaf, &target_fields) + + // Populate tabelPaths + err := pop_PortBaseCounterStats(&tmpl, pathG2S, target_fields) + if err != nil { + return err + } + return nil +} + +// Populate redis key and fields +func pop_PortBaseCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath, target_fields []string) error { + dbName := "COUNTERS_DB" + separator, _ := GetTableKeySeparator(dbName) + + elems := path.GetElem() + + // Populate port level + var idx_port = 1 + portName := elems[idx_port].GetKey()["name"] + if portName == "*" { + // Wildcard port name + for port, _ := range countersPortNameMap { + // Alias translation + var oport string + if alias, ok := name2aliasMap[port]; ok { + oport = alias + } else { + log.V(2).Infof("%v does not have a vendor alias", port) + oport = port + } + // Create a gNMI path for each port + var copyPath = gnmipb.Path{} + deepcopy(path, ©Path) + copyPath.Elem[idx_port].Key["name"] = oport + err := pop_PortBaseCounterStats(©Path, pathG2S, target_fields) + if err != nil { + return err + } + } + return nil + } + + // Alias translation + var alias, _name string + alias = portName + _name = alias + if val, ok := alias2nameMap[alias]; ok { + _name = val + } + + oid_port, ok := countersPortNameMap[_name] + if !ok { + return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) + } + + // TODO: Subscribe to only particular fields + if len(target_fields) > 0 { + return fmt.Errorf("Subscribe to field of Path: %v not supported", path) + } + tblPath_port := tablePath { + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_port}, separator), + delimitor: separator, + patterns: []string{"SAI_PORT_STAT_I.*", "SAI_PORT_STAT_ETHER.*"}, + } + + (*pathG2S)[path] = []tablePath{tblPath_port} + return nil +} diff --git a/new_sonic_data_client/handler_queue_counter.go b/new_sonic_data_client/handler_queue_counter.go new file mode 100644 index 000000000..12c98be72 --- /dev/null +++ b/new_sonic_data_client/handler_queue_counter.go @@ -0,0 +1,156 @@ +package client + +import ( + "fmt" + "strings" + + log "github.com/golang/glog" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" +) + +// Return template path +func GetTmpl_PortQueueCounterStats(path *gnmipb.Path) { + path.Elem = []*gnmipb.PathElem{} + + var name string + name = "Interfaces" + path.Elem = append(path.Elem, &gnmipb.PathElem{Name: name}) + + name = "Port" + path.Elem = append(path.Elem, &gnmipb.PathElem{ + Name: name, + Key: map[string]string{"name": "*"}, + }) + + name = "Queue" + path.Elem = append(path.Elem, &gnmipb.PathElem{ + Name: name, + Key: map[string]string{"name": "*"}, + }) + + name = "QueueCounter" + path.Elem = append(path.Elem, &gnmipb.PathElem{Name: name}) +} + +// gNMI paths are like +// [Interfaces Port[name= Queue[name=] QueueCounter] +func v2rPortQueueCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { + var tmpl = gnmipb.Path{} + GetTmpl_PortQueueCounterStats(&tmpl) + + parentConfig := map[int]string{1: "Port", 2: "Queue"} + + leaf := leafConfig { + idx: 3, + name: "QueueCounter", + } + + target_fields := []string{} + updatePath(path, &tmpl, parentConfig, leaf, &target_fields) + + // Populate tablePaths + err := pop_PortQueueCounterStats(&tmpl, pathG2S, target_fields) + if err != nil { + return err + } + return nil +} + +// Populate redis key and fields +func pop_PortQueueCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath, target_fields []string) error { + dbName := "COUNTERS_DB" + separator, _ := GetTableKeySeparator(dbName) + + elems := path.GetElem() + + // Populate port level + var idx_port = 1 + portName := elems[idx_port].GetKey()["name"] + if portName == "*" { + // wildcard port name + for port, _ := range countersPortNameMap { + // Alias translation + var oport string + if alias, ok := name2aliasMap[port]; ok { + oport = alias + } else { + log.V(2).Infof("%v does not have a vendor alias", port) + oport = port + } + // Create a gNMI path for each port + var copyPath = gnmipb.Path{} + deepcopy(path, ©Path) + copyPath.Elem[idx_port].Key["name"] = oport + err := pop_PortQueueCounterStats(©Path, pathG2S, target_fields) + if err != nil { + return err + } + } + return nil + } + + // Alias translation + var alias, _name string + alias = portName + _name = alias + if val, ok := alias2nameMap[alias]; ok { + _name = val + } + + _, ok := countersQueueNameMap[_name] + if !ok { + return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) + } + + // Populate queue level + var idx_que = 2 + queName := elems[idx_que].GetKey()["name"] + if queName == "*" { + // wildcard queue name + for que, _ := range countersQueueNameMap[_name] { + // que is in format of "Ethernet68:12" + stringSlice := strings.Split(que, separator) + new_queName := "Queue" + stringSlice[1] + // Create a gNMI path for each queue + var copyPath = gnmipb.Path{} + deepcopy(path, ©Path) + copyPath.Elem[idx_que].Key["name"] = new_queName + err := pop_PortQueueCounterStats(©Path, pathG2S, target_fields) + if err != nil { + return err + } + } + return nil + } + + // Alias translation + //stringSlice := strings.Split(queName, separator) + if !strings.HasPrefix(queName, "Queue") { + return fmt.Errorf("%v not a vaild queue name in request. Use format 'Queue'", queName) + } + queNum := strings.TrimPrefix(queName, "Queue") + que := strings.Join([]string{_name, queNum}, separator) + oid_que, ok := countersQueueNameMap[_name][que] + if !ok { + return fmt.Errorf("%v not a valid queue name in redis db.", que) + } + + // TODO: subscribe to only particular fields + if len(target_fields) > 0 { + return fmt.Errorf("Subscribe to particular field of path %v not supported", path) + } + + tblPath_que := tablePath{ + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_que}, separator), + delimitor: separator, + fields: []string{ + "SAI_QUEUE_STAT_PACKETS", + "SAI_QUEUE_STAT_BYTES", + "SAI_QUEUE_STAT_DROPPED_PACKETS", + "SAI_QUEUE_STAT_DROPPED_BYTES"}, + } + (*pathG2S)[path] = []tablePath{tblPath_que} + return nil +} + diff --git a/new_sonic_data_client/map_init.go b/new_sonic_data_client/map_init.go new file mode 100644 index 000000000..4bfab332f --- /dev/null +++ b/new_sonic_data_client/map_init.go @@ -0,0 +1,219 @@ +package client + +import ( + "fmt" + log "github.com/golang/glog" + "strings" +) + +var ( + // Port name to oid map in COUNTERS table of COUNTERS_DB + countersPortNameMap = make(map[string]string) + + // Queue name to oid map in COUNTERS table of COUNTERS_DB + //countersQueueNameMap = make(map[string]string) + countersQueueNameMap = make(map[string]map[string]string) + + // Alias translation: from vendor port name to sonic interface name + alias2nameMap = make(map[string]string) + // Alias translation: from sonic interface name to vendor port name + name2aliasMap = make(map[string]string) + + // SONiC interface name to their PFC-WD enabled queues, then to oid map + countersPfcwdNameMap = make(map[string]map[string]string) +) + +func initCountersQueueNameMap() error { + dbName := "COUNTERS_DB" + separator, _ := GetTableKeySeparator(dbName) + + if len(countersQueueNameMap) == 0 { + queueMap, err := getCountersMap("COUNTERS_QUEUE_NAME_MAP") + if err != nil { + return err + } + for k, v := range queueMap { + stringSlice := strings.Split(k, separator) + port := stringSlice[0] + if _, ok := countersQueueNameMap[port]; !ok { + countersQueueNameMap[port] = make(map[string]string) + } + countersQueueNameMap[port][k] = v + } + } + return nil +} + +func initCountersPortNameMap() error { + var err error + if len(countersPortNameMap) == 0 { + countersPortNameMap, err = getCountersMap("COUNTERS_PORT_NAME_MAP") + if err != nil { + return err + } + } + return nil +} + +func initAliasMap() error { + var err error + if len(alias2nameMap) == 0 { + alias2nameMap, name2aliasMap, err = getAliasMap() + if err != nil { + return err + } + } + return nil +} + +func initCountersPfcwdNameMap() error { + var err error + if len(countersPfcwdNameMap) == 0 { + countersPfcwdNameMap, err = getPfcwdMap() + 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) + + dbName := "CONFIG_DB" + separator, _ := GetTableKeySeparator(dbName) + redisDb, _ := Target2RedisDb[dbName] + _, err := redisDb.Ping().Result() + if err != nil { + log.V(1).Infof("Can not connect to %v, err: %v", dbName, err) + return nil, err + } + + keyName := fmt.Sprintf("PFC_WD_TABLE%v*", separator) + resp, err := redisDb.Keys(keyName).Result() + if err != nil { + log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) + return nil, err + } + + if len(resp) == 0 { + // PFC WD service not enabled on device + log.V(1).Infof("PFC WD not enabled on device") + return nil, nil + } + + for _, key := range resp { + name := key[13:] + pfcwdName_map[name] = make(map[string]string) + } + + // Get Queue indexes that are enabled with PFC-WD + keyName = "PORT_QOS_MAP*" + resp, err = redisDb.Keys(keyName).Result() + if err != nil { + log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) + return nil, err + } + if len(resp) == 0 { + log.V(1).Infof("PFC WD not enabled on device") + return nil, nil + } + qos_key := resp[0] + + fieldName := "pfc_enable" + priorities, err := redisDb.HGet(qos_key, fieldName).Result() + if err != nil { + log.V(1).Infof("redis get field failed for %v, key = %v, field = %v, err: %v", dbName, qos_key, fieldName, err) + return nil, err + } + + keyName = fmt.Sprintf("MAP_PFC_PRIORITY_TO_QUEUE%vAZURE", separator) + pfc_queue_map, err := redisDb.HGetAll(keyName).Result() + if err != nil { + log.V(1).Infof("redis get fields failed for %v, key = %v, err: %v", dbName, keyName, err) + return nil, err + } + + var indices []string + for _, p := range strings.Split(priorities, ",") { + _, ok := pfc_queue_map[p] + if !ok { + log.V(1).Infof("Missing mapping between PFC priority %v to queue", p) + } else { + indices = append(indices, pfc_queue_map[p]) + } + } + + if len(countersQueueNameMap) == 0 { + log.V(1).Infof("COUNTERS_QUEUE_NAME_MAP is empty") + return nil, nil + } + + var queue_key string + queue_separator, _ := GetTableKeySeparator("COUNTERS_DB") + for port, _ := range pfcwdName_map { + for _, indice := range indices { + queue_key = port + queue_separator + indice + oid, ok := countersQueueNameMap[port][queue_key] + if !ok { + return nil, fmt.Errorf("key %v not exists in COUNTERS_QUEUE_NAME_MAP", queue_key) + } + pfcwdName_map[port][queue_key] = oid + } + } + + log.V(6).Infof("countersPfcwdNameMap: %v", pfcwdName_map) + return pfcwdName_map, nil +} + +// Get the mapping between sonic interface name and vendor alias +func getAliasMap() (map[string]string, map[string]string, error) { + var alias2name_map = make(map[string]string) + var name2alias_map = make(map[string]string) + + dbName := "CONFIG_DB" + separator, _ := GetTableKeySeparator(dbName) + redisDb, _ := Target2RedisDb[dbName] + _, err := redisDb.Ping().Result() + if err != nil { + log.V(1).Infof("Can not connect to %v, err: %v", dbName, err) + return nil, nil, err + } + + keyName := fmt.Sprintf("PORT%v*", separator) + resp, err := redisDb.Keys(keyName).Result() + if err != nil { + log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) + return nil, nil, err + } + for _, key := range resp { + alias, err := redisDb.HGet(key, "alias").Result() + if err != nil { + log.V(1).Infof("redis get field alias failed for %v, key = %v, err: %v", dbName, key, err) + // clear aliasMap + alias2name_map = make(map[string]string) + name2alias_map = make(map[string]string) + return nil, nil, err + } + alias2name_map[alias] = key[5:] + name2alias_map[key[5:]] = alias + } + log.V(6).Infof("alias2nameMap: %v", alias2name_map) + log.V(6).Infof("name2aliasMap: %v", name2alias_map) + return alias2name_map, name2alias_map, nil +} + +// Get the mapping between objects in counters DB, Ex. port name to oid in "COUNTERS_PORT_NAME_MAP" table. +// Aussuming static port name to oid map in COUNTERS table +func getCountersMap(tableName string) (map[string]string, error) { + redisDb, _ := Target2RedisDb["COUNTERS_DB"] + fv, err := redisDb.HGetAll(tableName).Result() + if err != nil { + log.V(2).Infof("redis HGetAll failed for COUNTERS_DB, tableName: %s", tableName) + return nil, err + } + log.V(6).Infof("tableName: %s, map %v", tableName, fv) + return fv, nil +} + diff --git a/new_sonic_data_client/path.go b/new_sonic_data_client/path.go new file mode 100644 index 000000000..322bcb086 --- /dev/null +++ b/new_sonic_data_client/path.go @@ -0,0 +1,330 @@ +package client + +import ( + "fmt" + "strconv" + //"strings" + "time" + "net" + "regexp" + "encoding/json" + + log "github.com/golang/glog" + spb "github.com/Azure/sonic-telemetry/proto" + "github.com/go-redis/redis" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" +) + +// gnmiFullPath builds the full path from the prefix and path. +func gnmiFullPath(prefix, path *gnmipb.Path) *gnmipb.Path { + + fullPath := &gnmipb.Path{Origin: path.Origin} + if path.GetElement() != nil { + fullPath.Element = append(prefix.GetElement(), path.GetElement()...) + } + if path.GetElem() != nil { + fullPath.Elem = append(prefix.GetElem(), path.GetElem()...) + } + return fullPath +} + +func populateAlltablePaths(prefix *gnmipb.Path, paths []*gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { + for _, path := range paths { + err := populateNewtablePath(prefix, path, pathG2S) + if err != nil { + return err + } + } + return nil +} + +// First translate gNMI paths to a list of unique +// root-to-leaf virtual paths in the vpath tree. +// Then map each vpath to a list of redis DB path. +func populateNewtablePath(prefix, path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { + fullPath := path + if prefix != nil { + fullPath = gnmiFullPath(prefix, path) + } + fmt.Printf("fullPath: %v\n", fullPath) + + target := prefix.GetTarget() + stringSlice := []string{target} + elems := path.GetElem() + for _, elem := range elems{ + stringSlice = append(stringSlice, elem.GetName()) + } + + err := searchPathTrie(stringSlice, path, pathG2S) + if err != nil { + return err + } + + // Debug + for k, v := range (*pathG2S) { + fmt.Printf("gNMI path: %v\n", k) + for _, tblPath := range v{ + fmt.Printf("new tablePath: %v\n", tblPath) + } + } + return nil +} + +func msi2TypedValue(msi map[string]interface{}) (*gnmipb.TypedValue, error) { + jv, err := emitJSON(&msi) + if err != nil { + log.V(2).Infof("emitJSON err %s for %v", err, msi) + return nil, fmt.Errorf("emitJSON err %s for %v", err, msi) + } + return &gnmipb.TypedValue{ + Value: &gnmipb.TypedValue_JsonIetfVal{ + JsonIetfVal: jv, + }}, nil +} + +// emitJSON marshalls map[string]interface{} to JSON byte stream. +func emitJSON(v *map[string]interface{}) ([]byte, error) { + //j, err := json.MarshalIndent(*v, "", indentString) + j, err := json.Marshal(*v) + if err != nil { + return nil, fmt.Errorf("JSON marshalling error: %v", err) + } + + return j, nil +} + +// Render the redis DB data to map[string]interface{} +// which may be marshaled to JSON format +// tablePath includes [dbName, keyName, fields] +func tableData2TypedValue(tblPaths []tablePath) (*gnmipb.TypedValue, error) { + msi := make(map[string]interface{}) + + for _, tblPath := range tblPaths { + err := tableData2Msi(&tblPath, &msi) + if err != nil { + return nil, err + } + } + return msi2TypedValue(msi) +} + +func tableData2Msi(tblPath *tablePath, msi *map[string]interface{}) error { + dbName := tblPath.dbName + keyName := tblPath.keyName + + redisDb := Target2RedisDb[dbName] + val, err := redisDb.HGetAll(keyName).Result() + if err != nil { + log.V(3).Infof("redis HGetAll failed for %v, dbName = %v, keyName=%v", tblPath, dbName, keyName) + return err + } + + //log.V(5).Infof("val: %v\n", val) + patterns := tblPath.patterns + for field, value := range val { + for _, pattern := range patterns { + r := regexp.MustCompile(pattern) + if r.MatchString(field) { + (*msi)[field] = value + break + } + } + } + + fields := tblPath.fields + for _, field := range fields { + if value, ok := val[field]; !ok { + log.V(1).Infof("Missing field: %v", field) + } else{ + (*msi)[field] = value + } + } + return nil +} + +func enqueFatalMsg(c *DbClient, msg string) { + c.q.Put(Value{ + &spb.Value{ + Timestamp: time.Now().UnixNano(), + Fatal: msg, + }, + }) +} + +type redisSubData struct { + tblPath tablePath + pubsub *redis.PubSub +} + +func dbSingleTableKeySubscribe(rsd redisSubData, c *DbClient, msiInit *map[string]interface{}, msiOut *map[string]interface{}) { + tblPath := rsd.tblPath + pubsub := rsd.pubsub + msi := make(map[string]interface{}) + // Initialize msi + for k, v := range (*msiInit) { + msi[k] = v + } + + for { + select { + default: + msgi, err := pubsub.ReceiveTimeout(time.Millisecond * 500) + if err != nil { + neterr, ok := err.(net.Error) + if ok { + if neterr.Timeout() == true { + continue + } + } + log.V(2).Infof("pubsub.ReceiveTimeout err %v", err) + continue + } + newMsi := make(map[string]interface{}) + subscr := msgi.(*redis.Message) + + if subscr.Payload == "hset" || subscr.Payload == "hsetnx" || subscr.Payload == "hmset" { + err = tableData2Msi(&tblPath, &newMsi) + if err != nil { + enqueFatalMsg(c, err.Error()) + return + } + + c.mu.Lock() + for k, v := range newMsi { + _, ok := msi[k] + if !ok { + (*msiOut)[k] = v + msi[k] = v + } else { + if v != msi[k] { + (*msiOut)[k] = v + msi[k] = v + } + } + } + c.mu.Unlock() + } + case <-c.channel: + log.V(2).Infof("Stopping dbSingleTableKeySubscribe routine for %+v", tblPath) + return + } + } +} + +// Subscribe to a specific gNMI path +func dbPathSubscribe(gnmiPath *gnmipb.Path, tblPaths []tablePath, c *DbClient) { + //tblPaths := c.pathG2S[gnmiPath] + msi := make(map[string]interface{}) + + for _, tblPath := range tblPaths { + err := tableData2Msi(&tblPath, &msi) + if err != nil { + enqueFatalMsg(c, err.Error()) + return + } + } + val, err := msi2TypedValue(msi) + if err != nil { + enqueFatalMsg(c, err.Error()) + return + } + + var spbv *spb.Value + spbv = &spb.Value{ + Prefix: c.prefix, + Path: gnmiPath, + Timestamp: time.Now().UnixNano(), + Val: val, + } + if err = c.q.Put(Value{spbv}); err != nil { + log.V(1).Infof("Queue error: %v", err) + return + } + + // First sync for this key is done + c.synced.Done() + + msiInit := make(map[string]interface{}) + for k, v := range msi { + msiInit[k] = v + } + for k := range msi { + delete(msi, k) + } + + // Redis pubsub to monitor table keys + for _, tblPath := range tblPaths { + dbName := tblPath.dbName + keyName := tblPath.keyName + redisDb := Target2RedisDb[dbName] + + // Subscribe to keyspace notification + pattern := "__keyspace@" + strconv.Itoa(int(spb.Target_value[dbName])) + "__:" + pattern += keyName + pubsub := redisDb.PSubscribe(pattern) + defer pubsub.Close() + + msgi, err := pubsub.ReceiveTimeout(time.Second) + if err != nil { + log.V(1).Infof("psubscribe to %s failed for %v", pattern, tblPath) + enqueFatalMsg(c, fmt.Sprintf("psubscribe to %s failed for %v", pattern, tblPath)) + return + } + + subscr := msgi.(*redis.Subscription) + if subscr.Channel != pattern { + log.V(1).Infof("psubscribe to %s failed for %v", pattern, tblPath) + enqueFatalMsg(c, fmt.Sprintf("psubscribe to %s failed for %v", pattern, tblPath)) + return + } + log.V(2).Infof("Psubscribe succeeded for %v: %v", tblPath, subscr) + + rsd := redisSubData { + tblPath: tblPath, + pubsub: pubsub, + } + go dbSingleTableKeySubscribe(rsd, c, &msiInit, &msi) + } + + for { + select { + default : + val = nil + err = nil + c.mu.Lock() + if len(msi) > 0 { + val, err = msi2TypedValue(msi) + for k := range msi { + delete(msi, k) + } + } + c.mu.Unlock() + + if err != nil { + enqueFatalMsg(c, err.Error()) + return + } + + if val != nil { + spbv = &spb.Value{ + Path: gnmiPath, + Timestamp: time.Now().UnixNano(), + Val: val, + } + + log.V(5).Infof("dbTableKeySubscribe enque: %v", spbv) + if err = c.q.Put(Value{spbv}); err != nil { + log.V(1).Infof("Queue error: %v", err) + return + } + } + + // check possible value change every 100 millisecond + // TODO: make all the instances of wait timer consistent + time.Sleep(time.Millisecond * 100) + case <-c.channel: + log.V(1).Infof("Stopping dbTableKeySubscribe routine for %v ", gnmiPath) + return + } + } +} diff --git a/new_sonic_data_client/trie.go b/new_sonic_data_client/trie.go new file mode 100644 index 000000000..cee88775d --- /dev/null +++ b/new_sonic_data_client/trie.go @@ -0,0 +1,114 @@ +package client + +import ( + //"fmt" +) + +type PathNode struct { + val string + depth int + term bool + children map[string]*PathNode + parent *PathNode + meta interface{} +} + +type PathTrie struct { + root *PathNode + size int +} + +func NewPathTrie() *PathTrie { + return &PathTrie{ + root: &PathNode{children: make(map[string]*PathNode), depth: 0}, + size: 0, + } +} + +// Adds an entry to the Trie, including meta data. Meta data +// is stored as 'interface{}' and must be type cast by the caller +func (t *PathTrie) Add(keys []string, meta interface{}) *PathNode{ + node := t.root + for _, key := range keys { + if _, ok := node.children[key]; !ok { + // A new PathNode + newNode := PathNode{ + val: key, + depth: node.depth + 1, + term: false, + children: make(map[string]*PathNode), + parent: node, + meta: meta, + } + node.children[key] = &newNode + } + node = node.children[key] + } + node.meta = meta + node.term = true + return node +} + +// Returns the parent of this node +func (n PathNode) Parent() *PathNode { + return n.parent +} + +func (n PathNode) Meta() interface{} { + return n.meta +} + +func (n PathNode) Terminating() bool { + return n.term +} + +func (n PathNode) Val() string { + return n.val +} + +func (n PathNode) Children() map[string]*PathNode { + return n.children +} + +func findPathNode(node *PathNode, keys []string, result *[]*PathNode) { + // gNMI path convention: + // '...' is multi-level wildcard, and '*' is single-level wildcard + + if len(keys) == 0 { + if node.Terminating() == true { + *result = append(*result, node) + } + return + } + + key := keys[0] + if node.Terminating() == true { + // Leaf node + if (len(keys) == 1) && (key == "...") { + *result = append(*result, node) + } + return + } + + children := node.Children() + if key == "..." { + if len(keys) > 1 { + if child, ok := children[keys[1]]; ok{ + findPathNode(child, keys[2:], result) + } + } + for _, child := range children { + findPathNode(child, keys, result) + } + } else if key == "*" { + for _, child := range children { + findPathNode(child, keys[1:], result) + } + } else { + if child, ok := children[key]; ok { + findPathNode(child, keys[1:], result) + } + } + return +} + diff --git a/new_vpath.go b/new_vpath.go new file mode 100644 index 000000000..44af3f92c --- /dev/null +++ b/new_vpath.go @@ -0,0 +1,68 @@ +package client + +import ( + "fmt" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" +) + + +func deepCopyPath(path, copyPath *gnmipb.Path) error { + elems := path.GetElem() + for _, elem := range elems { + copyElem := gnmipb.PathElem{} + copyElem.Name = elem.GetName() + copyElem.Key = make(map[string]string) + for k, v := range elem.GetKey() { + copyElem.Key[k] = v + } + copyPath.Elem = append(copyPath.Elem, ©Elem) + } + return nil +} + + +// Populate real data paths from virtual paths like +//[Interfaces Port Queue Pfcwd] +func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]newtablePath) error { + fmt.Printf("path: %v\n", path) + + elems := path.GetElem() + // If port name is wildcard + idx_port := 1 + keys := elems[idx_port].GetKey() + if portName, ok := keys["name"]; !ok{ + return fmt.Errorf("Missing port name in request %v", path) + } + + if portName == "*" { + // All Ethernet ports + for port, _ := range countersPortNameMap { + var oport string + if alias, ok := name2aliasMap[port]; ok { + oport = alias + } else { + log.V(2).Infof("%v does not have a vendor alias", port) + oport = port + } + + // Make a deep copy of the elems + copyPath := gnmipb.Path{} + deepCopyPath(path, ©Path) + copyElems := copyPath.GetElem() + keys = copyElems[idx_port].GetKey() + keys["name"] = oport + err := v2rPortQueuePfcwdstats(copyPath, pathG2S) + if err != nil { + return err + } + } + } + + + // If queue is wildcard + //idx_que := 2 + //keys = elems[idx_que].GetKey() + //if queName, ok := keys["name"]; !ok{ + // return nil, fmt.Errorf("Missing queue name in request %v", path) + //} +} diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index f2b93a5b0..0075b5af6 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -23,8 +23,8 @@ import ( const ( // indentString represents the default indentation string used for // JSON. Two spaces are used here. - indentString string = " " - Default_REDIS_UNIXSOCKET string = "/var/run/redis/redis.sock" + indentString string = " " + Default_REDIS_UNIXSOCKET string = "/var/run/redis/redis.sock" Default_REDIS_LOCAL_TCP_PORT string = "localhost:6379" ) @@ -60,11 +60,11 @@ var UseRedisLocalTcpPort bool = false var Target2RedisDb = make(map[string]*redis.Client) type tablePath struct { - dbName string + dbName string tableName string tableKey string delimitor string - field string + field string // path name to be used in json data which may be different // from the real data path. Ex. in Counters table, real tableKey // is oid:0x####, while key name like Ethernet## may be put @@ -72,7 +72,7 @@ type tablePath struct { jsonTableName string jsonTableKey string jsonDelimitor string - jsonField string + jsonField string } type Value struct { @@ -91,18 +91,19 @@ func (val Value) Compare(other queue.Item) int { } type DbClient struct { - prefix *gnmipb.Path + prefix *gnmipb.Path pathG2S map[*gnmipb.Path][]tablePath - q *queue.PriorityQueue + + q *queue.PriorityQueue channel chan struct{} synced sync.WaitGroup // Control when to send gNMI sync_response - w *sync.WaitGroup // wait for all sub go routines to finish - mu sync.RWMutex // Mutex for data protection among routines for DbClient + w *sync.WaitGroup // wait for all sub go routines to finish + mu sync.RWMutex // Mutex for data protection among routines for DbClient sendMsg int64 recvMsg int64 - errors int64 + errors int64 } func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { @@ -112,6 +113,14 @@ func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { if UseRedisLocalTcpPort { useRedisTcpClient() } + + // TODO: Remove debug log + for _, _path := range paths { + fmt.Printf("single path: %v\n", _path) + } + + fmt.Printf("prefix: %v\n", prefix) + if prefix.GetTarget() == "COUNTERS_DB" { err = initCountersPortNameMap() if err != nil { @@ -145,7 +154,7 @@ func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { // String returns the target the client is querying. func (c *DbClient) String() string { // TODO: print gnmiPaths of this DbClient - return fmt.Sprintf("DbClient Prefix %v sendMsg %v, recvMsg %v", + return fmt.Sprintf("DbClient Prefix %v sendMsg %v, recvMsg %v", c.prefix.GetTarget(), c.sendMsg, c.recvMsg) } @@ -178,7 +187,7 @@ func (c *DbClient) StreamRun(q *queue.PriorityQueue, stop chan struct{}, w *sync // Inject sync message c.q.Put(Value{ &spb.Value{ - Timestamp: time.Now().UnixNano(), + Timestamp: time.Now().UnixNano(), SyncResponse: true, }, }) @@ -214,11 +223,11 @@ func (c *DbClient) PollRun(q *queue.PriorityQueue, poll chan struct{}, w *sync.W } spbv := &spb.Value{ - Prefix: c.prefix, - Path: gnmiPath, - Timestamp: time.Now().UnixNano(), + Prefix: c.prefix, + Path: gnmiPath, + Timestamp: time.Now().UnixNano(), SyncResponse: false, - Val: val, + Val: val, } c.q.Put(Value{spbv}) @@ -227,7 +236,7 @@ func (c *DbClient) PollRun(q *queue.PriorityQueue, poll chan struct{}, w *sync.W c.q.Put(Value{ &spb.Value{ - Timestamp: time.Now().UnixNano(), + Timestamp: time.Now().UnixNano(), SyncResponse: true, }, }) @@ -243,15 +252,16 @@ func (c *DbClient) Get(w *sync.WaitGroup) ([]*spb.Value, error) { ts := time.Now() for gnmiPath, tblPaths := range c.pathG2S { val, err := tableData2TypedValue(tblPaths, nil) + //log.V(5).Infof("Val: %v\n", val) if err != nil { return nil, err } values = append(values, &spb.Value{ Prefix: c.prefix, - Path: gnmiPath, + Path: gnmiPath, Timestamp: ts.UnixNano(), - Val: val, + Val: val, }) } log.V(6).Infof("Getting #%v", values) @@ -324,10 +334,10 @@ func useRedisTcpClient() { var redisDb *redis.Client if UseRedisLocalTcpPort { redisDb = redis.NewClient(&redis.Options{ - Network: "tcp", - Addr: Default_REDIS_LOCAL_TCP_PORT, - Password: "", // no password set - DB: int(dbn), + Network: "tcp", + Addr: Default_REDIS_LOCAL_TCP_PORT, + Password: "", // no password set + DB: int(dbn), DialTimeout: 0, }) } @@ -344,10 +354,10 @@ func init() { var redisDb *redis.Client redisDb = redis.NewClient(&redis.Options{ - Network: "unix", - Addr: Default_REDIS_UNIXSOCKET, - Password: "", // no password set - DB: int(dbn), + Network: "unix", + Addr: Default_REDIS_UNIXSOCKET, + Password: "", // no password set + DB: int(dbn), DialTimeout: 0, }) Target2RedisDb[dbName] = redisDb @@ -496,6 +506,12 @@ func makeJSON_redis(msi *map[string]interface{}, key *string, op *string, mfv ma for f, v := range mfv { (*msi)[f] = v } + // Debug log + //log.V(5).Infof("msi: %v\n", msi) + //log.V(5).Infof("key: %v\n", key) + //log.V(5).Infof("op: %v\n", op) + //log.V(5).Infof("fv: %v\n", mfv) + return nil } @@ -515,6 +531,12 @@ func makeJSON_redis(msi *map[string]interface{}, key *string, op *string, mfv ma of[*op] = fp (*msi)[*key] = of } + + // Debug log + //log.V(5).Infof("msi: %v\n", msi) + //log.V(5).Infof("key: %v\n", key) + //log.V(5).Infof("op: %v\n", op) + //log.V(5).Infof("fv: %v\n", mfv) return nil } @@ -589,6 +611,7 @@ func tableData2Msi(tblPath *tablePath, useKey bool, op *string, msi *map[string] // Split dbkey string into two parts and second part is key in table keys := strings.SplitN(dbkey, tblPath.delimitor, 2) key = keys[1] + err = makeJSON_redis(msi, &key, op, fv) } if err != nil { @@ -597,6 +620,7 @@ func tableData2Msi(tblPath *tablePath, useKey bool, op *string, msi *map[string] } log.V(6).Infof("Added idex %v fv %v ", idx, fv) } + return nil } @@ -644,6 +668,9 @@ func tableData2TypedValue(tblPaths []tablePath, op *string) (*gnmipb.TypedValue, } } + // Debug logging + log.V(5).Infof("tblPath: %v\n", tblPath) + err := tableData2Msi(&tblPath, useKey, nil, &msi) if err != nil { return nil, err @@ -656,7 +683,7 @@ func enqueFatalMsg(c *DbClient, msg string) { c.q.Put(Value{ &spb.Value{ Timestamp: time.Now().UnixNano(), - Fatal: msg, + Fatal: msg, }, }) } @@ -724,9 +751,9 @@ func dbFieldMultiSubscribe(gnmiPath *gnmipb.Path, c *DbClient) { spbv := &spb.Value{ Prefix: c.prefix, - Path: gnmiPath, + Path: gnmiPath, Timestamp: time.Now().UnixNano(), - Val: val, + Val: val, } if err = c.q.Put(Value{spbv}); err != nil { @@ -783,7 +810,7 @@ func dbFieldSubscribe(gnmiPath *gnmipb.Path, c *DbClient) { if newVal != val { spbv := &spb.Value{ Prefix: c.prefix, - Path: gnmiPath, + Path: gnmiPath, Timestamp: time.Now().UnixNano(), Val: &gnmipb.TypedValue{ Value: &gnmipb.TypedValue_StringVal{ @@ -810,7 +837,7 @@ func dbFieldSubscribe(gnmiPath *gnmipb.Path, c *DbClient) { type redisSubData struct { tblPath tablePath - pubsub *redis.PubSub + pubsub *redis.PubSub prefixLen int } @@ -958,9 +985,9 @@ func dbTableKeySubscribe(gnmiPath *gnmipb.Path, c *DbClient) { var spbv *spb.Value spbv = &spb.Value{ Prefix: c.prefix, - Path: gnmiPath, + Path: gnmiPath, Timestamp: time.Now().UnixNano(), - Val: val, + Val: val, } if err = c.q.Put(Value{spbv}); err != nil { log.V(1).Infof("Queue error: %v", err) @@ -990,9 +1017,9 @@ func dbTableKeySubscribe(gnmiPath *gnmipb.Path, c *DbClient) { } if val != nil { spbv = &spb.Value{ - Path: gnmiPath, + Path: gnmiPath, Timestamp: time.Now().UnixNano(), - Val: val, + Val: val, } log.V(5).Infof("dbTableKeySubscribe enque: %v", spbv) From b2c6c5ef99dd6bb806d707c6e2ba886e25ecab76 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Mon, 25 Mar 2019 19:26:03 +0000 Subject: [PATCH 05/20] Unit tests for virtual database target SONiC, rename new_sonic_data_client to virtual_database_client --- dialout/dialout_client/dialout_client_test.go | 4 +- gnmi_server/client_subscribe.go | 11 +- gnmi_server/server.go | 12 +- gnmi_server/server_test.go | 18 +- new_sonic_data_client/map_init.go | 219 ------------ new_vpath.go | 68 ---- sonic_data_client/virtual_db.go | 6 +- telemetry/telemetry.go | 4 +- ...ces_Port_name_Ethernet68_1_BaseCounter.txt | 84 +++++ ...aces_Port_name_Ethernet68_1_PfcCounter.txt | 18 + ...e_Ethernet68_1_Queue_name_Queue4_Pfcwd.txt | 6 + ...net68_1_Queue_name_Queue4_QueueCounter.txt | 6 + .../db_client.go | 0 virtual_database_client/db_client_test.go | 313 ++++++++++++++++++ .../handler_func.go | 0 .../handler_pfc_counter.go | 77 ++--- .../handler_pfcwd.go | 102 +++--- .../handler_port_counter.go | 71 ++-- .../handler_queue_counter.go | 32 +- virtual_database_client/map_init.go | 219 ++++++++++++ .../path.go | 0 .../trie.go | 0 22 files changed, 825 insertions(+), 445 deletions(-) delete mode 100644 new_sonic_data_client/map_init.go delete mode 100644 new_vpath.go create mode 100644 testdata/Interfaces_Port_name_Ethernet68_1_BaseCounter.txt create mode 100644 testdata/Interfaces_Port_name_Ethernet68_1_PfcCounter.txt create mode 100644 testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_Pfcwd.txt create mode 100644 testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_QueueCounter.txt rename {new_sonic_data_client => virtual_database_client}/db_client.go (100%) create mode 100644 virtual_database_client/db_client_test.go rename {new_sonic_data_client => virtual_database_client}/handler_func.go (100%) rename {new_sonic_data_client => virtual_database_client}/handler_pfc_counter.go (55%) rename {new_sonic_data_client => virtual_database_client}/handler_pfcwd.go (76%) rename {new_sonic_data_client => virtual_database_client}/handler_port_counter.go (61%) rename {new_sonic_data_client => virtual_database_client}/handler_queue_counter.go (88%) create mode 100644 virtual_database_client/map_init.go rename {new_sonic_data_client => virtual_database_client}/path.go (100%) rename {new_sonic_data_client => virtual_database_client}/trie.go (100%) diff --git a/dialout/dialout_client/dialout_client_test.go b/dialout/dialout_client/dialout_client_test.go index 11cd040fc..644d2e260 100644 --- a/dialout/dialout_client/dialout_client_test.go +++ b/dialout/dialout_client/dialout_client_test.go @@ -30,10 +30,10 @@ import ( //sds "github.com/Azure/sonic-telemetry/dialout/dialout_server" spb "github.com/Azure/sonic-telemetry/proto" - sds "test/sonic-telemetry-pfcwd/dialout/dialout_server" + sds "test/sonic-telemetry-new-pfcwd/dialout/dialout_server" //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" gclient "github.com/openconfig/gnmi/client/gnmi" - sdc "test/sonic-telemetry-pfcwd/sonic_data_client" + sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" ) var clientTypes = []string{gclient.Type} diff --git a/gnmi_server/client_subscribe.go b/gnmi_server/client_subscribe.go index b55357240..afa07402d 100644 --- a/gnmi_server/client_subscribe.go +++ b/gnmi_server/client_subscribe.go @@ -13,9 +13,10 @@ import ( //spb "github.com/Azure/sonic-telemetry/proto" //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" - gnmipb "github.com/openconfig/gnmi/proto/gnmi" sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" - newdc "test/sonic-telemetry-new-pfcwd/new_sonic_data_client" + vdc "test/sonic-telemetry-new-pfcwd/virtual_database_client" + + gnmipb "github.com/openconfig/gnmi/proto/gnmi" ) // Client contains information about a subscribe client that has connected to the server. @@ -123,7 +124,7 @@ func (c *Client) Run(stream gnmipb.GNMI_SubscribeServer) (err error) { if target == "OTHERS" { dc, err = sdc.NewNonDbClient(paths, prefix) } else if target == "SONiC_DB" { - dc, err = newdc.NewDbClient(paths, prefix) + dc, err = vdc.NewDbClient(paths, prefix) } else { dc, err = sdc.NewDbClient(paths, prefix) } @@ -231,8 +232,8 @@ func (c *Client) send(stream gnmipb.GNMI_SubscribeServer) error { c.errors++ return err } - case newdc.Value: - if resp, err = newdc.ValToResp(v); err != nil { + case vdc.Value: + if resp, err = vdc.ValToResp(v); err != nil { c.errors++ return err } diff --git a/gnmi_server/server.go b/gnmi_server/server.go index d032364e8..ddfb94fd4 100644 --- a/gnmi_server/server.go +++ b/gnmi_server/server.go @@ -15,9 +15,10 @@ import ( "google.golang.org/grpc/reflection" "google.golang.org/grpc/status" - gnmipb "github.com/openconfig/gnmi/proto/gnmi" sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" - newdc "test/sonic-telemetry-new-pfcwd/new_sonic_data_client" + vdc "test/sonic-telemetry-new-pfcwd/virtual_database_client" + + gnmipb "github.com/openconfig/gnmi/proto/gnmi" ) var ( @@ -78,6 +79,11 @@ func (srv *Server) Serve() error { return srv.s.Serve(srv.lis) } +func (srv *Server) Stop() { + s := srv.s + s.Stop() +} + // Address returns the port the Server is listening to. func (srv *Server) Address() string { addr := srv.lis.Addr().String() @@ -176,7 +182,7 @@ func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetRe if target == "OTHERS" { dc, err = sdc.NewNonDbClient(paths, prefix) } else if target == "SONiC_DB" { - dc, err = newdc.NewDbClient(paths, prefix) + dc, err = vdc.NewDbClient(paths, prefix) } else { dc, err = sdc.NewDbClient(paths, prefix) } diff --git a/gnmi_server/server_test.go b/gnmi_server/server_test.go index 59222b28a..253600b58 100644 --- a/gnmi_server/server_test.go +++ b/gnmi_server/server_test.go @@ -6,10 +6,18 @@ package gnmi import ( "crypto/tls" "encoding/json" + testcert "github.com/Azure/sonic-telemetry/testdata/tls" "github.com/go-redis/redis" "github.com/golang/protobuf/proto" + "io/ioutil" + "os" + "os/exec" + "reflect" + "testing" + "time" + "github.com/kylelemons/godebug/pretty" "github.com/openconfig/gnmi/client" pb "github.com/openconfig/gnmi/proto/gnmi" @@ -19,17 +27,13 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/status" - "io/ioutil" - "os" - "os/exec" - "reflect" - "testing" - "time" + // Register supported client types. spb "github.com/Azure/sonic-telemetry/proto" //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" - gclient "github.com/jipanyang/gnmi/client/gnmi" sdc "test/sonic-telemetry-pfcwd/sonic_data_client" + + gclient "github.com/jipanyang/gnmi/client/gnmi" ) var clientTypes = []string{gclient.Type} diff --git a/new_sonic_data_client/map_init.go b/new_sonic_data_client/map_init.go deleted file mode 100644 index 4bfab332f..000000000 --- a/new_sonic_data_client/map_init.go +++ /dev/null @@ -1,219 +0,0 @@ -package client - -import ( - "fmt" - log "github.com/golang/glog" - "strings" -) - -var ( - // Port name to oid map in COUNTERS table of COUNTERS_DB - countersPortNameMap = make(map[string]string) - - // Queue name to oid map in COUNTERS table of COUNTERS_DB - //countersQueueNameMap = make(map[string]string) - countersQueueNameMap = make(map[string]map[string]string) - - // Alias translation: from vendor port name to sonic interface name - alias2nameMap = make(map[string]string) - // Alias translation: from sonic interface name to vendor port name - name2aliasMap = make(map[string]string) - - // SONiC interface name to their PFC-WD enabled queues, then to oid map - countersPfcwdNameMap = make(map[string]map[string]string) -) - -func initCountersQueueNameMap() error { - dbName := "COUNTERS_DB" - separator, _ := GetTableKeySeparator(dbName) - - if len(countersQueueNameMap) == 0 { - queueMap, err := getCountersMap("COUNTERS_QUEUE_NAME_MAP") - if err != nil { - return err - } - for k, v := range queueMap { - stringSlice := strings.Split(k, separator) - port := stringSlice[0] - if _, ok := countersQueueNameMap[port]; !ok { - countersQueueNameMap[port] = make(map[string]string) - } - countersQueueNameMap[port][k] = v - } - } - return nil -} - -func initCountersPortNameMap() error { - var err error - if len(countersPortNameMap) == 0 { - countersPortNameMap, err = getCountersMap("COUNTERS_PORT_NAME_MAP") - if err != nil { - return err - } - } - return nil -} - -func initAliasMap() error { - var err error - if len(alias2nameMap) == 0 { - alias2nameMap, name2aliasMap, err = getAliasMap() - if err != nil { - return err - } - } - return nil -} - -func initCountersPfcwdNameMap() error { - var err error - if len(countersPfcwdNameMap) == 0 { - countersPfcwdNameMap, err = getPfcwdMap() - 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) - - dbName := "CONFIG_DB" - separator, _ := GetTableKeySeparator(dbName) - redisDb, _ := Target2RedisDb[dbName] - _, err := redisDb.Ping().Result() - if err != nil { - log.V(1).Infof("Can not connect to %v, err: %v", dbName, err) - return nil, err - } - - keyName := fmt.Sprintf("PFC_WD_TABLE%v*", separator) - resp, err := redisDb.Keys(keyName).Result() - if err != nil { - log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) - return nil, err - } - - if len(resp) == 0 { - // PFC WD service not enabled on device - log.V(1).Infof("PFC WD not enabled on device") - return nil, nil - } - - for _, key := range resp { - name := key[13:] - pfcwdName_map[name] = make(map[string]string) - } - - // Get Queue indexes that are enabled with PFC-WD - keyName = "PORT_QOS_MAP*" - resp, err = redisDb.Keys(keyName).Result() - if err != nil { - log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) - return nil, err - } - if len(resp) == 0 { - log.V(1).Infof("PFC WD not enabled on device") - return nil, nil - } - qos_key := resp[0] - - fieldName := "pfc_enable" - priorities, err := redisDb.HGet(qos_key, fieldName).Result() - if err != nil { - log.V(1).Infof("redis get field failed for %v, key = %v, field = %v, err: %v", dbName, qos_key, fieldName, err) - return nil, err - } - - keyName = fmt.Sprintf("MAP_PFC_PRIORITY_TO_QUEUE%vAZURE", separator) - pfc_queue_map, err := redisDb.HGetAll(keyName).Result() - if err != nil { - log.V(1).Infof("redis get fields failed for %v, key = %v, err: %v", dbName, keyName, err) - return nil, err - } - - var indices []string - for _, p := range strings.Split(priorities, ",") { - _, ok := pfc_queue_map[p] - if !ok { - log.V(1).Infof("Missing mapping between PFC priority %v to queue", p) - } else { - indices = append(indices, pfc_queue_map[p]) - } - } - - if len(countersQueueNameMap) == 0 { - log.V(1).Infof("COUNTERS_QUEUE_NAME_MAP is empty") - return nil, nil - } - - var queue_key string - queue_separator, _ := GetTableKeySeparator("COUNTERS_DB") - for port, _ := range pfcwdName_map { - for _, indice := range indices { - queue_key = port + queue_separator + indice - oid, ok := countersQueueNameMap[port][queue_key] - if !ok { - return nil, fmt.Errorf("key %v not exists in COUNTERS_QUEUE_NAME_MAP", queue_key) - } - pfcwdName_map[port][queue_key] = oid - } - } - - log.V(6).Infof("countersPfcwdNameMap: %v", pfcwdName_map) - return pfcwdName_map, nil -} - -// Get the mapping between sonic interface name and vendor alias -func getAliasMap() (map[string]string, map[string]string, error) { - var alias2name_map = make(map[string]string) - var name2alias_map = make(map[string]string) - - dbName := "CONFIG_DB" - separator, _ := GetTableKeySeparator(dbName) - redisDb, _ := Target2RedisDb[dbName] - _, err := redisDb.Ping().Result() - if err != nil { - log.V(1).Infof("Can not connect to %v, err: %v", dbName, err) - return nil, nil, err - } - - keyName := fmt.Sprintf("PORT%v*", separator) - resp, err := redisDb.Keys(keyName).Result() - if err != nil { - log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) - return nil, nil, err - } - for _, key := range resp { - alias, err := redisDb.HGet(key, "alias").Result() - if err != nil { - log.V(1).Infof("redis get field alias failed for %v, key = %v, err: %v", dbName, key, err) - // clear aliasMap - alias2name_map = make(map[string]string) - name2alias_map = make(map[string]string) - return nil, nil, err - } - alias2name_map[alias] = key[5:] - name2alias_map[key[5:]] = alias - } - log.V(6).Infof("alias2nameMap: %v", alias2name_map) - log.V(6).Infof("name2aliasMap: %v", name2alias_map) - return alias2name_map, name2alias_map, nil -} - -// Get the mapping between objects in counters DB, Ex. port name to oid in "COUNTERS_PORT_NAME_MAP" table. -// Aussuming static port name to oid map in COUNTERS table -func getCountersMap(tableName string) (map[string]string, error) { - redisDb, _ := Target2RedisDb["COUNTERS_DB"] - fv, err := redisDb.HGetAll(tableName).Result() - if err != nil { - log.V(2).Infof("redis HGetAll failed for COUNTERS_DB, tableName: %s", tableName) - return nil, err - } - log.V(6).Infof("tableName: %s, map %v", tableName, fv) - return fv, nil -} - diff --git a/new_vpath.go b/new_vpath.go deleted file mode 100644 index 44af3f92c..000000000 --- a/new_vpath.go +++ /dev/null @@ -1,68 +0,0 @@ -package client - -import ( - "fmt" - gnmipb "github.com/openconfig/gnmi/proto/gnmi" -) - - -func deepCopyPath(path, copyPath *gnmipb.Path) error { - elems := path.GetElem() - for _, elem := range elems { - copyElem := gnmipb.PathElem{} - copyElem.Name = elem.GetName() - copyElem.Key = make(map[string]string) - for k, v := range elem.GetKey() { - copyElem.Key[k] = v - } - copyPath.Elem = append(copyPath.Elem, ©Elem) - } - return nil -} - - -// Populate real data paths from virtual paths like -//[Interfaces Port Queue Pfcwd] -func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]newtablePath) error { - fmt.Printf("path: %v\n", path) - - elems := path.GetElem() - // If port name is wildcard - idx_port := 1 - keys := elems[idx_port].GetKey() - if portName, ok := keys["name"]; !ok{ - return fmt.Errorf("Missing port name in request %v", path) - } - - if portName == "*" { - // All Ethernet ports - for port, _ := range countersPortNameMap { - var oport string - if alias, ok := name2aliasMap[port]; ok { - oport = alias - } else { - log.V(2).Infof("%v does not have a vendor alias", port) - oport = port - } - - // Make a deep copy of the elems - copyPath := gnmipb.Path{} - deepCopyPath(path, ©Path) - copyElems := copyPath.GetElem() - keys = copyElems[idx_port].GetKey() - keys["name"] = oport - err := v2rPortQueuePfcwdstats(copyPath, pathG2S) - if err != nil { - return err - } - } - } - - - // If queue is wildcard - //idx_que := 2 - //keys = elems[idx_que].GetKey() - //if queName, ok := keys["name"]; !ok{ - // return nil, fmt.Errorf("Missing queue name in request %v", path) - //} -} diff --git a/sonic_data_client/virtual_db.go b/sonic_data_client/virtual_db.go index 7b1592cf7..9bea54331 100644 --- a/sonic_data_client/virtual_db.go +++ b/sonic_data_client/virtual_db.go @@ -2,8 +2,9 @@ package client import ( "fmt" - log "github.com/golang/glog" "strings" + + log "github.com/golang/glog" ) // virtual db is to Handle @@ -290,6 +291,7 @@ func v2rEthPortStats(paths []string) ([]tablePath, error) { } oid, ok := countersPortNameMap[name] if !ok { + log.V(1).Infof("RANDY: 5") return nil, fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", name, alias) } tblPaths = []tablePath{{ @@ -342,6 +344,7 @@ func v2rEthPortFieldStats(paths []string) ([]tablePath, error) { } oid, ok := countersPortNameMap[name] if !ok { + log.V(1).Infof("RANDY: 6") return nil, fmt.Errorf(" %v not a valid sonic interface. Vendor alias is %v ", name, alias) } tblPaths = []tablePath{{ @@ -392,6 +395,7 @@ func v2rEthPortPfcwdStats(paths []string) ([]tablePath, error) { } _, ok := countersPortNameMap[name] if !ok { + log.V(1).Infof("RANDY: 7") return nil, fmt.Errorf("%v not a valid SONiC interface. Vendor alias is %v", name, alias) } diff --git a/telemetry/telemetry.go b/telemetry/telemetry.go index b10430457..624475f73 100644 --- a/telemetry/telemetry.go +++ b/telemetry/telemetry.go @@ -10,7 +10,9 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" - gnmi "github.com/Azure/sonic-telemetry/gnmi_server" + //gnmi "github.com/Azure/sonic-telemetry/gnmi_server" + gnmi "test/sonic-telemetry-new-pfcwd/gnmi_server" + testcert "github.com/Azure/sonic-telemetry/testdata/tls" ) diff --git a/testdata/Interfaces_Port_name_Ethernet68_1_BaseCounter.txt b/testdata/Interfaces_Port_name_Ethernet68_1_BaseCounter.txt new file mode 100644 index 000000000..7c0f87b6d --- /dev/null +++ b/testdata/Interfaces_Port_name_Ethernet68_1_BaseCounter.txt @@ -0,0 +1,84 @@ +{ + "SAI_PORT_STAT_ETHER_IN_PKTS_1024_TO_1518_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_128_TO_255_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_1519_TO_2047_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_2048_TO_4095_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_256_TO_511_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_4096_TO_9216_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_512_TO_1023_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_64_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_65_TO_127_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_9217_TO_16383_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_1024_TO_1518_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_128_TO_255_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_1519_TO_2047_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_2048_TO_4095_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_256_TO_511_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_4096_TO_9216_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_512_TO_1023_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_64_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_65_TO_127_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_9217_TO_16383_OCTETS": "0", + "SAI_PORT_STAT_ETHER_RX_OVERSIZE_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_BROADCAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_COLLISIONS": "0", + "SAI_PORT_STAT_ETHER_STATS_CRC_ALIGN_ERRORS": "0", + "SAI_PORT_STAT_ETHER_STATS_DROP_EVENTS": "0", + "SAI_PORT_STAT_ETHER_STATS_FRAGMENTS": "0", + "SAI_PORT_STAT_ETHER_STATS_JABBERS": "0", + "SAI_PORT_STAT_ETHER_STATS_MULTICAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_OVERSIZE_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_1024_TO_1518_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_128_TO_255_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_1519_TO_2047_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_2048_TO_4095_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_256_TO_511_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_4096_TO_9216_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_512_TO_1023_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_64_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_65_TO_127_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_9217_TO_16383_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_RX_NO_ERRORS": "0", + "SAI_PORT_STAT_ETHER_STATS_TX_NO_ERRORS": "0", + "SAI_PORT_STAT_ETHER_STATS_UNDERSIZE_PKTS": "0", + "SAI_PORT_STAT_ETHER_TX_OVERSIZE_PKTS": "0", + "SAI_PORT_STAT_IF_IN_BROADCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_DISCARDS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_MULTICAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_UNKNOWN_PROTOS": "0", + "SAI_PORT_STAT_IF_IN_VLAN_DISCARDS": "0", + "SAI_PORT_STAT_IF_OUT_BROADCAST_PKTS": "0", + "SAI_PORT_STAT_IF_OUT_DISCARDS": "0", + "SAI_PORT_STAT_IF_OUT_ERRORS": "0", + "SAI_PORT_STAT_IF_OUT_MULTICAST_PKTS": "0", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_OUT_QLEN": "0", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "0", + "SAI_PORT_STAT_IPV6_IN_DISCARDS": "0", + "SAI_PORT_STAT_IPV6_IN_MCAST_PKTS": "0", + "SAI_PORT_STAT_IPV6_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IPV6_IN_OCTETS": "0", + "SAI_PORT_STAT_IPV6_IN_RECEIVES": "0", + "SAI_PORT_STAT_IPV6_IN_UCAST_PKTS": "0", + "SAI_PORT_STAT_IPV6_OUT_DISCARDS": "0", + "SAI_PORT_STAT_IPV6_OUT_MCAST_PKTS": "0", + "SAI_PORT_STAT_IPV6_OUT_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IPV6_OUT_OCTETS": "0", + "SAI_PORT_STAT_IPV6_OUT_UCAST_PKTS": "0", + "SAI_PORT_STAT_IP_IN_DISCARDS": "0", + "SAI_PORT_STAT_IP_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IP_IN_OCTETS": "0", + "SAI_PORT_STAT_IP_IN_RECEIVES": "0", + "SAI_PORT_STAT_IP_IN_UCAST_PKTS": "0", + "SAI_PORT_STAT_IP_OUT_DISCARDS": "0", + "SAI_PORT_STAT_IP_OUT_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IP_OUT_OCTETS": "0", + "SAI_PORT_STAT_IP_OUT_UCAST_PKTS": "0" +} diff --git a/testdata/Interfaces_Port_name_Ethernet68_1_PfcCounter.txt b/testdata/Interfaces_Port_name_Ethernet68_1_PfcCounter.txt new file mode 100644 index 000000000..93ac64469 --- /dev/null +++ b/testdata/Interfaces_Port_name_Ethernet68_1_PfcCounter.txt @@ -0,0 +1,18 @@ +{ + "SAI_PORT_STAT_PFC_0_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_0_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_1_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_1_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_2_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_2_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_3_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_3_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_4_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_4_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_5_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_5_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_6_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_6_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_7_RX_PKTS": "2", + "SAI_PORT_STAT_PFC_7_TX_PKTS": "0" +} diff --git a/testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_Pfcwd.txt b/testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_Pfcwd.txt new file mode 100644 index 000000000..f1fcd47f7 --- /dev/null +++ b/testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_Pfcwd.txt @@ -0,0 +1,6 @@ +{ + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_STATUS": "operational", + "SAI_PORT_STAT_PFC_4_RX_PKTS": "0" +} diff --git a/testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_QueueCounter.txt b/testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_QueueCounter.txt new file mode 100644 index 000000000..630a0a914 --- /dev/null +++ b/testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_QueueCounter.txt @@ -0,0 +1,6 @@ +{ + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0" +} diff --git a/new_sonic_data_client/db_client.go b/virtual_database_client/db_client.go similarity index 100% rename from new_sonic_data_client/db_client.go rename to virtual_database_client/db_client.go diff --git a/virtual_database_client/db_client_test.go b/virtual_database_client/db_client_test.go new file mode 100644 index 000000000..6aeb7eb8a --- /dev/null +++ b/virtual_database_client/db_client_test.go @@ -0,0 +1,313 @@ +package client_test + +// Prerequisite: redis-server should be running. + +import ( + "context" + tls "crypto/tls" + "encoding/json" + "io/ioutil" + "os" + "os/exec" + "reflect" + sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" + "testing" + "time" + + gnmi "test/sonic-telemetry-new-pfcwd/gnmi_server" + + xpath "github.com/jipanyang/gnxi/utils/xpath" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" + value "github.com/openconfig/gnmi/value" + + spb "github.com/Azure/sonic-telemetry/proto" + testcert "github.com/Azure/sonic-telemetry/testdata/tls" + redis "github.com/go-redis/redis" + "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + status "google.golang.org/grpc/status" +) + +func getRedisClient(t *testing.T, dbName string) *redis.Client { + dbn := spb.Target_value[dbName] + rclient := redis.NewClient(&redis.Options{ + Network: "tcp", + Addr: "localhost:6379", + Password: "", // no password set + DB: int(dbn), + DialTimeout: 0, + }) + _, err := rclient.Ping().Result() + if err != nil { + t.Fatal("failed to connect to redis server ", err) + } + return rclient +} + +func setTestDataToRedisDB(t *testing.T, rclient *redis.Client, mpi map[string]interface{}) { + for key, fv := range mpi { + switch fv.(type) { + case map[string]interface{}: + _, err := rclient.HMSet(key, fv.(map[string]interface{})).Result() + if err != nil { + t.Errorf("Invalid data for db: %v : %v %v", key, fv, err) + } + default: + t.Errorf("Invalid data for db: %v : %v", key, fv) + } + } +} + +func parseTestData(t *testing.T, key string, in []byte) map[string]interface{} { + var fvp map[string]interface{} + + err := json.Unmarshal(in, &fvp) + if err != nil { + t.Errorf("Failed to Unmarshal %v err: %v", in, err) + } + if key != "" { + kv := map[string]interface{}{} + kv[key] = fvp + return kv + } + return fvp +} + +func loadTestDataIntoRedis(t *testing.T, redisClient *redis.Client, dbKey string, testDataPath string) { + data, err := ioutil.ReadFile(testDataPath) + if err != nil { + t.Fatalf("read file %v err: %v", testDataPath, err) + } + data_kv_map := parseTestData(t, dbKey, data) + setTestDataToRedisDB(t, redisClient, data_kv_map) +} + +func prepareConfigDB(t *testing.T) { + configDB := getRedisClient(t, "CONFIG_DB") + defer configDB.Close() + configDB.FlushDB() + + loadTestDataIntoRedis(t, configDB, "", "../testdata/COUNTERS_PORT_ALIAS_MAP.txt") + loadTestDataIntoRedis(t, configDB, "", "../testdata/CONFIG_PFCWD_PORTS.txt") +} + +func creategNMIServer(t *testing.T) *gnmi.Server { + certificate, err := testcert.NewCert() + if err != nil { + t.Errorf("could not load server key pair: %s", err) + } + tlsCfg := &tls.Config{ + ClientAuth: tls.RequestClientCert, + Certificates: []tls.Certificate{certificate}, + } + + opts := []grpc.ServerOption{grpc.Creds(credentials.NewTLS(tlsCfg))} + cfg := &gnmi.Config{Port: 8080} + s, err := gnmi.NewServer(cfg, opts) + if err != nil { + t.Errorf("Failed to create gNMI server: %v", err) + } + + return s +} + +func rungNMIServer(t *testing.T, s *gnmi.Server) { + //t.Log("Starting RPC server on address:", s.Address()) + err := s.Serve() // blocks until close + if err != nil { + t.Fatalf("gRPC server err: %v", err) + } + //t.Log("Exiting RPC server on address", s.Address()) +} + +func sendGetRequest(t *testing.T, ctx context.Context, gnmiClient gnmipb.GNMIClient, xPath string, + pathToTargetDB string, expectedReturnCode codes.Code) *gnmipb.GetResponse { + // Issue Get RPC. + pbPath, err := xpath.ToGNMIPath(xPath) + if err != nil { + t.Fatalf("error in parsing xpath %q to gnmi path", xPath) + } + + prefix := gnmipb.Path{Target: pathToTargetDB} + request := &gnmipb.GetRequest{ + Prefix: &prefix, + Path: []*gnmipb.Path{pbPath}, + Encoding: gnmipb.Encoding_JSON_IETF, + } + + response, err := gnmiClient.Get(ctx, request) + + // Check return value and gRPC status code. + returnStatus, ok := status.FromError(err) + if !ok { + t.Fatal("got a non-grpc error from grpc call") + } + if returnStatus.Code() != expectedReturnCode { + t.Log("err: ", err) + t.Fatalf("got return code %v, expected %v", returnStatus.Code(), expectedReturnCode) + } + + return response +} + +func assertExpectedValue(t *testing.T, response *gnmipb.GetResponse, expectedResponseValue interface{}) { + var gotVal interface{} + if response != nil { + notifs := response.GetNotification() + if len(notifs) != 1 { + t.Fatalf("got %d notifications, want 1", len(notifs)) + } + updates := notifs[0].GetUpdate() + if len(updates) != 1 { + t.Fatalf("got %d updates in the notification, want 1", len(updates)) + } + val := updates[0].GetVal() + if val.GetJsonIetfVal() == nil { + gotVal, err := value.ToScalar(val) + if err != nil { + t.Errorf("got: %v, want a scalar value", gotVal) + } + } else { + // Unmarshal json data to gotVal container for comparison. + if err := json.Unmarshal(val.GetJsonIetfVal(), &gotVal); err != nil { + t.Fatalf("error in unmarshaling IETF JSON data to json container: %v", err) + } + var expectedJSONStruct interface{} + if err := json.Unmarshal(expectedResponseValue.([]byte), &expectedJSONStruct); err != nil { + t.Fatalf("error in unmarshaling IETF JSON data to json container: %v", err) + } + expectedResponseValue = expectedJSONStruct + } + } + + if !reflect.DeepEqual(gotVal, expectedResponseValue) { + t.Errorf("got: %v (%T),\nwant %v (%T)", gotVal, gotVal, expectedResponseValue, expectedResponseValue) + } +} + +func loadExpectedResponseByteData(t *testing.T, path string) interface{} { + data, err := ioutil.ReadFile(path) + if err != nil { + t.Fatalf("read file %v err: %v", path, err) + } + return data +} + +func TestVirtualPathClient(t *testing.T) { + // Open COUNTERS_DB redis client. + countersDB := getRedisClient(t, "COUNTERS_DB") + defer countersDB.Close() + countersDB.FlushDB() + + // Enable keyspace notification. + // Note (@ragaul): + // Don't know exactly why this is needed -- likely for testing pub/sub (need investigate + + // confirmation). Copied from gnmi_server/server_test.go + os.Setenv("PATH", "/usr/bin:/sbin:/bin:/usr/local/bin") + cmd := exec.Command("redis-cli", "config", "set", "notify-keyspace-events", "KEA") + _, err := cmd.Output() + if err != nil { + t.Fatal("failed to enable redis keyspace notification ", err) + } + + // Load test data into COUNTERS_DB. + loadTestDataIntoRedis(t, countersDB, "COUNTERS_PORT_NAME_MAP", "../testdata/COUNTERS_PORT_NAME_MAP.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS_QUEUE_NAME_MAP", "../testdata/COUNTERS_QUEUE_NAME_MAP.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1000000000039", "../testdata/COUNTERS:Ethernet68.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1000000000003", "../testdata/COUNTERS:Ethernet1.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000092a", "../testdata/COUNTERS:oid:0x1500000000092a.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000091c", "../testdata/COUNTERS:oid:0x1500000000091c.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000091e", "../testdata/COUNTERS:oid:0x1500000000091e.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000091f", "../testdata/COUNTERS:oid:0x1500000000091f.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000091f", "../testdata/COUNTERS:oid:0x1500000000091f.txt") + + // Load CONFIG_DB, flush old data, and load in test data. + prepareConfigDB(t) + + // Start telementry service. + gnmiServer := creategNMIServer(t) + if gnmiServer == nil { + t.Fatalf("Unable to bind gNMI server to local port 8080.") + } + go rungNMIServer(t, gnmiServer) + defer gnmiServer.Stop() + + // Create a GNMI client used to invoke RPCs. + tlsConfig := &tls.Config{InsecureSkipVerify: true} + opts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))} + + targetAddr := "127.0.0.1:8080" + conn, err := grpc.Dial(targetAddr, opts...) + if err != nil { + t.Fatalf("Dialing to %q failed: %v", targetAddr, err) + } + defer conn.Close() + + gnmiClient := gnmipb.NewGNMIClient(conn) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // Perform unit tests. + t.Run("Get Interfaces/Port[name=Ethernet68/1]/BaseCounter", func(t *testing.T) { + expectedReturnCode := codes.OK + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet68/1]/BaseCounter" + response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_BaseCounter.txt") + assertExpectedValue(t, response, expectedResponseValue) + }) + t.Run("Get Interfaces/Port[name=Ethernet68]/BaseCounter (no slash /1 after Ethernet68)", func(t *testing.T) { + expectedReturnCode := codes.OK + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet68]/BaseCounter" + response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_BaseCounter.txt") + assertExpectedValue(t, response, expectedResponseValue) + }) + t.Run("Get Interfaces/Port[name=Ethernet68/1]/PfcCounter", func(t *testing.T) { + expectedReturnCode := codes.OK + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet68/1]/PfcCounter" + response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_PfcCounter.txt") + assertExpectedValue(t, response, expectedResponseValue) + }) + t.Run("Get Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/Pfcwd", func(t *testing.T) { + expectedReturnCode := codes.OK + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/Pfcwd" + response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_Pfcwd.txt") + assertExpectedValue(t, response, expectedResponseValue) + }) + t.Run("Get Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/Pfcwd", func(t *testing.T) { + expectedReturnCode := codes.OK + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/QueueCounter" + response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_QueueCounter.txt") + assertExpectedValue(t, response, expectedResponseValue) + }) + t.Run("Get Interfaces/Port[name=Ethernet70], a valid path (with no corresponding data in the db); expected NotFound", func(t *testing.T) { + expectedReturnCode := codes.NotFound + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet70]" + response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + var expectedResponseValue interface{} = nil + assertExpectedValue(t, response, expectedResponseValue) + }) + t.Run("Get Interfaces/Port[name=*]/..., Retrieve everything under all ports", func(t *testing.T) { + expectedReturnCode := codes.OK + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=*]/..." + sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + // Only checking return code, since returned data will: A) require a large text file; B) change + // whenever new kinds of test data is loaded into the DB (for example when modifying tests). + }) +} + +func init() { + // Inform gNMI server to use redis tcp localhost connection + sdc.UseRedisLocalTcpPort = true +} diff --git a/new_sonic_data_client/handler_func.go b/virtual_database_client/handler_func.go similarity index 100% rename from new_sonic_data_client/handler_func.go rename to virtual_database_client/handler_func.go diff --git a/new_sonic_data_client/handler_pfc_counter.go b/virtual_database_client/handler_pfc_counter.go similarity index 55% rename from new_sonic_data_client/handler_pfc_counter.go rename to virtual_database_client/handler_pfc_counter.go index d660d6569..2b33192c4 100644 --- a/new_sonic_data_client/handler_pfc_counter.go +++ b/virtual_database_client/handler_pfc_counter.go @@ -18,8 +18,8 @@ func GetTmpl_PortPfcCounterStats(path *gnmipb.Path) { name = "Port" path.Elem = append(path.Elem, &gnmipb.PathElem{ - Name: name, - Key: map[string]string{"name": "*"}, + Name: name, + Key: map[string]string{"name": "*"}, }) name = "PfcCounter" @@ -34,9 +34,9 @@ func v2rPortPfcCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]table parentConfig := map[int]string{1: "Port"} - leaf := leafConfig { - idx: 2, - name: "PfcCounter", + leaf := leafConfig{ + idx: 2, + name: "PfcCounter", } target_fields := []string{} @@ -62,50 +62,51 @@ func pop_PortPfcCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl portName := elems[idx_port].GetKey()["name"] if portName == "*" { // Wildcard port name - for port, _ := range countersPortNameMap { - // Alias translation - var oport string - if alias, ok := name2aliasMap[port]; ok { - oport = alias - } else { - log.V(2).Infof("%v does not have a vendor alias", port) - oport = port - } - // Create a gNMI path for each port - var copyPath = gnmipb.Path{} - deepcopy(path, ©Path) - copyPath.Elem[idx_port].Key["name"] = oport - err := pop_PortPfcCounterStats(©Path, pathG2S, target_fields) + for port, _ := range countersPortNameMap { + // Alias translation + var oport string + if alias, ok := name2aliasMap[port]; ok { + oport = alias + } else { + log.V(2).Infof("%v does not have a vendor alias", port) + oport = port + } + // Create a gNMI path for each port + var copyPath = gnmipb.Path{} + deepcopy(path, ©Path) + copyPath.Elem[idx_port].Key["name"] = oport + err := pop_PortPfcCounterStats(©Path, pathG2S, target_fields) if err != nil { return err } - } - return nil - } - - // Alias translation - var alias, _name string - alias = portName - _name = alias - if val, ok := alias2nameMap[alias]; ok { - _name = val - } + } + return nil + } + + // Alias translation + var alias, _name string + alias = portName + _name = alias + if val, ok := alias2nameMap[alias]; ok { + _name = val + } oid_port, ok := countersPortNameMap[_name] if !ok { + log.V(1).Infof("RANDY: 1") return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) } - // TODO: Subscribe to only particular fields - if len(target_fields) > 0 { - return fmt.Errorf("Subscribe to field of Path: %v not supported", path) + // TODO: Subscribe to only particular fields + if len(target_fields) > 0 { + return fmt.Errorf("Subscribe to field of Path: %v not supported", path) } - tblPath_port := tablePath { - dbName: dbName, - keyName: strings.Join([]string{"COUNTERS", oid_port}, separator), - delimitor: separator, - patterns: []string{"SAI_PORT_STAT_PFC_._RX_PKTS$", "SAI_PORT_STAT_PFC_._TX_PKTS$"}, + tblPath_port := tablePath{ + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_port}, separator), + delimitor: separator, + patterns: []string{"SAI_PORT_STAT_PFC_._RX_PKTS$", "SAI_PORT_STAT_PFC_._TX_PKTS$"}, } (*pathG2S)[path] = []tablePath{tblPath_port} diff --git a/new_sonic_data_client/handler_pfcwd.go b/virtual_database_client/handler_pfcwd.go similarity index 76% rename from new_sonic_data_client/handler_pfcwd.go rename to virtual_database_client/handler_pfcwd.go index ac6623ffb..07d612da9 100644 --- a/new_sonic_data_client/handler_pfcwd.go +++ b/virtual_database_client/handler_pfcwd.go @@ -2,9 +2,10 @@ package client import ( "fmt" - gnmipb "github.com/openconfig/gnmi/proto/gnmi" - log "github.com/golang/glog" "strings" + + log "github.com/golang/glog" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" //proto "github.com/golang/protobuf/proto" ) @@ -28,7 +29,7 @@ func deepcopy(path, copyPath *gnmipb.Path) { // Contains tell whether array contains X func contains(a []string, x string) bool { - for _, n := range(a) { + for _, n := range a { if x == n { return true } @@ -37,8 +38,8 @@ func contains(a []string, x string) bool { } type leafConfig struct { - idx int - name string + idx int + name string } func updatePath(path, tmpl *gnmipb.Path, parentConfig map[int]string, leaf leafConfig, target_fields *[]string) { @@ -72,14 +73,14 @@ func GetTmpl_PortQueuePfcwdStats(path *gnmipb.Path) { name = "Port" path.Elem = append(path.Elem, &gnmipb.PathElem{ - Name: name, - Key: map[string]string{"name": "*"}, + Name: name, + Key: map[string]string{"name": "*"}, }) name = "Queue" path.Elem = append(path.Elem, &gnmipb.PathElem{ - Name: name, - Key: map[string]string{"name": "*"}, + Name: name, + Key: map[string]string{"name": "*"}, }) name = "Pfcwd" @@ -88,23 +89,23 @@ func GetTmpl_PortQueuePfcwdStats(path *gnmipb.Path) { // Translate gNMI path into a list of unique root-to-leaf vpaths // then map each unique vpath to a list of real DB tablePaths -// gNMI paths are like +// gNMI paths are like // [Inerfaces Port[name=] Queue[name=] Pfcwd] -func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error{ +func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { var tmpl = gnmipb.Path{} GetTmpl_PortQueuePfcwdStats(&tmpl) fmt.Printf("tmpl: %v\n", &tmpl) parentConfig := map[int]string{1: "Port", 2: "Queue"} - leaf := leafConfig { - idx: 3, - name: "Pfcwd", + leaf := leafConfig{ + idx: 3, + name: "Pfcwd", } - + target_fields := []string{} updatePath(path, &tmpl, parentConfig, leaf, &target_fields) - + // Populate tablePaths fmt.Printf("path passed in populate: %v\n", &tmpl) err := pop_PortQueuePfcwdStats(&tmpl, pathG2S, target_fields) @@ -114,8 +115,8 @@ func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]table return nil } -// Populate -func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath, target_fields []string) error{ +// Populate +func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath, target_fields []string) error { dbName := "COUNTERS_DB" separator, _ := GetTableKeySeparator(dbName) @@ -158,9 +159,10 @@ func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl oid_port, ok := countersPortNameMap[_name] if !ok { + log.V(1).Infof("RANDY: 2") return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) } - + // Populate queue level var idx_que = 2 queName := elems[idx_que].GetKey()["name"] @@ -191,25 +193,25 @@ func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl } queNum := strings.TrimPrefix(queName, "Queue") pfcque := strings.Join([]string{_name, queNum}, separator) - if _, ok := countersPfcwdNameMap[_name]; ok{ - if oid_que, ok := countersPfcwdNameMap[_name][pfcque]; ok{ + if _, ok := countersPfcwdNameMap[_name]; ok { + if oid_que, ok := countersPfcwdNameMap[_name][pfcque]; ok { // PFC WD is enabled for port:queue out_tblPaths := []tablePath{} // Fields under the queue oid - full_fields := []string { + full_fields := []string{ "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", - "PFC_WD_QUEUE_STATS_TX_DROPPED_PACKETS", - "PFC_WD_QUEUE_STATS_RX_DROPPED_PACKETS", - "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED", - "PFC_wD_QUEUE_STATS_TX_PACKETS", - "PFC_WD_QUEUE_STATS_RX_PACKETS", - "PFC_WD_STATUS", + "PFC_WD_QUEUE_STATS_TX_DROPPED_PACKETS", + "PFC_WD_QUEUE_STATS_RX_DROPPED_PACKETS", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED", + "PFC_wD_QUEUE_STATS_TX_PACKETS", + "PFC_WD_QUEUE_STATS_RX_PACKETS", + "PFC_WD_STATUS", } if len(target_fields) > 0 { // Subscirbe to only particular fields key_target_fields := []string{} - for _, targetField := range(target_fields) { + for _, targetField := range target_fields { if contains(full_fields, targetField) { key_target_fields = append(key_target_fields, targetField) } @@ -218,35 +220,35 @@ func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl } if len(full_fields) > 0 { - tblPath_que := tablePath { - dbName: dbName, - keyName: strings.Join([]string{"COUNTERS", oid_que}, separator), - delimitor: separator, - fields: full_fields, + tblPath_que := tablePath{ + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_que}, separator), + delimitor: separator, + fields: full_fields, } out_tblPaths = append(out_tblPaths, tblPath_que) } - + // Fields under the port oid full_fields = []string{fmt.Sprintf("SAI_PORT_STAT_PFC_%v_RX_PKTS", queNum)} - if len(target_fields) > 0 { - // Subscirbe to only particular fields - key_target_fields := []string{} - for _, targetField := range(target_fields) { - if contains(full_fields, targetField) { - key_target_fields = append(key_target_fields, targetField) - } - } - full_fields = key_target_fields - } + if len(target_fields) > 0 { + // Subscirbe to only particular fields + key_target_fields := []string{} + for _, targetField := range target_fields { + if contains(full_fields, targetField) { + key_target_fields = append(key_target_fields, targetField) + } + } + full_fields = key_target_fields + } if len(full_fields) > 0 { - tblPath_port := tablePath { - dbName: dbName, - keyName: strings.Join([]string{"COUNTERS", oid_port}, separator), - delimitor: separator, - fields: full_fields, + tblPath_port := tablePath{ + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_port}, separator), + delimitor: separator, + fields: full_fields, } out_tblPaths = append(out_tblPaths, tblPath_port) } diff --git a/new_sonic_data_client/handler_port_counter.go b/virtual_database_client/handler_port_counter.go similarity index 61% rename from new_sonic_data_client/handler_port_counter.go rename to virtual_database_client/handler_port_counter.go index 8d9c815ff..0ddedc6de 100644 --- a/new_sonic_data_client/handler_port_counter.go +++ b/virtual_database_client/handler_port_counter.go @@ -18,8 +18,8 @@ func GetTmpl_PortBaseCounterStats(path *gnmipb.Path) { name = "Port" path.Elem = append(path.Elem, &gnmipb.PathElem{ - Name: name, - Key: map[string]string{"name": "*"}, + Name: name, + Key: map[string]string{"name": "*"}, }) name = "BaseCounter" @@ -34,9 +34,9 @@ func v2rPortBaseCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl parentConfig := map[int]string{1: "Port"} - leaf := leafConfig { - idx: 2, - name: "BaseCounter", + leaf := leafConfig{ + idx: 2, + name: "BaseCounter", } target_fields := []string{} @@ -62,37 +62,38 @@ func pop_PortBaseCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tab portName := elems[idx_port].GetKey()["name"] if portName == "*" { // Wildcard port name - for port, _ := range countersPortNameMap { - // Alias translation - var oport string - if alias, ok := name2aliasMap[port]; ok { - oport = alias - } else { - log.V(2).Infof("%v does not have a vendor alias", port) - oport = port - } - // Create a gNMI path for each port - var copyPath = gnmipb.Path{} - deepcopy(path, ©Path) - copyPath.Elem[idx_port].Key["name"] = oport - err := pop_PortBaseCounterStats(©Path, pathG2S, target_fields) + for port, _ := range countersPortNameMap { + // Alias translation + var oport string + if alias, ok := name2aliasMap[port]; ok { + oport = alias + } else { + log.V(2).Infof("%v does not have a vendor alias", port) + oport = port + } + // Create a gNMI path for each port + var copyPath = gnmipb.Path{} + deepcopy(path, ©Path) + copyPath.Elem[idx_port].Key["name"] = oport + err := pop_PortBaseCounterStats(©Path, pathG2S, target_fields) if err != nil { return err } - } - return nil - } - - // Alias translation - var alias, _name string - alias = portName - _name = alias - if val, ok := alias2nameMap[alias]; ok { - _name = val - } + } + return nil + } + + // Alias translation + var alias, _name string + alias = portName + _name = alias + if val, ok := alias2nameMap[alias]; ok { + _name = val + } oid_port, ok := countersPortNameMap[_name] if !ok { + log.V(1).Infof("RANDY: 3") return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) } @@ -100,11 +101,11 @@ func pop_PortBaseCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tab if len(target_fields) > 0 { return fmt.Errorf("Subscribe to field of Path: %v not supported", path) } - tblPath_port := tablePath { - dbName: dbName, - keyName: strings.Join([]string{"COUNTERS", oid_port}, separator), - delimitor: separator, - patterns: []string{"SAI_PORT_STAT_I.*", "SAI_PORT_STAT_ETHER.*"}, + tblPath_port := tablePath{ + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_port}, separator), + delimitor: separator, + patterns: []string{"SAI_PORT_STAT_I.*", "SAI_PORT_STAT_ETHER.*"}, } (*pathG2S)[path] = []tablePath{tblPath_port} diff --git a/new_sonic_data_client/handler_queue_counter.go b/virtual_database_client/handler_queue_counter.go similarity index 88% rename from new_sonic_data_client/handler_queue_counter.go rename to virtual_database_client/handler_queue_counter.go index 12c98be72..ff102c7ae 100644 --- a/new_sonic_data_client/handler_queue_counter.go +++ b/virtual_database_client/handler_queue_counter.go @@ -18,14 +18,14 @@ func GetTmpl_PortQueueCounterStats(path *gnmipb.Path) { name = "Port" path.Elem = append(path.Elem, &gnmipb.PathElem{ - Name: name, - Key: map[string]string{"name": "*"}, + Name: name, + Key: map[string]string{"name": "*"}, }) name = "Queue" path.Elem = append(path.Elem, &gnmipb.PathElem{ - Name: name, - Key: map[string]string{"name": "*"}, + Name: name, + Key: map[string]string{"name": "*"}, }) name = "QueueCounter" @@ -40,9 +40,9 @@ func v2rPortQueueCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tab parentConfig := map[int]string{1: "Port", 2: "Queue"} - leaf := leafConfig { - idx: 3, - name: "QueueCounter", + leaf := leafConfig{ + idx: 3, + name: "QueueCounter", } target_fields := []string{} @@ -99,6 +99,7 @@ func pop_PortQueueCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]ta _, ok := countersQueueNameMap[_name] if !ok { + log.V(1).Infof("RANDY: 4") return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) } @@ -141,16 +142,15 @@ func pop_PortQueueCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]ta } tblPath_que := tablePath{ - dbName: dbName, - keyName: strings.Join([]string{"COUNTERS", oid_que}, separator), - delimitor: separator, - fields: []string{ - "SAI_QUEUE_STAT_PACKETS", - "SAI_QUEUE_STAT_BYTES", - "SAI_QUEUE_STAT_DROPPED_PACKETS", - "SAI_QUEUE_STAT_DROPPED_BYTES"}, + dbName: dbName, + keyName: strings.Join([]string{"COUNTERS", oid_que}, separator), + delimitor: separator, + fields: []string{ + "SAI_QUEUE_STAT_PACKETS", + "SAI_QUEUE_STAT_BYTES", + "SAI_QUEUE_STAT_DROPPED_PACKETS", + "SAI_QUEUE_STAT_DROPPED_BYTES"}, } (*pathG2S)[path] = []tablePath{tblPath_que} return nil } - diff --git a/virtual_database_client/map_init.go b/virtual_database_client/map_init.go new file mode 100644 index 000000000..52d69d327 --- /dev/null +++ b/virtual_database_client/map_init.go @@ -0,0 +1,219 @@ +package client + +import ( + "fmt" + "strings" + + log "github.com/golang/glog" +) + +var ( + // Port name to oid map in COUNTERS table of COUNTERS_DB + countersPortNameMap = make(map[string]string) + + // Queue name to oid map in COUNTERS table of COUNTERS_DB + //countersQueueNameMap = make(map[string]string) + countersQueueNameMap = make(map[string]map[string]string) + + // Alias translation: from vendor port name to sonic interface name + alias2nameMap = make(map[string]string) + // Alias translation: from sonic interface name to vendor port name + name2aliasMap = make(map[string]string) + + // SONiC interface name to their PFC-WD enabled queues, then to oid map + countersPfcwdNameMap = make(map[string]map[string]string) +) + +func initCountersQueueNameMap() error { + dbName := "COUNTERS_DB" + separator, _ := GetTableKeySeparator(dbName) + + if len(countersQueueNameMap) == 0 { + queueMap, err := getCountersMap("COUNTERS_QUEUE_NAME_MAP") + if err != nil { + return err + } + for k, v := range queueMap { + stringSlice := strings.Split(k, separator) + port := stringSlice[0] + if _, ok := countersQueueNameMap[port]; !ok { + countersQueueNameMap[port] = make(map[string]string) + } + countersQueueNameMap[port][k] = v + } + } + return nil +} + +func initCountersPortNameMap() error { + var err error + if len(countersPortNameMap) == 0 { + countersPortNameMap, err = getCountersMap("COUNTERS_PORT_NAME_MAP") + if err != nil { + return err + } + } + return nil +} + +func initAliasMap() error { + var err error + if len(alias2nameMap) == 0 { + alias2nameMap, name2aliasMap, err = getAliasMap() + if err != nil { + return err + } + } + return nil +} + +func initCountersPfcwdNameMap() error { + var err error + if len(countersPfcwdNameMap) == 0 { + countersPfcwdNameMap, err = getPfcwdMap() + 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) + + dbName := "CONFIG_DB" + separator, _ := GetTableKeySeparator(dbName) + redisDb, _ := Target2RedisDb[dbName] + _, err := redisDb.Ping().Result() + if err != nil { + log.V(1).Infof("Can not connect to %v, err: %v", dbName, err) + return nil, err + } + + keyName := fmt.Sprintf("PFC_WD_TABLE%v*", separator) + resp, err := redisDb.Keys(keyName).Result() + if err != nil { + log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) + return nil, err + } + + if len(resp) == 0 { + // PFC WD service not enabled on device + log.V(1).Infof("PFC WD not enabled on device") + return nil, nil + } + + for _, key := range resp { + name := key[13:] + pfcwdName_map[name] = make(map[string]string) + } + + // Get Queue indexes that are enabled with PFC-WD + keyName = "PORT_QOS_MAP*" + resp, err = redisDb.Keys(keyName).Result() + if err != nil { + log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) + return nil, err + } + if len(resp) == 0 { + log.V(1).Infof("PFC WD not enabled on device") + return nil, nil + } + qos_key := resp[0] + + fieldName := "pfc_enable" + priorities, err := redisDb.HGet(qos_key, fieldName).Result() + if err != nil { + log.V(1).Infof("redis get field failed for %v, key = %v, field = %v, err: %v", dbName, qos_key, fieldName, err) + return nil, err + } + + keyName = fmt.Sprintf("MAP_PFC_PRIORITY_TO_QUEUE%vAZURE", separator) + pfc_queue_map, err := redisDb.HGetAll(keyName).Result() + if err != nil { + log.V(1).Infof("redis get fields failed for %v, key = %v, err: %v", dbName, keyName, err) + return nil, err + } + + var indices []string + for _, p := range strings.Split(priorities, ",") { + _, ok := pfc_queue_map[p] + if !ok { + log.V(1).Infof("Missing mapping between PFC priority %v to queue", p) + } else { + indices = append(indices, pfc_queue_map[p]) + } + } + + if len(countersQueueNameMap) == 0 { + log.V(1).Infof("COUNTERS_QUEUE_NAME_MAP is empty") + return nil, nil + } + + var queue_key string + queue_separator, _ := GetTableKeySeparator("COUNTERS_DB") + for port, _ := range pfcwdName_map { + for _, indice := range indices { + queue_key = port + queue_separator + indice + oid, ok := countersQueueNameMap[port][queue_key] + if !ok { + return nil, fmt.Errorf("key %v not exists in COUNTERS_QUEUE_NAME_MAP", queue_key) + } + pfcwdName_map[port][queue_key] = oid + } + } + + log.V(6).Infof("countersPfcwdNameMap: %v", pfcwdName_map) + return pfcwdName_map, nil +} + +// Get the mapping between sonic interface name and vendor alias +func getAliasMap() (map[string]string, map[string]string, error) { + var alias2name_map = make(map[string]string) + var name2alias_map = make(map[string]string) + + dbName := "CONFIG_DB" + separator, _ := GetTableKeySeparator(dbName) + redisDb, _ := Target2RedisDb[dbName] + _, err := redisDb.Ping().Result() + if err != nil { + log.V(1).Infof("Can not connect to %v, err: %v", dbName, err) + return nil, nil, err + } + + keyName := fmt.Sprintf("PORT%v*", separator) + resp, err := redisDb.Keys(keyName).Result() + if err != nil { + log.V(1).Infof("redis get keys failed for %v, key = %v, err: %v", dbName, keyName, err) + return nil, nil, err + } + for _, key := range resp { + alias, err := redisDb.HGet(key, "alias").Result() + if err != nil { + log.V(1).Infof("redis get field alias failed for %v, key = %v, err: %v", dbName, key, err) + // clear aliasMap + alias2name_map = make(map[string]string) + name2alias_map = make(map[string]string) + return nil, nil, err + } + alias2name_map[alias] = key[5:] + name2alias_map[key[5:]] = alias + } + log.V(6).Infof("alias2nameMap: %v", alias2name_map) + log.V(6).Infof("name2aliasMap: %v", name2alias_map) + return alias2name_map, name2alias_map, nil +} + +// Get the mapping between objects in counters DB, Ex. port name to oid in "COUNTERS_PORT_NAME_MAP" table. +// Aussuming static port name to oid map in COUNTERS table +func getCountersMap(tableName string) (map[string]string, error) { + redisDb, _ := Target2RedisDb["COUNTERS_DB"] + fv, err := redisDb.HGetAll(tableName).Result() + if err != nil { + log.V(2).Infof("redis HGetAll failed for COUNTERS_DB, tableName: %s", tableName) + return nil, err + } + log.V(6).Infof("tableName: %s, map %v", tableName, fv) + return fv, nil +} diff --git a/new_sonic_data_client/path.go b/virtual_database_client/path.go similarity index 100% rename from new_sonic_data_client/path.go rename to virtual_database_client/path.go diff --git a/new_sonic_data_client/trie.go b/virtual_database_client/trie.go similarity index 100% rename from new_sonic_data_client/trie.go rename to virtual_database_client/trie.go From 0fcf9a5ba97bed29c272811a2b5d23dbbe658861 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Tue, 26 Mar 2019 19:04:30 +0000 Subject: [PATCH 06/20] remove testing directory imports --- dialout/dialout_client/dialout_client.go | 8 ++++++-- dialout/dialout_client/dialout_client_test.go | 8 +++++--- dialout/dialout_server_cli/dialout_server_cli.go | 3 +-- gnmi_server/client_subscribe.go | 6 ++---- gnmi_server/server.go | 4 ++-- telemetry/telemetry.go | 3 +-- virtual_database_client/db_client_test.go | 5 +++-- 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/dialout/dialout_client/dialout_client.go b/dialout/dialout_client/dialout_client.go index ae19c1861..22f8535a6 100644 --- a/dialout/dialout_client/dialout_client.go +++ b/dialout/dialout_client/dialout_client.go @@ -5,8 +5,13 @@ import ( "crypto/tls" "errors" "fmt" + spb "github.com/Azure/sonic-telemetry/proto" + //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + "net" + + sdc "github.com/Azure/sonic-telemetry/sonic_data_client" "github.com/go-redis/redis" log "github.com/golang/glog" gpb "github.com/openconfig/gnmi/proto/gnmi" @@ -15,8 +20,7 @@ import ( "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/credentials" - "net" - sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" + //"reflect" "strconv" "strings" diff --git a/dialout/dialout_client/dialout_client_test.go b/dialout/dialout_client/dialout_client_test.go index 644d2e260..01288e19d 100644 --- a/dialout/dialout_client/dialout_client_test.go +++ b/dialout/dialout_client/dialout_client_test.go @@ -6,7 +6,9 @@ package telemetry_dialout import ( "crypto/tls" "encoding/json" + "github.com/go-redis/redis" + //"github.com/golang/protobuf/proto" testcert "github.com/Azure/sonic-telemetry/testdata/tls" @@ -16,6 +18,7 @@ import ( "github.com/openconfig/gnmi/value" "golang.org/x/net/context" "google.golang.org/grpc" + //"google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" //"google.golang.org/grpc/status" @@ -29,11 +32,10 @@ import ( "time" //sds "github.com/Azure/sonic-telemetry/dialout/dialout_server" + sds "github.com/Azure/sonic-telemetry/dialout/dialout_server" spb "github.com/Azure/sonic-telemetry/proto" - sds "test/sonic-telemetry-new-pfcwd/dialout/dialout_server" - //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + sdc "github.com/Azure/sonic-telemetry/sonic_data_client" gclient "github.com/openconfig/gnmi/client/gnmi" - sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" ) var clientTypes = []string{gclient.Type} diff --git a/dialout/dialout_server_cli/dialout_server_cli.go b/dialout/dialout_server_cli/dialout_server_cli.go index f2106e249..02b9cee06 100644 --- a/dialout/dialout_server_cli/dialout_server_cli.go +++ b/dialout/dialout_server_cli/dialout_server_cli.go @@ -10,9 +10,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" - //ds "github.com/Azure/sonic-telemetry/dialout/dialout_server" + ds "github.com/Azure/sonic-telemetry/dialout/dialout_server" testcert "github.com/Azure/sonic-telemetry/testdata/tls" - ds "test/sonic-telemetry-new-pfcwd/dialout/dialout_server" ) var ( diff --git a/gnmi_server/client_subscribe.go b/gnmi_server/client_subscribe.go index afa07402d..87ba30cea 100644 --- a/gnmi_server/client_subscribe.go +++ b/gnmi_server/client_subscribe.go @@ -11,10 +11,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" - //spb "github.com/Azure/sonic-telemetry/proto" - //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" - sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" - vdc "test/sonic-telemetry-new-pfcwd/virtual_database_client" + sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + vdc "github.com/Azure/sonic-telemetry/virtual_database_client" gnmipb "github.com/openconfig/gnmi/proto/gnmi" ) diff --git a/gnmi_server/server.go b/gnmi_server/server.go index ddfb94fd4..82577eb67 100644 --- a/gnmi_server/server.go +++ b/gnmi_server/server.go @@ -15,8 +15,8 @@ import ( "google.golang.org/grpc/reflection" "google.golang.org/grpc/status" - sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" - vdc "test/sonic-telemetry-new-pfcwd/virtual_database_client" + sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + vdc "github.com/Azure/sonic-telemetry/virtual_database_client" gnmipb "github.com/openconfig/gnmi/proto/gnmi" ) diff --git a/telemetry/telemetry.go b/telemetry/telemetry.go index 624475f73..01394b3fa 100644 --- a/telemetry/telemetry.go +++ b/telemetry/telemetry.go @@ -10,8 +10,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" - //gnmi "github.com/Azure/sonic-telemetry/gnmi_server" - gnmi "test/sonic-telemetry-new-pfcwd/gnmi_server" + gnmi "github.com/Azure/sonic-telemetry/gnmi_server" testcert "github.com/Azure/sonic-telemetry/testdata/tls" ) diff --git a/virtual_database_client/db_client_test.go b/virtual_database_client/db_client_test.go index 6aeb7eb8a..fe7814254 100644 --- a/virtual_database_client/db_client_test.go +++ b/virtual_database_client/db_client_test.go @@ -10,11 +10,12 @@ import ( "os" "os/exec" "reflect" - sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" "testing" "time" - gnmi "test/sonic-telemetry-new-pfcwd/gnmi_server" + sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + + gnmi "github.com/Azure/sonic-telemetry/gnmi_server" xpath "github.com/jipanyang/gnxi/utils/xpath" gnmipb "github.com/openconfig/gnmi/proto/gnmi" From f0e0fdb246a92f5ea5301ea4fd15e8f91e4afbef Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Wed, 10 Apr 2019 21:07:38 +0000 Subject: [PATCH 07/20] silence unnecessary printfs --- virtual_database_client/handler_pfcwd.go | 10 +- virtual_database_client/path.go | 115 ++++++++++++----------- 2 files changed, 63 insertions(+), 62 deletions(-) diff --git a/virtual_database_client/handler_pfcwd.go b/virtual_database_client/handler_pfcwd.go index 07d612da9..f57db7a6a 100644 --- a/virtual_database_client/handler_pfcwd.go +++ b/virtual_database_client/handler_pfcwd.go @@ -94,7 +94,7 @@ func GetTmpl_PortQueuePfcwdStats(path *gnmipb.Path) { func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { var tmpl = gnmipb.Path{} GetTmpl_PortQueuePfcwdStats(&tmpl) - fmt.Printf("tmpl: %v\n", &tmpl) + //fmt.Printf("tmpl: %v\n", &tmpl) parentConfig := map[int]string{1: "Port", 2: "Queue"} @@ -103,12 +103,12 @@ func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]table name: "Pfcwd", } - target_fields := []string{} - updatePath(path, &tmpl, parentConfig, leaf, &target_fields) + targetFields := []string{} + updatePath(path, &tmpl, parentConfig, leaf, &targetFields) // Populate tablePaths - fmt.Printf("path passed in populate: %v\n", &tmpl) - err := pop_PortQueuePfcwdStats(&tmpl, pathG2S, target_fields) + //fmt.Printf("path passed in populate: %v\n", &tmpl) + err := pop_PortQueuePfcwdStats(&tmpl, pathG2S, targetFields) if err != nil { return err } diff --git a/virtual_database_client/path.go b/virtual_database_client/path.go index 322bcb086..8be89e56c 100644 --- a/virtual_database_client/path.go +++ b/virtual_database_client/path.go @@ -3,29 +3,30 @@ package client import ( "fmt" "strconv" + //"strings" - "time" + "encoding/json" "net" "regexp" - "encoding/json" + "time" - log "github.com/golang/glog" spb "github.com/Azure/sonic-telemetry/proto" "github.com/go-redis/redis" + log "github.com/golang/glog" gnmipb "github.com/openconfig/gnmi/proto/gnmi" ) // gnmiFullPath builds the full path from the prefix and path. func gnmiFullPath(prefix, path *gnmipb.Path) *gnmipb.Path { - fullPath := &gnmipb.Path{Origin: path.Origin} - if path.GetElement() != nil { - fullPath.Element = append(prefix.GetElement(), path.GetElement()...) - } - if path.GetElem() != nil { - fullPath.Elem = append(prefix.GetElem(), path.GetElem()...) - } - return fullPath + fullPath := &gnmipb.Path{Origin: path.Origin} + if path.GetElement() != nil { + fullPath.Element = append(prefix.GetElement(), path.GetElement()...) + } + if path.GetElem() != nil { + fullPath.Elem = append(prefix.GetElem(), path.GetElem()...) + } + return fullPath } func populateAlltablePaths(prefix *gnmipb.Path, paths []*gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { @@ -42,16 +43,16 @@ func populateAlltablePaths(prefix *gnmipb.Path, paths []*gnmipb.Path, pathG2S *m // root-to-leaf virtual paths in the vpath tree. // Then map each vpath to a list of redis DB path. func populateNewtablePath(prefix, path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { - fullPath := path - if prefix != nil { - fullPath = gnmiFullPath(prefix, path) - } - fmt.Printf("fullPath: %v\n", fullPath) + //fullPath := path + //if prefix != nil { + // fullPath = gnmiFullPath(prefix, path) + //} + //fmt.Printf("fullPath: %v\n", fullPath) target := prefix.GetTarget() stringSlice := []string{target} elems := path.GetElem() - for _, elem := range elems{ + for _, elem := range elems { stringSlice = append(stringSlice, elem.GetName()) } @@ -61,36 +62,36 @@ func populateNewtablePath(prefix, path *gnmipb.Path, pathG2S *map[*gnmipb.Path][ } // Debug - for k, v := range (*pathG2S) { - fmt.Printf("gNMI path: %v\n", k) - for _, tblPath := range v{ - fmt.Printf("new tablePath: %v\n", tblPath) - } - } + //for k, v := range (*pathG2S) { + // fmt.Printf("gNMI path: %v\n", k) + // for _, tblPath := range v{ + // fmt.Printf("new tablePath: %v\n", tblPath) + // } + //} return nil } func msi2TypedValue(msi map[string]interface{}) (*gnmipb.TypedValue, error) { - jv, err := emitJSON(&msi) - if err != nil { - log.V(2).Infof("emitJSON err %s for %v", err, msi) - return nil, fmt.Errorf("emitJSON err %s for %v", err, msi) - } - return &gnmipb.TypedValue{ - Value: &gnmipb.TypedValue_JsonIetfVal{ - JsonIetfVal: jv, - }}, nil + jv, err := emitJSON(&msi) + if err != nil { + log.V(2).Infof("emitJSON err %s for %v", err, msi) + return nil, fmt.Errorf("emitJSON err %s for %v", err, msi) + } + return &gnmipb.TypedValue{ + Value: &gnmipb.TypedValue_JsonIetfVal{ + JsonIetfVal: jv, + }}, nil } // emitJSON marshalls map[string]interface{} to JSON byte stream. func emitJSON(v *map[string]interface{}) ([]byte, error) { - //j, err := json.MarshalIndent(*v, "", indentString) - j, err := json.Marshal(*v) - if err != nil { - return nil, fmt.Errorf("JSON marshalling error: %v", err) - } + //j, err := json.MarshalIndent(*v, "", indentString) + j, err := json.Marshal(*v) + if err != nil { + return nil, fmt.Errorf("JSON marshalling error: %v", err) + } - return j, nil + return j, nil } // Render the redis DB data to map[string]interface{} @@ -135,7 +136,7 @@ func tableData2Msi(tblPath *tablePath, msi *map[string]interface{}) error { for _, field := range fields { if value, ok := val[field]; !ok { log.V(1).Infof("Missing field: %v", field) - } else{ + } else { (*msi)[field] = value } } @@ -145,15 +146,15 @@ func tableData2Msi(tblPath *tablePath, msi *map[string]interface{}) error { func enqueFatalMsg(c *DbClient, msg string) { c.q.Put(Value{ &spb.Value{ - Timestamp: time.Now().UnixNano(), - Fatal: msg, + Timestamp: time.Now().UnixNano(), + Fatal: msg, }, }) } type redisSubData struct { - tblPath tablePath - pubsub *redis.PubSub + tblPath tablePath + pubsub *redis.PubSub } func dbSingleTableKeySubscribe(rsd redisSubData, c *DbClient, msiInit *map[string]interface{}, msiOut *map[string]interface{}) { @@ -161,7 +162,7 @@ func dbSingleTableKeySubscribe(rsd redisSubData, c *DbClient, msiInit *map[strin pubsub := rsd.pubsub msi := make(map[string]interface{}) // Initialize msi - for k, v := range (*msiInit) { + for k, v := range *msiInit { msi[k] = v } @@ -231,10 +232,10 @@ func dbPathSubscribe(gnmiPath *gnmipb.Path, tblPaths []tablePath, c *DbClient) { var spbv *spb.Value spbv = &spb.Value{ - Prefix: c.prefix, - Path: gnmiPath, - Timestamp: time.Now().UnixNano(), - Val: val, + Prefix: c.prefix, + Path: gnmiPath, + Timestamp: time.Now().UnixNano(), + Val: val, } if err = c.q.Put(Value{spbv}); err != nil { log.V(1).Infof("Queue error: %v", err) @@ -263,7 +264,7 @@ func dbPathSubscribe(gnmiPath *gnmipb.Path, tblPaths []tablePath, c *DbClient) { pattern += keyName pubsub := redisDb.PSubscribe(pattern) defer pubsub.Close() - + msgi, err := pubsub.ReceiveTimeout(time.Second) if err != nil { log.V(1).Infof("psubscribe to %s failed for %v", pattern, tblPath) @@ -278,17 +279,17 @@ func dbPathSubscribe(gnmiPath *gnmipb.Path, tblPaths []tablePath, c *DbClient) { return } log.V(2).Infof("Psubscribe succeeded for %v: %v", tblPath, subscr) - - rsd := redisSubData { - tblPath: tblPath, - pubsub: pubsub, + + rsd := redisSubData{ + tblPath: tblPath, + pubsub: pubsub, } go dbSingleTableKeySubscribe(rsd, c, &msiInit, &msi) } for { select { - default : + default: val = nil err = nil c.mu.Lock() @@ -307,9 +308,9 @@ func dbPathSubscribe(gnmiPath *gnmipb.Path, tblPaths []tablePath, c *DbClient) { if val != nil { spbv = &spb.Value{ - Path: gnmiPath, - Timestamp: time.Now().UnixNano(), - Val: val, + Path: gnmiPath, + Timestamp: time.Now().UnixNano(), + Val: val, } log.V(5).Infof("dbTableKeySubscribe enque: %v", spbv) From bd4af90ea1ce73f6c80f5065064289693852956a Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Wed, 10 Apr 2019 21:28:04 +0000 Subject: [PATCH 08/20] remove more debug printf's --- gnmi_server/client_subscribe.go | 2 +- gnmi_server/server.go | 4 +- gnmi_server/server_test.go | 3 +- sonic_data_client/db_client.go | 80 ++++++++++++++++----------------- 4 files changed, 44 insertions(+), 45 deletions(-) diff --git a/gnmi_server/client_subscribe.go b/gnmi_server/client_subscribe.go index afa07402d..06c96f10e 100644 --- a/gnmi_server/client_subscribe.go +++ b/gnmi_server/client_subscribe.go @@ -104,7 +104,7 @@ func (c *Client) Run(stream gnmipb.GNMI_SubscribeServer) (err error) { } var target string - fmt.Printf("Subscribe Prefix: %v\n", target) + //fmt.Printf("Subscribe Prefix: %v\n", target) prefix := c.subscribe.GetPrefix() if prefix == nil { return grpc.Errorf(codes.Unimplemented, "No target specified in prefix") diff --git a/gnmi_server/server.go b/gnmi_server/server.go index ddfb94fd4..82577eb67 100644 --- a/gnmi_server/server.go +++ b/gnmi_server/server.go @@ -15,8 +15,8 @@ import ( "google.golang.org/grpc/reflection" "google.golang.org/grpc/status" - sdc "test/sonic-telemetry-new-pfcwd/sonic_data_client" - vdc "test/sonic-telemetry-new-pfcwd/virtual_database_client" + sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + vdc "github.com/Azure/sonic-telemetry/virtual_database_client" gnmipb "github.com/openconfig/gnmi/proto/gnmi" ) diff --git a/gnmi_server/server_test.go b/gnmi_server/server_test.go index 253600b58..f90602e8c 100644 --- a/gnmi_server/server_test.go +++ b/gnmi_server/server_test.go @@ -30,8 +30,7 @@ import ( // Register supported client types. spb "github.com/Azure/sonic-telemetry/proto" - //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" - sdc "test/sonic-telemetry-pfcwd/sonic_data_client" + sdc "github.com/Azure/sonic-telemetry/sonic_data_client" gclient "github.com/jipanyang/gnmi/client/gnmi" ) diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index 0075b5af6..10a0a4eef 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -23,8 +23,8 @@ import ( const ( // indentString represents the default indentation string used for // JSON. Two spaces are used here. - indentString string = " " - Default_REDIS_UNIXSOCKET string = "/var/run/redis/redis.sock" + indentString string = " " + Default_REDIS_UNIXSOCKET string = "/var/run/redis/redis.sock" Default_REDIS_LOCAL_TCP_PORT string = "localhost:6379" ) @@ -60,11 +60,11 @@ var UseRedisLocalTcpPort bool = false var Target2RedisDb = make(map[string]*redis.Client) type tablePath struct { - dbName string + dbName string tableName string tableKey string delimitor string - field string + field string // path name to be used in json data which may be different // from the real data path. Ex. in Counters table, real tableKey // is oid:0x####, while key name like Ethernet## may be put @@ -72,7 +72,7 @@ type tablePath struct { jsonTableName string jsonTableKey string jsonDelimitor string - jsonField string + jsonField string } type Value struct { @@ -91,19 +91,19 @@ func (val Value) Compare(other queue.Item) int { } type DbClient struct { - prefix *gnmipb.Path + prefix *gnmipb.Path pathG2S map[*gnmipb.Path][]tablePath - q *queue.PriorityQueue + q *queue.PriorityQueue channel chan struct{} synced sync.WaitGroup // Control when to send gNMI sync_response - w *sync.WaitGroup // wait for all sub go routines to finish - mu sync.RWMutex // Mutex for data protection among routines for DbClient + w *sync.WaitGroup // wait for all sub go routines to finish + mu sync.RWMutex // Mutex for data protection among routines for DbClient sendMsg int64 recvMsg int64 - errors int64 + errors int64 } func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { @@ -115,11 +115,11 @@ func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { } // TODO: Remove debug log - for _, _path := range paths { - fmt.Printf("single path: %v\n", _path) - } - - fmt.Printf("prefix: %v\n", prefix) + //for _, _path := range paths { + // fmt.Printf("single path: %v\n", _path) + //} + // + //fmt.Printf("prefix: %v\n", prefix) if prefix.GetTarget() == "COUNTERS_DB" { err = initCountersPortNameMap() @@ -187,7 +187,7 @@ func (c *DbClient) StreamRun(q *queue.PriorityQueue, stop chan struct{}, w *sync // Inject sync message c.q.Put(Value{ &spb.Value{ - Timestamp: time.Now().UnixNano(), + Timestamp: time.Now().UnixNano(), SyncResponse: true, }, }) @@ -223,11 +223,11 @@ func (c *DbClient) PollRun(q *queue.PriorityQueue, poll chan struct{}, w *sync.W } spbv := &spb.Value{ - Prefix: c.prefix, - Path: gnmiPath, - Timestamp: time.Now().UnixNano(), + Prefix: c.prefix, + Path: gnmiPath, + Timestamp: time.Now().UnixNano(), SyncResponse: false, - Val: val, + Val: val, } c.q.Put(Value{spbv}) @@ -236,7 +236,7 @@ func (c *DbClient) PollRun(q *queue.PriorityQueue, poll chan struct{}, w *sync.W c.q.Put(Value{ &spb.Value{ - Timestamp: time.Now().UnixNano(), + Timestamp: time.Now().UnixNano(), SyncResponse: true, }, }) @@ -259,9 +259,9 @@ func (c *DbClient) Get(w *sync.WaitGroup) ([]*spb.Value, error) { values = append(values, &spb.Value{ Prefix: c.prefix, - Path: gnmiPath, + Path: gnmiPath, Timestamp: ts.UnixNano(), - Val: val, + Val: val, }) } log.V(6).Infof("Getting #%v", values) @@ -334,10 +334,10 @@ func useRedisTcpClient() { var redisDb *redis.Client if UseRedisLocalTcpPort { redisDb = redis.NewClient(&redis.Options{ - Network: "tcp", - Addr: Default_REDIS_LOCAL_TCP_PORT, - Password: "", // no password set - DB: int(dbn), + Network: "tcp", + Addr: Default_REDIS_LOCAL_TCP_PORT, + Password: "", // no password set + DB: int(dbn), DialTimeout: 0, }) } @@ -354,10 +354,10 @@ func init() { var redisDb *redis.Client redisDb = redis.NewClient(&redis.Options{ - Network: "unix", - Addr: Default_REDIS_UNIXSOCKET, - Password: "", // no password set - DB: int(dbn), + Network: "unix", + Addr: Default_REDIS_UNIXSOCKET, + Password: "", // no password set + DB: int(dbn), DialTimeout: 0, }) Target2RedisDb[dbName] = redisDb @@ -683,7 +683,7 @@ func enqueFatalMsg(c *DbClient, msg string) { c.q.Put(Value{ &spb.Value{ Timestamp: time.Now().UnixNano(), - Fatal: msg, + Fatal: msg, }, }) } @@ -751,9 +751,9 @@ func dbFieldMultiSubscribe(gnmiPath *gnmipb.Path, c *DbClient) { spbv := &spb.Value{ Prefix: c.prefix, - Path: gnmiPath, + Path: gnmiPath, Timestamp: time.Now().UnixNano(), - Val: val, + Val: val, } if err = c.q.Put(Value{spbv}); err != nil { @@ -810,7 +810,7 @@ func dbFieldSubscribe(gnmiPath *gnmipb.Path, c *DbClient) { if newVal != val { spbv := &spb.Value{ Prefix: c.prefix, - Path: gnmiPath, + Path: gnmiPath, Timestamp: time.Now().UnixNano(), Val: &gnmipb.TypedValue{ Value: &gnmipb.TypedValue_StringVal{ @@ -837,7 +837,7 @@ func dbFieldSubscribe(gnmiPath *gnmipb.Path, c *DbClient) { type redisSubData struct { tblPath tablePath - pubsub *redis.PubSub + pubsub *redis.PubSub prefixLen int } @@ -985,9 +985,9 @@ func dbTableKeySubscribe(gnmiPath *gnmipb.Path, c *DbClient) { var spbv *spb.Value spbv = &spb.Value{ Prefix: c.prefix, - Path: gnmiPath, + Path: gnmiPath, Timestamp: time.Now().UnixNano(), - Val: val, + Val: val, } if err = c.q.Put(Value{spbv}); err != nil { log.V(1).Infof("Queue error: %v", err) @@ -1017,9 +1017,9 @@ func dbTableKeySubscribe(gnmiPath *gnmipb.Path, c *DbClient) { } if val != nil { spbv = &spb.Value{ - Path: gnmiPath, + Path: gnmiPath, Timestamp: time.Now().UnixNano(), - Val: val, + Val: val, } log.V(5).Infof("dbTableKeySubscribe enque: %v", spbv) From da43c690952f68d7cbc97eaba82acb9f632f1e90 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Thu, 25 Apr 2019 19:59:12 +0000 Subject: [PATCH 09/20] Attempt to fixup import paths and remove old unnecessary debug formatting --- virtual_database_client/db_client_test.go | 2 ++ virtual_database_client/handler_pfc_counter.go | 1 - virtual_database_client/handler_pfcwd.go | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/virtual_database_client/db_client_test.go b/virtual_database_client/db_client_test.go index 6aeb7eb8a..d80fa5725 100644 --- a/virtual_database_client/db_client_test.go +++ b/virtual_database_client/db_client_test.go @@ -6,6 +6,7 @@ import ( "context" tls "crypto/tls" "encoding/json" + "fmt" "io/ioutil" "os" "os/exec" @@ -181,6 +182,7 @@ func assertExpectedValue(t *testing.T, response *gnmipb.GetResponse, expectedRes } } + fmt.Printf("got: %v (%T),\nwant %v (%T)\n", gotVal, gotVal, expectedResponseValue, expectedResponseValue) if !reflect.DeepEqual(gotVal, expectedResponseValue) { t.Errorf("got: %v (%T),\nwant %v (%T)", gotVal, gotVal, expectedResponseValue, expectedResponseValue) } diff --git a/virtual_database_client/handler_pfc_counter.go b/virtual_database_client/handler_pfc_counter.go index 2b33192c4..3f3aeb6be 100644 --- a/virtual_database_client/handler_pfc_counter.go +++ b/virtual_database_client/handler_pfc_counter.go @@ -93,7 +93,6 @@ func pop_PortPfcCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl oid_port, ok := countersPortNameMap[_name] if !ok { - log.V(1).Infof("RANDY: 1") return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) } diff --git a/virtual_database_client/handler_pfcwd.go b/virtual_database_client/handler_pfcwd.go index f57db7a6a..cf5346999 100644 --- a/virtual_database_client/handler_pfcwd.go +++ b/virtual_database_client/handler_pfcwd.go @@ -159,7 +159,6 @@ func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl oid_port, ok := countersPortNameMap[_name] if !ok { - log.V(1).Infof("RANDY: 2") return fmt.Errorf("%v not a valid sonic interface. Vendor alias is %v", _name, alias) } From d16da4cfd70b4e6fe990a5b153c0fe50d3b68f50 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Sun, 5 May 2019 20:33:41 +0000 Subject: [PATCH 10/20] get tests in a good state --- virtual_database_client/db_client_test.go | 223 +++++++++++++++++++++- 1 file changed, 220 insertions(+), 3 deletions(-) diff --git a/virtual_database_client/db_client_test.go b/virtual_database_client/db_client_test.go index 6ea42dd47..52d9d5e26 100644 --- a/virtual_database_client/db_client_test.go +++ b/virtual_database_client/db_client_test.go @@ -153,6 +153,177 @@ func sendGetRequest(t *testing.T, ctx context.Context, gnmiClient gnmipb.GNMICli return response } +var expectedValueEthernet68 = map[string]interface{}{ + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", + "PFC_WD_STATUS": "operational", + "SAI_PORT_STAT_PFC_4_RX_PKTS": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "SAI_PORT_STAT_ETHER_STATS_RX_NO_ERRORS": "0", + "SAI_PORT_STAT_IF_OUT_OCTETS": "0", + "SAI_PORT_STAT_IPV6_IN_RECEIVES": "0", + "SAI_PORT_STAT_IPV6_OUT_MCAST_PKTS": "0", + "SAI_PORT_STAT_IP_IN_UCAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_OVERSIZE_PKTS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_128_TO_255_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_256_TO_511_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_9217_TO_16383_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_UNDERSIZE_PKTS": "0", + "SAI_PORT_STAT_IF_IN_MULTICAST_PKTS": "0", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_1024_TO_1518_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_64_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_2048_TO_4095_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_65_TO_127_OCTETS": "0", + "SAI_PORT_STAT_ETHER_RX_OVERSIZE_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_JABBERS": "0", + "SAI_PORT_STAT_IPV6_OUT_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IP_IN_DISCARDS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_2048_TO_4095_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_VLAN_DISCARDS": "0", + "SAI_PORT_STAT_IP_OUT_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_256_TO_511_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS": "0", + "SAI_PORT_STAT_IF_OUT_ERRORS": "0", + "SAI_PORT_STAT_IP_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_BROADCAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_128_TO_255_OCTETS": "0", + "SAI_PORT_STAT_IPV6_OUT_DISCARDS": "0", + "SAI_PORT_STAT_IPV6_OUT_UCAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_1519_TO_2047_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_9217_TO_16383_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_MULTICAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_1519_TO_2047_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_512_TO_1023_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_64_OCTETS": "0", + "SAI_PORT_STAT_IF_OUT_MULTICAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_65_TO_127_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_65_TO_127_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_9217_TO_16383_OCTETS": "0", + "SAI_PORT_STAT_ETHER_TX_OVERSIZE_PKTS": "0", + "SAI_PORT_STAT_IF_OUT_DISCARDS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_4096_TO_9216_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_1024_TO_1518_OCTETS": "0", + "SAI_PORT_STAT_IPV6_IN_DISCARDS": "0", + "SAI_PORT_STAT_IPV6_OUT_OCTETS": "0", + "SAI_PORT_STAT_IP_IN_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_4096_TO_9216_OCTETS": "0", + "SAI_PORT_STAT_IPV6_IN_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_COLLISIONS": "0", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IP_OUT_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IP_OUT_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_512_TO_1023_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_1024_TO_1518_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_128_TO_255_OCTETS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_512_TO_1023_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_CRC_ALIGN_ERRORS": "0", + "SAI_PORT_STAT_ETHER_STATS_DROP_EVENTS": "0", + "SAI_PORT_STAT_ETHER_STATS_PKTS_2048_TO_4095_OCTETS": "0", + "SAI_PORT_STAT_ETHER_IN_PKTS_256_TO_511_OCTETS": "0", + "SAI_PORT_STAT_IPV6_IN_MCAST_PKTS": "0", + "SAI_PORT_STAT_IP_IN_RECEIVES": "0", + "SAI_PORT_STAT_IF_IN_BROADCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_DISCARDS": "0", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_4096_TO_9216_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_FRAGMENTS": "0", + "SAI_PORT_STAT_ETHER_STATS_TX_NO_ERRORS": "0", + "SAI_PORT_STAT_IF_OUT_BROADCAST_PKTS": "0", + "SAI_PORT_STAT_IPV6_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IP_OUT_DISCARDS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_1519_TO_2047_OCTETS": "0", + "SAI_PORT_STAT_ETHER_STATS_OCTETS": "0", + "SAI_PORT_STAT_IF_IN_UNKNOWN_PROTOS": "0", + "SAI_PORT_STAT_IF_OUT_QLEN": "0", + "SAI_PORT_STAT_IPV6_IN_UCAST_PKTS": "0", + "SAI_PORT_STAT_ETHER_OUT_PKTS_64_OCTETS": "0", + "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", + "SAI_QUEUE_STAT_PACKETS": "0", + "SAI_QUEUE_STAT_BYTES": "0", + "SAI_QUEUE_STAT_DROPPED_BYTES": "0", + "SAI_PORT_STAT_PFC_3_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_7_RX_PKTS": "2", + "SAI_PORT_STAT_PFC_4_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_6_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_5_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_7_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_1_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_2_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_5_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_6_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_0_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_2_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_3_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_0_TX_PKTS": "0", + "SAI_PORT_STAT_PFC_1_RX_PKTS": "0", +} + +var expectedValueEthernet68Pfcwd = map[string]interface{}{ + "PFC_WD_STATUS": "operational", + "SAI_PORT_STAT_PFC_3_RX_PKTS": "0", + "SAI_PORT_STAT_PFC_4_RX_PKTS": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED": "0", + "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED": "0", +} + +func dumpMapFromResponse(response *gnmipb.GetResponse, name string) { + fmt.Printf("\n\n>>>>>\n\n") + notifs := response.GetNotification() + var gotVal interface{} + var gotMap = make(map[string]interface{}) + + count := len(notifs) + for i := 0; i < count; i++ { + val := notifs[i].GetUpdate()[0].GetVal() + json.Unmarshal(val.GetJsonIetfVal(), &gotVal) + m := gotVal.(map[string]interface{}) + for k, v := range m { + gotMap[k] = v + } + } + + fmt.Printf("var %s = map[string]interface{}{\n", name) + for k, v := range gotMap { + fmt.Printf("\t\"%v\": \"%v\",\n", k, v) + } + fmt.Printf("}\n") + fmt.Printf("\n\n>>>>>\n\n") +} + +func assertExpectedValueFromMap(t *testing.T, response *gnmipb.GetResponse, expected map[string]interface{}) { + notifs := response.GetNotification() + var gotVal interface{} + var gotMap = make(map[string]interface{}) + + // Load up all k, v pairs out of the JSON value into a go map. + count := len(notifs) + for i := 0; i < count; i++ { + val := notifs[i].GetUpdate()[0].GetVal() + json.Unmarshal(val.GetJsonIetfVal(), &gotVal) + m := gotVal.(map[string]interface{}) + for k, v := range m { + gotMap[k] = v + } + } + + // Assert matching k, v pairs from the `expected` map and data from the gnmi response. + if len(expected) != len(gotMap) { + t.Fatalf("Expected %v entries, got %v.", len(expected), len(gotMap)) + } + for k, v := range gotMap { + if val, ok := expected[k]; ok { + if val != v { + t.Fatalf("Expected key %v with value %v, but got the value %v instead.", k, val, v) + } + } else { + t.Fatalf("Received unexpected key %v from output.", k) + } + } +} + func assertExpectedValue(t *testing.T, response *gnmipb.GetResponse, expectedResponseValue interface{}) { var gotVal interface{} if response != nil { @@ -183,7 +354,6 @@ func assertExpectedValue(t *testing.T, response *gnmipb.GetResponse, expectedRes } } - fmt.Printf("got: %v (%T),\nwant %v (%T)\n", gotVal, gotVal, expectedResponseValue, expectedResponseValue) if !reflect.DeepEqual(gotVal, expectedResponseValue) { t.Errorf("got: %v (%T),\nwant %v (%T)", gotVal, gotVal, expectedResponseValue, expectedResponseValue) } @@ -251,7 +421,54 @@ func TestVirtualPathClient(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - // Perform unit tests. + // Perform unit tests that closely resemble Jipan's original gnmi tests. + t.Run("Get Interfaces/Port[name=Ethernet70], a valid path (with no corresponding data in the db); expected NotFound", func(t *testing.T) { + expectedReturnCode := codes.NotFound + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet70]" + sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + }) + t.Run("Get Interfaces/Port[name=Ethernet400], invalid valid path; expected NotFound", func(t *testing.T) { + expectedReturnCode := codes.NotFound + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet400]" + sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + }) + t.Run("Get Interfaces/Port[name=Ethernet68]/..., Everything under Ethernet68", func(t *testing.T) { + expectedReturnCode := codes.OK + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet68]/..." + response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + assertExpectedValueFromMap(t, response, expectedValueEthernet68) + }) + t.Run("Get Interfaces/Port[name=Ethernet68]/PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS], valid path for specific leaf, but not implemented.", func(t *testing.T) { + expectedReturnCode := codes.NotFound + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet68]/PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS]" + sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + }) + t.Run("Get Interfaces/Port[name=Ethernet68]/Queue[name=*]/Pfcwd", func(t *testing.T) { + expectedReturnCode := codes.OK + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=Ethernet68]/Queue[name=*]/Pfcwd" + response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + assertExpectedValueFromMap(t, response, expectedValueEthernet68Pfcwd) + }) + t.Run("Get Interfaces/Port[name=*]/PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS], valid path for specific leaf for all nodes, but not implemented.", func(t *testing.T) { + expectedReturnCode := codes.NotFound + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/Port[name=*]/PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS]" + sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + }) + t.Run("Get Interfaces/.../Pfcwd, valid path for specific PFC-related leaf for all nodes, but not implemented.", func(t *testing.T) { + expectedReturnCode := codes.OK + pathToTargetDB := "SONiC_DB" + xpath := "Interfaces/.../Pfcwd" + response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) + assertExpectedValueFromMap(t, response, expectedValueEthernet68Pfcwd) + }) + + // Perform some additional unit tests. t.Run("Get Interfaces/Port[name=Ethernet68/1]/BaseCounter", func(t *testing.T) { expectedReturnCode := codes.OK pathToTargetDB := "SONiC_DB" @@ -284,7 +501,7 @@ func TestVirtualPathClient(t *testing.T) { expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_Pfcwd.txt") assertExpectedValue(t, response, expectedResponseValue) }) - t.Run("Get Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/Pfcwd", func(t *testing.T) { + t.Run("Get Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/QueueCounter", func(t *testing.T) { expectedReturnCode := codes.OK pathToTargetDB := "SONiC_DB" xpath := "Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/QueueCounter" From b414595d1707a03ae17785d054af6231359de75b Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Mon, 6 May 2019 04:39:33 +0000 Subject: [PATCH 11/20] Got a basic subscribe test working. --- virtual_database_client/db_client_test.go | 131 +++++++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/virtual_database_client/db_client_test.go b/virtual_database_client/db_client_test.go index 52d9d5e26..bca5a9fa0 100644 --- a/virtual_database_client/db_client_test.go +++ b/virtual_database_client/db_client_test.go @@ -15,10 +15,12 @@ import ( "time" sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + "github.com/kylelemons/godebug/pretty" gnmi "github.com/Azure/sonic-telemetry/gnmi_server" xpath "github.com/jipanyang/gnxi/utils/xpath" + "github.com/openconfig/gnmi/client" gnmipb "github.com/openconfig/gnmi/proto/gnmi" value "github.com/openconfig/gnmi/value" @@ -29,8 +31,12 @@ import ( codes "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" status "google.golang.org/grpc/status" + + gclient "github.com/jipanyang/gnmi/client/gnmi" ) +var clientTypes = []string{gclient.Type} + func getRedisClient(t *testing.T, dbName string) *redis.Client { dbn := spb.Target_value[dbName] rclient := redis.NewClient(&redis.Options{ @@ -367,16 +373,13 @@ func loadExpectedResponseByteData(t *testing.T, path string) interface{} { return data } -func TestVirtualPathClient(t *testing.T) { +func TestVirtualDatabaseGNMIGet(t *testing.T) { // Open COUNTERS_DB redis client. countersDB := getRedisClient(t, "COUNTERS_DB") defer countersDB.Close() countersDB.FlushDB() // Enable keyspace notification. - // Note (@ragaul): - // Don't know exactly why this is needed -- likely for testing pub/sub (need investigate + - // confirmation). Copied from gnmi_server/server_test.go os.Setenv("PATH", "/usr/bin:/sbin:/bin:/usr/local/bin") cmd := exec.Command("redis-cli", "config", "set", "notify-keyspace-events", "KEA") _, err := cmd.Output() @@ -527,6 +530,126 @@ func TestVirtualPathClient(t *testing.T) { }) } +func flushDBAndLoadTestData(t *testing.T, countersDB *redis.Client) { + countersDB.FlushDB() + + loadTestDataIntoRedis(t, countersDB, "COUNTERS_PORT_NAME_MAP", "../testdata/COUNTERS_PORT_NAME_MAP.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS_QUEUE_NAME_MAP", "../testdata/COUNTERS_QUEUE_NAME_MAP.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1000000000039", "../testdata/COUNTERS:Ethernet68.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1000000000003", "../testdata/COUNTERS:Ethernet1.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000092a", "../testdata/COUNTERS:oid:0x1500000000092a.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000091c", "../testdata/COUNTERS:oid:0x1500000000091c.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000091e", "../testdata/COUNTERS:oid:0x1500000000091e.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000091f", "../testdata/COUNTERS:oid:0x1500000000091f.txt") + loadTestDataIntoRedis(t, countersDB, "COUNTERS:oid:0x1500000000091f", "../testdata/COUNTERS:oid:0x1500000000091f.txt") + + prepareConfigDB(t) +} + +func loadTestDataAsJSON(t *testing.T, testDataPath string) interface{} { + data, err := ioutil.ReadFile(testDataPath) + if err != nil { + t.Fatalf("read file %v err: %v", testDataPath, err) + } + + var dataJSON interface{} + json.Unmarshal(data, &dataJSON) + + return dataJSON +} + +func TestVirtualDatabaseGNMISubscribe(t *testing.T) { + // Open COUNTERS_DB redis client. + countersDB := getRedisClient(t, "COUNTERS_DB") + defer countersDB.Close() + + // Enable keyspace notification. + os.Setenv("PATH", "/usr/bin:/sbin:/bin:/usr/local/bin") + cmd := exec.Command("redis-cli", "config", "set", "notify-keyspace-events", "KEA") + _, err := cmd.Output() + if err != nil { + t.Fatal("failed to enable redis keyspace notification ", err) + } + + // Start telementry service. + gnmiServer := creategNMIServer(t) + if gnmiServer == nil { + t.Fatalf("Unable to bind gNMI server to local port 8080.") + } + go rungNMIServer(t, gnmiServer) + defer gnmiServer.Stop() + + // One unit test. + t.Run("Test description.", func(t *testing.T) { + flushDBAndLoadTestData(t, countersDB) + + time.Sleep(time.Millisecond * 1000) + + c := client.New() + defer c.Close() + + // Query + var query client.Query + query.Addrs = []string{"127.0.0.1:8080"} + query.Target = "COUNTERS_DB" + query.Type = client.Stream + query.Queries = []client.Path{{"COUNTERS", "Ethernet68"}} + query.TLS = &tls.Config{InsecureSkipVerify: true} + + logNotifications := false + + // Collate notifications with handler. + var gotNotifications []client.Notification + query.NotificationHandler = func(notification client.Notification) error { + if logNotifications { + t.Logf("reflect.TypeOf(notification) %v : %v", reflect.TypeOf(notification), notification) + } + + if n, ok := notification.(client.Update); ok { + n.TS = time.Unix(0, 200) + gotNotifications = append(gotNotifications, n) + } else { + gotNotifications = append(gotNotifications, notification) + } + + return nil + } + + go c.Subscribe(context.Background(), query) + defer c.Close() + + // Wait for subscription to sync. + time.Sleep(time.Millisecond * 500) + + // Do updates. + // rclient.HSet(update.tableName+update.delimitor+update.tableKey, update.field, update.value) + countersDB.HSet("COUNTERS:oid:0x1000000000039", "test_field", "test_value") + + // Wait for updates to propogate notifications. + time.Sleep(time.Millisecond * 1000) + + countersEthernet68 := loadTestDataAsJSON(t, "../testdata/COUNTERS:Ethernet68.txt") + countersEthernet68Updated := loadTestDataAsJSON(t, "../testdata/COUNTERS:Ethernet68.txt") + updateMap := countersEthernet68Updated.(map[string]interface{}) + updateMap["test_field"] = "test_value" + + // Expected notifications. + expectedNotifications := []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68"}, TS: time.Unix(0, 200), Val: countersEthernet68}, + client.Sync{}, + client.Update{Path: []string{"COUNTERS", "Ethernet68"}, TS: time.Unix(0, 200), Val: countersEthernet68Updated}, + } + + // Compare results. + if diff := pretty.Compare(expectedNotifications, gotNotifications); diff != "" { + t.Log("\n Want: \n", expectedNotifications) + t.Log("\n Got : \n", gotNotifications) + t.Errorf("Unexpected updates:\n%s", diff) + } + }) +} + func init() { // Inform gNMI server to use redis tcp localhost connection sdc.UseRedisLocalTcpPort = true From e29cfa5885f33148114050cb858c8f18043d7d32 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Mon, 6 May 2019 06:20:50 +0000 Subject: [PATCH 12/20] Figured out way to subscribe to target SONiC_DB --- virtual_database_client/db_client_test.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/virtual_database_client/db_client_test.go b/virtual_database_client/db_client_test.go index bca5a9fa0..932dcb667 100644 --- a/virtual_database_client/db_client_test.go +++ b/virtual_database_client/db_client_test.go @@ -591,12 +591,12 @@ func TestVirtualDatabaseGNMISubscribe(t *testing.T) { // Query var query client.Query query.Addrs = []string{"127.0.0.1:8080"} - query.Target = "COUNTERS_DB" + query.Target = "SONiC_DB" query.Type = client.Stream - query.Queries = []client.Path{{"COUNTERS", "Ethernet68"}} + query.Queries = []client.Path{{"Interfaces", "Port[name=Ethernet68]", "BaseCounter"}} query.TLS = &tls.Config{InsecureSkipVerify: true} - logNotifications := false + logNotifications := true // Collate notifications with handler. var gotNotifications []client.Notification @@ -615,7 +615,13 @@ func TestVirtualDatabaseGNMISubscribe(t *testing.T) { return nil } - go c.Subscribe(context.Background(), query) + logSubscribeErr := true + go func() { + c.Subscribe(context.Background(), query) + if logSubscribeErr { + fmt.Printf("c.Subscribe err: %v\n", err) + } + }() defer c.Close() // Wait for subscription to sync. @@ -643,8 +649,8 @@ func TestVirtualDatabaseGNMISubscribe(t *testing.T) { // Compare results. if diff := pretty.Compare(expectedNotifications, gotNotifications); diff != "" { - t.Log("\n Want: \n", expectedNotifications) - t.Log("\n Got : \n", gotNotifications) + t.Log("\n\nWant: \n\n", expectedNotifications) + t.Log("\n\nGot : \n\n", gotNotifications) t.Errorf("Unexpected updates:\n%s", diff) } }) From e597358b14b43db87ceb666c2177bfc6d34dc953 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Tue, 7 May 2019 00:45:44 +0000 Subject: [PATCH 13/20] Wrapped up stream queries. --- virtual_database_client/db_client_test.go | 199 +++++++++++++++++++--- 1 file changed, 176 insertions(+), 23 deletions(-) diff --git a/virtual_database_client/db_client_test.go b/virtual_database_client/db_client_test.go index 932dcb667..5853957b8 100644 --- a/virtual_database_client/db_client_test.go +++ b/virtual_database_client/db_client_test.go @@ -579,24 +579,31 @@ func TestVirtualDatabaseGNMISubscribe(t *testing.T) { go rungNMIServer(t, gnmiServer) defer gnmiServer.Stop() - // One unit test. - t.Run("Test description.", func(t *testing.T) { + // Generic function for performing a subscription test. The flow is: + // 1. Flush redis db and load in all test data. + // 2. Construct a gNMI client to perform the subscription RPC. + // 3. Build the subscription query struct. + // 4. Perform database updates. + // 5. Assert expectations on collated notifications. + doSubscribeTest := func(t *testing.T, queryPaths []client.Path, expectedNotifications []client.Notification, updates func(), shouldSucceed bool) { + // 1. Flush redis db and load in all test data. flushDBAndLoadTestData(t, countersDB) time.Sleep(time.Millisecond * 1000) + // 2. Construct a gNMI client to perform the subscription RPC. c := client.New() defer c.Close() - // Query + // 3. Build the subscription query struct. var query client.Query query.Addrs = []string{"127.0.0.1:8080"} query.Target = "SONiC_DB" query.Type = client.Stream - query.Queries = []client.Path{{"Interfaces", "Port[name=Ethernet68]", "BaseCounter"}} + query.Queries = queryPaths query.TLS = &tls.Config{InsecureSkipVerify: true} - logNotifications := true + logNotifications := false // Collate notifications with handler. var gotNotifications []client.Notification @@ -606,7 +613,7 @@ func TestVirtualDatabaseGNMISubscribe(t *testing.T) { } if n, ok := notification.(client.Update); ok { - n.TS = time.Unix(0, 200) + n.TS = time.Unix(0, 0) // Clear this to zero so expected notification formats are easier to assert. gotNotifications = append(gotNotifications, n) } else { gotNotifications = append(gotNotifications, notification) @@ -615,11 +622,11 @@ func TestVirtualDatabaseGNMISubscribe(t *testing.T) { return nil } - logSubscribeErr := true + logSubscribeErr := false go func() { c.Subscribe(context.Background(), query) if logSubscribeErr { - fmt.Printf("c.Subscribe err: %v\n", err) + t.Logf("c.Subscribe err: %v\n", err) } }() defer c.Close() @@ -627,32 +634,178 @@ func TestVirtualDatabaseGNMISubscribe(t *testing.T) { // Wait for subscription to sync. time.Sleep(time.Millisecond * 500) - // Do updates. - // rclient.HSet(update.tableName+update.delimitor+update.tableKey, update.field, update.value) - countersDB.HSet("COUNTERS:oid:0x1000000000039", "test_field", "test_value") + // 4. Perform database updates. + updates() // Wait for updates to propogate notifications. time.Sleep(time.Millisecond * 1000) - countersEthernet68 := loadTestDataAsJSON(t, "../testdata/COUNTERS:Ethernet68.txt") - countersEthernet68Updated := loadTestDataAsJSON(t, "../testdata/COUNTERS:Ethernet68.txt") - updateMap := countersEthernet68Updated.(map[string]interface{}) - updateMap["test_field"] = "test_value" + // 5. Assert expectations on collated notifications. + if diff := pretty.Compare(expectedNotifications, gotNotifications); shouldSucceed && diff != "" { + t.Log("\n\nWant: \n\n", expectedNotifications) + t.Log("\n\nGot : \n\n", gotNotifications) + t.Errorf("Unexpected updates:\n%s", diff) + } + } + + t.Run("Query all under Ethernet68, add new test field, assert failure (not implemented).", func(t *testing.T) { + queryPaths := []client.Path{{"Interfaces", "Port[name=Ethernet68]", "..."}} + + updates := func() { + countersDB.HSet("COUNTERS:oid:0x1000000000039", "test_field", "test_value") + } + + // Querying for a new field is not yet implemented. + assertFailure := false + + doSubscribeTest(t, queryPaths, []client.Notification{}, updates, assertFailure) + }) + + t.Run("Query all under Ethernet68/1 (vendor valias), add new test field, assert failure (not implemented).", func(t *testing.T) { + queryPaths := []client.Path{{"Interfaces", "Port[name=Ethernet68/1]", "..."}} + + updates := func() { + countersDB.HSet("COUNTERS:oid:0x1000000000039", "test_field", "test_value") + } + + // Querying for a new field is not yet implemented. + assertFailure := false + + doSubscribeTest(t, queryPaths, []client.Notification{}, updates, assertFailure) + }) + + t.Run("Stream query for Interfaces/Port[name=Ethernet68]/BaseCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS], updating SAI_PORT_STAT_PFC_7_RX_PKTS from 2 to 3, assert failure (not implemented).", func(t *testing.T) { + queryPaths := []client.Path{{"Interfaces", "Port[name=Ethernet68]", "BaseCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS]"}} - // Expected notifications. expectedNotifications := []client.Notification{ client.Connected{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68"}, TS: time.Unix(0, 200), Val: countersEthernet68}, + client.Update{Path: []string{"COUNTERS", "Ethernet68"}, TS: time.Unix(0, 0), Val: "2"}, client.Sync{}, - client.Update{Path: []string{"COUNTERS", "Ethernet68"}, TS: time.Unix(0, 200), Val: countersEthernet68Updated}, + client.Update{Path: []string{"COUNTERS", "Ethernet68"}, TS: time.Unix(0, 0), Val: "3"}, } - // Compare results. - if diff := pretty.Compare(expectedNotifications, gotNotifications); diff != "" { - t.Log("\n\nWant: \n\n", expectedNotifications) - t.Log("\n\nGot : \n\n", gotNotifications) - t.Errorf("Unexpected updates:\n%s", diff) + updates := func() { + countersDB.HSet("COUNTERS:oid:0x1000000000039", "SAI_PORT_STAT_PFC_7_RX_PKTS", "3") + } + + // Querying for a specific field under BaseCounter is not yet implemented. + assertFailure := false + + doSubscribeTest(t, queryPaths, expectedNotifications, updates, assertFailure) + }) + + t.Run("Stream query for Interfaces/Port[name=Ethernet68]/Queue[name=Queue3]/Pfcwd, updating PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED from 0 to 1.", func(t *testing.T) { + queryPaths := []client.Path{{"Interfaces", "Port[name=Ethernet68]", "Queue[name=Queue3]", "Pfcwd"}} + + initialValue := make(map[string]string) + initialValue["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "0" + initialValue["PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED"] = "0" + initialValue["PFC_WD_STATUS"] = "operational" + initialValue["SAI_PORT_STAT_PFC_3_RX_PKTS"] = "0" + + updatedValue := make(map[string]string) + updatedValue["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "1" + + expectedNotifications := []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"Interfaces", "Port", "Ethernet68", "Queue", "Queue3", "Pfcwd"}, TS: time.Unix(0, 0), Val: initialValue}, + client.Sync{}, + client.Update{Path: []string{"Interfaces", "Port", "Ethernet68", "Queue", "Queue3", "Pfcwd"}, TS: time.Unix(0, 0), Val: updatedValue}, + } + + updates := func() { + countersDB.HSet("COUNTERS:oid:0x1500000000091e", "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", "1") + } + + doSubscribeTest(t, queryPaths, expectedNotifications, updates, true) + }) + + t.Run("Stream query for Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue3]/Pfcwd (use vendor alias), updating PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED from 0 to 1.", func(t *testing.T) { + queryPaths := []client.Path{{"Interfaces", "Port[name=Ethernet68/1]", "Queue[name=Queue3]", "Pfcwd"}} + + initialValue := make(map[string]string) + initialValue["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "0" + initialValue["PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED"] = "0" + initialValue["PFC_WD_STATUS"] = "operational" + initialValue["SAI_PORT_STAT_PFC_3_RX_PKTS"] = "0" + + updatedValue := make(map[string]string) + updatedValue["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "1" + + expectedNotifications := []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"Interfaces", "Port", "Ethernet68/1", "Queue", "Queue3", "Pfcwd"}, TS: time.Unix(0, 0), Val: initialValue}, + client.Sync{}, + client.Update{Path: []string{"Interfaces", "Port", "Ethernet68/1", "Queue", "Queue3", "Pfcwd"}, TS: time.Unix(0, 0), Val: updatedValue}, + } + + updates := func() { + countersDB.HSet("COUNTERS:oid:0x1500000000091e", "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", "1") + } + + doSubscribeTest(t, queryPaths, expectedNotifications, updates, true) + }) + + t.Run("Stream query for Interfaces/Port[name=*]/..., updating with new test field (not implemented).", func(t *testing.T) { + queryPaths := []client.Path{{"Interfaces", "Port[name=*]", "..."}} + + updates := func() { + countersDB.HSet("COUNTERS:oid:0x1000000000039", "test_field", "test_value") } + + // Querying for a new field is not yet implemented. + assertFailure := false + + doSubscribeTest(t, queryPaths, []client.Notification{}, updates, assertFailure) + }) + + t.Run("Stream query for Interfaces/Port[name=*]/PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS], updating SAI_PORT_STAT_PFC_7_RX_PKTS from 2 to 4 (not implemented).", func(t *testing.T) { + queryPaths := []client.Path{{"Interfaces", "Port[name=*]", "PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS]"}} + + initialValue := make(map[string]string) + initialValue["SAI_PORT_STAT_PFC_7_RX_PKTS"] = "2" + + updatedValue := make(map[string]string) + updatedValue["SAI_PORT_STAT_PFC_7_RX_PKTS"] = "4" + + expectedNotifications := []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"Interfaces", "Port", "Ethernet68", "PfcCounter", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, TS: time.Unix(0, 0), Val: initialValue}, + client.Sync{}, + client.Update{Path: []string{"Interfaces", "Port", "Ethernet68", "PfcCounter", "SAI_PORT_STAT_PFC_7_RX_PKTS"}, TS: time.Unix(0, 0), Val: updatedValue}, + } + + updates := func() { + countersDB.HSet("COUNTERS:oid:0x1000000000039", "SAI_PORT_STAT_PFC_7_RX_PKTS", "4") + } + + // Querying for a specific field under PfcCounter is not yet implemented. + assertFailure := false + + doSubscribeTest(t, queryPaths, expectedNotifications, updates, assertFailure) + }) + + t.Run("Stream query for Interfaces/Port[name=*]/Queue[name=*]/Pfcwd[field=PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED], updating PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED from 0 to 1.", func(t *testing.T) { + queryPaths := []client.Path{{"Interfaces", "Port[name=Ethernet68]", "Queue[name=Queue3]", "Pfcwd[field=PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED]"}} + + initialValue := make(map[string]string) + initialValue["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "0" + + updatedValue := make(map[string]string) + updatedValue["PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED"] = "1" + + expectedNotifications := []client.Notification{ + client.Connected{}, + client.Update{Path: []string{"Interfaces", "Port", "Ethernet68", "Queue", "Queue3", "Pfcwd"}, TS: time.Unix(0, 0), Val: initialValue}, + client.Sync{}, + client.Update{Path: []string{"Interfaces", "Port", "Ethernet68", "Queue", "Queue3", "Pfcwd"}, TS: time.Unix(0, 0), Val: updatedValue}, + } + + updates := func() { + countersDB.HSet("COUNTERS:oid:0x1500000000091e", "PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED", "1") + } + + doSubscribeTest(t, queryPaths, expectedNotifications, updates, true) }) } From 90d4437c92b765b0b173196eabef01c55aa6ae53 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Wed, 15 May 2019 19:20:42 +0000 Subject: [PATCH 14/20] gofmt on all code under folder. --- virtual_database_client/db_client.go | 277 ++++++++++++------------ virtual_database_client/handler_func.go | 22 +- virtual_database_client/trie.go | 147 +++++++------ 3 files changed, 221 insertions(+), 225 deletions(-) diff --git a/virtual_database_client/db_client.go b/virtual_database_client/db_client.go index 5368b3eaf..910430c91 100644 --- a/virtual_database_client/db_client.go +++ b/virtual_database_client/db_client.go @@ -3,50 +3,50 @@ package client import ( - //"bytes" - //"encoding/json" - "fmt" - //"net" - //"reflect" - //"strconv" - //"strings" - "sync" - "time" - - log "github.com/golang/glog" - - spb "github.com/Azure/sonic-telemetry/proto" - "github.com/go-redis/redis" - gnmipb "github.com/openconfig/gnmi/proto/gnmi" - "github.com/workiva/go-datastructures/queue" + //"bytes" + //"encoding/json" + "fmt" + //"net" + //"reflect" + //"strconv" + //"strings" + "sync" + "time" + + log "github.com/golang/glog" + + spb "github.com/Azure/sonic-telemetry/proto" + "github.com/go-redis/redis" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" + "github.com/workiva/go-datastructures/queue" ) const ( // indentString represents the default indentation string used for JSON. // Two spaces are used here. - indentString string = " " - Default_REDIS_UNIXSOCKET string = "/var/run/redis/redis.sock" - Default_REDIS_LOCAL_TCP_PORT string = "localhost:6379" + indentString string = " " + Default_REDIS_UNIXSOCKET string = "/var/run/redis/redis.sock" + Default_REDIS_LOCAL_TCP_PORT string = "localhost:6379" ) // Client defines a set of methods which every client must implement. // This package provides one implmentation for now: the DbClient // type Client interface { - // StreamRun will start watching service on data source - // and enqueue data change to the priority queue. - // It stops all activities upon receiving signal on stop channel - // It should run as a go routine - StreamRun(q *queue.PriorityQueue, stop chan struct{}, w *sync.WaitGroup) - // Poll will start service to respond poll signal received on poll channel. - // data read from data source will be enqueued on to the priority queue - // The service will stop upon detection of poll channel closing. - // It should run as a go routine - PollRun(q *queue.PriorityQueue, poll chan struct{}, w *sync.WaitGroup) - // Get return data from the data source in format of *spb.Value - Get(w *sync.WaitGroup) ([]*spb.Value, error) - // Close provides implemenation for explicit cleanup of Client - Close() error + // StreamRun will start watching service on data source + // and enqueue data change to the priority queue. + // It stops all activities upon receiving signal on stop channel + // It should run as a go routine + StreamRun(q *queue.PriorityQueue, stop chan struct{}, w *sync.WaitGroup) + // Poll will start service to respond poll signal received on poll channel. + // data read from data source will be enqueued on to the priority queue + // The service will stop upon detection of poll channel closing. + // It should run as a go routine + PollRun(q *queue.PriorityQueue, poll chan struct{}, w *sync.WaitGroup) + // Get return data from the data source in format of *spb.Value + Get(w *sync.WaitGroup) ([]*spb.Value, error) + // Close provides implemenation for explicit cleanup of Client + Close() error } var ( @@ -59,11 +59,11 @@ var ( ) type tablePath struct { - dbName string - keyName string - delimitor string - fields []string // fields listed in list are returned - patterns []string // fields matched with patterns are returned + dbName string + keyName string + delimitor string + fields []string // fields listed in list are returned + patterns []string // fields matched with patterns are returned } type Value struct { @@ -82,30 +82,30 @@ func (val Value) Compare(other queue.Item) int { } type DbClient struct { - prefix *gnmipb.Path + prefix *gnmipb.Path // Used by Get server - paths []*gnmipb.Path - //pathG2S map[*gnmipb.Path][]tablePath + paths []*gnmipb.Path + //pathG2S map[*gnmipb.Path][]tablePath - q *queue.PriorityQueue - channel chan struct{} + q *queue.PriorityQueue + channel chan struct{} - synced sync.WaitGroup // Control when to send gNMI sync_response - w *sync.WaitGroup // wait for all sub go routines to finish - mu sync.RWMutex // Mutex for data protection among routines for DbClient + synced sync.WaitGroup // Control when to send gNMI sync_response + w *sync.WaitGroup // wait for all sub go routines to finish + mu sync.RWMutex // Mutex for data protection among routines for DbClient - sendMsg int64 - recvMsg int64 - errors int64 + sendMsg int64 + recvMsg int64 + errors int64 } func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { - var client DbClient - var err error - // Testing program may ask to use redis local tcp connection - if UseRedisLocalTcpPort { - useRedisTcpClient() - } + var client DbClient + var err error + // Testing program may ask to use redis local tcp connection + if UseRedisLocalTcpPort { + useRedisTcpClient() + } err = initCountersPortNameMap() if err != nil { @@ -128,72 +128,69 @@ func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { client.paths = paths return &client, nil /* - client.pathG2S = make(map[*gnmipb.Path][]tablePath) - err = populateAlltablePaths(prefix, paths, &client.pathG2S) + client.pathG2S = make(map[*gnmipb.Path][]tablePath) + err = populateAlltablePaths(prefix, paths, &client.pathG2S) - if err != nil { - return nil, err - } else { - return &client, nil - } + if err != nil { + return nil, err + } else { + return &client, nil + } */ } - func (c *DbClient) StreamRun(q *queue.PriorityQueue, stop chan struct{}, w *sync.WaitGroup) { c.w = w defer c.w.Done() c.q = q c.channel = stop - pathG2S := make(map[*gnmipb.Path][]tablePath) - err := populateAlltablePaths(c.prefix, c.paths, &pathG2S) - if err != nil { - enqueFatalMsg(c, err.Error()) + pathG2S := make(map[*gnmipb.Path][]tablePath) + err := populateAlltablePaths(c.prefix, c.paths, &pathG2S) + if err != nil { + enqueFatalMsg(c, err.Error()) return - } + } if len(pathG2S) == 0 { enqueFatalMsg(c, fmt.Sprintf("Prefix:%v, path: %v not valid paths", c.prefix, c.paths)) return } - + // Assume all ON_CHANGE mode for gnmiPath, tblPaths := range pathG2S { c.w.Add(1) c.synced.Add(1) go dbPathSubscribe(gnmiPath, tblPaths, c) } - - // Wait until all data values corresponding to the paths specified + + // Wait until all data values corresponding to the paths specified // in the SubscriptionList has been transmitted at least once c.synced.Wait() // Inject sync message c.q.Put(Value{ &spb.Value{ - Timestamp: time.Now().UnixNano(), - SyncResponse: true, + Timestamp: time.Now().UnixNano(), + SyncResponse: true, }, }) log.V(2).Infof("%v Synced", pathG2S) return } - func (c *DbClient) PollRun(q *queue.PriorityQueue, poll chan struct{}, w *sync.WaitGroup) { return } - func (c *DbClient) Get(w *sync.WaitGroup) ([]*spb.Value, error) { // wait sync for Get, not used for now c.w = w - pathG2S := make(map[*gnmipb.Path][]tablePath) - err := populateAlltablePaths(c.prefix, c.paths, &pathG2S) - if err != nil { - return nil, err - } + pathG2S := make(map[*gnmipb.Path][]tablePath) + err := populateAlltablePaths(c.prefix, c.paths, &pathG2S) + if err != nil { + return nil, err + } if len(pathG2S) == 0 { return nil, fmt.Errorf("Failed to map to real db paths. Prefix: %v, paths: %v not valid paths", c.prefix, c.paths) @@ -208,10 +205,10 @@ func (c *DbClient) Get(w *sync.WaitGroup) ([]*spb.Value, error) { } values = append(values, &spb.Value{ - Prefix: c.prefix, - Path: gnmiPath, - Timestamp: ts.UnixNano(), - Val: val, + Prefix: c.prefix, + Path: gnmiPath, + Timestamp: ts.UnixNano(), + Val: val, }) } log.V(5).Infof("Getting #%v", values) @@ -221,65 +218,65 @@ func (c *DbClient) Get(w *sync.WaitGroup) ([]*spb.Value, error) { // TODO: Log data related to this session func (c *DbClient) Close() error { - return nil + return nil } func GetTableKeySeparator(target string) (string, error) { - _, ok := spb.Target_value[target] - if !ok { - log.V(1).Infof(" %v not a valid path target", target) - return "", fmt.Errorf("%v not a valid path target", target) - } - - var separator string - switch target { - case "CONFIG_DB": - separator = "|" - case "STATE_DB": - separator = "|" - default: - separator = ":" - } - return separator, nil + _, ok := spb.Target_value[target] + if !ok { + log.V(1).Infof(" %v not a valid path target", target) + return "", fmt.Errorf("%v not a valid path target", target) + } + + var separator string + switch target { + case "CONFIG_DB": + separator = "|" + case "STATE_DB": + separator = "|" + default: + separator = ":" + } + return separator, nil } // For testing only func useRedisTcpClient() { - for dbName, dbn := range spb.Target_value { - if dbName != "OTHERS" { - // DB connector for direct redis operation - var redisDb *redis.Client - if UseRedisLocalTcpPort { - redisDb = redis.NewClient(&redis.Options{ - Network: "tcp", - Addr: Default_REDIS_LOCAL_TCP_PORT, - Password: "", // no password set - DB: int(dbn), - DialTimeout: 0, - }) - } - Target2RedisDb[dbName] = redisDb - } - } + for dbName, dbn := range spb.Target_value { + if dbName != "OTHERS" { + // DB connector for direct redis operation + var redisDb *redis.Client + if UseRedisLocalTcpPort { + redisDb = redis.NewClient(&redis.Options{ + Network: "tcp", + Addr: Default_REDIS_LOCAL_TCP_PORT, + Password: "", // no password set + DB: int(dbn), + DialTimeout: 0, + }) + } + Target2RedisDb[dbName] = redisDb + } + } } // Client package prepare redis clients to all DBs automatically func init() { - for dbName, dbn := range spb.Target_value { - if dbName != "OTHERS" { - // DB connector for direct redis operation - var redisDb *redis.Client - - redisDb = redis.NewClient(&redis.Options{ - Network: "unix", - Addr: Default_REDIS_UNIXSOCKET, - Password: "", // no password set - DB: int(dbn), - DialTimeout: 0, - }) - Target2RedisDb[dbName] = redisDb - } - } + for dbName, dbn := range spb.Target_value { + if dbName != "OTHERS" { + // DB connector for direct redis operation + var redisDb *redis.Client + + redisDb = redis.NewClient(&redis.Options{ + Network: "unix", + Addr: Default_REDIS_UNIXSOCKET, + Password: "", // no password set + DB: int(dbn), + DialTimeout: 0, + }) + Target2RedisDb[dbName] = redisDb + } + } } // Convert from SONiC Value to its corresponding gNMI proto stream @@ -288,7 +285,7 @@ func ValToResp(val Value) (*gnmipb.SubscribeResponse, error) { switch val.GetSyncResponse() { case true: return &gnmipb.SubscribeResponse{ - Response: &gnmipb.SubscribeResponse_SyncResponse{ + Response: &gnmipb.SubscribeResponse_SyncResponse{ SyncResponse: true, }, }, nil @@ -299,14 +296,14 @@ func ValToResp(val Value) (*gnmipb.SubscribeResponse, error) { } return &gnmipb.SubscribeResponse{ - Response: &gnmipb.SubscribeResponse_Update{ - Update: &gnmipb.Notification{ - Timestamp: val.GetTimestamp(), - Prefix: val.GetPrefix(), - Update: []*gnmipb.Update{ + Response: &gnmipb.SubscribeResponse_Update{ + Update: &gnmipb.Notification{ + Timestamp: val.GetTimestamp(), + Prefix: val.GetPrefix(), + Update: []*gnmipb.Update{ { - Path: val.GetPath(), - Val: val.GetVal(), + Path: val.GetPath(), + Val: val.GetVal(), }, }, }, diff --git a/virtual_database_client/handler_func.go b/virtual_database_client/handler_func.go index 40024b744..0ea22c835 100644 --- a/virtual_database_client/handler_func.go +++ b/virtual_database_client/handler_func.go @@ -9,32 +9,32 @@ import ( type handlerFunc func(*gnmipb.Path, *map[*gnmipb.Path][]tablePath) error type pathHdlrFunc struct { - path []string - handler handlerFunc + path []string + handler handlerFunc } var ( - pathTrie *PathTrie + pathTrie *PathTrie // path2HdlrFuncTbl is used to populate trie tree which is used to // map gNMI path to real database paths. path2HdlrFuncTbl = []pathHdlrFunc{ { // new virtual path for PFC WD stats - path: []string{"SONiC_DB", "Interfaces", "Port", "Queue", "Pfcwd"}, - handler: handlerFunc(v2rPortQueuePfcwdStats), + path: []string{"SONiC_DB", "Interfaces", "Port", "Queue", "Pfcwd"}, + handler: handlerFunc(v2rPortQueuePfcwdStats), }, { // new virtual path for Queue counters - path: []string{"SONiC_DB", "Interfaces", "Port", "Queue", "QueueCounter"}, - handler: handlerFunc(v2rPortQueueCounterStats), + path: []string{"SONiC_DB", "Interfaces", "Port", "Queue", "QueueCounter"}, + handler: handlerFunc(v2rPortQueueCounterStats), }, { // new virtual path for Port PFC counters - path: []string{"SONiC_DB", "Interfaces", "Port", "PfcCounter"}, - handler: handlerFunc(v2rPortPfcCounterStats), + path: []string{"SONiC_DB", "Interfaces", "Port", "PfcCounter"}, + handler: handlerFunc(v2rPortPfcCounterStats), }, { // new virtual path for Port Base Counters - path: []string{"SONiC_DB", "Interfaces", "Port", "BaseCounter"}, - handler: handlerFunc(v2rPortBaseCounterStats), + path: []string{"SONiC_DB", "Interfaces", "Port", "BaseCounter"}, + handler: handlerFunc(v2rPortBaseCounterStats), }, } ) diff --git a/virtual_database_client/trie.go b/virtual_database_client/trie.go index cee88775d..4de28d37c 100644 --- a/virtual_database_client/trie.go +++ b/virtual_database_client/trie.go @@ -1,114 +1,113 @@ package client import ( - //"fmt" +//"fmt" ) type PathNode struct { - val string - depth int - term bool - children map[string]*PathNode - parent *PathNode - meta interface{} + val string + depth int + term bool + children map[string]*PathNode + parent *PathNode + meta interface{} } type PathTrie struct { - root *PathNode - size int + root *PathNode + size int } func NewPathTrie() *PathTrie { - return &PathTrie{ - root: &PathNode{children: make(map[string]*PathNode), depth: 0}, - size: 0, - } + return &PathTrie{ + root: &PathNode{children: make(map[string]*PathNode), depth: 0}, + size: 0, + } } // Adds an entry to the Trie, including meta data. Meta data // is stored as 'interface{}' and must be type cast by the caller -func (t *PathTrie) Add(keys []string, meta interface{}) *PathNode{ - node := t.root - for _, key := range keys { - if _, ok := node.children[key]; !ok { - // A new PathNode - newNode := PathNode{ - val: key, - depth: node.depth + 1, - term: false, - children: make(map[string]*PathNode), - parent: node, - meta: meta, - } - node.children[key] = &newNode - } - node = node.children[key] - } - node.meta = meta - node.term = true +func (t *PathTrie) Add(keys []string, meta interface{}) *PathNode { + node := t.root + for _, key := range keys { + if _, ok := node.children[key]; !ok { + // A new PathNode + newNode := PathNode{ + val: key, + depth: node.depth + 1, + term: false, + children: make(map[string]*PathNode), + parent: node, + meta: meta, + } + node.children[key] = &newNode + } + node = node.children[key] + } + node.meta = meta + node.term = true return node } // Returns the parent of this node func (n PathNode) Parent() *PathNode { - return n.parent + return n.parent } func (n PathNode) Meta() interface{} { - return n.meta + return n.meta } func (n PathNode) Terminating() bool { - return n.term + return n.term } func (n PathNode) Val() string { - return n.val + return n.val } func (n PathNode) Children() map[string]*PathNode { - return n.children + return n.children } func findPathNode(node *PathNode, keys []string, result *[]*PathNode) { - // gNMI path convention: - // '...' is multi-level wildcard, and '*' is single-level wildcard + // gNMI path convention: + // '...' is multi-level wildcard, and '*' is single-level wildcard - if len(keys) == 0 { - if node.Terminating() == true { - *result = append(*result, node) - } - return - } + if len(keys) == 0 { + if node.Terminating() == true { + *result = append(*result, node) + } + return + } - key := keys[0] - if node.Terminating() == true { - // Leaf node - if (len(keys) == 1) && (key == "...") { - *result = append(*result, node) - } - return - } + key := keys[0] + if node.Terminating() == true { + // Leaf node + if (len(keys) == 1) && (key == "...") { + *result = append(*result, node) + } + return + } - children := node.Children() - if key == "..." { - if len(keys) > 1 { - if child, ok := children[keys[1]]; ok{ - findPathNode(child, keys[2:], result) - } - } - for _, child := range children { - findPathNode(child, keys, result) - } - } else if key == "*" { - for _, child := range children { - findPathNode(child, keys[1:], result) - } - } else { - if child, ok := children[key]; ok { - findPathNode(child, keys[1:], result) - } - } - return + children := node.Children() + if key == "..." { + if len(keys) > 1 { + if child, ok := children[keys[1]]; ok { + findPathNode(child, keys[2:], result) + } + } + for _, child := range children { + findPathNode(child, keys, result) + } + } else if key == "*" { + for _, child := range children { + findPathNode(child, keys[1:], result) + } + } else { + if child, ok := children[key]; ok { + findPathNode(child, keys[1:], result) + } + } + return } - From ede7a94bb266c92a55b913df8d5e957dffa86912 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Wed, 15 May 2019 19:36:09 +0000 Subject: [PATCH 15/20] Remove dead code (comments). --- dialout/dialout_client/dialout_client_test.go | 10 ++-------- virtual_database_client/db_client.go | 16 ---------------- virtual_database_client/handler_func.go | 1 - virtual_database_client/handler_pfcwd.go | 7 +------ virtual_database_client/path.go | 3 +-- virtual_database_client/trie.go | 4 ---- 6 files changed, 4 insertions(+), 37 deletions(-) diff --git a/dialout/dialout_client/dialout_client_test.go b/dialout/dialout_client/dialout_client_test.go index 01288e19d..580c9d672 100644 --- a/dialout/dialout_client/dialout_client_test.go +++ b/dialout/dialout_client/dialout_client_test.go @@ -9,20 +9,13 @@ import ( "github.com/go-redis/redis" - //"github.com/golang/protobuf/proto" testcert "github.com/Azure/sonic-telemetry/testdata/tls" - //"github.com/kylelemons/godebug/pretty" - //"github.com/openconfig/gnmi/client" pb "github.com/openconfig/gnmi/proto/gnmi" "github.com/openconfig/gnmi/value" "golang.org/x/net/context" "google.golang.org/grpc" - //"google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials" - //"google.golang.org/grpc/status" - //"fmt" "io/ioutil" "os" "os/exec" @@ -31,7 +24,8 @@ import ( "testing" "time" - //sds "github.com/Azure/sonic-telemetry/dialout/dialout_server" + "google.golang.org/grpc/credentials" + sds "github.com/Azure/sonic-telemetry/dialout/dialout_server" spb "github.com/Azure/sonic-telemetry/proto" sdc "github.com/Azure/sonic-telemetry/sonic_data_client" diff --git a/virtual_database_client/db_client.go b/virtual_database_client/db_client.go index 910430c91..47315cfdd 100644 --- a/virtual_database_client/db_client.go +++ b/virtual_database_client/db_client.go @@ -3,13 +3,7 @@ package client import ( - //"bytes" - //"encoding/json" "fmt" - //"net" - //"reflect" - //"strconv" - //"strings" "sync" "time" @@ -127,16 +121,6 @@ func NewDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path) (Client, error) { client.prefix = prefix client.paths = paths return &client, nil - /* - client.pathG2S = make(map[*gnmipb.Path][]tablePath) - err = populateAlltablePaths(prefix, paths, &client.pathG2S) - - if err != nil { - return nil, err - } else { - return &client, nil - } - */ } func (c *DbClient) StreamRun(q *queue.PriorityQueue, stop chan struct{}, w *sync.WaitGroup) { diff --git a/virtual_database_client/handler_func.go b/virtual_database_client/handler_func.go index 0ea22c835..1c0b79f23 100644 --- a/virtual_database_client/handler_func.go +++ b/virtual_database_client/handler_func.go @@ -1,7 +1,6 @@ package client import ( - //"fmt" log "github.com/golang/glog" gnmipb "github.com/openconfig/gnmi/proto/gnmi" ) diff --git a/virtual_database_client/handler_pfcwd.go b/virtual_database_client/handler_pfcwd.go index cf5346999..07341dbf4 100644 --- a/virtual_database_client/handler_pfcwd.go +++ b/virtual_database_client/handler_pfcwd.go @@ -6,13 +6,8 @@ import ( log "github.com/golang/glog" gnmipb "github.com/openconfig/gnmi/proto/gnmi" - //proto "github.com/golang/protobuf/proto" ) -//func (m *tablePath) String() string { -// return proto.CompactTextString(m) -//} - func deepcopy(path, copyPath *gnmipb.Path) { copyPath.Elem = []*gnmipb.PathElem{} @@ -121,7 +116,7 @@ func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl separator, _ := GetTableKeySeparator(dbName) elems := path.GetElem() - //fmt.Printf("path: %v\n\n", path) + log.V(5).Infof("path: %v\n\n", path) // Populate port level var idx_port = 1 diff --git a/virtual_database_client/path.go b/virtual_database_client/path.go index 8be89e56c..d2750f66f 100644 --- a/virtual_database_client/path.go +++ b/virtual_database_client/path.go @@ -4,7 +4,6 @@ import ( "fmt" "strconv" - //"strings" "encoding/json" "net" "regexp" @@ -120,7 +119,7 @@ func tableData2Msi(tblPath *tablePath, msi *map[string]interface{}) error { return err } - //log.V(5).Infof("val: %v\n", val) + log.V(5).Infof("val: %v\n", val) patterns := tblPath.patterns for field, value := range val { for _, pattern := range patterns { diff --git a/virtual_database_client/trie.go b/virtual_database_client/trie.go index 4de28d37c..694dcf311 100644 --- a/virtual_database_client/trie.go +++ b/virtual_database_client/trie.go @@ -1,9 +1,5 @@ package client -import ( -//"fmt" -) - type PathNode struct { val string depth int From f01f39c5b5b0f8b459e21367e4c89d6ed36c79d8 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Wed, 15 May 2019 19:50:28 +0000 Subject: [PATCH 16/20] SONiC_DB to SONIC_DB --- gnmi_server/client_subscribe.go | 3 +-- gnmi_server/server.go | 4 +-- virtual_database_client/db_client_test.go | 30 +++++++++++------------ virtual_database_client/handler_func.go | 8 +++--- virtual_database_client/path.go | 1 - 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/gnmi_server/client_subscribe.go b/gnmi_server/client_subscribe.go index f53a21d89..847193610 100644 --- a/gnmi_server/client_subscribe.go +++ b/gnmi_server/client_subscribe.go @@ -102,7 +102,6 @@ func (c *Client) Run(stream gnmipb.GNMI_SubscribeServer) (err error) { } var target string - //fmt.Printf("Subscribe Prefix: %v\n", target) prefix := c.subscribe.GetPrefix() if prefix == nil { return grpc.Errorf(codes.Unimplemented, "No target specified in prefix") @@ -121,7 +120,7 @@ func (c *Client) Run(stream gnmipb.GNMI_SubscribeServer) (err error) { var dc sdc.Client if target == "OTHERS" { dc, err = sdc.NewNonDbClient(paths, prefix) - } else if target == "SONiC_DB" { + } else if target == "SONIC_DB" { dc, err = vdc.NewDbClient(paths, prefix) } else { dc, err = sdc.NewDbClient(paths, prefix) diff --git a/gnmi_server/server.go b/gnmi_server/server.go index 82577eb67..dbea0a7df 100644 --- a/gnmi_server/server.go +++ b/gnmi_server/server.go @@ -181,7 +181,7 @@ func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetRe var dc sdc.Client if target == "OTHERS" { dc, err = sdc.NewNonDbClient(paths, prefix) - } else if target == "SONiC_DB" { + } else if target == "SONIC_DB" { dc, err = vdc.NewDbClient(paths, prefix) } else { dc, err = sdc.NewDbClient(paths, prefix) @@ -195,7 +195,7 @@ func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetRe return nil, status.Error(codes.NotFound, err.Error()) } - if target == "SONiC_DB" { + if target == "SONIC_DB" { notifications = make([]*gnmipb.Notification, len(spbValues)) } diff --git a/virtual_database_client/db_client_test.go b/virtual_database_client/db_client_test.go index 5853957b8..08176dd45 100644 --- a/virtual_database_client/db_client_test.go +++ b/virtual_database_client/db_client_test.go @@ -427,45 +427,45 @@ func TestVirtualDatabaseGNMIGet(t *testing.T) { // Perform unit tests that closely resemble Jipan's original gnmi tests. t.Run("Get Interfaces/Port[name=Ethernet70], a valid path (with no corresponding data in the db); expected NotFound", func(t *testing.T) { expectedReturnCode := codes.NotFound - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet70]" sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) }) t.Run("Get Interfaces/Port[name=Ethernet400], invalid valid path; expected NotFound", func(t *testing.T) { expectedReturnCode := codes.NotFound - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet400]" sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) }) t.Run("Get Interfaces/Port[name=Ethernet68]/..., Everything under Ethernet68", func(t *testing.T) { expectedReturnCode := codes.OK - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet68]/..." response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) assertExpectedValueFromMap(t, response, expectedValueEthernet68) }) t.Run("Get Interfaces/Port[name=Ethernet68]/PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS], valid path for specific leaf, but not implemented.", func(t *testing.T) { expectedReturnCode := codes.NotFound - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet68]/PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS]" sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) }) t.Run("Get Interfaces/Port[name=Ethernet68]/Queue[name=*]/Pfcwd", func(t *testing.T) { expectedReturnCode := codes.OK - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet68]/Queue[name=*]/Pfcwd" response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) assertExpectedValueFromMap(t, response, expectedValueEthernet68Pfcwd) }) t.Run("Get Interfaces/Port[name=*]/PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS], valid path for specific leaf for all nodes, but not implemented.", func(t *testing.T) { expectedReturnCode := codes.NotFound - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=*]/PfcCounter[field=SAI_PORT_STAT_PFC_7_RX_PKTS]" sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) }) t.Run("Get Interfaces/.../Pfcwd, valid path for specific PFC-related leaf for all nodes, but not implemented.", func(t *testing.T) { expectedReturnCode := codes.OK - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/.../Pfcwd" response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) assertExpectedValueFromMap(t, response, expectedValueEthernet68Pfcwd) @@ -474,7 +474,7 @@ func TestVirtualDatabaseGNMIGet(t *testing.T) { // Perform some additional unit tests. t.Run("Get Interfaces/Port[name=Ethernet68/1]/BaseCounter", func(t *testing.T) { expectedReturnCode := codes.OK - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet68/1]/BaseCounter" response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_BaseCounter.txt") @@ -482,7 +482,7 @@ func TestVirtualDatabaseGNMIGet(t *testing.T) { }) t.Run("Get Interfaces/Port[name=Ethernet68]/BaseCounter (no slash /1 after Ethernet68)", func(t *testing.T) { expectedReturnCode := codes.OK - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet68]/BaseCounter" response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_BaseCounter.txt") @@ -490,7 +490,7 @@ func TestVirtualDatabaseGNMIGet(t *testing.T) { }) t.Run("Get Interfaces/Port[name=Ethernet68/1]/PfcCounter", func(t *testing.T) { expectedReturnCode := codes.OK - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet68/1]/PfcCounter" response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_PfcCounter.txt") @@ -498,7 +498,7 @@ func TestVirtualDatabaseGNMIGet(t *testing.T) { }) t.Run("Get Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/Pfcwd", func(t *testing.T) { expectedReturnCode := codes.OK - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/Pfcwd" response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_Pfcwd.txt") @@ -506,7 +506,7 @@ func TestVirtualDatabaseGNMIGet(t *testing.T) { }) t.Run("Get Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/QueueCounter", func(t *testing.T) { expectedReturnCode := codes.OK - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet68/1]/Queue[name=Queue4]/QueueCounter" response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) expectedResponseValue := loadExpectedResponseByteData(t, "../testdata/Interfaces_Port_name_Ethernet68_1_Queue_name_Queue4_QueueCounter.txt") @@ -514,7 +514,7 @@ func TestVirtualDatabaseGNMIGet(t *testing.T) { }) t.Run("Get Interfaces/Port[name=Ethernet70], a valid path (with no corresponding data in the db); expected NotFound", func(t *testing.T) { expectedReturnCode := codes.NotFound - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=Ethernet70]" response := sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) var expectedResponseValue interface{} = nil @@ -522,7 +522,7 @@ func TestVirtualDatabaseGNMIGet(t *testing.T) { }) t.Run("Get Interfaces/Port[name=*]/..., Retrieve everything under all ports", func(t *testing.T) { expectedReturnCode := codes.OK - pathToTargetDB := "SONiC_DB" + pathToTargetDB := "SONIC_DB" xpath := "Interfaces/Port[name=*]/..." sendGetRequest(t, ctx, gnmiClient, xpath, pathToTargetDB, expectedReturnCode) // Only checking return code, since returned data will: A) require a large text file; B) change @@ -598,7 +598,7 @@ func TestVirtualDatabaseGNMISubscribe(t *testing.T) { // 3. Build the subscription query struct. var query client.Query query.Addrs = []string{"127.0.0.1:8080"} - query.Target = "SONiC_DB" + query.Target = "SONIC_DB" query.Type = client.Stream query.Queries = queryPaths query.TLS = &tls.Config{InsecureSkipVerify: true} diff --git a/virtual_database_client/handler_func.go b/virtual_database_client/handler_func.go index 1c0b79f23..9b1ced4e8 100644 --- a/virtual_database_client/handler_func.go +++ b/virtual_database_client/handler_func.go @@ -20,19 +20,19 @@ var ( path2HdlrFuncTbl = []pathHdlrFunc{ { // new virtual path for PFC WD stats - path: []string{"SONiC_DB", "Interfaces", "Port", "Queue", "Pfcwd"}, + path: []string{"SONIC_DB", "Interfaces", "Port", "Queue", "Pfcwd"}, handler: handlerFunc(v2rPortQueuePfcwdStats), }, { // new virtual path for Queue counters - path: []string{"SONiC_DB", "Interfaces", "Port", "Queue", "QueueCounter"}, + path: []string{"SONIC_DB", "Interfaces", "Port", "Queue", "QueueCounter"}, handler: handlerFunc(v2rPortQueueCounterStats), }, { // new virtual path for Port PFC counters - path: []string{"SONiC_DB", "Interfaces", "Port", "PfcCounter"}, + path: []string{"SONIC_DB", "Interfaces", "Port", "PfcCounter"}, handler: handlerFunc(v2rPortPfcCounterStats), }, { // new virtual path for Port Base Counters - path: []string{"SONiC_DB", "Interfaces", "Port", "BaseCounter"}, + path: []string{"SONIC_DB", "Interfaces", "Port", "BaseCounter"}, handler: handlerFunc(v2rPortBaseCounterStats), }, } diff --git a/virtual_database_client/path.go b/virtual_database_client/path.go index d2750f66f..6e9396e33 100644 --- a/virtual_database_client/path.go +++ b/virtual_database_client/path.go @@ -119,7 +119,6 @@ func tableData2Msi(tblPath *tablePath, msi *map[string]interface{}) error { return err } - log.V(5).Infof("val: %v\n", val) patterns := tblPath.patterns for field, value := range val { for _, pattern := range patterns { From d33fca6ace83eed79bd09f2905ab8114ac590d6c Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Fri, 17 May 2019 05:33:12 +0000 Subject: [PATCH 17/20] Removed dead code. --- sonic_data_client/db_client.go | 5 ----- virtual_database_client/handler_pfcwd.go | 1 - virtual_database_client/handler_queue_counter.go | 1 - virtual_database_client/map_init.go | 1 - virtual_database_client/path.go | 13 ------------- 5 files changed, 21 deletions(-) diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index 10a0a4eef..c75c8d2db 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -532,11 +532,6 @@ func makeJSON_redis(msi *map[string]interface{}, key *string, op *string, mfv ma (*msi)[*key] = of } - // Debug log - //log.V(5).Infof("msi: %v\n", msi) - //log.V(5).Infof("key: %v\n", key) - //log.V(5).Infof("op: %v\n", op) - //log.V(5).Infof("fv: %v\n", mfv) return nil } diff --git a/virtual_database_client/handler_pfcwd.go b/virtual_database_client/handler_pfcwd.go index 07341dbf4..60b08ccb6 100644 --- a/virtual_database_client/handler_pfcwd.go +++ b/virtual_database_client/handler_pfcwd.go @@ -181,7 +181,6 @@ func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl } // Alias translation - //stringSlice := strings.Split(queName, separator) if !strings.HasPrefix(queName, "Queue") { return fmt.Errorf("%v not a vaild queue name. Use format 'Queue'", queName) } diff --git a/virtual_database_client/handler_queue_counter.go b/virtual_database_client/handler_queue_counter.go index ff102c7ae..dd14ae9df 100644 --- a/virtual_database_client/handler_queue_counter.go +++ b/virtual_database_client/handler_queue_counter.go @@ -125,7 +125,6 @@ func pop_PortQueueCounterStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]ta } // Alias translation - //stringSlice := strings.Split(queName, separator) if !strings.HasPrefix(queName, "Queue") { return fmt.Errorf("%v not a vaild queue name in request. Use format 'Queue'", queName) } diff --git a/virtual_database_client/map_init.go b/virtual_database_client/map_init.go index 52d69d327..cb98facfa 100644 --- a/virtual_database_client/map_init.go +++ b/virtual_database_client/map_init.go @@ -12,7 +12,6 @@ var ( countersPortNameMap = make(map[string]string) // Queue name to oid map in COUNTERS table of COUNTERS_DB - //countersQueueNameMap = make(map[string]string) countersQueueNameMap = make(map[string]map[string]string) // Alias translation: from vendor port name to sonic interface name diff --git a/virtual_database_client/path.go b/virtual_database_client/path.go index 6e9396e33..3ab23a9b8 100644 --- a/virtual_database_client/path.go +++ b/virtual_database_client/path.go @@ -42,12 +42,6 @@ func populateAlltablePaths(prefix *gnmipb.Path, paths []*gnmipb.Path, pathG2S *m // root-to-leaf virtual paths in the vpath tree. // Then map each vpath to a list of redis DB path. func populateNewtablePath(prefix, path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { - //fullPath := path - //if prefix != nil { - // fullPath = gnmiFullPath(prefix, path) - //} - //fmt.Printf("fullPath: %v\n", fullPath) - target := prefix.GetTarget() stringSlice := []string{target} elems := path.GetElem() @@ -60,13 +54,6 @@ func populateNewtablePath(prefix, path *gnmipb.Path, pathG2S *map[*gnmipb.Path][ return err } - // Debug - //for k, v := range (*pathG2S) { - // fmt.Printf("gNMI path: %v\n", k) - // for _, tblPath := range v{ - // fmt.Printf("new tablePath: %v\n", tblPath) - // } - //} return nil } From 9f943243948d26149143dc101b4c899457b27c5b Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Fri, 17 May 2019 05:39:34 +0000 Subject: [PATCH 18/20] Remove more dead code. --- dialout/dialout_client/dialout_client.go | 3 --- sonic_data_client/db_client.go | 1 - virtual_database_client/handler_pfcwd.go | 1 - 3 files changed, 5 deletions(-) diff --git a/dialout/dialout_client/dialout_client.go b/dialout/dialout_client/dialout_client.go index 22f8535a6..5ab5964d7 100644 --- a/dialout/dialout_client/dialout_client.go +++ b/dialout/dialout_client/dialout_client.go @@ -1,14 +1,12 @@ package telemetry_dialout import ( - // "encoding/json" "crypto/tls" "errors" "fmt" spb "github.com/Azure/sonic-telemetry/proto" - //sdc "github.com/Azure/sonic-telemetry/sonic_data_client" "net" sdc "github.com/Azure/sonic-telemetry/sonic_data_client" @@ -21,7 +19,6 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" - //"reflect" "strconv" "strings" "sync" diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index c75c8d2db..aab71d2b0 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -537,7 +537,6 @@ func makeJSON_redis(msi *map[string]interface{}, key *string, op *string, mfv ma // emitJSON marshalls map[string]interface{} to JSON byte stream. func emitJSON(v *map[string]interface{}) ([]byte, error) { - //j, err := json.MarshalIndent(*v, "", indentString) j, err := json.Marshal(*v) if err != nil { return nil, fmt.Errorf("JSON marshalling error: %v", err) diff --git a/virtual_database_client/handler_pfcwd.go b/virtual_database_client/handler_pfcwd.go index 60b08ccb6..1b6f1d579 100644 --- a/virtual_database_client/handler_pfcwd.go +++ b/virtual_database_client/handler_pfcwd.go @@ -102,7 +102,6 @@ func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]table updatePath(path, &tmpl, parentConfig, leaf, &targetFields) // Populate tablePaths - //fmt.Printf("path passed in populate: %v\n", &tmpl) err := pop_PortQueuePfcwdStats(&tmpl, pathG2S, targetFields) if err != nil { return err From 6f2b22037df912d01fdd4ffdb53cb340d054323b Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Fri, 17 May 2019 21:23:33 +0000 Subject: [PATCH 19/20] sdc to vdc (use correct path for setting TCP redis settings) --- virtual_database_client/db_client_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/virtual_database_client/db_client_test.go b/virtual_database_client/db_client_test.go index 08176dd45..3d3ff4ec3 100644 --- a/virtual_database_client/db_client_test.go +++ b/virtual_database_client/db_client_test.go @@ -14,7 +14,7 @@ import ( "testing" "time" - sdc "github.com/Azure/sonic-telemetry/sonic_data_client" + vdc "github.com/Azure/sonic-telemetry/virtual_database_client" "github.com/kylelemons/godebug/pretty" gnmi "github.com/Azure/sonic-telemetry/gnmi_server" @@ -811,5 +811,5 @@ func TestVirtualDatabaseGNMISubscribe(t *testing.T) { func init() { // Inform gNMI server to use redis tcp localhost connection - sdc.UseRedisLocalTcpPort = true + vdc.UseRedisLocalTcpPort = true } From 53c0e702f23807dbf1069b10a778d427ddf44c96 Mon Sep 17 00:00:00 2001 From: Randy Gaul Date: Fri, 17 May 2019 21:38:13 +0000 Subject: [PATCH 20/20] Remove dead code from sonic_data_client. --- sonic_data_client/db_client.go | 5 ----- virtual_database_client/handler_pfcwd.go | 3 --- 2 files changed, 8 deletions(-) diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index aab71d2b0..e39af5c23 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -506,11 +506,6 @@ func makeJSON_redis(msi *map[string]interface{}, key *string, op *string, mfv ma for f, v := range mfv { (*msi)[f] = v } - // Debug log - //log.V(5).Infof("msi: %v\n", msi) - //log.V(5).Infof("key: %v\n", key) - //log.V(5).Infof("op: %v\n", op) - //log.V(5).Infof("fv: %v\n", mfv) return nil } diff --git a/virtual_database_client/handler_pfcwd.go b/virtual_database_client/handler_pfcwd.go index 1b6f1d579..ea772c2c4 100644 --- a/virtual_database_client/handler_pfcwd.go +++ b/virtual_database_client/handler_pfcwd.go @@ -89,7 +89,6 @@ func GetTmpl_PortQueuePfcwdStats(path *gnmipb.Path) { func v2rPortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tablePath) error { var tmpl = gnmipb.Path{} GetTmpl_PortQueuePfcwdStats(&tmpl) - //fmt.Printf("tmpl: %v\n", &tmpl) parentConfig := map[int]string{1: "Port", 2: "Queue"} @@ -245,8 +244,6 @@ func pop_PortQueuePfcwdStats(path *gnmipb.Path, pathG2S *map[*gnmipb.Path][]tabl out_tblPaths = append(out_tblPaths, tblPath_port) } - //fmt.Printf("tablePath: %v\n", &tblPath_que) - //fmt.Printf("tablePath: %v\n", &tblPath_port) if len(out_tblPaths) > 0 { (*pathG2S)[path] = out_tblPaths }