1 # copyright (c) 2021 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 ipaddress import ip_address
18 from resources.libraries.python.topology import Topology
19 from resources.libraries.python.ssh import exec_cmd_no_error
20 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
23 """Utilities for flow configuration."""
26 def vpp_create_ip4_n_tuple_flow(
27 node, src_ip, dst_ip, src_port, dst_port,
28 proto, action, value=0):
29 """Create IP4_N_TUPLE flow.
31 :param node: DUT node.
32 :param src_ip: Source IP4 address.
33 :param dst_ip: Destination IP4 address.
34 :param src_port: Source port.
35 :param dst_port: Destination port.
36 :param proto: TCP or UDP.
37 :param action: Mark, drop or redirect-to-queue.
38 :param value: Action value.
51 from vpp_papi import VppEnum
54 flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_N_TUPLE
57 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_TCP
59 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
61 raise ValueError(f"proto error: {proto}")
64 u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"},
65 u'dst_addr': {u'addr': dst_ip, u'mask': u"255.255.255.255"},
66 u'src_port': {u'port': src_port, u'mask': 0xFFFF},
67 u'dst_port': {u'port': dst_port, u'mask': 0xFFFF},
68 u'protocol': {u'prot': flow_proto}
71 flow_index = FlowUtil.vpp_flow_add(
72 node, flow, flow_type, pattern, action, value)
77 def vpp_create_ip6_n_tuple_flow(
78 node, src_ip, dst_ip, src_port, dst_port,
79 proto, action, value=0):
80 """Create IP6_N_TUPLE flow.
82 :param node: DUT node.
83 :param src_ip: Source IP6 address.
84 :param dst_ip: Destination IP6 address.
85 :param src_port: Source port.
86 :param dst_port: Destination port.
87 :param proto: TCP or UDP.
88 :param action: Mark, drop or redirect-to-queue.
89 :param value: Action value.
102 from vpp_papi import VppEnum
104 flow = u"ip6_n_tuple"
105 flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP6_N_TUPLE
108 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_TCP
109 elif proto == u"UDP":
110 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
112 raise ValueError(f"proto error: {proto}")
115 u'src_addr': {u'addr': src_ip, \
116 u'mask': u"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"},
117 u'dst_addr': {u'addr': dst_ip, \
118 u'mask': u"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"},
119 u'src_port': {u'port': src_port, u'mask': 0xFFFF},
120 u'dst_port': {u'port': dst_port, u'mask': 0xFFFF},
121 u'protocol': {u'prot': flow_proto}
124 flow_index = FlowUtil.vpp_flow_add(
125 node, flow, flow_type, pattern, action, value)
130 def vpp_create_ip4_flow(
131 node, src_ip, dst_ip, proto, action, value=0):
134 :param node: DUT node.
135 :param src_ip: Source IP4 address.
136 :param dst_ip: Destination IP4 address.
137 :param proto: TCP or UDP.
138 :param action: Mark, drop or redirect-to-queue.
139 :param value: Action value.
147 :returns: flow_index.
150 from vpp_papi import VppEnum
153 flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4
156 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_TCP
157 elif proto == u"UDP":
158 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
160 raise ValueError(f"proto error: {proto}")
163 u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"},
164 u'dst_addr': {u'addr': dst_ip, u'mask': u"255.255.255.255"},
165 u'protocol': {u'prot': flow_proto}
168 flow_index = FlowUtil.vpp_flow_add(
169 node, flow, flow_type, pattern, action, value)
174 def vpp_create_ip6_flow(
175 node, src_ip, dst_ip, proto, action, value=0):
178 :param node: DUT node.
179 :param src_ip: Source IP6 address.
180 :param dst_ip: Destination IP6 address.
181 :param proto: TCP or UDP.
182 :param action: Mark, drop or redirect-to-queue.
183 :param value: Action value.
191 :returns: flow_index.
194 from vpp_papi import VppEnum
197 flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP6
200 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_TCP
201 elif proto == u"UDP":
202 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
204 raise ValueError(f"proto error: {proto}")
207 u'src_addr': {u'addr': src_ip, \
208 u'mask': u"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"},
209 u'dst_addr': {'addr': dst_ip, \
210 u'mask': u"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"},
211 u'protocol': {u'prot': flow_proto}
214 flow_index = FlowUtil.vpp_flow_add(
215 node, flow, flow_type, pattern, action, value)
220 def vpp_create_ip4_gtpu_flow(
221 node, src_ip, dst_ip, teid, action, value=0):
222 """Create IP4_GTPU flow.
224 :param node: DUT node.
225 :param src_ip: Source IP4 address.
226 :param dst_ip: Destination IP4 address.
227 :param teid: Tunnel endpoint identifier.
228 :param action: Mark, drop or redirect-to-queue.
229 :param value: Action value.
237 :returns: flow_index.
240 from vpp_papi import VppEnum
243 flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_GTPU
244 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
247 u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"},
248 u'dst_addr': {u'addr': dst_ip, u'mask': u"255.255.255.255"},
249 u'protocol': {u'prot': flow_proto},
253 flow_index = FlowUtil.vpp_flow_add(
254 node, flow, flow_type, pattern, action, value)
259 def vpp_create_ip4_ipsec_flow(node, proto, spi, action, value=0):
260 """Create IP4_IPSEC flow.
262 :param node: DUT node.
263 :param proto: TCP or UDP.
264 :param spi: Security Parameters Index.
265 :param action: Mark, drop or redirect-to-queue.
266 :param value: Action value.
273 :returns: flow_index.
276 from vpp_papi import VppEnum
279 flow = u"ip4_ipsec_esp"
280 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_ESP
281 flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_IPSEC_ESP
283 flow = u"ip4_ipsec_ah"
284 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_AH
285 flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_IPSEC_AH
287 raise ValueError(f"proto error: {proto}")
290 u'protocol': {u'prot': flow_proto},
294 flow_index = FlowUtil.vpp_flow_add(
295 node, flow, flow_type, pattern, action, value)
300 def vpp_create_ip4_l2tp_flow(node, session_id, action, value=0):
301 """Create IP4_L2TPV3OIP flow.
303 :param node: DUT node.
304 :param session_id: PPPoE session ID
305 :param action: Mark, drop or redirect-to-queue.
306 :param value: Action value.
309 :type session_id: int
312 :returns: flow_index.
315 from vpp_papi import VppEnum
317 flow = u"ip4_l2tpv3oip"
318 flow_proto = 115 # IP_API_PROTO_L2TP
319 flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_L2TPV3OIP
322 u'protocol': {u'prot': flow_proto},
323 u'session_id': session_id
326 flow_index = FlowUtil.vpp_flow_add(
327 node, flow, flow_type, pattern, action, value)
332 def vpp_create_ip4_vxlan_flow(node, src_ip, dst_ip, vni, action, value=0):
333 """Create IP4_VXLAN flow.
335 :param node: DUT node.
336 :param src_ip: Source IP4 address.
337 :param dst_ip: Destination IP4 address.
338 :param vni: Virtual network instance.
339 :param action: Mark, drop or redirect-to-queue.
340 :param value: Action value.
348 :returns: flow_index.
350 from vpp_papi import VppEnum
353 flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_VXLAN
354 flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
357 u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"},
358 u'dst_addr': {u'addr': dst_ip, u'mask': u"255.255.255.255"},
359 u'dst_port': {u'port': 4789, 'mask': 0xFFFF},
360 u'protocol': {u'prot': flow_proto},
364 flow_index = FlowUtil.vpp_flow_add(
365 node, flow, flow_type, pattern, action, value)
370 def vpp_flow_add(node, flow, flow_type, pattern, action, value=0):
373 :param node: DUT node.
374 :param flow: Name of flow.
375 :param flow_type: Type of flow.
376 :param pattern: Pattern of flow.
377 :param action: Mark, drop or redirect-to-queue.
378 :param value: Action value.
386 :returns: flow_index.
388 :raises ValueError: If action type is not supported.
390 from vpp_papi import VppEnum
394 if action == u"redirect-to-queue":
397 u'actions': VppEnum.vl_api_flow_action_t.\
398 FLOW_ACTION_REDIRECT_TO_QUEUE,
399 u'redirect_queue': value,
400 u'flow': {flow : pattern}
402 elif action == u"mark":
405 u'actions': VppEnum.vl_api_flow_action_t.FLOW_ACTION_MARK,
406 u'mark_flow_id': value,
407 u'flow': {flow : pattern}
409 elif action == u"drop":
412 u'actions': VppEnum.vl_api_flow_action_t.FLOW_ACTION_DROP,
413 u'flow': {flow : pattern}
416 raise ValueError(f"Unsupported action type: {action}")
418 err_msg = f"Failed to create {flow} flow on host {node[u'host']}."
419 args = dict(flow=flow_rule)
421 with PapiSocketExecutor(node) as papi_exec:
422 reply = papi_exec.add(cmd, **args).get_reply(err_msg)
423 flow_index = reply[u"flow_index"]
428 def vpp_flow_enable(node, interface, flow_index=0):
431 :param node: DUT node.
432 :param interface: Interface sw_if_index.
433 :param flow_index: Flow index.
437 :type flow_index: int
440 from vpp_papi import VppEnum
443 sw_if_index = Topology.get_interface_sw_index(node, interface)
445 flow_index=int(flow_index),
446 hw_if_index=int(sw_if_index)
449 err_msg = u"Failed to enable flow on host {node[u'host']}"
450 with PapiSocketExecutor(node) as papi_exec:
451 papi_exec.add(cmd, **args).get_reply(err_msg)
454 def vpp_flow_disable(node, interface, flow_index=0):
457 :param node: DUT node.
458 :param interface: Interface sw_if_index.
459 :param flow_index: Flow index.
463 :type flow_index: int
466 from vpp_papi import VppEnum
468 cmd = u"flow_disable"
469 sw_if_index = Topology.get_interface_sw_index(node, interface)
471 flow_index=int(flow_index),
472 hw_if_index=int(sw_if_index)
475 err_msg = u"Failed to disable flow on host {node[u'host']}"
476 with PapiSocketExecutor(node) as papi_exec:
477 papi_exec.add(cmd, **args).get_reply(err_msg)
480 def vpp_flow_del(node, flow_index=0):
483 :param node: DUT node.
484 :param flow_index: Flow index.
487 :type flow_index: int
490 from vpp_papi import VppEnum
494 flow_index=int(flow_index)
497 err_msg = u"Failed to delete flow on host {node[u'host']}"
498 with PapiSocketExecutor(node) as papi_exec:
499 papi_exec.add(cmd, **args).get_reply(err_msg)
502 def vpp_show_flow_entry(node):
505 :param node: DUT node.
508 :returns: flow entry.
511 from vpp_papi import VppEnum
513 cmd = u"vppctl show flow entry"
515 err_msg = u"Failed to show flow on host {node[u'host']}"
516 stdout, _ = exec_cmd_no_error(
517 node, cmd, sudo=False, message=err_msg, retries=120
520 return stdout.strip()
523 def vpp_verify_flow_action(
525 src_mac=u"11:22:33:44:55:66", dst_mac=u"11:22:33:44:55:66",
526 src_ip=None, dst_ip=None):
527 """Verify the correctness of the flow action.
529 :param node: DUT node.
530 :param action: Action.
531 :param value: Action value.
532 :param src_mac: Source mac address.
533 :param dst_mac: Destination mac address.
534 :param src_ip: Source IP address.
535 :param dst_ip: Destination IP address.
545 :raises RuntimeError: If the verification of flow action fails.
546 :raises ValueError: If action type is not supported.
548 from vpp_papi import VppEnum
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}")