contiki-ng / contiki-ng

Contiki-NG: The OS for Next Generation IoT Devices
https://www.contiki-ng.org/
BSD 3-Clause "New" or "Revised" License
1.31k stars 700 forks source link

The semantics of `node_id` #195

Open g-oikonomou opened 6 years ago

g-oikonomou commented 6 years ago

I never quite managed to get my head around this one. How do people use it? What is it needed for? I am thinking that we need to come up with a uniform way of handling it across all supported ports.

joakimeriksson commented 6 years ago

Previously a bit used for proprietary protocols similar to a short MAC address of 802.15.4 more or less. Also used in printouts in COOJA, etc for something shorter then a full 802.15.4 MAC address.

simonduq commented 6 years ago

My guess is that it is only of use in research / non-IP setups. I personally use it in testbed, to match the infrastructure's node ID to the internal ID.

g-oikonomou commented 6 years ago

OK that helps. Is there an expected relationship between it, the node's LL address and the short/long address used by the radio?

simonduq commented 6 years ago

I would say no (for sure not in my case)

simonduq commented 6 years ago

Well there can be a mapping, if that counts as relationship

simonduq commented 6 years ago

I have a module I use for my testbed runs to auto-map node-ID from radio address (per-testbed hardcoded mapping)

g-oikonomou commented 6 years ago

By "relationship" I mean if e.g. node_id is 0xABCD does the short address also have to be 0xABCD? Does the long address need to end in 0xABCD? From what you are saying, I understand that the answer is no?

CC13xx/CC26xx platforms do node_id = short_addr;. We should either homogenize that, or I can get rid of it altogether.

simonduq commented 6 years ago

The answer is no indeed. I agree on homogenizing! I could contribute my testbed mapping module. When the module is not there, we could either have node_id = short_addr or why not have no node_id at all.

romain-jacob commented 5 years ago

Hi there, I would like to reopen this issue. I saw that you implemented this homogenization in release 4.2. In principle, I don't have any objection against that, but it leads to some issues I am not too sure how to solve.

For the case of the Sky motes, as far as I understand the new implementation, the node_id is initialized based on the LL address, which is itself initialized using the ds2411. Okay.

The problem is that I cannot directly control anymore the desired node ID of one mote (which used to be done with the node_id_restore() function, looking at the first bytes sitting in flash). It seems that the intended way to solve this is to use the BUILD_WITH_DEPLOYMENT, but as far as I understand this, it seems I need to map the desired node ID to the LL address (which does not really solve anything, since I still can't control the LL address that I get).

The practical issue here is that we use protocols that assign specific roles to specific node ID (e.g., node 1 is the data sink of a collection scenario). If I use the BUILD_WITH_DEPLOYMENT, I can get the mapping ID <-> LLaddres, but that means that every time I exchange two nodes, I need to update the mapping... More annoying, it means if I share my code with someone, they can not run it out of the box with their nodes, because they will have different node IDs.

As a side note, if the LINKADDR_CONF_SIZE < 8, there are no guarantee to have unique node IDs anymore, which is not great either.

Here are some ideas to resolve this:

  1. Include back the node_id_restore() and node_id_burn() functions: Pros: Simple to use and well-known to the current practitioners. Sufficient for everyone doing only ad-hoc networking. Allows to program many nodes at once. Cons: Platform-specific
  2. Let the user define the desired ID at compile time with a flag NODE_ID=xx Pros: Let anyone using any node ID desired, without too much overhead Cons: Can only flash one at a time...

What do you think?

g-oikonomou commented 5 years ago

Hi @romain-jacob thanks for the feedback.

I am definitely against 1. due to it being platform-specific as you say, unless someone can somehow come up with a way to make the _burn() and _restore() functions cross-platform. What we had previously was, we had those functions for a small subset of platforms, and then other platforms were using node_id in some undocumented, platform-specific, it-felt-like-a-good-idea-when-I-wrote-it fashion, whereas some other platforms plain and simple did not support node_id at all.

I am not opposed to 2., but this takes us back to the OP: What are the semantics? If you specify NODE_ID=3 at build time, how is that meant to affect (if at all) a node's link layer and/or v6 address(es)?

Perhaps what we need is:

  1. Understand our requirements and then come up with a proper cross-platform solution, with or without node_id.

As far as I can understand you want to be able to use the same firmware for nodes that can perform a different functions? The choice of which function to perform (e.g. sink, source) depends on some flag that comes from somewhere (at run time?). Am I on the right track here? Do you want multiple different values of this flag? For example, do you actually need unique identifiers per device, or do you just need a way to toggle across N different modes of operation? Do you need to be able to change such modes at run time? How were you previously writing those first bytes in flash?

I'm re-opening this for now.

romain-jacob commented 5 years ago

Thanks for picking that up so quickly!

I think the requirement is really to set a unique identifier per device, but that:

I guess this concern is limited to the case where no no specific MAC or NET layers are being used (NULLMAC, NULLNET), but that's an important share of the current research I believe... Need to think about something what would fit the bill while being cross-platform... TBC

g-oikonomou commented 5 years ago

I am still not 100% sure I am following you. The way this is coming across is, you are trying to explain to me a solution, but what I am trying to achieve here is to understand the problem to begin with :)

  • can be picked by the user (e.g., you want a node that has node_id = 1 in your network)

