1 // Copyright (c) 2020 Cisco and/or its affiliates.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
32 "go.fd.io/govpp/adapter/socketclient"
33 "go.fd.io/govpp/binapi/vlib"
34 "go.fd.io/govpp/binapi/vpe"
35 "go.fd.io/govpp/binapigen"
36 "go.fd.io/govpp/binapigen/vppapi"
42 apifiles, err := vppapi.Parse()
47 switch cmd := flag.Arg(0); cmd {
49 runServer(apifiles, ":7777")
51 showVPPAPI(os.Stdout, apifiles)
54 writeAsJSON(os.Stdout, apifiles)
58 for _, apifile := range apifiles {
59 if apifile.Name == f {
60 writeAsJSON(os.Stdout, apifile)
66 log.Fatalf("VPP API file %q not found", f)
78 log.Fatalf("invalid command: %q", cmd)
83 func writeAsJSON(w io.Writer, data interface{}) {
84 b, err := json.MarshalIndent(data, "", " ")
89 if _, err := w.Write(b); err != nil {
94 func showRPC(apifiles []*vppapi.File) {
95 for _, apifile := range apifiles {
96 fmt.Printf("%s.api\n", apifile.Name)
97 if apifile.Service == nil {
100 for _, rpc := range apifile.Service.RPCs {
104 reply = "stream " + reply
106 fmt.Printf(" rpc (%s) --> (%s)\n", req, reply)
111 func showVPPAPI(out io.Writer, apifiles []*vppapi.File) {
112 binapigen.SortFilesByImports(apifiles)
115 w := tabwriter.NewWriter(&buf, 0, 0, 3, ' ', 0)
116 fmt.Fprintf(w, "API\tOPTIONS\tCRC\tPATH\tIMPORTED\tTYPES\t\n")
118 for _, apifile := range apifiles {
119 importedTypes := binapigen.ListImportedTypes(apifiles, apifile)
121 for k, v := range apifile.Options {
122 options = append(options, fmt.Sprintf("%s=%v", k, v))
124 imports := fmt.Sprintf("%d apis, %2d types", len(apifile.Imports), len(importedTypes))
125 path := strings.TrimPrefix(apifile.Path, vppapi.DefaultDir+"/")
126 types := fmt.Sprintf("%2d enum, %2d enumflag, %2d alias, %2d struct, %2d union, %2d msg",
127 len(apifile.EnumTypes), len(apifile.EnumflagTypes), len(apifile.AliasTypes), len(apifile.StructTypes), len(apifile.UnionTypes), len(apifile.Messages))
128 fmt.Fprintf(w, " %s\t%s\t%s\t%s\t%v\t%s\t\n",
129 apifile.Name, strings.Join(options, " "), apifile.CRC, path, imports, types)
132 if err := w.Flush(); err != nil {
135 fmt.Fprint(out, buf.String())
138 func sendCLI(args []string) {
139 cmd := strings.Join(args, " ")
140 fmt.Printf("# %s\n", cmd)
142 conn, err := govpp.Connect("/run/vpp/api.sock")
146 defer conn.Disconnect()
148 ch, err := conn.NewAPIChannel()
154 if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil {
158 client := vlib.NewServiceClient(conn)
159 reply, err := client.CliInband(context.Background(), &vlib.CliInband{
166 fmt.Print(reply.Reply)
169 func runServer(apifiles []*vppapi.File, addr string) {
170 apiRoutes(apifiles, http.DefaultServeMux)
172 conn, err := govpp.Connect(socketclient.DefaultSocketName)
177 vpeRPC := vpe.NewServiceClient(conn)
178 c := vpe.HTTPHandler(vpeRPC)
182 log.Printf("listening on %v", addr)
184 if err := http.ListenAndServe(addr, nil); err != nil {
189 func apiRoutes(apifiles []*vppapi.File, mux *http.ServeMux) {
190 for _, apifile := range apifiles {
192 mux.HandleFunc("/vppapi/"+name, apiFileHandler(apifile))
193 mux.HandleFunc("/raw/"+name, rawHandler(apifile))
194 mux.HandleFunc("/rpc/"+name, rpcHandler(apifile))
196 mux.HandleFunc("/vppapi", apiHandler(apifiles))
199 func rpcHandler(apifile *vppapi.File) func(http.ResponseWriter, *http.Request) {
200 return func(w http.ResponseWriter, req *http.Request) {
201 msgName := strings.TrimPrefix(req.URL.Path, "/rpc/"+apifile.Name+"/")
203 http.Error(w, "no message name", 500)
207 input, err := ioutil.ReadAll(req.Body)
209 http.Error(w, err.Error(), 500)
213 msgReq := make(map[string]interface{})
214 err = json.Unmarshal(input, &msgReq)
216 http.Error(w, err.Error(), 500)
220 var msg *vppapi.Message
221 for _, m := range apifile.Messages {
222 if m.Name == msgName {
228 http.Error(w, "unknown message name: "+msgName, 500)
235 func apiHandler(apifiles []*vppapi.File) func(http.ResponseWriter, *http.Request) {
236 return func(w http.ResponseWriter, req *http.Request) {
237 b, err := json.MarshalIndent(apifiles, "", " ")
239 http.Error(w, err.Error(), 500)
246 func apiFileHandler(apifile *vppapi.File) func(http.ResponseWriter, *http.Request) {
247 return func(w http.ResponseWriter, req *http.Request) {
248 b, err := json.MarshalIndent(apifile, "", " ")
250 http.Error(w, err.Error(), 500)
257 func rawHandler(apifile *vppapi.File) func(http.ResponseWriter, *http.Request) {
258 return func(w http.ResponseWriter, req *http.Request) {
259 b, err := ioutil.ReadFile(apifile.Path)
261 http.Error(w, err.Error(), 500)