Bluetooth Mesh 1.1 Directed Forwarding: Implementing a Custom Directed Forwarding Engine on a Zephyr-Based SoC with C Code

The Bluetooth Mesh protocol has evolved significantly since its initial adoption in July 2017 (Mesh Profile v1.0). With the introduction of Bluetooth Mesh v1.1, the specification brought a powerful new feature: Directed Forwarding. This mechanism fundamentally changes how messages traverse a mesh network, moving away from the traditional flooding-based approach to a more efficient, route-directed method. In this article, we will explore the technical underpinnings of Directed Forwarding as defined in the Mesh Protocol v1.1 and demonstrate how to implement a custom Directed Forwarding engine on a Zephyr RTOS-based System-on-Chip (SoC), such as the Silicon Labs SiBG301, using C code.

Understanding Directed Forwarding in Bluetooth Mesh 1.1

In classic Bluetooth Mesh (v1.0 and v1.0.1), every node in a network retransmits every message unless it is the intended destination. This flooding mechanism, while robust, creates significant network overhead, especially in dense deployments. Directed Forwarding, introduced in Mesh v1.1, addresses this by enabling unicast-based routing. A node that supports Directed Forwarding (a "DF-Node") can send a message along a specific path to a single destination, using a Directed Forwarding Table (DFT) to decide which neighbor to forward the message to.

Key concepts defined in the Mesh Protocol v1.1 specification include:

  • Directed Forwarding Table (DFT): A local table in each DF-Node that maps destination addresses to next-hop addresses. This table is populated and maintained through a process called "Directed Forwarding Discovery" (DFD).
  • Directed Forwarding Discovery (DFD): A procedure used to establish and maintain routes. It involves sending route request (RREQ) and route reply (RREP) messages, similar to ad-hoc routing protocols.
  • Directed Forwarding Tag (DFTAG): A 16-bit identifier carried in the network PDU header that indicates the message is using directed forwarding. The tag is used to prevent loops and to identify the path.
  • Path Originator and Path Destination: The node that initiates the directed forwarding route (typically the source) and the node that terminates it (the destination).

The primary benefit of Directed Forwarding is a dramatic reduction in network congestion and energy consumption. Instead of every node waking up to relay a flood, only nodes along the directed path need to process and forward the message. This is particularly critical for battery-powered devices and large-scale lighting control networks, where mesh models defined in the Mesh Model specification (MMDL v1.1.1) are heavily used.

Architecture of a Custom Directed Forwarding Engine

To implement a Directed Forwarding engine on a Zephyr-based SoC, we need to integrate with the existing Bluetooth Mesh stack. The Zephyr RTOS provides a robust Bluetooth Mesh implementation (found in subsys/bluetooth/mesh), but as of version 3.6, Directed Forwarding is not fully supported in the mainline. Therefore, we must build a custom engine that operates alongside the standard foundation models.

The engine consists of three main components:

  • DFT Manager: Handles the creation, lookup, and maintenance of the Directed Forwarding Table.
  • DFD Protocol Handler: Processes RREQ and RREP messages to discover and maintain routes.
  • Forwarding Engine: Intercepts outgoing and incoming network PDUs to apply directed forwarding logic.

Implementing the DFT Manager in C

First, we define a data structure for the Directed Forwarding Table entry. Each entry must store the destination address (unicast), the next-hop address, the DFTAG, and a lifetime counter.

/* dft_manager.h */
#include <stdint.h>
#include <zephyr/bluetooth/mesh.h>

#define DFT_MAX_ENTRIES 32
#define DFT_LIFETIME_SEC 300  /* 5 minutes, typical */

struct dft_entry {
    uint16_t dst;           /* Destination unicast address */
    uint16_t next_hop;      /* Next-hop unicast address */
    uint16_t dftag;         /* Directed Forwarding Tag */
    uint32_t lifetime_sec;  /* Remaining lifetime in seconds */
    bool     valid;
};

/* DFT Manager API */
int dft_init(void);
int dft_add_entry(uint16_t dst, uint16_t next_hop, uint16_t dftag);
int dft_lookup(uint16_t dst, struct dft_entry *entry);
void dft_remove_entry(uint16_t dst);
void dft_maintenance(void);  /* Called periodically to decrement lifetimes */

The implementation of dft_add_entry involves inserting a new entry or updating an existing one. The DFTAG must be unique per path; a simple approach is to use a hash of the source and destination addresses combined with a random salt.

/* dft_manager.c */
#include "dft_manager.h"

static struct dft_entry dft_table[DFT_MAX_ENTRIES];

