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