Skip to content

Commit ae72767

Browse files
authored
Add gnmi_dump tool for debug and unit test (#60)
Why I did it Add tool for debug and unit test. How I did it Use share memory to support counters. Move check for EnableTranslibWrite to beginning of Set(). This change will simplify the logic for gnmi set fail, and no need to authenticate when EnableTranslibWrite is false. How to verify it Build image and run unit test.
1 parent 8226e46 commit ae72767

File tree

6 files changed

+282
-13
lines changed

6 files changed

+282
-13
lines changed

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,15 @@ ifeq ($(CROSS_BUILD_ENVIRON),y)
5757
$(GO) build -o ${GOBIN}/gnmi_set -mod=vendor github.com/jipanyang/gnxi/gnmi_set
5858
$(GO) build -o ${GOBIN}/gnmi_cli -mod=vendor github.com/openconfig/gnmi/cmd/gnmi_cli
5959
$(GO) build -o ${GOBIN}/gnoi_client -mod=vendor github.com/sonic-net/sonic-gnmi/gnoi_client
60+
$(GO) build -o ${GOBIN}/gnmi_dump -mod=vendor github.com/sonic-net/sonic-gnmi/gnmi_dump
6061
else
6162
$(GO) install -mod=vendor $(BLD_FLAGS) github.com/sonic-net/sonic-gnmi/telemetry
6263
$(GO) install -mod=vendor $(BLD_FLAGS) github.com/sonic-net/sonic-gnmi/dialout/dialout_client_cli
6364
$(GO) install -mod=vendor github.com/jipanyang/gnxi/gnmi_get
6465
$(GO) install -mod=vendor github.com/jipanyang/gnxi/gnmi_set
6566
$(GO) install -mod=vendor github.com/openconfig/gnmi/cmd/gnmi_cli
6667
$(GO) install -mod=vendor github.com/sonic-net/sonic-gnmi/gnoi_client
68+
$(GO) install -mod=vendor github.com/sonic-net/sonic-gnmi/gnmi_dump
6769
endif
6870

6971
check_gotest:
@@ -99,6 +101,7 @@ install:
99101
$(INSTALL) -D $(BUILD_DIR)/gnmi_set $(DESTDIR)/usr/sbin/gnmi_set
100102
$(INSTALL) -D $(BUILD_DIR)/gnmi_cli $(DESTDIR)/usr/sbin/gnmi_cli
101103
$(INSTALL) -D $(BUILD_DIR)/gnoi_client $(DESTDIR)/usr/sbin/gnoi_client
104+
$(INSTALL) -D $(BUILD_DIR)/gnmi_dump $(DESTDIR)/usr/sbin/gnmi_dump
102105

103106

104107
deinstall:
@@ -107,5 +110,6 @@ deinstall:
107110
rm $(DESTDIR)/usr/sbin/gnmi_get
108111
rm $(DESTDIR)/usr/sbin/gnmi_set
109112
rm $(DESTDIR)/usr/sbin/gnoi_client
113+
rm $(DESTDIR)/usr/sbin/gnmi_dump
110114

111115

common_utils/context.go

+42-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,33 @@ const requestContextKey contextkey = 0
3636
// Request Id generator
3737
var requestCounter uint64
3838

39+
type CounterType int
40+
const (
41+
GNMI_GET CounterType = iota
42+
GNMI_GET_FAIL
43+
GNMI_SET
44+
GNMI_SET_FAIL
45+
COUNTER_SIZE
46+
)
47+
48+
func (c CounterType) String() string {
49+
switch c {
50+
case GNMI_GET:
51+
return "GNMI get"
52+
case GNMI_GET_FAIL:
53+
return "GNMI get fail"
54+
case GNMI_SET:
55+
return "GNMI set"
56+
case GNMI_SET_FAIL:
57+
return "GNMI set fail"
58+
default:
59+
return ""
60+
}
61+
}
62+
63+
var globalCounters [COUNTER_SIZE]uint64
64+
65+
3966
// GetContext function returns the RequestContext object for a
4067
// gRPC request. RequestContext is maintained as a context value of
4168
// the request. Creates a new RequestContext object is not already
@@ -55,8 +82,20 @@ func GetContext(ctx context.Context) (*RequestContext, context.Context) {
5582

5683
func GetUsername(ctx context.Context, username *string) {
5784
rc, _ := GetContext(ctx)
58-
if rc != nil {
59-
*username = rc.Auth.User
60-
}
85+
if rc != nil {
86+
*username = rc.Auth.User
87+
}
88+
}
89+
90+
func InitCounters() {
91+
for i := 0; i < int(COUNTER_SIZE); i++ {
92+
globalCounters[i] = 0
93+
}
94+
SetMemCounters(&globalCounters)
95+
}
96+
97+
func IncCounter(cnt CounterType) {
98+
atomic.AddUint64(&globalCounters[cnt], 1)
99+
SetMemCounters(&globalCounters)
61100
}
62101

common_utils/shareMem.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package common_utils
2+
3+
import (
4+
"fmt"
5+
"syscall"
6+
"unsafe"
7+
)
8+
9+
// Use share memory to dump GNMI internal counters,
10+
// GNMI server and gnmi_dump should use memKey to access the share memory,
11+
// memSize is 1024 bytes, so we can support 128 counters
12+
// memMode is 0x380, this value is O_RDWR|IPC_CREAT,
13+
// O_RDWR means: Owner can write and read the file, everyone else can't.
14+
// IPC_CREAT means: Create a shared memory segment if a shared memory identifier does not exist for memKey.
15+
var (
16+
memKey = 7749
17+
memSize = 1024
18+
memMode = 0x380
19+
)
20+
21+
func SetMemCounters(counters *[int(COUNTER_SIZE)]uint64) error {
22+
shmid, _, err := syscall.Syscall(syscall.SYS_SHMGET, uintptr(memKey), uintptr(memSize), uintptr(memMode))
23+
if int(shmid) == -1 {
24+
return fmt.Errorf("syscall error, err: %v\n", err)
25+
}
26+
27+
shmaddr, _, err := syscall.Syscall(syscall.SYS_SHMAT, shmid, 0, 0)
28+
if int(shmaddr) == -1 {
29+
return fmt.Errorf("syscall error, err: %v\n", err)
30+
}
31+
defer syscall.Syscall(syscall.SYS_SHMDT, shmaddr, 0, 0)
32+
33+
const size = unsafe.Sizeof(uint64(0))
34+
addr := uintptr(unsafe.Pointer(shmaddr))
35+
36+
for i := 0; i < len(counters); i++ {
37+
*(*uint64)(unsafe.Pointer(addr)) = counters[i]
38+
addr += size
39+
}
40+
return nil
41+
}
42+
43+
func GetMemCounters(counters *[int(COUNTER_SIZE)]uint64) error {
44+
shmid, _, err := syscall.Syscall(syscall.SYS_SHMGET, uintptr(memKey), uintptr(memSize), uintptr(memMode))
45+
if int(shmid) == -1 {
46+
return fmt.Errorf("syscall error, err: %v\n", err)
47+
}
48+
49+
shmaddr, _, err := syscall.Syscall(syscall.SYS_SHMAT, shmid, 0, 0)
50+
if int(shmaddr) == -1 {
51+
return fmt.Errorf("syscall error, err: %v\n", err)
52+
}
53+
defer syscall.Syscall(syscall.SYS_SHMDT, shmaddr, 0, 0)
54+
55+
const size = unsafe.Sizeof(uint64(0))
56+
addr := uintptr(unsafe.Pointer(shmaddr))
57+
58+
for i := 0; i < len(counters); i++ {
59+
counters[i] = *(*uint64)(unsafe.Pointer(addr))
60+
addr += size
61+
}
62+
return nil
63+
}
64+

gnmi_dump/gnmi_dump.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"github.com/sonic-net/sonic-gnmi/common_utils"
7+
)
8+
9+
const help = `
10+
gnmi_dump is used to dump internal counters for debugging purpose,
11+
including GNMI request counter, GNOI request counter and DBUS request counter.
12+
`
13+
14+
func main() {
15+
flag.Usage = func() {
16+
fmt.Print(help)
17+
}
18+
flag.Parse()
19+
var counters [common_utils.COUNTER_SIZE]uint64
20+
err := common_utils.GetMemCounters(&counters)
21+
if err != nil {
22+
fmt.Printf("Error: Fail to read counters, %v", err)
23+
return
24+
}
25+
fmt.Printf("Dump GNMI counters\n")
26+
for i := 0; i < int(common_utils.COUNTER_SIZE); i++ {
27+
cnt := common_utils.CounterType(i)
28+
fmt.Printf("%v---%v\n", cnt.String(), counters[i])
29+
}
30+
}

gnmi_server/server.go

+19-5
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ func NewServer(config *Config, opts []grpc.ServerOption) (*Server, error) {
124124
return nil, errors.New("config not provided")
125125
}
126126

127+
common_utils.InitCounters()
128+
127129
s := grpc.NewServer(opts...)
128130
reflection.Register(s)
129131

@@ -274,26 +276,32 @@ func (s *Server) checkEncodingAndModel(encoding gnmipb.Encoding, models []*gnmip
274276

275277
// Get implements the Get RPC in gNMI spec.
276278
func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetResponse, error) {
279+
common_utils.IncCounter(common_utils.GNMI_GET)
277280
ctx, err := authenticate(s.config.UserAuth, ctx)
278281
if err != nil {
282+
common_utils.IncCounter(common_utils.GNMI_GET_FAIL)
279283
return nil, err
280284
}
281285

282286
if req.GetType() != gnmipb.GetRequest_ALL {
287+
common_utils.IncCounter(common_utils.GNMI_GET_FAIL)
283288
return nil, status.Errorf(codes.Unimplemented, "unsupported request type: %s", gnmipb.GetRequest_DataType_name[int32(req.GetType())])
284289
}
285290

286291
if err = s.checkEncodingAndModel(req.GetEncoding(), req.GetUseModels()); err != nil {
292+
common_utils.IncCounter(common_utils.GNMI_GET_FAIL)
287293
return nil, status.Error(codes.Unimplemented, err.Error())
288294
}
289295

290296
var target string
291297
prefix := req.GetPrefix()
292298
if prefix == nil {
299+
common_utils.IncCounter(common_utils.GNMI_GET_FAIL)
293300
return nil, status.Error(codes.Unimplemented, "No target specified in prefix")
294301
} else {
295302
target = prefix.GetTarget()
296303
if target == "" {
304+
common_utils.IncCounter(common_utils.GNMI_GET_FAIL)
297305
return nil, status.Error(codes.Unimplemented, "Empty target data not supported yet")
298306
}
299307
}
@@ -315,11 +323,13 @@ func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetRe
315323
}
316324

317325
if err != nil {
326+
common_utils.IncCounter(common_utils.GNMI_GET_FAIL)
318327
return nil, status.Error(codes.NotFound, err.Error())
319328
}
320329
notifications := make([]*gnmipb.Notification, len(paths))
321330
spbValues, err := dc.Get(nil)
322331
if err != nil {
332+
common_utils.IncCounter(common_utils.GNMI_GET_FAIL)
323333
return nil, status.Error(codes.NotFound, err.Error())
324334
}
325335

@@ -339,8 +349,14 @@ func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetRe
339349
}
340350

