279589b5d415087d10cec63072878d0046a9e88a
[vpp.git] / extras / hs-test / actions.go
1 package main
2
3 import (
4         "bytes"
5         "context"
6         "fmt"
7         "os"
8         "path/filepath"
9
10         "git.fd.io/govpp.git/api"
11         "github.com/edwarnicke/exechelper"
12         "github.com/edwarnicke/govpp/binapi/af_packet"
13         "github.com/edwarnicke/govpp/binapi/ethernet_types"
14         interfaces "github.com/edwarnicke/govpp/binapi/interface"
15         "github.com/edwarnicke/govpp/binapi/interface_types"
16         ip_types "github.com/edwarnicke/govpp/binapi/ip_types"
17         "github.com/edwarnicke/govpp/binapi/session"
18         "github.com/edwarnicke/govpp/binapi/tapv2"
19         "github.com/edwarnicke/govpp/binapi/vlib"
20         "github.com/edwarnicke/vpphelper"
21 )
22
23 var (
24         workDir, _ = os.Getwd()
25 )
26
27 type ConfFn func(context.Context, api.Connection) error
28
29 type Actions struct {
30 }
31
32 func configureProxyTcp(ifName0, ipAddr0, ifName1, ipAddr1 string) ConfFn {
33         return func(ctx context.Context,
34                 vppConn api.Connection) error {
35
36                 _, err := configureAfPacket(ctx, vppConn, ifName0, ipAddr0)
37                 if err != nil {
38                         fmt.Printf("failed to create af packet: %v", err)
39                         return err
40                 }
41                 _, err = configureAfPacket(ctx, vppConn, ifName1, ipAddr1)
42                 if err != nil {
43                         fmt.Printf("failed to create af packet: %v", err)
44                         return err
45                 }
46                 return nil
47         }
48 }
49
50 func (a *Actions) RunHttpCliSrv(args []string) *ActionResult {
51         cmd := fmt.Sprintf("http cli server")
52         return ApiCliInband(workDir, cmd)
53 }
54
55 func (a *Actions) RunHttpCliCln(args []string) *ActionResult {
56         cmd := fmt.Sprintf("http cli client uri http://10.10.10.1/80 query %s", getArgs())
57         fmt.Println(cmd)
58         return ApiCliInband(workDir, cmd)
59 }
60
61 func (a *Actions) ConfigureVppProxy(args []string) *ActionResult {
62         ctx, cancel := newVppContext()
63         defer cancel()
64
65         con, vppErrCh := vpphelper.StartAndDialContext(ctx,
66                 vpphelper.WithVppConfig(configTemplate),
67                 vpphelper.WithRootDir(workDir))
68         exitOnErrCh(ctx, cancel, vppErrCh)
69
70         confFn := configureProxyTcp("vpp0", "10.0.0.2/24", "vpp1", "10.0.1.2/24")
71         err := confFn(ctx, con)
72         if err != nil {
73                 return NewActionResult(err, ActionResultWithDesc("configuration failed"))
74         }
75         writeSyncFile(OkResult())
76         <-ctx.Done()
77         return nil
78 }
79
80 func (a *Actions) ConfigureEnvoyProxy(args []string) *ActionResult {
81         var startup Stanza
82         startup.
83                 NewStanza("session").
84                 Append("enable").
85                 Append("use-app-socket-api").
86                 Append("evt_qs_memfd_seg").
87                 Append("event-queue-length 100000").Close()
88         ctx, cancel := newVppContext()
89         defer cancel()
90
91         con, vppErrCh := vpphelper.StartAndDialContext(ctx,
92                 vpphelper.WithVppConfig(configTemplate+startup.ToString()),
93                 vpphelper.WithRootDir(workDir))
94         exitOnErrCh(ctx, cancel, vppErrCh)
95
96         confFn := configureProxyTcp("vpp0", "10.0.0.2/24", "vpp1", "10.0.1.2/24")
97         err := confFn(ctx, con)
98         if err != nil {
99                 return NewActionResult(err, ActionResultWithDesc("configuration failed"))
100         }
101         err0 := exechelper.Run("chmod 777 -R " + workDir)
102         if err0 != nil {
103                 return NewActionResult(err, ActionResultWithDesc("setting permissions failed"))
104         }
105         writeSyncFile(OkResult())
106         <-ctx.Done()
107         return nil
108 }
109
110 func getArgs() string {
111         s := ""
112         for i := 2; i < len(os.Args); i++ {
113                 s = s + " " + os.Args[i]
114         }
115         return s
116 }
117
118 func ApiCliInband(root, cmd string) *ActionResult {
119         ctx, _ := newVppContext()
120         con := vpphelper.DialContext(ctx, filepath.Join(root, "/var/run/vpp/api.sock"))
121         cliInband := vlib.CliInband{Cmd: cmd}
122         cliInbandReply, err := vlib.NewServiceClient(con).CliInband(ctx, &cliInband)
123         return NewActionResult(err, ActionResultWithStdout(cliInbandReply.Reply))
124 }
125
126 func (a *Actions) RunEchoClient(args []string) *ActionResult {
127         outBuff := bytes.NewBuffer([]byte{})
128         errBuff := bytes.NewBuffer([]byte{})
129
130         cmd := fmt.Sprintf("vpp_echo client socket-name %s/var/run/app_ns_sockets/2 use-app-socket-api uri %s://10.10.10.1/12344", workDir, args[2])
131         err := exechelper.Run(cmd,
132                 exechelper.WithStdout(outBuff), exechelper.WithStderr(errBuff),
133                 exechelper.WithStdout(os.Stdout), exechelper.WithStderr(os.Stderr))
134
135         return NewActionResult(err, ActionResultWithStdout(string(outBuff.String())),
136                 ActionResultWithStderr(string(errBuff.String())))
137 }
138
139 func (a *Actions) RunEchoServer(args []string) *ActionResult {
140         cmd := fmt.Sprintf("vpp_echo server TX=RX socket-name %s/var/run/app_ns_sockets/1 use-app-socket-api uri %s://10.10.10.1/12344", workDir, args[2])
141         errCh := exechelper.Start(cmd)
142         select {
143         case err := <-errCh:
144                 writeSyncFile(NewActionResult(err, ActionResultWithDesc("echo_server: ")))
145         default:
146         }
147         writeSyncFile(OkResult())
148         return nil
149 }
150
151 func (a *Actions) RunEchoSrvInternal(args []string) *ActionResult {
152         cmd := fmt.Sprintf("test echo server %s uri tcp://10.10.10.1/1234", getArgs())
153         return ApiCliInband(workDir, cmd)
154 }
155
156 func (a *Actions) RunEchoClnInternal(args []string) *ActionResult {
157         cmd := fmt.Sprintf("test echo client %s uri tcp://10.10.10.1/1234", getArgs())
158         return ApiCliInband(workDir, cmd)
159 }
160
161 func (a *Actions) RunVclEchoServer(args []string) *ActionResult {
162         f, err := os.Create("vcl_1.conf")
163         if err != nil {
164                 return NewActionResult(err, ActionResultWithStderr(("create vcl config: ")))
165         }
166         socketPath := fmt.Sprintf("%s/var/run/app_ns_sockets/1", workDir)
167         fmt.Fprintf(f, vclTemplate, socketPath, "1")
168         f.Close()
169
170         os.Setenv("VCL_CONFIG", "./vcl_1.conf")
171         cmd := fmt.Sprintf("vcl_test_server -p %s 12346", args[2])
172         errCh := exechelper.Start(cmd)
173         select {
174         case err := <-errCh:
175                 writeSyncFile(NewActionResult(err, ActionResultWithDesc("vcl_test_server: ")))
176         default:
177         }
178         writeSyncFile(OkResult())
179         return nil
180 }
181
182 func (a *Actions) RunVclEchoClient(args []string) *ActionResult {
183         outBuff := bytes.NewBuffer([]byte{})
184         errBuff := bytes.NewBuffer([]byte{})
185
186         f, err := os.Create("vcl_2.conf")
187         if err != nil {
188                 return NewActionResult(err, ActionResultWithStderr(("create vcl config: ")))
189         }
190         socketPath := fmt.Sprintf("%s/var/run/app_ns_sockets/2", workDir)
191         fmt.Fprintf(f, vclTemplate, socketPath, "2")
192         f.Close()
193
194         os.Setenv("VCL_CONFIG", "./vcl_2.conf")
195         cmd := fmt.Sprintf("vcl_test_client -U -p %s 10.10.10.1 12346", args[2])
196         err = exechelper.Run(cmd,
197                 exechelper.WithStdout(outBuff), exechelper.WithStderr(errBuff),
198                 exechelper.WithStdout(os.Stdout), exechelper.WithStderr(os.Stderr))
199
200         return NewActionResult(err, ActionResultWithStdout(string(outBuff.String())),
201                 ActionResultWithStderr(string(errBuff.String())))
202 }
203
204 func configure2vethsTopo(ifName, interfaceAddress, namespaceId string, secret uint64, optionalHardwareAddress ...string) ConfFn {
205         return func(ctx context.Context,
206                 vppConn api.Connection) error {
207
208                 var swIfIndex interface_types.InterfaceIndex
209                 var err error
210                 if optionalHardwareAddress == nil {
211                         swIfIndex, err = configureAfPacket(ctx, vppConn, ifName, interfaceAddress)
212                 } else {
213                         swIfIndex, err = configureAfPacket(ctx, vppConn, ifName, interfaceAddress, optionalHardwareAddress[0])
214                 }
215                 if err != nil {
216                         fmt.Printf("failed to create af packet: %v", err)
217                 }
218                 _, er := session.NewServiceClient(vppConn).AppNamespaceAddDelV2(ctx, &session.AppNamespaceAddDelV2{
219                         Secret:      secret,
220                         SwIfIndex:   swIfIndex,
221                         NamespaceID: namespaceId,
222                 })
223                 if er != nil {
224                         fmt.Printf("add app namespace: %v", err)
225                         return err
226                 }
227
228                 _, er1 := session.NewServiceClient(vppConn).SessionEnableDisable(ctx, &session.SessionEnableDisable{
229                         IsEnable: true,
230                 })
231                 if er1 != nil {
232                         fmt.Printf("session enable %v", err)
233                         return err
234                 }
235                 return nil
236         }
237 }
238
239 func (a *Actions) Configure2Veths(args []string) *ActionResult {
240         var startup Stanza
241         startup.
242                 NewStanza("session").
243                 Append("enable").
244                 Append("use-app-socket-api").Close()
245
246         ctx, cancel := newVppContext()
247         defer cancel()
248
249         vppConfig, err := deserializeVppConfig(args[2])
250         if err != nil {
251                 return NewActionResult(err, ActionResultWithDesc("deserializing configuration failed"))
252         }
253
254         con, vppErrCh := vpphelper.StartAndDialContext(ctx,
255                 vpphelper.WithVppConfig(vppConfig.getTemplate()+startup.ToString()),
256                 vpphelper.WithRootDir(workDir))
257         exitOnErrCh(ctx, cancel, vppErrCh)
258
259         var fn func(context.Context, api.Connection) error
260         switch vppConfig.Variant {
261         case "srv":
262                 fn = configure2vethsTopo("vppsrv", "10.10.10.1/24", "1", 1)
263         case "srv-with-preset-hw-addr":
264                 fn = configure2vethsTopo("vppsrv", "10.10.10.1/24", "1", 1, "00:00:5e:00:53:01")
265         case "cln":
266                 fallthrough
267         default:
268                 fn = configure2vethsTopo("vppcln", "10.10.10.2/24", "2", 2)
269         }
270         err = fn(ctx, con)
271         if err != nil {
272                 return NewActionResult(err, ActionResultWithDesc("configuration failed"))
273         }
274         writeSyncFile(OkResult())
275         <-ctx.Done()
276         return nil
277 }
278
279 func configureAfPacket(ctx context.Context, vppCon api.Connection,
280         name, interfaceAddress string, optionalHardwareAddress ...string) (interface_types.InterfaceIndex, error) {
281         var err error
282         ifaceClient := interfaces.NewServiceClient(vppCon)
283         afPacketCreate := af_packet.AfPacketCreateV2{
284                 UseRandomHwAddr: true,
285                 HostIfName:      name,
286                 NumRxQueues:     1,
287         }
288         if len(optionalHardwareAddress) > 0 {
289                 afPacketCreate.HwAddr, err = ethernet_types.ParseMacAddress(optionalHardwareAddress[0])
290                 if err != nil {
291                         fmt.Printf("failed to parse mac address: %v", err)
292                         return 0, err
293                 }
294                 afPacketCreate.UseRandomHwAddr = false
295         }
296         afPacketCreateRsp, err := af_packet.NewServiceClient(vppCon).AfPacketCreateV2(ctx, &afPacketCreate)
297         if err != nil {
298                 fmt.Printf("failed to create af packet: %v", err)
299                 return 0, err
300         }
301         _, err = ifaceClient.SwInterfaceSetFlags(ctx, &interfaces.SwInterfaceSetFlags{
302                 SwIfIndex: afPacketCreateRsp.SwIfIndex,
303                 Flags:     interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
304         })
305         if err != nil {
306                 fmt.Printf("set interface state up failed: %v\n", err)
307                 return 0, err
308         }
309         ipPrefix, err := ip_types.ParseAddressWithPrefix(interfaceAddress)
310         if err != nil {
311                 fmt.Printf("parse ip address %v\n", err)
312                 return 0, err
313         }
314         ipAddress := &interfaces.SwInterfaceAddDelAddress{
315                 IsAdd:     true,
316                 SwIfIndex: afPacketCreateRsp.SwIfIndex,
317                 Prefix:    ipPrefix,
318         }
319         _, errx := ifaceClient.SwInterfaceAddDelAddress(ctx, ipAddress)
320         if errx != nil {
321                 fmt.Printf("add ip address %v\n", err)
322                 return 0, err
323         }
324         return afPacketCreateRsp.SwIfIndex, nil
325 }
326
327 func (a *Actions) ConfigureHttpTps(args []string) *ActionResult {
328         ctx, cancel := newVppContext()
329         defer cancel()
330         con, vppErrCh := vpphelper.StartAndDialContext(ctx,
331                 vpphelper.WithVppConfig(configTemplate))
332         exitOnErrCh(ctx, cancel, vppErrCh)
333
334         confFn := configureProxyTcp("vpp0", "10.0.0.2/24", "vpp1", "10.0.1.2/24")
335         err := confFn(ctx, con)
336         if err != nil {
337                 return NewActionResult(err, ActionResultWithDesc("configuration failed"))
338         }
339
340         _, err = session.NewServiceClient(con).SessionEnableDisable(ctx, &session.SessionEnableDisable{
341                 IsEnable: true,
342         })
343         if err != nil {
344                 return NewActionResult(err, ActionResultWithDesc("configuration failed"))
345         }
346         Vppcli("", "http tps uri tcp://0.0.0.0/8080")
347         writeSyncFile(OkResult())
348         <-ctx.Done()
349         return nil
350 }
351
352 func (a *Actions) ConfigureTap(args []string) *ActionResult {
353         var startup Stanza
354         startup.
355                 NewStanza("session").
356                 Append("enable").
357                 Append("use-app-socket-api").Close()
358
359         ctx, cancel := newVppContext()
360         defer cancel()
361         con, vppErrCh := vpphelper.StartAndDialContext(ctx,
362                 vpphelper.WithRootDir(workDir),
363                 vpphelper.WithVppConfig(configTemplate+startup.ToString()))
364         exitOnErrCh(ctx, cancel, vppErrCh)
365         ifaceClient := interfaces.NewServiceClient(con)
366
367         pref, err := ip_types.ParseIP4Prefix("10.10.10.2/24")
368         if err != nil {
369                 return NewActionResult(err, ActionResultWithDesc("failed to parse ip4 address"))
370         }
371         createTapReply, err := tapv2.NewServiceClient(con).TapCreateV2(ctx, &tapv2.TapCreateV2{
372                 HostIfNameSet:    true,
373                 HostIfName:       "tap0",
374                 HostIP4PrefixSet: true,
375                 HostIP4Prefix:    ip_types.IP4AddressWithPrefix(pref),
376         })
377         if err != nil {
378                 return NewActionResult(err, ActionResultWithDesc("failed to configure tap"))
379         }
380         ipPrefix, err := ip_types.ParseAddressWithPrefix("10.10.10.1/24")
381         if err != nil {
382                 return NewActionResult(err, ActionResultWithDesc("parsing ip address failed"))
383         }
384         ipAddress := &interfaces.SwInterfaceAddDelAddress{
385                 IsAdd:     true,
386                 SwIfIndex: createTapReply.SwIfIndex,
387                 Prefix:    ipPrefix,
388         }
389         _, errx := ifaceClient.SwInterfaceAddDelAddress(ctx, ipAddress)
390         if errx != nil {
391                 return NewActionResult(err, ActionResultWithDesc("configuring ip address failed"))
392         }
393         _, err = ifaceClient.SwInterfaceSetFlags(ctx, &interfaces.SwInterfaceSetFlags{
394                 SwIfIndex: createTapReply.SwIfIndex,
395                 Flags:     interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
396         })
397         if err != nil {
398                 return NewActionResult(err, ActionResultWithDesc("failed to set interface state"))
399         }
400         _, err = session.NewServiceClient(con).SessionEnableDisable(ctx, &session.SessionEnableDisable{
401                 IsEnable: true,
402         })
403         if err != nil {
404                 return NewActionResult(err, ActionResultWithDesc("configuration failed"))
405         }
406         writeSyncFile(OkResult())
407         <-ctx.Done()
408         return nil
409 }