Why do you need to check for node_id==1? Does it absolutely have to be node_id==1? Could it be a check if the_answer==42? Could it be some_randomly_assigned_variable & 1 == 0?

  • is small enough to be practical, i.e. 2 bytes typically in low-power networking.

Easy enough to pass at build time, but is this something you need to be able to change at run time? If so, then do you need it to persist across restarts?

romain-jacob commented 5 years ago

Why do you need to check for node_id==1? One typical case is, you have a node playing a central role, let's call it a host, or master. Which node is playing that role is decided based on a define (or a variable), something like HOST_ID = 1. At runtime, all nodes need to check what their role is, which they will do with a test (node_id == HOST_ID), and execute the corresponding part of the code.

Another example is to check if one node id is in some list, something like is_in_list(node_id, ACTIVE_NODE_LIST).

This can be done using the current LLaddres (which comes from the DS2411 on the sky mote). Problem are (i) it's 8 bytes long, which is a lot of overhead for low-power motes (ii) if I take a subset, the IDs are not guarantee to be unique anymore (iii) the IDs are hardware specific: if I have in my code the LLaddres of my sky motes, it needs being changed by anyone else that want to use my code. The BUILD_WITH_DEPLOYMENT makes this a bit less cumbersome, but the problem remains.

Easy enough to pass at build time, but is this something you need to be able to change at run time? If so, then do you need it to persist across restarts?

Fixed at deployment time is ok. I cannot think of any protocol that updates the node ID at runtime...

Does this make things clearer?

atiselsts commented 5 years ago

For information, we're currently using what is basically a third option next to the two @romain-jacob mentions, one that I think is worth considering for implementation: have the node-id / MAC address be stored in a fixed address in the firmware image. Then, one firmware image is built for all nodes, but prepared for each node separately, by rewriting a particular line in the .hex file. The result is that I can upload it with setting the node-id / MAC address from command line for a particular node with ID=1 by typing make hello-world.upload A=1. Or, I can run the make hello-world.testbed target, which generates a bunch of .hex files with node IDs / MAC address in predefined range and uploads them to the testbed. Swapping the hardware becomes easy, and the node ids remain the same.

romain-jacob commented 5 years ago

We actually do something very similar to what @atiselsts for running tests on Flocklab. We define a specific symbol (called TOS_NODE_ID for historical reasons) and assign node_id = TOS_NODE_ID during initialization. When programming the hardware, the testbed uses the tos-set-symbol utility to replace the value in TOS_NODE_ID by the desired ID for specific node.

A solution in the line of 'make hello-world.upload NODE_ID=1' would be good I think.

g-oikonomou commented 5 years ago

So this is what I have done for CC2538DK (2 consecutive sections of the same wiki page):

https://github.com/contiki-ng/contiki-ng/wiki/Platform-cc2538dk#node-ieee-and-ipv6-addresses https://github.com/contiki-ng/contiki-ng/wiki/Platform-cc2538dk#scripted-multi-image-builds

Edit: Exact same logic for zoul

atiselsts commented 5 years ago

Hmm, interesting, but that does require rebuilding the binary for each node. I rather like the .hex file approach which decouples the "building firmware" step from the "installing firmware" step. The node id could be put in a dedicated .section in the firmware file with a fixed (platform-specific) address, no? The address can be set from LDFLAGS, for example with the option -Wl,--section-start=.nodeid=0x5000.

romain-jacob commented 5 years ago

I agree with @atiselsts . Changing the node id when flashing rather than at compile time would be nicer. It does not sound like much, that that makes a big difference when you have to program 20 nodes!

simonduq commented 5 years ago

My understanding is that for your use-case @romain-jacob, you don't need the deployment module at all. The point of the module is to provide compile-time well-known mappings between IDs and addresses, and this is not something you have in your setup.

What about simply having platforms optionally define their own ID initialization function, used by node_id_init whenever BUILD_WITH_DEPLOYMENT is unset? Would you be against that for being platform-specific @g-oikonomou?

atiselsts commented 5 years ago

This is the implementation of the ":.hex file override" idea I mentioned here, by the way: https://github.com/contiki-ng/contiki-ng/commit/2ced5bb7629ffbc6f798a5a077dd38ead191e3fc It's published in a branch along with our source code for the Instant protocol from EWSN paper.

rahav commented 1 year ago

Hello everyone. I am not sure if this was finalized or implemented. Having read above, a solution such as make hello-world.upload A=1 seems a good option in a research setting, but I can't find whether something like it was implemented in Contiki 4.9.

The requirement is: a unique, small, and easily configurable node_id.

Is there a solution?

If there isn't, do we have docs on how to use BUILD_WITH_DEPLOYMENT?