341351
func (s *Server) Set(ctx context.Context, req *gnmipb.SetRequest) (*gnmipb.SetResponse, error) {
352+
common_utils.IncCounter(common_utils.GNMI_SET)
353+
if s.config.EnableTranslibWrite == false {
354+
common_utils.IncCounter(common_utils.GNMI_SET_FAIL)
355+
return nil, grpc.Errorf(codes.Unimplemented, "GNMI is in read-only mode")
356+
}
342357
ctx, err := authenticate(s.config.UserAuth, ctx)
343358
if err != nil {
359+
common_utils.IncCounter(common_utils.GNMI_SET_FAIL)
344360
return nil, err
345361
}
346362
var results []*gnmipb.UpdateResult
@@ -388,13 +404,11 @@ func (s *Server) Set(ctx context.Context, req *gnmipb.SetRequest) (*gnmipb.SetRe
388404
/* Add to Set response results. */
389405
results = append(results, &res)
390406
}
391-
if s.config.EnableTranslibWrite {
392-
err = dc.Set(req.GetDelete(), req.GetReplace(), req.GetUpdate())
393-
} else {
394-
return nil, grpc.Errorf(codes.Unimplemented, "Telemetry is in read-only mode")
407+
err = dc.Set(req.GetDelete(), req.GetReplace(), req.GetUpdate())
408+
if err != nil {
409+
common_utils.IncCounter(common_utils.GNMI_SET_FAIL)
395410
}
396411

397-
398412
return &gnmipb.SetResponse{
399413
Prefix: req.GetPrefix(),
400414
Response: results,

0 commit comments

Comments
 (0)