Пример #1
0
    def _trySendingFrame(self):
        """Only send if no carrier is sensed and we are not in backoff."""
        if self._transmitting or self._outstandingFrame:
            # Another frame is currently being transmitted. Wait for next call.
            return
        if not self._transmitQueue:
            # Nothing to transmit.
            return
        if self._backingOff:
            # Still waiting backoff
            return

        if self._device.phy.carrierSense():
            # Channel is occupied. Do backoff. *** COLLISION AVOIDANCE ***
            self._backingOff = True
            SCHEDULE(self._computeBackoff(), self._endBackoff)
            ACTIVITY_INDICATION(self, "tx", "CA backoff", "darkblue", 1, 2)
            return

        type, dstAddr, bitstream = self._transmitQueue.pop(0)
        if type == self.ACK:
            # Create a new Ack frame and send it.
            ACTIVITY_INDICATION(self, "tx", "ACK/NAK", "grey", 0, 0)
            self._phySendFrame(dstAddr=dstAddr, data="")
        else:
            if type == self.RETR:
                self.packetRetransmissions += 1
                ACTIVITY_INDICATION(self, "tx", "Resend", "orange", 0, 0)
            else:
                ACTIVITY_INDICATION(self, "tx", "Send", "yellow", 0, 0)
                self._resetBackoff()
                self.packetsSent += 1
            self._retransmissionTimer = SCHEDULE(self.retransmissionTimeout,
                                                 self._timeout)
            self._outstandingFrame = self._phySendFrame(dstAddr, bitstream)
Пример #2
0
    def _backoff(self):
        """Compute backoff and schedule retransmission.

        This method is called after the end of the jam transmission. In half
        duplex mode, it does the following:
        - compute a backoff
        - enter backoff mode
        - schedule the retransmission of the frame.
        If the maximum number of collisions is already reached, abandon the
        frame and signal an error to the upper layer.
        """

        ACTIVITY_INDICATION(self, "tx", "backoff", "blue", 1, 2)
        self._jamming = False
        if self._transmissionAttemps >= 16:
            # Transmission failed. Update statistics, inform dl and clean up
            SCHEDULE(0.0, self._niu.dl.sendStatus,
                     (_EXCESSIVE_COLLISION_ERROR, self._sendBuffer))
            self.excessiveCollisions += 1
            print "Excessive collisions"
            self._transmissionAttemps = 0
            self._sendBuffer = None
            self._niu.XOFF = False
            return

        k = min(10, self._transmissionAttemps)
        r = int(random() * (1 << k))
        if self._niu.phy.getDataRate() == 1000e6:
            backoff = r * self._GIGA_SLOTTIME * self._niu.phy.bittime()
        else:
            backoff = r * self._SLOTTIME * self._niu.phy.bittime()
        SCHEDULE(backoff, self._mediumAccess)
Пример #3
0
    def send(self, bitstream):
        """Simulate the transmission of the data on the medium.

        Schedule the call to inform the DL entity when finished.
        
        Arguments:
          bitstream:Bitstream -- Block of data to transmit onto the medium.
        Return value: None.
        """
        self._niu.medium.startTransmission(self._niu)
        transmissionDelay = len(bitstream) * 8 / self._dataRate
        SCHEDULE(transmissionDelay, self._niu.medium.completeTransmission,
                 (self._niu, bitstream))
        SCHEDULE(transmissionDelay, self._niu.dl.sendStatus, (0, bitstream))
