Example #1
0
    def put_packet_on_link(self, arg_list):
        '''
        Description:        This puts a Packet on the Link.  It then enqueues 
                            some Event.  One will check after transmission time 
                            if there is another Packet that can go in the same 
                            direction. One will check wait for transmission 
                            time then reset the in_transmission flag.  One 
                            waits for the Packet to reach the other end to see 
                            if there is a Packet waiting to go the opposite 
                            direction, and the last is for the other end to 
                            receive the Packet.
        
        Arguments:          arg_list ([]) 
                                - Unused.
        
        Return Values:      None.
        
        Shared Variables:   buffers (READ/WRITE) 
                                - Read to see if there is anything to put on 
                                the Link, written if something is taken
                                off of the buffer to put on the link.
                          
                            packets_on_link (READ/WRITE) 
                                - Read to see direction of travel and written 
                                to put Packet on the Link.
                          
                            in_transmission (WRITE) 
                                - Written to True when a packet is being 
                                transmitted.
                          
                            data_on_link (WRITE) 
                                - The amount of data on the Link is updated.
        
        Global Variables: None.
        
        Limitations:      None.
        
        Known Bugs:       None.
        
        Revision History: 2015/10/22: Created function handle and docstring
                          2015/10/29: Filled function in.
                          2015/11/03: Changed the link buffers to use the 
                                      python queue data structure and only 
                                      store the flow_name and packet_name
                          2015/11/16: Now checks for next packet to put on 
                                      Link and creates Event for it.
        '''
        # If there is a packet in transmission, we cannot put anything on the
        #   link.
        if self.in_transmission:
            return
            
        # If there are no packets in either buffer, then we have no business
        #   here.
        if len(self.buffers[0]) == 0 and len(self.buffers[1]) == 0:
            return

        # Get which buffer to pop a packet from next (0 or 1)
        data_src, next_pop = self.get_next_buffer_pop()

        # Now that we know the source of the next packet, we know if it goes on
        #   right away.  If the next packet will go in the same direction of 
        #   travel as the other packets, put it on the link.  Otherwise, we 
        #   must wait until the link is clear to send it the opposite 
        #   direction.
        if (next_pop == data_src and not self.in_transmission) or \
            data_src == -1:
            # We are sending a packet, so set the in_transmission flag.
            self.in_transmission = True
            
            # The next packet will go in the same direction as data on the 
            #   link. Pop the packet from the link buffer
            [time, flow_name, packet_ID] = heapq.heappop(
                                                    self.buffers[next_pop])
            
            # Put it on the link and use the current time so we can heapify
            #   more easily.  Subtract from the buffer load to reflect that the
            #   packet is no longer on the buffer
            heapq.heappush(self.packets_on_link[next_pop],
                           (sim.network_now(), flow_name, packet_ID))
            packet_size = sim.packets[(flow_name, packet_ID)].size # in bytes
            self.buffer_load[next_pop] -= cv.bytes_to_KB(packet_size)

            self.data_on_link += cv.bytes_to_Mb(packet_size)
            
            # Calculate the transmission time as the size of the packet 
            #   divided by the link capacity (aka rate).
            packet_size = sim.packets[(flow_name, packet_ID)].size
            transmission_time =  (cv.bytes_to_Mb(packet_size) / self.rate) 
            transmission_time /= 1000 # To get it in ms 
            
            # Create an event after this packet's transmission to reset the
            #   in_transmission flag.  Subtract a small amount of time to 
            #   assure it happens before the next call of this function.
            reset_time = sim.network_now() + transmission_time - ct.TIME_BIT
            reset_event = e.Event(self.link_name, 'reset_in_transmission', [])
            sim.enqueue_event(reset_time, reset_event)
            
            # Create an event to check if we should send another packet after
            #   transmission.
            pkt1_time = sim.network_now() + transmission_time
            pkt1_event = e.Event(self.link_name, 'put_packet_on_link', [])
            sim.enqueue_event(pkt1_time, pkt1_event)
            
            # Enqueue the event for the opposite end to receive the packet.
            #   This occurs at the same time as the transmission plus delay
            #   event.
            rcv_time = pkt1_time + self.delay
            rcv_event = e.Event(self.link_name, 'handoff_packet', [next_pop])
            sim.enqueue_event(rcv_time, rcv_event)
            
            # If we are not sending another packet after transmission, we need
            #   to also have an event that checks after propagation.  Because 
            #   we do not know yet, we must make the event no matter what.
            pkt2_time = rcv_time
            pkt2_event = e.Event(self.link_name, 'put_packet_on_link', [])
            sim.enqueue_event(pkt2_time, pkt2_event)
Example #2
0
    def put_packet_on_buffer(self, sender_name, packet):
        '''
        Description:        This takes a packet and if there is space on the 
                            buffer, moves it onto the buffer.  If there is 
                            nothing on the Link or either buffer, it also puts 
                            it on the Link.
        
        Arguments:          sender_name (string) 
                                - The name of the endpoint that sent the 
                                Packet.

                            packet (Packet) 
                                - The Packet being sent.
        
        Return Values:      None.
        
        Shared Variables:   self.buffers (WRITE) 
                                - This function enqueues a packet onto one of 
                                the buffers (potentially).
                            
                            self.end_points (READ) 
                                - This is read to determine which buffer should 
                                be altered, if any.

                            self.buffer_load (WRITE) 
                                - This changes the buffer load when adding to 
                                the buffer.
                            
                            self.buffer_size (READ) 
                                - This is used to determine if there is enough 
                                space on the buffer to enqueue a Packet.
        
        Global Variables: None.
        
        Limitations:      None.
        
        Known Bugs:       None.
        
        Revision History: 2015/10/22: Created function handle and docstring
                          2015/10/29: Filled function in.
                          2015/11/03: Changed the link buffers to use the 
                                      python queue data structure and only 
                                      store the flow_name and packet_name
        '''
        # Get the index of the endpoint sender_name represents and then the
        #   index of the opposite endpoint.
        ep, other_ep = u.assign_endpoints(self.end_points, sender_name)
        
        # Add the buffer recording
        st.add_buffer_recording(sim.network_now(), self.link_name)

        # Put the packet onto the buffer heapqueue corresponding to the sender.
        #   The time we use for this will be now, because we are using first
        #   come first served priority on the links, but only if there is 
        #   enough space.
        if packet.size + cv.KB_to_bytes(self.buffer_load[ep]) <= \
           cv.KB_to_bytes(self.buffer_size):
            # Add the packet identifier to the link buffer heap queue along 
            # 	with the time
            heapq.heappush(self.buffers[ep], 
                (sim.network_now(), packet.flow, packet.ID))

            # Update the buffer load for this link buffer because it is now
            # storing an additional packet.size
            self.buffer_load[ep] += cv.bytes_to_KB(packet.size)
            
            # Add to the totals so Bellman Ford can run.
            self.total_packets[ep] += 1
            self.total_buffer_load[ep] += packet.size
        
        else: 
            self.num_packets_lost += 1

        # We now want to kickstart the putting packets on the link.  If there
        #   is already a packet in transmission, then nothing will happen.
        #   Otherwise, we are telling it the buffer is now nonempty.  However,
        #   create an event some dt in the future so all the "current" events
        #   can finish first.
        link_time = sim.network_now() + ct.TIME_BIT
        link_ev = e.Event(self.link_name, 'put_packet_on_link', [])
        sim.enqueue_event(link_time, link_ev)