1 # copyright (c) 2023 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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """Flow Utilities Library."""
16 from enum import IntEnum
17 from ipaddress import ip_address
19 from resources.libraries.python.topology import Topology
20 from resources.libraries.python.ssh import exec_cmd_no_error
21 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
23 class FlowType(IntEnum):
25 FLOW_TYPE_ETHERNET = 1
28 FLOW_TYPE_IP4_L2TPV3OIP = 4
29 FLOW_TYPE_IP4_IPSEC_ESP = 5
30 FLOW_TYPE_IP4_IPSEC_AH = 6
31 FLOW_TYPE_IP4_N_TUPLE = 7
32 FLOW_TYPE_IP6_N_TUPLE = 8
33 FLOW_TYPE_IP4_VXLAN = 11
34 FLOW_TYPE_IP6_VXLAN = 12
35 FLOW_TYPE_IP4_GTPU = 14
37 class FlowProto(IntEnum):
43 IP_API_PROTO_L2TP = 115
45 class FlowAction(IntEnum):
48 FLOW_ACTION_REDIRECT_TO_QUEUE = 16
52 """Utilities for flow configuration."""
55 def vpp_create_ip4_n_tuple_flow(
56 node, src_ip, dst_ip, src_port, dst_port,
57 proto, action, value=0):
58 """Create IP4_N_TUPLE flow.
60 :param node: DUT node.
61 :param src_ip: Source IP4 address.
62 :param dst_ip: Destination IP4 address.
63 :param src_port: Source port.
64 :param dst_port: Destination port.
65 :param proto: TCP or UDP.
66 :param action: Mark, drop or redirect-to-queue.
67 :param value: Action value.
81 flow_type = FlowType.FLOW_TYPE_IP4_N_TUPLE
84 flow_proto = FlowProto.IP_API_PROTO_TCP
86 flow_proto = FlowProto.IP_API_PROTO_UDP
88 raise ValueError(f"proto error: {proto}")
91 u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"},
92 u'dst_addr': {u'addr': dst_ip, u'mask': u"255.255.255.255"},
93 u'src_port': {u'port': src_port, u'mask': 0xFFFF},
94 u'dst_port': {u'port': dst_port, u'mask': 0xFFFF},
95 u'protocol': {u'prot': flow_proto}
98 flow_index = FlowUtil.vpp_flow_add(
99 node, flow, flow_type, pattern, action, value)
104 def vpp_create_ip6_n_tuple_flow(
105 node, src_ip, dst_ip, src_port, dst_port,
106 proto, action, value=0):
107 """Create IP6_N_TUPLE flow.
109 :param node: DUT node.
110 :param src_ip: Source IP6 address.
111 :param dst_ip: Destination IP6 address.
112 :param src_port: Source port.
113 :param dst_port: Destination port.
114 :param proto: TCP or UDP.
115 :param action: Mark, drop or redirect-to-queue.
116 :param value: Action value.
126 :returns: flow_index.
129 flow = u"ip6_n_tuple"
130 flow_type = FlowType.FLOW_TYPE_IP6_N_TUPLE
133 flow_proto = FlowProto.IP_API_PROTO_TCP
134 elif proto == u"UDP":
135 flow_proto = FlowProto.IP_API_PROTO_UDP
137 raise ValueError(f"proto error: {proto}")
140 u'src_addr': {u'addr': src_ip, \
141 u'mask': u"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"},
142 u'dst_addr': {u'addr': dst_ip, \
143 u'mask': u"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"},
144 u'src_port': {u'port': src_port, u'mask': 0xFFFF},
145 u'dst_port': {u'port': dst_port, u'mask': 0xFFFF},
146 u'protocol': {u'prot': flow_proto}
149 flow_index = FlowUtil.vpp_flow_add(
150 node, flow, flow_type, pattern, action, value)
155 def vpp_create_ip4_flow(
156 node, src_ip, dst_ip, proto, action, value=0):
159 :param node: DUT node.
160 :param src_ip: Source IP4 address.
161 :param dst_ip: Destination IP4 address.
162 :param proto: TCP or UDP.
163 :param action: Mark, drop or redirect-to-queue.
164 :param value: Action value.
172 :returns: flow_index.
176 flow_type = FlowType.FLOW_TYPE_IP4
179 flow_proto = FlowProto.IP_API_PROTO_TCP
180 elif proto == u"UDP":
181 flow_proto = FlowProto.IP_API_PROTO_UDP
183 raise ValueError(f"proto error: {proto}")
186 u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"},
187 u'dst_addr': {u'addr': dst_ip, u'mask': u"255.255.255.255"},
188 u'protocol': {u'prot': flow_proto}
191 flow_index = FlowUtil.vpp_flow_add(
192 node, flow, flow_type, pattern, action, value)
197 def vpp_create_ip6_flow(
198 node, src_ip, dst_ip, proto, action, value=0):
201 :param node: DUT node.
202 :param src_ip: Source IP6 address.
203 :param dst_ip: Destination IP6 address.
204 :param proto: TCP or UDP.
205 :param action: Mark, drop or redirect-to-queue.
206 :param value: Action value.
214 :returns: flow_index.
218 flow_type = FlowType.FLOW_TYPE_IP6
221 flow_proto = FlowProto.IP_API_PROTO_TCP
222 elif proto == u"UDP":
223 flow_proto = FlowProto.IP_API_PROTO_UDP
225 raise ValueError(f"proto error: {proto}")
228 u'src_addr': {u'addr': src_ip, \
229 u'mask': u"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"},
230 u'dst_addr': {'addr': dst_ip, \
231 u'mask': u"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"},
232 u'protocol': {u'prot': flow_proto}
235 flow_index = FlowUtil.vpp_flow_add(
236 node, flow, flow_type, pattern, action, value)
241 def vpp_create_ip4_gtpu_flow(
242 node, src_ip, dst_ip, teid, action, value=0):
243 """Create IP4_GTPU flow.
245 :param node: DUT node.
246 :param src_ip: Source IP4 address.
247 :param dst_ip: Destination IP4 address.
248 :param teid: Tunnel endpoint identifier.
249 :param action: Mark, drop or redirect-to-queue.
250 :param value: Action value.
258 :returns: flow_index.
262 flow_type = FlowType.FLOW_TYPE_IP4_GTPU
263 flow_proto = FlowProto.IP_API_PROTO_UDP
266 u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"},
267 u'dst_addr': {u'addr': dst_ip, u'mask': u"255.255.255.255"},
268 u'protocol': {u'prot': flow_proto},
272 flow_index = FlowUtil.vpp_flow_add(
273 node, flow, flow_type, pattern, action, value)
278 def vpp_create_ip4_ipsec_flow(node, proto, spi, action, value=0):
279 """Create IP4_IPSEC flow.
281 :param node: DUT node.
282 :param proto: TCP or UDP.
283 :param spi: Security Parameters Index.
284 :param action: Mark, drop or redirect-to-queue.
285 :param value: Action value.
292 :returns: flow_index.
296 flow = u"ip4_ipsec_esp"
297 flow_proto = FlowProto.IP_API_PROTO_ESP
298 flow_type = FlowType.FLOW_TYPE_IP4_IPSEC_ESP
300 flow = u"ip4_ipsec_ah"
301 flow_proto = FlowProto.IP_API_PROTO_AH
302 flow_type = FlowType.FLOW_TYPE_IP4_IPSEC_AH
304 raise ValueError(f"proto error: {proto}")
307 u'protocol': {u'prot': flow_proto},
311 flow_index = FlowUtil.vpp_flow_add(
312 node, flow, flow_type, pattern, action, value)
317 def vpp_create_ip4_l2tp_flow(node, session_id, action, value=0):
318 """Create IP4_L2TPV3OIP flow.
320 :param node: DUT node.
321 :param session_id: PPPoE session ID
322 :param action: Mark, drop or redirect-to-queue.
323 :param value: Action value.
326 :type session_id: int
329 :returns: flow_index.
332 flow = u"ip4_l2tpv3oip"
333 flow_proto = FlowProto.IP_API_PROTO_L2TP
334 flow_type = FlowType.FLOW_TYPE_IP4_L2TPV3OIP
337 u'protocol': {u'prot': flow_proto},
338 u'session_id': session_id
341 flow_index = FlowUtil.vpp_flow_add(
342 node, flow, flow_type, pattern, action, value)
347 def vpp_create_ip4_vxlan_flow(node, src_ip, dst_ip, vni, action, value=0):
348 """Create IP4_VXLAN flow.
350 :param node: DUT node.
351 :param src_ip: Source IP4 address.
352 :param dst_ip: Destination IP4 address.
353 :param vni: Virtual network instance.
354 :param action: Mark, drop or redirect-to-queue.
355 :param value: Action value.
363 :returns: flow_index.
366 flow_type = FlowType.FLOW_TYPE_IP4_VXLAN
367 flow_proto = FlowProto.IP_API_PROTO_UDP
370 u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"},
371 u'dst_addr': {u'addr': dst_ip, u'mask': u"255.255.255.255"},
372 u'dst_port': {u'port': 4789, 'mask': 0xFFFF},
373 u'protocol': {u'prot': flow_proto},
377 flow_index = FlowUtil.vpp_flow_add(
378 node, flow, flow_type, pattern, action, value)
383 def vpp_flow_add(node, flow, flow_type, pattern, action, value=0):
386 :param node: DUT node.
387 :param flow: Name of flow.
388 :param flow_type: Type of flow.
389 :param pattern: Pattern of flow.
390 :param action: Mark, drop or redirect-to-queue.
391 :param value: Action value.
399 :returns: flow_index.
401 :raises ValueError: If action type is not supported.
405 if action == u"redirect-to-queue":
408 u'actions': FlowAction.FLOW_ACTION_REDIRECT_TO_QUEUE,
409 u'redirect_queue': value,
410 u'flow': {flow : pattern}
412 elif action == u"mark":
415 u'actions': FlowAction.FLOW_ACTION_MARK,
416 u'mark_flow_id': value,
417 u'flow': {flow : pattern}
419 elif action == u"drop":
422 u'actions': FlowAction.FLOW_ACTION_DROP,
423 u'flow': {flow : pattern}
426 raise ValueError(f"Unsupported action type: {action}")
428 err_msg = f"Failed to create {flow} flow on host {node[u'host']}."
429 args = dict(flow=flow_rule)
431 with PapiSocketExecutor(node) as papi_exec:
432 reply = papi_exec.add(cmd, **args).get_reply(err_msg)
433 flow_index = reply[u"flow_index"]
438 def vpp_flow_enable(node, interface, flow_index=0):
441 :param node: DUT node.
442 :param interface: Interface sw_if_index.
443 :param flow_index: Flow index.
447 :type flow_index: int
451 sw_if_index = Topology.get_interface_sw_index(node, interface)
453 flow_index=int(flow_index),
454 hw_if_index=int(sw_if_index)
457 err_msg = f"Failed to enable flow on host {node[u'host']}"
458 with PapiSocketExecutor(node) as papi_exec:
459 papi_exec.add(cmd, **args).get_reply(err_msg)
462 def vpp_flow_disable(node, interface, flow_index=0):
465 :param node: DUT node.
466 :param interface: Interface sw_if_index.
467 :param flow_index: Flow index.
471 :type flow_index: int
474 cmd = u"flow_disable"
475 sw_if_index = Topology.get_interface_sw_index(node, interface)
477 flow_index=int(flow_index),
478 hw_if_index=int(sw_if_index)
481 err_msg = u"Failed to disable flow on host {node[u'host']}"
482 with PapiSocketExecutor(node) as papi_exec:
483 papi_exec.add(cmd, **args).get_reply(err_msg)
486 def vpp_flow_del(node, flow_index=0):
489 :param node: DUT node.
490 :param flow_index: Flow index.
493 :type flow_index: int
498 flow_index=int(flow_index)
501 err_msg = u"Failed to delete flow on host {node[u'host']}"
502 with PapiSocketExecutor(node) as papi_exec:
503 papi_exec.add(cmd, **args).get_reply(err_msg)
506 def vpp_show_flow_entry(node):
509 :param node: DUT node.
512 :returns: flow entry.
515 cmd = u"vppctl show flow entry"
517 err_msg = u"Failed to show flow on host {node[u'host']}"
518 stdout, _ = exec_cmd_no_error(
519 node, cmd, sudo=False, message=err_msg, retries=120
522 return stdout.strip()
525 def vpp_verify_flow_action(
527 src_mac=u"11:22:33:44:55:66", dst_mac=u"11:22:33:44:55:66",
528 src_ip=None, dst_ip=None):
529 """Verify the correctness of the flow action.
531 :param node: DUT node.
532 :param action: Action.
533 :param value: Action value.
534 :param src_mac: Source mac address.
535 :param dst_mac: Destination mac address.
536 :param src_ip: Source IP address.
537 :param dst_ip: Destination IP address.
547 :raises RuntimeError: If the verification of flow action fails.
548 :raises ValueError: If action type is not supported.
550 err_msg = f"Failed to show trace on host {node[u'host']}"
551 cmd = u"vppctl show trace"
552 stdout, _ = exec_cmd_no_error(
553 node, cmd, sudo=False, message=err_msg, retries=120
556 err_info = f"Verify flow {action} failed"
559 expected_str = f"{src_mac} -> {dst_mac}"
561 src_ip = ip_address(src_ip)
562 dst_ip = ip_address(dst_ip)
563 expected_str = f"{src_ip} -> {dst_ip}"
565 if action == u"drop":
566 if expected_str in stdout:
567 raise RuntimeError(err_info)
568 elif action == u"redirect-to-queue":
569 if f"queue {value}" not in stdout \
570 and f"qid {value}" not in stdout:
571 raise RuntimeError(err_info)
572 if expected_str not in stdout:
573 raise RuntimeError(err_info)
574 elif action == u"mark":
575 if u"PKT_RX_FDIR" not in stdout and u"flow-id 1" not in stdout:
576 raise RuntimeError(err_info)
577 if expected_str not in stdout:
578 raise RuntimeError(err_info)
580 raise ValueError(f"Unsupported action type: {action}")