CSIT-843: Update actual topology in case of new/updated/deleted interface
[csit.git] / resources / libraries / python / Classify.py
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:
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 """Classify utilities library."""
15
16 from robot.api import logger
17
18 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
19 from resources.libraries.python.topology import Topology
20
21
22 class Classify(object):
23     """Classify utilities."""
24
25     @staticmethod
26     def vpp_creates_classify_table_l3(node, ip_version, direction):
27         """Create classify table for IP address filtering.
28
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.
32         :type node: dict
33         :type ip_version: str
34         :type direction: str
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.
41         """
42
43         output = VatExecutor.cmd_from_template(node, "classify_add_table.vat",
44                                                ip_version=ip_version,
45                                                direction=direction)
46
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']))
53         else:
54             raise RuntimeError('Unable to create classify table on node {}'
55                                .format(node['host']))
56
57         return table_index, skip_n, match_n
58
59     @staticmethod
60     def vpp_creates_classify_table_l2(node, direction):
61         """Create classify table for MAC address filtering.
62
63         :param node: VPP node to create classify table.
64         :param direction: Direction of traffic - src/dst.
65         :type node: dict
66         :type direction: str
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.
73         """
74         output = VatExecutor.cmd_from_template(node,
75                                                "classify_add_table_l2.vat",
76                                                direction=direction)
77
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']))
84         else:
85             raise RuntimeError('Unable to create classify table on node {}'
86                                .format(node['host']))
87
88         return table_index, skip_n, match_n
89
90     @staticmethod
91     def vpp_creates_classify_table_hex(node, hex_mask):
92         """Create classify table with hex mask.
93
94         :param node: VPP node to create classify table based on hex mask.
95         :param hex_mask: Classify hex mask.
96         :type node: dict
97         :type hex_mask: str
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.
104         """
105         output = VatExecutor.cmd_from_template(node,
106                                                "classify_add_table_hex.vat",
107                                                hex_mask=hex_mask)
108
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']))
115         else:
116             raise RuntimeError('Unable to create classify table on node {}'
117                                .format(node['host']))
118
119         return table_index, skip_n, match_n
120
121     @staticmethod
122     def vpp_configures_classify_session_l3(node, acl_method, table_index,
123                                            skip_n, match_n, ip_version,
124                                            direction, address):
125         """Configuration of classify session for IP address filtering.
126
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.
135         :type node: dict
136         :type acl_method: str
137         :type table_index: int
138         :type skip_n: int
139         :type match_n: int
140         :type ip_version: str
141         :type direction: str
142         :type address: str
143         """
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,
148                                                     skip_n=skip_n,
149                                                     match_n=match_n,
150                                                     ip_version=ip_version,
151                                                     direction=direction,
152                                                     address=address)
153
154     @staticmethod
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.
158
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.
166         :type node: dict
167         :type acl_method: str
168         :type table_index: int
169         :type skip_n: int
170         :type match_n: int
171         :type direction: str
172         :type address: str
173         """
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,
179                 skip_n=skip_n,
180                 match_n=match_n,
181                 direction=direction,
182                 address=address)
183
184     @staticmethod
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.
188
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.
195         :type node: dict
196         :type acl_method: str
197         :type table_index: int
198         :type skip_n: int
199         :type match_n: int
200         :type hex_value: str
201         """
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,
207                 skip_n=skip_n,
208                 match_n=match_n,
209                 hex_value=hex_value)
210
211     @staticmethod
212     def vpp_configures_classify_session_generic(node, session_type, table_index,
213                                                 skip_n, match_n, match,
214                                                 match2=''):
215         """Configuration of classify session.
216
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.
227         :type node: dict
228         :type session_type: str
229         :type table_index: int
230         :type skip_n: int
231         :type match_n: int
232         :type match: str
233         :type match2: str
234         """
235
236         match = ' '.join((match, match2))
237
238         with VatTerminal(node) as vat:
239             vat.vat_terminal_exec_cmd_from_template(
240                 "classify_add_session_generic.vat",
241                 type=session_type,
242                 table_index=table_index,
243                 skip_n=skip_n,
244                 match_n=match_n,
245                 match=match,
246             )
247
248     @staticmethod
249     def compute_classify_hex_mask(ip_version, protocol, direction):
250         """Compute classify hex mask for TCP or UDP packet matching.
251
252         :param ip_version: Version of IP protocol.
253         :param protocol: Type of protocol.
254         :param direction: Traffic direction.
255         :type ip_version: str
256         :type protocol: str
257         :type direction: str
258         :returns: Classify hex mask.
259         :rtype : str
260         :raises ValueError: If protocol is not TCP or UDP.
261         :raises ValueError: If direction is not source or destination or
262                             source + destination.
263         """
264         if protocol == 'TCP' or protocol == 'UDP':
265             base_mask = Classify._compute_base_mask(ip_version)
266
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'
273             else:
274                 raise ValueError("Invalid direction!")
275         else:
276             raise ValueError("Invalid protocol!")
277
278     @staticmethod
279     def compute_classify_hex_value(hex_mask, source_port, destination_port):
280         """Compute classify hex value for TCP or UDP packet matching.
281
282         :param hex_mask: Classify hex mask.
283         :param source_port: Source TCP/UDP port.
284         :param destination_port: Destination TCP/UDP port.
285         :type hex_mask: str
286         :type source_port: str
287         :type destination_port: str
288         :returns: Classify hex value.
289         :rtype: str
290         """
291         source_port_hex = Classify._port_convert(source_port)
292         destination_port_hex = Classify._port_convert(destination_port)
293
294         return hex_mask[:-8] + source_port_hex + destination_port_hex
295
296     @staticmethod
297     def _port_convert(port):
298         """Convert port number for classify hex table format.
299
300         :param port: TCP/UDP port number.
301         :type port: str
302         :returns: TCP/UDP port number in 4-digit hexadecimal format.
303         :rtype: str
304         """
305         return '{0:04x}'.format(int(port))
306
307     @staticmethod
308     def _compute_base_mask(ip_version):
309         """Compute base classify hex mask based on IP version.
310
311         :param ip_version: Version of IP protocol.
312         :type ip_version: str
313         :return: Base hex mask.
314         :rtype: str
315         """
316         if ip_version == 'ip4':
317             return 68 * '0'
318             # base value of classify hex table for IPv4 TCP/UDP ports
319         elif ip_version == 'ip6':
320             return 108 * '0'
321             # base value of classify hex table for IPv6 TCP/UDP ports
322         else:
323             raise ValueError("Invalid IP version!")
324
325     @staticmethod
326     def get_classify_table_data(node, table_index):
327         """Retrieve settings for classify table by ID.
328
329         :param node: VPP node to retrieve classify data from.
330         :param table_index: Index of a specific classify table.
331         :type node: dict
332         :type table_index: int
333         :returns: Classify table settings.
334         :rtype: dict
335         """
336         with VatTerminal(node) as vat:
337             data = vat.vat_terminal_exec_cmd_from_template(
338                 "classify_table_info.vat",
339                 table_id=table_index
340             )
341         return data[0]
342
343     @staticmethod
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.
347
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)
351         :type node: dict
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.
356         :rtype: list or dict
357         """
358         with VatTerminal(node) as vat:
359             data = vat.vat_terminal_exec_cmd_from_template(
360                 "classify_session_dump.vat",
361                 table_id=table_index
362             )
363         if session_index is not None:
364             return data[0][session_index]
365         else:
366             return data[0]
367
368     @staticmethod
369     def vpp_log_plugin_acl_settings(node):
370         """Retrieve configured settings from the ACL plugin
371          and write to robot log.
372
373         :param node: VPP node.
374         :type node: dict
375         """
376         try:
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
381             pass
382
383     @staticmethod
384     def vpp_log_plugin_acl_interface_assignment(node):
385         """Retrieve interface assignment from the ACL plugin
386         and write to robot log.
387
388         :param node: VPP node.
389         :type node: dict
390         """
391         try:
392             VatExecutor.cmd_from_template(
393                 node, "acl_plugin/acl_interface_dump.vat", json_out=False)
394         except RuntimeError:
395             # Fails to parse response, but it is still logged
396             pass
397
398     @staticmethod
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.
402
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.
407         :type node: dict
408         :type interface: str or int
409         :type acl_type: str
410         :type acl_idx: list
411         :raises RuntimeError: If unable to set ACL list for the interface.
412         """
413         if isinstance(interface, basestring):
414             sw_if_index = Topology.get_interface_sw_index(node, interface)
415         else:
416             sw_if_index = interface
417
418         acl_list = acl_type + ' ' + ' '.join(str(idx) for idx in acl_idx) \
419             if acl_idx else acl_type
420
421         try:
422             with VatTerminal(node, json_param=False) as vat:
423                 vat.vat_terminal_exec_cmd_from_template(
424                     "acl_plugin/acl_interface_set_acl_list.vat",
425                     interface=sw_if_index, acl_list=acl_list)
426         except RuntimeError:
427             raise RuntimeError("Setting of ACL list for interface {0} failed "
428                                "on node {1}".format(interface, node['host']))
429
430     @staticmethod
431     def add_replace_acl(node, acl_idx=None, ip_ver="ipv4", action="permit",
432                         src=None, dst=None, sport=None, dport=None, proto=None,
433                         tcpflg_val=None, tcpflg_mask=None):
434         """Add a new ACL or replace the existing one. To replace an existing
435         ACL, pass the ID of this ACL.
436
437         :param node: VPP node to set ACL on.
438         :param acl_idx: ID of ACL. (Optional)
439         :param ip_ver: IP version. (Optional)
440         :param action: ACL action. (Optional)
441         :param src: Source IP in format IP/plen. (Optional)
442         :param dst: Destination IP in format IP/plen. (Optional)
443         :param sport: Source port or ICMP4/6 type - range format X-Y allowed.
444          (Optional)
445         :param dport: Destination port or ICMP4/6 code - range format X-Y
446          allowed. (Optional)
447         :param proto: L4 protocol (http://www.iana.org/assignments/protocol-
448          numbers/protocol-numbers.xhtml). (Optional)
449         :param tcpflg_val: TCP flags value. (Optional)
450         :param tcpflg_mask: TCP flags mask. (Optional)
451         :type node: dict
452         :type acl_idx: int
453         :type ip_ver: str
454         :type action: str
455         :type src: str
456         :type dst: str
457         :type sport: str or int
458         :type dport: str or int
459         :type proto: int
460         :type tcpflg_val: int
461         :type tcpflg_mask: int
462         :raises RuntimeError: If unable to add or replace ACL.
463         """
464         acl_idx = '{0}'.format(acl_idx) if acl_idx else ''
465
466         src = 'src {0}'.format(src) if src else ''
467
468         dst = 'dst {0}'.format(dst) if dst else ''
469
470         sport = 'sport {0}'.format(sport) if sport else ''
471
472         dport = 'dport {0}'.format(dport) if dport else ''
473
474         proto = 'proto {0}'.format(proto) if proto else ''
475
476         tcpflags = 'tcpflags {0} {1}'.format(tcpflg_val, tcpflg_mask) \
477             if tcpflg_val and tcpflg_mask else ''
478
479         try:
480             with VatTerminal(node, json_param=False) as vat:
481                 vat.vat_terminal_exec_cmd_from_template(
482                     "acl_plugin/acl_add_replace.vat", acl_idx=acl_idx,
483                     ip_ver=ip_ver, action=action, src=src, dst=dst, sport=sport,
484                     dport=dport, proto=proto, tcpflags=tcpflags)
485         except RuntimeError:
486             raise RuntimeError("Adding or replacing of ACL failed on "
487                                "node {0}".format(node['host']))
488
489     @staticmethod
490     def add_replace_acl_multi_entries(node, acl_idx=None, rules=None):
491         """Add a new ACL or replace the existing one. To replace an existing
492         ACL, pass the ID of this ACL.
493
494         :param node: VPP node to set ACL on.
495         :param acl_idx: ID of ACL. (Optional)
496         :param rules: Required rules. (Optional)
497         :type node: dict
498         :type acl_idx: int
499         :type rules: str
500         :raises RuntimeError: If unable to add or replace ACL.
501         """
502         acl_idx = '{0}'.format(acl_idx) if acl_idx else ''
503
504         rules = '{0}'.format(rules) if rules else ''
505
506         try:
507             with VatTerminal(node, json_param=False) as vat:
508                 vat.vat_terminal_exec_cmd_from_template(
509                     "acl_plugin/acl_add_replace.vat", acl_idx=acl_idx,
510                     ip_ver=rules, action='', src='', dst='', sport='',
511                     dport='', proto='', tcpflags='')
512         except RuntimeError:
513             raise RuntimeError("Adding or replacing of ACL failed on "
514                                "node {0}".format(node['host']))
515
516     @staticmethod
517     def delete_acl(node, idx):
518         """Delete required ACL.
519
520         :param node: VPP node to delete ACL on.
521         :param idx: Index of ACL to be deleted.
522         :type node: dict
523         :type idx: int or str
524         :raises RuntimeError: If unable to delete ACL.
525         """
526         try:
527             with VatTerminal(node, json_param=False) as vat:
528                 vat.vat_terminal_exec_cmd_from_template(
529                     "acl_plugin/acl_delete.vat", idx=idx)
530         except RuntimeError:
531             raise RuntimeError("Deletion of ACL failed on node {0}".
532                                format(node['host']))
533
534     @staticmethod
535     def cli_show_acl(node, acl_idx=None):
536         """Show ACLs.
537
538         :param node: VPP node to show ACL on.
539         :param acl_idx: Index of ACL to be shown.
540         :type node: dict
541         :type acl_idx: int or str
542         :raises RuntimeError: If unable to delete ACL.
543         """
544         acl_idx = '{0}'.format(acl_idx) if acl_idx else ''
545
546         try:
547             with VatTerminal(node, json_param=False) as vat:
548                 vat.vat_terminal_exec_cmd_from_template(
549                     "acl_plugin/show_acl.vat", idx=acl_idx)
550         except RuntimeError:
551             raise RuntimeError("Failed to show ACL on node {0}".
552                                format(node['host']))
553
554     @staticmethod
555     def add_macip_acl(node, ip_ver="ipv4", action="permit", src_ip=None,
556                       src_mac=None, src_mac_mask=None):
557         """Add a new MACIP ACL.
558
559         :param node: VPP node to set MACIP ACL on.
560         :param ip_ver: IP version. (Optional)
561         :param action: ACL action. (Optional)
562         :param src_ip: Source IP in format IP/plen. (Optional)
563         :param src_mac: Source MAC address in format with colons. (Optional)
564         :param src_mac_mask: Source MAC address mask in format with colons.
565          00:00:00:00:00:00 is a wildcard mask. (Optional)
566         :type node: dict
567         :type ip_ver: str
568         :type action: str
569         :type src_ip: str
570         :type src_mac: str
571         :type src_mac_mask: str
572         :raises RuntimeError: If unable to add MACIP ACL.
573         """
574         src_ip = 'ip {0}'.format(src_ip) if src_ip else ''
575
576         src_mac = 'mac {0}'.format(src_mac) if src_mac else ''
577
578         src_mac_mask = 'mask {0}'.format(src_mac_mask) if src_mac_mask else ''
579
580         try:
581             with VatTerminal(node, json_param=False) as vat:
582                 vat.vat_terminal_exec_cmd_from_template(
583                     "acl_plugin/macip_acl_add.vat", ip_ver=ip_ver,
584                     action=action, src_ip=src_ip, src_mac=src_mac,
585                     src_mac_mask=src_mac_mask)
586         except RuntimeError:
587             raise RuntimeError("Adding of MACIP ACL failed on node {0}".
588                                format(node['host']))
589
590     @staticmethod
591     def add_macip_acl_multi_entries(node, rules=None):
592         """Add a new MACIP ACL.
593
594         :param node: VPP node to set MACIP ACL on.
595         :param rules: Required MACIP rules. (Optional)
596         :type node: dict
597         :type rules: str
598         :raises RuntimeError: If unable to add MACIP ACL.
599         """
600         rules = '{0}'.format(rules) if rules else ''
601
602         try:
603             with VatTerminal(node, json_param=False) as vat:
604                 vat.vat_terminal_exec_cmd_from_template(
605                     "acl_plugin/macip_acl_add.vat", ip_ver=rules, action='',
606                     src_ip='', src_mac='', src_mac_mask='')
607         except RuntimeError:
608             raise RuntimeError("Adding of MACIP ACL failed on node {0}".
609                                format(node['host']))
610
611     @staticmethod
612     def delete_macip_acl(node, idx):
613         """Delete required MACIP ACL.
614
615         :param node: VPP node to delete MACIP ACL on.
616         :param idx: Index of ACL to be deleted.
617         :type node: dict
618         :type idx: int or str
619         :raises RuntimeError: If unable to delete MACIP ACL.
620         """
621         try:
622             with VatTerminal(node, json_param=False) as vat:
623                 vat.vat_terminal_exec_cmd_from_template(
624                     "acl_plugin/macip_acl_delete.vat", idx=idx)
625         except RuntimeError:
626             raise RuntimeError("Deletion of MACIP ACL failed on node {0}".
627                                format(node['host']))
628
629     @staticmethod
630     def vpp_log_macip_acl_settings(node):
631         """Retrieve configured MACIP settings from the ACL plugin
632          and write to robot log.
633
634         :param node: VPP node.
635         :type node: dict
636         """
637         try:
638             VatExecutor.cmd_from_template(
639                 node, "acl_plugin/macip_acl_dump.vat")
640         except (ValueError, RuntimeError):
641             # Fails to parse JSON data in response, but it is still logged
642             pass
643
644     @staticmethod
645     def add_del_macip_acl_interface(node, interface, action, acl_idx):
646         """Apply/un-apply the MACIP ACL to/from a given interface.
647
648         :param node: VPP node to set MACIP ACL on.
649         :param interface: Interface name or sw_if_index.
650         :param action: Required action - add or del.
651         :param acl_idx: ACL index to be applied on the interface.
652         :type node: dict
653         :type interface: str or int
654         :type action: str
655         :type acl_idx: str or int
656         :raises RuntimeError: If unable to set MACIP ACL for the interface.
657         """
658         if isinstance(interface, basestring):
659             sw_if_index = Topology.get_interface_sw_index(node, interface)
660         else:
661             sw_if_index = interface
662
663         try:
664             with VatTerminal(node, json_param=False) as vat:
665                 vat.vat_terminal_exec_cmd_from_template(
666                     "acl_plugin/macip_acl_interface_add_del.vat",
667                     sw_if_index=sw_if_index, action=action, acl_idx=acl_idx)
668         except RuntimeError:
669             raise RuntimeError("Setting of MACIP ACL index for interface {0} "
670                                "failed on node {1}".
671                                format(interface, node['host']))
672
673     @staticmethod
674     def vpp_log_macip_acl_interface_assignment(node):
675         """Get interface list and associated MACIP ACLs and write to robot log.
676
677         :param node: VPP node.
678         :type node: dict
679         """
680         try:
681             VatExecutor.cmd_from_template(
682                 node, "acl_plugin/macip_acl_interface_get.vat", json_out=False)
683         except RuntimeError:
684             # Fails to parse response, but it is still logged
685             pass