공용 네트워크 서버 또는 클라이언트가 NAT 네트워크인 서버는 tcp_를 동시에 켜지 마십시오.tw_recycle 및 tcp_timestamps

9224 단어 계통

카탈로그

  • 디렉토리
  • 배경 및 현상
  • 문제의 원인
  • 결론
  • 실천
  • tcp_ 구성 방법tw_recycle 및 tcp_timestamps
  • 왜 tcp를 많이 켰는지 _tw_recycle도 문제가 발생하지 않았습니다


  • 배경 및 현상


    서버: 공공 네트워크 서버 클라이언트: 외부 네트워크 모바일 클라이언트 유저 측 현상: 대량의 같은 랜 내의 내부 유저들이 서버에 접속하는 시간이 초과되었지만 4G로 전환된 후에 연결이 원활하다.서비스 사이드 현상: netstat -s" "passive connections rejected because of time stamp"수량이 빠르게 증가하고 닫힘tcp_tw_recycle 또는 tcp_timestamps 정상적으로 회복되며 유저 사이드 현상이 사라집니다.

    문제의 원인

    tcp_tw_recycle의존tcp_timestamps, 전자는 기본적으로 닫고 후자는 기본적으로 엽니다.둘 다 켜져 있으면 서버가 FIN 패키지를 받을 때 이 FIN 패키지의 타임스탬프 값은 IP에 따라 캐시됩니다(캐시 TCP_PAWS_MSL, 즉 60s). 캐시 시간 내에 같은 IP의 SYN 패키지 타임스탬프가 이 값보다 작으면 바로 버려집니다.코드 분석은 다음과 같습니다.
    tcp_v4_conn_request()
    /* VJ's idea. We save last timestamp seen
     * from the destination in peer table, when entering
     * state TIME-WAIT, and check against it before
     * accepting new connection request.
     *
     * If "isn" is not zero, this request hit alive
     * timewait bucket, so that all the necessary checks
     * are made in the function processing timewait state.
     */
    if (tmp_opt.saw_tstamp &&
        tcp_death_row.sysctl_tw_recycle &&
        (dst = inet_csk_route_req(sk, req)) != NULL &&
        (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
        peer->v4daddr == saddr) {
            if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
                (s32)(peer->tcp_ts - req->ts_recent) >
                                            TCP_PAWS_WINDOW) {
                    NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
                    goto drop_and_release;
            }
    }
    peer->tcp_ts_stamp는 이전에 FIN 패키지를 받았을 때 서버의 시간 스탬프를 기록하기 때문에, peer->tcp_ts는 FIN 패키지의 시간 스탬프를 기록하고, req->ts_recent는 현재 SYN 패키지의 시간 스탬프를 표시하기 때문에, (u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL 캐시가 아직 만료되지 않았음을 나타내고, (s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW 현재 SYN 패키지의 시간 스탬프가 이전 FIN 패키지의 시간 스탬프보다 1s 작음을 나타내기 때문에, 현재 SYN 패키지가 이전에 재전송된 것으로 간주하여 그대로 버린다.
    req - struct request_sock peer- struct inet_peer, inet_getpeer() get_seconds() - 현재 서버 시간 가져오기
    TCP_PAWS_MSL
    #define TCP_PAWS_MSL    60              /* Per-host timestamps are invalidated
                                             * after this time. It should be equal
                                             * (or greater than) TCP_TIMEWAIT_LEN
                                             * to provide reliability equal to one
                                             * provided by timewait state.

    TCP_PAWS_WINDOW
    #define TCP_PAWS_WINDOW 1               /* Replay window for per-host
                                             * timestamps. It must be less than
                                             * minimal timewait lifetime.
                                             */

    tcp_v4_tw_remember_stamp()
    int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
    {
            struct inet_peer *peer = inet_getpeer(tw->tw_daddr, 1);
    
            if (peer) {
                    const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
    
                    if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 ||
                        ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL &&
                         peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) {
                            peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp;
                            peer->tcp_ts       = tcptw->tw_ts_recent;
                    }
                    inet_putpeer(peer);
                    return 1;
            }
    
            return 0;
    }
    peer->tcp_ts_stamptcptw->tw_ts_recent_stamp,peer->tcp_tstcptw->tw_ts_recent,참조tcp_timewait_state_process().
    tcptw - struct tcp_timewait_sock, struct inet_timewait_sock
    tcp_timewait_state_process()
    /* FIN arrived, enter true time-wait state. */
    tw->tw_substate   = TCP_TIME_WAIT;
    tcptw->tw_rcv_nxt = TCP_SKB_CB(skb)->end_seq;
    if (tmp_opt.saw_tstamp) {
            tcptw->tw_ts_recent_stamp = get_seconds();
            tcptw->tw_ts_recent       = tmp_opt.rcv_tsval;
    }
    
    /* I am shamed, but failed to make it more elegant.
     * Yes, it is direct reference to IP, which is impossible
     * to generalize to IPv6. Taking into account that IPv6
     * do not understand recycling in any case, it not
     * a big problem in practice. --ANK */
    if (tw->tw_family == AF_INET &&
        tcp_death_row.sysctl_tw_recycle && tcptw->tw_ts_recent_stamp &&
        tcp_v4_tw_remember_stamp(tw))
            inet_twsk_schedule(tw, &tcp_death_row, tw->tw_timeout,
                               TCP_TIMEWAIT_LEN);
    else
            inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
                               TCP_TIMEWAIT_LEN);
    return TCP_TW_ACK;

    여기서 알 수 있듯이 tcptw->tw_ts_recent_stamp 은 FIN 패키지를 받았을 때 서버의 현재 시간을 기록하고 tcptw->tw_ts_recent 는 FIN 패키지의 양쪽 끝에 있는 시간 스탬프를 기록합니다.

    결론


    대량의 내부 유저가 같은 NAT 네트워크에 있기 때문에 모든 유저의 IP는 같은 출구 IP로 변환되지만 타임 스탬프는 보존되어 있기 때문에 서버에 도착한 패키지의 타임 스탬프 순서와 도착 순서는 일치하지 않습니다. tcp_tw_recycletcp_timestamps를 동시에 열 때 한 유저가 연결을 끊으면 다른 유저의 SYN 패키지가 버려질 수 있습니다.

    실천


    tcp_ 구성 방법tw_recycle 및 tcp_timestamps

    tcp_timestamp 오픈 권장.tcp_timestamp는 RFC1323이 정의한 최적화 옵션으로 TCP 연결에서 RTT(Round Trip Time) 계산에 주로 사용되며, 오픈tcp_timestamp은 시스템 계산에 더욱 정확한 RTT와 TCP 성능 향상에 도움이 된다.tcp_tw_recycle 닫기를 권장합니다.
    대부분의 시스템의 기본 설정도 마찬가지입니다.

    왜 tcp_를 많이 켰는지tw_recycle도 문제가 없어요.


    첫째, 현재 네트워크에서 대량의 사용자가 같은 NAT 네트워크에 있고 가방이 NAT 게이트웨이에 전송된 후 순서가 혼란스러워 수량이 적더라도 발생한다.둘째, 일부 클라이언트 시스템에서는 XP 및 대부분의 Windows 7과 같은 타임 스탬프를 사용하지 않습니다.

    좋은 웹페이지 즐겨찾기