Topics

echo_client / echo_server hop limit


Diana Rivera
 

Hello,

I am currently working on an OpenThread app based on the echo_client and echo_server. I am currently trying to use the hop-limit field by setting it as follows:

In the echo_client udp.c file:
static void send_udp_data(struct net_app_ctx *ctx, struct data *data)
{
    struct net_pkt *pkt;
    size_t len;
    int ret;

    data->expecting_udp = ipsum_len;

    pkt = prepare_send_pkt(ctx, data->proto, &data->expecting_udp);
    if (!pkt) {
        return;
    }
    
    net_pkt_set_ipv6_hop_limit(pkt, 8);
    NET_INFO("Hop limit set to: %d", net_pkt_ipv6_hop_limit(pkt));
    len = net_pkt_get_len(pkt);


    NET_ASSERT_INFO(data->expecting_udp == len,
            "Data to send %d bytes, real len %zu",
            data->expecting_udp, len);

    ret = net_app_send_pkt(ctx, pkt, NULL, 0, K_FOREVER,
                   UINT_TO_POINTER(len));
    if (ret < 0) {
        NET_ERR("Cannot send %s data to peer (%d)", data->proto, ret);

        net_pkt_unref(pkt);
    }

    k_delayed_work_submit(&data->recv, WAIT_TIME);
}

In the echo_server udp.c:

struct net_pkt *build_reply_pkt(const char *name,
                struct net_app_ctx *ctx,
                struct net_pkt *pkt)
{
    struct net_pkt *reply_pkt;
    struct net_buf *frag, *tmp;
    int header_len = 0, recv_len, reply_len;
    u8_t *ptr = net_pkt_appdata(pkt);
    // hop_lim = pkt->ipv6_hop_limit;
    hop_lim = net_pkt_ipv6_hop_limit(pkt);

    NET_INFO("Application message received: %s, hop limit: %d\n", ptr, hop_lim);
    NET_INFO("%s received %d bytes", name, net_pkt_appdatalen(pkt));


    if (net_pkt_appdatalen(pkt) == 0) {
        return NULL;
    }

    reply_pkt = net_app_get_net_pkt(ctx, net_pkt_family(pkt), K_FOREVER);

    NET_ASSERT(reply_pkt);
    NET_ASSERT(net_pkt_family(reply_pkt) == net_pkt_family(pkt));

    recv_len = net_pkt_get_len(pkt);

    tmp = pkt->frags;

    /* If we have link layer headers, then get rid of them here. */
    if (recv_len != net_pkt_appdatalen(pkt)) {
        /* First fragment will contain IP header so move the data
         * down in order to get rid of it.
         */
        header_len = net_pkt_appdata(pkt) - tmp->data;

        NET_ASSERT(header_len < CONFIG_NET_BUF_DATA_SIZE);

        /* After this pull, the tmp->data points directly to application
         * data.
         */
        net_buf_pull(tmp, header_len);
    }

    net_pkt_set_appdatalen(reply_pkt, net_pkt_appdatalen(pkt));

    while (tmp) {
        frag = net_app_get_net_buf(ctx, reply_pkt, K_FOREVER);

        if (net_buf_headroom(tmp) == 0) {
            /* If there is no link layer headers in the
             * received fragment, then get rid of that also
             * in the sending fragment. We end up here
             * if MTU is larger than fragment size, this
             * is typical for ethernet.
             */
            net_buf_push(frag, net_buf_headroom(frag));

            frag->len = 0; /* to make fragment empty */

            /* Make sure to set the reserve so that
             * in sending side we add the link layer
             * header if needed.
             */
            net_pkt_set_ll_reserve(reply_pkt, 0);
        }

        NET_ASSERT_INFO(net_buf_tailroom(frag) >= tmp->len,
                "tail %zd longer than len %d",
                net_buf_tailroom(frag), tmp->len);

        memcpy(net_buf_add(frag, tmp->len), tmp->data, tmp->len);

        tmp = net_pkt_frag_del(pkt, NULL, tmp);
    }

    reply_len = net_pkt_get_len(reply_pkt);

    NET_ASSERT_INFO((recv_len - header_len) == reply_len,
            "Received %d bytes, sending %d bytes",
            recv_len - header_len, reply_len);

    return reply_pkt;
}

On the client side, I'm able to observe that the hop limit has been set to 8; however, by the time I read the hop limit field at the server, this value returns zero, instead of having decreased by just 1 as expected.
Am I making a mistake in the way I'm using the   net_pkt_set_ipv6_hop_limit and   net_pkt_ipv6_hop_limit functions? Or is there another way to be able to use the hop limit field in OT?

Thank you in advance for your answer,
Diana


Lubos, Robert
 

Hi Diana,

 

I checked if there is any interference of OT port in Zephyr with Hop Limit IPv6 field, and there is no such a thing. A quick research showed up that it is rather a problem in Zephyr’s IPv6 layer. It looks like it does not set the ipv6_hop_limit filed in the packet structure based on the received IPv6 header (that’s why you see 0, it’s left as it was initialized). For a quick fix you can add the following line to the net_ipv6_process_pkt function (ipv6.c):

 

net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_HDR(pkt)->hop_limit);

 

It will copy the Hop Limit value from the header to the packet structure. Still, someone more familiar with IPv6 in Zephyr might propose a better fix or submit a PR to fix the problem.

 

Also please note that Hop Limit is decremented only when a packet is forwarded (there are routers between the endpoints), so if there’s a direct link between two endpoints the Hop Limit will remain unchanged.

 

Best Regards,

Robert

