Add basic 4o4 LISP unit test
[vpp.git] / test / lisp.py
diff --git a/test/lisp.py b/test/lisp.py
new file mode 100644 (file)
index 0000000..865070d
--- /dev/null
@@ -0,0 +1,326 @@
+from random import randint
+from socket import AF_INET, AF_INET6
+from scapy.all import *
+from scapy.packet import *
+from scapy.fields import *
+from lisp import *
+from framework import *
+from vpp_object import *
+
+
+class VppLispLocatorSet(VppObject):
+    """ Represents LISP locator set in VPP """
+
+    def __init__(self, test, ls_name):
+        self._test = test
+        self._ls_name = ls_name
+
+    @property
+    def test(self):
+        return self._test
+
+    @property
+    def ls_name(self):
+        return self._ls_name
+
+    def add_vpp_config(self):
+        self.test.vapi.lisp_locator_set(ls_name=self._ls_name)
+        self._test.registry.register(self, self.test.logger)
+
+    def get_lisp_locator_sets_dump_entry(self):
+        result = self.test.vapi.lisp_locator_set_dump()
+        for ls in result:
+            if ls.ls_name.strip('\x00') == self._ls_name:
+                return ls
+        return None
+
+    def query_vpp_config(self):
+        return self.get_lisp_locator_sets_dump_entry() is not None
+
+    def remove_vpp_config(self):
+        self.test.vapi.lisp_locator_set(ls_name=self._ls_name, is_add=0)
+
+    def object_id(self):
+        return 'lisp-locator-set-%s' % self._ls_name
+
+
+class VppLispLocator(VppObject):
+    """ Represents LISP locator in VPP """
+
+    def __init__(self, test, sw_if_index, ls_name, priority=1, weight=1):
+        self._test = test
+        self._sw_if_index = sw_if_index
+        self._ls_name = ls_name
+        self._priority = priority
+        self._weight = weight
+
+    @property
+    def test(self):
+        """ Test which created this locator """
+        return self._test
+
+    @property
+    def ls_name(self):
+        """ Locator set name """
+        return self._ls_name
+
+    @property
+    def sw_if_index(self):
+        return self._sw_if_index
+
+    @property
+    def priority(self):
+        return self.priority
+
+    @property
+    def weight(self):
+        return self._weight
+
+    def add_vpp_config(self):
+        self.test.vapi.lisp_locator(ls_name=self._ls_name,
+                                    sw_if_index=self._sw_if_index,
+                                    priority=self._priority,
+                                    weight=self._weight)
+        self._test.registry.register(self, self.test.logger)
+
+    def get_lisp_locator_dump_entry(self):
+        locators = self.test.vapi.lisp_locator_dump(
+                is_index_set=0, ls_name=self._ls_name)
+        for locator in locators:
+            if locator.sw_if_index == self._sw_if_index:
+                return locator
+        return None
+
+    def query_vpp_config(self):
+        locator = self.get_lisp_locator_dump_entry()
+        return locator is not None
+
+    def remove_vpp_config(self):
+        self.test.vapi.lisp_locator(
+                ls_name=self._ls_name, sw_if_index=self._sw_if_index,
+                priority=self._priority, weight=self._weight, is_add=0)
+        self._test.registry.register(self, self.test.logger)
+
+    def object_id(self):
+        return 'lisp-locator-%s-%d' % (self._ls_name, self._sw_if_index)
+
+
+class LispEIDType(object):
+    IP4 = 0
+    IP6 = 1
+    MAC = 2
+
+
+class LispKeyIdType(object):
+    NONE = 0
+    SHA1 = 1
+    SHA256 = 2
+
+
+class LispEID(object):
+    """ Lisp endpoint identifier """
+    def __init__(self, eid):
+        self.eid = eid
+
+        # find out whether EID is ip4 prefix, ip6 prefix or MAC
+        if self.eid.find("/") != -1:
+            if self.eid.find(":") == -1:
+                self.eid_type = LispEIDType.IP4
+                self.data_length = 4
+            else:
+                self.eid_type = LispEIDType.IP6
+                self.data_length = 16
+
+            self.eid_address = self.eid.split("/")[0]
+            self.prefix_length = int(self.eid.split("/")[1])
+        elif self.eid.count(":") == 5:  # MAC address
+            self.eid_type = LispEIDType.MAC
+            self.eid_address = self.eid
+            self.prefix_length = 0
+            self.data_length = 6
+        else:
+            raise Exception('Unsupported EID format {}!'.format(eid))
+
+    def __str__(self):
+        if self.eid_type == LispEIDType.IP4:
+            return socket.inet_pton(socket.AF_INET, self.eid_address)
+        elif self.eid_type == LispEIDType.IP6:
+            return socket.inet_pton(socket.AF_INET6, self.eid_address)
+        elif self.eid_type == LispEIDType.MAC:
+            return Exception('Unimplemented')
+        raise Exception('Unknown EID type {}!'.format(self.eid_type))
+
+
+class VppLispMapping(VppObject):
+    """ Represents common features for remote and local LISP mapping in VPP """
+
+    def __init__(self, test, eid, vni=0, priority=1, weight=1):
+        self._eid = LispEID(eid)
+        self._test = test
+        self._priority = priority
+        self._weight = weight
+        self._vni = vni
+
+    @property
+    def test(self):
+        return self._test
+
+    @property
+    def vni(self):
+        return self._vni
+
+    @property
+    def eid(self):
+        return self._eid
+
+    @property
+    def priority(self):
+        return self._priority
+
+    @property
+    def weight(self):
+        return self._weight
+
+    def get_lisp_mapping_dump_entry(self):
+        return self.test.vapi.lisp_eid_table_dump(
+                eid_set=1, prefix_length=self._eid.prefix_length,
+                vni=self._vni, eid_type=self._eid.eid_type, eid=str(self._eid))
+
+    def query_vpp_config(self):
+        mapping = self.get_lisp_mapping_dump_entry()
+        return mapping
+
+
+class VppLocalMapping(VppLispMapping):
+    """ LISP Local mapping """
+    def __init__(self, test, eid, ls_name, vni=0, priority=1, weight=1,
+                 key_id=LispKeyIdType.NONE, key=''):
+        super(VppLocalMapping, self).__init__(test, eid, vni, priority, weight)
+        self._ls_name = ls_name
+        self._key_id = key_id
+        self._key = key
+
+    @property
+    def ls_name(self):
+        return self._ls_name
+
+    @property
+    def key_id(self):
+        return self._key_id
+
+    @property
+    def key(self):
+        return self._key
+
+    def add_vpp_config(self):
+        self.test.vapi.lisp_local_mapping(
+                ls_name=self._ls_name, eid_type=self._eid.eid_type,
+                eid=str(self._eid), prefix_len=self._eid.prefix_length,
+                vni=self._vni, key_id=self._key_id, key=self._key)
+        self._test.registry.register(self, self.test.logger)
+
+    def remove_vpp_config(self):
+        self.test.vapi.lisp_local_mapping(
+                ls_name=self._ls_name, eid_type=self._eid.eid_type,
+                eid=str(self._eid), prefix_len=self._eid.prefix_length,
+                vni=self._vni, is_add=0)
+
+    def object_id(self):
+        return 'lisp-eid-local-mapping-%s[%d]' % (self._eid, self._vni)
+
+
+class VppRemoteMapping(VppLispMapping):
+
+    def __init__(self, test, eid, rlocs=None, vni=0, priority=1, weight=1):
+        super(VppRemoteMapping, self).__init__(test, eid, vni, priority,
+                                               weight)
+        self._rlocs = rlocs
+
+    @property
+    def rlocs(self):
+        return self._rlocs
+
+    def add_vpp_config(self):
+        self.test.vapi.lisp_remote_mapping(
+                rlocs=self._rlocs, eid_type=self._eid.eid_type,
+                eid=str(self._eid), eid_prefix_len=self._eid.prefix_length,
+                vni=self._vni, rlocs_num=len(self._rlocs))
+        self._test.registry.register(self, self.test.logger)
+
+    def remove_vpp_config(self):
+        self.test.vapi.lisp_remote_mapping(
+                eid_type=self._eid.eid_type, eid=str(self._eid),
+                eid_prefix_len=self._eid.prefix_length, vni=self._vni,
+                is_add=0, rlocs_num=0)
+
+    def object_id(self):
+        return 'lisp-eid-remote-mapping-%s[%d]' % (self._eid, self._vni)
+
+
+class VppLispAdjacency(VppObject):
+    """ Represents LISP adjacency in VPP """
+
+    def __init__(self, test, leid, reid, vni=0):
+        self._leid = LispEID(leid)
+        self._reid = LispEID(reid)
+        if self._leid.eid_type != self._reid.eid_type:
+            raise Exception('remote and local EID are different types!')
+        self._vni = vni
+        self._test = test
+
+    @property
+    def test(self):
+        return self._test
+
+    @property
+    def leid(self):
+        return self._leid
+
+    @property
+    def reid(self):
+        return self._reid
+
+    @property
+    def vni(self):
+        return self._vni
+
+    def add_vpp_config(self):
+        self.test.vapi.lisp_adjacency(
+                leid=str(self._leid),
+                reid=str(self._reid), eid_type=self._leid.eid_type,
+                leid_len=self._leid.prefix_length,
+                reid_len=self._reid.prefix_length, vni=self._vni)
+        self._test.registry.register(self, self.test.logger)
+
+    def eid_equal(self, eid, eid_type, eid_data, prefix_len):
+        if eid.eid_type != eid_type:
+            return False
+
+        if eid_type == LispEIDType.IP4 or eid_type == LispEIDType.IP6:
+            if eid.prefix_length != prefix_len:
+                return False
+
+        if str(eid) != eid_data[0:eid.data_length]:
+            return False
+
+        return True
+
+    def query_vpp_config(self):
+        res = self.test.vapi.lisp_adjacencies_get(vni=self._vni)
+        for adj in res.adjacencies:
+            if self.eid_equal(self._leid, adj.eid_type, adj.leid,
+                              adj.leid_prefix_len) and \
+                self.eid_equal(self._reid, adj.eid_type, adj.reid,
+                               adj.reid_prefix_len):
+                return True
+        return False
+
+    def remove_vpp_config(self):
+        self.test.vapi.lisp_adjacency(
+                leid=str(self._leid),
+                reid=str(self._reid), eid_type=self._leid.eid_type,
+                leid_len=self._leid.prefix_length,
+                reid_len=self._reid.prefix_length, vni=self._vni, is_add=0)
+
+    def object_id(self):
+        return 'lisp-adjacency-%s-%s[%d]' % (self._leid, self._reid, self._vni)