Esempio n. 1
0
class NFNStack(object):
    def __init__(self,
                 replica_id,
                 port=9500,
                 log_level=255,
                 encoder: BasicEncoder = NdnTlvEncoder):
        # debug level
        logger = Logger("Repo", log_level)

        # packet encoder
        encoder.set_log_level(log_level)
        self.encoder = encoder

        # create datastruct
        synced_data_struct_factory = PiCNSyncDataStructFactory()
        synced_data_struct_factory.register("cs", ContentStoreMemoryExact)
        synced_data_struct_factory.register(
            "fib", ForwardingInformationBaseMemoryPrefix)
        synced_data_struct_factory.register("pit",
                                            PendingInterstTableMemoryExact)
        synced_data_struct_factory.register("face_id_table", FaceIDDict)
        synced_data_struct_factory.create_manager()

        cs = synced_data_struct_factory.manager.cs()
        fib = synced_data_struct_factory.manager.fib()
        pit = synced_data_struct_factory.manager.pit()
        face_id_table = synced_data_struct_factory.manager.face_id_table()

        # initialize layers
        self.link_layer = BasicLinkLayer([UDP4Interface(port)],
                                         face_id_table,
                                         log_level=log_level)
        self.packet_encoding_layer = BasicPacketEncodingLayer(
            self.encoder, log_level=log_level)
        self.icn_layer = BasicICNLayer(log_level=log_level)
        self.nfn_computation_layer = PiCN.Playground.ForwardingStrategy.NFNComputationLayer(
            replica_id, log_level=log_level)

        # tell icn_layer that there is a higher layer which might satisfy interests
        self.icn_layer._interest_to_app = True  # TODO -- decide here if it should be forwarded upwards or not
        # self.icn_layer._interest_to_app = lambda interest: interest.name.components[-1] == b"pNFN"

        # setup stack
        self.stack: LayerStack = LayerStack([
            self.nfn_computation_layer, self.icn_layer,
            self.packet_encoding_layer, self.link_layer
        ])

        # set CS, FIB, PIT in forwarding layer
        self.icn_layer.cs = cs
        self.icn_layer.fib = fib
        self.icn_layer.pit = pit

    def start_forwarder(self):
        self.stack.start_all()
        self.icn_layer.ageing()

    def stop_forwarder(self):
        self.stack.stop_all()
        self.stack.close_all()
Esempio n. 2
0
    def setUp(self):

        #setup icn_layer
        self.icn_layer = BasicICNLayer(log_level=255)

        synced_data_struct_factory = PiCNSyncDataStructFactory()
        synced_data_struct_factory.register("cs", ContentStoreMemoryExact)
        synced_data_struct_factory.register(
            "fib", ForwardingInformationBaseMemoryPrefix)
        synced_data_struct_factory.register("pit",
                                            PendingInterestTableMemoryExact)
        synced_data_struct_factory.create_manager()

        cs = synced_data_struct_factory.manager.cs()
        fib = synced_data_struct_factory.manager.fib()
        pit = synced_data_struct_factory.manager.pit()
        cs.set_cs_timeout(2)
        pit.set_pit_timeout(2)
        pit.set_pit_retransmits(2)

        self.icn_layer.cs = cs
        self.icn_layer.fib = fib
        self.icn_layer.pit = pit

        #setup queues icn_routing layer
        self.queue1_icn_routing_up = multiprocessing.Queue()
        self.queue1_icn_routing_down = multiprocessing.Queue()

        #add queues to ICN layer
        self.icn_layer.queue_from_lower = self.queue1_icn_routing_up
        self.icn_layer.queue_to_lower = self.queue1_icn_routing_down
