由于项目需要多通讯口,查阅资料发现lwip支持多网口操作。于是,就开搞了。
利用xemac_add函数在网卡链表中添加一个网卡,即使用netif块重复xemac_add操作。
先用轮询的方式实现双网口,后期修改为中断模式
导入官方例程LWip echo server, 修改main函数,增加一个netif块
#if LWIP_IPV6==0
#if LWIP_DHCP==1
extern volatile int dhcp_timoutcntr;
extern volatile int dhcp_timoutcntr1;
err_t dhcp_start(struct netif *netif);
#endif
#endif
extern volatile int TcpFastTmrFlag;
extern volatile int TcpSlowTmrFlag;
extern volatile int TcpFastTmrFlag1;
extern volatile int TcpSlowTmrFlag1;
static struct netif server_netif;
struct netif *echo_netif;
static struct netif server_netif1;
struct netif *echo_netif1;
int main()
{
#if LWIP_IPV6==0
ip_addr_t ipaddr, netmask, gw;
ip_addr_t ipaddr1, netmask1, gw1;
#endif
/* the mac address of the board. this should be unique per board */
unsigned char mac_ethernet_address[] =
{ 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
unsigned char mac_ethernet_address1[] =
{ 0x00, 0x0a, 0x35, 0x00, 0x01, 0x03 };
echo_netif = &server_netif;
#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
ProgramSi5324();
ProgramSfpPhy();
#endif
#endif
/* Define this board specific macro in order perform PHY reset on ZCU102 */
#ifdef XPS_BOARD_ZCU102
if(IicPhyReset()) {
xil_printf("Error performing PHY reset \n\r");
return -1;
}
#endif
// init_platform();
//官方例程使用的定时器是私有scutimer定时器,我将其更改为TTL定时器TTL0,后续的网口1则使用TTL1
platform_setup_timer0();//TTL定时器0配置以及使能中断
#if LWIP_IPV6==0
#if LWIP_DHCP==1
ipaddr.addr = 0;
gw.addr = 0;
netmask.addr = 0;
ipaddr1.addr = 0;
gw1.addr = 0;
netmask1.addr = 0;
#else
/* initliaze IP addresses to be used */
IP4_ADDR(&ipaddr, 192, 168, 1, 10);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 192, 168, 1, 1);
#endif
#endif
print_app_header();
lwip_init();
#if (LWIP_IPV6 == 0)
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(echo_netif, &ipaddr, &netmask,
&gw, mac_ethernet_address,
PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\n\r");
return -1;
}
#else
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(echo_netif, NULL, NULL, NULL, mac_ethernet_address,
PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\n\r");
return -1;
}
echo_netif->ip6_autoconfig_enabled = 1;
netif_create_ip6_linklocal_address(echo_netif, 1);
netif_ip6_addr_set_state(echo_netif, 0, IP6_ADDR_VALID);
print_ip6("\n\rBoard IPv6 address ", &echo_netif->ip6_addr[0].u_addr.ip6);
#endif
netif_set_default(echo_netif);
/* specify that the network if is up */
netif_set_up(echo_netif);
#if (LWIP_IPV6 == 0)
#if (LWIP_DHCP==1)
/* Create a new DHCP client for this interface.
* Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
* the predefined regular intervals after starting the client.
*/
dhcp_start(echo_netif);
dhcp_timoutcntr = 24;
while(((echo_netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
xemacif_input(echo_netif);
if (dhcp_timoutcntr <= 0) {
if ((echo_netif->ip_addr.addr) == 0) {
xil_printf("DHCP Timeout\r\n");
xil_printf("Configuring default IP of 192.168.1.33\r\n");
IP4_ADDR(&(echo_netif->ip_addr), 192, 168, 1, 33);
IP4_ADDR(&(echo_netif->netmask), 255, 255, 255, 15);
IP4_ADDR(&(echo_netif->gw), 192, 168, 1, 1);
}
}
ipaddr.addr = echo_netif->ip_addr.addr;
gw.addr = echo_netif->gw.addr;
netmask.addr = echo_netif->netmask.addr;
#endif
print_ip_settings(&ipaddr, &netmask, &gw);
#endif
/**< 重复操作,创建netif1块,此处写入网卡1地址XPAR_XEMACPS_1_BASEADDR*/
echo_netif1 = &server_netif1;
if (!xemac_add(echo_netif1, &ipaddr1, &netmask1,
&gw1, mac_ethernet_address1,
XPAR_XEMACPS_1_BASEADDR)) {
return -1;
}
netif_set_up(echo_netif1);
//platform_enable_interrupts();
platform_setup_timer1();//TTL定时器1
dhcp_start(echo_netif1);
dhcp_timoutcntr1 = 24;
while(((echo_netif1->ip_addr.addr) == 0) && (dhcp_timoutcntr1 > 0))
xemacif_input(echo_netif1);
if (dhcp_timoutcntr1 <= 0) {
if ((echo_netif1->ip_addr.addr) == 0) {
xil_printf("DHCP Timeout\r\n");
xil_printf("Configuring default IP of 192.168.1.10\r\n");
IP4_ADDR(&(echo_netif1->ip_addr), 192, 168, 1, 10);
IP4_ADDR(&(echo_netif1->netmask), 255, 255, 255, 0);
IP4_ADDR(&(echo_netif1->gw), 192, 168, 1, 1);
}
}
ipaddr1.addr = echo_netif1->ip_addr.addr;
gw1.addr = echo_netif1->gw.addr;
netmask1.addr = echo_netif1->netmask.addr;
print_ip_settings(&ipaddr1, &netmask1, &gw1);
/* start the application (web server, rxtest, txtest, etc..) */
start_application();//此函数无须修改
/* receive and process packets */
while (1) {
if (TcpFastTmrFlag) {
tcp_fasttmr();
TcpFastTmrFlag = 0;
}
if (TcpSlowTmrFlag) {
tcp_slowtmr();
TcpSlowTmrFlag = 0;
}
if (TcpFastTmrFlag1) {
tcp_fasttmr();
TcpFastTmrFlag1 = 0;
}
if (TcpSlowTmrFlag1) {
tcp_slowtmr();
TcpSlowTmrFlag1 = 0;
}
xemacif_input(echo_netif1);
xemacif_input(echo_netif);
transfer_data();
}
/* never reached */
cleanup_platform();
return 0;
}
此处运行已经可以ping通两个网卡,但是会出现ping网卡1成功,ping网卡2成功,tcp网卡1成功,tcp网卡2失败。网上查阅资料,发现如下:
对于low_level_init,low_level_output,low_level_input以及ethernetif_input函数,由于我是直接再新建一个netif块,有两个不同的mac地址,追踪函数发现,不需要再对上述函数进行修改,只剩下ip_route().
再ip4.c中,修改ip4_route函数为ip4_route2
原函数处理
ip4_addr_netcmp函数认为只要是本网段就退出,由于我只是为了多个通讯口做的双网口,所以均在同一网段,这里把ip4_addr_netcmp修改一下,修改为比较源地址的方式。
注意:
lwip源码中ip4_route(const ip4_addr_t *dest)只有一个参数,需要自行追踪ip4_route,修改为ip4_route2(const ip4_addr_t *src,const ip4_addr_t *dest),需要修改一些头文件的定义以及#define
以下是我修改的源码函数:
/**
* Finds the appropriate network interface for a given IP address. It
* searches the list of network interfaces linearly. A match is found
* if the masked IP address of the network interface equals the masked
* IP address given to the function.
*
* @param dest the destination IP address for which to find the route
* @return the netif on which to send to reach dest
*/
struct netif *
ip4_route2(const ip4_addr_t *src,const ip4_addr_t *dest)
{
#if !LWIP_SINGLE_NETIF
struct netif *netif;
LWIP_ASSERT_CORE_LOCKED();
#if LWIP_MULTICAST_TX_OPTIONS
/* Use administratively selected interface for multicast by default */
if (ip4_addr_ismulticast(dest) && ip4_default_multicast_netif) {
return ip4_default_multicast_netif;
}
#endif /* LWIP_MULTICAST_TX_OPTIONS */
/* bug #54569: in case LWIP_SINGLE_NETIF=1 and LWIP_DEBUGF() disabled, the following loop is optimized away */
LWIP_UNUSED_ARG(dest);
/* iterate through netifs */
NETIF_FOREACH(netif) {
/* is the netif up, does it have a link and a valid address? */
if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) {
/* network mask matches? */
// if (ip4_addr_netcmp(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) {
if (ip4_addr_cmp(src, netif_ip4_addr(netif))) {
/* return netif on which to forward IP packet */
return netif;
}
/* gateway matches on a non broadcast interface? (i.e. peer in a point to point interface) */
if (((netif->flags & NETIF_FLAG_BROADCAST) == 0) && ip4_addr_cmp(dest, netif_ip4_gw(netif))) {
/* return netif on which to forward IP packet */
return netif;
}
}
}
#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF
/* loopif is disabled, looopback traffic is passed through any netif */
if (ip4_addr_isloopback(dest)) {
/* don't check for link on loopback traffic */
if (netif_default != NULL && netif_is_up(netif_default)) {
return netif_default;
}
/* default netif is not up, just use any netif for loopback traffic */
NETIF_FOREACH(netif) {
if (netif_is_up(netif)) {
return netif;
}
}
return NULL;
}
#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */
#ifdef LWIP_HOOK_IP4_ROUTE_SRC
netif = LWIP_HOOK_IP4_ROUTE_SRC(NULL, dest);
if (netif != NULL) {
return netif;
}
#elif defined(LWIP_HOOK_IP4_ROUTE)
netif = LWIP_HOOK_IP4_ROUTE(dest);
if (netif != NULL) {
return netif;
}
#endif
#endif /* !LWIP_SINGLE_NETIF */
if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) ||
ip4_addr_isany_val(*netif_ip4_addr(netif_default)) || ip4_addr_isloopback(dest)) {
/* No matching netif found and default netif is not usable.
If this is not good enough for you, use LWIP_HOOK_IP4_ROUTE() */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
IP_STATS_INC(ip.rterr);
MIB2_STATS_INC(mib2.ipoutnoroutes);
return NULL;
}
return netif_default;
}
由于前期不熟悉关于lwip的源码,在做第二个网口的时候纠结在low_level_init,low_level_output,low_level_input三个函数的区分不同网卡数据处理中踩了许多的坑,后来阅读了源码文档后,发现在zynq的例程上无须修改上述函数,只需要修改ip4_route即可。