Elektroda.pl
Elektroda.pl
X

Search our partners

Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[lwIP][FreeRTOS] - Wyłączenie jednego hosta uniemożliwia komunikację UDP z innym

grzegorzn 23 Jul 2015 21:50 759 5
  • #1
    grzegorzn
    Level 12  
    Korzystam z lwip oraz FreeRTOS na STM32F4, wykorzystuję socket API. Na moim urządzeniu działa serwer WWW, ono samo także komunikuje się z innymi serwerami, zarówno po UDP jak i TCP. Ostatnio zauważyłem dziwną rzecz: wyłączenie komputera na którym działa usługa TCP, do której co minutę na krótką chwilę łączy się moja płytka powoduje, że lwip przestaje przetwarzać przychodzące pakiety UDP od dwóch innych komputerów, które pozostają włączone. TCP cały czas działa, zarówno przychodzące żądania HTTP do działającego na urządzeniu serwera WWW jak i połączenia TCP nawiązywane przez urządzenie do innych komputerów. Tylko UDP przestaje działać - pakiety są wysyłane do mojego urządzenia, ale są ignorowane (dropowane) przez stos lwip. Wysyłanie pakietów UDP przez moją płytkę działa poprawnie.



    Podkreślę, że chodzi o sam fakt wyłączenia komputera. Nie ma znaczenia, czy włączona jest na nim usługa TCP, do której łączy się moje urządzenie i czy mojej płytce uda się połączyć. Problem pojawia się tylko wtedy, gdy komputer ten zostanie wyłączony w czasie pracy mojego urządzenia. Jeśli był wyłączony cały czas, to moje urządzenie działa poprawnie - wymienia pakiety UDP z innymi komputerami.

    Podejrzewam, że ma to związek z wygasającym wpisem ARP w cache od tego wyłączanego komputera. Dopóki komputer jest włączony i jego wpis istnieje, wszystko jest w porządku. Również gdy nie ma wpisu jest OK. Tylko po jego usunięciu jest problem. Być może lwip próbuje odświeżyć wpis, wysyła zapytanie ARP, ale nie dostając odpowiedzi czeka w nieskończoność. Tylko dlaczego to blokuje odbieranie UDP, a nie blokuje komunikacji TCP? Co do samego lwip to wygląda na problem z zarządzaniem pamięcią: memp_malloc() zwraca wtedy NULL w funkcji recv_udp().
  • #2
    michcior
    Level 30  
    Czy sam integrowałeś stos ze sprzętem karty (emac)? Podejrzewam, że nie bo byś miał więcej przemyśleń na ten temat. Logicznie, LwIP dostaje i wysyła pakiety ethernet'owe do modułu emac twojego procesora. Znajdź to miejsce i je monitoruj. To będzie realizowane poprzez DMA.

    Podejrzewam, że usunięcie hosta z połączeniem TCP , zwiększa aktywność mechanizmów utrzymywania połączenia i nie starcza już czasu na zawracanie sobie głowy pakietami UDP, a inne TCP działają dzięki powtórzeniom, np.
    Spróbuj zmienić prędkość na 10Mbs, jeśli tak jest to zauważysz różnicę.

    Jak znajdziesz gdzieś HUB na 100Mbs (rarytas) to możesz monitorować ruch do twojego procesora WireShark'iem

    Jeśli jest tak jak podejrzewam, to zabawa timerami od TCP i timeoutami też powinna pomóc.
  • #3
    grzegorzn
    Level 12  
    Nie integrowałem sam, bo nie ma takiej potrzeby. Są gotowe przykłady. Wiem też jak to jest realizowane i nie widzę potrzeby monitorowania akurat tego miejsca. Pakiet są prawidłowo transmitowane przez DMA do EMAC i dalej na zewnątrz do PHY. Podobnie w drugą stronę. Problem jest w samym stosie lwip, bo tam pakiety są dropowane.

    Nie wiem dlaczego ma nie starczać czasu. Pakiety UDP są 4 na minutę. Jak nie zacznę chodzić po WWW, to pakietów TCP też jest kilka na minutę. Jak zacznę, to oczywiście jest więcej, ale Wireshark nie pokazuje powtórzeń. TCP działa jak najbardziej poprawnie. Nie ma z resztą powodu żeby były jakieś trudności. Jedynym powtarzaniem jest wielokrotna retransmisja pakietu SYN do wyłączonego komputera. Jest wysyłane 14 takich pakietów w odstępach 3-sekundowych. Nie wydaje mi się to z resztą niczym niezwykłym. Po kilku minutach pakiety SYN już nie są wysyłane wcale, tylko ARP z zapytaniem o wyłączony host.
  • #5
    grzegorzn
    Level 12  
    Zgadza się, o problemie z pamięcią pisałem już w pierwszym poście. Widać to dokładniej po włączeniu MEMP_DEBUG i dodaniu dodatkowych komunikatów. UDP_DEBUG jest o tyle przydatne, że zastępuje sniffer i pokazuje nagłówki pakietów, ale nie pokazuje nic ciekawego odnośnie pamięci.

    Sytuacja wygląda tak, że normalnie przy wysłaniu pakietu UDP alokowany jest obszar z puli NETBUF i po odebraniu odpowiedzi i zamknięciu socketa jest zwalniany. Próba nawiązania połączenia TCP do komputera z wyłączoną usługą nie powoduje alokacji z puli NETBUF. Natomiast gdy ten komputer zostanie wyłączony, to po kilku minutach (nie mierzyłem dokładnie, ale mniej więcej tyle na ile ustawione jest wygasanie wpisów ARP) nagle zaczynają się alokacje NETBUF i pojawiają się komunikaty o braku wolnego miejsca w tej puli.
  • #6
    grzegorzn
    Level 12  
    W końcu znalazłem.

    Z debugowania wyszło, że problem dotyczy ARP raczej pośrednio. Wpisy ARP najwyraźniej wygasają na switchu, który zaczyna pakiety SYN rozgłaszać na wszystkich portach i trafiają one także do routera. Router odpowiada wtedy pakietami ICMP type 5 code 1 (Redirect Datagram for the Host). Te pakiety trafiają do mojego urządzenia i powodują alokację NETBUFów. Nie są one potem dealokowane i blokują przetwarzanie pakietów UDP. Taki sam efekt daje pingowanie urządzenia. Wystarczą cztery pingi żeby zapchać pulę NETBUF i zablokować odbieranie pakietów UDP. Przy okazji zauważyłem, że odebrane pakiety ICMP lecą do mailboksa, czyli jakby do socketa.

    I w końcu sobie przypomniałem. Mam funkcję pingującą. Jest ona zrobiona na sockecie typu RAW, który jest cały czas otwarty. I on zbiera pakiety ICMP. Natomiast odbierane są z FreeRTOSowego mailboksa tylko w momencie gdy to urządzenie pinguje. Gdy nie pinguje, przychodzące pakiety nie są wyciąganie z mailboksa i nie następuje dealokacja z puli NETBUF.