리 눅 스 커 널 분석-네트워크[15]:육 유 표[재 론]
육 유 표 는 3 층 협의의 핵심 데이터 구조 로 서 그것 을 이해 하 는 것 이 중요 하 다.앞에서 경로 표를 분 석 했 으 니 관심 있 는 것 은 참고 할 수 있 습 니 다. 루트 테이블http://blog.csdn.net/qy532846454/article/details/6423496 루트 테이블 의 기본 데이터 구조 와 기본 조작 을 분석 했다 루트 테이블 사용http://blog.csdn.net/qy532846454/article/details/6726171 루트 테이블 의 기본 사용 을 분석 했다
이번 에는 더욱 실제 적 인 예 를 들 어 과정 에서 경로 표 의 사용 상황 을 분석 할 것 입 니 다.다음 글 은 모두 경로 캐 시 표 에 대한 설명 입 니 다.경로 표 는 네트워크 카드 주 소 를 설정 한 후에 다시 바 뀌 지 않 기 때 문 입 니 다(인위적인 변경 이 없 는 한).테스트 환경 은 다음 그림 과 같 습 니 다.
두 호스트 Host 1 과 Host 2 는 각각 IP 주소 192.168.1.1 과 192.168.1.2 를 설정 하고 두 호스트 간 에 네트워크 로 직접 연결 합 니 다.두 호스트 에서 각각 다음 작업 을 수행 합 니 다. 1. Host 1 에서 ping 호스트 Host 2 2. Host 2 에서 ping 호스트 Host 1 간단 하고 일반적인 두 호스트 가 서로 ping 하 는 예 를 들 어 이 과정 에서 경로 표 의 변 화 를 분석 하고 경로 캐 시 의 변화 라 고 준비 합 니 다.우선,루트 캐 시 에 몇 개의 항목 이 존재 합 니까?답 은 2 개가 아니 라 3 개 입 니 다.이 점 이 중요 합 니 다.구체 적 으로/proc/net/rt 를 통 해cache 는 캐 시 시트 를 보 려 고 합 니 다.아래 그림 은 상기 작업 을 수행 한 결과 입 니 다.
brcm 0.1 은 Host 호스트 의 네트워크 카드 장치 로 자주 사용 하 는 eth 0 과 같 고 lo 는 순환 장치 입 니 다.결 과 를 조금 분석 해 보면 항목 1 과 항목 2 는 똑 같 습 니 다.계수 의 Use 를 제외 하고 약간 차이 가 있 습 니 다.이러한 상황 이 존재 하 는 이 유 는 캐 시 시트 가 Hash 표 형식 으로 저장 되 어 있 기 때 문 입 니 다.비록 두 가지 내용 이 같 지만 실제 삽입 할 때 사용 하 는 키 값 은 다 릅 니 다.다음은 Host 2 호스트 의 경로 캐 시 시트 를 시각 으로 합 니 다.상호 ping 의 과정 에 대해 하나씩 분석 하 다.
brcm 0.1 장치 의 index=2 단계 0 을 가정 합 니 다.초기 에 육 로 는 캐 시 에서 비어 있 습 니 다.
STEP 1:호스트 Host 1 ping 호스트 Host 2 Host 2 는 Host 1 에서 온 echo 메시지(dst=192.168.1.2,src=192.168.1.1)를 받 았 다. 메시지 가 IP 층 에 들 어간 후에 경로 표를 조회 하여 메시지 의 수신 방식 을 확인 하고 해당 하 는 호출 절 차 를 확인 합 니 다. ip_route_input() -> ip_route_input_slow() ip 에서route_input()에서 루트 캐 시 를 조회 할 때 사용 하 는 키 값 은[192.168.1.2,192.168.1.1,2,id]입 니 다.캐 시 테이블 이 비어 있어 조회 에 실 패 했 습 니 다.ip 을 계속 진행 하 십시오.route_input_slow()는 새 캐 시 항목 을 만 들 고 삽입 합 니 다.
hash = rt_hash(daddr, saddr, iif, rt_genid(net));
ip 에서route_input_slow()에서 경로 표를 조회 합 니 다.이 컴퓨터 로 보 내기 때문에 회의 LOCAL 표 에 192.168.1.2 항목 이 일치 하고 조회 결과 res.type==RTNLOCAL。
if ((err = fib_lookup(net, &fl, &res)) != 0) {
if (!IN_DEV_FORWARD(in_dev))
goto e_hostunreach;
goto no_route;
}
그리고 res.type 에 따라 local 로 이동input 코드 세그먼트,새로운 경로 저장 소 를 만 들 고 육 유 캐 시 를 삽입 합 니 다.
rth = dst_alloc(&ipv4_dst_ops);
……
rth->u.dst.dev = net->loopback_dev;
rth->rt_dst = daddr;
rth->rt_src = saddr;
rth->rt_gateway = daddr;
rth->rt_spec_dst = spec_dst; (spec_dst=daddr)
……
hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));
err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);
따라서 삽 입 된 첫 번 째 캐 시 정 보 는 다음 과 같 습 니 다. Key = [dst = 192.168.1.2 src = 192.168.1.1 idx = 2 id = id] Value = [Iface = lo dst = 192.168.1.2 src = 192.168.1.1 idx = 2 id = id ……]
STEP 2:호스트 Host 2 호스트 Host 1(dst=192.168.1.1 src=192.168.1.2)에 echo reply 메 시 지 를 보 냅 니 다. 절차 2 는 절차 1 에 이 어 Host 2 는 echo 메 시 지 를 받 은 후에 echo reply 메 시 지 를 즉시 답장 하고 해당 호출 절차: icmp_reply() -> ip_route_output_key() -> ip_route_output_flow() -> __ip_route_output_key() -> ip_route_output_slow() -> ip_mkroute_output() -> __mkroute_output() icmp 에서reply()에 서 는 나중에 찾 을 수 있 는 관건 적 인 데이터 플 로 우 를 생 성 합 니 다.찾 을 수 있 는 키 값 으로 볼 수 있 습 니 다.받 은 메 시 지 를 답장 하 는 것 이기 때문에 목적 과 소스 IP 주 소 는 이미 알 고 있 습 니 다.아래 구조 에 서 는 daddr=192.168.1.1,saddr=192.168.1.2.
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = rt->rt_spec_dst,
.tos = RT_TOS(ip_hdr(skb)->tos) } },
.proto = IPPROTO_ICMP };
재ip_route_output_key()에 서 는 캐 시 시트 를 조회 합 니 다.조회 의 키 값 은[192.168.1.1,192.168.1.2,0,id]입 니 다.이 때 캐 시 에 방금 삽 입 된 192.168.1.1->192.168.1.2 캐 시 항목 만 있 기 때문에 조회 에 실 패 했 습 니 다.ip 을 계속 갑 니 다.route_output_slow()는 새 캐 시 항목 을 만 들 고 삽입 합 니 다.
hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif, rt_genid(net));
ip 에서route_input_slow()에서 경로 표를 조회 합 니 다.같은 네트워크 에 있 기 때문에 회 MAIN 표 에서 192.168.1.0/24 항목 과 일치 합 니 다.조회 결과 res.type==RTNUNICAST。
if (fib_lookup(net, &fl, &res)) {
…..
}
그리고 호출mkroute_output()는 새로운 루트 캐 시 를 생 성 합 니 다.정 보 는 다음 과 같 습 니 다.
rth->u.dst.dev = dev_out;
rth->rt_dst = fl->fl4_dst;
rth->rt_src = fl->fl4_src;
rth->rt_gateway = fl->fl4_dst;
rth->rt_spec_dst= fl->fl4_src;
rth->fl.oif = oldflp->oif; (oldflp->oif 0)
루트 캐 시 테이블 을 삽입 할 때 사용 하 는 키 값 은:
hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, rt_genid(dev_net(dev_out)));
이 문 구 는 매우 관건 적 입 니 다.캐 시 저장 형식 은 hash 표 입 니 다.캐 시 정 보 를 생 성 하 는 것 외 에 해당 하 는 키 가 있어 야 합 니 다.이 문장의 hash 는 바로 생 성 된 키 입 니 다.볼 수 있 습 니 다.이것 은(dst,src,oif,id)4 원 그룹 에서 생 성 된 것 입 니 다.dst 와 src 는 잘 이해 합 니 다.id 는 net 에 있어 서 정 해진 값 이 고 oif 는 관건 입 니 다.여기 서 사용 하 는 것 은 oldflp->oif(그 값 은 0)입 니 다.캐 시 에 대응 하 는 인터페이스 장치 가 dev 임 에 도 불구 하고out。따라서 두 번 째 캐 시 정 보 는 다음 과 같다. Key = [dst = 192.168.1.1 src = 192.168.1.2 idx = 0 id = id] Value = [Iface = brcm0.1 dst = 192.168.1.1 src = 192.168.1.2 idx = 2 id = id ……]
STEP 3:호스트 Host 2 ping 호스트 Host 1 Host 2 Host 1 에 echo 메시지 보 내기(dst=192.168.1.1,src=192.168.1.2) Host 2 주동 적 으로 echo 메시지 발송,SOCK 사용RAW 와 IPPROTOICMP 조합의 소켓,해당 호출 절차: raw_sendmsg() -> ip_route_output_flow() -> __ip_route_output_key() -> ip_route_output_slow() -> ip_mkroute_output() -> __mkroute_output()rawsendmsg()에 서 는 나중에 찾 을 수 있 는 관건 적 인 데이터 플 로 우 를 생 성 합 니 다.찾 을 수 있 는 키 값 으로 볼 수 있 습 니 다.주동 적 으로 보 내 는 메시지 이기 때문에 원본 IP 주 소 는 알 수 없습니다.호스트 가 다 중 인터페이스 일 수 있 기 때문에 경로 표를 조회 한 후에 야 가 야 할 장치 인터페이스 와 해당 하 는 원본 IP 주 소 를 얻 을 수 있 습 니 다.아래 구조 에서 daddr=192.168.1.1,saddr=0.
struct flowi fl = { .oif = ipc.oif,
.mark = sk->sk_mark,
.nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = saddr,
.tos = tos } },
.proto = inet->hdrincl ? IPPROTO_RAW :
sk->sk_protocol,
};
재ip_route_output_key()에 서 는 캐 시 시트 를 조회 합 니 다.검색 의 키 값 은[192.168.1.1,0,0,id]입 니 다.비록 이때 캐 시 에 192.168.1.2->192.168.1.1 항목 이 삽입 되 었 지만 이들 의 키 값 이 다 르 기 때문에 조회 가 실 패 했 습 니 다.ip 을 계속 가 십시오.route_output_slow()는 새 캐 시 항목 을 만 들 고 삽입 합 니 다.
hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif, rt_genid(net));
Host 2 가 Host 1 에 답장 한 echo 메시지 에 비해 진입 함수 가 다 릅 니 다(전 자 는 icmpreply,후 자 는 rawsendmsg),후속 호출 프로 세 스 가 완전히 같 아서 최종 루트 캐 시가 다 르 게 되 었 습 니 다.(정확히 말 하면 키 값)초기 플러그 인 이 다 르 기 때 문 입 니 다. 여기,rawsendmsg()에서 flow i 의 초기 값:dst=192.168.1.1,src=0,oif=0 대비 icmpreply()에서 flow i 의 초기 값:dst=192.168.1.1,src=192.168.1.2,oif=0 상기 호출 프로 세 스에 서ip_route_output_key()에서 경로 캐 시 를 찾 습 니 다.비록 이 때 경로 캐 시 는 192.168.1.2 에서 192.168.1.1 까지 의 캐 시 항목 이 있 지만 키 값 은 이번에 찾 은 키 값[192.168.1.1,192.168.1.2,0]과 다음 표 에서 뚜렷하게 볼 수 있 습 니 다.
검색 에 실 패 했 기 때문에 새로운 루트 캐 시 항목 을 생 성하 고 루트 캐 시 표를 삽입 합 니 다.ip 에 주의 하 십시오route_output_slow()에서 경로 표를 찾 은 후 캐 시 된 src 를 설정 합 니 다.
if (!fl.fl4_src)
fl.fl4_src = FIB_RES_PREFSRC(res);
따라서 삽 입 된 세 번 째 캐 시 정 보 는 다음 과 같 습 니 다.두 번 째 캐 시 와 같 습 니 다.키 값 이 다 릅 니 다. Key = [dst = 192.168.1.1 src = 0 idx = 0 id = id] Value = [Iface = brcm0.1 dst = 192.168.1.1 src = 192.168.1.2 idx = 2 id = id ……]
최종 경로 캐 시 표 는 다음 과 같 습 니 다.
세 번 째 캐 시 항목 키 값 은 src=0,idx=0 을 사용 하 는 이 유 는 호스트 가 192.168.1.1 호스트 에 메 시 지 를 보 낼 때 IP 층 경로 가 조회 되 기 전 까지 사용 할 인터페이스 주 소 를 알 수 없 기 때 문 입 니 다.캐 시 검색 은 경로 조회 전에 발생 하기 때문에 src=0,idx=0 은 후속 메시지 가 이 항목 을 사용 하도록 보장 할 수 있 습 니 다.