Пример #4
0
    def send(self, bitstream):
        """Encapsulate the data into a frame and send it to the phy layer.

        May only be called if self._device.XOFF is False, i.e. if the
        device is ready to accept a new data packet from the higher layer.
        """

        # Make sure there is no other packet already in transit.
        assert (self._device.XOFF == False and not self._sendBuffer)

        # Block any new transmission until this packet has been acknowledged
        self._device.XOFF = True

        # Create a new frame with CRC and sequence numbers.
        frame = self._newFrame()
        frame.SN = self._VS
        self._VS = (self._VS + 1) % 2
        frame.RN = self._VR
        frame.data = bitstream
        checksum = crc32(frame.serialize()[:-4]) & ((1L << 32) - 1)
        frame.FCS = checksum

        # Set the retransmission timer
        self._sendBuffer = frame
        self._retransmissionTimer = SCHEDULE(self.retransmissionTimeout,
                                             self._timeout)

        # Sent the frame
        ACTIVITY_INDICATION(self, "tx", "Send", "yellow", 0, 0)
        self.packetsSent += 1
        self._device.phy.send(frame.serialize())
        return 0
Пример #5
0
    def _trySendingFrame(self):
        """Send the next frame waiting in the transmitQ, if there is any."""
        if self._transmitting or self._outstandingFrame:
            # Another frame is currently being transmitted. Wait for next call.
            return
        if not self._transmitQueue:
            # Nothing to transmit.
            return

        type, dstAddr, bitstream = self._transmitQueue.pop(0)
        if type == self.ACK:
            # Create a new Ack frame and send it.
            ACTIVITY_INDICATION(self, "tx", "ACK/NAK", "grey", 0, 0)
            self._phySendFrame(dstAddr=dstAddr, data="")
        else:
            if type == self.RETR:
                self.packetRetransmissions += 1
                ACTIVITY_INDICATION(self, "tx", "Resend", "orange", 0, 0)
            else:
                ACTIVITY_INDICATION(self, "tx", "Send", "yellow", 0, 0)
                self._resetBackoff()
                self.packetsSent += 1
            self._retransmissionTimer = SCHEDULE(self.retransmissionTimeout,
                                                 self._timeout)
            self._outstandingFrame = self._phySendFrame(dstAddr, bitstream)
Пример #6
0
 def _timeout(self):
     """Called when a retransmission timeout occurs."""
     ACTIVITY_INDICATION(self, "tx", "TIMEOUT")
     self._retransmissionTimer = None
     self._consecutiveCollisions += 1
     self._backingOff = True
     ACTIVITY_INDICATION(self, "tx", "Retr backoff", "blue", 1, 2)
     SCHEDULE(self._computeBackoff(), self._endBackoff)
Пример #7
0
    def _trySendingFrame(self):
        """Send the next frame waiting in the sendBuffer, if there is any."""
        if self._transmitting:
            # Another frame is currently being transmitted. Wait for next call.
            return
        if not self._transmitQueue:
            # Nothing to transmit.
            return

        type, sn = self._transmitQueue.pop(0)
        if type == self.ACK or type == self.SREJ:
            # Create a new Ack frame and send it.
            ack = self._newFrame()
            ack.SN = self._SNmax  # Allowed since payload is empty
            ack.RN = sn
            if type == self.SREJ:
                ack.SREJ = 1
                ACTIVITY_INDICATION(self, "tx",
                                    "Send SREJ RN=%s" % str(ack.RN), "red", 0,
                                    0)
            else:
                ACTIVITY_INDICATION(self, "tx", "Send ACK RN=%s" % str(ack.RN),
                                    "grey", 0, 0)
            checksum = crc32(ack.serialize()[:-4]) & ((1L << 32) - 1)
            ack.FCS = checksum
            self._transmitting = True
            self._device.phy.send(ack.serialize())

        else:
            assert (type == self.FIRSTTR or type == self.RETR)
            # Create a new data packet and send it
            bitstream = self._sendBuffer[sn]
            frame = self._newFrame()
            frame.SN = sn
            frame.RN = self._VR
            frame.data = bitstream
            checksum = crc32(frame.serialize()[:-4]) & ((1L << 32) - 1)
            frame.FCS = checksum

            # Set the retransmission timer
            if sn in self._retransmissionTimer:
                timer = self._retransmissionTimer.pop(sn)
                CANCEL(timer)
            self._retransmissionTimer[sn] = SCHEDULE(
                self.retransmissionTimeout, self._timeout, (sn, ))

            # Send the frame and update the statistics
            if type == self.RETR:
                self.packetRetransmissions += 1
                ACTIVITY_INDICATION(self, "tx", "Retr SN=%s" % str(frame.SN),
                                    "orange", 0, 0)

            else:
                ACTIVITY_INDICATION(self, "tx", "Send SN=%s" % str(frame.SN),
                                    "yellow", 0, 0)
            self.packetsSent += 1
            self._transmitting = True
            self._device.phy.send(frame.serialize())