int dft_init(void) {
    for (int i = 0; i < DFT_MAX_ENTRIES; i++) {
        dft_table[i].valid = false;
    }
    return 0;
}

int dft_add_entry(uint16_t dst, uint16_t next_hop, uint16_t dftag) {
    for (int i = 0; i < DFT_MAX_ENTRIES; i++) {
        if (!dft_table[i].valid) {
            dft_table[i].dst = dst;
            dft_table[i].next_hop = next_hop;
            dft_table[i].dftag = dftag;
            dft_table[i].lifetime_sec = DFT_LIFETIME_SEC;
            dft_table[i].valid = true;
            return 0;
        }
    }
    return -ENOMEM;  /* Table full */
}

int dft_lookup(uint16_t dst, struct dft_entry *entry) {
    for (int i = 0; i < DFT_MAX_ENTRIES; i++) {
        if (dft_table[i].valid && dft_table[i].dst == dst) {
            *entry = dft_table[i];
            return 0;
        }
    }
    return -ENOENT;  /* Not found */
}

Implementing the Directed Forwarding Discovery (DFD)

DFD is essential for populating the DFT. When a node wants to send a directed message to a destination for which it has no DFT entry, it initiates a discovery by broadcasting an RREQ. The RREQ message is a special network PDU with a specific opcode (0x01 for RREQ per Mesh Protocol v1.1). Intermediate DF-Nodes that receive the RREQ check if they have a route to the destination; if not, they rebroadcast the RREQ. When the RREQ reaches the destination, it sends a unicast RREP back along the reverse path, populating the DFTs of intermediate nodes.

In our custom engine, we handle RREQ and RREP messages in the network layer. The following code snippet shows a simplified handler for an incoming RREQ:

/* dfd_handler.c */
#include "dft_manager.h"
#include <zephyr/bluetooth/mesh/access.h>

/* Assume we have a function to send a network PDU */
void send_network_pdu(struct bt_mesh_net_tx *tx, uint16_t dst);

void handle_rreq(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) {
    uint16_t orig_dst;  /* The final destination of the RREQ */
    uint16_t orig_src;  /* The originator of the RREQ */

    /* Parse RREQ payload (simplified) */
    orig_src = net_buf_simple_pull_le16(buf);
    orig_dst = net_buf_simple_pull_le16(buf);

    /* Check if we are the destination */
    if (orig_dst == bt_mesh_primary_addr()) {
        /* Send RREP back to orig_src via the path the RREQ came from */
        struct bt_mesh_net_tx tx = {
            .src = bt_mesh_primary_addr(),
            .dst = rx->addr,
            .ctx = &rx->ctx,
        };
        /* Build RREP payload and send */
        send_rrep(&tx, orig_src);
    } else {
        /* Check DFT for existing route to orig_dst */
        struct dft_entry entry;
        if (dft_lookup(orig_dst, &entry) == 0) {
            /* Forward RREQ towards destination using existing DFT entry */
            /* (This is a simplified version; real DFD may have more logic) */
        } else {
            /* Re-broadcast the RREQ (flooding fallback) */
            /* Update the path record in the RREQ payload */
            bt_mesh_net_send(&tx, buf);
        }
    }
}

Integrating with the Zephyr Network Layer

To intercept network PDUs, we need to hook into the Bluetooth Mesh network layer. Zephyr provides a callback mechanism via bt_mesh_net_recv_cb for incoming PDUs and bt_mesh_net_send_cb for outgoing PDUs. We register our custom forwarding engine to inspect each PDU for the Directed Forwarding tag (DFTAG).

When a node receives a directed PDU (identified by a specific bit in the network header), the engine must:

  • Check if the PDU is destined for this node.
  • If not, look up the destination in the DFT.
  • If a next-hop is found, decrement the TTL and re-encapsulate the PDU with the new next-hop address.
  • If no entry is found, optionally fall back to flooding or drop the message.

Here is a simplified forwarding callback:

/* forwarding_engine.c */
#include "dft_manager.h"

int mesh_net_recv_cb(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) {
    /* Check if this is a directed forwarding PDU (e.g., bit 7 in TTL field) */
    if (rx->ttl & 0x80) {  /* Assume bit 7 indicates directed mode */
        uint16_t dst = rx->addr;
        struct dft_entry entry;

        /* If not for us, try to forward */
        if (dst != bt_mesh_primary_addr()) {
            if (dft_lookup(dst, &entry) == 0) {
                /* Forward to next-hop */
                struct bt_mesh_net_tx tx = {
                    .src = bt_mesh_primary_addr(),
                    .dst = entry.next_hop,
                    .ctx = &rx->ctx,
                };
                /* Decrement TTL and set directed flag */
                /* ... */
                bt_mesh_net_send(&tx, buf);
                return 0;  /* Packet consumed */
            } else {
                /* No route; drop or flood */
                return -ENOENT;
            }
        }
    }
    /* If not directed or for us, let the normal stack handle it */
    return 1;  /* Continue processing */
}

