Grid’5000 and FIT/IoT-LAB - IPv6#

Introduction#

This example shows how to interact with both platforms in a single experiment.

An IPv6 network is built in IoT-LAB platform, composed of a border sensor and CoAP servers. A node in Grid’5000 is the client, which uses a CoAP client to read the sensor using its global IPv6 address.

Inspired on: https://www.iot-lab.info/legacy/tutorials/contiki-coap-m3/index.html

[ ]:
from enoslib import *
import logging
import sys

Configuring logging: save DEBUG to a file and INFO to stdout

[ ]:
log = logging.getLogger()
log.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fileHandler = logging.FileHandler("debug.log", 'a')
fileHandler.setLevel(logging.DEBUG)
fileHandler.setFormatter(formatter)
log.addHandler(fileHandler)

cformat = logging.Formatter("[%(levelname)8s] : %(message)s")
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(cformat)
consoleHandler.setLevel(logging.INFO)
log.addHandler(consoleHandler)

Getting resources#

IoT-LAB provider configuration: reserve M3 nodes in saclay site#

Note: It uses the following M3 images: border-router.iotlab-m3 and er-example-server.iotlab-m3.

More details on how to generate these images in: https://www.iot-lab.info/legacy/tutorials/contiki-coap-m3/index.html

[ ]:
job_name="iotlab_g5k-ipv6"
iotlab_dict = {
    "walltime": "01:00",
    "job_name": job_name,
    "resources": {
        "machines": [
            {
                "roles": ["border_router"],
                "archi": "m3:at86rf231",
                "site": "saclay",
                "number": 1,
                "image": "border-router.iotlab-m3",
            },
            {
                "roles": ["sensor"],
                "archi": "m3:at86rf231",
                "site": "saclay",
                "number": 2,
                "image": "er-example-server.iotlab-m3",
            },
        ]
    },
}
iotlab_conf = IotlabConf.from_dictionary(iotlab_dict)

Grid’5000 provider configuration: reserve nodes in grenoble#

[ ]:
g5k_dict = {
    "job_type": [],
    "job_name": job_name,
    "resources": {
        "machines": [
            {
                "roles": ["client"],
                "cluster": "yeti",
                "nodes": 1,
                "primary_network": "default",
                "secondary_networks": [],
            },
        ],
        "networks": [
            {"id": "default", "type": "prod", "roles": ["my_network"], "site": "grenoble"}
        ],
    },
}
g5k_conf = G5kConf.from_dictionnary(g5k_dict)

We still need a Static provider to interact with the IoT-LAB frontend machine#

[ ]:
import iotlabcli.auth
iotlab_user, _ = iotlabcli.auth.get_user_credentials()

iotlab_frontend_conf = (
    StaticConf()
    .add_machine(
        roles=["frontend"],
        address="saclay.iot-lab.info",
        alias="saclay",
        user=iotlab_user
    )
    .finalize()
)

IoT-LAB: getting resources#

[ ]:
iotlab_provider = Iotlab(iotlab_conf)
iotlab_roles, _ = iotlab_provider.init()
print(iotlab_roles)

Grid’5000: getting resources#

[ ]:
g5k_provider = G5k(g5k_conf)
g5k_roles, g5knetworks = g5k_provider.init()
print(g5k_roles)

Static: getting resources#

[ ]:
frontend_provider = Static(iotlab_frontend_conf)
frontend_roles, _ = frontend_provider.init()
print(frontend_roles)

Configuring network connectivity#

Enabling IPv6 on Grid’5000 nodes (https://www.grid5000.fr/w/IPv6)#

[ ]:
result=run_command("dhclient -6 br0", roles=g5k_roles)
[ ]:
result = run_command("ip address show dev br0", roles=g5k_roles)
print(result['ok'])

Starting tunslip command in frontend.#

Redirect tunslip command output to a file to read it later.

[ ]:
iotlab_ipv6_net="2001:660:3207:4c0::"
tun_cmd = "sudo tunslip6.py -v2 -L -a %s -p 20000 %s1/64 > tunslip.output 2>&1" % (iotlab_roles["border_router"][0].alias, iotlab_ipv6_net)
result=run_command(tun_cmd, roles=frontend_roles, asynch=3600, poll=0)

Reseting border router#

[ ]:
iotlab_roles["border_router"][0].reset()

Get the Border Router IPv6 address from tunslip output#

[ ]:
result = run_command("cat tunslip.output", roles=frontend_roles)
print(result['ok'])
[ ]:
import re
out = result['ok']['saclay']['stdout']
print(out)
match = re.search(rf'Server IPv6 addresses:\n.+({iotlab_ipv6_net}\w{{4}})', out, re.MULTILINE|re.DOTALL)
br_ipv6 = match.groups()[0]
print("Border Router IPv6 address from tunslip output: %s" % br_ipv6)

Checking ping from Grid’5000 to border router node#

[ ]:
result = run_command("ping6 -c3 %s" % br_ipv6, pattern_hosts="client*", roles=g5k_roles)
print(result['ok'])

Installing and using CoAP clients#

Install aiocoap client and lynx on grid’5000 nodes#

[ ]:
with play_on(roles=g5k_roles) as p:
    p.apt(name=["python3-aiocoap", "lynx"], state="present")

Grab the CoAP server node’s IPv6 address from the BR’s web interface#

[ ]:
result = run_command("lynx -dump http://[%s]" % br_ipv6, roles=g5k_roles)
print(result['ok'])

For a CoAP server, GET light sensor#

[ ]:
out = result['ok'][g5k_roles["client"][0].address]['stdout']
print(out)
match = re.search(r'fe80::(\w{4})', out, re.MULTILINE|re.DOTALL)
node_uid = match.groups()[0]
print(node_uid)
[ ]:
result = run_command("aiocoap-client coap://[%s%s]:5683/sensors/light" % (iotlab_ipv6_net, node_uid), roles=g5k_roles)
print(result['ok'])

GET pressure for the same sensor#

[ ]:
result = run_command("aiocoap-client coap://[%s%s]:5683/sensors/pressure" % (iotlab_ipv6_net, node_uid), roles=g5k_roles)
print(result['ok'])

Clean-up phase#

Stop tunslip in frontend node#

[ ]:
result = run_command("pgrep tunslip6 | xargs kill", roles=frontend_roles)

Destroy jobs in testbeds#

[ ]:
g5k_provider.destroy()
iotlab_provider.destroy()