コード例 #1
0
def handleDAO(interfaces, message):
    route_updated = False

    if not Address(message.dst).is_RPL_all_nodes(
    ) and not gv.address_cache.is_assigned(message.dst):
        logger.debug("DAO message is for a different node, dropping it")
        return

    is_multicast = Address(message.dst).is_RPL_all_nodes()
    dao = DAO()
    payload = dao.parse(message.msg)

    if gv.dodag_cache.is_empty() or dao.instanceID != gv.global_instanceID:
        logger.debug(
            "Currently not participating in any DODAG for this instanceID, cannot process the DAO message"
        )
        return

    if is_multicast and dao.K:
        logger.debug(
            "Multicast DAO message can not request an acknowledgment (K=1)")
        return

    dodag = gv.dodag_cache.get_active_dodag()

    # when D flag is set in the DAO, check that the DODAGID matches the current DODAG
    if dao.D and dodag.dodagID != dao.DODAGID:
        logger.debug("DAO indicates a DODAG ID (%s) that does not match the active DODAG (%s), dropping it" % \
                     (repr(Address(dao.DODAGID)), repr(Address(dodag.dodagID))))
        return

    options = getAllOption(payload)

    targets = []
    last_opt_is_transit_info = False
    logger.debug("DAO message contains the following (%d) options:" %
                 len(options))
    for opt in options:
        logger.debug("- " + opt.__class__.__name__)

        if isinstance(opt, RPL_Option_RPL_Target):
            if last_opt_is_transit_info:
                targets = []
                last_opt_is_transit_info = False
            targets.append(
                Route(repr(Address(opt.target_prefix)) + "/" +
                      str(opt.prefix_len),
                      message.src,
                      message.iface,
                      onehop=is_multicast))

        if isinstance(opt, RPL_Option_Transit_Information):
            last_opt_is_transit_info = True

            if opt.E:
                logger.debug(
                    "E flag is not supported for the RPL Transit Information Option, dropping DAO message"
                )
                return

            if not opt.path_control == 0:
                logger.debug(
                    "Path control different than 0 is not supported, dropping DAO message"
                )
                return

            if opt.path_lifetime == 0:  # this is a No-Path DAO
                route_updated += gv.route_cache.remove_routes(targets)
                for target in targets:
                    try:
                        dodag.downward_route_del(target)
                    except KeyError:
                        pass
            elif opt.path_lifetime == 0xff:  # infinite lifetime
                for target in targets:
                    dodag.downward_route_add(target)

            else:
                logger.debug(
                    "Path lifetime that is not null or infinite is not supported"
                )
                return

            (removed_routes, new_routes) = dodag.get_filtered_downward_routes()
            logger.debug("routes to be removed (%d):\n" % len(removed_routes) +
                         repr(removed_routes))
            logger.debug("routes to be added (%d):\n" % len(new_routes) +
                         repr(new_routes))

            route_updated += gv.route_cache.remove_routes(removed_routes)
            route_updated += gv.route_cache.add_routes(new_routes)

    if dao.K:
        dodag.sendDAO_ACK(message.iface, message.src, dao.DAOsequence,
                          dao.DODAGID)

    if route_updated:
        dodag.last_PathSequence += 1
        if not dodag.is_dodagRoot:
            logger.debug(
                "Downward routes have been updated, scheduling a DAO message transmission"
            )
            dodag.setDAOtimer()
