1. VPP 接口文件
vpp同控制平面交互的定义接口位于目录vpp/src/vnet
和vpp/src/plugins
中的api文件;例如src/vnet/ip/ip_types.api文件中定义实例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
/* Hey Emacs use -*- mode: C -*- */ /* * Copyright (c) 2018 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ option version = "3.0.0"; manual_print typedef u8 ip4_address[4]; manual_print typedef u8 ip6_address[16]; enum address_family : u8 { ADDRESS_IP4 = 0, ADDRESS_IP6, }; /** * @brief The location at which to apply a feature */ enum ip_feature_location: u8 { IP_API_FEATURE_INPUT = 0, IP_API_FEATURE_OUTPUT, IP_API_FEATURE_LOCAL, IP_API_FEATURE_PUNT, IP_API_FEATURE_DROP, }; /* ECN code points - RFC 3168 https://tools.ietf.org/html/rfc3168 */ enum ip_ecn : u8 { IP_API_ECN_NONE = 0, IP_API_ECN_ECT0 = 1, IP_API_ECN_ECT1 = 2, IP_API_ECN_CE = 3, }; /* DSCP code points - RFC 2474 https://tools.ietf.org/html/rfc2474 Values other than these RFC defined values are accepted. */ enum ip_dscp : u8 { IP_API_DSCP_CS0 = 0, IP_API_DSCP_CS1 = 8, IP_API_DSCP_AF11 = 10, IP_API_DSCP_AF12 = 12, IP_API_DSCP_AF13 = 14, IP_API_DSCP_CS2 = 16, IP_API_DSCP_AF21 = 18, IP_API_DSCP_AF22 = 20, IP_API_DSCP_AF23 = 22, IP_API_DSCP_CS3 = 24, IP_API_DSCP_AF31 = 26, IP_API_DSCP_AF32 = 28, IP_API_DSCP_AF33 = 30, IP_API_DSCP_CS4 = 32, IP_API_DSCP_AF41 = 34, IP_API_DSCP_AF42 = 36, IP_API_DSCP_AF43 = 38, IP_API_DSCP_CS5 = 40, IP_API_DSCP_EF = 46, IP_API_DSCP_CS6 = 48, IP_API_DSCP_CS7 = 50, }; enum ip_proto : u8 { IP_API_PROTO_HOPOPT = 0, IP_API_PROTO_ICMP = 1, IP_API_PROTO_IGMP = 2, IP_API_PROTO_TCP = 6, IP_API_PROTO_UDP = 17, IP_API_PROTO_GRE = 47, IP_API_PROTO_ESP = 50, IP_API_PROTO_AH = 51, IP_API_PROTO_ICMP6 = 58, IP_API_PROTO_EIGRP = 88, IP_API_PROTO_OSPF = 89, IP_API_PROTO_SCTP = 132, IP_API_PROTO_RESERVED = 255, }; union address_union { vl_api_ip4_address_t ip4; vl_api_ip6_address_t ip6; }; manual_print typedef address { vl_api_address_family_t af; vl_api_address_union_t un; }; manual_print typedef prefix { vl_api_address_t address; u8 len; }; typedef ip4_address_and_mask { vl_api_ip4_address_t addr; vl_api_ip4_address_t mask; }; typedef ip6_address_and_mask { vl_api_ip6_address_t addr; vl_api_ip6_address_t mask; }; typedef mprefix { vl_api_address_family_t af; u16 grp_address_length; vl_api_address_union_t grp_address; vl_api_address_union_t src_address; }; manual_print typedef ip6_prefix { vl_api_ip6_address_t address; u8 len; }; manual_print typedef ip4_prefix { vl_api_ip4_address_t address; u8 len; }; /** \brief * * The vl_api_[ip4|ip6]_address_with_prefix_t types are used as a type to denote * both an IP address and a prefix. I.e. in CIDR notation * '192.168.10.1/24' the address is 192.168.10.1 and the network * prefix is 192.168.10.0/24. * * If only an address is needed use: vl_api_address_t types and if * only a network prefix is needed (i.e. no hosts bits), then use the * vl_api_prefix_t types. * **/ manual_print typedef vl_api_prefix_t address_with_prefix; manual_print typedef vl_api_ip4_prefix_t ip4_address_with_prefix; manual_print typedef vl_api_ip6_prefix_t ip6_address_with_prefix; /** \brief A context for matching prefixes against. (Think ip prefix list.) The meaning (exact match / want subnets) of an unset matcher is left to the implementer. @param le - le mut be <= to prefix.len. Default: 255 (not set). @param ge - ge must be greater than le and <= max_size of prefix. Default: 255 (not set). */ typedef prefix_matcher { u8 le; /* [default=255] */ u8 ge; /* [default=255] */ }; |
2. VPP 接口帮助文档
生成其他类型的接口文件,需要先生成json,然后根据json生成其他类型文件
- vpp/src/tools/vppapigen/VPPAPI.md
3. VPP 生成不同语言接口文件
3.1. json
1 2 3 4 5 |
cd /root/go/src/github.com/FDio/vpp/src/tools/vppapigen #首先生成.json文件 mkdir /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/api python3 generate_json.py --srcdir /root/go/src/github.com/FDio/vpp/src --output /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/api --debug-target |
3.2. C
/root/go/src/github.com/FDio/vpp/src/tools/vppapigen目录中有很多python文件用于转换.api为其他格式接口;这里总体入口是vppapigen.py文件,其他依赖文件主要作为依赖插件加载并执行解析;
1 2 3 4 5 6 7 8 9 10 |
cd /root/go/src/github.com/FDio/vpp/src/tools/vppapigen mkdir /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/c #这里的output_module模块默认是c代码,即采用vppapigen_c.py文件执行;这里是编译ip_types.api为c文件 #--input 待转换的.api接口文件 #--outputdir 生成文件输出路径 #--includedir用于定位寻找依赖项文件的路径 python3 vppapigen.py --includedir /root/go/src/github.com/FDio/vpp/src --input /root/go/src/github.com/FDio/vpp/src/vnet/ip/ip_types.api --outputdir /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/c --debug #python3 /root/go/src/github.com/FDio/vpp/src/vpp-api/vapi/vapi_c_gen.py |
3.3. Go
1 2 3 4 5 6 7 8 9 |
cd /root/go/src/github.com/FDio/vpp/src/tools/vppapigen mkdir /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/go # 方法1.根据json文件生成其他不通语言api文件,此处生成golang文件 python3 generate_go.py -input-dir /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/api -output-dir /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/go # 方法2. vpp-agne 中的govpp 项目中,也有自动生成文件;/root/go/src/github.com/ligato/govpp/cmd/binapi-generator/binapi-generator mkdir /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/go ./binapi-generator -input-dir /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/api -output-dir /root/go/src/github.com/FDio/vpp/src/tools/vppapigen/go |
- generate_go.py文件生成golang代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
#!/usr/bin/env python3 import argparse import os import pathlib import subprocess import tarfile #import requests import sys # # GoVPP API generator generates Go bindings compatible with the local VPP # parser = argparse.ArgumentParser() parser.add_argument("-govpp-commit", help="GoVPP commit or branch (defaults to v0.3.5-45-g671f16c)", default="671f16c", # fixed GoVPP version type=str) parser.add_argument("-output-dir", help="output target directory for generated bindings", type=str) parser.add_argument("-api-files", help="api files to generate (without commas)", nargs="+", type=str) parser.add_argument("-import-prefix", help="prefix imports in the generated go code", type=str) parser.add_argument("-no-source-path-info", help="disable source path info in generated files", nargs='?', const=True, default=False) parser.add_argument('-input-dir', help="api json files dir to generate (without commas)", type=str) args = parser.parse_args() # Check input arguments def validate_args(vpp_dir, o, f, c, i): if o is not None: if not os.path.exists(o) or os.path.isfile(o): print(o + " is not a valid output path") sys.exit(1) else: o = vpp_dir if f is None: f = [] if c is None: c = "671f16c" if i is None: i = "" return str(o), f, c, i # Returns version of the installed Go def get_go_version(go_root): p = subprocess.Popen(["./go", "version"], cwd=go_root + "/bin", stdout=subprocess.PIPE, universal_newlines=True, ) output, _ = p.communicate() output_fmt = output.replace("go version go", "", 1) return output_fmt.rstrip("\n") # Returns version of the installed binary API generator def get_binapi_gen_version(go_path): p = subprocess.Popen(["./binapi-generator", "-version"], cwd=go_path + "/bin", stdout=subprocess.PIPE, universal_newlines=True, ) output, _ = p.communicate() output_fmt = output.replace("govpp", "", 1) return output_fmt.rstrip("\n") # Verifies local Go installation and installs the latest # one if missing def install_golang(go_root): go_bin = go_root + "/bin/go" return # if os.path.exists(go_bin) and os.path.isfile(go_bin): # print('Go ' + get_go_version(go_root) + ' is already installed') # return # print("Go binary not found, installing the latest version...") # go_folders = ['src', 'pkg', 'bin'] # for f in go_folders: # if not os.path.exists(os.path.join(go_root, f)): # os.makedirs(os.path.join(go_root, f)) # filename = requests.get('https://golang.org/VERSION?m=text').text + ".linux-amd64.tar.gz" # url = "https://dl.google.com/go/" + filename # r = requests.get(url) # with open("/tmp/" + filename, 'wb') as f: # f.write(r.content) # go_tf = tarfile.open("/tmp/" + filename) # # Strip /go dir from the go_root path as it will # # be created while extracting the tar file # go_root_head, _ = os.path.split(go_root) # go_tf.extractall(path=go_root_head) # go_tf.close() # os.remove("/tmp/" + filename) # print('Go ' + get_go_version(go_root) + ' was installed') # Installs latest binary API generator def install_binapi_gen(c, go_root, go_path): os.environ['GO111MODULE'] = "on" if os.path.exists(go_root + "/bin/go") & os.path.isfile(go_root + "/bin/go"): p = subprocess.Popen(["./go", "get", "git.fd.io/govpp.git/cmd/binapi-generator@" + c], cwd=go_root + "/bin", stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, ) _, error = p.communicate() if p.returncode != 0: print("binapi generator installation failed: %d %s" % (p.returncode, error)) sys.exit(1) bg_ver = get_binapi_gen_version(go_path) print('Installed binary API generator ' + bg_ver) # Creates generated bindings using GoVPP binapigen to the target folder def generate_api(output_dir, json_dir, api_list, import_prefix, no_source, go_path): output_binapi = output_dir + "binapi" if output_dir[-1] == "/" else output_dir + "/binapi" if not os.path.exists(json_dir): print("Missing JSON api definitions") sys.exit(1) print("Generating API") cmd = ["./binapi-generator", "--output-dir=" + output_binapi, "--input-dir=" + json_dir] if len(api_list): print("Following API files were requested by 'GO_API_FILES': " + str(api_list)) print("Note that dependency requirements may generate additional API files") cmd.append(api_list) if not import_prefix == "": cmd.append("-import-prefix=" + import_prefix) if no_source: cmd.append("-no-source-path-info") p = subprocess.Popen(cmd, cwd=go_path + "/bin", stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, ) out = p.communicate()[1] if p.returncode != 0: print("go api generate failed: %d %s" % (p.returncode, out)) sys.exit(1) # Print nice output of the binapi generator for msg in out.split(): if "=" in msg: print() print(msg, end=" ") print("\n") print("Go API bindings were generated to " + output_binapi) def main(): # project root directory root = pathlib.Path(os.path.dirname(os.path.abspath(__file__))) vpp_dir: str = root.parent.parent.parent o, f, c, i = validate_args(vpp_dir, args.output_dir, args.api_files, args.govpp_commit, args.import_prefix) # go specific environment variables if "GOROOT" in os.environ: go_root = os.environ['GOROOT'] else: go_root = os.environ['HOME'] + "/.go" if "GOPATH" in os.environ: go_path = os.environ['GOPATH'] else: go_path = os.environ['HOME'] + "/go" install_golang(go_root) install_binapi_gen(c, go_root, go_path) json_dir = args.input_dir generate_api(o, json_dir, f, i, args.no_source_path_info, go_path) if __name__ == "__main__": main() |
微信赞赏
支付宝赞赏