Skip to content

Commit

Permalink
Feature to auto add on-mesh prefixes as interface route (#438)
Browse files Browse the repository at this point in the history
This commit adds a new feature in `wpantund` to auto add a route on
the host primary interface corresponding to on-mesh prefixes from
Thread network.

This feature can be enabled through a newly added wpan property with
name "Daemon:OnMeshPrefix:AutoAddAsIntterfaceRoute" which is enabled
by default.

When enabled, wpantund would add a route on host primary interface for
any prefix from thread network (with on-mesh flag set). This in turn
ensures that traffic destined to an IPv6 address matching the prefix
would be correctly forwarded to the `wpan` interface on host.
  • Loading branch information
abtink authored Oct 9, 2019
1 parent 5f7a39d commit 32b29ce
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 53 deletions.
148 changes: 95 additions & 53 deletions src/wpantund/NCPInstanceBase-Addresses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,11 @@ NCPInstanceBase::on_mesh_prefix_was_added(Origin origin, const struct in6_addr &
} else {
cb(kWPANTUNDStatus_Ok);
}

if (mAutoAddOnMeshPrefixesAsInterfaceRoutes) {
mRequestRouteRefresh = true;
}

} else {
cb(kWPANTUNDStatus_Ok);
}
Expand Down Expand Up @@ -967,6 +972,10 @@ NCPInstanceBase::on_mesh_prefix_was_removed(Origin origin, const struct in6_addr
cb(kWPANTUNDStatus_Ok);
}

if (mAutoAddOnMeshPrefixesAsInterfaceRoutes) {
mRequestRouteRefresh = true;
}

