From ce4b6451787389c5b0ebfac413c350ef3a424b8b Mon Sep 17 00:00:00 2001 From: Ting Xu Date: Sun, 24 Apr 2022 06:14:25 +0000 Subject: packetforge: add packetforge for generic flow to extras Add a new tool packetforge to extras. This tool is to support generic flow. Packetforge is a library to translate naming or json profile format flow pattern to the required input of generic flow, i.e. spec and mask. Using python script flow_create.py, it can add and enable a new flow rule for an interface via flow VAPI, and can delete an existed flow rule as well. Command examples are shown below. Json profile examples can be found in ./parsegraph/samples. Naming format input: python flow_create.py --add -p "mac()/ipv4(src=1.1.1.1,dst=2.2.2.2)/udp()" -a "redirect-to-queue 3" -i 1 python flow_create.py --del -i 1 -I 0 Json profile format input: python flow_create.py -f "./flow_rule_examples/mac_ipv4.json" -i 1 With this command, flow rule can be added or deleted, and the flow entry can be listed with "show flow entry" command in VPP CLI. Packetforge is based on a parsegraph. The parsegraph can be built by users. A Spec can be found in ./parsegraph as guidance. More details about packetforge are in README file. Type: feature Signed-off-by: Ting Xu Change-Id: Ia9f539741c5dca27ff236f2bcc493c5dd48c0df1 --- extras/packetforge/flow_create.py | 157 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 extras/packetforge/flow_create.py (limited to 'extras/packetforge/flow_create.py') diff --git a/extras/packetforge/flow_create.py b/extras/packetforge/flow_create.py new file mode 100644 index 00000000000..fbbdec56694 --- /dev/null +++ b/extras/packetforge/flow_create.py @@ -0,0 +1,157 @@ +# Copyright (c) 2022 Intel 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. + +from vpp_papi.vpp_papi import VPPApiClient +import sys, getopt +import packetforge +import fnmatch +import os + +# Get VPP json API file directory +CLIENT_ID = "Vppclient" +VPP_JSON_DIR = ( + os.path.abspath("../..") + "/build-root/install-vpp-native/vpp/share/vpp/api/core" +) +VPP_JSON_DIR_PLUGIN = ( + os.path.abspath("../..") + + "/build-root/install-vpp-native/vpp/share/vpp/api/plugins" +) +API_FILE_SUFFIX = "*.api.json" + + +def Main(argv): + file_flag = False + operation = None + try: + opts, args = getopt.getopt( + argv, + "hf:p:a:i:I:", + [ + "help=", + "add", + "del", + "file=", + "pattern=", + "actions=", + "interface=", + "flow-index=", + ], + ) + except getopt.GetoptError: + print( + "flow_create.py --add|del -f -p -a -i -I " + ) + sys.exit() + for opt, arg in opts: + if opt == "-h": + print( + "flow_create.py --add|del -f -p -a -i -I " + ) + sys.exit() + elif opt == "--add": + operation = "add" + elif opt == "--del": + operation = "del" + elif opt in ("-f", "--file"): + actions = "" + json_file = arg + file_flag = True + elif opt in ("-p", "--pattern") and not file_flag: + pattern = arg + elif opt in ("-a", "--actions"): + actions = arg + elif opt in ("-i", "--interface"): + iface = arg + elif opt in ("-I", "--flow-index"): + flow_index = arg + + if operation == None: + print("Error: Please choose the operation: add or del") + sys.exit() + + if operation == "add": + if not file_flag: + result = packetforge.Forge(pattern, actions, False) + else: + result = packetforge.Forge(json_file, actions, True) + return result, int(iface), operation, None + elif operation == "del": + return None, int(iface), operation, int(flow_index) + + +def load_json_api_files(suffix=API_FILE_SUFFIX): + jsonfiles = [] + json_dir = VPP_JSON_DIR + for root, dirnames, filenames in os.walk(json_dir): + for filename in fnmatch.filter(filenames, suffix): + jsonfiles.append(os.path.join(json_dir, filename)) + json_dir = VPP_JSON_DIR_PLUGIN + for root, dirnames, filenames in os.walk(json_dir): + for filename in fnmatch.filter(filenames, suffix): + jsonfiles.append(os.path.join(json_dir, filename)) + if not jsonfiles: + raise RuntimeError("Error: no json api files found") + else: + print("load json api file done") + return jsonfiles + + +def connect_vpp(jsonfiles): + vpp = VPPApiClient(apifiles=jsonfiles) + r = vpp.connect("CLIENT_ID") + print("VPP api opened with code: %s" % r) + return vpp + + +if __name__ == "__main__": + # Python API need json definitions to interpret messages + vpp = connect_vpp(load_json_api_files()) + print(vpp.api.show_version()) + + # Parse the arguments + my_flow, iface, operation, del_flow_index = Main(sys.argv[1:]) + + # set inteface states + vpp.api.sw_interface_set_flags(sw_if_index=iface, flags=1) + + if operation == "add": + # add flow + rv = vpp.api.flow_add_v2(flow=my_flow) + flow_index = rv[3] + print(rv) + + # enable added flow + rv = vpp.api.flow_enable(flow_index=flow_index, hw_if_index=iface) + ena_res = rv[2] + # if enable flow fail, delete added flow + if ena_res: + print("Error: enable flow failed, delete flow") + rv = vpp.api.flow_del(flow_index=flow_index) + print(rv) + + elif operation == "del": + # disable flow + rv = vpp.api.flow_disable(flow_index=del_flow_index, hw_if_index=iface) + dis_res = rv[2] + if dis_res: + print("Error: disable flow failed") + sys.exit() + print(rv) + + # delete flow + rv = vpp.api.flow_del(flow_index=del_flow_index) + print(rv) + +# command example: +# python flow_create.py --add -p "mac()/ipv4(src=1.1.1.1,dst=2.2.2.2)/udp()" -a "redirect-to-queue 3" -i 1 +# python flow_create.py --del -i 1 -I 0 -- cgit 1.2.3-korg