コード例 #2
0
ファイル: core.py プロジェクト: abdelwas/Ryu-RPL
def handleDAO(interfaces, message):
    route_updated = False

    if not Address(message.dst).is_RPL_all_nodes() and not gv.address_cache.is_assigned(message.dst):
        logger.debug("DAO message is for a different node, dropping it")
        return

    is_multicast = Address(message.dst).is_RPL_all_nodes()
    dao = DAO()
    payload = dao.parse(message.msg)

    if gv.dodag_cache.is_empty() or dao.instanceID != gv.global_instanceID:
        logger.debug("Currently not participating in any DODAG for this instanceID, cannot process the DAO message")
        return

    if is_multicast and dao.K:
        logger.debug("Multicast DAO message can not request an acknowledgment (K=1)")
        return

    dodag = gv.dodag_cache.get_active_dodag()

    # when D flag is set in the DAO, check that the DODAGID matches the current DODAG
    if dao.D and dodag.dodagID != dao.DODAGID:
        logger.debug("DAO indicates a DODAG ID (%s) that does not match the active DODAG (%s), dropping it" % \
                     (repr(Address(dao.DODAGID)), repr(Address(dodag.dodagID))))
        return

    options = getAllOption(payload)

    targets = []
    last_opt_is_transit_info = False
    logger.debug("DAO message contains the following (%d) options:" % len(options))
    for opt in options:
        logger.debug("- " + opt.__class__.__name__)

        if isinstance(opt, RPL_Option_RPL_Target):
            if last_opt_is_transit_info:
                targets = []
                last_opt_is_transit_info = False
            targets.append(Route(repr(Address(opt.target_prefix)) + "/" + str(opt.prefix_len),
                                  message.src,
                                  message.iface,
                                  onehop=is_multicast))

        if isinstance(opt, RPL_Option_Transit_Information):
            last_opt_is_transit_info = True

            if opt.E:
                logger.debug("E flag is not supported for the RPL Transit Information Option, dropping DAO message")
                return

            if not opt.path_control == 0:
                logger.debug("Path control different than 0 is not supported, dropping DAO message")
                return

            if opt.path_lifetime == 0:  # this is a No-Path DAO
                route_updated += gv.route_cache.remove_routes(targets)
                for target in targets:
                    try:
                        dodag.downward_route_del(target)
                    except KeyError: pass
            elif opt.path_lifetime == 0xff:  # infinite lifetime
                for target in targets: dodag.downward_route_add(target)

            else:
                logger.debug("Path lifetime that is not null or infinite is not supported")
                return

            (removed_routes, new_routes) = dodag.get_filtered_downward_routes()
            logger.debug("routes to be removed (%d):\n" % len(removed_routes) + repr(removed_routes))
            logger.debug("routes to be added (%d):\n" % len(new_routes) + repr(new_routes))

            route_updated += gv.route_cache.remove_routes(removed_routes)
            route_updated += gv.route_cache.add_routes(new_routes)

    if dao.K:
        dodag.sendDAO_ACK(message.iface, message.src, dao.DAOsequence, dao.DODAGID)

    if route_updated:
        dodag.last_PathSequence += 1
        if not dodag.is_dodagRoot:
            logger.debug("Downward routes have been updated, scheduling a DAO message transmission")
            dodag.setDAOtimer()