Esempio n. 3
0
class test_BasicICNLayer(unittest.TestCase):
    """Test the Basic ICN Layer implementation"""
    def setUp(self):

        #setup icn_layer
        self.icn_layer = BasicICNLayer(log_level=255)

        synced_data_struct_factory = PiCNSyncDataStructFactory()
        synced_data_struct_factory.register("cs", ContentStoreMemoryExact)
        synced_data_struct_factory.register(
            "fib", ForwardingInformationBaseMemoryPrefix)
        synced_data_struct_factory.register("pit",
                                            PendingInterestTableMemoryExact)
        synced_data_struct_factory.create_manager()

        cs = synced_data_struct_factory.manager.cs()
        fib = synced_data_struct_factory.manager.fib()
        pit = synced_data_struct_factory.manager.pit()
        cs.set_cs_timeout(2)
        pit.set_pit_timeout(2)
        pit.set_pit_retransmits(2)

        self.icn_layer.cs = cs
        self.icn_layer.fib = fib
        self.icn_layer.pit = pit

        #setup queues icn_routing layer
        self.queue1_icn_routing_up = multiprocessing.Queue()
        self.queue1_icn_routing_down = multiprocessing.Queue()

        #add queues to ICN layer
        self.icn_layer.queue_from_lower = self.queue1_icn_routing_up
        self.icn_layer.queue_to_lower = self.queue1_icn_routing_down

    def tearDown(self):
        self.icn_layer.stop_process()

    def test_ICNLayer_interest_forward_basic(self):
        """Test ICN layer with no CS and PIT entry"""
        self.icn_layer.start_process()

        to_faceid = 1
        from_faceid = 2

        #Add entry to the fib
        name = Name("/test/data")
        interest = Interest("/test/data")
        self.icn_layer.fib.add_fib_entry(name, [to_faceid], static=True)

        #forward entry
        self.queue1_icn_routing_up.put([from_faceid, interest])
        try:
            faceid, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        #check output
        self.assertEqual(faceid, to_faceid)
        self.assertEqual(data, interest)

        #check data structures
        self.assertEqual(self.icn_layer.cs.get_container_size(), 0)
        self.assertEqual(self.icn_layer.fib.get_container_size(), 1)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(
            self.icn_layer.fib.find_fib_entry(name).faceid, [to_faceid])
        self.assertEqual(self.icn_layer.fib.find_fib_entry(name).name, name)
        self.assertEqual(
            self.icn_layer.pit.find_pit_entry(name).faceids[0], from_faceid)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(name).name, name)

    def test_ICNLayer_interest_forward_longest_match(self):
        """Test ICN layer with no CS and no PIT entry and longest match"""
        self.icn_layer.start_process()

        to_face_id = 1
        from_face_id = 2

        #Add entry to the fib
        name = Name("/test")
        interest = Interest("/test/data")
        self.icn_layer.fib.add_fib_entry(name, [to_face_id], static=True)

        #forward entry
        self.queue1_icn_routing_up.put([from_face_id, interest])
        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        #check output
        self.assertEqual(face_id, to_face_id)
        self.assertEqual(data, interest)

        #check data structures
        self.assertEqual(self.icn_layer.cs.get_container_size(), 0)
        self.assertEqual(self.icn_layer.fib.get_container_size(), 1)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(
            self.icn_layer.fib.find_fib_entry(name).faceid, [to_face_id])
        self.assertEqual(self.icn_layer.fib.find_fib_entry(name).name, name)
        self.assertEqual(
            self.icn_layer.pit.find_pit_entry(interest.name).faceids[0],
            from_face_id)
        self.assertEqual(
            self.icn_layer.pit.find_pit_entry(interest.name).name,
            interest.name)

    def test_ICNLayer_interest_forward_deduplication(self):
        """Test ICN layer with no CS and no PIT entry and deduplication"""
        self.icn_layer.start_process()

        to_face_id = 1
        from_face_id_1 = 2
        from_face_id_2 = 3

        # Add entry to the fib
        name = Name("/test")
        interest1 = Interest("/test/data")
        interest2 = Interest("/test/data")
        self.icn_layer.fib.add_fib_entry(name, [to_face_id])

        # forward entry
        self.queue1_icn_routing_up.put([from_face_id_1, interest1])
        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.queue1_icn_routing_up.put([from_face_id_2, interest2], block=True)
        self.assertTrue(self.queue1_icn_routing_down.empty())

        time.sleep(3)

        # check output
        self.assertEqual(face_id, to_face_id)
        self.assertEqual(data, interest1)

        time.sleep(
            0.3
        )  # sleep required, since there is no blocking get before the checks
        # check data structures
        self.assertEqual(self.icn_layer.cs.get_container_size(), 0)
        self.assertEqual(self.icn_layer.fib.get_container_size(), 1)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(
            self.icn_layer.fib.find_fib_entry(name).faceid, [to_face_id])
        self.assertEqual(self.icn_layer.fib.find_fib_entry(name).name, name)
        self.assertEqual(
            len(self.icn_layer.pit.find_pit_entry(interest1.name).faceids), 2)
        self.assertEqual(
            self.icn_layer.pit.find_pit_entry(interest1.name).faceids,
            [from_face_id_1, from_face_id_2])
        self.assertEqual(
            self.icn_layer.pit.find_pit_entry(interest1.name).name,
            interest1.name)

    def test_ICNLayer_interest_forward_content_match(self):
        """Test ICN layer with CS entry matching"""
        self.icn_layer.start_process()

        from_face_id = 2
        interest = Interest("/test/data")

        #add content
        content = Content("/test/data")
        self.icn_layer.cs.add_content_object(content)

        #request content
        self.queue1_icn_routing_up.put([from_face_id, interest])

        #get content
        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.assertEqual(data, content)
        self.assertEqual(face_id, from_face_id)

    def test_ICNLayer_interest_forward_content_no_match(self):
        """Test ICN layer with CS entry no match"""
        self.icn_layer.start_process()

        to_face_id = 1
        from_face_id = 2
        interest = Interest("/test/data/bla")
        name = Name("/test/data")
        self.icn_layer.fib.add_fib_entry(name, [to_face_id], static=True)

        #add content
        content = Content("/test/data")
        self.icn_layer.cs.add_content_object(content)

        #request content
        self.queue1_icn_routing_up.put([from_face_id, interest])

        #get data from fib
        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.assertTrue(data, interest)
        self.assertTrue(face_id, to_face_id)
        self.assertTrue(self.queue1_icn_routing_up.empty())
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(
            self.icn_layer.pit.find_pit_entry(interest.name).name,
            interest.name)

    def test_ICNLayer_content_no_pit(self):
        """Test receiving a content object with no PIT entry"""
        self.icn_layer.start_process()
        from_face_id = 2
        content = Content("/test/data")
        self.queue1_icn_routing_up.put([from_face_id, content])

        self.assertTrue(self.queue1_icn_routing_down.empty())

    def test_ICNLayer_content_pit(self):
        """Test receiving a content object with PIT entry"""
        self.icn_layer.start_process()
        content_in_face_id = 1
        from_face_id = 2
        name = Name("/test/data")
        content = Content("/test/data")

        self.icn_layer.pit.add_pit_entry(name, from_face_id, None, None)

        self.queue1_icn_routing_up.put([content_in_face_id, content])

        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.assertEqual(face_id, from_face_id)
        self.assertEqual(data, content)

    def test_ICNLayer_content_two_pit_entries(self):
        """Test receiving a content object with two PIT entries"""
        self.icn_layer.start_process()
        content_in_face_id = 1
        from_face_id_1 = 2
        from_face_id_2 = 3
        name = Name("/test/data")
        content = Content("/test/data")

        self.icn_layer.pit.add_pit_entry(name, from_face_id_1, None, False)
        self.icn_layer.pit.add_pit_entry(name, from_face_id_2, None, False)

        self.queue1_icn_routing_up.put([content_in_face_id, content])

        try:
            face_id_1, data1 = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.assertEqual(face_id_1, from_face_id_1)
        self.assertEqual(data1, content)

        face_id_2, data2 = self.queue1_icn_routing_down.get()

        self.assertEqual(face_id_2, from_face_id_2)
        self.assertEqual(data2, content)

    def test_ICNLayer_ageing_pit(self):
        """Test PIT ageing"""

        self.icn_layer.start_process()
        from_face_id_1 = 1
        to_face_id = 2
        name = Name("/test/data")
        interest = Interest(name)

        self.icn_layer.fib.add_fib_entry(name, [to_face_id])
        self.icn_layer.pit.add_pit_entry(name, from_face_id_1, interest, False)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(name).name, name)

        #test retransmit 1
        self.icn_layer.ageing()
        time.sleep(0.1)
        self.assertFalse(self.icn_layer.queue_to_lower.empty())
        try:
            rface_id, rinterest = self.icn_layer.queue_to_lower.get(
                timeout=2.0)
        except:
            self.fail()
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(rface_id, to_face_id)
        self.assertEqual(rinterest, interest)

        # test retransmit 2
        self.icn_layer.ageing()
        time.sleep(0.1)
        self.assertFalse(self.icn_layer.queue_to_lower.empty())
        try:
            rface_id, rinterest = self.icn_layer.queue_to_lower.get(
                timeout=2.0)
        except:
            self.fail()
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(rface_id, to_face_id)
        self.assertEqual(rinterest, interest)

        #Wait for timeout
        time.sleep(2)

        # test retransmit 3 to get number of retransmit
        self.icn_layer.ageing()
        time.sleep(0.1)
        self.assertFalse(self.icn_layer.queue_to_lower.empty())
        try:
            rface_id, rinterest = self.icn_layer.queue_to_lower.get(
                timeout=2.0)
        except:
            self.fail()
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(rface_id, to_face_id)
        self.assertEqual(rinterest, interest)

        # test remove pit entry
        self.icn_layer.ageing()
        #nack = self.icn_layer.queue_to_lower.get(timeout=8.0) # invalid, no PIT Timeout Nack anymore
        #self.assertEqual(nack, [1, Nack(rinterest.name, NackReason.PIT_TIMEOUT, rinterest)])
        self.assertTrue(self.icn_layer.queue_to_lower.empty())
        self.assertEqual(self.icn_layer.pit.get_container_size(), 0)

    def test_ICNLayer_ageing_cs(self):
        """Test CS ageing and static entries"""

        self.icn_layer.start_process()
        name1 = Name("/test/data")
        content1 = Content(name1, "HelloWorld")

        name2 = Name("/data/test")
        content2 = Content(name2, "Goodbye")

        self.icn_layer.cs.add_content_object(content1)
        self.icn_layer.cs.add_content_object(content2, static=True)

        self.assertEqual(self.icn_layer.cs.get_container_size(), 2)
        self.assertEqual(
            self.icn_layer.cs.find_content_object(name1).content, content1)
        self.assertEqual(
            self.icn_layer.cs.find_content_object(name2).content, content2)

        #Test aging 1
        self.icn_layer.ageing()
        self.assertEqual(self.icn_layer.cs.get_container_size(), 2)
        self.assertEqual(
            self.icn_layer.cs.find_content_object(name1).content, content1)
        self.assertEqual(
            self.icn_layer.cs.find_content_object(name2).content, content2)

        time.sleep(2)
        # Test aging 2
        self.icn_layer.ageing()
        self.assertEqual(self.icn_layer.cs.get_container_size(), 1)
        self.assertEqual(
            self.icn_layer.cs.find_content_object(name2).content, content2)

    def test_ICNLayer_content_from_app_layer_no_pit(self):
        """get content from app layer when there is no pit entry available"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()

        n = Name("/test/data")
        c = Content(n, "HelloWorld")
        self.icn_layer.queue_from_higher.put([0, c])
        time.sleep(1)
        self.assertTrue(self.queue1_icn_routing_down.empty())

    def test_ICNLayer_content_from_app_layer(self):
        """get content from app layer when there is a pit entry available"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()
        face_id = 1
        n = Name("/test/data")
        self.icn_layer.pit.add_pit_entry(n, face_id)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        c = Content(n, "HelloWorld")
        self.icn_layer.queue_from_higher.put([0, c])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data, [face_id, c])

    def test_ICNLayer_content_to_app_layer_no_pit(self):
        """get content to app layer no pit"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()
        from_face_id = 1
        n = Name("/test/data")
        c = Content(n, "HelloWorld")
        self.icn_layer.queue_from_lower.put([from_face_id, c])
        time.sleep(1)
        self.assertTrue(self.icn_layer.queue_to_higher.empty())

    def test_ICNLayer_content_to_app_layer(self):
        """get content to app layer"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()
        face_id = -1
        from_face_id = 1
        n = Name("/test/data")
        self.icn_layer.pit.add_pit_entry(n,
                                         face_id,
                                         interest=None,
                                         local_app=True)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        c = Content(n, "HelloWorld")
        self.icn_layer.queue_from_lower.put([from_face_id, c])
        try:
            data = self.icn_layer.queue_to_higher.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data, [1, c])

    def test_ICNLayer_interest_from_app_layer_no_pit(self):
        """Test sending and interest message from APP with no PIT entry"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app = True
        self.icn_layer.start_process()
        face_id = 1
        n = Name("/test/data")
        i = Interest(n)
        self.icn_layer.fib.add_fib_entry(n, [face_id], True)
        self.icn_layer.queue_from_higher.put([0, i])
        try:
            to_faceid, data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(to_faceid, face_id)
        self.assertEqual(i, data)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(n).interest, i)
        self.assertTrue(self.icn_layer.pit.find_pit_entry(n).local_app[0])

    def test_ICNLayer_interest_from_app_layer_pit(self):
        """Test sending and interest message from APP with a PIT entry --> interest not for higher layer"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app = True
        self.icn_layer.start_process()
        face_id = 1
        from_face_id = 2
        n = Name("/test/data")
        i = Interest(n)
        self.icn_layer.fib.add_fib_entry(n, [face_id], True)
        self.icn_layer.pit.add_pit_entry(n, from_face_id, i, local_app=False)
        self.assertFalse(self.icn_layer.pit.find_pit_entry(n).local_app[0])
        self.icn_layer.queue_from_higher.put([0, i])
        try:
            to_face_id, data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(to_face_id, face_id)
        self.assertEqual(i, data)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(n).interest, i)
        self.assertFalse(self.icn_layer.pit.find_pit_entry(
            n).local_app[0])  #Just forward, not from local app

    def test_ICNLayer_interest_to_app_layer_no_pit(self):
        """Test sending and interest message from APP with no PIT entry"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app = True
        self.icn_layer.start_process()
        face_id = 1
        from_face_id = 2
        n = Name("/test/data")
        i = Interest(n)
        self.icn_layer.fib.add_fib_entry(n, [face_id], True)
        self.icn_layer.queue_from_lower.put([from_face_id, i])
        try:
            data = self.icn_layer.queue_to_higher.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data[1], i)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(n).interest, i)

    def test_ICNLayer_interest_to_app_layer_pit(self):
        """Test sending and interest message from APP with a PIT entry"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app = True
        self.icn_layer.start_process()
        face_id = [1]
        from_face_id = 2
        n = Name("/test/data")
        i = Interest(n)
        self.icn_layer.fib.add_fib_entry(n, face_id, True)
        self.icn_layer.pit.add_pit_entry(n, from_face_id, i, local_app=False)
        self.icn_layer.queue_from_lower.put([from_face_id, i])
        time.sleep(1)
        self.assertTrue(self.icn_layer.queue_to_higher.empty()
                        )  #--> deduplication by pit entry

    def test_ICNLayer_interest_to_app_layer_cs(self):
        """Test sending and interest message from APP with a CS entry"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app = True
        self.icn_layer.start_process()
        face_id = 1
        from_face_id = 2
        n = Name("/test/data")
        i = Interest(n)
        c = Content(n, "Hello World")
        self.icn_layer.fib.add_fib_entry(n, [face_id], True)
        self.icn_layer.cs.add_content_object(c)
        self.icn_layer.queue_from_lower.put([from_face_id, i])
        try:
            to_face_id, data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(to_face_id, from_face_id)
        self.assertEqual(data, c)
        self.assertTrue(self.icn_layer.queue_to_higher.empty()
                        )  # --> was answered by using Content from cache

    def test_ICNLayer_issue_nack_no_content_no_fib_from_lower(self):
        """Test if ICN Layer issues Nack if no content and no fib entry is available from lower"""
        self.icn_layer.start_process()
        interest = Interest("/test/data")
        nack = Nack(interest.name, NackReason.NO_ROUTE, interest=interest)
        self.icn_layer.queue_from_lower.put([1, interest])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        fid = data[0]
        packet = data[1]
        self.assertEqual(fid, 1)
        self.assertEqual(packet, nack)

    def test_ICNLayer_issue_nack_no_content_no_fib_from_higher(self):
        """Test if ICN Layer issues Nack if no content and no fib entry is available from higher"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()
        interest = Interest("/test/data")
        nack = Nack(interest.name, NackReason.NO_ROUTE, interest=interest)
        self.icn_layer.queue_from_higher.put([1, interest])
        try:
            data = self.icn_layer.queue_to_higher.get(timeout=2.0)
        except:
            self.fail()
        fid = data[0]
        packet = data[1]
        self.assertEqual(fid, 1)
        self.assertEqual(packet, nack)

    def test_ICNLayer_handling_nack_no_fib(self):
        """Test if ICN Layer handles a Nack correctly if no fib entry is available"""
        self.icn_layer.start_process()
        n1 = Name("/test/data")
        i1 = Interest(n1)
        fid_1 = 1
        nack_1 = Nack(n1, NackReason.NO_ROUTE, interest=i1)
        self.icn_layer.pit.add_pit_entry(n1, fid_1, i1, False)
        self.icn_layer.queue_from_lower.put([2, nack_1])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data[0], fid_1)
        self.assertEqual(data[1], nack_1)

    def test_ICNLayer_handling_nack_next_fib(self):
        """Test if ICN Layer handles a Nack correctly if further fib entry is available"""
        self.icn_layer.start_process()
        n1 = Name("/test/data/d1")
        i1 = Interest(n1)
        from_fid = 1
        to_fib1 = 2
        to_fib2 = 3
        to_fib3 = 4
        nack_1 = Nack(n1, NackReason.NO_ROUTE, interest=i1)
        self.icn_layer.pit.add_pit_entry(n1, from_fid, i1, None)
        self.icn_layer.fib.add_fib_entry(Name("/test"), [to_fib2])
        self.icn_layer.fib.add_fib_entry(Name("/test/data"), [to_fib3])
        self.icn_layer.fib.add_fib_entry(Name("/test/data/d1"), [
            to_fib1
        ])  #assuning this entry was used first and is active when nack arrives
        self.icn_layer.queue_from_lower.put([to_fib1, nack_1])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data[0], to_fib3)
        self.assertEqual(data[1], i1)
        #check testing second path
        self.icn_layer.queue_from_lower.put([to_fib3, nack_1])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data[0], to_fib2)
        self.assertEqual(data[1], i1)
        #check no path left
        self.icn_layer.queue_from_lower.put([to_fib2, nack_1])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data[0], from_fid)
        self.assertEqual(data[1], nack_1)

    def test_multicast_and_nack_handling(self):
        """Test if a multicast works, and if the nack counter for the multicast works"""

        i1 = Interest("/test/data")
        n1 = Nack(i1.name, NackReason.NO_CONTENT, i1)

        self.icn_layer.start_process()

        self.icn_layer.fib.add_fib_entry(i1.name, [2, 3])

        self.icn_layer.queue_from_lower.put([1, i1])

        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        d2 = self.icn_layer.queue_to_lower.get(timeout=2.0)

        self.assertEqual([2, i1], d1)
        self.assertEqual([3, i1], d2)

        self.icn_layer.queue_from_lower.put([3, n1])
        self.assertTrue(self.icn_layer.queue_to_lower.empty())

        self.icn_layer.queue_from_lower.put([2, n1])
        d3 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        self.assertEqual([1, n1], d3)

    def test_multicast_and_nack_handling_with_retransmit(self):
        """Test if a multicast works, and if the nack counter for the multicast works"""

        i1 = Interest("/test/data")
        n1 = Nack(i1.name, NackReason.NO_CONTENT, i1)

        self.icn_layer.start_process()

        self.icn_layer.fib.add_fib_entry(i1.name, [2, 3])

        self.icn_layer.queue_from_lower.put([1, i1])

        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        d2 = self.icn_layer.queue_to_lower.get(timeout=2.0)

        self.assertEqual([2, i1], d1)
        self.assertEqual([3, i1], d2)

        self.icn_layer.queue_from_lower.put([3, n1])
        self.assertTrue(self.icn_layer.queue_to_lower.empty())

        self.icn_layer.ageing()
        d3 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        self.assertEqual([2, i1], d3)

        self.icn_layer.queue_from_lower.put([2, n1])
        d4 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        self.assertEqual([1, n1], d4)