From: devel@... [mailto:devel@...] On Behalf Of Diana Rivera
Sent: Tuesday, June 5, 2018 10:37
To: devel@...
Subject: [Zephyr-devel] echo_client / echo_server hop limit

 

Hello,

I am currently working on an OpenThread app based on the echo_client and echo_server. I am currently trying to use the hop-limit field by setting it as follows:

In the echo_client udp.c file:
static void send_udp_data(struct net_app_ctx *ctx, struct data *data)
{
    struct net_pkt *pkt;
    size_t len;
    int ret;

    data->expecting_udp = ipsum_len;

    pkt = prepare_send_pkt(ctx, data->proto, &data->expecting_udp);
    if (!pkt) {
        return;
    }
    
    net_pkt_set_ipv6_hop_limit(pkt, 8);
    NET_INFO("Hop limit set to: %d", net_pkt_ipv6_hop_limit(pkt));
    len = net_pkt_get_len(pkt);


    NET_ASSERT_INFO(data->expecting_udp == len,
            "Data to send %d bytes, real len %zu",
            data->expecting_udp, len);

    ret = net_app_send_pkt(ctx, pkt, NULL, 0, K_FOREVER,
                   UINT_TO_POINTER(len));
    if (ret < 0) {
        NET_ERR("Cannot send %s data to peer (%d)", data->proto, ret);

        net_pkt_unref(pkt);
    }

    k_delayed_work_submit(&data->recv, WAIT_TIME);
}

In the echo_server udp.c:

struct net_pkt *build_reply_pkt(const char *name,
                struct net_app_ctx *ctx,
                struct net_pkt *pkt)
{
    struct net_pkt *reply_pkt;
    struct net_buf *frag, *tmp;
    int header_len = 0, recv_len, reply_len;
    u8_t *ptr = net_pkt_appdata(pkt);
    // hop_lim = pkt->ipv6_hop_limit;
    hop_lim = net_pkt_ipv6_hop_limit(pkt);

    NET_INFO("Application message received: %s, hop limit: %d\n", ptr, hop_lim);
    NET_INFO("%s received %d bytes", name, net_pkt_appdatalen(pkt));


    if (net_pkt_appdatalen(pkt) == 0) {
        return NULL;
    }

    reply_pkt = net_app_get_net_pkt(ctx, net_pkt_family(pkt), K_FOREVER);

    NET_ASSERT(reply_pkt);
    NET_ASSERT(net_pkt_family(reply_pkt) == net_pkt_family(pkt));

    recv_len = net_pkt_get_len(pkt);

    tmp = pkt->frags;

    /* If we have link layer headers, then get rid of them here. */
    if (recv_len != net_pkt_appdatalen(pkt)) {
        /* First fragment will contain IP header so move the data
         * down in order to get rid of it.
         */
        header_len = net_pkt_appdata(pkt) - tmp->data;

        NET_ASSERT(header_len < CONFIG_NET_BUF_DATA_SIZE);

        /* After this pull, the tmp->data points directly to application
         * data.
         */
        net_buf_pull(tmp, header_len);
    }

    net_pkt_set_appdatalen(reply_pkt, net_pkt_appdatalen(pkt));

    while (tmp) {
        frag = net_app_get_net_buf(ctx, reply_pkt, K_FOREVER);

        if (net_buf_headroom(tmp) == 0) {
            /* If there is no link layer headers in the
             * received fragment, then get rid of that also
             * in the sending fragment. We end up here
             * if MTU is larger than fragment size, this
             * is typical for ethernet.
             */
            net_buf_push(frag, net_buf_headroom(frag));

            frag->len = 0; /* to make fragment empty */

            /* Make sure to set the reserve so that
             * in sending side we add the link layer
             * header if needed.
             */
            net_pkt_set_ll_reserve(reply_pkt, 0);
        }

        NET_ASSERT_INFO(net_buf_tailroom(frag) >= tmp->len,
                "tail %zd longer than len %d",
                net_buf_tailroom(frag), tmp->len);

        memcpy(net_buf_add(frag, tmp->len), tmp->data, tmp->len);

        tmp = net_pkt_frag_del(pkt, NULL, tmp);
    }

    reply_len = net_pkt_get_len(reply_pkt);

    NET_ASSERT_INFO((recv_len - header_len) == reply_len,
            "Received %d bytes, sending %d bytes",
            recv_len - header_len, reply_len);

    return reply_pkt;
}

On the client side, I'm able to observe that the hop limit has been set to 8; however, by the time I read the hop limit field at the server, this value returns zero, instead of having decreased by just 1 as expected.
Am I making a mistake in the way I'm using the   net_pkt_set_ipv6_hop_limit and   net_pkt_ipv6_hop_limit functions? Or is there another way to be able to use the hop limit field in OT?

Thank you in advance for your answer,
Diana


Jukka Rissanen
 

On Tue, 2018-06-05 at 09:24 +0000, Lubos, Robert wrote:
Hi Diana,

I checked if there is any interference of OT port in Zephyr with Hop
Limit IPv6 field, and there is no such a thing. A quick research
showed up that it is rather a problem in Zephyr’s IPv6 layer. It
looks like it does not set the ipv6_hop_limit filed in the packet
structure based on the received IPv6 header (that’s why you see 0,
it’s left as it was initialized). For a quick fix you can add the
following line to the net_ipv6_process_pkt function (ipv6.c):

net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_HDR(pkt)->hop_limit);
Note that we set the hop-limit in ipv6.c line 717
(net_ipv6_create_raw() function) if the user has not set it itself. It
seems that there is a glitch somewhere if the user set hop-limit is
lost.

Diana, could you create a issue in github that describes the scenario
so we do not forget it.


Cheers,
Jukka