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)
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)