ZeroAOS를 설치하고 운용하는 과정에서 배우는 팁이나 정보를 공개하려고 합니다. 그래서 별도의 분류를 하였습니다. Linux 전문가라면 다 아는 내용이겠지만 혹시라도 필요할 분을 위하여 마련하였습니다.
1.
KRX의 시세분배시스템은 Multicast를 프로토콜로 사용합니다. 멀티캐스트 그룹에 가입하고 해제하는 과정을 제외하면 UDP와 차이가 없습니다. 그래서 ZeroFeeder를 설치하고 시세를 받는 것은 간단한 일로 생각했습니다. 그런데 문제가 발생하였습니다.
환경은 Suse Enterprise Server 11입니다. Xeon 3.45Ghz 12코어를 설치하였고 NIC이 4개입니다. ZeroFeeder를 설치하고 환경파일에서 수신하고자 하는 주소와 그룹을 등록하였습니다. ZeroFeeder의 로그를 보니까 그룹에 정상적으로 가입하였습니다. 이제 데이타를 수신하면 되는데 데이타가 recvfrom()로 넘어오지 않네요. 그래서 tcpdump로 패킷을 살폈습니다. eth2로 패킷이 들어옵니다.
1 |
15:16:11.308952 IP 10.164.130.2.61417 > 224.16.17.23.47806: UDP, length 1400(예) |
그런데 recvfrom()에서 데이타를 받지 못합니다. 시세가 들어오지 않습니다.
혹시 이런 경험이 있으시나요? 솔직히 저는 처음이었습니다. 지금부터 문제를 풀어나간 과정을 하나씩 소개합니다. 먼저 IGMP프로토콜의 상태를 확인하였습니다.
1 2 |
netstat -g | grep 224.16.17.23 eth3 1 224.16.17.23 |
멀티캐스팅 그룹에 정상적으로 가입하였다는 표시입니다. 다음으로 시세수신 프로그램이 정상적인지 확인을 하였습니다.
1 2 |
netstat -l | grep 47806 udp 0 0 *:47806 *:* |
여기까지 이상이 없습니다. 물론 실제 IP주소와 포트번호는 다릅니다. tcpdump는 OSI Layer 2(Datalink)수준에서 팻킷데이타를 갈무리하는 도구입니다. 위의 현상을 그래로 읽으면 Layer3, Layver4 수준에서 받은 데이타를 처리하는 과정에서 무슨 문제가 있었다는 뜻입니다. 무슨 문제일까요?
2.
솔직히 전혀 짐작을 할 수 없었습니다. 방법은 구글링입니다. 이런 저런 자료를 살펴보니까 공통된 단어가 등장합니다. rp_filter입니다.RP는 Reverse Path의 약자입니다. rp_filter는 Reverser Path Filtering에 관한 정책을 결정하는 커널 패러매터값입니다.
The RP Filter is meant to reject traffic from unknown hosts, and is on by default in new Linux distros. Note that “all” has the effect of over-riding all interface settings, and default sets a default that is inherited by interfaces as they are created. So echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter will force rp_filter off for all interfaces. If the value is 1 for “all” but 0 for the specific interface, the result is still 1.
리눅스 커널이 라우팅 테이블을 참조하여 수신된 IP 패킷을 외부로 전달하는 기능을 하는 IP forwardingr과 달리 RP Filtering은 패킷이 들어오는 네트워크 인터페이스와 라우팅 테이블에 등록되어 있는 출발지 주소가 일치하지 않는 경우 자동으로 들어오는 패킷을 거절하는 역할을 합니다.
1 2 |
IP Forwarding Parameter: /proc/sys/net/<int>/ip_forward RP Filtering Parameter: /proc/sys/net/<int>/rp_filter |
리눅스 커널의 라이팅 테이블을 확인하려면 netstat를 사용합니다.
1 2 3 4 5 6 7 |
#netstat -rn Routing tables Destination Gateway Flags Refs Use Interface 127.0.0.1 127.0.0.1 UH 0 216 lo0 default 15.32.8.1 UG 0 10198 lan0 15.32.8 5.32.9.34 U 5 266610 lan0 127/8 127.0.0.1 U 30 7520307 lo0 |
이제 앞서 tcpdump로 데이타패킷을 확인하였지만 recvfrom()으로 데이타가 들어오지 않는 현상으로 돌아가보죠. rp_filter 설정이 문제라고 한다면/proc/sys/net/ipv4/conf/eth2/rp_filter=1로 되어 있어야 합니다. 또한 rp_filter=0로 변경하면 recvfrom()이 데이타팻킷을 받아야 합니다. 이를 검증하기 위하여 Host와 가상화한 Guest를 놓고 시험을 하였습니다.
1. 가상박스에서 CentOS 리부팅 직후
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
[jongi@centos ~]$ sudo sysctl -a|grep rp_filter [sudo] password for jongi: net.ipv4.conf.all.rp_filter = 0 net.ipv4.conf.all.arp_filter = 0 net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.default.arp_filter = 0 net.ipv4.conf.lo.rp_filter = 1 net.ipv4.conf.lo.arp_filter = 0 net.ipv4.conf.eth2.rp_filter = 1 net.ipv4.conf.eth2.arp_filter = 0 net.ipv4.conf.eth1.rp_filter = 1 net.ipv4.conf.eth1.arp_filter = 0 net.ipv4.conf.eth0.rp_filter = 1 net.ipv4.conf.eth0.arp_filter = 0 [jongi@centos ~]$ ifconfig -a eth0 Link encap:Ethernet HWaddr 08:00:27:87:E9:39 inet addr:10.1.2.97 Bcast:10.1.2.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fe87:e939/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:468 errors:0 dropped:0 overruns:0 frame:0 TX packets:46 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:63432 (61.9 KiB) TX bytes:6049 (5.9 KiB) eth1 Link encap:Ethernet HWaddr 08:00:27:7E:43:A1 inet addr:10.1.2.98 Bcast:10.1.2.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fe7e:43a1/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:444 errors:0 dropped:0 overruns:0 frame:0 TX packets:56 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:65993 (64.4 KiB) TX bytes:7319 (7.1 KiB) Interrupt:16 Base address:0xd240 eth2 Link encap:Ethernet HWaddr 08:00:27:6A:FD:80 inet addr:10.1.2.171 Bcast:10.1.2.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fe6a:fd80/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:449 errors:0 dropped:0 overruns:0 frame:0 TX packets:29 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:56284 (54.9 KiB) TX bytes:5078 (4.9 KiB) Interrupt:17 Base address:0xd260 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:480 (480.0 b) TX bytes:480 (480.0 b) |
2. 리눅스 호스트 (우분투)에서 멀티캐스트 전송 프로그램 작동
3. 가상박스에서 멀티캐스트 수신 프로그램 작동 (eth2 = 10.1.2.171)
1 2 |
[jongi@centos multicast]$ ./listener.x 5555 225.1.1.1 10.1.2.171 hello_port=5555,hello_group=225.1.1.1,hello_myaddr=10.1.2.171 |
수신 안 됨.
4. /etc/sysctl.conf에 다음 한 줄 추가
1 |
net.ipv4.conf.eth2.rp_filter = 0 |
그리고 sysctl -p 명령 실행 (/etc/sysctl.conf 적용)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[jongi@centos ~]$ sudo sysctl -p net.ipv4.ip_forward = 0 net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.default.accept_source_route = 0 kernel.sysrq = 0 kernel.core_uses_pid = 1 net.ipv4.tcp_syncookies = 1 kernel.msgmnb = 65536 kernel.msgmax = 65536 kernel.shmmax = 68719476736 kernel.shmall = 4294967296 net.core.rmem_max = 104857600 net.core.rmem_default = 104857600 net.core.wmem_max = 104857600 net.core.wmem_default = 104857600 net.ipv4.conf.eth2.rp_filter = 0 |
다른 터미널에 실행 중이던 창에서
1 2 3 4 5 6 7 |
[jongi@centos multicast]$ ./listener.x 5555 225.1.1.1 10.1.2.171 hello_port=5555,hello_group=225.1.1.1,hello_myaddr=10.1.2.171 Hello, World! Hello, World! Hello, World! Hello, World! |
수신되기 시작함.
5. rp_filter = 1로 설정하고 다시 sysctl -p 적용
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[jongi@centos ~]$ sudo sysctl -p net.ipv4.ip_forward = 0 net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.default.accept_source_route = 0 kernel.sysrq = 0 kernel.core_uses_pid = 1 net.ipv4.tcp_syncookies = 1 kernel.msgmnb = 65536 kernel.msgmax = 65536 kernel.shmmax = 68719476736 kernel.shmall = 4294967296 net.core.rmem_max = 104857600 net.core.rmem_default = 104857600 net.core.wmem_max = 104857600 net.core.wmem_default = 104857600 net.ipv4.conf.eth2.rp_filter = 1 |
데이터는 여전히 수신되고 있음.
6. 아래 명령 실행
1 2 3 4 5 6 7 8 9 |
[jongi@centos ~]$ sudo /etc/init.d/network restart 인터페이스 eth0 (을)를 종료 중: 장치 상태: 3 (연결 끊겼음) [ OK ] loopback 인터페이스 종료 중: [ OK ] loopback 인터페이스 활성화중 입니다: [ OK ] eth0 인터페이스 활성화중 입니다: 활성화된 연결 상태: 활성화중 활성화된 연결 경로: /org/freedesktop/NetworkManager/ActiveConnection/3 상태: 활성화됨 연결이 활성화되었습니다 [ OK ] [jongi@centos ~]$ |
데이터 수신 멈춤
7. 다시 rp_filter = 0으로 설정 그리고 sysctl -p 명령 실행하자마자 데이터 수신 다시 시작함.
이상의 결론을 내리고 ZeroFeeder를 설치한 장비의 커널패러매터를 변경하였습니다. 이후 시세가 정상적으로 동작하였습니다.
3.
한가지 의문이 생겼습니다. 이전에도 리눅스를 이용한 서비스가 많았는데 이런 문제가 없었을까? 유추해석할 수 있는 변화가 있었습니다.
A change in the 2.6.31 Linux kernel made the net.ipv4.conf.default.rp_filter = 1 more strict in the I/O that is accepted. Consequently, in Red Hat Enterprise Linux 6, if there are multiple interfaces on the same subnet and I/O is sent to the one that is not the default route, the I/O will be dropped. Note that this applies to iSCSI iface binding when multiple interfaces are on the same subnet. To work around this, set the net.ipv4.conf.default.rp_filter parameter in /etc/sysctl.conf to 0 or 2, and reboot the machine.
2.6.31 커널을 사용하는 리눅스배포판부터 rp_filter의 기본값이 0에서 1로 변화하였다고 합니다. 그래서 SUSE Enterprise Server 11이나 Redhat Enterprise Server 6.0은 앞서와 같은 문제가 발생한 것입니다. 물론 이전 버전은 아마도 문제가 없었을 듯 합니다.
크게 도움을 받았습니다. 정말 감사합니다.^^
큰 도움? 작은 도움이라도 주었다고 하니 저도 좋네요. 감사합니다.