blob: 42bfeb01e008340d9af95105437266f9d1c93d60 [file] [log] [blame]
Ting Xuce4b6452022-04-24 06:14:25 +00001# Copyright (c) 2022 Intel and/or its affiliates.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at:
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
14from vpp_papi.vpp_papi import VppEnum
15from ParseGraph import *
16from Path import *
17import json
18import re
19import os
20
21parsegraph_path = os.getcwd() + "/parsegraph"
22
23
Ting Xuf34420f2023-03-16 01:22:33 +000024def Forge(pattern, actions, file_flag, show_result_only):
Ting Xuce4b6452022-04-24 06:14:25 +000025 pg = ParseGraph.Create(parsegraph_path)
26 if pg == None:
27 print("error: create parsegraph failed")
28 return None
29
30 if not file_flag:
31 token = ParsePattern(pattern)
32 if token == None:
33 return None
34 else:
35 if not os.path.exists(pattern):
36 print("error: file not exist '%s' " % (pattern))
37 return
38 f = open(pattern, "r", encoding="utf-8")
39 token = json.load(f)
40 if "actions" in token:
41 actions = token["actions"]
42
43 path = Path.Create(token)
44 if path == None:
45 print("error: path not exit")
46 return None
47
48 result = pg.Forge(path)
49 if result == None:
50 print("error: result not available")
51 return None
52
53 spec, mask = GetBinary(result.ToJSON())
54
55 # create generic flow
56 my_flow = {
Ting Xuce4b6452022-04-24 06:14:25 +000057 "flow": {
58 "generic": {
59 "pattern": {"spec": bytes(spec.encode()), "mask": bytes(mask.encode())}
60 }
61 },
62 }
63
Ting Xuf34420f2023-03-16 01:22:33 +000064 if show_result_only:
65 return my_flow
66
67 my_flow.update(
68 {
69 "type": VppEnum.vl_api_flow_type_v2_t.FLOW_TYPE_GENERIC_V2,
70 }
71 )
72
Ting Xuce4b6452022-04-24 06:14:25 +000073 # update actions entry
74 my_flow = GetAction(actions, my_flow)
75
76 return my_flow
77
78
79def GetAction(actions, flow):
80 if len(actions.split(" ")) > 1:
81 type = actions.split(" ")[0]
82 else:
83 type = actions
84
85 if type == "mark":
86 flow.update(
87 {
88 "actions": VppEnum.vl_api_flow_action_v2_t.FLOW_ACTION_MARK_V2,
89 "mark_flow_id": int(actions.split(" ")[1]),
90 }
91 )
92 elif type == "next-node":
93 flow.update(
94 {
95 "actions": VppEnum.vl_api_flow_action_v2_t.FLOW_ACTION_REDIRECT_TO_NODE_V2,
96 "redirect_node_index": int(actions.split(" ")[1]),
97 }
98 )
99 elif type == "buffer-advance":
100 flow.update(
101 {
102 "actions": VppEnum.vl_api_flow_action_v2_t.FLOW_ACTION_BUFFER_ADVANCE_V2,
103 "buffer_advance": int(actions.split(" ")[1]),
104 }
105 )
106 elif type == "redirect-to-queue":
107 flow.update(
108 {
109 "actions": VppEnum.vl_api_flow_action_v2_t.FLOW_ACTION_REDIRECT_TO_QUEUE_V2,
110 "redirect_queue": int(actions.split(" ")[1]),
111 }
112 )
113 elif type == "rss":
114 flow.update({"actions": VppEnum.vl_api_flow_action_v2_t.FLOW_ACTION_RSS_V2})
115 elif type == "rss-queues":
116 queue_end = int(actions.split(" ")[-1])
117 queue_start = int(actions.split(" ")[-3])
118 flow.update(
119 {
120 "actions": VppEnum.vl_api_flow_action_v2_t.FLOW_ACTION_RSS_V2,
121 "queue_index": queue_start,
122 "queue_num": queue_end - queue_start + 1,
123 }
124 )
125 elif type == "drop":
126 flow.update({"actions": VppEnum.vl_api_flow_action_v2_t.FLOW_ACTION_DROP_V2})
127
128 return flow
129
130
131def GetBinary(flow_info):
132 spec = "".join(flow_info["Packet"])
133 mask = "".join(flow_info["Mask"])
134 return spec, mask
135
136
137def ParseFields(item):
138 # get protocol name
139 prot = item.split("(")[0]
140 stack = {"header": prot}
141 # get fields contents
142 fields = re.findall(r"[(](.*?)[)]", item)
143 if not fields:
144 print("error: invalid pattern")
145 return None
146 if fields == [""]:
147 return stack
148 stack.update({"fields": []})
149 return ParseStack(stack, fields[0].split(","))
150
151
152def GetMask(item):
153 if "format" in item:
154 format = item["format"]
155 if format == "mac":
Ting Xuc9d916c2022-09-29 13:50:55 +0800156 mask = "ff:ff:ff:ff:ff:ff"
Ting Xuce4b6452022-04-24 06:14:25 +0000157 elif format == "ipv4":
158 mask = "255.255.255.255"
159 elif format == "ipv6":
160 mask = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
161 return mask
162 if "size" in item:
163 mask = str((1 << int(item["size"])) - 1)
164 else:
165 print("mask error")
166 return mask
167
168
169# parse protocol headers and its fields. Available fields are defined in corresponding nodes.
170def ParseStack(stack, fields):
171 prot = stack["header"]
172 node_path = parsegraph_path + "/nodes/" + prot + ".json"
173 if not os.path.exists(node_path):
174 print("error file not exist '%s' " % (node_path))
175 return None
176 f = open(node_path, "r", encoding="utf-8")
177 nodeinfo = json.load(f)
178 for field in fields:
179 fld_name = field.split("=")[0].strip()
180 fld_value = (
181 field.split("=")[-1].strip() if (len(field.split("=")) >= 2) else None
182 )
183 for item in nodeinfo["layout"]:
184 if fld_name == item["name"]:
185 mask = GetMask(item)
186 stack["fields"].append(
187 {"name": fld_name, "value": fld_value, "mask": mask}
188 )
189 break
190 if not stack["fields"]:
191 print("warning: invalid field '%s'" % (fld_name))
192 return None
193
194 return stack
195
196
197def ParsePattern(pattern):
198 # create json template
199 json_tmp = {"type": "path", "stack": []}
200
201 items = pattern.split("/")
202 for item in items:
203 stack = ParseFields(item)
204 if stack == None:
205 return None
206 json_tmp["stack"].append(stack)
207
208 return json_tmp