1 # Copyright (c) 2017 Cisco 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 """Classify utilities library."""
16 from robot.api import logger
18 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
19 from resources.libraries.python.topology import Topology
22 class Classify(object):
23 """Classify utilities."""
26 def vpp_creates_classify_table_l3(node, ip_version, direction):
27 """Create classify table for IP address filtering.
29 :param node: VPP node to create classify table.
30 :param ip_version: Version of IP protocol.
31 :param direction: Direction of traffic - src/dst.
35 :returns (table_index, skip_n, match_n)
36 table_index: Classify table index.
37 skip_n: Number of skip vectors.
38 match_n: Number of match vectors.
39 :rtype: tuple(int, int, int)
40 :raises RuntimeError: If VPP can't create table.
43 output = VatExecutor.cmd_from_template(node, "classify_add_table.vat",
44 ip_version=ip_version,
47 if output[0]["retval"] == 0:
48 table_index = output[0]["new_table_index"]
49 skip_n = output[0]["skip_n_vectors"]
50 match_n = output[0]["match_n_vectors"]
51 logger.trace('Classify table with table_index {} created on node {}'
52 .format(table_index, node['host']))
54 raise RuntimeError('Unable to create classify table on node {}'
55 .format(node['host']))
57 return table_index, skip_n, match_n
60 def vpp_creates_classify_table_l2(node, direction):
61 """Create classify table for MAC address filtering.
63 :param node: VPP node to create classify table.
64 :param direction: Direction of traffic - src/dst.
67 :returns (table_index, skip_n, match_n)
68 table_index: Classify table index.
69 skip_n: Number of skip vectors.
70 match_n: Number of match vectors.
71 :rtype: tuple(int, int, int)
72 :raises RuntimeError: If VPP can't create table.
74 output = VatExecutor.cmd_from_template(node,
75 "classify_add_table_l2.vat",
78 if output[0]["retval"] == 0:
79 table_index = output[0]["new_table_index"]
80 skip_n = output[0]["skip_n_vectors"]
81 match_n = output[0]["match_n_vectors"]
82 logger.trace('Classify table with table_index {} created on node {}'
83 .format(table_index, node['host']))
85 raise RuntimeError('Unable to create classify table on node {}'
86 .format(node['host']))
88 return table_index, skip_n, match_n
91 def vpp_creates_classify_table_hex(node, hex_mask):
92 """Create classify table with hex mask.
94 :param node: VPP node to create classify table based on hex mask.
95 :param hex_mask: Classify hex mask.
98 :returns (table_index, skip_n, match_n)
99 table_index: Classify table index.
100 skip_n: Number of skip vectors.
101 match_n: Number of match vectors.
102 :rtype: tuple(int, int, int)
103 :raises RuntimeError: If VPP can't create table.
105 output = VatExecutor.cmd_from_template(node,
106 "classify_add_table_hex.vat",
109 if output[0]["retval"] == 0:
110 table_index = output[0]["new_table_index"]
111 skip_n = output[0]["skip_n_vectors"]
112 match_n = output[0]["match_n_vectors"]
113 logger.trace('Classify table with table_index {} created on node {}'
114 .format(table_index, node['host']))
116 raise RuntimeError('Unable to create classify table on node {}'
117 .format(node['host']))
119 return table_index, skip_n, match_n
122 def vpp_configures_classify_session_l3(node, acl_method, table_index,
123 skip_n, match_n, ip_version,
125 """Configuration of classify session for IP address filtering.
127 :param node: VPP node to setup classify session.
128 :param acl_method: ACL method - deny/permit.
129 :param table_index: Classify table index.
130 :param skip_n: Number of skip vectors based on mask.
131 :param match_n: Number of match vectors based on mask.
132 :param ip_version: Version of IP protocol.
133 :param direction: Direction of traffic - src/dst.
134 :param address: IPv4 or IPv6 address.
136 :type acl_method: str
137 :type table_index: int
140 :type ip_version: str
144 with VatTerminal(node) as vat:
145 vat.vat_terminal_exec_cmd_from_template("classify_add_session.vat",
146 acl_method=acl_method,
147 table_index=table_index,
150 ip_version=ip_version,
155 def vpp_configures_classify_session_l2(node, acl_method, table_index,
156 skip_n, match_n, direction, address):
157 """Configuration of classify session for MAC address filtering.
159 :param node: VPP node to setup classify session.
160 :param acl_method: ACL method - deny/permit.
161 :param table_index: Classify table index.
162 :param skip_n: Number of skip vectors based on mask.
163 :param match_n: Number of match vectors based on mask.
164 :param direction: Direction of traffic - src/dst.
165 :param address: IPv4 or IPv6 address.
167 :type acl_method: str
168 :type table_index: int
174 with VatTerminal(node) as vat:
175 vat.vat_terminal_exec_cmd_from_template(
176 "classify_add_session_l2.vat",
177 acl_method=acl_method,
178 table_index=table_index,
185 def vpp_configures_classify_session_hex(node, acl_method, table_index,
186 skip_n, match_n, hex_value):
187 """Configuration of classify session with hex value.
189 :param node: VPP node to setup classify session.
190 :param acl_method: ACL method - deny/permit.
191 :param table_index: Classify table index.
192 :param skip_n: Number of skip vectors based on mask.
193 :param match_n: Number of match vectors based on mask.
194 :param hex_value: Classify hex value.
196 :type acl_method: str
197 :type table_index: int
202 with VatTerminal(node) as vat:
203 vat.vat_terminal_exec_cmd_from_template(
204 "classify_add_session_hex.vat",
205 acl_method=acl_method,
206 table_index=table_index,
212 def vpp_configures_classify_session_generic(node, session_type, table_index,
213 skip_n, match_n, match,
215 """Configuration of classify session.
217 :param node: VPP node to setup classify session.
218 :param session_type: Session type - hit-next, l2-hit-next, acl-hit-next
219 or policer-hit-next, and their respective parameters.
220 :param table_index: Classify table index.
221 :param skip_n: Number of skip vectors based on mask.
222 :param match_n: Number of match vectors based on mask.
223 :param match: Match value - l2, l3, l4 or hex, and their
224 respective parameters.
225 :param match2: Additional match values, to avoid using overly long
226 variables in RobotFramework.
228 :type session_type: str
229 :type table_index: int
236 match = ' '.join((match, match2))
238 with VatTerminal(node) as vat:
239 vat.vat_terminal_exec_cmd_from_template(
240 "classify_add_session_generic.vat",
242 table_index=table_index,
249 def compute_classify_hex_mask(ip_version, protocol, direction):
250 """Compute classify hex mask for TCP or UDP packet matching.
252 :param ip_version: Version of IP protocol.
253 :param protocol: Type of protocol.
254 :param direction: Traffic direction.
255 :type ip_version: str
258 :returns: Classify hex mask.
260 :raises ValueError: If protocol is not TCP or UDP.
261 :raises ValueError: If direction is not source or destination or
262 source + destination.
264 if protocol == 'TCP' or protocol == 'UDP':
265 base_mask = Classify._compute_base_mask(ip_version)
267 if direction == 'source':
268 return base_mask + 'FFFF0000'
269 elif direction == 'destination':
270 return base_mask + '0000FFFF'
271 elif direction == 'source + destination':
272 return base_mask + 'FFFFFFFF'
274 raise ValueError("Invalid direction!")
276 raise ValueError("Invalid protocol!")
279 def compute_classify_hex_value(hex_mask, source_port, destination_port):
280 """Compute classify hex value for TCP or UDP packet matching.
282 :param hex_mask: Classify hex mask.
283 :param source_port: Source TCP/UDP port.
284 :param destination_port: Destination TCP/UDP port.
286 :type source_port: str
287 :type destination_port: str
288 :returns: Classify hex value.
291 source_port_hex = Classify._port_convert(source_port)
292 destination_port_hex = Classify._port_convert(destination_port)
294 return hex_mask[:-8] + source_port_hex + destination_port_hex
297 def _port_convert(port):
298 """Convert port number for classify hex table format.
300 :param port: TCP/UDP port number.
302 :returns: TCP/UDP port number in 4-digit hexadecimal format.
305 return '{0:04x}'.format(int(port))
308 def _compute_base_mask(ip_version):
309 """Compute base classify hex mask based on IP version.
311 :param ip_version: Version of IP protocol.
312 :type ip_version: str
313 :return: Base hex mask.
316 if ip_version == 'ip4':
318 # base value of classify hex table for IPv4 TCP/UDP ports
319 elif ip_version == 'ip6':
321 # base value of classify hex table for IPv6 TCP/UDP ports
323 raise ValueError("Invalid IP version!")
326 def get_classify_table_data(node, table_index):
327 """Retrieve settings for classify table by ID.
329 :param node: VPP node to retrieve classify data from.
330 :param table_index: Index of a specific classify table.
332 :type table_index: int
333 :returns: Classify table settings.
336 with VatTerminal(node) as vat:
337 data = vat.vat_terminal_exec_cmd_from_template(
338 "classify_table_info.vat",
344 def get_classify_session_data(node, table_index, session_index=None):
345 """Retrieve settings for all classify sessions in a table,
346 or for a specific classify session.
348 :param node: VPP node to retrieve classify data from.
349 :param table_index: Index of a classify table.
350 :param session_index: Index of a specific classify session. (Optional)
352 :type table_index: int
353 :type session_index: int
354 :returns: List of classify session settings, or a dictionary of settings
355 for a specific classify session.
358 with VatTerminal(node) as vat:
359 data = vat.vat_terminal_exec_cmd_from_template(
360 "classify_session_dump.vat",
363 if session_index is not None:
364 return data[0][session_index]
369 def vpp_log_plugin_acl_settings(node):
370 """Retrieve configured settings from the ACL plugin
371 and write to robot log.
373 :param node: VPP node.
377 VatExecutor.cmd_from_template(
378 node, "acl_plugin/acl_dump.vat")
379 except (ValueError, RuntimeError):
380 # Fails to parse JSON data in response, but it is still logged
384 def vpp_log_plugin_acl_interface_assignment(node):
385 """Retrieve interface assignment from the ACL plugin
386 and write to robot log.
388 :param node: VPP node.
392 VatExecutor.cmd_from_template(
393 node, "acl_plugin/acl_interface_dump.vat", json_out=False)
395 # Fails to parse response, but it is still logged
399 def set_acl_list_for_interface(node, interface, acl_type, acl_idx=None):
400 """Set the list of input or output ACLs applied to the interface. It
401 unapplies any previously applied ACLs.
403 :param node: VPP node to set ACL on.
404 :param interface: Interface name or sw_if_index.
405 :param acl_type: Type of ACL(s) - input or output.
406 :param acl_idx: Index(ies) of ACLs to be applied on the interface.
408 :type interface: str or int
411 :raises RuntimeError: If unable to set ACL list for the interface.
413 sw_if_index = Topology.get_interface_sw_index(node, interface) \
414 if isinstance(interface, basestring) else interface
416 acl_list = acl_type + ' ' + ' '.join(str(idx) for idx in acl_idx) \
417 if acl_idx else acl_type
420 with VatTerminal(node, json_param=False) as vat:
421 vat.vat_terminal_exec_cmd_from_template(
422 "acl_plugin/acl_interface_set_acl_list.vat",
423 interface=sw_if_index, acl_list=acl_list)
425 raise RuntimeError("Setting of ACL list for interface {0} failed "
426 "on node {1}".format(interface, node['host']))
429 def add_replace_acl(node, acl_idx=None, ip_ver="ipv4", action="permit",
430 src=None, dst=None, sport=None, dport=None, proto=None,
431 tcpflg_val=None, tcpflg_mask=None):
432 """Add a new ACL or replace the existing one. To replace an existing
433 ACL, pass the ID of this ACL.
435 :param node: VPP node to set ACL on.
436 :param acl_idx: ID of ACL. (Optional)
437 :param ip_ver: IP version. (Optional)
438 :param action: ACL action. (Optional)
439 :param src: Source IP in format IP/plen. (Optional)
440 :param dst: Destination IP in format IP/plen. (Optional)
441 :param sport: Source port or ICMP4/6 type - range format X-Y allowed.
443 :param dport: Destination port or ICMP4/6 code - range format X-Y
445 :param proto: L4 protocol (http://www.iana.org/assignments/protocol-
446 numbers/protocol-numbers.xhtml). (Optional)
447 :param tcpflg_val: TCP flags value. (Optional)
448 :param tcpflg_mask: TCP flags mask. (Optional)
455 :type sport: str or int
456 :type dport: str or int
458 :type tcpflg_val: int
459 :type tcpflg_mask: int
460 :raises RuntimeError: If unable to add or replace ACL.
462 acl_idx = '{0}'.format(acl_idx) if acl_idx else ''
464 src = 'src {0}'.format(src) if src else ''
466 dst = 'dst {0}'.format(dst) if dst else ''
468 sport = 'sport {0}'.format(sport) if sport else ''
470 dport = 'dport {0}'.format(dport) if dport else ''
472 proto = 'proto {0}'.format(proto) if proto else ''
474 tcpflags = 'tcpflags {0} {1}'.format(tcpflg_val, tcpflg_mask) \
475 if tcpflg_val and tcpflg_mask else ''
478 with VatTerminal(node, json_param=False) as vat:
479 vat.vat_terminal_exec_cmd_from_template(
480 "acl_plugin/acl_add_replace.vat", acl_idx=acl_idx,
481 ip_ver=ip_ver, action=action, src=src, dst=dst, sport=sport,
482 dport=dport, proto=proto, tcpflags=tcpflags)
484 raise RuntimeError("Adding or replacing of ACL failed on "
485 "node {0}".format(node['host']))
488 def add_replace_acl_multi_entries(node, acl_idx=None, rules=None):
489 """Add a new ACL or replace the existing one. To replace an existing
490 ACL, pass the ID of this ACL.
492 :param node: VPP node to set ACL on.
493 :param acl_idx: ID of ACL. (Optional)
494 :param rules: Required rules. (Optional)
498 :raises RuntimeError: If unable to add or replace ACL.
500 acl_idx = '{0}'.format(acl_idx) if acl_idx else ''
502 rules = '{0}'.format(rules) if rules else ''
505 with VatTerminal(node, json_param=False) as vat:
506 vat.vat_terminal_exec_cmd_from_template(
507 "acl_plugin/acl_add_replace.vat", acl_idx=acl_idx,
508 ip_ver=rules, action='', src='', dst='', sport='',
509 dport='', proto='', tcpflags='')
511 raise RuntimeError("Adding or replacing of ACL failed on "
512 "node {0}".format(node['host']))
515 def delete_acl(node, idx):
516 """Delete required ACL.
518 :param node: VPP node to delete ACL on.
519 :param idx: Index of ACL to be deleted.
521 :type idx: int or str
522 :raises RuntimeError: If unable to delete ACL.
525 with VatTerminal(node, json_param=False) as vat:
526 vat.vat_terminal_exec_cmd_from_template(
527 "acl_plugin/acl_delete.vat", idx=idx)
529 raise RuntimeError("Deletion of ACL failed on node {0}".
530 format(node['host']))
533 def cli_show_acl(node, acl_idx=None):
536 :param node: VPP node to show ACL on.
537 :param acl_idx: Index of ACL to be shown.
539 :type acl_idx: int or str
540 :raises RuntimeError: If unable to delete ACL.
542 acl_idx = '{0}'.format(acl_idx) if acl_idx else ''
545 with VatTerminal(node, json_param=False) as vat:
546 vat.vat_terminal_exec_cmd_from_template(
547 "acl_plugin/show_acl.vat", idx=acl_idx)
549 raise RuntimeError("Failed to show ACL on node {0}".
550 format(node['host']))