Performance Considerations and Optimization

Directed Forwarding significantly reduces the number of relayed packets. In a typical lighting network with 100 nodes, flooding would cause each message to be relayed by every node, resulting in up to 100 transmissions per message. With Directed Forwarding, only nodes along the path (typically 3-5 hops) relay the message, reducing radio activity by 90-95%.

However, the DFT maintenance overhead must be considered. DFD messages themselves consume bandwidth. To optimize, we can implement the following strategies:

  • Proactive Route Maintenance: Periodically refresh DFT entries for frequently used destinations before they expire.
  • Reactive Discovery: Only initiate DFD when a message needs to be sent and no route exists.
  • DFTAG Collision Avoidance: Use a 16-bit random number generated per path to minimize collisions.

On the Zephyr side, the implementation must be efficient to avoid blocking the network stack. Using a dedicated workqueue for DFT maintenance and DFD processing is recommended. The Silicon Labs SiBG301, with its Cortex-M33 core running at up to 80 MHz, provides ample compute for these operations while maintaining ultra-low power consumption.

Conclusion

Bluetooth Mesh 1.1 Directed Forwarding represents a significant leap forward in mesh networking efficiency. By implementing a custom Directed Forwarding engine on a Zephyr-based SoC, developers can unlock the full potential of this technology for applications such as advanced LED lighting and home automation, as highlighted by the Silicon Labs SiBG301 platform. The code examples provided give a starting point for building a DFT manager, DFD handler, and forwarding callback. As the Bluetooth SIG continues to refine the specification (with MMDL v1.1.1 being the latest), Directed Forwarding will become an indispensable tool for large-scale, low-power mesh networks.

For further reading, refer to the Mesh Protocol v1.1 specification and the Zephyr RTOS documentation on Bluetooth Mesh. The combination of a robust RTOS like Zephyr and a powerful SoC like the SiBG301 provides an ideal platform for deploying Directed Forwarding in production environments.

常见问题解答

问: What are the main advantages of using Directed Forwarding in Bluetooth Mesh 1.1 compared to the flooding approach in v1.0?

答: Directed Forwarding reduces network congestion and energy consumption by sending messages along specific paths instead of flooding the entire network. Only nodes on the directed path process and forward messages, which is critical for battery-powered devices and large-scale networks like lighting control systems.

问: How does the Directed Forwarding Table (DFT) work in a custom Directed Forwarding engine on Zephyr?

答: The DFT is a local table in each Directed Forwarding node that maps destination addresses to next-hop addresses. It is populated and maintained through Directed Forwarding Discovery (DFD), which uses route request (RREQ) and route reply (RREP) messages to establish paths. In a Zephyr-based SoC, you implement this table as a data structure in C code, updating it based on DFD procedures to enable efficient unicast routing.

问: What role does the Directed Forwarding Tag (DFTAG) play in preventing loops in the mesh network?

答: The DFTAG is a 16-bit identifier carried in the network PDU header that indicates a message uses directed forwarding. It helps prevent loops by uniquely identifying the path; nodes check the DFTAG to avoid forwarding the same message multiple times, ensuring efficient and loop-free routing along the established directed path.

问: How do you implement Directed Forwarding Discovery (DFD) in C code on a Zephyr-based SoC?

答: DFD is implemented by handling route request (RREQ) and route reply (RREP) messages in the custom engine. In C code on Zephyr, you write functions to parse incoming RREQ messages, update the DFT with potential routes, and generate RREP messages back to the path originator. This involves using Zephyr's Bluetooth Mesh APIs to send and receive network PDUs, and maintaining a state machine for route discovery.

问: What are the key challenges in implementing a custom Directed Forwarding engine on a constrained SoC like the Silicon Labs SiBG301?

答: Key challenges include managing memory for the DFT in resource-constrained environments, ensuring real-time processing of DFD messages without excessive latency, and optimizing power consumption to benefit battery life. The custom engine must be carefully designed in C to balance route maintenance overhead with the limited RAM and flash of the SoC, while leveraging Zephyr's RTOS features for efficient task scheduling and interrupt handling.

💬 欢迎到论坛参与讨论: 点击这里分享您的见解或提问

Login

Bluetoothchina Wechat Official Accounts

qrcode for gh 84b6e62cdd92 258