Esempio n. 4
0
    def setUp(self):
        synced_data_struct_factory = PiCNSyncDataStructFactory()
        synced_data_struct_factory.register('cs', ContentStoreMemoryExact)
        synced_data_struct_factory.register('pit',
                                            PendingInterstTableMemoryExact)
        synced_data_struct_factory.register(
            'fib', ForwardingInformationBaseMemoryPrefix)
        synced_data_struct_factory.register('faceidtable', FaceIDDict)
        synced_data_struct_factory.create_manager()
        # Set up forwarder
        cs = synced_data_struct_factory.manager.cs()
        pit = synced_data_struct_factory.manager.pit()
        fib = synced_data_struct_factory.manager.fib()
        prefixes = [(Name('/test/prefix/repos'), True)]
        # Auto-assign port
        forwarder_interface = UDP4Interface(0)
        forwarder_fidtable = synced_data_struct_factory.manager.faceidtable()
        forwarder_linklayer = BasicLinkLayer([forwarder_interface],
                                             forwarder_fidtable)
        forwarder_port = forwarder_interface.get_port()
        forwarder_encoder = NdnTlvEncoder()
        icnlayer = BasicICNLayer()
        icnlayer.cs = cs
        icnlayer.pit = pit
        icnlayer.fib = fib
        forwarder_autoconfiglayer = AutoconfigServerLayer(
            forwarder_linklayer, registration_prefixes=prefixes)
        forwarder_autoconfiglayer.fib = fib
        self.forwarder = LayerStack([
            icnlayer, forwarder_autoconfiglayer,
            BasicPacketEncodingLayer(forwarder_encoder), forwarder_linklayer
        ])

        # Set up repo
        repository = MockRepository(Name('/thisshouldbechanged'))
        repo_chunkifyer = SimpleContentChunkifyer()
        repo_chunklayer = BasicChunkLayer(repo_chunkifyer)
        repo_encoder = NdnTlvEncoder()
        # Auto-assign port
        repo_interface = UDP4Interface(0)
        repo_fidtable = synced_data_struct_factory.manager.faceidtable()
        repo_linklayer = BasicLinkLayer([repo_interface], repo_fidtable)
        repo_port = repo_interface.get_port()
        self.repo = LayerStack([
            BasicRepositoryLayer(repository), repo_chunklayer,
            AutoconfigRepoLayer('testrepo', repo_linklayer, repository,
                                '127.0.0.1', forwarder_port),
            BasicPacketEncodingLayer(repo_encoder), repo_linklayer
        ])

        # Set up fetch client
        client_chunkifyer = SimpleContentChunkifyer()
        client_chunklayer = BasicChunkLayer(client_chunkifyer)
        client_encoder = NdnTlvEncoder()
        client_interface = UDP4Interface(0)
        client_fidtable = synced_data_struct_factory.manager.faceidtable()
        client_linklayer = BasicLinkLayer([client_interface], client_fidtable)
        self.client = LayerStack([
            client_chunklayer,
            AutoconfigClientLayer(client_linklayer, bcport=forwarder_port),
            BasicPacketEncodingLayer(client_encoder), client_linklayer
        ])
