Пример #1
0
    def RECV(self, fsm):
        """RECV state; monitor traffic from lower layer.

        This state receives packets on `Port` 'RXD'. It then uses `ptype` to
        determine which packet handler should process the new data packet, and
        spawns a new thread to run the handler.
        
        :note: Currently, IPv4 is the only protocol type supported. Non-IPv4
               packets are passed to `ERRRECV` for handling.
        """
        # error messages
        rxderror = "[ROUTING]: Error occurred while receiving " + \
                   "traffic from RXD port!"
        pkterror = "[ROUTING]: Invalid packet from lower layer!"
        # get packet from lower layer
        yield self.RXD.recv(fsm, 1)
        assert fsm.acquired(self.RXD) and (len(fsm.got)==1), rxderror
        p = fsm.got[0]
        if isinstance(p, Reference): p = p._deref
        assert ANNO.supported(p), pkterror
        # use appropriate recv function based on ptype
        if (self.ptype == const.ARP_PTYPE_IP):
            f = FSM.launch(self.IPRECV, p)      # IP ptype
        else:
            f = FSM.launch(self.ERRRECV, p)     # unknown ptype
        # continue in RECV
        yield fsm.goto(self.RECV)
Пример #2
0
    def maintain(self, p, nexthop):
        """Start or udpate route maintenace on IP+DSR packet.

        :note: This assumes a IP+DSR packet was passed to it.
        """
        # error messages
        errornexthop = "[DSR]: maintain() found invalid nexthop!"
        dropbuffer = "maintenance buffer overflow"
        dropttl = "TTL expired"
        # get IP/DSR/Option parameters
        ip, dsr = p[IP], p[DSRPacket]
        addr, src, dst, ttl = self.address, ip.src, ip.dst, ip.ttl
        # TTL expired?
        if (ttl<1):
            self.log_drop(p, drop=dropttl)
            return
        # start or continue route maintenance
        if nexthop in self.maintbuffer:
            # add packet to end of maintenance buffer
            buff = self.maintbuffer[nexthop]['buffer']
            if (len(buff)<self.RexmtBufferSize):
                buff.append(ip)
                self.debug("MAINTBUFF", ip)
            else:
                self.log_drop(ip, drop=dropbuffer)
        else:
            # add new buffer and launch thread to maintain it
            self.maintbuffer[nexthop] = {'buffer':[ip]}
            f = FSM.launch(self.MAINT, nexthop)
Пример #3
0
    def RXRREP(self, fsm, ip, dsr, opt):
        """RXRREP state; handle route reply message.

        :note: Assumes `checkiprecv()` passed.
        """
        self.debug("RXRREP", ip)
        # get IP/DSR/Option parameters
        src, dst = ip.src, ip.dst
        addr, target = self.address, opt.addresses[-1]
        rreponly = (dsr.nextheader==const.IP_PROTO_NONE)
        # only keep RREP options and update route cache
        assert (dst==addr)
        dsr.options = [o for o in dsr.options if (getdsr_rrep(o))]
        self.cacheroute(ip)
        #assert (self.hasroute(target))
        assert self.safe((self.hasroute(target)))   # verify route to target
        # get entry from Route Request Table and forward packets
        rre = self.rrt.getentry(target)
        while rre.sendbuffer:
            p = rre.sendbuffer.pop(0)
            f = FSM.launch(self.IPRECOVER, p, addr, target)
        self.rrt.delentry(target)
        # more than RREP?
        if not rreponly:
            # remove DSR options and reclassify
            dsr.options = []
            yield fsm.goto(self.IRECV, ip)
Пример #4
0
    def SEND(self, fsm):
        """SEND state; monitor traffic from upstream protocol and pass to
        routing algorithm.

        This state uses the 'net-src' and 'net-dst' annotations to determine the
        addresses of the source and destination. If not available, these values
        default to the local `address` and `broadcast` address.

        This state then uses `ptype` to determine which packet handler should
        process the new data packet, and spawns a new thread to run the handler.
        
        :note: Currently, IPv4 is the only protocol type supported. Non-IPv4
               packets are passed to `ERRSEND` for handling. Also, this state
               will check for loopback addresses and send them back to the upper
               layer protocol.
        """
        # error messages
        rxuerror = "[ROUTING]: Error occurred receiving from RXU port!"
        pkterror = "[ROUTING]: Invalid packet from upper layer!"
        # get packet to send from upperlayer
        yield self.RXU.recv(fsm, 1)
        assert fsm.acquired(self.RXU) and (len(fsm.got)==1), rxuerror
        p = fsm.got[0]
        if isinstance(p, Reference): p = p._deref
        assert ANNO.supported(p), pkterror
        # process new data packet
        addr = self.address
        src, dst = addr, self.broadcast
        if p.hasanno('net-src'): src = p.getanno('net-src')
        if p.hasanno('net-dst'): dst = p.getanno('net-dst')
        r = self.set_sendanno(p, src, dst)
        # send loopback back to upper layer
        if (dst==addr):
            self.log_loopback(p, src=src, dst=dst)
            yield self.TXU.send(fsm, [p])
            yield fsm.goto(self.SEND)           # continue in SEND
        # otherwise -> use appropriate send function based on ptype
        if (self.ptype == const.ARP_PTYPE_IP):
            f = FSM.launch(self.IPSEND, r, src, dst)        # IP ptype
        else:
            f = FSM.launch(self.ERRSEND, r, src, dst)       # unknown ptype
        # continue in SEND
        yield fsm.goto(self.SEND)
