From 1061ce302a9bc046d2df68b6c59ad75d1ce56fa0 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 16 Mar 2017 12:30:51 +0200 Subject: [PATCH] net: route: Try to route IPv6 packet if we are not the recipient Instead of simply dropping the packet if the destination IPv6 address is not ours, try to figure out if there is a route to real destination and then re-route the IPv6 packet there. Change-Id: I6b2a0d7096b3d7877b82b04f38e3a6e588587c11 Signed-off-by: Jukka Rissanen --- include/net/nbuf.h | 21 ++++++++++++++++ subsys/net/ip/ipv6.c | 8 ++++++ subsys/net/ip/net_core.c | 24 +++++++++++++++++- subsys/net/ip/route.c | 54 ++++++++++++++++++++++++++++++++++++++++ subsys/net/ip/route.h | 25 +++++++++++++++++++ 5 files changed, 131 insertions(+), 1 deletion(-) diff --git a/include/net/nbuf.h b/include/net/nbuf.h index 0f86b342301d5e..1e9799563d196f 100644 --- a/include/net/nbuf.h +++ b/include/net/nbuf.h @@ -76,6 +76,10 @@ struct net_nbuf { #if defined(CONFIG_NET_TCP) bool buf_sent; /* Is this net_buf sent or not */ #endif + +#if defined(CONFIG_NET_ROUTE) + bool forwarding; /* Are we forwarding this buf */ +#endif /* @endcond */ }; @@ -218,6 +222,23 @@ static inline void net_nbuf_set_buf_sent(struct net_buf *buf, bool sent) } #endif +#if defined(CONFIG_NET_ROUTE) +static inline bool net_nbuf_forwarding(struct net_buf *buf) +{ + return ((struct net_nbuf *)net_buf_user_data(buf))->forwarding; +} + +static inline void net_nbuf_set_forwarding(struct net_buf *buf, bool forward) +{ + ((struct net_nbuf *)net_buf_user_data(buf))->forwarding = forward; +} +#else +static inline bool net_nbuf_forwarding(struct net_buf *buf) +{ + return false; +} +#endif + static inline uint16_t net_nbuf_get_len(struct net_buf *buf) { return buf->len; diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 579a74b28bd8af..eba431cd9f5460 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -621,6 +621,14 @@ static struct net_buf *update_ll_reserve(struct net_buf *buf, uint16_t reserve, room_len, copy_len, pos; struct net_buf *orig_frag, *frag; + /* No need to do anything if we are forwarding the packet + * as we already know everything about the destination of + * the packet. + */ + if (net_nbuf_forwarding(buf)) { + return buf; + } + reserve = net_if_get_ll_reserve(net_nbuf_iface(buf), addr); if (reserve == net_nbuf_ll_reserve(buf)) { return buf; diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 6fa3abd03f1e53..5411e410176087 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -258,7 +258,29 @@ static inline enum net_verdict process_ipv6_pkt(struct net_buf *buf) !net_is_my_ipv6_maddr(&hdr->dst) && !net_is_ipv6_addr_mcast(&hdr->dst) && !net_is_ipv6_addr_loopback(&hdr->dst)) { - NET_DBG("IPv6 packet in buf %p not for me", buf); +#if defined(CONFIG_NET_ROUTE) + struct net_route_entry *route; + struct in6_addr *nexthop; + + /* Check if the packet can be routed */ + if (net_route_get_info(&hdr->dst, &route, &nexthop)) { + int ret; + + ret = net_route_packet(buf, route, nexthop); + if (ret < 0) { + NET_DBG("Cannot re-route buf %p via %s (%d)", + buf, net_sprint_ipv6_addr(nexthop), + ret); + } else { + return NET_OK; + } + } else +#endif /* CONFIG_NET_ROUTE */ + + { + NET_DBG("IPv6 packet in buf %p not for me", buf); + } + net_stats_update_ipv6_drop(); goto drop; } diff --git a/subsys/net/ip/route.c b/subsys/net/ip/route.c index 7e727f070eab32..a8ad6e3deea513 100644 --- a/subsys/net/ip/route.c +++ b/subsys/net/ip/route.c @@ -671,6 +671,60 @@ net_route_mcast_lookup(struct in6_addr *group) } #endif /* CONFIG_NET_ROUTE_MCAST */ +bool net_route_get_info(struct in6_addr *dst, + struct net_route_entry **route, + struct in6_addr **nexthop) +{ + *route = net_route_lookup(NULL, dst); + if (*route) { + *nexthop = net_route_get_nexthop(*route); + if (!*nexthop) { + return false; + } + + return true; + } + + return false; +} + +int net_route_packet(struct net_buf *buf, struct net_route_entry *route, + struct in6_addr *nexthop) +{ + struct net_linkaddr_storage *lladdr; + struct net_nbr *nbr; + + nbr = net_ipv6_nbr_lookup(route->iface, nexthop); + if (!nbr) { + NET_DBG("Cannot find %s neighbor.", + net_sprint_ipv6_addr(nexthop)); + return -ENOENT; + } + + lladdr = net_nbr_get_lladdr(nbr->idx); + if (!lladdr) { + NET_DBG("Cannot find %s neighbor link layer address.", + net_sprint_ipv6_addr(nexthop)); + return -ESRCH; + } + + net_nbuf_set_iface(buf, route->iface); + net_nbuf_set_forwarding(buf, true); + + /* Set the destination and source ll address in the packet. + * We set the destination address to be the nexthop recipient. + */ + net_nbuf_ll_src(buf)->addr = net_nbuf_ll_if(buf)->addr; + net_nbuf_ll_src(buf)->type = net_nbuf_ll_if(buf)->type; + net_nbuf_ll_src(buf)->len = net_nbuf_ll_if(buf)->len; + + net_nbuf_ll_dst(buf)->addr = lladdr->addr; + net_nbuf_ll_dst(buf)->type = lladdr->type; + net_nbuf_ll_dst(buf)->len = lladdr->len; + + return net_send_data(buf); +} + void net_route_init(void) { NET_DBG("Allocated %d routing entries (%zu bytes)", diff --git a/subsys/net/ip/route.h b/subsys/net/ip/route.h index c9a6d3f814d486..d5568dc5a1f966 100644 --- a/subsys/net/ip/route.h +++ b/subsys/net/ip/route.h @@ -233,6 +233,31 @@ net_route_mcast_lookup(struct in6_addr *group); #endif /* CONFIG_NET_ROUTE_MCAST */ +/** + * @brief Return a route to destination via some intermediate host. + * + * @param dst Destination IPv6 address + * @param route Route entry to destination is returned. + * @param nexthop Next hop neighbor IPv6 address is returned. + * + * @return True if there is a route to the destination, False otherwise + */ +bool net_route_get_info(struct in6_addr *dst, + struct net_route_entry **route, + struct in6_addr **nexthop); + +/** + * @brief Send the network packet to network via some intermediate host. + * + * @param buf Network buffer to send. + * @param route Route entry to destination. + * @param nexthop Next hop neighbor IPv6 address. + * + * @return 0 if there was no error, <0 if the packet could not be sent. + */ +int net_route_packet(struct net_buf *buf, struct net_route_entry *route, + struct in6_addr *nexthop); + #else /* CONFIG_NET_ROUTE */ #define net_route_init(...) #endif /* CONFIG_NET_ROUTE */