Пример #8
0
    def send(self, bitstream):
        """Accept a block of data and simulate transmission on the medium.

        Called by the MAC layer to transmit a block of data. Can be called
        multiple times while Phy.transmitting is active (). In this case, if the
        previous block has not yet been completely transmitted onto the medium,
        the remaining data is discarded and the transmission continues with the
        new data. Therefore, the MAC should call this method only after having
        received a MAC.sendStatus notification or if a collision
        has been detected and the MAC wants to stop the transmission of data
        and continue with a jam signal.

        Arguments:
          bitstream:Bitstream -- Block of data to transmit onto the medium.
        Return value: None.
        """
        if self._transmitting == False:
            raise RuntimeError("Attempt to transmit without previously "
                               "activating transmission on NIU: " +
                               self._niu._node.hostname + "." +
                               self._niu.devicename + ".phy")
        if self._transmittedData == None:
            # New transmission
            self._transmittedData = bitstream
            self._transmitStartTime = TIME()
            self._niu.medium.startTransmission(self._niu)

            transmissionDelay = len(bitstream) * 8 / self._dataRate
            self._completeTxEventId = SCHEDULE(transmissionDelay,
                                               self._completeTransmission)

            if self._receiveActivities > 0:
                self._niu.mac.collisionDetect()
        else:
            # Interrupt current transmission and send new data
            bytelen = int(
                ((TIME() - self._transmitStartTime) * self._dataRate + 0.05) /
                8)
            self._transmittedData = self._transmittedData[0:bytelen] + bitstream
            CANCEL(self._completeTxEventId)
            transmissionDelay = len(bitstream) * 8 / self._dataRate
            self._completeTxEventId = SCHEDULE(transmissionDelay,
                                               self._completeTransmission)
Пример #9
0
    def _retransmit(self):
        """Retransmits the current frame.

        Called either because of a negative ack or by a retransmission timeout.
        """
        ACTIVITY_INDICATION(self, "tx", "Retransmit", "orange", 0, 0)
        if self._retransmissionTimer:
            CANCEL(self._retransmissionTimer)
        self._retransmissionTimer = SCHEDULE(self.retransmissionTimeout,
                                             self._timeout)
        self.packetRetransmissions += 1
        self.packetsSent += 1
        self._device.phy.send(self._sendBuffer.serialize())
Пример #10
0
    def _checkAck(self, frame):
        """Look if the frame contains an ACK and handle it."""
        if self._outstandingFrame != None:  # We are waiting for an ACK
            if frame.RN == (self._VS[frame.SrcAddr] + 1) % 2:
                # POSITIVE ACKNOWLEDGEMENT
                ACTIVITY_INDICATION(self, "rx", "ACK ok")
                self._outstandingFrame = None
                if self._retransmissionTimer:
                    CANCEL(self._retransmissionTimer)
                self._retransmissionTimer = None
                self._VS[frame.SrcAddr] = frame.RN

                # Do a backoff. *** COLLISION AVOIDANCE ***
                self._backingOff = True
                SCHEDULE(self._computeBackoff(), self._endBackoff)
                ACTIVITY_INDICATION(self, "tx", "CA backoff", "darkblue", 1, 2)
