Support single-packet queueing in ND6 (similar to ARP), when

!LWIP_ND6_QUEUEING.
This commit is contained in:
Ivan Delamer 2012-03-22 11:14:49 -06:00
parent ac4c802089
commit 2b4c10e705
3 changed files with 43 additions and 24 deletions

View File

@ -185,13 +185,9 @@ ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr)
return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
} }
#if LWIP_ND6_QUEUEING
/* We should queue packet on this interface. */ /* We should queue packet on this interface. */
pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR); pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR);
return nd6_queue_packet(i, q); return nd6_queue_packet(i, q);
#else /* LWIP_ND6_QUEUEING */
return ERR_OK;
#endif /* LWIP_ND6_QUEUEING */
} }
#endif /* LWIP_IPV6 && LWIP_ETHERNET */ #endif /* LWIP_IPV6 && LWIP_ETHERNET */

View File

@ -102,8 +102,10 @@ static void nd6_send_rs(struct netif * netif);
#if LWIP_ND6_QUEUEING #if LWIP_ND6_QUEUEING
static void nd6_free_q(struct nd6_q_entry *q); static void nd6_free_q(struct nd6_q_entry *q);
static void nd6_send_q(s8_t i); #else /* LWIP_ND6_QUEUEING */
#define nd6_free_q(q) pbuf_free(q)
#endif /* LWIP_ND6_QUEUEING */ #endif /* LWIP_ND6_QUEUEING */
static void nd6_send_q(s8_t i);
/** /**
@ -236,12 +238,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
} }
neighbor_cache[i].state = ND6_REACHABLE; neighbor_cache[i].state = ND6_REACHABLE;
#if LWIP_ND6_QUEUEING
/* Send queued packets, if any. */ /* Send queued packets, if any. */
if (neighbor_cache[i].q != NULL) { if (neighbor_cache[i].q != NULL) {
nd6_send_q(i); nd6_send_q(i);
} }
#endif /* LWIP_ND6_QUEUEING */
} }
break; /* ICMP6_TYPE_NA */ break; /* ICMP6_TYPE_NA */
@ -639,12 +639,10 @@ nd6_tmr(void)
} }
break; break;
case ND6_REACHABLE: case ND6_REACHABLE:
#if LWIP_ND6_QUEUEING
/* Send queued packets, if any are left. Should have been sent already. */ /* Send queued packets, if any are left. Should have been sent already. */
if (neighbor_cache[i].q != NULL) { if (neighbor_cache[i].q != NULL) {
nd6_send_q(i); nd6_send_q(i);
} }
#endif /* LWIP_ND6_QUEUEING */
if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) {
/* Change to stale state. */ /* Change to stale state. */
neighbor_cache[i].state = ND6_STALE; neighbor_cache[i].state = ND6_STALE;
@ -1083,9 +1081,7 @@ nd6_new_neighbor_cache_entry(void)
j = -1; j = -1;
for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
if ( if (
#if LWIP_ND6_QUEUEING
(neighbor_cache[i].q == NULL) && (neighbor_cache[i].q == NULL) &&
#endif /* LWIP_ND6_QUEUEING */
(neighbor_cache[i].state == ND6_INCOMPLETE) && (neighbor_cache[i].state == ND6_INCOMPLETE) &&
(!neighbor_cache[i].isrouter)) { (!neighbor_cache[i].isrouter)) {
if (neighbor_cache[i].counter.probes_sent >= time) { if (neighbor_cache[i].counter.probes_sent >= time) {
@ -1100,7 +1096,6 @@ nd6_new_neighbor_cache_entry(void)
} }
/* Next, find oldest incomplete entry with queued packets. */ /* Next, find oldest incomplete entry with queued packets. */
#if LWIP_ND6_QUEUEING
time = 0; time = 0;
j = -1; j = -1;
for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
@ -1116,7 +1111,6 @@ nd6_new_neighbor_cache_entry(void)
nd6_free_neighbor_cache_entry(j); nd6_free_neighbor_cache_entry(j);
return j; return j;
} }
#endif /* LWIP_ND6_QUEUEING */
/* No more entries to try. */ /* No more entries to try. */
return -1; return -1;
@ -1135,13 +1129,11 @@ nd6_free_neighbor_cache_entry(s8_t i)
return; return;
} }
#if LWIP_ND6_QUEUEING
/* Free any queued packets. */ /* Free any queued packets. */
if (neighbor_cache[i].q != NULL) { if (neighbor_cache[i].q != NULL) {
nd6_free_q(neighbor_cache[i].q); nd6_free_q(neighbor_cache[i].q);
neighbor_cache[i].q = NULL; neighbor_cache[i].q = NULL;
} }
#endif /* LWIP_ND6_QUEUEING */
neighbor_cache[i].state = ND6_NO_ENTRY; neighbor_cache[i].state = ND6_NO_ENTRY;
neighbor_cache[i].isrouter = 0; neighbor_cache[i].isrouter = 0;
@ -1337,9 +1329,7 @@ nd6_new_router(ip6_addr_t * router_addr, struct netif * netif)
} }
ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr);
neighbor_cache[neighbor_index].netif = netif; neighbor_cache[neighbor_index].netif = netif;
#if LWIP_ND6_QUEUEING
neighbor_cache[neighbor_index].q = NULL; neighbor_cache[neighbor_index].q = NULL;
#endif /* LWIP_ND6_QUEUEING */
neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; neighbor_cache[neighbor_index].state = ND6_INCOMPLETE;
neighbor_cache[neighbor_index].counter.probes_sent = 0; neighbor_cache[neighbor_index].counter.probes_sent = 0;
} }
@ -1536,8 +1526,6 @@ nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif)
return nd6_cached_neighbor_index; return nd6_cached_neighbor_index;
} }
#if LWIP_ND6_QUEUEING
/** /**
* Queue a packet for a neighbor. * Queue a packet for a neighbor.
* *
@ -1551,7 +1539,9 @@ nd6_queue_packet(s8_t neighbor_index, struct pbuf * q)
err_t result = ERR_MEM; err_t result = ERR_MEM;
struct pbuf *p; struct pbuf *p;
int copy_needed = 0; int copy_needed = 0;
#if LWIP_ND6_QUEUEING
struct nd6_q_entry *new_entry, *r; struct nd6_q_entry *new_entry, *r;
#endif /* LWIP_ND6_QUEUEING */
if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) { if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) {
return ERR_ARG; return ERR_ARG;
@ -1573,10 +1563,15 @@ nd6_queue_packet(s8_t neighbor_index, struct pbuf * q)
p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM);
while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) {
/* Free oldest packet (as per RFC recommendation) */ /* Free oldest packet (as per RFC recommendation) */
#if LWIP_ND6_QUEUEING
r = neighbor_cache[neighbor_index].q; r = neighbor_cache[neighbor_index].q;
neighbor_cache[neighbor_index].q = r->next; neighbor_cache[neighbor_index].q = r->next;
r->next = NULL; r->next = NULL;
nd6_free_q(r); nd6_free_q(r);
#else /* LWIP_ND6_QUEUEING */
pbuf_free(neighbor_cache[neighbor_index].q);
neighbor_cache[neighbor_index].q = NULL;
#endif /* LWIP_ND6_QUEUEING */
p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM);
} }
if(p != NULL) { if(p != NULL) {
@ -1593,6 +1588,7 @@ nd6_queue_packet(s8_t neighbor_index, struct pbuf * q)
/* packet was copied/ref'd? */ /* packet was copied/ref'd? */
if (p != NULL) { if (p != NULL) {
/* queue packet ... */ /* queue packet ... */
#if LWIP_ND6_QUEUEING
/* allocate a new nd6 queue entry */ /* allocate a new nd6 queue entry */
new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE);
if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) {
@ -1617,14 +1613,23 @@ nd6_queue_packet(s8_t neighbor_index, struct pbuf * q)
/* queue did not exist, first item in queue */ /* queue did not exist, first item in queue */
neighbor_cache[neighbor_index].q = new_entry; neighbor_cache[neighbor_index].q = new_entry;
} }
LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)q, (s16_t)neighbor_index)); LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index));
result = ERR_OK; result = ERR_OK;
} else { } else {
/* the pool MEMP_ND6_QUEUE is empty */ /* the pool MEMP_ND6_QUEUE is empty */
pbuf_free(p); pbuf_free(p);
LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p));
/* { result == ERR_MEM } through initialization */ /* { result == ERR_MEM } through initialization */
} }
#else /* LWIP_ND6_QUEUEING */
/* Queue a single packet. If an older packet is already queued, free it as per RFC. */
if (neighbor_cache[neighbor_index].q != NULL) {
pbuf_free(neighbor_cache[neighbor_index].q);
}
neighbor_cache[neighbor_index].q = p;
LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index));
result = ERR_OK;
#endif /* LWIP_ND6_QUEUEING */
} else { } else {
LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q));
/* { result == ERR_MEM } through initialization */ /* { result == ERR_MEM } through initialization */
@ -1633,6 +1638,7 @@ nd6_queue_packet(s8_t neighbor_index, struct pbuf * q)
return result; return result;
} }
#if LWIP_ND6_QUEUEING
/** /**
* Free a complete queue of nd6 q entries * Free a complete queue of nd6 q entries
* *
@ -1652,6 +1658,7 @@ nd6_free_q(struct nd6_q_entry *q)
memp_free(MEMP_ND6_QUEUE, r); memp_free(MEMP_ND6_QUEUE, r);
} }
} }
#endif /* LWIP_ND6_QUEUEING */
/** /**
* Send queued packets for a neighbor * Send queued packets for a neighbor
@ -1662,12 +1669,15 @@ static void
nd6_send_q(s8_t i) nd6_send_q(s8_t i)
{ {
struct ip6_hdr *ip6hdr; struct ip6_hdr *ip6hdr;
#if LWIP_ND6_QUEUEING
struct nd6_q_entry *q; struct nd6_q_entry *q;
#endif /* LWIP_ND6_QUEUEING */
if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) {
return; return;
} }
#if LWIP_ND6_QUEUEING
while (neighbor_cache[i].q != NULL) { while (neighbor_cache[i].q != NULL) {
/* remember first in queue */ /* remember first in queue */
q = neighbor_cache[i].q; q = neighbor_cache[i].q;
@ -1684,9 +1694,21 @@ nd6_send_q(s8_t i)
/* now queue entry can be freed */ /* now queue entry can be freed */
memp_free(MEMP_ND6_QUEUE, q); memp_free(MEMP_ND6_QUEUE, q);
} }
#else /* LWIP_ND6_QUEUEING */
if (neighbor_cache[i].q != NULL) {
/* Get ipv6 header. */
ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload);
/* Override ip6_current_dest_addr() so that we have an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest));
/* send the queued IPv6 packet */
(neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, ip6_current_dest_addr());
/* free the queued IP packet */
pbuf_free(neighbor_cache[i].q);
neighbor_cache[i].q = NULL;
}
#endif /* LWIP_ND6_QUEUEING */
} }
#endif /* LWIP_ND6_QUEUEING */
/** /**
* Get the Path MTU for a destination. * Get the Path MTU for a destination.

View File

@ -67,6 +67,9 @@ struct nd6_neighbor_cache_entry {
#if LWIP_ND6_QUEUEING #if LWIP_ND6_QUEUEING
/** Pointer to queue of pending outgoing packets on this entry. */ /** Pointer to queue of pending outgoing packets on this entry. */
struct nd6_q_entry *q; struct nd6_q_entry *q;
#else /* LWIP_ND6_QUEUEING */
/** Pointer to a single pending outgoing packet on this entry. */
struct pbuf *q;
#endif /* LWIP_ND6_QUEUEING */ #endif /* LWIP_ND6_QUEUEING */
u8_t state; u8_t state;
u8_t isrouter; u8_t isrouter;
@ -352,9 +355,7 @@ void nd6_input(struct pbuf *p, struct netif *inp);
s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif); s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif);
s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif); s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif);
u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif); u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif);
#if LWIP_ND6_QUEUEING
err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p); err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p);
#endif /* LWIP_ND6_QUEUEING */
#if LWIP_ND6_TCP_REACHABILITY_HINTS #if LWIP_ND6_TCP_REACHABILITY_HINTS
void nd6_reachability_hint(ip6_addr_t * ip6addr); void nd6_reachability_hint(ip6_addr_t * ip6addr);
#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */