1. VPP 接口文件
vpp同控制平面交互的定义接口位于目录vpp/src/vnet
和vpp/src/plugins
中的api文件;例如src/vnet/ip/ip_types.api文件中定义实例如下:
/* 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
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文件,其他依赖文件主要作为依赖插件加载并执行解析;
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
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代码
#!/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()