35077d8268733d6a167b86f43905aaa741d167a8
[csit.git] / resources / libraries / python / InterfaceUtil.py
1 # Copyright (c) 2016 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:
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
14 """Interface util library"""
15
16 from time import time, sleep
17
18 from robot.api import logger
19
20 from resources.libraries.python.ssh import SSH
21 from resources.libraries.python.IPUtil import convert_ipv4_netmask_prefix
22 from resources.libraries.python.ssh import exec_cmd_no_error
23 from resources.libraries.python.topology import NodeType, Topology
24 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
25 from resources.libraries.python.VatJsonUtil import VatJsonUtil
26 from resources.libraries.python.parsers.JsonParser import JsonParser
27
28
29 class InterfaceUtil(object):
30     """General utilities for managing interfaces"""
31
32     __UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules'
33
34     @staticmethod
35     def set_interface_state(node, interface, state):
36         """Set interface state on a node.
37
38         Function can be used for DUTs as well as for TGs.
39
40         :param node: Node where the interface is.
41         :param interface: Interface name or sw_if_index.
42         :param state: One of 'up' or 'down'.
43         :type node: dict
44         :type interface: str or int
45         :type state: str
46         :return: nothing
47         """
48         if node['type'] == NodeType.DUT:
49             if state == 'up':
50                 state = 'admin-up'
51             elif state == 'down':
52                 state = 'admin-down'
53             else:
54                 raise ValueError('Unexpected interface state: {}'.format(state))
55
56             if isinstance(interface, basestring):
57                 sw_if_index = Topology.get_interface_sw_index(node, interface)
58             else:
59                 sw_if_index = interface
60
61             VatExecutor.cmd_from_template(node, 'set_if_state.vat',
62                                           sw_if_index=sw_if_index, state=state)
63
64         elif node['type'] == NodeType.TG or node['type'] == NodeType.VM:
65             cmd = 'ip link set {} {}'.format(interface, state)
66             exec_cmd_no_error(node, cmd, sudo=True)
67         else:
68             raise Exception('Node {} has unknown NodeType: "{}"'.
69                             format(node['host'], node['type']))
70
71     @staticmethod
72     def set_interface_ethernet_mtu(node, interface, mtu):
73         """Set Ethernet MTU for specified interface.
74
75         Function can be used only for TGs.
76
77         :param node: Node where the interface is.
78         :param interface: Interface name.
79         :param mtu: MTU to set.
80         :type node: dict
81         :type interface: str
82         :type mtu: int
83         :return: nothing
84         """
85         if node['type'] == NodeType.DUT:
86             ValueError('Node {}: Setting Ethernet MTU for interface '
87                        'on DUT nodes not supported', node['host'])
88         elif node['type'] == NodeType.TG:
89             cmd = 'ip link set {} mtu {}'.format(interface, mtu)
90             exec_cmd_no_error(node, cmd, sudo=True)
91         else:
92             raise ValueError('Node {} has unknown NodeType: "{}"'.
93                              format(node['host'], node['type']))
94
95     @staticmethod
96     def set_default_ethernet_mtu_on_all_interfaces_on_node(node):
97         """Set default Ethernet MTU on all interfaces on node.
98
99         Function can be used only for TGs.
100
101         :param node: Node where to set default MTU.
102         :type node: dict
103         :return: nothing
104         """
105         for ifc in node['interfaces'].values():
106             InterfaceUtil.set_interface_ethernet_mtu(node, ifc['name'], 1500)
107
108     @staticmethod
109     def vpp_node_interfaces_ready_wait(node, timeout=10):
110         """Wait until all interfaces with admin-up are in link-up state.
111
112         :param node: Node to wait on.
113         :param timeout: Waiting timeout in seconds (optional, default 10s).
114         :type node: dict
115         :type timeout: int
116         :raises: RuntimeError if the timeout period value has elapsed.
117         """
118         if_ready = False
119         not_ready = []
120         start = time()
121         while not if_ready:
122             out = InterfaceUtil.vpp_get_interface_data(node)
123             if time() - start > timeout:
124                 for interface in out:
125                     if interface.get('admin_up_down') == 1:
126                         if interface.get('link_up_down') != 1:
127                             logger.debug('{0} link-down'.format(
128                                 interface.get('interface_name')))
129                 raise RuntimeError('timeout, not up {0}'.format(not_ready))
130             not_ready = []
131             for interface in out:
132                 if interface.get('admin_up_down') == 1:
133                     if interface.get('link_up_down') != 1:
134                         not_ready.append(interface.get('interface_name'))
135             if not not_ready:
136                 if_ready = True
137             else:
138                 logger.debug('Interfaces still in link-down state: {0}, '
139                              'waiting...'.format(not_ready))
140                 sleep(1)
141
142     @staticmethod
143     def vpp_nodes_interfaces_ready_wait(nodes, timeout=10):
144         """Wait until all interfaces with admin-up are in link-up state for
145         listed nodes.
146
147         :param nodes: List of nodes to wait on.
148         :param timeout: Seconds to wait per node for all interfaces to come up.
149         :type nodes: list
150         :type timeout: int
151         :raises: RuntimeError if the timeout period value has elapsed.
152         """
153         for node in nodes:
154             InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
155
156     @staticmethod
157     def all_vpp_interfaces_ready_wait(nodes, timeout=10):
158         """Wait until all interfaces with admin-up are in link-up state for all
159         nodes in the topology.
160
161         :param nodes: Nodes in the topology.
162         :param timeout: Seconds to wait per node for all interfaces to come up.
163         :type nodes: dict
164         :type timeout: int
165         :raises: RuntimeError if the timeout period value has elapsed.
166         """
167         for node in nodes.values():
168             if node['type'] == NodeType.DUT:
169                 InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
170
171     @staticmethod
172     def vpp_get_interface_data(node, interface=None):
173         """Get all interface data from a VPP node. If a name or
174         sw_interface_index is provided, return only data for the matching
175         interface.
176
177         :param node: VPP node to get interface data from.
178         :param interface: Numeric index or name string of a specific interface.
179         :type node: dict
180         :type interface: int or str
181         :return: List of dictionaries containing data for each interface, or a
182         single dictionary for the specified interface.
183         :rtype: list or dict
184         """
185         with VatTerminal(node) as vat:
186             response = vat.vat_terminal_exec_cmd_from_template(
187                 "interface_dump.vat")
188
189         data = response[0]
190
191         if interface is not None:
192             if isinstance(interface, basestring):
193                 param = "interface_name"
194             elif isinstance(interface, int):
195                 param = "sw_if_index"
196             else:
197                 raise TypeError
198             for data_if in data:
199                 if data_if[param] == interface:
200                     return data_if
201             return dict()
202         return data
203
204     @staticmethod
205     def vpp_get_interface_ip_addresses(node, interface, ip_version):
206         """Get list of IP addresses from an interface on a VPP node.
207
208          :param node: VPP node to get data from.
209          :param interface: Name of an interface on the VPP node.
210          :param ip_version: IP protocol version (ipv4 or ipv6).
211          :type node: dict
212          :type interface: str
213          :type ip_version: str
214          :return: List of dictionaries, each containing IP address, subnet
215          prefix length and also the subnet mask for ipv4 addresses.
216          Note: A single interface may have multiple IP addresses assigned.
217          :rtype: list
218         """
219         sw_if_index = Topology.get_interface_sw_index(node, interface)
220
221         with VatTerminal(node) as vat:
222             response = vat.vat_terminal_exec_cmd_from_template(
223                 "ip_address_dump.vat", ip_version=ip_version,
224                 sw_if_index=sw_if_index)
225
226         data = response[0]
227
228         if ip_version == "ipv4":
229             for item in data:
230                 item["netmask"] = convert_ipv4_netmask_prefix(
231                     item["prefix_length"])
232         return data
233
234     @staticmethod
235     def tg_set_interface_driver(node, pci_addr, driver):
236         """Set interface driver on the TG node.
237
238         :param node: Node to set interface driver on (must be TG node).
239         :param pci_addr: PCI address of the interface.
240         :param driver: Driver name.
241         :type node: dict
242         :type pci_addr: str
243         :type driver: str
244         """
245         old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr)
246         if old_driver == driver:
247             return
248
249         ssh = SSH()
250         ssh.connect(node)
251
252         # Unbind from current driver
253         if old_driver is not None:
254             cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'.format(
255                 pci_addr, old_driver)
256             (ret_code, _, _) = ssh.exec_command_sudo(cmd)
257             if int(ret_code) != 0:
258                 raise Exception("'{0}' failed on '{1}'".format(cmd,
259                                                                node['host']))
260
261         # Bind to the new driver
262         cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'.format(
263             pci_addr, driver)
264         (ret_code, _, _) = ssh.exec_command_sudo(cmd)
265         if int(ret_code) != 0:
266             raise Exception("'{0}' failed on '{1}'".format(cmd, node['host']))
267
268     @staticmethod
269     def tg_get_interface_driver(node, pci_addr):
270         """Get interface driver from the TG node.
271
272         :param node: Node to get interface driver on (must be TG node).
273         :param pci_addr: PCI address of the interface.
274         :type node: dict
275         :type pci_addr: str
276         :return: Interface driver or None if not found.
277         :rtype: str
278
279         .. note::
280             # lspci -vmmks 0000:00:05.0
281             Slot:   00:05.0
282             Class:  Ethernet controller
283             Vendor: Red Hat, Inc
284             Device: Virtio network device
285             SVendor:        Red Hat, Inc
286             SDevice:        Device 0001
287             PhySlot:        5
288             Driver: virtio-pci
289         """
290         ssh = SSH()
291         ssh.connect(node)
292
293         cmd = 'lspci -vmmks {0}'.format(pci_addr)
294
295         (ret_code, stdout, _) = ssh.exec_command(cmd)
296         if int(ret_code) != 0:
297             raise Exception("'{0}' failed on '{1}'".format(cmd, node['host']))
298
299         for line in stdout.splitlines():
300             if len(line) == 0:
301                 continue
302             (name, value) = line.split("\t", 1)
303             if name == 'Driver:':
304                 return value
305
306         return None
307
308     @staticmethod
309     def tg_set_interfaces_udev_rules(node):
310         """Set udev rules for interfaces.
311
312         Create udev rules file in /etc/udev/rules.d where are rules for each
313         interface used by TG node, based on MAC interface has specific name.
314         So after unbind and bind again to kernel driver interface has same
315         name as before. This must be called after TG has set name for each
316         port in topology dictionary.
317         udev rule example
318         SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f",
319         NAME="eth1"
320
321         :param node: Node to set udev rules on (must be TG node).
322         :type node: dict
323         """
324         ssh = SSH()
325         ssh.connect(node)
326
327         cmd = 'rm -f {0}'.format(InterfaceUtil.__UDEV_IF_RULES_FILE)
328         (ret_code, _, _) = ssh.exec_command_sudo(cmd)
329         if int(ret_code) != 0:
330             raise Exception("'{0}' failed on '{1}'".format(cmd, node['host']))
331
332         for interface in node['interfaces'].values():
333             rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \
334                    '==\\"' + interface['mac_address'] + '\\", NAME=\\"' + \
335                    interface['name'] + '\\"'
336             cmd = 'sh -c "echo \'{0}\' >> {1}"'.format(
337                 rule, InterfaceUtil.__UDEV_IF_RULES_FILE)
338             (ret_code, _, _) = ssh.exec_command_sudo(cmd)
339             if int(ret_code) != 0:
340                 raise Exception("'{0}' failed on '{1}'".format(cmd,
341                                                                node['host']))
342
343         cmd = '/etc/init.d/udev restart'
344         ssh.exec_command_sudo(cmd)
345
346     @staticmethod
347     def tg_set_interfaces_default_driver(node):
348         """Set interfaces default driver specified in topology yaml file.
349
350         :param node: Node to setup interfaces driver on (must be TG node).
351         :type node: dict
352         """
353         for interface in node['interfaces'].values():
354             InterfaceUtil.tg_set_interface_driver(node,
355                                                   interface['pci_address'],
356                                                   interface['driver'])
357
358     @staticmethod
359     def update_vpp_interface_data_on_node(node):
360         """Update vpp generated interface data for a given node in DICT__nodes.
361
362         Updates interface names, software if index numbers and any other details
363         generated specifically by vpp that are unknown before testcase run.
364         It does this by dumping interface list to JSON output from all
365         devices using vpp_api_test, and pairing known information from topology
366         (mac address/pci address of interface) to state from VPP.
367
368         :param node: Node selected from DICT__nodes.
369         :type node: dict
370         """
371         vat_executor = VatExecutor()
372         vat_executor.execute_script_json_out("dump_interfaces.vat", node)
373         interface_dump_json = vat_executor.get_script_stdout()
374         VatJsonUtil.update_vpp_interface_data_from_json(node,
375                                                         interface_dump_json)
376
377     @staticmethod
378     def update_tg_interface_data_on_node(node):
379         """Update interface name for TG/linux node in DICT__nodes.
380
381         :param node: Node selected from DICT__nodes.
382         :type node: dict
383
384         .. note::
385             # for dev in `ls /sys/class/net/`;
386             > do echo "\"`cat /sys/class/net/$dev/address`\": \"$dev\""; done
387             "52:54:00:9f:82:63": "eth0"
388             "52:54:00:77:ae:a9": "eth1"
389             "52:54:00:e1:8a:0f": "eth2"
390             "00:00:00:00:00:00": "lo"
391
392         .. todo:: parse lshw -json instead
393         """
394         # First setup interface driver specified in yaml file
395         InterfaceUtil.tg_set_interfaces_default_driver(node)
396
397         # Get interface names
398         ssh = SSH()
399         ssh.connect(node)
400
401         cmd = ('for dev in `ls /sys/class/net/`; do echo "\\"`cat '
402                '/sys/class/net/$dev/address`\\": \\"$dev\\""; done;')
403
404         (ret_code, stdout, _) = ssh.exec_command(cmd)
405         if int(ret_code) != 0:
406             raise Exception('Get interface name and MAC failed')
407         tmp = "{" + stdout.rstrip().replace('\n', ',') + "}"
408         interfaces = JsonParser().parse_data(tmp)
409         for interface in node['interfaces'].values():
410             name = interfaces.get(interface['mac_address'])
411             if name is None:
412                 continue
413             interface['name'] = name
414
415         # Set udev rules for interfaces
416         InterfaceUtil.tg_set_interfaces_udev_rules(node)
417
418     @staticmethod
419     def update_all_interface_data_on_all_nodes(nodes):
420         """Update interface names on all nodes in DICT__nodes.
421
422         This method updates the topology dictionary by querying interface lists
423         of all nodes mentioned in the topology dictionary.
424
425         :param nodes: Nodes in the topology.
426         :type nodes: dict
427         """
428         for node_data in nodes.values():
429             if node_data['type'] == NodeType.DUT:
430                 InterfaceUtil.update_vpp_interface_data_on_node(node_data)
431             elif node_data['type'] == NodeType.TG:
432                 InterfaceUtil.update_tg_interface_data_on_node(node_data)
433
434     @staticmethod
435     def create_vlan_subinterface(node, interface, vlan):
436         """Create VLAN subinterface on node.
437
438         :param node: Node to add VLAN subinterface on.
439         :param interface: Interface name on which create VLAN subinterface.
440         :param vlan: VLAN ID of the subinterface to be created.
441         :type node: dict
442         :type interface: str
443         :type vlan: int
444         :return: Name and index of created subinterface.
445         :rtype: tuple
446         """
447         sw_if_index = Topology.get_interface_sw_index(node, interface)
448
449         output = VatExecutor.cmd_from_template(node, "create_vlan_subif.vat",
450                                                sw_if_index=sw_if_index,
451                                                vlan=vlan)
452         if output[0]["retval"] == 0:
453             sw_subif_index = output[0]["sw_if_index"]
454             logger.trace('VLAN subinterface with sw_if_index {} and VLAN ID {} '
455                          'created on node {}'.format(sw_subif_index,
456                                                      vlan, node['host']))
457         else:
458             raise RuntimeError('Unable to create VLAN subinterface on node {}'
459                                .format(node['host']))
460
461         with VatTerminal(node, False) as vat:
462             vat.vat_terminal_exec_cmd('exec show interfaces')
463
464         return '{}.{}'.format(interface, vlan), sw_subif_index
465
466     @staticmethod
467     def create_vxlan_interface(node, vni, source_ip, destination_ip):
468         """Create VXLAN interface and return sw if index of created interface.
469
470         Executes "vxlan_add_del_tunnel src {src} dst {dst} vni {vni}" VAT
471         command on the node.
472
473         :param node: Node where to create VXLAN interface.
474         :param vni: VXLAN Network Identifier.
475         :param source_ip: Source IP of a VXLAN Tunnel End Point.
476         :param destination_ip: Destination IP of a VXLAN Tunnel End Point.
477         :type node: dict
478         :type vni: int
479         :type source_ip: str
480         :type destination_ip: str
481         :return: SW IF INDEX of created interface.
482         :rtype: int
483         """
484         output = VatExecutor.cmd_from_template(node, "vxlan_create.vat",
485                                                src=source_ip,
486                                                dst=destination_ip,
487                                                vni=vni)
488         output = output[0]
489
490         if output["retval"] == 0:
491             return output["sw_if_index"]
492         else:
493             raise RuntimeError('Unable to create VXLAN interface on node {0}'
494                                .format(node))
495
496     @staticmethod
497     def vxlan_dump(node, interface=None):
498         """Get VxLAN data for the given interface.
499
500         :param node: VPP node to get interface data from.
501         :param interface: Numeric index or name string of a specific interface.
502         If None, information about all VxLAN interfaces is returned.
503         :type node: dict
504         :type interface: int or str
505         :return: Dictionary containing data for the given VxLAN interface or if
506         interface=None, the list of dictionaries with all VxLAN interfaces.
507         :rtype: dict or list
508         """
509         param = "sw_if_index"
510         if interface is None:
511             param = ''
512             sw_if_index = ''
513         elif isinstance(interface, basestring):
514             sw_if_index = Topology.get_interface_sw_index(node, interface)
515         elif isinstance(interface, int):
516             sw_if_index = interface
517         else:
518             raise Exception("Wrong interface format {0}".format(interface))
519
520         with VatTerminal(node) as vat:
521             response = vat.vat_terminal_exec_cmd_from_template(
522                 "vxlan_dump.vat", param=param, sw_if_index=sw_if_index)
523
524         if sw_if_index:
525             for vxlan in response[0]:
526                 if vxlan["sw_if_index"] == sw_if_index:
527                     return vxlan
528             return {}
529         return response[0]
530
531     @staticmethod
532     def vhost_user_dump(node):
533         """Get vhost-user data for the given node.
534
535         :param node: VPP node to get interface data from.
536         :type node: dict
537         :return: List of dictionaries with all vhost-user interfaces.
538         :rtype: list
539         """
540         with VatTerminal(node) as vat:
541             response = vat.vat_terminal_exec_cmd_from_template(
542                 "vhost_user_dump.vat")
543
544         return response[0]
545
546     @staticmethod
547     def tap_dump(node, name=None):
548         """Get all TAP interface data from the given node, or data about
549         a specific TAP interface.
550
551         :param node: VPP node to get data from.
552         :param name: Optional name of a specific TAP interface.
553         :type node: dict
554         :type name: str
555         :return: Dictionary of information about a specific TAP interface, or
556         a List of dictionaries containing all TAP data for the given node.
557         :rtype: dict or list
558         """
559         with VatTerminal(node) as vat:
560             response = vat.vat_terminal_exec_cmd_from_template(
561                 "tap_dump.vat")
562         if name is None:
563             return response[0]
564         else:
565             for item in response[0]:
566                 if name == item['dev_name']:
567                     return item
568             return {}
569
570     @staticmethod
571     def create_subinterface(node, interface, sub_id, outer_vlan_id,
572                             inner_vlan_id, type_subif):
573         """Create sub-interface on node.
574
575         :param node: Node to add sub-interface.
576         :param interface: Interface name on which create sub-interface.
577         :param sub_id: ID of the sub-interface to be created.
578         :param outer_vlan_id: Outer VLAN ID.
579         :param inner_vlan_id: Inner VLAN ID.
580         :param type_subif: Type of sub-interface.
581         :type node: dict
582         :type interface: str or int
583         :type sub_id: int
584         :type outer_vlan_id: int
585         :type inner_vlan_id: int
586         :type type_subif: str
587         :return: name and index of created sub-interface
588         :rtype: tuple
589         """
590
591         if isinstance(interface, basestring):
592             sw_if_index = Topology.get_interface_sw_index(node, interface)
593         else:
594             sw_if_index = interface
595
596         output = VatExecutor.cmd_from_template(node, "create_sub_interface.vat",
597                                                sw_if_index=sw_if_index,
598                                                sub_id=sub_id,
599                                                outer_vlan_id=outer_vlan_id,
600                                                inner_vlan_id=inner_vlan_id,
601                                                type_subif=type_subif)
602
603         if output[0]["retval"] == 0:
604             sw_subif_index = output[0]["sw_if_index"]
605             logger.trace('Created subinterface with index {}'
606                          .format(sw_subif_index))
607         else:
608             raise RuntimeError('Unable to create subinterface on node {}'
609                                .format(node['host']))
610
611         with VatTerminal(node) as vat:
612             vat.vat_terminal_exec_cmd('exec show interfaces')
613
614         name = '{}.{}'.format(interface, sub_id)
615         return name, sw_subif_index
616
617     @staticmethod
618     def create_gre_tunnel_interface(node, source_ip, destination_ip):
619         """Create GRE tunnel interface on node.
620
621         :param node: VPP node to add tunnel interface.
622         :param source_ip: Source of the GRE tunnel.
623         :param destination_ip: Destination of the GRE tunnel.
624         :type node: dict
625         :type source_ip: str
626         :type destination_ip: str
627         :return: Name and index of created GRE tunnel interface.
628         :rtype: tuple
629         :raises RuntimeError: If unable to create GRE tunnel interface.
630         """
631         output = VatExecutor.cmd_from_template(node, "create_gre.vat",
632                                                src=source_ip,
633                                                dst=destination_ip)
634         output = output[0]
635
636         if output["retval"] == 0:
637             sw_if_index = output["sw_if_index"]
638
639             vat_executor = VatExecutor()
640             vat_executor.execute_script_json_out("dump_interfaces.vat", node)
641             interface_dump_json = vat_executor.get_script_stdout()
642             name = VatJsonUtil.get_interface_name_from_json(
643                 interface_dump_json, sw_if_index)
644             return name, sw_if_index
645         else:
646             raise RuntimeError('Unable to create GRE tunnel on node {}.'
647                                .format(node))
648
649     @staticmethod
650     def vpp_create_loopback(node):
651         """Create loopback interface on VPP node.
652
653         :param node: Node to create loopback interface on.
654         :type node: dict
655         :return: SW interface index.
656         :rtype: int
657         """
658         out = VatExecutor.cmd_from_template(node, "create_loopback.vat")
659         if out[0].get('retval') == 0:
660             return out[0].get('sw_if_index')
661         else:
662             raise RuntimeError('Create loopback failed on node "{}"'
663                                .format(node['host']))
664
665     @staticmethod
666     def vpp_enable_input_acl_interface(node, interface, ip_version,
667                                        table_index):
668         """Enable input acl on interface.
669
670         :param node: VPP node to setup interface for input acl.
671         :param interface: Interface to setup input acl.
672         :param ip_version: Version of IP protocol.
673         :param table_index: Classify table index.
674         :type node: dict
675         :type interface: str or int
676         :type ip_version: str
677         :type table_index: int
678         """
679         if isinstance(interface, basestring):
680             sw_if_index = Topology.get_interface_sw_index(node, interface)
681         else:
682             sw_if_index = interface
683
684         with VatTerminal(node) as vat:
685             vat.vat_terminal_exec_cmd_from_template("input_acl_int.vat",
686                                                     sw_if_index=sw_if_index,
687                                                     ip_version=ip_version,
688                                                     table_index=table_index)