中级会员
 
- 积分
- 229
- 金钱
- 229
- 注册时间
- 2014-3-14
- 在线时间
- 40 小时
|
5金钱
最近在看llwip基于arp部分实现源码,想咨询下LWIP关于其ip数据包发送局域网外单播包的一点疑惑?就是lwip如果发现是非本地单播包会将发送的目的ip改为网关ip,那么我的疑惑是发给网关之后,那么网关是怎么知道数据是要发给谁的?小弟拜谢了
//ip层包的发送是借助etharp_output()接口实现,单播包会调用etharp_query()给指定的ip地址处发送ip数据包或arp请求,下面是etharp_output()部分代码
err_t
etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
{
struct eth_addr *dest;
struct eth_addr mcastaddr;
ip_addr_t *dst_addr = ipaddr;
LWIP_ASSERT("netif != NULL", netif != NULL);
LWIP_ASSERT("q != NULL", q != NULL);
LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL);
/* make room for Ethernet header - should not fail */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
/* bail out */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
("etharp_output: could not allocate room for header.\n"));
LINK_STATS_INC(link.lenerr);
return ERR_BUF;
}
/* Determine on destination hardware address. Broadcasts and multicasts
* are special, other IP addresses are looked up in the ARP table. */
/* broadcast destination IP address? */
if (ip_addr_isbroadcast(ipaddr, netif)) {
/* broadcast on Ethernet also */
dest = (struct eth_addr *)ðbroadcast;
/* multicast destination IP address? */
} else if (ip_addr_ismulticast(ipaddr)) {
/* Hash IP multicast address to MAC address.*/
mcastaddr.addr[0] = LL_MULTICAST_ADDR_0;
mcastaddr.addr[1] = LL_MULTICAST_ADDR_1;
mcastaddr.addr[2] = LL_MULTICAST_ADDR_2;
mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
mcastaddr.addr[4] = ip4_addr3(ipaddr);
mcastaddr.addr[5] = ip4_addr4(ipaddr);
/* destination Ethernet address is multicast */
dest = &mcastaddr;
/* unicast destination IP address? */
} else {
s8_t i;
/* outside local network? if so, this can neither be a global broadcast nor
a subnet broadcast. */
if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
!ip_addr_islinklocal(ipaddr)) {
#if LWIP_AUTOIP
struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload +
sizeof(struct eth_hdr));
/* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with
a link-local source address must always be "directly to its destination
on the same physical link. The host MUST NOT send the packet to any
router for forwarding". */
if (!ip_addr_islinklocal(&iphdr->src))
#endif /* LWIP_AUTOIP */
{
/* interface has default gateway? */
if (!ip_addr_isany(&netif->gw)) {
/* send to hardware address of default gateway IP address */
dst_addr = &(netif->gw); //这部分将i局域网外目的ip地址设置为网关ip,
/* no default gateway available */
} else {
/* no route to destination error (default gateway missing) */
return ERR_RTE;
}
}
}
#if LWIP_NETIF_HWADDRHINT
if (netif->addr_hint != NULL) {
/* per-pcb cached entry was given */
u8_t etharp_cached_entry = *(netif->addr_hint);
if (etharp_cached_entry < ARP_TABLE_SIZE) {
#endif /* LWIP_NETIF_HWADDRHINT */
if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
(ip_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) {
/* the per-pcb-cached entry is stable and the right one! */
ETHARP_STATS_INC(etharp.cachehit);
return etharp_output_to_arp_index(netif, q, etharp_cached_entry);
}
#if LWIP_NETIF_HWADDRHINT
}
}
#endif /* LWIP_NETIF_HWADDRHINT */
/* find stable entry: do this here since this is a critical path for
throughput and etharp_find_entry() is kind of slow */
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if ((arp_table.state >= ETHARP_STATE_STABLE) &&
(ip_addr_cmp(dst_addr, &arp_table.ipaddr))) {
/* found an existing, stable entry */
ETHARP_SET_HINT(netif, i);
return etharp_output_to_arp_index(netif, q, i);
}
}
/* no stable entry found, use the (slower) query function:
queue on destination Ethernet address belonging to ipaddr */
return etharp_query(netif, dst_addr, q); //单播包会调用etharp_query()实现单播包发送,那么网关怎么知道收到的数据包是发给谁的?如何转发的呢?
}
/* continuation for multicast/broadcast destinations */
/* obtain source Ethernet address of the given interface */
/* send packet directly on the link */
return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest);
}
|
最佳答案
查看完整内容[请看2#楼]
看懂了,是这样的,如果ip包发现发送的数据是局域网外的数据包,那么ip包会先查询网卡mac是否在缓存表中,没有,则发送arp请求,并将要发送到局域网外的数据包挂到arp缓存队列中。数据包的数据ip信息并没有修改,只是发送的目的是网关。当收到网关的arp应答后,etharp_uodate_entry()接口会将缓存队列的数据包发给网卡,整个过程中数据包并未发生改变。
|