Tolerate failures when setting MTU
[csit.git] / resources / libraries / python / SRv6.py
index a22bb5e..fe706f5 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2017 Cisco and/or its affiliates.
+# Copyright (c) 2018 Cisco and/or its affiliates.
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at:
 
 """Segment Routing over IPv6 dataplane utilities library."""
 
-from enum import Enum
-
 from resources.libraries.python.VatExecutor import VatTerminal
-from resources.libraries.python.VatJsonUtil import VatJsonUtil
 from resources.libraries.python.topology import Topology
 
 
-class SRv6Behaviour(Enum):
-    """Defines SRv6 endpoint functions implemented in VPP."""
-    # Endpoint function
-    END = 'end'
-    # Endpoint function with Layer-3 cross-connect
-    END_X = 'end.x'
-    # Endpoint with decapsulation and Layer-2 cross-connect
-    END_DX2 = 'end.dx2'
-    # Endpoint with decapsulation and IPv4 cross-connect
-    END_DX4 = 'end.dx4'
-    # Endpoint with decapsulation and IPv4 table lookup
-    END_DT4 = 'end.dt4'
-    # Endpoint with decapsulation and IPv6 cross-connect
-    END_DX6 = 'end.dx6'
-    # Endpoint with decapsulation and IPv6 table lookup
-    END_DT6 = 'end.dt6'
+# SRv6 LocalSID supported functions.
+# Endpoint function
+SRV6BEHAVIOUR_END = 'end'
+# Endpoint function with Layer-3 cross-connect
+SRV6BEHAVIOUR_END_X = 'end.x'
+# Endpoint with decapsulation and Layer-2 cross-connect
+SRV6BEHAVIOUR_END_DX2 = 'end.dx2'
+# Endpoint with decapsulation and IPv4 cross-connect
+SRV6BEHAVIOUR_END_DX4 = 'end.dx4'
+# Endpoint with decapsulation and IPv4 table lookup
+SRV6BEHAVIOUR_END_DT4 = 'end.dt4'
+# Endpoint with decapsulation and IPv6 cross-connect
+SRV6BEHAVIOUR_END_DX6 = 'end.dx6'
+# Endpoint with decapsulation and IPv6 table lookup
+SRV6BEHAVIOUR_END_DT6 = 'end.dt6'
+# Endpoint to SR-unaware appliance via static proxy
+SRV6BEHAVIOUR_END_AS = 'end.as'
+# Endpoint to SR-unaware appliance via dynamic proxy
+SRV6BEHAVIOUR_END_AD = 'end.ad'
+# Endpoint to SR-unaware appliance via masquerading
+SRV6BEHAVIOUR_END_AM = 'end.am'
 
 
 class SRv6(object):
@@ -46,7 +48,8 @@ class SRv6(object):
 
     @staticmethod
     def configure_sr_localsid(node, local_sid, behavior, interface=None,
-                              next_hop=None, fib_table=None):
+                              next_hop=None, fib_table=None, out_if=None,
+                              in_if=None, src_addr=None, sid_list=None):
         """Create SRv6 LocalSID and binds it to a particular behaviour on
         the given node.
 
@@ -59,47 +62,77 @@ class SRv6(object):
             xconnects).
         :param fib_table: FIB table for IPv4/IPv6 lookup (Optional, required for
             L3 routing).
+        :param out_if: Interface name of local interface for sending traffic
+            towards the Service Function (Optional, required for SRv6 endpoint
+            to SR-unaware appliance).
+        :param in_if: Interface name of local interface receiving the traffic
+            coming back from the Service Function (Optional, required for SRv6
+            endpoint to SR-unaware appliance).
+        :param src_addr: Source address on the packets coming back on in_if
+            interface (Optional, required for SRv6 endpoint to SR-unaware
+            appliance via static proxy).
+        :param sid_list: SID list (Optional, required for SRv6 endpoint to
+            SR-unaware appliance via static proxy).
         :type node: dict
         :type local_sid: str
         :type behavior: str
         :type interface: str
         :type next_hop: int
         :type fib_table: str
+        :type out_if: str
+        :type in_if: str
+        :type src_addr: str
+        :type sid_list: list
         :raises ValueError: If unsupported SRv6 LocalSID function used or
             required parameter is missing.
         """