Пример #11
0
    def _sendPacket(self):
        """Send PDUs to the lower layer until the whole page is transmitted.

        At the end, start a new OFF period by calling generate."""
        length = min(self._pageSize, self._pduSize)
        bitstream = self._uniqueBitstream(length)
        self.send(bitstream)
        self.octetsTransmitted += length
        self.pdusTransmitted += 1

        self._pageSize -= length
        if self._pageSize > 0:
            delay = (self._pduSize*8.0) / self._onRate
            SCHEDULE(delay, self._sendPacket)
        else:
            self.pagesTransmitted += 1
            self.generate()
Пример #12
0
    def completeTransmission(self, txNIU, data):
        """Finish a transmission and deliver the data to receiving NIUs.

        By calling this method, a phy layer entity of an attached NIU
        indicates that it has finished the transmission previously started
        by calling startTransmission. The data provided to the medium is
        delivered, after a propagation delay, to the phy entities of
        attached NIUs by calling phy.receive.

        Arguments:
          txNIU:NIU -- Transmitting NIU
          data:Bitstream -- Transmitted data
        Return value: None.
        """
        for rxNIU, rxPos in self._niuDict.items():
            if rxNIU != txNIU:
                propDelay = self._distances[(txNIU, rxNIU)] / self.signalSpeed
                SCHEDULE(propDelay, rxNIU.phy.receive, (data, ))
Пример #13
0
    def startTransmission(self, txNIU):
        """Start a transmission on the medium.

        A phy protocol entity calls this method to indicate that it
        starts the transmission of a signal. The other NIU is
        informed, after the propagation delay, that a new transmission
        has started by calling the method phy.newChannelActivity of
        its phy entity. No data is actually transmitted. This will be
        done by the function completeTransmission, which is called by
        the phy layer entity at the end of the transmission.

        Arguments:
          niu:NIU -- Transmitting NIU
        Return value: None.
        """
        txPos = self._niuDict[txNIU]
        for rxNIU, rxPos in self._niuDict.items():
            if rxNIU != txNIU:
                propDelay = abs(rxPos - txPos) / self.signalSpeed
                SCHEDULE(propDelay, rxNIU.phy.newChannelActivity)
Пример #14
0
    def sendStatus(self, status, bitstream):
        """Terminate the transmission, inform dl, and clean up.

        This method is called from the phy layer, when a transmission
        previously initiated with PHY.send terminates.
        First check if we are sending a jam. In this case, the jam
        transmission has completed. Switch of the transmission and call the
        backoff method.
        If not jamming, terminate the transmission, update the statistics,
        clean up and inform the upper layer.

        A status==0 indicates success. Any other status indicates an error.
        """
        self._latestTransmitActivity = TIME()

        if self._jamming:
            ACTIVITY_INDICATION(self, "tx")
            self._niu.phy.transmitting(False)
            self._backoff()
            return

        ACTIVITY_INDICATION(self, "tx")
        self._niu.phy.transmitting(False)  # Terminate the transmission
        if not status:
            self.framesTransmittedOK += 1
            self.octetsTransmittedOK += len(self._sendBuffer.data)
            if self._transmissionAttemps > 2:
                self.multipleCollisionFrames += 1
            if self._transmissionAttemps == 2:
                self.singleCollisionFrames += 1
        else:
            # Discard the frame and inform DL (LLC)
            self.octetsTransmittedError += len(self._sendBuffer.data)
            status = _UNKNOWN_TRANSMISSION_ERROR

        SCHEDULE(0.0, self._niu.dl.sendStatus, (status, self._sendBuffer))
        self._transmissionAttemps = 0
        self._sendBuffer = None
        self._niu.XOFF = False
Пример #15
0
 def generate(self):
     length = max(9,int(self._pduSizeRNG()))
     self.send(self._uniqueBitstream(length))
     self.octetsTransmitted += length
     self.pdusTransmitted += 1
     SCHEDULE(self._interarrivalRNG(), self.generate)
