ZYNQ裸机LWIP双网口实现

文章目录

  • 前言
  • 一、LWIP双网口
  • 二、使用步骤
    • 1.部分说明
    • 2.部分代码
  • 总结


前言


一、LWIP双网口

由于项目需要多通讯口,查阅资料发现lwip支持多网口操作。于是,就开搞了。

二、使用步骤

1.部分说明

利用xemac_add函数在网卡链表中添加一个网卡,即使用netif块重复xemac_add操作。
先用轮询的方式实现双网口,后期修改为中断模式

2.部分代码

导入官方例程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失败。网上查阅资料,发现如下:
ZYNQ裸机LWIP双网口实现_第1张图片
对于low_level_init,low_level_output,low_level_input以及ethernetif_input函数,由于我是直接再新建一个netif块,有两个不同的mac地址,追踪函数发现,不需要再对上述函数进行修改,只剩下ip_route().

再ip4.c中,修改ip4_route函数为ip4_route2
原函数处理ZYNQ裸机LWIP双网口实现_第2张图片
ip4_addr_netcmp函数认为只要是本网段就退出,由于我只是为了多个通讯口做的双网口,所以均在同一网段,这里把ip4_addr_netcmp修改一下,修改为比较源地址的方式。
ZYNQ裸机LWIP双网口实现_第3张图片
注意:
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即可。

你可能感兴趣的:(网络,linux,运维)