Esempio n. 5
0
    def __init__(self,
                 port=9000,
                 log_level=255,
                 encoder: BasicEncoder = None,
                 interfaces: List[BaseInterface] = None,
                 executors: BaseNFNExecutor = None,
                 ageing_interval: int = 3,
                 use_thunks=False):
        # debug level
        logger = Logger("NFNForwarder", log_level)
        logger.info("Start PiCN NFN Forwarder on port " + str(port))

        # packet encoder
        if encoder is None:
            self.encoder = SimpleStringEncoder(log_level=log_level)
        else:
            encoder.set_log_level(log_level)
            self.encoder = encoder

    # setup data structures
        synced_data_struct_factory = PiCNSyncDataStructFactory()
        synced_data_struct_factory.register("cs", ContentStoreMemoryExact)
        synced_data_struct_factory.register(
            "fib", ForwardingInformationBaseMemoryPrefix)
        synced_data_struct_factory.register("pit",
                                            PendingInterstTableMemoryExact)
        synced_data_struct_factory.register("faceidtable", FaceIDDict)

        synced_data_struct_factory.register("computation_table",
                                            NFNComputationList)
        synced_data_struct_factory.register("timeoutprevention_dict",
                                            TimeoutPreventionMessageDict)
        if use_thunks:
            synced_data_struct_factory.register("thunktable", ThunkList)
            synced_data_struct_factory.register("plantable", PlanTable)

        synced_data_struct_factory.create_manager()

        cs = synced_data_struct_factory.manager.cs()
        fib = synced_data_struct_factory.manager.fib()
        pit = synced_data_struct_factory.manager.pit()
        faceidtable = synced_data_struct_factory.manager.faceidtable()

        self.parser = DefaultNFNParser()
        if use_thunks:
            thunktable = synced_data_struct_factory.manager.thunktable()
            plantable = synced_data_struct_factory.manager.plantable(
                self.parser)

        #setup chunkifier
        self.chunkifier = SimpleContentChunkifyer()

        # default interface
        if interfaces is not None:
            self.interfaces = interfaces
            mgmt_port = port
        else:
            interfaces = [UDP4Interface(port)]
            mgmt_port = interfaces[0].get_port()

        # initialize layers
        self.linklayer = BasicLinkLayer(interfaces,
                                        faceidtable,
                                        log_level=log_level)
        self.packetencodinglayer = BasicPacketEncodingLayer(
            self.encoder, log_level=log_level)
        self.icnlayer = BasicICNLayer(log_level=log_level,
                                      ageing_interval=ageing_interval)
        self.chunklayer = BasicChunkLayer(self.chunkifier, log_level=log_level)

        # setup nfn
        self.icnlayer._interest_to_app = True
        if executors is None:
            self.executors = {"PYTHON": NFNPythonExecutor()}
        else:
            self.executors = executors
        self.r2cclient = TimeoutR2CHandler()
        comp_table = synced_data_struct_factory.manager.computation_table(
            self.r2cclient, self.parser)
        self.nfnlayer = BasicNFNLayer(cs,
                                      fib,
                                      pit,
                                      faceidtable,
                                      comp_table,
                                      self.executors,
                                      self.parser,
                                      self.r2cclient,
                                      log_level=log_level)
        if use_thunks:
            self.thunk_layer = BasicThunkLayer(cs,
                                               fib,
                                               pit,
                                               faceidtable,
                                               thunktable,
                                               plantable,
                                               self.parser,
                                               log_level=log_level)
            self.nfnlayer.optimizer = ThunkPlanExecutor(
                cs, fib, pit, faceidtable, plantable)

        timeoutprevention_dict = synced_data_struct_factory.manager.timeoutprevention_dict(
        )
        self.timeoutpreventionlayer = BasicTimeoutPreventionLayer(
            timeoutprevention_dict, comp_table, pit=pit, log_level=log_level)

        if use_thunks:
            self.lstack: LayerStack = LayerStack([
                self.nfnlayer, self.chunklayer, self.timeoutpreventionlayer,
                self.thunk_layer, self.icnlayer, self.packetencodinglayer,
                self.linklayer
            ])
        else:
            self.lstack: LayerStack = LayerStack([
                self.nfnlayer, self.chunklayer, self.timeoutpreventionlayer,
                self.icnlayer, self.packetencodinglayer, self.linklayer
            ])

        self.icnlayer.cs = cs
        self.icnlayer.fib = fib
        self.icnlayer.pit = pit

        # mgmt
        self.mgmt = Mgmt(self.icnlayer.cs,
                         self.icnlayer.fib,
                         self.icnlayer.pit,
                         self.linklayer,
                         mgmt_port,
                         self.stop_forwarder,
                         log_level=log_level)
