STM 32 LwIPシングルNICバインド複数IPアドレス


STM 32 LwIPシングルNICバインド複数IPアドレス


チップ:STM 32 F 107 VC
コンパイラ:KEIL 4
作者:SY
日付:2018-6-28 11:02:53

概要


物理ネットワークカードが1つしかない場合、ソフトウェアを介して複数のIP を仮想化し、時間分割通信することができる.
  • プロトコルスタック:LwIP
  • メインチップ:STM32F107VC
  • インプリメンテーション


    まず、LwIPを移植し、単一のIP で利用できることを保証する.
    次に仮想NICを追加します.
    void LwIP_Init(void)
    {
        /*  1 */
        IP4_ADDR(&ipaddr1, 192, 168, 0, 234);
        IP4_ADDR(&netmask1, 255, 255, 255, 0);
        IP4_ADDR(&gw1, 192, 168, 0, 1);
        netif_add(&netif1, &ipaddr1, &netmask1, &gw1, NULL, &ethernetif_init, &ethernet_input);
        netif_set_up(&netif1);
        netif_set_default(&netif1);
    
        /*  2 */
        IP4_ADDR(&ipaddr2, 192, 168, 1, 234);
        IP4_ADDR(&netmask2, 255, 255, 255, 0);
        IP4_ADDR(&gw2, 192, 168, 1, 1);
        netif_add(&netif2, &ipaddr2, &netmask2, &gw2, NULL, &ethernetif_init, &ethernet_input);
        netif_set_up(&netif2);
    
        /*  UDP  */
        struct udp_pcb *UdpPcb;
        /* Create a new UDP control block  */
        UdpPcb = udp_new();  
    
        /* Bind the upcb to any IP address and the UDP_PORT port*/
        udp_bind(UdpPcb, IP_ADDR_ANY, UDP_CLIENT_PORT);
    
        /* Set a receive callback for the upcb */
        udp_recv(UdpPcb, udp_client_callback, NULL); 
    }

    このように処理すると、次の問題が発生します.
  • 一部のパケットはNICに滞在し、不確定な時間後に
  • に送信されます.
  • パケットは毎回2回
  • を送信する
  • の最初のNICのIP は、データを受け取ることができず、イーサネットデバッグアシスタントを使用してIPにデータを送信してもパケットをつかむことができません.

  • イーサネット通信プロトコルによれば、ローカルエリアネットワーク内のデータ送受信は、MACアドレスで通信する必要があるため、まずARPパケットを送信する必要があり、目的のIP にプロトコルパケットを送信し、相手のMAC を要求する必要がある.パッケージツールで調べたところ、やはり、パソコン側から送信されたARPパケットは、デバイスから返信されなかった.
    したがって、ARP を修正する.
    /*
    *********************************************************************************************************
    * Function Name : GetActiveNetif
    * Description   :  
    * Input         : None
    * Output        : None
    * Return        : None
    *********************************************************************************************************
    */
    struct netif *GetActiveNetif(struct ip_addr *src_ip)
    {
        struct netif *curNetif = NULL;
        if (ip_addr_cmp(src_ip, &netif1.ip_addr)) {
            curNetif = &netif1;
        } else if (ip_addr_cmp(src_ip, &netif2.ip_addr)) {
            curNetif = &netif2;
        }
        return curNetif;
    }

    パケットの IPフィールドを解析し、現在の2枚のNICの IPフィールドと比較することで、パケットがどのNICに送信されたかを特定します.
    void
    etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
    {
        /* this interface is not configured? */
        if (netif->ip_addr.addr == 0) {
            for_us = 0;
        } else {
            /* ARP packet directed to us? */
            struct netif *GetActiveNetif(struct ip_addr *src_ip);
            struct netif *activeNetif = GetActiveNetif(&dipaddr);
            if (activeNetif != NULL) {
                for_us = 1;
                netif = activeNetif;
            }
        }
    
        /* ARP message directed to us? */
        if (for_us) {
            /* add IP address in ARP cache; assume requester wants to talk to us.
             * can result in directly sending the queued packets for this host. */
            update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
            /* ARP message not directed to us? */
        } else {
            /* update the source IP address in the cache, if present */
            update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);
        }
    }

    上記の修正により、上位機のパケットを受け取ることができます.
    /**
     * In this function, the hardware should be initialized.
     * Called from ethernetif_init().
     *
     * @param netif the already initialized lwip network interface structure
     *        for this ethernetif
     */
    static void
    low_level_init(struct netif *netif)
    {
        /* device capabilities */
          /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
          netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_LINK_UP;
    }

    以上のヒントに従って、複数のネットワークがある場合は、NETIF_FLAG_ETHARPフィールドを削除する必要があります.OK、上記の変更により、両方のIP がパケットを受信することができる.

    まとめ


    IPアドレスは異なるセグメントに構成する必要がある

    IPルーティング規則を参照:
    /**
     * 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 *
    ip_route(struct ip_addr *dest)
    {
      struct netif *netif;
    
      /* iterate through netifs */
      for(netif = netif_list; netif != NULL; netif = netif->next) {
        /* network mask matches? */
        if (netif_is_up(netif)) {
          if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
            /* return netif on which to forward IP packet */
            return netif;
          }
        }
      }
      if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
        LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"
    "
    , dest->addr)); IP_STATS_INC(ip.rterr); snmp_inc_ipoutnoroutes(); return NULL; } /* no matching netif found, use default netif */ return netif_default; }

    2枚のNICのIP が同じセグメントにある場合、NICを巡るときに、最後に追加されたNICが優先されます.つまり、どのNICにパケットを送信しても、デバイスがデータを返信するときに、2枚目のNICからデータが返信されます.
    例えば、IP (192, 168, 0, 234)にパケットを送信し、データの返信を受信すると、ソースIP IP(192, 168, 1, 234)になる.
    2枚のNICが独立して動作する場合は、正常にデータを送受信することができます.2枚のNICのIP を異なるセグメントに設定する必要があります.同時に、パソコン側はデバイス側と同じセグメントに設定する必要があります.
    例:
    ホスト1:
    IP:     192.168.0.88
    MASK:   255.255.255.0
    GATEWAY:192.168.0.1 

    デバイス1:
    IP:     192.168.0.249
    MASK:   255.255.255.0
    GATEWAY:192.168.0.1 

    これにより、ホスト1とデバイス1とが正常に通信できる.
    ホスト2:
    IP:     192.168.1.88
    MASK:   255.255.255.0
    GATEWAY:192.168.1.1 

    デバイス2:
    IP:     192.168.1.249
    MASK:   255.255.255.0
    GATEWAY:192.168.1.1 

    これにより、ホスト2とデバイス2とが正常に通信できる.
    交差したらどうなるの?パケットツールを捕まえると、ターゲットが達成できないことがわかります.彼らはもう同じサブネット内にいないからです.
    デバイス1とデバイス2が同じサブネット内にいたらどうなりますか?
    ホスト:
    IP:     192.168.0.88
    MASK:   255.255.255.0
    GATEWAY:192.168.0.1 

    デバイス1:
    IP:     192.168.0.249
    MASK:   255.255.255.0
    GATEWAY:192.168.0.1 

    デバイス2:
    IP:     192.168.0.248
    MASK:   255.255.255.0
    GATEWAY:192.168.0.1 

    現象:
    ホスト->デバイス1:デバイス2->ホスト
    ホスト->デバイス2:デバイス2->ホスト
    そこで、私たちは結論を出しました.
  • は、同じサブネット内のホストおよびデバイスのみが正常にデータを送受信できる
  • である.
  • 同じサブネット内に2台のデバイスがある場合、ホストは最後に追加されたNICにバインドされたIP と正常に通信するしかありません.最初に追加したNICとの通信では、ip_routの関係で、最後にバインドしたNICのIP を使用して返信します!