def test_rank_computation(self, sim_engine): # https://tools.ietf.org/html/rfc8180#section-5.1.2 sim_engine = sim_engine( diff_config = { 'exec_numMotes' : 6, 'exec_numSlotframesPerRun': 10000, 'app_pkPeriod' : 0, 'secjoin_enabled' : False, 'tsch_keep_alive_interval': 0, 'conn_class' : 'Linear', } ) print("TESTING RECEIVED") # shorthand motes = sim_engine.motes asn_at_end_of_simulation = ( sim_engine.settings.tsch_slotframeLength * sim_engine.settings.exec_numSlotframesPerRun ) # get the network ready to be test u.run_until_everyone_joined(sim_engine) assert sim_engine.getAsn() < asn_at_end_of_simulation # set ETX=100/75 (numTx=100, numTxAck=75) for mote_id in range(1, len(motes)): mote = motes[mote_id] parent = motes[mote_id - 1] # inject DIO to the mote dio = parent.rpl._create_DIO() dio['mac'] = {'srcMac': parent.get_mac_addr()} mote.rpl.action_receiveDIO(dio) # set numTx and numTxAck preferred_parent = mote.rpl.of.preferred_parent preferred_parent['numTx'] = 100 preferred_parent['numTxAck'] = 75 mote.rpl.of._update_neighbor_rank_increase(preferred_parent) # test using rank values in Figure 4 of RFC 8180 assert motes[0].rpl.get_rank() == 256 assert motes[0].rpl.getDagRank() == 1 print motes[1].rpl.of.preferred_parent assert motes[1].rpl.get_rank() == 768 assert motes[1].rpl.getDagRank() == 3 assert motes[2].rpl.get_rank() == 1280 assert motes[2].rpl.getDagRank() == 5 assert motes[3].rpl.get_rank() == 1792 assert motes[3].rpl.getDagRank() == 7 assert motes[4].rpl.get_rank() == 2304 assert motes[4].rpl.getDagRank() == 9 assert motes[5].rpl.get_rank() == 2816 assert motes[5].rpl.getDagRank() == 11
def test_run_until_everyone_joined( sim_engine, exec_num_motes, secjoin_enabled ): sim_engine = sim_engine( diff_config = { 'exec_numMotes' : exec_num_motes, 'secjoin_enabled' : secjoin_enabled, 'exec_numSlotframesPerRun': 10000, 'app_pkPeriod' : 0, 'conn_class' : 'Linear' } ) # everyone should have not been joined yet assert ( len([m for m in sim_engine.motes if m.secjoin.getIsJoined() is False]) > 0 ) u.run_until_everyone_joined(sim_engine) # everyone should have been joined assert ( len([m for m in sim_engine.motes if m.secjoin.getIsJoined() is False]) == 0 ) # expect the simulator has the remaining time; that is, the simulator # should not be paused by run_until_end() called inside of # run_until_everyone_joined() slotframe_length = sim_engine.settings.tsch_slotframeLength num_slotframes = sim_engine.settings.exec_numSlotframesPerRun asn_at_end = slotframe_length * num_slotframes assert sim_engine.getAsn() < asn_at_end
def test_upstream_routing(sim_engine): sim_engine = sim_engine( diff_config = { 'exec_numMotes': 3, 'conn_class' : 'FullyMeshed' } ) root = sim_engine.motes[0] mote_1 = sim_engine.motes[1] mote_2 = sim_engine.motes[2] asn_at_end_of_simulation = ( sim_engine.settings.tsch_slotframeLength * sim_engine.settings.exec_numSlotframesPerRun ) u.run_until_everyone_joined(sim_engine) assert sim_engine.getAsn() < asn_at_end_of_simulation # We're making the RPL topology of "root -- mote_1 (-- mote_2)" dio_from_root = root.rpl._create_DIO() dio_from_root['mac'] = {'srcMac': root.get_mac_addr()} dio_from_root['app']['rank'] = 256 mote_1.rpl.action_receiveDIO(dio_from_root) assert mote_1.rpl.getPreferredParent() == root.get_mac_addr() # Then, put mote_1 behind mote_2: "root -- mote_2 -- mote_1" mote_2.rpl.action_receiveDIO(dio_from_root) dio_from_mote_2 = mote_2.rpl._create_DIO() dio_from_mote_2['mac'] = {'srcMac': mote_2.get_mac_addr()} dio_from_root['app']['rank'] = 65535 mote_1.rpl.action_receiveDIO(dio_from_root) dio_from_mote_2['app']['rank'] = 256 # inject DIO from mote_2 to mote_1 mote_1.rpl.action_receiveDIO(dio_from_mote_2) assert mote_1.rpl.getPreferredParent() == mote_2.get_mac_addr() assert mote_2.rpl.getPreferredParent() == root.get_mac_addr() # create a dummy packet, which is used to get the next hop dummy_packet = { 'net': { 'srcIp': mote_1.get_ipv6_global_addr(), 'dstIp': root.get_ipv6_global_addr() } } # the next hop should be parent assert mote_1.sixlowpan._find_nexthop_mac_addr(dummy_packet) == mote_1.rpl.getPreferredParent()
def test_free_run(self, sim_engine): # all the motes should be able to join the network sim_engine = sim_engine( diff_config={ 'exec_numSlotframesPerRun': 10000, 'conn_class': 'Random', 'secjoin_enabled': False, "phy_numChans": 1, }) asn_at_end_of_simulation = ( sim_engine.settings.tsch_slotframeLength * sim_engine.settings.exec_numSlotframesPerRun) u.run_until_everyone_joined(sim_engine) assert sim_engine.getAsn() < asn_at_end_of_simulation
def test_upstream_routing(sim_engine): sim_engine = sim_engine(diff_config={ 'exec_numMotes': 3, 'conn_class': 'FullyMeshed', }) root = sim_engine.motes[0] mote_1 = sim_engine.motes[1] mote_2 = sim_engine.motes[2] u.run_until_everyone_joined(sim_engine) # We're making the RPL topology of "root -- mote_1 (-- mote_2)" dio_from_root = root.rpl._create_DIO() dio_from_root['mac'] = {'srcMac': root.id} dio_from_root['app']['rank'] = 256 mote_1.rpl.action_receiveDIO(dio_from_root) assert mote_1.rpl.getPreferredParent() == root.id # Then, put mote_1 behind mote_2: "root -- mote_2 -- mote_1" mote_2.rpl.action_receiveDIO(dio_from_root) dio_from_mote_2 = mote_2.rpl._create_DIO() dio_from_mote_2['mac'] = {'srcMac': mote_2.id} dio_from_root['app']['rank'] = 65535 mote_1.rpl.action_receiveDIO(dio_from_root) dio_from_mote_2['app']['rank'] = 256 # inject DIO from mote_2 to mote_1 mote_1.rpl.action_receiveDIO(dio_from_mote_2) assert mote_1.rpl.getPreferredParent() == mote_2.id assert mote_2.rpl.getPreferredParent() == root.id # create a dummy packet, which is used to get the next hop dummy_packet = {'net': {'srcIp': mote_1.id, 'dstIp': root.id}} # the next hop should be parent assert mote_1.sixlowpan.find_nexthop_mac_addr( dummy_packet) == mote_1.rpl.getPreferredParent()
def test_tx_with_two_slotframes(sim_engine): sim_engine = sim_engine( diff_config={ 'app_pkPeriod': 0, 'exec_numMotes': 2, 'exec_numSlotframesPerRun': 1000, 'secjoin_enabled': False, 'sf_class': 'SFNone', 'conn_class': 'Linear', 'rpl_extensions': [], 'rpl_daoPeriod': 0 }) # shorthands root = sim_engine.motes[0] hop_1 = sim_engine.motes[1] # add one slotframe to the two motes for mote in sim_engine.motes: mote.tsch.add_slotframe(1, 101) asn_at_end_of_simulation = (sim_engine.settings.tsch_slotframeLength * sim_engine.settings.exec_numSlotframesPerRun) u.run_until_everyone_joined(sim_engine) assert sim_engine.getAsn() < asn_at_end_of_simulation # put DIO to hop1 dio = root.rpl._create_DIO() dio['mac'] = {'srcMac': root.get_mac_addr()} hop_1.rpl.action_receiveDIO(dio) # install one TX cells to each slotframe for i in range(2): hop_1.tsch.addCell(slotOffset=i + 1, channelOffset=0, neighbor=root.get_mac_addr(), cellOptions=[d.CELLOPTION_TX], slotframe_handle=i) root.tsch.addCell(slotOffset=i + 1, channelOffset=0, neighbor=hop_1.get_mac_addr(), cellOptions=[d.CELLOPTION_RX], slotframe_handle=i) # the first dedicated cell is scheduled at slot_offset 1, the other is at # slot_offset 2 cell_in_slotframe_0 = hop_1.tsch.get_cells(root.get_mac_addr(), 0)[0] cell_in_slotframe_1 = hop_1.tsch.get_cells(root.get_mac_addr(), 1)[0] # run until the end of this slotframe slot_offset = sim_engine.getAsn() % 101 u.run_until_asn(sim_engine, sim_engine.getAsn() + (101 - slot_offset - 1)) # send two application packets, which will be sent over the dedicated cells hop_1.app._send_a_single_packet() hop_1.app._send_a_single_packet() # run for one slotframe asn = sim_engine.getAsn() assert (asn % 101) == 100 # the next slot is slotoffset 0 u.run_until_asn(sim_engine, asn + 101) # check logs ## TX side (hop_1) logs = [ log for log in u.read_log_file(filter=[SimLog.LOG_TSCH_TXDONE['type']], after_asn=asn) if log['_mote_id'] == hop_1.id ] assert len(logs) == 2 assert (logs[0]['_asn'] % 101) == cell_in_slotframe_0.slot_offset assert (logs[1]['_asn'] % 101) == cell_in_slotframe_1.slot_offset ## RX side (root) logs = [ log for log in u.read_log_file(filter=[SimLog.LOG_TSCH_RXDONE['type']], after_asn=asn) if log['_mote_id'] == root.id ] assert len(logs) == 2 assert (logs[0]['_asn'] % 101) == cell_in_slotframe_0.slot_offset assert (logs[1]['_asn'] % 101) == cell_in_slotframe_1.slot_offset # confirm hop_1 has the minimal cell assert len(hop_1.tsch.get_cells(None)) == 1 assert (hop_1.tsch.get_cells(None)[0].options == [ d.CELLOPTION_TX, d.CELLOPTION_RX, d.CELLOPTION_SHARED ])
def test_retransmission_backoff_algorithm(sim_engine, cell_type): sim_engine = sim_engine( diff_config={ 'exec_numSlotframesPerRun': 10000, 'exec_numMotes': 2, 'app_pkPeriod': 0, 'secjoin_enabled': False, 'tsch_keep_alive_interval': 0 }) sim_log = SimLog.SimLog() # filter logs to make this test faster; we need only SimLog.LOG_TSCH_TXDONE sim_log.set_log_filters([SimLog.LOG_TSCH_TXDONE['type']]) # for quick access root = sim_engine.motes[0] hop_1 = sim_engine.motes[1] slotframe_length = sim_engine.settings.tsch_slotframeLength # increase TSCH_MAXTXRETRIES so that we can have enough retransmission # samples to validate d.TSCH_MAXTXRETRIES = 100 #== test setup == u.run_until_everyone_joined(sim_engine) # make hop_1 ready to send an application packet assert hop_1.rpl.dodagId is None dio = root.rpl._create_DIO() dio['mac'] = {'srcMac': root.get_mac_addr()} hop_1.rpl.action_receiveDIO(dio) assert hop_1.rpl.dodagId is not None # make root ignore all the incoming frame for this test def ignoreRx(self, packet, channel): self.waitingFor = None isACKed = False return isACKed root.tsch.rxDone = types.MethodType(ignoreRx, root.tsch) if cell_type == 'dedicated-cell': # allocate one TX=1/RX=1/SHARED=1 cell to the motes as their dedicate cell. cellOptions = [d.CELLOPTION_TX, d.CELLOPTION_RX, d.CELLOPTION_SHARED] assert len(root.tsch.get_cells(hop_1.get_mac_addr())) == 0 root.tsch.addCell(1, 1, hop_1.get_mac_addr(), cellOptions) assert len(root.tsch.get_cells(hop_1.get_mac_addr())) == 1 assert len(hop_1.tsch.get_cells(root.get_mac_addr())) == 0 hop_1.tsch.addCell(1, 1, root.get_mac_addr(), cellOptions) assert len(hop_1.tsch.get_cells(root.get_mac_addr())) == 1 # make sure hop_1 send a application packet when the simulator starts hop_1.tsch.txQueue = [] hop_1.app._send_a_single_packet() assert len(hop_1.tsch.txQueue) == 1 #== start test == asn_starting_test = sim_engine.getAsn() # run the simulator until hop_1 drops the packet or the simulation ends def drop_packet(self, packet, reason): if packet['type'] == d.PKT_TYPE_DATA: # pause the simulator sim_engine.pauseAtAsn(sim_engine.getAsn() + 1) hop_1.drop_packet = types.MethodType(drop_packet, hop_1) u.run_until_end(sim_engine) # confirm # - hop_1 sent the application packet to the root # - retransmission backoff worked logs = u.read_log_file(filter=[SimLog.LOG_TSCH_TXDONE['type']], after_asn=asn_starting_test) app_data_tx_logs = [] for log in logs: if ((log['_mote_id'] == hop_1.id) and (root.is_my_mac_addr(log['packet']['mac']['dstMac'])) and (log['packet']['type'] == d.PKT_TYPE_DATA)): app_data_tx_logs.append(log) assert len(app_data_tx_logs) == 1 + d.TSCH_MAXTXRETRIES # all transmission should have happened only on the dedicated cell if it's # available (it shouldn't transmit a unicast frame to the root on the # minimal (shared) cell. if cell_type == 'dedicated-cell': _cell = hop_1.tsch.get_cells(root.get_mac_addr())[0] expected_cell_offset = _cell.slot_offset elif cell_type == 'shared-cell': expected_cell_offset = 0 # the minimal (shared) cell else: raise NotImplementedError() for log in app_data_tx_logs: slot_offset = log['_asn'] % slotframe_length assert slot_offset == expected_cell_offset # retransmission should be performed after backoff wait; we should see gaps # between consecutive retransmissions. If all the gaps are 101 slots, that # is, one slotframe, this means there was no backoff wait between # transmissions. timestamps = [log['_asn'] for log in app_data_tx_logs] diffs = map(lambda x: x[1] - x[0], zip(timestamps[:-1], timestamps[1:])) assert len([diff for diff in diffs if diff != slotframe_length]) > 0
def test_msf(self, sim_engine): """ Test Scheduling Function Traffic Adaptation - objective : test if msf adjust the number of allocated cells in accordance with traffic - precondition: form a 2-mote linear network - precondition: the network is formed - action : change traffic - expectation : MSF should trigger ADD/DELETE/RELOCATE accordingly """ sim_engine = sim_engine( diff_config={ 'app_pkPeriod': 0, 'app_pkPeriodVar': 0.05, 'exec_numMotes': 3, 'exec_numSlotframesPerRun': 4000, 'secjoin_enabled': False, 'sf_class': 'MSF', 'conn_class': 'Linear', }) # XXX d.MSF_MIN_NUM_TX = 10 # for quick access root = sim_engine.motes[0] hop_1 = sim_engine.motes[1] hop_2 = sim_engine.motes[2] asn_at_end_of_simulation = ( sim_engine.settings.tsch_slotframeLength * sim_engine.settings.exec_numSlotframesPerRun) # make hop_1 not receive anything on dedicated RX cells other than the # first allocated one than one dedicated RX cell so that MSF would # perform cell relocation hop_1.tsch.original_addCell = hop_1.tsch.addCell hop_1.tsch.original_tsch_action_RX = hop_1.tsch._tsch_action_RX def new_addCell(self, slotOffset, channelOffset, neighbor, cellOptions): if ((cellOptions == [d.CELLOPTION_RX]) and (len(self.getRxCells(neighbor)) == 0)): # remember the slotoffset of first allocated dedicated cell. While # this cell might be deleted later, ignore such an edge case for # this test. self.first_dedicated_slot_offset = slotOffset self.original_addCell(slotOffset, channelOffset, neighbor, cellOptions) def new_action_RX(self): slot_offset = self.engine.getAsn( ) % self.settings.tsch_slotframeLength cell = self.schedule[slot_offset] if ((cell['neighbor'] is not None) and hasattr(self, 'first_dedicated_slot_offset') and ((self.first_dedicated_slot_offset) != slot_offset)): # do nothing on this dedicated cell pass else: self.original_tsch_action_RX() hop_1.tsch.addCell = types.MethodType(new_addCell, hop_1.tsch) hop_1.tsch._tsch_action_RX = types.MethodType(new_action_RX, hop_1.tsch) # wait for the network formed u.run_until_everyone_joined(sim_engine) # wait for hop_2 to get ready to start application run_until_mote_is_ready_for_app(sim_engine, hop_2) assert sim_engine.getAsn() < asn_at_end_of_simulation # generate application traffic which is supposed to trigger an ADD # transaction between hop_2 and hop_1 asn_starting_app_traffic = sim_engine.getAsn() set_app_traffic_rate(sim_engine, 1.4) start_app_traffic(hop_2) run_until_dedicated_tx_cell_is_allocated(sim_engine, hop_2) assert sim_engine.getAsn() < asn_at_end_of_simulation # increase the traffic asn_increasing_app_traffic = sim_engine.getAsn() set_app_traffic_rate(sim_engine, 1.1) run_until_dedicated_tx_cell_is_allocated(sim_engine, hop_2) assert sim_engine.getAsn() < asn_at_end_of_simulation # decrease the traffic; run until a RELOCATE command is issued set_app_traffic_rate(sim_engine, 1.4) run_until_sixp_cmd_is_seen(sim_engine, hop_2, d.SIXP_CMD_RELOCATE) assert sim_engine.getAsn() < asn_at_end_of_simulation # stop the traffic; run until a DELETE command is issued stop_app_traffic(sim_engine) run_until_sixp_cmd_is_seen(sim_engine, hop_2, d.SIXP_CMD_DELETE) assert sim_engine.getAsn() < asn_at_end_of_simulation