Esempio n. 6
0
    def __init__(self,
                 port=9000,
                 log_level=255,
                 encoder: BasicEncoder = None,
                 routing: bool = False,
                 peers=None,
                 autoconfig: bool = False,
                 interfaces: List[BaseInterface] = None,
                 ageing_interval: int = 3,
                 node_name: str = None):
        # debug level
        logger = Logger("ICNForwarder",
                        log_level)  # FIXME: Why isn't this self.logger???
        self._node_name = node_name
        # packet encoder
        if encoder is None:
            self.encoder = SimpleStringEncoder(log_level=log_level)
        else:
            encoder.set_log_level(log_level=log_level)
            self.encoder = encoder

        # setup data structures
        synced_data_struct_factory = PiCNSyncDataStructFactory()
        synced_data_struct_factory.register("cs", ContentStoreMemoryExact)
        synced_data_struct_factory.register(
            "fib", ForwardingInformationBaseMemoryPrefix)
        synced_data_struct_factory.register("pit",
                                            PendingInterestTableMemoryExact)
        synced_data_struct_factory.register("rib", TreeRoutingInformationBase)
        synced_data_struct_factory.register("faceidtable", FaceIDDict)
        synced_data_struct_factory.create_manager()

        cs = synced_data_struct_factory.manager.cs()
        fib = synced_data_struct_factory.manager.fib()
        pit = synced_data_struct_factory.manager.pit()

        rib = None
        if routing:
            rib = synced_data_struct_factory.manager.rib()
        faceidtable = synced_data_struct_factory.manager.faceidtable()

        # default interface
        if interfaces is not None:
            self.interfaces = interfaces
            mgmt_port = port
        else:
            interfaces = [UDP4Interface(port)]
            mgmt_port = interfaces[0].get_port()

        # initialize layers
        self.linklayer = BasicLinkLayer(interfaces,
                                        faceidtable,
                                        log_level=log_level)
        self.packetencodinglayer = BasicPacketEncodingLayer(
            self.encoder, log_level=log_level)
        self.icnlayer = BasicICNLayer(log_level=log_level,
                                      ageing_interval=ageing_interval)

        self.lstack: LayerStack = LayerStack(
            [self.icnlayer, self.packetencodinglayer, self.linklayer])

        if autoconfig:
            self.autoconfiglayer: AutoconfigServerLayer = AutoconfigServerLayer(
                linklayer=self.linklayer,
                address='127.0.0.1',
                registration_prefixes=[(Name('/testnetwork/repos'), True)],
                log_level=log_level)
            self.lstack.insert(self.autoconfiglayer, below_of=self.icnlayer)

        if routing:
            self.routinglayer = BasicRoutingLayer(self.linklayer,
                                                  peers=peers,
                                                  log_level=log_level)
            self.lstack.insert(self.routinglayer, below_of=self.icnlayer)

        self.icnlayer.cs = cs
        self.icnlayer.fib = fib
        # ----- by Luc # FIXME: How to pass these parameters to __init__
        self.icnlayer.fib.logger = logger
        self.icnlayer.fib.node_name = self._node_name
        # ----- by Luc # FIXME: How to pass these parameters to __init__
        self.icnlayer.pit = pit
        self.icnlayer.pit.logger = logger
        self.icnlayer.pit.node_name = self._node_name
        # -----

        if autoconfig:
            self.autoconfiglayer.fib = fib
        if routing:
            self.routinglayer.rib = rib
            self.routinglayer.fib = fib

        # mgmt
        self.mgmt = Mgmt(cs,
                         fib,
                         pit,
                         self.linklayer,
                         mgmt_port,
                         self.stop_forwarder,
                         log_level=log_level)
Esempio n. 7
0
class ICNForwarder(object):
    """A ICN Forwarder using PiCN"""
    def __init__(self,
                 port=9000,
                 log_level=255,
                 encoder: BasicEncoder = None,
                 routing: bool = False,
                 peers=None,
                 autoconfig: bool = False,
                 interfaces: List[BaseInterface] = None,
                 ageing_interval: int = 3):
        # debug level
        logger = Logger("ICNForwarder", log_level)

        # packet encoder
        if encoder is None:
            self.encoder = SimpleStringEncoder(log_level=log_level)
        else:
            encoder.set_log_level(log_level=log_level)
            self.encoder = encoder

        # setup data structures
        synced_data_struct_factory = PiCNSyncDataStructFactory()
        synced_data_struct_factory.register("cs", ContentStoreMemoryExact)
        synced_data_struct_factory.register(
            "fib", ForwardingInformationBaseMemoryPrefix)
        synced_data_struct_factory.register("pit",
                                            PendingInterstTableMemoryExact)
        synced_data_struct_factory.register("rib", TreeRoutingInformationBase)
        synced_data_struct_factory.register("faceidtable", FaceIDDict)
        synced_data_struct_factory.create_manager()

        cs = synced_data_struct_factory.manager.cs()
        fib = synced_data_struct_factory.manager.fib()
        pit = synced_data_struct_factory.manager.pit()
        if routing:
            rib = synced_data_struct_factory.manager.rib()
        faceidtable = synced_data_struct_factory.manager.faceidtable()

        #default interface
        if interfaces is not None:
            self.interfaces = interfaces
            mgmt_port = port
        else:
            interfaces = [UDP4Interface(port)]
            mgmt_port = interfaces[0].get_port()

        # initialize layers
        self.linklayer = BasicLinkLayer(interfaces,
                                        faceidtable,
                                        log_level=log_level)
        self.packetencodinglayer = BasicPacketEncodingLayer(
            self.encoder, log_level=log_level)
        self.icnlayer = BasicICNLayer(log_level=log_level,
                                      ageing_interval=ageing_interval)

        self.lstack: LayerStack = LayerStack(
            [self.icnlayer, self.packetencodinglayer, self.linklayer])

        if autoconfig:
            self.autoconfiglayer: AutoconfigServerLayer = AutoconfigServerLayer(
                linklayer=self.linklayer,
                address='127.0.0.1',
                registration_prefixes=[(Name('/testnetwork/repos'), True)],
                log_level=log_level)
            self.lstack.insert(self.autoconfiglayer, below_of=self.icnlayer)

        if routing:
            self.routinglayer = BasicRoutingLayer(self.linklayer,
                                                  peers=peers,
                                                  log_level=log_level)
            self.lstack.insert(self.routinglayer, below_of=self.icnlayer)

        self.icnlayer.cs = cs
        self.icnlayer.fib = fib
        self.icnlayer.pit = pit
        if autoconfig:
            self.autoconfiglayer.fib = fib
        if routing:
            self.routinglayer.rib = rib
            self.routinglayer.fib = fib

        # mgmt
        self.mgmt = Mgmt(cs,
                         fib,
                         pit,
                         self.linklayer,
                         mgmt_port,
                         self.stop_forwarder,
                         log_level=log_level)

    def start_forwarder(self):
        # start processes
        self.lstack.start_all()
        self.icnlayer.ageing()
        self.mgmt.start_process()

    def stop_forwarder(self):
        # Stop processes
        self.lstack.stop_all()
        # close queues file descriptors
        if self.mgmt.process:
            self.mgmt.stop_process()
        self.lstack.close_all()
Esempio n. 8
0
class NFNForwarder(object):
    """NFN Forwarder for PICN"""

    # TODO add chunking layer
    def __init__(self,
                 port=9000,
                 log_level=255,
                 encoder: BasicEncoder = None,
                 interfaces: List[BaseInterface] = None,
                 ageing_interval: int = 3):
        # debug level
        logger = Logger("NFNForwarder", log_level)
        logger.info("Start PiCN NFN Forwarder on port " + str(port))

        # packet encoder
        if encoder is None:
            self.encoder = SimpleStringEncoder(log_level=log_level)
        else:
            encoder.set_log_level(log_level)
            self.encoder = encoder

    # setup data structures
        synced_data_struct_factory = PiCNSyncDataStructFactory()
        synced_data_struct_factory.register("cs", ContentStoreMemoryExact)
        synced_data_struct_factory.register(
            "fib", ForwardingInformationBaseMemoryPrefix)
        synced_data_struct_factory.register("pit",
                                            PendingInterstTableMemoryExact)
        synced_data_struct_factory.register("faceidtable", FaceIDDict)

        synced_data_struct_factory.register("computation_table",
                                            NFNComputationList)
        synced_data_struct_factory.create_manager()

        cs = synced_data_struct_factory.manager.cs()
        fib = synced_data_struct_factory.manager.fib()
        pit = synced_data_struct_factory.manager.pit()
        faceidtable = synced_data_struct_factory.manager.faceidtable()

        #setup chunkifier
        self.chunkifier = SimpleContentChunkifyer()

        # default interface
        if interfaces is not None:
            self.interfaces = interfaces
            mgmt_port = port
        else:
            interfaces = [UDP4Interface(port)]
            mgmt_port = interfaces[0].get_port()

        # initialize layers
        self.linklayer = BasicLinkLayer(interfaces,
                                        faceidtable,
                                        log_level=log_level)
        self.packetencodinglayer = BasicPacketEncodingLayer(
            self.encoder, log_level=log_level)
        self.icnlayer = BasicICNLayer(log_level=log_level,
                                      ageing_interval=ageing_interval)
        self.chunklayer = BasicChunkLayer(self.chunkifier, log_level=log_level)

        # setup nfn
        self.icnlayer._interest_to_app = True
        self.executors = {"PYTHON": NFNPythonExecutor()}
        self.parser = DefaultNFNParser()
        self.r2cclient = TimeoutR2CHandler()
        comp_table = synced_data_struct_factory.manager.computation_table(
            self.r2cclient, self.parser)
        self.nfnlayer = BasicNFNLayer(cs,
                                      fib,
                                      pit,
                                      faceidtable,
                                      comp_table,
                                      self.executors,
                                      self.parser,
                                      self.r2cclient,
                                      log_level=log_level)

        self.lstack: LayerStack = LayerStack([
            self.nfnlayer, self.chunklayer, self.icnlayer,
            self.packetencodinglayer, self.linklayer
        ])

        self.icnlayer.cs = cs
        self.icnlayer.fib = fib
        self.icnlayer.pit = pit

        # mgmt
        self.mgmt = Mgmt(self.icnlayer.cs,
                         self.icnlayer.fib,
                         self.icnlayer.pit,
                         self.linklayer,
                         mgmt_port,
                         self.stop_forwarder,
                         log_level=log_level)

    def start_forwarder(self):
        # start processes
        self.lstack.start_all()
        self.icnlayer.ageing()
        self.mgmt.start_process()

    def stop_forwarder(self):
        # Stop processes
        self.mgmt.stop_process()
        self.lstack.stop_all()
        # close queues file descriptors
        self.lstack.close_all()