コード例 #3
0
def handleDIO(interfaces, message):
    """Handler for DIO messages"""
    dio = DIO()
    payload = dio.parse(message.msg)
    consistent = True

    # attach to the very first RPL Instance we see
    if gv.global_instanceID == 0:
        gv.global_instanceID = dio.instanceID

    if dio.instanceID != gv.global_instanceID:
        logger.debug(
            "ignoring DIO message address targeting a different RPL instance")
        return (None, None)

    try:
        dodag = gv.dodag_cache.get_dodag(dio.DODAGID, dio.version,
                                         dio.instanceID)[0]
    except IndexError:
        dodag = None

    if dodag and dodag.is_dodagRoot:
        logger.debug(
            "This node is the DODAG Root for this DODAG, dropping DIO")
        return  # we should not process this DIO message any further
    elif dodag:  # this is a DIO, from the same RPL Instance, DODAG ID, Version
        logger.debug("Updating information on an existing DODAG")

        dodag.last_dio = time()

        if dio.MOP != dodag.MOP:
            raise NotImplementedError(
                "Change MOP on an existing DODAG is not implemented")

        if dio.Prf != dodag.Prf:
            dodag.Prf = dio.Prf
            consistent = False

        # if the rank is INFINITE_RANK, remove the source node from the parent
        # list (and from the neighbor set)
        node = gv.neigh_cache.get_node(message.iface, message.src, dodag)
        if dio.rank == INFINITE_RANK and node:
            logger.debug(
                "Node %s advertises a DIO message with infinite rank" %
                repr(Address(message.src)))
            updated = gv.neigh_cache.remove_node_by_address(dodag, message.src)
            if updated: consistent = False
            node = None

        # check if the node is a DIO parent and request its sub-DODAG to send DAO messages
        if node and node.dtsn < dio.DTSN and node in gv.neigh_cache.get_parent_list(
        ):
            logger.info(
                "Parent %s has increased its DTSN field, scheduling a DAO message"
                % repr(Address(message.src)))
            dodag.downward_routes_reset()
            dodag.setDAOtimer()
            consistent = False

        dodag.DTSN.set_val(dio.DTSN)
    else:
        # we might have multiple older or newer versions of this DODAG still in
        # our cache
        old_dodags = gv.dodag_cache.get_dodag(dio.DODAGID,
                                              instanceID=dio.instanceID)

        try:
            if old_dodags[0].is_dodagRoot:
                logger.debug(
                    "This node is the DODAG Root for this DODAG, dropping DIO")
                return  # we should not process this DIO message any further

            least_recent = old_dodags[0].version
            most_recent = old_dodags[0].version
            least_recent_dodag = old_dodags[0]
            most_recent_dodag = old_dodags[0]
            for old_dodag in old_dodags:
                dodag_version = old_dodag.version
                if dodag_version < least_recent:
                    least_recent = dodag_version
                    least_recent_dodag = old_dodag
                if dodag_version > most_recent:
                    most_recent = dodag_version
                    most_recent_dodag = old_dodag

            if dio.version > most_recent:
                logger.debug("Receiving a DIO from a new version of the DODAG %s," \
                             " version %d < version %d" % (repr(Address(most_recent_dodag.dodagID)), most_recent_dodag.version.get_val(), dio.version ))
                # this should trigger global repair downward
                consistent = False

            if dio.version < least_recent:
                logger.debug("Receiving a DIO from an old version of the DODAG %s," \
                             " version %d < version %d" % (repr(Address(least_recent_dodag.dodagID)), dio.version, least_recent_dodag.version.get_val()))
                logger.debug("DIO dropped")
                return
        except IndexError:  # there was not older version of this DODAG
            pass

        # this is the first time we receive a DIO from this DODAG version
        # make sure that the DODAG is grounded, and that we support this
        # mode of operation.
        if dio.rank != INFINITE_RANK and dio.G == 1 and dio.MOP == 2:
            logger.info(
                "Receiving a DIO from a new DODAG, adding it to our cache")
            dodag = DODAG(instanceID=dio.instanceID,
                          version=dio.version,
                          G=dio.G,
                          MOP=dio.MOP,
                          Prf=dio.Prf,
                          DTSN=dio.DTSN,
                          dodagID=dio.DODAGID,
                          interfaces=interfaces)
            try:  # if this is a newer version of a DODAG, some information needs to be passed down
                dodag.last_DAOSequence = deepcopy(
                    most_recent_dodag.last_DAOSequence)
                dodag.last_PathSequence = deepcopy(
                    most_recent_dodag.last_PathSequence)
            except NameError:
                pass
            gv.dodag_cache.add(dodag)
            consistent = False
        else:
            logger.debug("DIO dropped")
            if dio.rank == INFINITE_RANK:
                logger.debug("Rank is INFINITE_RANK")
            if not dio.G:
                logger.debug("floating DODAG are not supported")
            if dio.MOP != 2:
                logger.debug("incompatible Mode of Operation (MOP)")
            return

    options = getAllOption(payload)

    logger.debug("DIO message contains the following options:")
    for opt in options:
        logger.debug("- " + opt.__class__.__name__)

        if isinstance(opt, RPL_Option_DODAG_Configuration):
            dodag.authenticated = opt.A
            dodag.PCS = opt.PCS
            dodag.DIOIntDoublings = opt.DIOIntDoubl
            dodag.DIOIntMin = opt.DIOIntMin
            dodag.DIORedundancyConst = opt.DIORedun
            dodag.MaxRankIncrease = opt.MaxRankIncrease
            dodag.MinHopRankIncrease = opt.MinHopRankIncrease
            dodag.OCP = opt.OCP
            dodag.DftLft = opt.DefLifetime
            dodag.LftUnit = opt.LifetimeUnit

        if isinstance(opt, RPL_Option_Prefix_Information):
            if opt.L:
                # TODO: prefix field contains an address that can be used for
                # on-link determination
                # (It means that one can send a packet directly to the parent,
                # meaning that the node can probably have a direct route)
                pass

            if opt.R:
                # TODO: process the R flags (only seems useful if the RPL target
                # option is required somehow)
                # - if L=O and R=1, the parent provides its own address in the
                # PIO, then the parent must advertise that address as a DAO
                # target
                pass

            if opt.A:
                if opt.prefix_len != 64:
                    logger.debug(
                        "PIO option: cannot derive an address from a prefix whose length is not 64 bits"
                    )
                    continue

                # take only the 64 first bits of the prefix
                prefix = opt.prefix[:8]

                # Compute an IID for each interface/physical address
                # and build an IPv6 address with this prefix for each interfaces
                addresses = []
                for iface in interfaces:
                    address = derive_address(iface, prefix)
                    if address:
                        addresses.append((address, iface))

                # assigns the new addresses
                for (address, iface) in addresses:
                    gv.address_cache.add(repr(address), iface, 64,
                                         opt.valid_lifetime,
                                         opt.preferred_lifetime)

                # make sure we record this prefix as one of the prefix we
                # advertise
                if prefix not in dodag.advertised_prefixes:
                    dodag.advertised_prefixes.append(prefix)

        if isinstance(opt, RPL_Option_DAG_Metric_Container):
            # TODO
            pass

    if dio.rank != INFINITE_RANK:
        gv.neigh_cache.register_node(message.iface, message.src, dodag,
                                     dio.rank, dio.DTSN)

    # update the DIO parent (the new parent could be from a different DODAG)
    updated = gv.neigh_cache.update_DIO_parent()
    if updated: consistent = False

    # if there is no DIO parent for this node, it must advertises an
    # INFINITE_RANK, so that it is not selected by its children
    parent = dodag.preferred_parent
    # there is no parent left for the node
    if not parent and dodag.rank != INFINITE_RANK:
        dodag.rank = INFINITE_RANK
        consistent = False

    # if we moved to a new DODAG version, now is a good time to clean up old
    # versions
    gv.dodag_cache.purge_old_versions()

    # happen when all neighboring nodes send a poison DIO message
    if gv.dodag_cache.is_empty():
        return

    if dodag.rank < dodag.lowest_rank_advertized:
        dodag.lowest_rank_advertized = dodag.rank

    # if not consistent, reset the trickle timer
    try:
        if not consistent:
            dodag.DIOtimer.hear_inconsistent()
            dodag.setDAOtimer()
        else:
            dodag.DIOtimer.hear_consistent()
    except AttributeError:
        pass

    return
