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