Esempio n. 9
0
class test_BasicICNLayer(unittest.TestCase):
    """Test the Basic ICN Layer implementation"""

    def setUp(self):

        #setup icn_layer
        self.icn_layer = BasicICNLayer(log_level=255)

        synced_data_struct_factory = PiCNSyncDataStructFactory()
        synced_data_struct_factory.register("cs", ContentStoreMemoryExact)
        synced_data_struct_factory.register("fib", ForwardingInformationBaseMemoryPrefix)
        synced_data_struct_factory.register("pit", PendingInterstTableMemoryExact)
        synced_data_struct_factory.create_manager()

        cs = synced_data_struct_factory.manager.cs()
        fib = synced_data_struct_factory.manager.fib()
        pit = synced_data_struct_factory.manager.pit()
        cs.set_cs_timeout(2)
        pit.set_pit_timeout(2)
        pit.set_pit_retransmits(2)

        self.icn_layer.cs = cs
        self.icn_layer.fib = fib
        self.icn_layer.pit = pit

        #setup queues icn_routing layer
        self.queue1_icn_routing_up = multiprocessing.Queue()
        self.queue1_icn_routing_down = multiprocessing.Queue()

        #add queues to ICN layer
        self.icn_layer.queue_from_lower = self.queue1_icn_routing_up
        self.icn_layer.queue_to_lower = self.queue1_icn_routing_down

    def tearDown(self):
        self.icn_layer.stop_process()

    def test_ICNLayer_interest_forward_basic(self):
        """Test ICN layer with no CS and PIT entry"""
        self.icn_layer.start_process()

        to_faceid = 1
        from_faceid = 2

        #Add entry to the fib
        name = Name("/test/data")
        interest = Interest("/test/data")
        self.icn_layer.fib.add_fib_entry(name, [to_faceid], static=True)

        #forward entry
        self.queue1_icn_routing_up.put([from_faceid, interest])
        try:
            faceid, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        #check output
        self.assertEqual(faceid, to_faceid)
        self.assertEqual(data, interest)

        #check data structures
        self.assertEqual(self.icn_layer.cs.get_container_size(), 0)
        self.assertEqual(self.icn_layer.fib.get_container_size(), 1)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(self.icn_layer.fib.find_fib_entry(name).faceid, [to_faceid])
        self.assertEqual(self.icn_layer.fib.find_fib_entry(name).name, name)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(name).faceids[0], from_faceid)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(name).name, name)

    def test_ICNLayer_interest_forward_longest_match(self):
        """Test ICN layer with no CS and no PIT entry and longest match"""
        self.icn_layer.start_process()

        to_face_id = 1
        from_face_id = 2

        #Add entry to the fib
        name = Name("/test")
        interest = Interest("/test/data")
        self.icn_layer.fib.add_fib_entry(name, [to_face_id], static=True)

        #forward entry
        self.queue1_icn_routing_up.put([from_face_id, interest])
        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        #check output
        self.assertEqual(face_id, to_face_id)
        self.assertEqual(data, interest)

        #check data structures
        self.assertEqual(self.icn_layer.cs.get_container_size(), 0)
        self.assertEqual(self.icn_layer.fib.get_container_size(), 1)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(self.icn_layer.fib.find_fib_entry(name).faceid, [to_face_id])
        self.assertEqual(self.icn_layer.fib.find_fib_entry(name).name, name)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(interest.name).faceids[0], from_face_id)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(interest.name).name, interest.name)

    def test_ICNLayer_interest_forward_deduplication(self):
        """Test ICN layer with no CS and no PIT entry and deduplication"""
        self.icn_layer.start_process()

        to_face_id = 1
        from_face_id_1 = 2
        from_face_id_2 = 3

        # Add entry to the fib
        name = Name("/test")
        interest1 = Interest("/test/data")
        interest2 = Interest("/test/data")
        self.icn_layer.fib.add_fib_entry(name, [to_face_id])

        # forward entry
        self.queue1_icn_routing_up.put([from_face_id_1, interest1])
        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.queue1_icn_routing_up.put([from_face_id_2, interest2], block=True)
        self.assertTrue(self.queue1_icn_routing_down.empty())

        time.sleep(3)

        # check output
        self.assertEqual(face_id, to_face_id)
        self.assertEqual(data, interest1)

        time.sleep(0.3) # sleep required, since there is no blocking get before the checks
        # check data structures
        self.assertEqual(self.icn_layer.cs.get_container_size(), 0)
        self.assertEqual(self.icn_layer.fib.get_container_size(), 1)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(self.icn_layer.fib.find_fib_entry(name).faceid, [to_face_id])
        self.assertEqual(self.icn_layer.fib.find_fib_entry(name).name, name)
        self.assertEqual(len(self.icn_layer.pit.find_pit_entry(interest1.name).faceids), 2)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(interest1.name).faceids, [from_face_id_1, from_face_id_2])
        self.assertEqual(self.icn_layer.pit.find_pit_entry(interest1.name).name, interest1.name)

    def test_ICNLayer_interest_forward_content_match(self):
        """Test ICN layer with CS entry matching"""
        self.icn_layer.start_process()

        from_face_id = 2
        interest = Interest("/test/data")

        #add content
        content = Content("/test/data")
        self.icn_layer.cs.add_content_object(content)

        #request content
        self.queue1_icn_routing_up.put([from_face_id, interest])

        #get content
        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.assertEqual(data, content)
        self.assertEqual(face_id, from_face_id)

    def test_ICNLayer_interest_forward_content_no_match(self):
        """Test ICN layer with CS entry no match"""
        self.icn_layer.start_process()

        to_face_id = 1
        from_face_id = 2
        interest = Interest("/test/data/bla")
        name = Name("/test/data")
        self.icn_layer.fib.add_fib_entry(name, [to_face_id], static=True)

        #add content
        content = Content("/test/data")
        self.icn_layer.cs.add_content_object(content)

        #request content
        self.queue1_icn_routing_up.put([from_face_id, interest])

        #get data from fib
        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.assertTrue(data, interest)
        self.assertTrue(face_id, to_face_id)
        self.assertTrue(self.queue1_icn_routing_up.empty())
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(interest.name).name, interest.name)

    def test_ICNLayer_content_no_pit(self):
        """Test receiving a content object with no PIT entry"""
        self.icn_layer.start_process()
        from_face_id = 2
        content = Content("/test/data")
        self.queue1_icn_routing_up.put([from_face_id, content])

        self.assertTrue(self.queue1_icn_routing_down.empty())

    def test_ICNLayer_content_pit(self):
        """Test receiving a content object with PIT entry"""
        self.icn_layer.start_process()
        content_in_face_id = 1
        from_face_id = 2
        name = Name("/test/data")
        content = Content("/test/data")

        self.icn_layer.pit.add_pit_entry(name, from_face_id, content_in_face_id, None, None)

        self.queue1_icn_routing_up.put([content_in_face_id, content])

        try:
            face_id, data = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.assertEqual(face_id, from_face_id)
        self.assertEqual(data, content)

    def test_ICNLayer_content_two_pit_entries(self):
        """Test receiving a content object with two PIT entries"""
        self.icn_layer.start_process()
        content_in_face_id = 1
        from_face_id_1 = 2
        from_face_id_2 = 3
        name = Name("/test/data")
        content = Content("/test/data")

        self.icn_layer.pit.add_pit_entry(name, from_face_id_1, content_in_face_id, None, False)
        self.icn_layer.pit.add_pit_entry(name, from_face_id_2, content_in_face_id, None, False)

        self.queue1_icn_routing_up.put([content_in_face_id, content])

        try:
            face_id_1, data1 = self.queue1_icn_routing_down.get(timeout=2.0)
        except:
            self.fail()

        self.assertEqual(face_id_1, from_face_id_1)
        self.assertEqual(data1, content)

        face_id_2, data2 = self.queue1_icn_routing_down.get()

        self.assertEqual(face_id_2, from_face_id_2)
        self.assertEqual(data2, content)

    def test_ICNLayer_ageing_pit(self):
        """Test PIT ageing"""

        self.icn_layer.start_process()
        from_face_id_1 = 1
        to_face_id = 2
        name = Name("/test/data")
        interest = Interest(name)

        self.icn_layer.fib.add_fib_entry(name, [to_face_id])
        self.icn_layer.pit.add_pit_entry(name, from_face_id_1, to_face_id, interest, False)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(name).name, name)

        # test retransmit 1
        self.icn_layer.ageing()
        time.sleep(0.1)
        self.assertFalse(self.icn_layer.queue_to_lower.empty())
        try:
            rface_id, rinterest = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(rface_id, to_face_id)
        self.assertEqual(rinterest, interest)

        # test retransmit 2
        self.icn_layer.ageing()
        time.sleep(0.1)
        self.assertFalse(self.icn_layer.queue_to_lower.empty())
        try:
            rface_id, rinterest = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(rface_id, to_face_id)
        self.assertEqual(rinterest, interest)

        # Wait for timeout
        time.sleep(2)

        # test retransmit 3 to get number of retransmit
        self.icn_layer.ageing()
        time.sleep(0.1)
        self.assertFalse(self.icn_layer.queue_to_lower.empty())
        try:
            rface_id, rinterest = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        self.assertEqual(rface_id, to_face_id)
        self.assertEqual(rinterest, interest)

        # test remove pit entry
        self.icn_layer.ageing()
        # nack = self.icn_layer.queue_to_lower.get(timeout=8.0) # invalid, no PIT Timeout Nack anymore
        # self.assertEqual(nack, [1, Nack(rinterest.name, NackReason.PIT_TIMEOUT, rinterest)])
        self.assertTrue(self.icn_layer.queue_to_lower.empty())
        self.assertEqual(self.icn_layer.pit.get_container_size(), 0)

    def test_ICNLayer_ageing_cs(self):
        """Test CS ageing and static entries"""

        self.icn_layer.start_process()
        name1 = Name("/test/data")
        content1 = Content(name1, "HelloWorld")

        name2 = Name("/data/test")
        content2 = Content(name2, "Goodbye")

        self.icn_layer.cs.add_content_object(content1)
        self.icn_layer.cs.add_content_object(content2, static=True)

        self.assertEqual(self.icn_layer.cs.get_container_size(), 2)
        self.assertEqual(self.icn_layer.cs.find_content_object(name1).content, content1)
        self.assertEqual(self.icn_layer.cs.find_content_object(name2).content, content2)

        #Test aging 1
        self.icn_layer.ageing()
        self.assertEqual(self.icn_layer.cs.get_container_size(), 2)
        self.assertEqual(self.icn_layer.cs.find_content_object(name1).content, content1)
        self.assertEqual(self.icn_layer.cs.find_content_object(name2).content, content2)

        time.sleep(2)
        # Test aging 2
        self.icn_layer.ageing()
        self.assertEqual(self.icn_layer.cs.get_container_size(), 1)
        self.assertEqual(self.icn_layer.cs.find_content_object(name2).content, content2)

    def test_ICNLayer_content_from_app_layer_no_pit(self):
        """get content from app layer when there is no pit entry available"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()

        n = Name("/test/data")
        c = Content(n, "HelloWorld")
        self.icn_layer.queue_from_higher.put([0, c])
        time.sleep(1)
        self.assertTrue(self.queue1_icn_routing_down.empty())

    def test_ICNLayer_content_from_app_layer(self):
        """get content from app layer when there is a pit entry available"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()
        face_id = 1
        n = Name("/test/data")
        self.icn_layer.pit.add_pit_entry(n, face_id, -1)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        c = Content(n, "HelloWorld")
        self.icn_layer.queue_from_higher.put([0, c])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data, [face_id, c])

    def test_ICNLayer_content_to_app_layer_no_pit(self):
        """get content to app layer no pit"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()
        from_face_id = 1
        n = Name("/test/data")
        c = Content(n, "HelloWorld")
        self.icn_layer.queue_from_lower.put([from_face_id, c])
        time.sleep(1)
        self.assertTrue(self.icn_layer.queue_to_higher.empty())
        
    def test_ICNLayer_content_to_app_layer(self):
        """get content to app layer"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()
        face_id = -1
        from_face_id = 1
        n = Name("/test/data")
        self.icn_layer.pit.add_pit_entry(n, face_id, -1, interest=None, local_app=True)
        self.assertEqual(self.icn_layer.pit.get_container_size(), 1)
        c = Content(n, "HelloWorld")
        self.icn_layer.queue_from_lower.put([from_face_id, c])
        try:
            data = self.icn_layer.queue_to_higher.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data, [1, c])

    def test_ICNLayer_interest_from_app_layer_no_pit(self):
        """Test sending and interest message from APP with no PIT entry"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app=True
        self.icn_layer.start_process()
        face_id = 1
        n = Name("/test/data")
        i = Interest(n)
        self.icn_layer.fib.add_fib_entry(n, [face_id], True)
        self.icn_layer.queue_from_higher.put([0, i])
        try:
            to_faceid, data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(to_faceid, face_id)
        self.assertEqual(i, data)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(n).interest, i)
        self.assertTrue(self.icn_layer.pit.find_pit_entry(n).local_app[0])

    def test_ICNLayer_interest_from_app_layer_pit(self):
        """Test sending and interest message from APP with a PIT entry --> interest not for higher layer"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app=True
        self.icn_layer.start_process()
        face_id = 1
        from_face_id = 2
        n = Name("/test/data")
        i = Interest(n)
        self.icn_layer.fib.add_fib_entry(n, [face_id], True)
        self.icn_layer.pit.add_pit_entry(n, from_face_id, face_id, i, local_app=False)
        self.assertFalse(self.icn_layer.pit.find_pit_entry(n).local_app[0])
        self.icn_layer.queue_from_higher.put([0, i])
        try:
            to_face_id, data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(to_face_id, face_id)
        self.assertEqual(i, data)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(n).interest, i)
        self.assertFalse(self.icn_layer.pit.find_pit_entry(n).local_app[0]) #Just forward, not from local app

    def test_ICNLayer_interest_to_app_layer_no_pit(self):
        """Test sending and interest message from APP with no PIT entry"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app = True
        self.icn_layer.start_process()
        face_id = 1
        from_face_id = 2
        n = Name("/test/data")
        i = Interest(n)
        self.icn_layer.fib.add_fib_entry(n, [face_id], True)
        self.icn_layer.queue_from_lower.put([from_face_id, i])
        try:
            data = self.icn_layer.queue_to_higher.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data[1], i)
        self.assertEqual(self.icn_layer.pit.find_pit_entry(n).interest, i)

    def test_ICNLayer_interest_to_app_layer_pit(self):
        """Test sending and interest message from APP with a PIT entry"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app = True
        self.icn_layer.start_process()
        face_id = [1]
        from_face_id = 2
        n = Name("/test/data")
        i = Interest(n)
        self.icn_layer.fib.add_fib_entry(n, face_id, True)
        self.icn_layer.pit.add_pit_entry(n, from_face_id, face_id[0], i, local_app=False)
        self.icn_layer.queue_from_lower.put([from_face_id, i])
        time.sleep(1)
        self.assertTrue(self.icn_layer.queue_to_higher.empty()) #--> deduplication by pit entry

    def test_ICNLayer_interest_to_app_layer_cs(self):
        """Test sending and interest message from APP with a CS entry"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer._interest_to_app = True
        self.icn_layer.start_process()
        face_id = 1
        from_face_id = 2
        n = Name("/test/data")
        i = Interest(n)
        c = Content(n, "Hello World")
        self.icn_layer.fib.add_fib_entry(n, [face_id], True)
        self.icn_layer.cs.add_content_object(c)
        self.icn_layer.queue_from_lower.put([from_face_id, i])
        try:
            to_face_id, data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(to_face_id, from_face_id)
        self.assertEqual(data, c)
        self.assertTrue(self.icn_layer.queue_to_higher.empty())  # --> was answered by using Content from cache

    def test_ICNLayer_issue_nack_no_content_no_fib_from_lower(self):
        """Test if ICN Layer issues Nack if no content and no fib entry is available from lower"""
        self.icn_layer.start_process()
        interest = Interest("/test/data")
        nack = Nack(interest.name, NackReason.NO_ROUTE, interest=interest)
        self.icn_layer.queue_from_lower.put([1, interest])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        fid = data[0]
        packet = data[1]
        self.assertEqual(fid, 1)
        self.assertEqual(packet, nack)

    def test_ICNLayer_issue_nack_no_content_no_fib_from_higher(self):
        """Test if ICN Layer issues Nack if no content and no fib entry is available from higher"""
        queue_to_higher = multiprocessing.Queue()
        queue_from_higher = multiprocessing.Queue()
        self.icn_layer.queue_to_higher = queue_to_higher
        self.icn_layer.queue_from_higher = queue_from_higher
        self.icn_layer.start_process()
        interest = Interest("/test/data")
        nack = Nack(interest.name, NackReason.NO_ROUTE, interest=interest)
        self.icn_layer.queue_from_higher.put([1, interest])
        try:
            data = self.icn_layer.queue_to_higher.get(timeout=2.0)
        except:
            self.fail()
        fid = data[0]
        packet = data[1]
        self.assertEqual(fid, 1)
        self.assertEqual(packet, nack)
    #TODO CHECK
    def test_ICNLayer_handling_nack_no_fib(self):
        """Test if ICN Layer handles a Nack correctly if no fib entry is available"""
        self.icn_layer.start_process()
        n1 = Name("/test/data")
        i1 = Interest(n1)
        fid_1 = 1
        nack_1 = Nack(n1, NackReason.NO_ROUTE, interest=i1)
        self.icn_layer.pit.add_pit_entry(n1, fid_1, -1, i1, False)
        self.icn_layer.queue_from_lower.put([2, nack_1])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
            print(data)
        except:
            self.fail()
        self.assertEqual(data[0], fid_1)
        self.assertEqual(data[1], nack_1)

    #TODO Fix the error
    def test_ICNLayer_handling_nack_next_fib(self):
        """Test if ICN Layer handles a Nack correctly if further fib entry is available"""
        self.icn_layer.start_process()
        n1 = Name("/test/data/d1")
        i1 = Interest(n1)
        from_fid = 1
        to_fib1 = 2
        to_fib2 = 3
        to_fib3 = 4
        nack_1 = Nack(n1, NackReason.NO_ROUTE, interest=i1)

        self.icn_layer.pit.add_pit_entry(n1, from_fid, to_fib3, i1, None)
        self.icn_layer.pit.add_used_fib_face(n1, [to_fib3])

        self.icn_layer.fib.add_fib_entry(Name("/test"), [to_fib1])
        self.icn_layer.fib.add_fib_entry(Name("/test/data"), [to_fib2])
        self.icn_layer.fib.add_fib_entry(Name("/test/data/d1"), [to_fib3]) #assuming this entry was used first and is active when nack arrives
        self.icn_layer.queue_from_lower.put([to_fib3, nack_1])

        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
             self.fail()

        self.assertEqual(data[0], to_fib2)
        self.assertEqual(data[1], i1)
        #check testing second path
        self.icn_layer.queue_from_lower.put([to_fib2, nack_1])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)

        except:
            self.fail()
        self.assertEqual(data[0], to_fib1)
        self.assertEqual(data[1], i1)
        #check no path left
        self.icn_layer.queue_from_lower.put([to_fib1, nack_1])
        try:
            data = self.icn_layer.queue_to_lower.get(timeout=2.0)
        except:
            self.fail()
        self.assertEqual(data[0], from_fid)
        self.assertEqual(data[1], nack_1)


    def test_multicast_and_nack_handling(self):
        """Test if a multicast works, and if the nack counter for the multicast works"""

        i1 = Interest("/test/data")
        n1 = Nack(i1.name, NackReason.NO_CONTENT, i1)

        self.icn_layer.start_process()

        self.icn_layer.fib.add_fib_entry(i1.name, [2,3,4])

        self.icn_layer.queue_from_lower.put([1, i1])

        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        self.assertEqual([2, i1], d1)

        self.assertTrue(self.icn_layer.queue_to_lower.empty())


        self.icn_layer.queue_from_lower.put([2, n1])
        d2 = self.icn_layer.queue_to_lower.get(timeout=4.0)
        print(d2)
        self.assertEqual([3, i1], d2)

        self.assertTrue(self.icn_layer.queue_to_lower.empty())

        self.icn_layer.queue_from_lower.put([3, n1])
        try:
            d3 = self.icn_layer.queue_to_lower.get(timeout=4.0)
        except:
            self.fail()
        print(d3)
        self.assertEqual([4, i1], d3)
        ##
        #
        #
        # self.assertTrue(self.icn_layer.queue_to_lower.empty())
        #
        # self.icn_layer.queue_from_lower.put([2, n1])
        # d3 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        # self.assertEqual([1, n1], d3)

    def test_communicating_vessels_forwarding_strategy(self):
        """This function test the whole idea of forwarding strategy with multiple PIT entries
         and multiple FIB entries with multiple matches in PIT and FIB and also it checks the NACK handler in case of one face was nacked in a fib entry or all faces
          of a fib entry was nacked"""

        ab_name = Name("/a/b")
        i1 = Interest("/a/b/x")
        i2 = Interest("/a/b/y")
        i3 = Interest("/a/b/z")
        i4 = Interest("/a/b/w")
        i5 = Interest("/a/b/k")


        i6 = Interest("/x/y")
        i7 = Interest("/x")
        i8 = Interest("/m/n")
        i9 = Interest("/o/p")

        n1 = Nack(i1.name, NackReason.NO_CONTENT, i1)



        self.icn_layer.start_process()
        self.icn_layer.fib.add_fib_entry(ab_name, [1, 2, 3])
        # here the fib table has many entries which contains the prefix of ab_name
        self.icn_layer.fib.add_fib_entry(i6.name, [1, 4])
        self.icn_layer.fib.add_fib_entry(i7.name, [2, 3])
        self.icn_layer.fib.add_fib_entry(i8.name, [1, 5])
        self.icn_layer.fib.add_fib_entry(i9.name, [5, 3])

        #send the first interest ("/a/b/x") with no matching PIT entry. The outgoing face should be "1"
        #as it is the first Interest and there is no pending Interests to affect the decision
        self.icn_layer.queue_from_lower.put([10, i1])
        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        pit_entry = self.icn_layer.pit.find_pit_entry(i1.name)
        self.assertEqual([1], pit_entry.outgoing_faces)

        #send the second Interest ("/a/b/y") while the PIT entry of ("a/b/x") was not removed yet from the PIT
        #The interest should be sent to face "2" as the occupancy of face "1" is higher than the occupancy of "2" and "3"
        self.icn_layer.queue_from_lower.put([10, i2])
        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        pit_entry = self.icn_layer.pit.find_pit_entry(i2.name)
        self.assertEqual([2], pit_entry.outgoing_faces)

        #send bunch of Interests which are ("/x/y"), ("/x"), ("/m/n"),("/o/p"). In this case and because there is no matching entry in PIT for any of them.
        # each one will be sent to the first avaialble face in FIB. So i6 will be sent to 1. i7 will be sent to 2...

        self.icn_layer.queue_from_lower.put([10, i6])
        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        self.icn_layer.queue_from_lower.put([10, i7])
        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        self.icn_layer.queue_from_lower.put([10, i8])
        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        self.icn_layer.queue_from_lower.put([10, i9])
        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)

        # send the second Interest i3 ("/a/b/z") while the PIT entry of ("a/b/x") and ("a/b/y") was not removed yet from the PIT
        # The interest should be sent to face "3" as the occupancy of face "1" and face "2" is higher than the occupancy of "3"
        self.icn_layer.queue_from_lower.put([10, i3])
        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        pit_entry = self.icn_layer.pit.find_pit_entry(i3.name)
        self.assertEqual([3], pit_entry.outgoing_faces)


        # now send an interest i4 (("/a/b/w") while the previous three matching interests still exist in PIT. All faces have equal capacity so it will be sent to the first one.
        self.icn_layer.queue_from_lower.put([10, i4])
        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        pit_entry = self.icn_layer.pit.find_pit_entry(i4.name)
        self.assertEqual([1], pit_entry.outgoing_faces)

        # we are removing i4 and i1 from the PIT table
        self.icn_layer.pit.remove_pit_entry(i4.name)
        self.icn_layer.pit.remove_pit_entry(i1.name)

        # senf=d i5 while i2 and i3 still exist in PIT and they match i5. So the interest will be sent to face 1 because i2 is sent to 2 and i3 is sent to 3 so 2,3 have higher occupancy than 1
        self.icn_layer.queue_from_lower.put([10, i5])
        d1 = self.icn_layer.queue_to_lower.get(timeout=2.0)
        pit_entry = self.icn_layer.pit.find_pit_entry(i5.name)
        self.assertEqual([1], pit_entry.outgoing_faces)