armethernetbare-metallwipzynq

LWIP RAW API dual ethernet connection problem


I am trying to use dual PL ethernet connection for redundancy on Xilinx Zynq 7020. At the normal scenarios the ethernets can work separately. So I started by adding network interface for second ethernet too. After adding it with different address which comes from digital design that corresponds to ethernet 2 I can use dual ethernet. My question is that I cannot use only first ethernet when I unplug eth2 cord. But I can use only second ethernet when I unplug first cable. I commented out the netif_set_default part but I believe because of I initialized second ethernet later it overrides ethernet 1. Is there a way for using both ethernet ports separately and together? I also use one pcb that works for both. When I tried to seperate it, there were many problems occur. Thanks for any advice.

netif = &server_netif;
netif2 = &server_netif2;
ipaddr = (ip_addr_t
            ) IPADDR4_INIT(ip);
    netif->ip_addr = ipaddr;
    local_multicast = (ip_addr_t
            ) IPADDR4_INIT(multicast_ip);
    if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address,
    PLATFORM_EMAC_BASEADDR_0))
        {
            xil_printf("Error adding N/W interface\r\n");
            return;
        }
//  netif_set_default(netif);
    netif_set_up(netif);
ipaddr2 = (ip_addr_t
                ) IPADDR4_INIT(ip2nd);
    netif2->ip_addr = ipaddr2;
    local_multicast2 = (ip_addr_t
            ) IPADDR4_INIT(multicast_ip2);
    if (!xemac_add(netif2, &ipaddr2, &netmask, &gw, mac_ethernet_address2,
    PLATFORM_EMAC_BASEADDR_1))
        {
            xil_printf("Error adding N/W interface\r\n");
            return;
        }
//  netif_set_default(netif2);
    netif_set_up(netif2);

err = igmp_joingroup(&ipaddr, &local_multicast);
err = igmp_joingroup(&ipaddr2, &local_multicast2);
pcb = udp_new();
err = udp_bind(pcb, IP_ANY_TYPE, IGMP_MULTICAST_PORT);
udp_recv(pcb, udp_multicast_recv, NULL);

Solution

  • Ok after the long struggle I solved the problem. My LWIP initialization above is actually true and interrupt works on any ethernet cable combination. The main issue here is I cannot send response from previously initialized network interface. After a long process of debugging, I finally find out that pcb (protocol control block) declares an ethernet, which likely last initialized connection, and sends data from it. What I made is got in to udp.c file and changed file to:

    err_t
    udp_sendto(struct udp_pcb * pcb, struct netif * netif, struct pbuf * p,
        const ip_addr_t * dst_ip, u16_t dst_port) {
        #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP
        return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0);
    }
    
    /** @ingroup udp_raw
     * Same as udp_sendto(), but with checksum */
    err_t
    udp_sendto_chksum(struct udp_pcb * pcb, struct pbuf * p,
        const ip_addr_t * dst_ip,
            u16_t dst_port, u8_t have_chksum, u16_t chksum) {
        #endif
    
        LWIP_ERROR("udp_sendto: invalid pcb", pcb != NULL,
            return ERR_ARG);
        LWIP_ERROR("udp_sendto: invalid pbuf", p != NULL,
            return ERR_ARG);
        LWIP_ERROR("udp_sendto: invalid dst_ip", dst_ip != NULL,
            return ERR_ARG);
    
        if (!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) {
            return ERR_VAL;
        }
    
        LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
    
        if (pcb -> netif_idx != NETIF_NO_INDEX) {
            //netif = netif_get_by_index(pcb->netif_idx);
        } else {
            #if LWIP_MULTICAST_TX_OPTIONS
            //netif = NULL;
            if (ip_addr_ismulticast(dst_ip)) {
    
                if (pcb -> mcast_ifindex != NETIF_NO_INDEX) {
                    //netif = netif_get_by_index(pcb->mcast_ifindex);
                }
                #if LWIP_IPV4
                else
                    #if LWIP_IPV6
                if (IP_IS_V4(dst_ip))
                    #endif /* LWIP_IPV6 */ {
    
                        if (!ip4_addr_isany_val(pcb -> mcast_ip4) &&
                            !ip4_addr_cmp( & pcb -> mcast_ip4, IP4_ADDR_BROADCAST)) {
                            //netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4);
                        }
                    }
                #endif /* LWIP_IPV4 */
            }
    
            if (netif == NULL)
                #endif /* LWIP_MULTICAST_TX_OPTIONS */ {
                    //netif = ip_route(&pcb->local_ip, dst_ip);
                }
        }
    
        if (netif == NULL) {
            LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to "));
            ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, dst_ip);
            LWIP_DEBUGF(UDP_DEBUG, ("\n"));
            UDP_STATS_INC(udp.rterr);
            return ERR_RTE;
        }
        #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP
        return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum);
        #else
        return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
        #endif
    }
    

    and

    err_t
    udp_send(struct udp_pcb *pcb,struct netif *netif, struct pbuf *p)
    {
      LWIP_ERROR("udp_send: invalid pcb", pcb != NULL, return ERR_ARG);
      LWIP_ERROR("udp_send: invalid pbuf", p != NULL, return ERR_ARG);
    
      if (IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) {
        return ERR_VAL;
      }
    
      /* send to the packet using remote ip and port stored in the pcb */
      return udp_sendto(pcb,netif, p,  &pcb->remote_ip, pcb->remote_port);
    }
    
    #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP
    /** @ingroup udp_raw
     * Same as udp_send() but with checksum
     */
    err_t
    udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
                    u8_t have_chksum, u16_t chksum)
    {
      LWIP_ERROR("udp_send_chksum: invalid pcb", pcb != NULL, return ERR_ARG);
      LWIP_ERROR("udp_send_chksum: invalid pbuf", p != NULL, return ERR_ARG);
    
      if (IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) {
        return ERR_VAL;
      }
    
      /* send to the packet using remote ip and port stored in the pcb */
      return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port,
                               have_chksum, chksum);
    }
    #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */
    

    with this way I could use the netif (network interface) that I choose.

    Have a nice day!