Пример #16
0
 def _timeout(self):
     """Called when a retransmission timeout occurs."""
     ACTIVITY_INDICATION(self, "tx", "TIMEOUT")
     self._retransmissionTimer = None
     self._consecutiveCollisions += 1
     SCHEDULE(self._computeBackoff(), self._retransmit)
Пример #17
0
 def start(self):
     SCHEDULE(self.interval, self.generate)
Пример #18
0
 def generate(self):
     """Schedule a new page transmission after a random OFF time."""
     offTime = self._offTimeRNG()
     offTime = min(offTime, self._offTimeMax)
     offTime = max(offTime, self._offTimeMin)
     SCHEDULE(offTime, self._sendPage)
Пример #19
0
    def _mediumAccess(self):
        """Acquire the transmit medium, transmit the frame and inform dl.

        This function tries to transmit a current frame according to the
        CSMA/CD algorithm, as described in the standard, Section 4.2.3.2.
        The following elements of the standard are implemented:
          - Half duplex transmission: CSMA/CD
          - Full duplex transmission
          - Carrier sense (in half duplex)
          - Interframe spacing (in half and full duplex)
          - Collision detection and enforcement through jam (in half duplex)
          - Exponential backoff and retransmission (half duplex)
          - Carrier extension (in half duplex for data rate > 100 Mb/s
        The following elements are not implemented:
          - Frame bursting (used for data rates > 100 Mb/s).
        """

        assert (self._sendBuffer != None)

        if self._niu.phy.getDuplexMode() == FULL_DUPLEX:

            # Transmission without contention. Only respect interframe gap
            gaptime = self._INTERFRAME_GAP * self._niu.phy.bittime()
            currentgap = TIME() - self._latestTransmitActivity
            if currentgap < gaptime:
                ACTIVITY_INDICATION(self, "tx", "gaptime", "grey", 3, 2)
                SCHEDULE(gaptime - currentgap, self._mediumAccess)
                return
            self._transmissionAttemps += 1
            ACTIVITY_INDICATION(self, "tx", "send FD", "green", 0, 0)
            self._niu.phy.transmitting(activate=True)
            self._niu.phy.send(self._sendBuffer.serialize())
            return

        else:  # Transmission in half duplex mode

            # 1. Carrier sense
            if self._niu.phy.carrierSense():
                ACTIVITY_INDICATION(self, "tx", "carrierSense", "blue", 3, 2)
                self._waitingForIdleChannel = True
                # Wait until channel activities end. The MAC.channelIdle
                # method will call us then
                return
            self._waitingForIdleChannel = False

            # 2. Interframe gap
            gaptime = self._INTERFRAME_GAP * self._niu.phy.bittime()
            currentgap = TIME() - max(self._latestTransmitActivity,
                                      self._latestReceiveActivity)
            if gaptime - currentgap > self._niu.phy.bittime() / 100:
                ACTIVITY_INDICATION(self, "tx", "gaptime", "grey", 3, 2)
                gapjitter = gaptime * random() / 100  # Avoid dicrete synchro.
                SCHEDULE(gaptime - currentgap + gapjitter, self._mediumAccess)
                return
            # 3. Here we go. Initiate the transmission. Wait for the
            #    transmissionCompleted or collisionDetect signal
            self._transmissionAttemps += 1
            ACTIVITY_INDICATION(self, "tx", "send HD", "green", 0, 0)
            self._niu.phy.transmitting(activate=True)
            self._niu.phy.send(self._sendBuffer.serialize())
            return
Пример #20
0
 def generate(self):
     self.send(self._uniqueBitstream(self._pduSize))
     self.octetsTransmitted += self._pduSize
     self.pdusTransmitted += 1
     SCHEDULE(self._interarrival, self.generate)
Пример #21
0
 def generate(self):
     data = 'y'*self.length # A string 'xxxxx' of the correct length
     packet = data + self.checksum(data)
     self.send(packet)
     SCHEDULE(self.interval, self.generate)