-        if behavior == SRv6Behaviour.END:
+        if behavior == SRV6BEHAVIOUR_END:
             params = ''
-        elif behavior in [SRv6Behaviour.END_X, SRv6Behaviour.END_DX4,
-                          SRv6Behaviour.END_DX6]:
+        elif behavior in [SRV6BEHAVIOUR_END_X, SRV6BEHAVIOUR_END_DX4,
+                          SRV6BEHAVIOUR_END_DX6]:
             if interface is None or next_hop is None:
-                raise ValueError('Required data missing.\ninterface:{0}\n'
-                                 'next_hop:{1}'.format(interface, next_hop))
+                raise ValueError('Required parameter(s) missing.\ninterface:{0}'
+                                 '\nnext_hop:{1}'.format(interface, next_hop))
             interface_name = Topology.get_interface_name(node, interface)
             params = '{0} {1}'.format(interface_name, next_hop)
-        elif behavior == SRv6Behaviour.END_DX2:
+        elif behavior == SRV6BEHAVIOUR_END_DX2:
             if interface is None:
-                raise ValueError('Required data missing.\ninterface:{0}\n'.
+                raise ValueError('Required parameter missing.\ninterface:{0}'.
                                  format(interface))
             params = '{0}'.format(interface)
-        elif behavior in [SRv6Behaviour.END_DT4, SRv6Behaviour.END_DT6]:
+        elif behavior in [SRV6BEHAVIOUR_END_DT4, SRV6BEHAVIOUR_END_DT6]:
             if fib_table is None:
-                raise ValueError('Required data missing.\nfib_table:{0}\n'.
+                raise ValueError('Required parameter missing.\nfib_table: {0}'.
                                  format(fib_table))
             params = '{0}'.format(fib_table)
+        elif behavior == SRV6BEHAVIOUR_END_AS:
+            if next_hop is None or out_if is None or in_if is None or \
+                            src_addr is None or sid_list is None:
+                raise ValueError('Required parameter(s) missing.\nnext_hop:{0}'
+                                 '\nout_if:{1}\nin_if:{2}\nsrc_addr:{3}\n'
+                                 'sid_list:{4}'.format(next_hop, out_if, in_if,
+                                                       src_addr, sid_list))
+            sid_conf = 'next ' + ' next '.join(sid_list)
+            params = 'nh {0} oif {1} iif {2} src {3} {4}'.\
+                format(next_hop, out_if, in_if, src_addr, sid_conf)
+        elif behavior in [SRV6BEHAVIOUR_END_AD, SRV6BEHAVIOUR_END_AM]:
+            if next_hop is None or out_if is None or in_if is None:
+                raise ValueError('Required parameter(s) missing.\nnext_hop:{0}'
+                                 '\nout_if:{1}\nin_if:{2}'.
+                                 format(next_hop, out_if, in_if))
+            params = 'nh {0} oif {1} iif {2}'.format(next_hop, out_if, in_if)
         else:
             raise ValueError('Unsupported SRv6 LocalSID function: {0}'.
                              format(behavior))
 
-        with VatTerminal(node) as vat:
-            resp = vat.vat_terminal_exec_cmd_from_template(
+        with VatTerminal(node, json_param=False) as vat:
+            vat.vat_terminal_exec_cmd_from_template(
                 'srv6/sr_localsid_add.vat', local_sid=local_sid,
                 behavior=behavior, params=params)
 
-        VatJsonUtil.verify_vat_retval(
-            resp[0],
-            err_msg='Create SRv6 LocalSID {0} failed on node {1}'.format(
-                local_sid, node['host']))
+        if "exec error: Misc" in vat.vat_stdout:
+            raise RuntimeError('Create SRv6 LocalSID {0} failed on node {1}'.
+                               format(local_sid, node['host']))
 
     @staticmethod
     def delete_sr_localsid(node, local_sid):
@@ -110,14 +143,13 @@ class SRv6(object):
         :type node: dict
         :type local_sid: str
         """
-        with VatTerminal(node) as vat:
-            resp = vat.vat_terminal_exec_cmd_from_template(
+        with VatTerminal(node, json_param=False) as vat:
+            vat.vat_terminal_exec_cmd_from_template(
                 'srv6/sr_localsid_del.vat', local_sid=local_sid)
 
-        VatJsonUtil.verify_vat_retval(
-            resp[0],
-            err_msg='Delete SRv6 LocalSID {0} failed on node {1}'.format(
-                local_sid, node['host']))
+        if "exec error: Misc" in vat.vat_stdout:
+            raise RuntimeError('Delete SRv6 LocalSID {0} failed on node {1}'.
+                               format(local_sid, node['host']))
 
     @staticmethod
     def show_sr_localsids(node):
@@ -126,7 +158,7 @@ class SRv6(object):
         :param node: Given node to show localSIDs on.
         :type node: dict
         """
-        with VatTerminal(node) as vat:
+        with VatTerminal(node, json_param=False) as vat:
             vat.vat_terminal_exec_cmd_from_template(
                 'srv6/sr_localsids_show.vat')
 
@@ -145,15 +177,14 @@ class SRv6(object):
         """
         sid_conf = 'next ' + ' next '.join(sid_list)
 
-        with VatTerminal(node) as vat:
-            resp = vat.vat_terminal_exec_cmd_from_template(
+        with VatTerminal(node, json_param=False) as vat:
+            vat.vat_terminal_exec_cmd_from_template(
                 'srv6/sr_policy_add.vat', bsid=bsid,
                 sid_conf=sid_conf, mode=mode)
 
-        VatJsonUtil.verify_vat_retval(
-            resp[0],
-            err_msg='Create SRv6 policy for BindingSID {0} failed on node '
-                    '{1}'.format(bsid, node['host']))
+        if "exec error: Misc" in vat.vat_stdout:
+            raise RuntimeError('Create SRv6 policy for BindingSID {0} failed on'
+                               ' node {1}'.format(bsid, node['host']))
 
     @staticmethod
     def delete_sr_policy(node, bsid):
@@ -164,14 +195,13 @@ class SRv6(object):
         :type node: dict
         :type bsid: str
         """
-        with VatTerminal(node) as vat:
-            resp = vat.vat_terminal_exec_cmd_from_template(
+        with VatTerminal(node, json_param=False) as vat:
+            vat.vat_terminal_exec_cmd_from_template(
                 'srv6/sr_policy_del.vat', bsid=bsid)
 
-        VatJsonUtil.verify_vat_retval(
-            resp[0],
-            err_msg='Delete SRv6 policy for BindingSID {0} failed on node '
-                    '{1}'.format(bsid, node['host']))
+        if "exec error: Misc" in vat.vat_stdout:
+            raise RuntimeError('Delete SRv6 policy for BindingSID {0} failed on'
+                               ' node {1}'.format(bsid, node['host']))
 
     @staticmethod
     def show_sr_policies(node):
@@ -186,7 +216,7 @@ class SRv6(object):
 
     @staticmethod
     def configure_sr_steer(node, mode, bsid, interface=None, ip_addr=None,
-                           mask=None):
+                           prefix=None):
         """Create SRv6 steering policy on the given node.
 
         :param node: Given node to create steering policy on.
@@ -196,38 +226,42 @@ class SRv6(object):
             L2 mode).
         :param ip_addr: IPv4/IPv6 address (Optional, required in case of L3
             mode).
-        :param mask: IP address mask (Optional, required in case of L3 mode).
+        :param prefix: IP address prefix (Optional, required in case of L3
+            mode).
         :type node: dict
         :type mode: str
         :type bsid: str
         :type interface: str
-        :type ip_addr: int
-        :type mask: int
+        :type ip_addr: str
+        :type prefix: int
         :raises ValueError: If unsupported mode used or required parameter
             is missing.
         """
-        if mode == 'l2':
+        if mode.lower() == 'l2':
             if interface is None:
                 raise ValueError('Required data missing.\ninterface:{0}\n'.
                                  format(interface))
             interface_name = Topology.get_interface_name(node, interface)
             params = 'l2 {0}'.format(interface_name)
-        elif mode == 'l3':
-            if ip_addr is None or mask is None:
+        elif mode.lower() == 'l3':
+            if ip_addr is None or prefix is None:
                 raise ValueError('Required data missing.\nIP address:{0}\n'
-                                 'mask:{1}'.format(ip_addr, mask))
-            params = '{0}/{1}'.format(ip_addr, mask)
+                                 'mask:{1}'.format(ip_addr, prefix))
+            params = 'l3 {0}/{1}'.format(ip_addr, prefix)
         else:
             raise ValueError('Unsupported mode: {0}'.format(mode))
 
-        with VatTerminal(node) as vat:
-            resp = vat.vat_terminal_exec_cmd_from_template(
+        with VatTerminal(node, json_param=False) as vat:
+            vat.vat_terminal_exec_cmd_from_template(
                 'srv6/sr_steer_add_del.vat', params=params, bsid=bsid)
 
-        VatJsonUtil.verify_vat_retval(
-            resp[0],
-            err_msg='Create SRv6 steering policy for BindingSID {0} failed on '
-                    'node {1}'.format(bsid, node['host']))
+        sr_steer_errors = ("exec error: Misc",
+                           "sr steer: No SR policy specified")
+        for err in sr_steer_errors:
+            if err in vat.vat_stdout:
+                raise RuntimeError('Create SRv6 steering policy for BindingSID'
+                                   ' {0} failed on node {1}'.
+                                   format(bsid, node['host']))
 
     @staticmethod
     def delete_sr_steer(node, mode, bsid, interface=None, ip_addr=None,
@@ -266,14 +300,13 @@ class SRv6(object):
         else:
             raise ValueError('Unsupported mode: {0}'.format(mode))
 
-        with VatTerminal(node) as vat:
-            resp = vat.vat_terminal_exec_cmd_from_template(
+        with VatTerminal(node, json_param=False) as vat:
+            vat.vat_terminal_exec_cmd_from_template(
                 'srv6/sr_steer_add_del.vat', params=params, bsid=bsid)
 
-        VatJsonUtil.verify_vat_retval(
-            resp[0],
-            err_msg='Delete SRv6 policy for bsid {0} failed on node {1}'.format(
-                bsid, node['host']))
+        if "exec error: Misc" in vat.vat_stdout:
+            raise RuntimeError('Delete SRv6 policy for bsid {0} failed on node'
+                               ' {1}'.format(bsid, node['host']))
 
     @staticmethod
     def show_sr_steering_policies(node):
@@ -285,3 +318,16 @@ class SRv6(object):
         with VatTerminal(node, json_param=False) as vat:
             vat.vat_terminal_exec_cmd_from_template(
                 'srv6/sr_steer_policies_show.vat')
+
+    @staticmethod
+    def set_sr_encaps_source_address(node, ip6_addr):
+        """Set SRv6 encapsulation source address on the given node.
+
+        :param node: Given node to set SRv6 encapsulation source address on.
+        :param ip6_addr: Local SID IPv6 address.
+        :type node: dict
+        :type ip6_addr: str
+        """
+        with VatTerminal(node, json_param=False) as vat:
+            vat.vat_terminal_exec_cmd_from_template(
+                'srv6/sr_set_encaps_source.vat', ip6_addr=ip6_addr)