if (entry.is_on_mesh() && entry.is_slaac() && prefix.get_length() == kSLAACPrefixLength
&& !has_slaac_on_mesh_prefix(prefix)
) {
Expand Down Expand Up @@ -1076,68 +1085,88 @@ bool
NCPInstanceBase::should_add_route_on_interface(const IPv6Prefix &route, uint32_t &metric)
{
bool should_add = false;
bool route_added_by_device = false;
bool route_added_by_others = false;
RoutePreference preference_device = NCPControlInterface::ROUTE_LOW_PREFRENCE;
RoutePreference preference_others = NCPControlInterface::ROUTE_LOW_PREFRENCE;

std::multimap<IPv6Prefix, OffMeshRouteEntry>::iterator iter, sub_iter, upper_iter;
if (mAutoAddOffMeshRoutesOnInterface) {
bool route_added_by_device = false;
bool route_added_by_others = false;
RoutePreference preference_device = NCPControlInterface::ROUTE_LOW_PREFRENCE;
RoutePreference preference_others = NCPControlInterface::ROUTE_LOW_PREFRENCE;

for (iter = mOffMeshRoutes.begin(); iter != mOffMeshRoutes.end(); iter = upper_iter) {
std::multimap<IPv6Prefix, OffMeshRouteEntry>::iterator iter, sub_iter, upper_iter;

// Get the iterator pointing to the first element that is greater than current key/route.
upper_iter = mOffMeshRoutes.upper_bound(iter->first);
for (iter = mOffMeshRoutes.begin(); iter != mOffMeshRoutes.end(); iter = upper_iter) {

// Skip all elements for which the multimap key does not match the route.
if (iter->first != route) {
continue;
}
// Get the iterator pointing to the first element that is greater than current key/route.
upper_iter = mOffMeshRoutes.upper_bound(iter->first);

// Iterate through all multimap elements with same key (i.e., same route).
for (sub_iter = iter; sub_iter != upper_iter; ++sub_iter) {
// Skip all elements for which the multimap key does not match the route.
if (iter->first != route) {
continue;
}

if ((sub_iter->second.get_origin() != kOriginThreadNCP) || sub_iter->second.is_next_hop_host()) {
route_added_by_device = true;
if (preference_device < sub_iter->second.get_preference()) {
preference_device = sub_iter->second.get_preference();
}
} else {
route_added_by_others = true;
if (preference_others < sub_iter->second.get_preference()) {
preference_others = sub_iter->second.get_preference();
// Iterate through all multimap elements with same key (i.e., same route).
for (sub_iter = iter; sub_iter != upper_iter; ++sub_iter) {

if ((sub_iter->second.get_origin() != kOriginThreadNCP) || sub_iter->second.is_next_hop_host()) {
route_added_by_device = true;
if (preference_device < sub_iter->second.get_preference()) {
preference_device = sub_iter->second.get_preference();
}
} else {
route_added_by_others = true;
if (preference_others < sub_iter->second.get_preference()) {
preference_others = sub_iter->second.get_preference();
}
}
}
}
}

// The route should be added on host primary interface, if it
// is added by at least one other device within the network and,
// (a) either it is not added by host/this-device, or
// (b) if it is also added by device then
// - filtering of self added routes is not enabled, and
// - it is added at lower preference level.
// The route should be added on host primary interface, if it
// is added by at least one other device within the network and,
// (a) either it is not added by host/this-device, or
// (b) if it is also added by device then
// - filtering of self added routes is not enabled, and
// - it is added at lower preference level.

if (route_added_by_others) {
if (!route_added_by_device || (!mFilterSelfAutoAddedOffMeshRoutes && (preference_others > preference_device))) {
should_add = true;
}
}

// If the route should be added, map the preference level to route metric.

if (route_added_by_others) {
if (!route_added_by_device || (!mFilterSelfAutoAddedOffMeshRoutes && (preference_others > preference_device))) {
should_add = true;
if (should_add) {
switch (preference_others) {
case NCPControlInterface::ROUTE_LOW_PREFRENCE:
metric = InterfaceRouteEntry::kRouteMetricLow;
break;

case NCPControlInterface::ROUTE_MEDIUM_PREFERENCE:
metric = InterfaceRouteEntry::kRouteMetricMedium;
break;

case NCPControlInterface::ROUTE_HIGH_PREFERENCE:
metric = InterfaceRouteEntry::kRouteMetricHigh;
break;
}
}
}

// If the route should be added, map the preference level to route metric.
if (!should_add && mAutoAddOnMeshPrefixesAsInterfaceRoutes) {

if (should_add) {
switch (preference_others) {
case NCPControlInterface::ROUTE_LOW_PREFRENCE:
metric = InterfaceRouteEntry::kRouteMetricLow;
break;
// If the "AutoAddOnMeshPrefixesAsInterfaceRoutes" feature is enabled
// check whether the route matches any of on-mesh prefixes from NCP
// (with on-mesh flag set).

case NCPControlInterface::ROUTE_MEDIUM_PREFERENCE:
metric = InterfaceRouteEntry::kRouteMetricMedium;
break;
std::multimap<IPv6Prefix, OnMeshPrefixEntry>::iterator iter;

case NCPControlInterface::ROUTE_HIGH_PREFERENCE:
metric = InterfaceRouteEntry::kRouteMetricHigh;
break;
for (iter = mOnMeshPrefixes.begin(); iter != mOnMeshPrefixes.end(); iter++) {
if ((iter->first == route) && iter->second.is_from_ncp() && iter->second.is_on_mesh()) {
should_add = true;
metric = InterfaceRouteEntry::kRouteMetricMedium;
break;
}
}
}

Expand All @@ -1150,12 +1179,10 @@ NCPInstanceBase::refresh_routes_on_interface(void)
bool did_remove = false;
uint32_t metric;

if (!mAutoAddOffMeshRoutesOnInterface) {
goto bail;
if (mAutoAddOffMeshRoutesOnInterface || mAutoAddOnMeshPrefixesAsInterfaceRoutes) {
syslog(LOG_INFO, "Refreshing routes on primary interface");
}

syslog(LOG_INFO, "Refreshing routes on primary interface");

// First, check all currently added routes on primary interface and remove any one that is no longer valid.

do {
Expand Down Expand Up @@ -1187,9 +1214,9 @@ NCPInstanceBase::refresh_routes_on_interface(void)
}
} while (did_remove);

// Iterate through all off-mesh route entries to check if there is a new route that should be added on interface.
if (mAutoAddOffMeshRoutesOnInterface) {
// Iterate through all off-mesh routes to check whether a new route should be added on interface.

{
std::multimap<IPv6Prefix, OffMeshRouteEntry>::iterator iter, upper_iter;

for (iter = mOffMeshRoutes.begin(); iter != mOffMeshRoutes.end(); iter = upper_iter) {
Expand All @@ -1207,8 +1234,23 @@ NCPInstanceBase::refresh_routes_on_interface(void)
}
}

bail:
return;
if (mAutoAddOnMeshPrefixesAsInterfaceRoutes) {
// Iterate through all on-mesh prefixes to check whether a new route should be added on interface.

std::multimap<IPv6Prefix, OnMeshPrefixEntry>::iterator iter;

for (iter = mOnMeshPrefixes.begin(); iter != mOnMeshPrefixes.end(); iter++) {

if (should_add_route_on_interface(iter->first, metric)
&& (mInterfaceRoutes.count(iter->first) == 0)
) {
syslog(LOG_INFO, "InterfaceRoutes: Adding route for prefix %s",
iter->second.get_description(iter->first).c_str());
mPrimaryInterface->add_route(&iter->first.get_prefix(), iter->first.get_length(), metric);
mInterfaceRoutes[iter->first] = InterfaceRouteEntry(metric);
}
}
}
}

// ========================================================================
Expand Down
16 changes: 16 additions & 0 deletions src/wpantund/NCPInstanceBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ NCPInstanceBase::NCPInstanceBase(const Settings& settings):
mSetSLAACForAutoAddedPrefix = false;
mAutoAddOffMeshRoutesOnInterface = true;
mFilterSelfAutoAddedOffMeshRoutes = true;
mAutoAddOnMeshPrefixesAsInterfaceRoutes = true;
mTerminateOnFault = false;
mWasBusy = false;
mNCPIsMisbehaving = false;
Expand Down Expand Up @@ -389,6 +390,7 @@ NCPInstanceBase::regsiter_all_get_handlers(void)
REGISTER_GET_HANDLER(IPv6SetSLAACForAutoAddedPrefix);
REGISTER_GET_HANDLER(DaemonOffMeshRouteAutoAddOnInterface);
REGISTER_GET_HANDLER(DaemonOffMeshRouteFilterSelfAutoAdded);
REGISTER_GET_HANDLER(DaemonOnMeshPrefixAutoAddAsIfaceRoute);
REGISTER_GET_HANDLER(IPv6MeshLocalPrefix);
REGISTER_GET_HANDLER(IPv6MeshLocalAddress);
REGISTER_GET_HANDLER(IPv6LinkLocalAddress);
Expand Down Expand Up @@ -608,6 +610,12 @@ NCPInstanceBase::get_prop_DaemonOffMeshRouteFilterSelfAutoAdded(CallbackWithStat
cb(kWPANTUNDStatus_Ok, boost::any(mFilterSelfAutoAddedOffMeshRoutes));
}

void
NCPInstanceBase::get_prop_DaemonOnMeshPrefixAutoAddAsIfaceRoute(CallbackWithStatusArg1 cb)
{
cb(kWPANTUNDStatus_Ok, boost::any(mAutoAddOnMeshPrefixesAsInterfaceRoutes));
}

void
NCPInstanceBase::get_prop_IPv6MeshLocalPrefix(CallbackWithStatusArg1 cb)
{
Expand Down Expand Up @@ -841,6 +849,7 @@ NCPInstanceBase::regsiter_all_set_handlers(void)
REGISTER_SET_HANDLER(IPv6SetSLAACForAutoAddedPrefix);
REGISTER_SET_HANDLER(DaemonOffMeshRouteAutoAddOnInterface);
REGISTER_SET_HANDLER(DaemonOffMeshRouteFilterSelfAutoAdded);
REGISTER_SET_HANDLER(DaemonOnMeshPrefixAutoAddAsIfaceRoute);
REGISTER_SET_HANDLER(IPv6MeshLocalPrefix);
REGISTER_SET_HANDLER(IPv6MeshLocalAddress);
REGISTER_SET_HANDLER(DaemonAutoDeepSleep);
Expand Down Expand Up @@ -1009,6 +1018,13 @@ NCPInstanceBase::set_prop_DaemonOffMeshRouteFilterSelfAutoAdded(const boost::any
cb(kWPANTUNDStatus_Ok);
}

void
NCPInstanceBase::set_prop_DaemonOnMeshPrefixAutoAddAsIfaceRoute(const boost::any &value, CallbackWithStatus cb)
{
mAutoAddOnMeshPrefixesAsInterfaceRoutes = any_to_bool(value);
cb(kWPANTUNDStatus_Ok);
}

void
NCPInstanceBase::set_prop_IPv6MeshLocalPrefix(const boost::any &value, CallbackWithStatus cb)
{
Expand Down
14 changes: 14 additions & 0 deletions src/wpantund/NCPInstanceBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ class NCPInstanceBase : public NCPInstance, public EventHandler {
void get_prop_IPv6SetSLAACForAutoAddedPrefix(CallbackWithStatusArg1 cb);
void get_prop_DaemonOffMeshRouteAutoAddOnInterface(CallbackWithStatusArg1 cb);
void get_prop_DaemonOffMeshRouteFilterSelfAutoAdded(CallbackWithStatusArg1 cb);
void get_prop_DaemonOnMeshPrefixAutoAddAsIfaceRoute(CallbackWithStatusArg1 cb);
void get_prop_IPv6MeshLocalPrefix(CallbackWithStatusArg1 cb);
void get_prop_IPv6MeshLocalAddress(CallbackWithStatusArg1 cb);
void get_prop_IPv6LinkLocalAddress(CallbackWithStatusArg1 cb);
Expand Down Expand Up @@ -379,6 +380,7 @@ class NCPInstanceBase : public NCPInstance, public EventHandler {
void set_prop_IPv6SetSLAACForAutoAddedPrefix(const boost::any &value, CallbackWithStatus cb);
void set_prop_DaemonOffMeshRouteAutoAddOnInterface(const boost::any &value, CallbackWithStatus cb);
void set_prop_DaemonOffMeshRouteFilterSelfAutoAdded(const boost::any &value, CallbackWithStatus cb);
void set_prop_DaemonOnMeshPrefixAutoAddAsIfaceRoute(const boost::any &value, CallbackWithStatus cb);
void set_prop_IPv6MeshLocalPrefix(const boost::any &value, CallbackWithStatus cb);
void set_prop_IPv6MeshLocalAddress(const boost::any &value, CallbackWithStatus cb);
void set_prop_DaemonAutoDeepSleep(const boost::any &value, CallbackWithStatus cb);
Expand Down Expand Up @@ -735,6 +737,18 @@ class NCPInstanceBase : public NCPInstance, public EventHandler {
//
bool mFilterSelfAutoAddedOffMeshRoutes;

// This boolean flag indicates whether wpantund should add routes corresponding
// to on-mesh prefixes on the host interface.
//
// When enabled, wpantund would add a route on host primary interface for any
// prefix from thread network (with on-mesh flag set). This in turn ensures that
// traffic destined to an IPv6 address matching the prefix would be correctly
// forwarded to the wpan interface.
//
// By default this is enabled (`true`).
//
bool mAutoAddOnMeshPrefixesAsInterfaceRoutes;

private:
NCPState mNCPState;
bool mIsInitializingNCP;
Expand Down
1 change: 1 addition & 0 deletions src/wpantund/wpan-properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#define kWPANTUNDProperty_DaemonSetDefRouteForAutoAddedPrefix "Daemon:SetDefaultRouteForAutoAddedPrefix"
#define kWPANTUNDProperty_DaemonOffMeshRouteAutoAddOnInterface "Daemon:OffMeshRoute:AutoAddOnInterface"
#define kWPANTUNDProperty_DaemonOffMeshRouteFilterSelfAutoAdded "Daemon:OffMeshRoute:FilterSelfAutoAdded"
#define kWPANTUNDProperty_DaemonOnMeshPrefixAutoAddAsIfaceRoute "Daemon:OnMeshPrefix:AutoAddAsInterfaceRoute"

#define kWPANTUNDProperty_NCPVersion "NCP:Version"
#define kWPANTUNDProperty_NCPState "NCP:State"
Expand Down

0 comments on commit 32b29ce

Please sign in to comment.