Пример #5
0
    def RXRREQ(self, fsm, ip, dsr, opt):
        """RXRREQ state; process route request option.

        :note: Assumes `checkiprecv()` passed.
        """
        self.debug("RXRREQ", ip)
        # error messages
        droprreq = "in source route or not new RREQ"
        # get IP/DSR/Option parameters
        addr, src, dst = self.address, ip.src, ip.dst
        ID, target = opt.identification, opt.target
        rreqonly = (dsr.nextheader==const.IP_PROTO_NONE)
        # check if target reached
        if (addr==target):
            # send RREP [and process remaining packet]
            path = [a for a in opt.addresses] + [target]
            f = FSM.launch(self.TXRREP, addr, src, opt, path)
            # strip RREQ and set dst=target
            dsr.options = [o for o in dsr.options if (not getdsr_rreq(o))]
            ip.dst = target
            # check for other options
            rerr, rrep = getdsr_rerr(dsr), getdsr_rrep(dsr)
            if rerr:
                yield fsm.goto(self.RXRERR, ip, dsr, rerr)
            elif rrep:
                yield fsm.goto(self.RXRREP, ip, dsr, rrep)
            # RREQ only -> HALT and discard packet
            if rreqonly: yield fsm.stop()
            # otherwise -> remove DSR options and reclassify
            dsr.options = []
            yield fsm.goto(self.IRECV, ip)
        # otherwise -> attempt to forward RREQ
        assert (addr!=target)
        inroute = (src==addr) or (addr in opt.addresses)
        newrreq = self.rrt.addcache(src, ID, target)
        # check if RREQ should be dropped
        if (inroute or (not newrreq)):
            self.log_drop(ip, drop=droprreq)
            yield fsm.stop()    # HALT and discard packet
        # update options and forward RREQ
        ip.ttl = ip.ttl - 1
        opt.addresses = [a for a in opt.addresses] + [addr]
        yield fsm.goto(self.IPFORWARD, ip)
Пример #6
0
    def MAINT(self, fsm, nexthop, rexmt=0, send=True):
        """MAINT state; perform route maintenace for nexthop.

        :note: Assume maintenance buffer contains valid IP+DSR packets.
        """
        yield hold, fsm, 0  # yield to other threads
        #assert (nexthop in self.maintbuffer)
        assert self.safe((nexthop in self.maintbuffer))
        # error messages
        droproute = "broken route"
        # get maintenance parameters
        buff = self.maintbuffer[nexthop]['buffer']
        if (len(buff)<1):
            del self.maintbuffer[nexthop]
            yield fsm.stop()        # HALT and stop maintenance
        # get head of buffer
        p = buff[0]
        ip, dsr = p[IP], p[DSRPacket]
        addr, src, dst = self.address, ip.src, ip.dst
        # check if path is still valid
        opt, path = getdsr_srcroute(ip), None   # one hop away?
        if opt:
            segsleft = opt.segsleft             # more than one hop?
            path = [a for a in opt.addresses[-segsleft:]]
        pathok = self.hasroute(dst, path)
        # if path is broken -> drop or resend
        if not pathok:
            p = buff.pop(0)
            if (addr==src):
                f = FSM.launch(self.IPRECOVER, p, src, dst)
            else:
                self.log_drop(p, drop=droproute)
            yield fsm.goto(self.MAINT, nexthop)     # continue with next packet
        # otherwise -> send head of buffer?
        if send:
            f = FSM.launch(self.IPDELIVER, ip, nexthop)
        # wait for link-level feedback (ACK/DROP)
        mac, feedback = self.mac, None
        yield waitevent, fsm, (mac.ackdata, mac.drpdata)
        if (mac.ackdata in fsm.eventsFired):
            p = mac.ackdata.signalparam
            if self.issame(ip, p): feedback = "ackdata"
        elif (mac.drpdata in fsm.eventsFired):
            p = mac.drpdata.signalparam
            if self.issame(ip, p): feedback = "drpdata"
        # process feedback
        if (feedback=="ackdata"):
            p = buff.pop(0)
            yield fsm.goto(self.MAINT, nexthop)     # continue with next packet
        elif (feedback=="drpdata"):
            rexmt += 1
            norexmt = (rexmt>self.MaxMaintRexmt)
            # rexmt not exceeded -> try again
            if not norexmt:
                self.debug("REXMT%d"%(rexmt), ip)
                yield fsm.goto(self.MAINT, nexthop, rexmt)
            # otherwise -> broken link!!
            etype = DSR_ERROR_NODE_UNREACHABLE
            esrc, unreachable = self.address, nexthop
            self.debug("DROPDATA", src=esrc, unreachable=unreachable)
            self.removelink(esrc, unreachable)
            # signal broken link
            self.sndfail.signal(esrc)
            # clear out maintenance buffer
            errdst = []
            while buff:
                p = buff.pop(0)
                ip, dsr = p[IP], p[DSRPacket]
                src, dst = ip.src, ip.dst
                # send RERR (for non-RREP messages)
                rrep = getdsr_rrep(ip)
                sendrerr = (not rrep) and (src not in errdst)
                # recover packet or send RERR
                if (addr==src):
                    f = FSM.launch(self.IPRECOVER, p, src, dst)
                elif sendrerr:
                    errdst.append(src)
            # send RERR to sources
            for edst in errdst:
                f = FSM.launch(self.TXRERR, esrc, edst, etype, unreachable)
            # continue to allow graceful shutdown
            yield fsm.goto(self.MAINT, nexthop)
        else:
            # feedback not for me -> continue waiting
            yield fsm.goto(self.MAINT, nexthop, rexmt, send=False)
