Skip to content

Commit 0a1e1f3

Browse files
committed
ndndpdk-godemo: NFD prefix registration utility
1 parent 7c76c32 commit 0a1e1f3

19 files changed

+613
-135
lines changed

cmd/ndndpdk-godemo/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,10 @@ ndndpdk-godemo --mtu 6000 put --name /segmented/1GB.bin --file /tmp/1GB.bin --ch
7373
# (on another console) run consumer and compute downloaded digest
7474
ndndpdk-godemo --mtu 6000 get --name /segmented/1GB.bin | openssl sha256
7575
```
76+
77+
## NFD Management API
78+
79+
[nfdreg.go](nfdreg.go) implements a prefix registration tool using [NFD management API](../../ndn/mgmt/nfdmgmt).
80+
This subcommand requires a local NDN-DPDK forwarder that connects to either local or remote NFD forwarder.
81+
It sends prefix registration commands to NFD so that Interests come to NDN-DPDK.
82+
See [NFD interop](../../docs/interop/NFD.md) for a usage example.

cmd/ndndpdk-godemo/dump.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func init() {
5555

5656
for {
5757
select {
58-
case <-interrupt:
58+
case <-c.Context.Done():
5959
return nil
6060
case packet := <-f.Rx():
6161
log.Println(packet)

cmd/ndndpdk-godemo/main.go

+16-14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
package main
33

44
import (
5+
"context"
56
"io"
67
"log"
78
"math/rand"
@@ -28,10 +29,9 @@ var (
2829
useNfd bool
2930
enableLog bool
3031

31-
interrupt = make(chan os.Signal, 1)
32-
client mgmt.Client
33-
face mgmt.Face
34-
fwFace l3.FwFace
32+
client mgmt.Client
33+
face mgmt.Face
34+
fwFace l3.FwFace
3535
)
3636

3737
func openUplink(c *cli.Context) (e error) {
@@ -62,13 +62,6 @@ func openUplink(c *cli.Context) (e error) {
6262
return nil
6363
}
6464

65-
func onInterrupt(cb func()) {
66-
go func() {
67-
<-interrupt
68-
cb()
69-
}()
70-
}
71-
7265
var app = &cli.App{
7366
Version: version.V.String(),
7467
Usage: "NDNgo library demo.",
@@ -87,7 +80,7 @@ var app = &cli.App{
8780
},
8881
&cli.BoolFlag{
8982
Name: "nfd",
90-
Usage: "connect to NFD or YaNFD (set FaceUri in NDN_CLIENT_TRANSPORT environment variable)",
83+
Usage: "connect to NFD or YaNFD instead of NDN-DPDK (set FaceUri in NDN_CLIENT_TRANSPORT environment variable)",
9184
Destination: &useNfd,
9285
},
9386
&cli.BoolFlag{
@@ -101,7 +94,6 @@ var app = &cli.App{
10194
if !enableLog {
10295
log.SetOutput(io.Discard)
10396
}
104-
signal.Notify(interrupt, syscall.SIGINT)
10597
if useNfd {
10698
client, e = nfdmgmt.New()
10799
} else {
@@ -124,7 +116,17 @@ func defineCommand(command *cli.Command) {
124116
func main() {
125117
rand.Seed(time.Now().UnixNano())
126118
sort.Sort(cli.CommandsByName(app.Commands))
127-
e := app.Run(os.Args)
119+
120+
ctx, cancel := context.WithCancel(context.Background())
121+
defer cancel()
122+
interrupt := make(chan os.Signal, 1)
123+
signal.Notify(interrupt, syscall.SIGINT)
124+
go func() {
125+
<-interrupt
126+
cancel()
127+
}()
128+
129+
e := app.RunContext(ctx, os.Args)
128130
if e != nil {
129131
log.Fatal(e)
130132
}

cmd/ndndpdk-godemo/nfdreg.go

+268
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/base64"
7+
"encoding/json"
8+
"errors"
9+
"fmt"
10+
"log"
11+
"os"
12+
"strings"
13+
"time"
14+
15+
"github.com/urfave/cli/v2"
16+
"github.com/usnistgov/ndn-dpdk/core/jsonhelper"
17+
"github.com/usnistgov/ndn-dpdk/ndn"
18+
"github.com/usnistgov/ndn-dpdk/ndn/endpoint"
19+
"github.com/usnistgov/ndn-dpdk/ndn/keychain"
20+
"github.com/usnistgov/ndn-dpdk/ndn/mgmt/nfdmgmt"
21+
"github.com/usnistgov/ndn-dpdk/ndn/tlv"
22+
)
23+
24+
type nfdReg struct {
25+
Client *nfdmgmt.Client
26+
ServedCerts []ndn.Data
27+
DefaultOrigin int
28+
DefaultCost int
29+
Commands []nfdmgmt.ControlCommand
30+
CommandsDesc []string
31+
Interval time.Duration
32+
Repeat time.Duration
33+
}
34+
35+
func (cmd *nfdReg) readBase64File(filename string) (wire []byte, e error) {
36+
b64, e := os.ReadFile(filename)
37+
if e != nil {
38+
return nil, e
39+
}
40+
41+
wire = make([]byte, base64.StdEncoding.DecodedLen(len(b64)))
42+
n, e := base64.StdEncoding.Decode(wire, b64)
43+
if e != nil {
44+
return nil, e
45+
}
46+
return wire[:n], nil
47+
}
48+
49+
func (cmd *nfdReg) SetSigner(safeBagFile, safeBagPassphrase string) error {
50+
if safeBagFile == "" {
51+
return nil
52+
}
53+
54+
wire, e := cmd.readBase64File(safeBagFile)
55+
if e != nil {
56+
return e
57+
}
58+
59+
pvt, cert, e := keychain.ImportSafeBag(wire, []byte(safeBagPassphrase))
60+
if e != nil {
61+
return e
62+
}
63+
64+
cmd.Client.Signer = pvt.WithKeyLocator(cert.Name())
65+
cmd.ServedCerts = append(cmd.ServedCerts, cert.Data())
66+
return nil
67+
}
68+
69+
func (cmd *nfdReg) AddCert(certFile string) error {
70+
wire, e := cmd.readBase64File(certFile)
71+
if e != nil {
72+
return e
73+
}
74+
75+
var pkt ndn.Packet
76+
if e := tlv.Decode(wire, &pkt); e != nil {
77+
return e
78+
}
79+
80+
if pkt.Data == nil {
81+
return errors.New("not a Data")
82+
}
83+
84+
cmd.ServedCerts = append(cmd.ServedCerts, *pkt.Data)
85+
return nil
86+
}
87+
88+
func (cmd *nfdReg) AddRegisterCommand(p string) (e error) {
89+
var c nfdmgmt.RibRegisterCommand
90+
if strings.HasPrefix(p, "/") {
91+
e = jsonhelper.Roundtrip(map[string]any{
92+
"name": p,
93+
"origin": cmd.DefaultOrigin,
94+
"cost": cmd.DefaultCost,
95+
"noInherit": true,
96+
"capture": true,
97+
}, &c)
98+
} else {
99+
e = json.Unmarshal([]byte(p), &c)
100+
}
101+
if e != nil {
102+
return e
103+
}
104+
105+
cmd.addCommand(c)
106+
return nil
107+
}
108+
109+
func (cmd *nfdReg) AddUnregisterCommand(p string) (e error) {
110+
var c nfdmgmt.RibUnregisterCommand
111+
if strings.HasPrefix(p, "/") {
112+
e = jsonhelper.Roundtrip(map[string]any{
113+
"name": p,
114+
"origin": cmd.DefaultOrigin,
115+
"cost": cmd.DefaultCost,
116+
}, &c)
117+
} else {
118+
e = json.Unmarshal([]byte(p), &c)
119+
}
120+
if e != nil {
121+
return e
122+
}
123+
124+
cmd.addCommand(c)
125+
return nil
126+
}
127+
128+
func (cmd *nfdReg) addCommand(c nfdmgmt.ControlCommand) {
129+
cmd.Commands = append(cmd.Commands, c)
130+
131+
var b bytes.Buffer
132+
fmt.Fprintf(&b, "%T ", c)
133+
json.NewEncoder(&b).Encode(c)
134+
cmd.CommandsDesc = append(cmd.CommandsDesc, string(bytes.TrimRight(b.Bytes(), "\n")))
135+
}
136+
137+
func (cmd *nfdReg) StartServeCerts(ctx context.Context) {
138+
for _, cert := range cmd.ServedCerts {
139+
cert := cert
140+
endpoint.Produce(ctx, endpoint.ProducerOptions{
141+
Prefix: keychain.ToKeyName(cert.Name),
142+
Handler: func(ctx context.Context, interest ndn.Interest) (ndn.Data, error) { return cert, nil },
143+
})
144+
}
145+
}
146+
147+
func (cmd *nfdReg) SendCommands(ctx context.Context) {
148+
for i, command := range cmd.Commands {
149+
cr, e := cmd.Client.Invoke(ctx, command)
150+
if e != nil {
151+
log.Printf("%v %s", e, cmd.CommandsDesc[i])
152+
} else {
153+
log.Printf("%d %s", cr.StatusCode, cmd.CommandsDesc[i])
154+
}
155+
time.Sleep(cmd.Interval)
156+
}
157+
}
158+
159+
func init() {
160+
var commandPrefixURI, safeBagFile, safeBagPassphrase string
161+
var serveCertSlice, registerSlice, unregisterSlice cli.StringSlice
162+
var cmd nfdReg
163+
164+
defineCommand(&cli.Command{
165+
Name: "nfdreg",
166+
Usage: "Register a prefix on NFD uplink.",
167+
Flags: []cli.Flag{
168+
&cli.StringFlag{
169+
Name: "command",
170+
Usage: "NFD command prefix.",
171+
Value: nfdmgmt.PrefixLocalhop.String(),
172+
Destination: &commandPrefixURI,
173+
},
174+
&cli.StringFlag{
175+
Name: "signer",
176+
Usage: "Signer key SafeBag file.",
177+
Destination: &safeBagFile,
178+
},
179+
&cli.StringFlag{
180+
Name: "signer-pass",
181+
Usage: "Signer key SafeBag passphrase.",
182+
Destination: &safeBagPassphrase,
183+
},
184+
&cli.StringSliceFlag{
185+
Name: "serve-cert",
186+
Usage: "Serve certificate(s).",
187+
Destination: &serveCertSlice,
188+
},
189+
&cli.IntFlag{
190+
Name: "origin",
191+
Usage: "Route origin, for prefix(es) not specified as JSON.",
192+
Value: nfdmgmt.RouteOriginClient,
193+
Destination: &cmd.DefaultOrigin,
194+
},
195+
&cli.IntFlag{
196+
Name: "cost",
197+
Usage: "Route cost, for prefix(es) not specified as JSON.",
198+
Value: 0,
199+
Destination: &cmd.DefaultCost,
200+
},
201+
&cli.StringSliceFlag{
202+
Name: "register",
203+
Usage: "Register prefix(es).",
204+
Destination: &registerSlice,
205+
},
206+
&cli.StringSliceFlag{
207+
Name: "unregister",
208+
Usage: "Unregister prefix(es).",
209+
Destination: &unregisterSlice,
210+
},
211+
&cli.DurationFlag{
212+
Name: "interval",
213+
Usage: "Interval between commands.",
214+
Value: 1 * time.Second,
215+
Destination: &cmd.Interval,
216+
},
217+
&cli.DurationFlag{
218+
Name: "repeat",
219+
Usage: "Repeat process after this duration. If zero, run once and exit.",
220+
Destination: &cmd.Repeat,
221+
},
222+
},
223+
Before: func(c *cli.Context) error {
224+
client, e := nfdmgmt.New()
225+
if e != nil {
226+
return e
227+
}
228+
cmd.Client = client
229+
cmd.Client.Prefix = ndn.ParseName(commandPrefixURI)
230+
231+
if e := cmd.SetSigner(safeBagFile, safeBagPassphrase); e != nil {
232+
return fmt.Errorf("import signer SafeBag: %w", e)
233+
}
234+
for i, certFile := range serveCertSlice.Value() {
235+
if e := cmd.AddCert(certFile); e != nil {
236+
return fmt.Errorf("add cert %d: %w", i, e)
237+
}
238+
}
239+
240+
for i, p := range unregisterSlice.Value() {
241+
if e := cmd.AddUnregisterCommand(p); e != nil {
242+
return fmt.Errorf("unregister command %d: %w", i, e)
243+
}
244+
}
245+
for i, p := range registerSlice.Value() {
246+
if e := cmd.AddRegisterCommand(p); e != nil {
247+
return fmt.Errorf("register command %d: %w", i, e)
248+
}
249+
}
250+
251+
return openUplink(c)
252+
},
253+
Action: func(c *cli.Context) error {
254+
cmd.StartServeCerts(c.Context)
255+
for {
256+
cmd.SendCommands(c.Context)
257+
if cmd.Repeat <= 0 {
258+
return nil
259+
}
260+
select {
261+
case <-c.Context.Done():
262+
return c.Context.Err()
263+
case <-time.After(cmd.Repeat):
264+
}
265+
}
266+
},
267+
})
268+
}

cmd/ndndpdk-godemo/ping.go

+3-6
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,7 @@ func init() {
5353
signer = ndn.DigestSigning
5454
}
5555

56-
ctx, cancel := context.WithCancel(context.Background())
57-
onInterrupt(cancel)
58-
59-
_, e := endpoint.Produce(ctx, endpoint.ProducerOptions{
56+
_, e := endpoint.Produce(c.Context, endpoint.ProducerOptions{
6057
Prefix: ndn.ParseName(name),
6158
NoAdvertise: !wantAdvertise,
6259
Handler: func(ctx context.Context, interest ndn.Interest) (ndn.Data, error) {
@@ -69,7 +66,7 @@ func init() {
6966
return e
7067
}
7168

72-
<-ctx.Done()
69+
<-c.Context.Done()
7370
return nil
7471
},
7572
})
@@ -123,7 +120,7 @@ func init() {
123120
var nData, nErrors atomic.Int64
124121
for {
125122
select {
126-
case <-interrupt:
123+
case <-c.Context.Done():
127124
return nil
128125
case timestamp := <-ticker.C:
129126
go func(t0 time.Time, s uint64) {

0 commit comments

Comments
 (0)