コード例 #4
0
ファイル: core.py プロジェクト: abdelwas/Ryu-RPL
def handleDIO(interfaces, message):
    """Handler for DIO messages"""
    dio = DIO()
    payload = dio.parse(message.msg)
    consistent = True

    # attach to the very first RPL Instance we see
    if gv.global_instanceID == 0:
        gv.global_instanceID = dio.instanceID

    if dio.instanceID != gv.global_instanceID:
        logger.debug("ignoring DIO message address targeting a different RPL instance")
        return (None, None)

    try:
        dodag = gv.dodag_cache.get_dodag(dio.DODAGID, dio.version, dio.instanceID)[0]
    except IndexError:
        dodag = None

    if dodag and dodag.is_dodagRoot:
        logger.debug("This node is the DODAG Root for this DODAG, dropping DIO")
        return  # we should not process this DIO message any further
    elif dodag:  # this is a DIO, from the same RPL Instance, DODAG ID, Version
        logger.debug("Updating information on an existing DODAG")

        dodag.last_dio = time()

        if dio.MOP != dodag.MOP:
            raise NotImplementedError("Change MOP on an existing DODAG is not implemented")

        if dio.Prf != dodag.Prf:
            dodag.Prf = dio.Prf
            consistent = False

        # if the rank is INFINITE_RANK, remove the source node from the parent
        # list (and from the neighbor set)
        node = gv.neigh_cache.get_node(message.iface, message.src, dodag)
        if dio.rank == INFINITE_RANK and node:
            logger.debug("Node %s advertises a DIO message with infinite rank" % repr(Address(message.src)))
            updated = gv.neigh_cache.remove_node_by_address(dodag, message.src)
            if updated: consistent = False
            node = None

        # check if the node is a DIO parent and request its sub-DODAG to send DAO messages
        if node and node.dtsn < dio.DTSN and node in gv.neigh_cache.get_parent_list():
            logger.info("Parent %s has increased its DTSN field, scheduling a DAO message" % repr(Address(message.src)))
            dodag.downward_routes_reset()
            dodag.setDAOtimer()
            consistent = False

        dodag.DTSN.set_val(dio.DTSN)
    else:
        # we might have multiple older or newer versions of this DODAG still in
        # our cache
        old_dodags = gv.dodag_cache.get_dodag(dio.DODAGID, instanceID=dio.instanceID)

        try:
            if old_dodags[0].is_dodagRoot:
                logger.debug("This node is the DODAG Root for this DODAG, dropping DIO")
                return  # we should not process this DIO message any further

            least_recent = old_dodags[0].version
            most_recent = old_dodags[0].version
            least_recent_dodag = old_dodags[0]
            most_recent_dodag = old_dodags[0]
            for old_dodag in old_dodags:
                dodag_version = old_dodag.version
                if dodag_version < least_recent:
                    least_recent = dodag_version
                    least_recent_dodag = old_dodag
                if dodag_version > most_recent:
                    most_recent = dodag_version
                    most_recent_dodag = old_dodag

            if dio.version > most_recent:
                logger.debug("Receiving a DIO from a new version of the DODAG %s," \
                             " version %d < version %d" % (repr(Address(most_recent_dodag.dodagID)), most_recent_dodag.version.get_val(), dio.version ))
                # this should trigger global repair downward
                consistent = False

            if dio.version < least_recent:
                logger.debug("Receiving a DIO from an old version of the DODAG %s," \
                             " version %d < version %d" % (repr(Address(least_recent_dodag.dodagID)), dio.version, least_recent_dodag.version.get_val()))
                logger.debug("DIO dropped")
                return
        except IndexError:  # there was not older version of this DODAG
            pass

        # this is the first time we receive a DIO from this DODAG version
        # make sure that the DODAG is grounded, and that we support this
        # mode of operation.
        if dio.rank != INFINITE_RANK and dio.G == 1 and dio.MOP == 2:
            logger.info("Receiving a DIO from a new DODAG, adding it to our cache")
            dodag = DODAG(instanceID=dio.instanceID, version=dio.version,
                        G=dio.G, MOP=dio.MOP, Prf=dio.Prf, DTSN=dio.DTSN,
                        dodagID=dio.DODAGID,
                        interfaces=interfaces
                        )
            try: # if this is a newer version of a DODAG, some information needs to be passed down
                dodag.last_DAOSequence  = deepcopy(most_recent_dodag.last_DAOSequence)
                dodag.last_PathSequence = deepcopy(most_recent_dodag.last_PathSequence)
            except NameError:
                pass
            gv.dodag_cache.add(dodag)
            consistent = False
        else:
            logger.debug("DIO dropped")
            if dio.rank == INFINITE_RANK:
                logger.debug("Rank is INFINITE_RANK")
            if not dio.G:
                logger.debug("floating DODAG are not supported")
            if dio.MOP != 2:
                logger.debug("incompatible Mode of Operation (MOP)")
            return


    options = getAllOption(payload)

    logger.debug("DIO message contains the following options:")
    for opt in options:
        logger.debug("- " + opt.__class__.__name__)

        if isinstance(opt, RPL_Option_DODAG_Configuration):
            dodag.authenticated = opt.A
            dodag.PCS = opt.PCS
            dodag.DIOIntDoublings = opt.DIOIntDoubl
            dodag.DIOIntMin = opt.DIOIntMin
            dodag.DIORedundancyConst = opt.DIORedun
            dodag.MaxRankIncrease = opt.MaxRankIncrease
            dodag.MinHopRankIncrease = opt.MinHopRankIncrease
            dodag.OCP = opt.OCP
            dodag.DftLft = opt.DefLifetime
            dodag.LftUnit = opt.LifetimeUnit

        if isinstance(opt, RPL_Option_Prefix_Information):
            if opt.L:
                # TODO: prefix field contains an address that can be used for
                # on-link determination
                # (It means that one can send a packet directly to the parent,
                # meaning that the node can probably have a direct route)
                pass

            if opt.R:
                # TODO: process the R flags (only seems useful if the RPL target
                # option is required somehow)
                # - if L=O and R=1, the parent provides its own address in the
                # PIO, then the parent must advertise that address as a DAO
                # target
                pass

            if opt.A:
                if opt.prefix_len != 64:
                    logger.debug("PIO option: cannot derive an address from a prefix whose length is not 64 bits")
                    continue

                # take only the 64 first bits of the prefix
                prefix = opt.prefix[:8]

                # Compute an IID for each interface/physical address
                # and build an IPv6 address with this prefix for each interfaces
                addresses = []
                for iface in interfaces:
                    address = derive_address(iface, prefix)
                    if address:
                        addresses.append((address, iface))

                # assigns the new addresses
                for (address, iface) in addresses:
                    gv.address_cache.add(repr(address), iface, 64, opt.valid_lifetime, opt.preferred_lifetime)

                # make sure we record this prefix as one of the prefix we
                # advertise
                if prefix not in dodag.advertised_prefixes:
                    dodag.advertised_prefixes.append(prefix)


        if isinstance(opt, RPL_Option_DAG_Metric_Container):
            # TODO
            pass

    if dio.rank != INFINITE_RANK:
        gv.neigh_cache.register_node(message.iface, message.src, dodag, dio.rank, dio.DTSN)

    # update the DIO parent (the new parent could be from a different DODAG)
    updated = gv.neigh_cache.update_DIO_parent()
    if updated: consistent = False

    # if there is no DIO parent for this node, it must advertises an
    # INFINITE_RANK, so that it is not selected by its children
    parent = dodag.preferred_parent
    # there is no parent left for the node
    if not parent and dodag.rank != INFINITE_RANK:
        dodag.rank = INFINITE_RANK
        consistent = False

    # if we moved to a new DODAG version, now is a good time to clean up old
    # versions
    gv.dodag_cache.purge_old_versions()

    # happen when all neighboring nodes send a poison DIO message
    if gv.dodag_cache.is_empty():
        return

    if dodag.rank < dodag.lowest_rank_advertized:
        dodag.lowest_rank_advertized = dodag.rank

    # if not consistent, reset the trickle timer
    try:
        if not consistent:
            dodag.DIOtimer.hear_inconsistent()
            dodag.setDAOtimer()
        else:
            dodag.DIOtimer.hear_consistent()
    except AttributeError:
        pass

    return