Пример #7
0
    def TXRREQ(self, fsm, target, options=[], rexmt=0):
        """TXRREQ state; create and send route request.

        :param target: Target for route discovery.
        :param options: Additional DSR options [default=None].

        :note: This state is persistent. It will keep trying to send until
        """
        # error messages
        rreqerror = "[DSR]: Error getting RREQ Table entry!"
        droprexmt = "max rexmt exceeded"
        drophasrt = "route already exists"
        # pause for jitter
        jitter = random.uniform(0,1)*self.BroadcastJitter
        yield hold, fsm, jitter
        # check route and rexmt count
        if self.hasroute(target):
            self.log("RREQSTOP", target=target, rexmt=rexmt, drop=drophasrt)
            rre = self.rrt.getentry(target)
            while rre.sendbuffer:
                p = rre.sendbuffer.pop(0)
                f = FSM.launch(self.IPRECOVER, p, self.address, target)
            self.rrt.delentry(target)
            # signal that RREQ has finished
            self.finrreq.signal(target)
            yield fsm.stop()    # HALT and stop sending RREQ
        if (rexmt>self.rrt.MaxRequestRexmt):
            self.log("RREQDROP", target=target, rexmt=rexmt, drop=droprexmt)
            rre = self.rrt.getentry(target)
            while rre.sendbuffer:
                p = rre.sendbuffer.pop(0)
                self.log_drop(p, drop=droprexmt)
            self.rrt.delentry(target)
            # signal that RREQ has been abandoned
            self.drprreq.signal(target)
            yield fsm.stop()    # HALT and stop sending RREQ
        # get RREQ parameters
        sendrreq = self.rrt.sendrreq(target)
        rre = self.rrt.getentry(target)
        tleft = rre.timeleft()
        # get parameters for logging
        kwargs = {'rexmt':rexmt, 'nbuffered': len(rre.sendbuffer)}
        kwargs['options']  = [o.tracename for o in options]
        kwargs['jitter'] = time2msec(jitter)
        kwargs['timeleft'] = time2msec(tleft)
        # cannot send RREQ? -> RREQ is busy, drop attempt
        if not sendrreq:
            self.debug("RREQBUSY", target=target, **kwargs)
            yield fsm.stop()    # HALT and allow other RREQ to finish
        # otherwise -> send RREQ
        ID, ttl = rre.ID, rre.ttl
        # create DSR+RREQ+options
        nextheader = self.getproto(None)
        dsr = DSRPacket(nextheader=nextheader)
        rreq = DSROPT_RREQ(identification=ID, target=target)
        dsr.options = [rreq] + [o for o in options]
        # create IP+DSR
        proto = self.getproto(dsr)
        src, dst = self.address, self.broadcast
        ip = IP(src=src, dst=dst, proto=proto, ttl=ttl)
        ip.add_payload(dsr)
        # send RREQ -> wait for timeout, then rexmt
        self.debug("TXRREQ", ip, target=target, **kwargs)
        f = FSM.launch(self.IPDELIVER, ip, dst)
        # signal that RREQ has been sent to target
        self.sndrreq.signal(target)
        # wait for send RREQ to timeout before trying again
        yield hold, fsm, tleft
        yield fsm.goto(self.TXRREQ, target, options, rexmt+1)