Systems/Unix / Linux2012/05/08 12:23

제가 쓰고 있는 Linux 배포판은 Centos입니다. 이 배포판에는 FUSE, 그러니까 Filesystem In Userspace 모듈이 함께 깔려 있습니다. 이 모듈은 사용자가 커널이 아닌 사용자 주소 공간에서 파일 시스템을 만들 수 있도록 해 줍니다. 


FUSE 프로젝트의 웹사이트는 http://fuse.sourceforge.net/ 입니다.


이 웹사이트에 가보시면 예제 파일이 하나 있습니다. hello world 파일 시스템이 그것인데요. 이 예제 파일 시스템을 컴파일하려면 약간의 준비작업이 필요합니다. 


먼저, 수퍼유저 계정으로 가셔서 다음과 같이 합니다.


#> yum install fuse-devel 


이렇게 하시면 fuse 라이브러리를 사용해서 파일 시스템을 구현하는 데 필요한 헤더 파일이 설치됩니다. 헤더 파일이 설치되는 위치는 대략 다음과 같습니다.


/usr/include/fuse.h

/usr/include/fuse/*.h


헤더 파일의 설치가 끝나면 이제 웹 사이트에 올려져 있는 예제 파일 시스템을 컴파일해 볼 수 있습니다. 


#> gcc hello.c


그런데 이렇게 하시면 아마 컴파일이 잘 안되실 겁니다. 



-D 플래그를 사용하라니까 그렇게 해 줘야 겠죠. 그런데 그렇게 해 봐도 잘 안됩니다. 



이 문제를 해결하기 위해서는 fuse.h의 documentation에 적혀 있는 다음과 같은 문구를 참조해야 합니다.



그러니까, 결국 다음과 같이 컴파일 해 줘야 하는 셈입니다. 



그런데 보시면 아시겠지만 그렇게 해도 뭔가 잘 안된다는 걸 알 수 있죠. 예제에 사용된 소스코드의 버전이 낮아서 그런 것인데요 (오픈소스 프로젝트에서 종종 발견되곤 하는 문제입니다), 따라서 소스 코드를 다음과 같이 수정해줘야 합니다. 즉, fuse_main을 호출하는 부분에 맨 마지막 인자로 0을 (아무것도 넘기지 않는 다는 뜻) 넘겨주어야 합니다. 




이렇게 하고 컴파일하면 잘 되는 것을 확인할 수 있습니다. (오호)



물론 이렇게만 하면 되는 것은 아니고, 실행이 가능하려면 fuse 라이브러리와 링크도 해 줘야 합니다. 그러니 다시 정리하자면, 


#> gcc -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26 -lfuse -o hello -c hello.c


와 같이 해 주셔야 된다는 것이 결론. 물론 소스 코드를 조금 고쳐주셔야 한다는 것은 잊지 마실 것.


저작자 표시 비영리 변경 금지


Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/411 관련글 쓰기

댓글을 달아 주세요

  1. 저에게도 환청이 들려오는 것 만 같습니다 ㅠ
    얘기들 들어보면 정말 대단한 분들이 많지요

    2012/05/10 12:55 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix / Linux2011/08/12 14:50
가상화 Solution중에 OpenVZ라는 것이 있습니다. Linux 기반 커널 위에 '컨테이너(container)'라고 불리는 경량의 독립 공간을 만드는 기술인데요. 보통 가상화라고 하면 별도의 운영체제가 완전히 추상화된 하드웨어 계층 위에 독립적으로 설치되어 돌아가는 것을 상상하는 경우가 많은데 OpenVZ는 좀 다릅니다. 커널은 Host OS의 커널을 공유하고, 그 위에 개별적인 OS quota를 주는 형식에 더 가깝죠.

그래서 '커널이 다른 OS를 OpenVZ로 가상화 하는 것은 곤란' 합니다.

자세한 사항은 www.openvz.org 에 가셔서 알아보시기 바라구요. 지금부터는 OpenVZ를 이용해 CentOS 5.6을 여러 개의 CentOS 5 머신으로 가상화하는 방법을 살펴보겠습니다. (이 문서는 작성일 이후 1년쯤 뒤에는 더 이상 참고자료로서 활용되지 못할 수 있으므로 주의하세요. 작성일은 2011년 8월 12일입니다.)

1. Centos 5.6 설치

OpenVZ는 아직 CentOS 6.0을 지원하지 않고 있습니다. (이 문서 작성일을 기준으로) 그래서 CentOS 5.6을 설치합니다. http://ftp.daum.net/centos/5.6/isos/i386/CentOS-5.6-i386-bin-DVD.torrent 링크를 클릭하셔서 torrent 프로그램을 통해 운영체제 이미지를 다운받고, 이미지를 DVD로 구워서 설치하시면 됩니다. torrent 프로그램으로는 uTorrent를 쓰시면 되겠군요.

운영체제 설치하실 때는 가급적 /vz/ 파티션을 따로 잡아주시고, 해당 파티션은 반드시 ext3 파일 시스템을 사용하도록 해 주세요. 이 아래에 가상 머신 이미지들이 들어간다고 보시면 됩니다.

2. OpenVZ 설치

설치가 끝나고 재부팅이 되면, 다음을 실행합니다.

# cd /etc/yum.repos.d
# wget http://download.openvz.org/openvz.repo
# rpm --import  http://download.openvz.org/RPM-GPG-Key-OpenVZ
# yum install ovzkernel
이제 OpenVZ 커널이 설치되었으니 부트로더를 수정할 순서입니다. /boot/grup/grub.conf 파일을 열어보면 아마 다음과 같은 항목이 추가되었을 겁니다.

title OpenVZ (2.6.8-022stab029.1)
        root (hd0,0)
        kernel /vmlinuz-2.6.8-022stab029.1 ro root=/dev/sda5
        initrd /initrd-2.6.8-022stab029.1.img
이제 재부팅할때 OpenVZ를 선택하면 되는데, 그 때 마다 OpenVZ를 수동으로 선택하는 것은 귀찮으니까 이 파일 안에 있는 default= 뒤에 있는 숫자를 OpenVZ에 할당되어 있는 숫자로 (아마 십중팔구 0일 겁니다) 바꾸어 주세요.

그런 다음에는 이제 sysctl 파일을 ( /etc/sysctl.conf ) 변경해야 합니다.

# On Hardware Node we generally need
# packet forwarding enabled and proxy arp disabled
net.ipv4.ip_forward = 1
net.ipv6.conf.default.forwarding = 1
net.ipv6.conf.all.forwarding = 1
net.ipv4.conf.default.proxy_arp = 0

# Enables source route verification
net.ipv4.conf.all.rp_filter = 1

# Enables the magic-sysrq key
kernel.sysrq = 1

# We do not want all our interfaces to send redirects
net.ipv4.conf.default.send_redirects = 1
net.ipv4.conf.all.send_redirects = 0
없는 항목은 추가하고, 있는 항목의 값은 적절히 바꾸어 주세요.

그런 다음에는 /etc/sysconfig/selinux 파일을 고쳐서 다음과 같이 해야 합니다.

SELINUX=disabled
그런 다음 재부팅 하시고,

이제 OpenVZ 사용에 필요한 파일을 다음과 같이 해서 깔아줍니다.

# yum install vzctl vzquota
x86_64 플랫폼이면 다음과 같이 해야 한다고 하는군요. 저는 안해봤습니다.

# yum install vzctl.x86_64 vzquota.x86_64
자. 그럼 이제 OpenVZ 설치는 끝난 겁니다. 다음과 같이 해서, 실행합시다.

# /sbin/service vz start
여기까지 하면 이제 OpenVZ 커널 모듈이 올라가 있을 것입니다. 시스템이 재부팅되었을 때 이 마지막 절차를 또 해야 하는지는 잘 모르겠군요.





3. 가상머신 생성

자. 그럼 이제 가상머신을 생성해 보죠. 가상머신을 생성할 때에는 소위 가상머신 템플릿이라는 것이 /vz/template/cache/ 디렉터리 아래에 있어야 합니다. wget http://download.openvz.org/template/precreated/centos-5-x86.tar.gz 같이 입력해서 다운받습니다. 그리고 해당 디렉터리 아래에 갖다놓습니다. 그리고 다음과 같이 합니다.

# ln -s /vz/template/cache/centos-5-x86.tar.gz /vz/template/cache/centos-5.tar.gz
가상머신 생성은 굉장히 간단합니다.

# vzctl create 1011
이렇게 하면 1011번 가상머신이 만들어집니다. 그럼 해당 가상머신을 설정해보죠.

# vzctl set 1011 --hostname 1011.xxxx.re.kr --save
# vzctl set 1011 --ipadd 10.0.0.11 --save
# vzctl set 1011 --nameserver 1.2.3.4 --save
# vzctl set 1011 --userpasswd root:rootpasswd
호스트 이름, 가상머신의 IP 주소, 네임서버, 패스워드 등은 적절히 입력해 주세요. ^^ 그런 다음 가상머신을 다음과 같이 실행합니다.

# vzctl start 1011
그런 다음 ssh 10.0.0.11해 보시면, 해당 가상머신으로 SSH 접속이 가능함을 확인하실 수 있을겁니다. :-)

SSH 접속 후에 외부로 PING을 해보면 가상 머신을 설치한 기계의 IP주소 외에는 PING이 안될수도 있습니다. 주로 가상머신에 사설 IP 주소를 할당한 경우에 그러한데요.

그런 경우에는 가상 머신을 설치한 HOST 운영체제에 IP_TABLE을 조작해서 NAT처럼 동작하도록 만들어줘야 합니다. 여러분이 설치한 기계의 IP 주소가 192.168.5.4라고 해 볼까요? 그럼 다음과 같이 하시면 됩니다.

# iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j SNAT --to 192.168.5.4

그리고 나서는 firewall 설정을 변경해줘야 합니다.

# /sbin/iptables -A RH-Firewall-1-INPUT -s 10.0.0.0/24 -j ACCEPT
# /sbin/iptables-save > /etc/sysconfig/iptables
# /sbin/service iptables restart

간혹 VE 안에서 DNS가 안되는 경우가 있는데, 그런 경우가 발생하면 강제로 DNS 포트를 개방해야합니다.

# /sbin/iptables -A RH-Firewall-1-INPUT -p udp --dport 53 -j ACCEPT
이렇게 하면 VE 안에서 네트워킹도 웬만하면 다 되실겁니다. 뭔가 안되는 프로그램이 있다면 (yum 같은 것이 안될 수도 있습니다) 관련된 포트를 찾아서 열어주면 됩니다 (yum의 경우에는 80 포트를 개방해야 합니다.) 이거 저거 다 귀찮으실 때는 모든 ip 프로토콜을 다 개방하는 방법도 있습니다. 좀 껄쩍지근하긴 하지만 -A RH-Firewall-1-INPUT -p ip -j ACCEPT 처럼 하시면 되겠습니다.

각각의 컨테이너에 프로그램을 깔때는 vzctl exec를 사용하면 편합니다.

# vzctl exec 1011 yum -y install gcc autoconf automake

4. Troubleshooting

4.1. Java

Java를 설치하고 실행하면  Error occurred during initialization of VM : java.lang.OutOfMemoryError: unable to create new native thread 같은 오류가 뜨면서 java가 실행이 안될때가 있습니다. 그럴때는 java -Xmx64m 처럼 해 보실 것. 안되면 64보다 더 낮은 값으로 낮추는 것도 괜찮습니다. 그래도 해결이 안되실 때는 http://forum.openvz.org/index.php?t=msg&goto=7057 이 쓰레드를 참고하실 것.

4.2 메모리 등의 자원 부족

OpenVZ 컨테이너 안에서 메모리 등의 자원 부족 현상이 발생할 경우, 쓰레드가 안뜬다거나 자바 가상 머신이 안돈다거나 하는 문제가 생길 수 있습니다. 그럴 때는 해당 자원을 늘려주어야 하는데요. http://wiki.openvz.org/Resource_shortage 여기 언급된 대로 실제 물리적 기계 상에서 cat /proc/user_beancounters 를 해 보면 각각의 컨테이너 ID 별로 어떤 자원이 부족해서 문제가 생겼는지를 파악할 수 있습니다. failcnt에 0 아닌 숫자가 찍히거든요.

그런 문제가 생기면 문제가 생긴 자원을 두배로 늘려줘 보세요. 하는 방법은 다음과 같이 하시면 됩니다. 물리적 메모리의 양을 화면에 표시된 barrier, limit의 값의 두 배 값으로 setting하는 예제입니다.

# vzctl set 1011 --kmemsize $((2752512*2)):$((2936012*2)) --save





Posted by 이병준
TAG centos, OpenVZ

TRACKBACK http://www.buggymind.com/trackback/357 관련글 쓰기

댓글을 달아 주세요

Systems/Unix / Linux2011/08/11 17:18
가장 단순하게 맥북을 백업하고 하드 디스크를 교체하기 위한 절차를 살펴보면 (OS X Lion 기준) 다음과 같습니다.

1. 백업

가장 먼저 해야 할 일은 백업을 하는 것입니다. 백업을 하는 가장 단순한 방법은 (1) 외장 하드디스크를 연결하고 (2) 해당 하드디스크를 타임머신(Time Machine) 디스크로 만든 다음(아래 그림에서 '디스크 선택...'을 클릭하시면 됩니다) (3) 백업하는 것입니다.

이렇게 하면 나중에 하드 디스크를 교체하고 해당 하드 디스크에 Lion을 다시 설치하는 절차가 굉장히 단순해 집니다. 절차는 http://support.apple.com/kb/ht1427?viewlocale=ko_KR&locale=ko_KR 이 링크를 참고하시면 됩니다.

이 그림 파일의 저작권은 Apple Korea에 있습니다.



2. Mac OS X Lion 설치 디스크 만들기

설치 디스크를 만드는 절차는 http://www.buggymind.com/349 이 글에 소개한 바 있습니다. 이 절차를 따라 설치 디스크를 생성합니다.



3. 하드 디스크 교체

이제 하드 디스크를 물리적으로 교체해야 하는데요. 맥북 프로의 경우에는 http://blog.naver.com/PostView.nhn?blogId=luke1011&logNo=70089111055 이 글을 참고하시면 됩니다. 아주 깔끔하게 정리가 잘 되어 있습니다.

4. 만들어 둔 설치 디스크로 재부팅

설치 디스크를 DVD 트레이에 넣고, 재부팅합니다. 재부팅하면 아마 다음과 같은 화면을 보게 될 것입니다.


이 화면에서 Restore Frome TIme Machine Backup을 하면 되는데, 하드 디스크가 새것이므로 먼저 파티션을 만들어 줘야 합니다. Disk Utility를 선택하고 들어가서 아무 것도 없는 여러분의 새 디스크에 통짜 파티션을 하나 만들어 줍시다.

그런 다음에 위의 화면으로 다시 돌아와서 Restore From Time Machine Backup, 즉 타임머신 백업으로부터 복구를 선택합시다. 복구할 백업을 선택하라는 말이 나오면 최신 백업을 선택합시다. 백업 선택 후에는 이제 대상 하드 디스크를 선택해 줘야 하는데, 아까 파티션을 잡는 절차를 안했으면 아무 디스크도 나오지 않을 것입니다. 파티션을 잡았다면, 나올 터이니 그 하드 디스크를 선택합시다.

나머지 절차는 전부 맥이 알아서 해 줄 터이고, 시스템 복구가 끝나고 나면 여러분의 OS 상태는 하드 디스크를 교체하기 직전 상태로, 깔끔하게 정리되어 있을 겁니다.

Olleh! (Windows를 쓸때는 이렇게 깔끔하게 하드를 교체한 적이 없었는데.. ㅎㅎㅎ)



Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/356 관련글 쓰기

댓글을 달아 주세요

  1. 이번에 맥북에 SSD을 설치하려는 데 참고할께요. 타이머신을 해서 SSD로 복원하는 데 복원 마지막에 오류가 나서 애먹고 있어요

    2011/09/21 00:43 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix / Linux2011/07/26 15:56
라이언 설치 과정은 앞선 글에서 살펴본 대로 두 단계로 나뉜다. (1) 설치 App 다운로드 (2) 설치. 근데 성질이 급해서 (2)를 완료하신 분들은 아쉽지만 설치 디스크를 만들기가 거의 불가능하다. 설치 App이 이미 디스크에서 사라져버렸기 때문이다.

복구 파티션에서 설치 디스크 이미지를 추출할 방법은 없나?

http://www.hyemi.org/26504 에 나오는 대로 복구 파티션을 마운트해서 보면 BaseSystem.dmg 파일이 있어야 하는데, 실제로 해 보면 없다. 아니, 터미널에서는 보이는데 이 파일을 마운트하거나 공 DVD에 기록할 방법이 없다. diskutil도 이 파일을 읽지 못한다. Lion 정식 버전에서는 BaseSystem.dmg를 볼 수 없도록 꽁수를 쓴 듯. 카피 도중에는 보이는데 카피가 끝나면 다시 볼 수 없는 상태가 된다.

저 파일이 보이지 않는다



그렇다면 설치 App을 다시 받을 수 있는 방법은 없나?

있다. App Store로 다시 가자. OS X 라이언으로 가는 링크가 대문짝만하게 보일 것이다. 이 상태에서 "Option" 키를 누르고 링크를 클릭한다. 그러면 묘하게도 "설치됨"으로 나와 있어야 할 콤보박스가 "29.99$"로 바뀐다. 다시 다운 받을 수 있다는 뜻.

하지만 그냥은 안된다. 역시 "Option" 키를 누르고 해당 버튼을 클릭해야 한다. 그래야 Apple Id 비번을 물어보면서 다시 다운로드 한다.

이제 설치 디스크를 만들 수 있다 

이제 https://iglassbox.wordpress.com/2011/07/20/mac-os-x-lion-%EB%B6%80%ED%8C%85-dvd-%EB%A7%8C%EB%93%A4%EA%B8%B0/ 에 기술된 방법을 써서 설치 디스크를 만들 수 있다. 

내부가 이렇게 생겨먹었다


 
설치 디스크를 만들어 두면 언제 써먹나? 하드를 일반 하드에서 SSD 등으로 교체하였을 경우 유용하다. 하드를 교체한 경우에는 설치 CD가 없으면 곤란하다. 갖고 있는게 Snow Leopard CD밖에 없다면? Lion 설치하자고 이전 운영체제를 통째로 다 설치한 다음에... 귀찮은 과정일 거라는 감이 팍팍 오실 듯.



실제로 재설치를 시도해 보면?

뭐 굳이 강조할 필요 없는 이야기지만... 타임머신에 백업을 받아놓든 뭘 하든 일단은 백업을 잘 받아 두자. 그리고 나서 재설치를 시도해 보면...

위의 방법으로 만든 디스크는 엄밀한 의미에서의 "설치용 배포판"은 아니라는 사실이 감이 딱 온다. 오히려, Lion으로 업그레이드 하면 생기는 "Recovery HD" 파티션 안에 들어있는 이미지에 가깝다. 구동되고 나면, 타임머신 백업으로부터 복원할 건지, 파티션부터 나눌 건지, 친절하게 물어보는 걸로 봐서 그렇다. 

요런 화면이 뜬다. Recovery HD로 부팅한 화면과 똑같다. http://www.cultofmac.com/mac-os-x-lion-adds-recovery-partition-support-gallery/83737

 

어쨌든, Recovery HD에 있는 내용과 똑같은 부팅 디스크를 얻었으니, 이제 맥이든 맥북이든 하드디스크 교체와 같은 빡센 작업을 할 때 활용해먹을 수 있다.

 


Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/349 관련글 쓰기

  1. 박상의 생각  삭제

    2011/07/26 23:03TRACKBACK FROM sanghyun's me2day

    OS X Lion 설치 종료 후 설치 디스크 만들기 역시 방법이 있는거군요. 미친병아리님도 참고하세요.

댓글을 달아 주세요

Systems/Unix / Linux2011/05/02 12:53
MAC에서 pdflatex 쓰실 때, 그림을 넣는 방법이 아마 여러가지 있을 겁니다. eps로 넣어도 되고, pdf로 넣어도 되고, 이도 저도 안되면 png같은 그림 파일로 넣는 방법도 있겠죠.

맥에서라면 아마 pdf파일로 많이들 넣으실 겁니다. MAC의 pdf 편집 기능이 워낙 강력해서일테죠. 논문 작성하시는 분이라면 아마 LaTeX Equation Editor + Keynote로 그림을 그린 후, 그 그림을 복사한 다음에 미리보기를 열어서 메타+N 키를 누르시겠죠. 그러면 복사된 그림이 PDF 페이지 안에 바로 붙여넣기 되고, 그 파일을 저장하면 바로 'pdf 파일 형태의 그림'이 만들어 집니다. 

LaTeX Equation Editor를 쓰면 PDF 페이지 안에 수식도 자유롭게 만들어 넣을 수 있으니 꽤 강력한 조합입니다.


그런데 LaTex Equation Editor를 써서 PDF 파일에 수식을 삽입하고, 그 수식을 다시 *.tex 파일 안에 집어넣을 때는 조심하셔야 합니다. 뭘 조심하셔야 하느냐면, 수식을 '회전(rotate)'시키지 않도록 조심하셔야 한다는 거죠.

회전시킨 수식을 포함하는 PDF 파일을 *.tex 파일에 삽입한 후 pdflatex으로 변환해 pdf 파일을 만들고 나면, 그 파일은 MAC에서는 제대로 보일런지 몰라도 Windows에서 Acro Read X로 열어보면 Acro Read X 프로그램이 죽어버립니다. ㅎㅎ

그러니, 가능하면 pdf 파일 안에 수식을 포함시키실 때는 그 수식을 회전시키지 마세요. ^^







Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/328 관련글 쓰기

댓글을 달아 주세요

Systems/Unix / Linux2011/03/04 18:04
이 파일은 원래 KAIST에서 학위논문을 LaTeX로 작성하기 위해 필요한 파일이었습니다. 이 파일을 조금 고쳐서, 충남대학교에서, 특히 컴퓨터공학과에서 학위논문을 LaTeX로 작성하기 위한 클래스 파일로 만들었습니다. 이 클래스 파일의 원저자이신 채승병님께 감사드립니다. 그 분이 없었더라면 논문 작성 쉽게 못했을겁니다.

이 파일의 사용법은 크게 어렵지 않습니다. 예제 파일 phd.tex 의 내용을 잠시 보여드리면...


\documentclass[doctor,korean,final]{cnu-ecs}

% kaist.cls 에서는 기본으로 dhucs, ifpdf, graphicx 패키지가 로드됩니다.
% 추가로 필요한 패키지가 있다면 주석을 풀고 적어넣으십시오,
%\usepackage{...}
%

%\usepackage{kotex}
\usepackage{multirow}
\usepackage{varwidth}

%\renewcommand\tablename{표}
%\renewcommand\figurename{그림}

\newtheorem{theorem}{Theorem}

% @command title 논문 제목
% @options [default: (none)]
% - korean: 한글제목 | english: 영문제목
\title[korean]{가용성이 높고 규모 확장이 용이한\linebreak 망 관리 시스템 구조}
\title[english]{A Scalable and Highly Available\linebreak Network Management Architecture}

\author[korean] {이}{병 준}
\author[english]{Lee}{Byungjoon}

\advisor[major]{이 영 석}{Youngseok Lee}{signed}

\department{CSE}

% @command studentid 학번
\studentid{200560000}

% 논문제출일
\submitdate{2011}{4}{1}

% @command approvaldate 지도교수논문승인일
% @param   year,month,day 연,월,일 순으로 입력
\approvaldate{2011}{6}{15}

% @command refereedate 심사위원논문심사일
% @param   year,month,day 연,월,일 순으로 입력
\refereedate{2011}{6}{1}

% @command gradyear 졸업년도
\gradyear{2011}{8}

% 본문 시작
\begin{document}

% 목차 (Table of Contents) 생성
\tableofcontents

% 표목차 (List of Tables) 생성
\listoftables

% 그림목차 (List of Figures) 생성
\listoffigures

% 위의 세 종류의 목차는 한꺼번에 다음 명령으로 생성할 수도 있습니다.
%\makecontents


\chapter{서론}

\section{개요}

망(network)이 고도화됨에 따라, 효과적으로 망을 관리하는 일은 점점 
더 어려워지고 있다. \ldots

\chapter{관련 연구}

\section{다계층 구조}

흔히 다계층 구조(multi-tier architecture)라 부르는 계층구조는 
어떤 소프트웨어의 규모 확장성을 높이고자 할 때 가장 먼저 
고려되는 구조 가운데 하나이다. \ldots

\chapter{결론}

오늘날의 망은 그 규모와 복잡성 면에서 날로 변화하고 있다.
클라우드 컴퓨팅 센터의 등장은 단순히 사용자가 자신의 데이터를 
인터넷 너머 어딘가에 저장할 수 있다는 것에 그치지 않고,
그 방대한 양의 데이터를 저장하기 위해 필요한 서버와 디스크들이 
어떻게 연결되어야 하는지, 그리고 그 연결이 만들어내는 새로운 형태의
대규모 망을 관리하려면 어떠한 망 관리 시스템이 필요한지에 
관한 새로운 물음들을 던지고 있다. \ldots

% references section

% can use a bibliography generated by BibTeX as a .bbl file
% BibTeX documentation can be easily obtained at:
% http://www.ctan.org/tex-archive/biblio/bibtex/contrib/doc/
% The IEEEtran BibTeX style support page is at:
% http://www.michaelshell.org/tex/ieeetran/bibtex/
%\bibliographystyle{IEEEtran}
% argument is your BibTeX string definitions and bibliography database(s)
%\bibliography{IEEEabrv,../bib/paper}
%
% <OR> manually copy in the resultant .bbl file
% set second argument of \begin to the number of references
% (used to reserve space for the reference number labels box)
\begin{thebibliography}{1}

\bibitem{greenberg}
A. Greenberg, J. Hamilton, D.A. Maltz, and P. Patel,
\emph{The cost of a Cloud: Research Problems in Data Center Networks},
ACM SIGCOMM Computer Communication Review (CCR), 
Vol. 39, No. 1, pp. 68-73, January 2009.

\bibitem{wallin}
S. Wallin, V. Leijon, 
\emph{Telecom Network and Service Management: An Operator Survey}, 
MMNS, 2009.

\bibitem{hscalability}
Wikipedia, \emph{Horizontal Scalability},
\url{http://en.wikipedia.org/wiki/Scalability#Scale_horizontally_.28scale_out.29}

\end{thebibliography}

% 한글초록
\begin{summary}
현대의 망은 다양한 종류의 장비로 구성되며, 여러 계층을 포함하기 때문에 복잡도가 높고,
다량의 장비가 설치되는 대규모 망이다. 
\ldots
\end{summary}

% 영문초록 (abstract)
\begin{abstract}
Modern networks are large-scale, composed of many layers with tens of thousands of devices. 
Cloud computing data centers and multi-layered transport networks are 
examples of such networks.
\ldots
\end{abstract}

\chapter*{감사의 글}

감사의 글을 적으시면 되겠습니다.
감사합니다.

\begin{flushright}
\vspace{1cm}
이병준 배상
\end{flushright}

\end{document}

뭐 이정도만 적으면 나머지는 충분히 알아서 하실 수 있으리라 믿고... 완벽하게 수정된 파일은 아닙니다만 일단 충남대학교 컴퓨터공학과에서 소기의 목적을 달성하는 데는 충분하리라 사료됩니다. 

파일은 여기에서 다운받으세요. ^^ 




Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/307 관련글 쓰기

댓글을 달아 주세요

Systems/Unix / Linux2010/10/27 09:17
autoconf를 통해 만들어진 소프트웨어를 cross-compiling하는 것은 생각보다 단순합니다. ./configure를 실행할 때 ./configure --target=mip64-linux 뭐 이런식으로 타겟 시스템 이름을 적어주면 됩니다. 물론 이때는 시스템에 크로스 컴파일링을 위한 mip64-linux-gcc 등이 깔려 있어야 합니다. 적어주지 않으면 그 때는 target 시스템은 host 시스템과 동일하게 간주되므로, 크로스컴파일링이 되지 않습니다.

문제는 컴파일하려는 대상 프로젝트가 다른 autoconf 프로젝트에 dependency를 가지고 있을 때인데, 이런 경우에는 피의존 프로젝트부터 순차적으로 크로스 컴파일링을 해야 합니다. 주의해야 할 점은 부모 프로젝트 (의존하는 프로젝트)가 자식 프로젝트(피의존 프로젝트)가 설치되어 있는지를 미리 찾아보고, 시스템에 설치되어 있지 않는 경우에는 configuration을 아예 포기한다는 점인데요. 이를 편리하게 우회하기 위해서는 약간의 꽁수를 부릴 필요가 있습니다.

먼저 피의존 프로젝트를 그냥 컴파일해서 설치합니다. 그러면 아마 /usr/local 밑에 해당 프로젝트가 깔릴 겁니다.

그런 다음에 피의존 프로젝트를 크로스 컴파일 해서 설치합니다. 이 때 prefix는 /usr/local이 아닌 다른 임의의 디렉토리로 지정합니다.

그런 다음 크로스 컴파일된 피의존 프로젝트의 바이너리를 /usr/local/lib과 /usr/local/bin 밑에 적절히 복사합니다.

그런 다음 부모 프로젝트를 크로스 컴파일합니다. 이 떄 prefix는 역시 /usr/local이 아닌 다른 임의의 디렉토리로 지정합니다.

만일 부모-자식 관계가 2단계 이상 길어지는 경우에는 위의 과정을 recursive하게 반복해주어야 합니다. 그러니 부모 프로젝트를 컴파일 할 때도 '그냥 컴파일'과 '크로스 컴파일'을 두 번 다 해주어야 합니다. 그래야 그 부모 프로젝트에 의존하는 '조부모' 프로젝트가 컴파일 될 수 있죠.

이런 삽질은 autoconf가 /usr/local 밑에 설치된 프로젝트를 자동으로 detect하고, 그 detection 과정을 override하기가 까다롭다는 점 때문에 발생합니다.

아무튼 위의 절차를 계속 반복하다 보면 크로스 컴파일 자체도 기계적인 과정이 되기 때문에, 아무리 큰 프로젝트라도 한 반나절 정도면 대충 크로스컴파일 할 수 있습니다.

물론 컴파일할 프로젝트들이 autoconf로 잘 packaging 되어 있다는 가정 하에서.


Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/293 관련글 쓰기

댓글을 달아 주세요

Systems/Unix / Linux2010/07/13 11:20
Mac OS X에서 pthread_t 타입은 opaque 타입이다. 간단하게 말하면, int나 uint32_t와 같은 간단한 타입이 아니라, 그 내부 구조에 의존적인 프로그래밍을 하면 안되는 구조체 타입이라는 뜻이다.

보통은 그렇다고 해서 문제가 생길 일은 없는데, 멀티 쓰레드 디버깅을 하려다 보면 문제가 간혹 불거질 때가 있다. 가령 보통의 Unix 플랫폼에서는 다음과 같은 디버깅 매크로를 작성하면 원하는 위치에서 내가 살펴보고자 하는 정보를 화면에 찍어 볼 수가 있다.

#define DUMP(PRNSTR,...)  printf( \
 "dumping   [%08u,%s,%04d] " #PRNSTR "\n", \
 (uint32_t)pthread_self(), __FILE__,__LINE__,__VA_ARGS__)

그러니까 무슨 말인고 하니, 다음과 같이 하면 꼭 printf 하듯이 필요한 정보를 화면에 찍을 수 있다는 소리이다.

DUMP("%d", int_variable);

그러면 화면에 쓰레드 아이디, 파일 이름, 라인 넘버까지 포함된 디버깅 정보가 쭉 찍힌다.

그런데 Mac OS X에서 pthread_self()가 반환하는 pthread_t 값은 opaque타입이기 때문에 uint32_t 타입으로 캐스팅 하려는 시도 자체가 아예 불가능하다. -_-

그래서 다음과 같은 꽁수를 써야 한다. (대체 뭐하는 짓인지...)

#define DUMP(PRNSTR,...)  printf( \
 "dumping   [%08ld,%s,%04d] " #PRNSTR "\n", \
 pthread_self()->__sig, __FILE__,__LINE__,__VA_ARGS__)

WIN32 환경이라면 다음과 같이 해야 할 것이다.

#define DUMP(PRNSTR,...)  printf( \
 "dumping   [%05d,%s,%04d] " #PRNSTR "\n", \
 GetCurrentThreadId(), __FILE__,__LINE__,__VA_ARGS__)

UNIX 소스를 Mac OS X, Win32에까지 신경써서 포팅하려면 실제 코드 말고도 이런 디버깅 매크로에까지, 신경써줘야 할 것들이 무지 많다.

- - -

최근에 이런 짓을 하면서 살다 보니, 인생이 피곤할 뿐 아니라 손가락도 저리다. 잡문 "프로그래머"는 지금 3부 2절까지 완결된 상태이다. 12절까지 작성되면 출판사로 넘겨드릴 생각인데 과연 받아주실 지는 불투명하다는... (내가 봐도 영 구려서.. ㅋㅋ)



Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/282 관련글 쓰기

  1. 공중곡예사의 생각  삭제

    2010/07/13 12:31TRACKBACK FROM bjlee72's me2DAY

    MAC OS X에서의 pthread_t

댓글을 달아 주세요

Systems/Windows2010/07/13 11:12
일반적인 Unix 플랫폼에서는 멀티 쓰레드 응용 프로그램을 작성하기 위해 pthread 라이브러리를 활용한다. pthread 라이브러리는 자체적으로 conditional variable을 지원하기 때문에, 그것을 활용해서 쓰레드간 동기화를 편하게 할 수 있다. 

그런데 WIN32 플랫폼에 이르면, Vista 전까지는 conditional variable을 지원하지 않았다. 따라서 conditional variable을 사용하기 위해 직접 conditional variable 기능을 구현하는 삽질을 해야만 했다.

하지만 vista 부터는 (Windows 7도 당근) conditional variable을 지원한다. 다음과 같이 사용하면 된다.

우선, pthread와 마찬가지로 conditional variable을 통한 동기화를 하려면 critial section과 같이 써야 한다. (pthread 라이브러리에서는 mutex와 같이 써야 했다.)

CRITICAL_SECTION critical_section;
CONDITION_VARIABLE conditional_variable;

초기화는 다음과 같이 한다.

// 이하는 전부
// pthread_mutexattr_init
// pthread_mutex_init
// pthread_condattr_init
// pthread_cond_iint에 대응한다.
InitializeConditionVariable(&conditional_variable);
InitializeCriticalSection(&critical_section);

다 쓰고 나면 삭제해 줘야 한다.

// 이하는 전부
// pthread_condattr_destroy
// pthread_cond_destroy
// pthread_mutexattr_destroy
// pthread_mutex_destroy에 대응한다.
DeleteCriticalSection(&critical_section);

conditional variable에 대한 락, 그러니까 동기화 지점에 대한 락은 critical section을 통해 해야 한다.

// pthread_mutex_lock에 대응
EnterCriticalSection(&critical_section);

락 해제는 다음과 같이 한다.

// pthread_mutex_unlock에 대응
LeaveCriticalSection(&critical_section);

특정한 조건이 만족되었는지 무한 대기하려면 다음과 같이 한다. (오류 체크 코드는 싹 다 뺐다.)

// pthread_cond_wait에 대응
SleepConditionVariableCS(&conditional_variable, &critical_section, INFINITE);

일정한 시간 동안만 대기하려면 다음과 같이 하면 된다. (초 단위로 대기하려는 경우)

// pthread_cond_timedwait에 대응
SleepConditionVariableCS(&conditional_variable, &critical_section, second * 1000);

조건이 충족되었을 경우 conditional variable 상에서 기다리고 있는 쓰레드들을 깨우는 방법으로는 다음의 두 가지가 있다.

// pthread_cond_signal에 대응
WakeConditionVariable(&conditional_variable);
// pthread_cond_broadcast에 대응
WakeAllConditionVariable(&conditional_variable);

위의 WIN32 프리미티브들을 활용하면 WIN32 쓰레드를 conditional variable을 활용하여 동기화할 수 있다. (Windows에서는 condition variable 이라고 부른다.)


Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/281 관련글 쓰기

  1. 공중곡예사의 생각  삭제

    2010/07/13 12:31TRACKBACK FROM bjlee72's me2DAY

    WIN32에서의 Conditional Variable

댓글을 달아 주세요

Systems/Unix / Linux2010/03/08 14:57
xfig로 그린 그림에 latex 수식을 삽입하고 싶을 때가 있습니다. 그럴때는 다음과 같은 절차를 따르면 됩니다. pdflatex을 쓰신다고 가정했지만, 다른 경우에도 비슷하지 않을까 싶습니다.

우선 문서에 \usepackage{graphicx}, \usepackage{color}의 두 가지 패키지를 적용합니다. \documentclass와 \begin{document} 사이입니다. 

그런 다음에, xfig로 그림을 그립니다. 텍스트를 넣을 때, 수식 부분은 $\mathcal F(p_{i,j})$와 같이 해서 넣어줍니다. 이렇게 수식을 텍스트 안에 포함시키는 경우, 해당 텍스트 부분을 "Edit" 버튼을 누른 다음 클릭하면 다이얼로그 박스가 뜨는데요. 그 창에 보면 "Special Flag"를 지정하는 콤보박스가 있습니다. 클릭해서 "Special"로 바꾸어 줍니다. 수식을 포함하는 모든 텍스트에 대해서 같은 짓을 반복해 주어야 합니다.

그런 다음에 그림을 저장하고, export합니다. export할 때에는 Language를 "Combined PDF/LaTeX (both parts)"를 선택합니다. 그런 다음 파일 명을 지정하는데, query.pdf와 같이 pdf 확장자를 갖도록 지정합니다.

그러면 파일이 두 개 만들어집니다. query.pdf와 query.pdf_t의 두 개 입니다.

이제 이 그림을 *.tex 문서 안에 포함시켜야 합니다. 포함시킬 때에는 다음과 같이 합니다.

\begin{figure}[t]
\centerline{
    \scalebox{0.63}{
        \input{query.pdf_t}
    } 
}
\caption{Communication using the result of a \emph{query}}
\label{query}
\end{figure}

이렇게 하면 그림 안에 포함시킨 모든 수식이 LaTeX 수식으로 바뀌어 포함됩니다.

문제가 생기면 보통 \usepackage를 제대로 해 주지 않아서 생기는 문제입니다. 필요한 패키지가 전부 문서에 포함되었다면, 특별한 문제 없이 제대로 되어야 합니다.

별건 아닌 팁인데, 하다 보니까 필요할 때 까먹기 쉬운 팁이라 포스팅해 봅니다. ^^ 이렇게 해서 만든 그림은 다음과 같은 모습을 하고 있습니다.


올려놓고 보니까 그림이 좀 작군요. ㅎㅎ

도움이 되셨기를...



Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/268 관련글 쓰기

댓글을 달아 주세요

  1. june8th

    IPE를 사용해보세요. http://en.wikipedia.org/wiki/Ipe_(program)
    수식이 많이 들어간 경우 인생이 편해집니다.

    2010/03/18 18:34 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix / Linux2008/06/14 16:54
Ubuntu 8.04를 설치하고 gcc를 실행하여 c 파일을 컴파일하려고 했을때 위와 같은 오류가 발생하는 경우가 있다. 이 경우, 다음과 같이 해 주면 문제가 해결된다.

sudo apt-get install libc6-dev

참고링크:

http://ubuntuforums.org/showthread.php?t=190193



Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/137 관련글 쓰기

댓글을 달아 주세요

Systems/Windows2008/06/09 16:06
이 책을 번역한지 꽤 시간이 지난거같습니다만, 최근에 이 책의 11장에 실린 예제에 관한 메일 두통을 받았습니다. 11장에 실린 예제가 이해하기 어렵다는 것이었습니다. 10장까지의 내용을 잘 따라하신 분이라면 그다지 큰 무리없이 하실 수 있을것 같은데 말이죠. 그래서 11장에 실린 내용에 잘못된 부분이 있나 검증도 해 볼겸, 한번 책의 예제를 그대로 따라해봤습니다.

사용자 삽입 이미지
우선 MFC AppWizard(exe)를 선택합니다.

사용자 삽입 이미지
SDI 프로그램을 만들어야 하니까, Single Document를 선택합니다.

사용자 삽입 이미지
대화상자를 하나 그립니다. 이 대화상자의 ID는 IDD_MAP_MODE로 해 놓습니다. 콤보 박스를 하나 그리고, 그 박스의 ID는 IDC_COMBO로 해 놓습니다. 여기까지는 간단합니다.

사용자 삽입 이미지
다이얼로그 박스를 다 그린다음에는 ctrl+W를 누르거나 다이얼로그 박스 그림을 더블클릭해서 해당 다이얼로그 박스에 대한 새로운 클래스를 만듭니다. 이름은 위와 같이 적어주면 됩니다.

사용자 삽입 이미지
그런 다음,  IDC_COMBO에 대한 멤버 변수를 추가합니다. 위의 화면에서 IDC_COMBO를 클릭한 다음에, Add Variable을 눌러주면 됩니다.

사용자 삽입 이미지
그러면 위와 같은 창이 뜨는데, 역시 위와 같이 입력해주고 OK하면 됩니다.

사용자 삽입 이미지
그런 다음에는 다이얼로그 박스 그림으로 돌아가서, 콤보 박스의 Property를 편집합니다. Data 부분에 위와 같이 적어주면 됩니다. 여러줄을 적으려면, 리턴 키를 누를 때 Ctrl키를 같이 누르면 됩니다.

사용자 삽입 이미지
이제 새로운 메뉴 항목을 보기(View) 아래에 추가할 차례입니다. 빈 곳을 더블클릭하면 아래와 같은 화면이 나타날 것입니다.

사용자 삽입 이미지
위의 화면에 역시 위와 같이 입력해 줍니다.

사용자 삽입 이미지
그런 다음에는 추가된 메뉴위에서 마우스 오른쪽 버튼을 클릭한 다음에 ClassWizard를 선택합니다.

사용자 삽입 이미지
위와 같이, Object ID가운데에서는 ID_VIEW_MAP_MODE를 선택하고, 오른쪽에 나타나는 Messages 가운데에서는 COMMAND를 선택합니다. 그런 다음에 Add Function 버튼을 누릅니다.

사용자 삽입 이미지
위와 같은 화면이 나타날텐데, 거기에 위와 같이 입력되어 나타날 것입니다. 그대로 OK 버튼을 누릅니다.

사용자 삽입 이미지
이제 소스 코드 편집창이 나타날 것인데, 거기에 책에 실린 소스코드(목록 11.3)를 입력합니다.

사용자 삽입 이미지
위와 같이 DCTestView.h 코드도 수정합니다.

사용자 삽입 이미지
include 해 주는 부분도 위와 같이 수정합니다.

사용자 삽입 이미지
이제 CDCTestView::OnDraw를 수정할 차례입니다. 위와 같이 선택한 다음에 (Ctrl + W를 누르면 나오는 화면입니다) 우측의 Edit Code 버튼을 누릅니다. 그런 다음 목록 11.5에 실린 코드를 입력합니다.

사용자 삽입 이미지
입력이 다 되었으면, 이제 마지막으로 CDCTestView 클래스의 생성자를 수정합니다.

사용자 삽입 이미지
코드를 정상적으로 입력하였다면 (그렇지 않았다면 에러메시지가 떴을 테지만) 위와 같은 메시지가 화면에 출력되는 것을 볼 수 있습니다. MAP MODE를 바꾸려면 아까 추가했던 메뉴 항목을 클릭하고 콤보 박스 안의 다른 항목을 선택한 다음 OK를 눌러주면 됩니다.

두 분이나 질문하실 만큼 그렇게 난감한 대목은 찾을수가 없네요. ^^;

아무튼, 위와 같이 하시면 되구요. 혹시 몰라서 예제 코드를 첨부합니다.




Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/133 관련글 쓰기

댓글을 달아 주세요

Systems/Unix / Linux2008/06/05 17:29
이 글은 Fedora Core 6에 Skype를 설치하는 방법을 다룬다. 전반부에 소개한 방법은 아래의 문서에 기술된 방법을 참고한 것이다.

http://kaiser.wordpress.com/2007/09/15/installing-skype-on-fedora-core-6/

후반부에 기술한 방법은 필자가 개인적으로 경험한 결과를 정리한 것이다. 삽질의 길은 멀고도 험하다 -_-;

[첫번째 방법]

yum으로 설치한다. yum install skype하면 끝.

그런데 skype를 repository에서 찾을 수 없다면 설치가 아마 안될 것이다. 그런 경우가 발생하면, /etc/yum.repos.d/ 아래에 skype.repo 파일을 만들고, 다음과 같이 입력한다.

[skype]
name=Skype Repository
baseurl=http://download.skype.com/linux/repos/fedora/updates/i586/
gpgkey=http://www.skype.com/products/skype/linux/rpm-public-key.asc
그런 다음에 yum install skype의 명령을 다시 실행한다.

[두번째 방법]

제대로 되었다면 정상 설치가 되어야 하는데, 간혹가다 "Header V3 DSA signature" 어쩌구 하는 메시지가 포함된 Warning이 뜨면서 설치가 안될 수 있다. (원인은 잘 모른다.)

그럴때는 다음의 절차를 따라한다. 우선

yum install nas
yum install qt4
yum install qt4-x11

위의 세 명령을 순차적으로 실행한다.

그런 다음 http://www.skype.com/download/skype/linux/choose/ 를 방문하여, Fedora Core 6 링크를 클릭하여 rpm을 다운받아 설치한다.

그런 다음 명령행(command line)에서 skype라고 입력하여 실행해 본다. 사용권에 동의할 것인지를 묻는 창이 나오면 성공한 것이다.

+ + +

논문에 필요한 시험을 Linux에서 하는 중인데, 추가 실험을 하려고 하다보니 Skype도 필요하고 이것도 필요하고 저것도 필요하고...

Linux가 '시험'하긴 좋은 운영체제인데, '뭘 좀 편하게' 하려면 이게 또 만만치는 않은듯. 10년 이상을 Unix/Linux를 만졌는데 뭘 좀 해보려고 하면 찾아볼게 한두가지가 아니니... 그래도 고쳐서 뭔가 해볼 수 있다는 걸 다행으로 생각해야 할듯.



Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/132 관련글 쓰기

댓글을 달아 주세요

Systems/Unix / Linux2008/03/18 17:02

원래 글을 잘라서 쓰는 걸 좋아하지 않는데, 제가 번역이다 뭐다 좀 바빴습니다. 양해해 주세요. ^^; 오늘은 저번에 마무리 짓지 못한 나머지 부분을 써 볼까 합니다.

Kprobes에 세 가지 정도의 kernel probe가 준비되어 있다는 이야기는 했습니다. 이 중 커널로부터 뭔가 쓸만한 정보를 알아내는 데 가장 활용도가 높은 것은 Jprobe입니다. 커널 함수를 Hooking할 수 있을 뿐 아니라, 그 함수에 전달되는 인자들까지 살펴볼 수가 있거든요. Jprobe는 다음과 같이 선언합니다. 구조체죠.

#include <linux/kprobes.h>

...

static struct jprobe my_probe = {
    .kp.addr = (kprobe_opcode_t *) udp_sendmsg,
    .entry = (kprobe_opcode_t *) inst_udp_sendmsg
};

udp_sendmsg는 커널 함수의 이름입니다. inst_udp_sendmsg는 후킹 함수의 이름입니다. inst_udp_sendmsg는 udp_sendmsg가 받는 인자들을 똑같이 받도록 정의되어야 합니다. 가령 udp_sendmsg는 다음과 같이 선언되어 있습니다.

// linux/udp.h
void udp_sendmsg(struct kiocb* iocb, struct sock* sk, struct msghdr* msg, size_t len);

그러므로 inst_udp_sendmsg는 다음과 같이 정의되어야 합니다.

static void inst_udp_sendmsg(
    struct kiocb* iocb,
    struct sock* sk,
    struct msghdr* msg,
    size_t len)
{
    ...
    jprobe_return();
}

이 함수의 제일 마지막에서 jprobe_return()을 호출하고 있다는 것을 유의해 보십시다. 이 함수를 호출하지 않으면, 후킹 함수가 1회 실행된 뒤에는 (그러니까 inst_udp_sendmsg가 실행된 뒤에) 커널이 hang되어 아무 작업도 할 수 없는 상태가 되므로 주의해야 합니다.

또 한 가지 주의할 것이 있군요. Jprobe를 정의할 때 구조체의 .kp.addr에 커널 함수의 이름(다시 말해, 커널 함수의 주소, 즉 포인터)을 저장하고 있음을 보실 수 있는데요. 커널 모듈을 컴파일하다 보면 컴파일러가 "그 함수의 정의를 찾을 수 없다"는 오류 메시지를 출력하는 경우를 간혹 보게 됩니다.

그런 경우에는 함수의 이름 대신 함수의 주소를 직접 넘겨주는 방법을 쓰는 것이 제일 속편합니다. 커널에 정의되어 있는 함수들의 주소는 어디 있냐면 (inline 함수 제외) /boot 아래에 있습니다. 이 아래에 보면 System.map-2.6.18-1.2798.fc6과 같은 파일이 있는데, 이 파일을 열어보면 커널 함수들과, 그 함수들의 주소가 전부 적혀 있습니다.

그러니 사실 jprobe를 정의할 때 이렇게 해도 됩니다.

static struct jprobe my_probe = {
    .kp.addr = (kprobe_opcode_t *) 0xc05e7c29,            // 정확한 값은 아닙니다. 대충 적었습니다.
    .entry = (kprobe_opcode_t *) inst_udp_sendmsg
};

이 방법보다 좀 더 우아한 방법으로는 kallsyms_lookup_name()이라는 다른 커널 함수를 사용하는 방법도 있는데, 간혹가다가 컴파일해 보면 이 함수의 정의를 찾을 수 없다고 불평하는 메시지가 나올 때도 있습니다. -_-; 그러니 그냥 속편하게, System.map 파일을 참고하는 것이 제일 나을 것입니다.

아무튼 이렇게 하면, (1) 커널을 후킹하는 함수를 정의하고 (2) 그 함수가 특정 커널 함수 실행 직전에 실행되도록 하여 (3) 그 함수에 전달되는 인자의 값을 검사할 수 있습니다.

가령 위에서 예로 든 예제 함수의 경우, UDP 패킷의 목적지 주소를 알아내고 싶다면 다음과 같이 하면 됩니다.

static void inst_udp_sendmsg(
    struct kiocb* iocb,
    struct sock* sk,
    struct msghdr* msg,
    size_t len)
{
    struct inet_sock* up = (struct inet_sock*)sk;
    printk("destination address = %u\n", ntohl(up->daddr) );

    jprobe_return();
}

자. 그런데 JProbe를 하나 정의한 것만으로는 사실 불충분하구요. 이 프로브를 커널에 명시적으로 심어주는 register_jprobe를 호출해 주어야 비로서 프로브가 커널 함수 호출을 hooking할 수 있게 됩니다. 이 함수 호출 형식은 모든 JProbe 프로브들에 대해서 동일하니까, 다음과 같이 매크로를 정의해두면 좀 편리하게 써먹을 수 있을 것 같습니다.

#define REGISTER_JPROBE(obj) \
    do { \
        if ( register_jprobe(&obj) < 0 ) { \
            printk("registration operation for " #obj " has failed\n"); \
        } \
    } while ( 0 )

#define UNREGISTER_JPROBE(obj) unregister_jprobe(&obj)

이 매크로들은 이전 글에서 설명했던 init_module() 함수와 cleanup_module() 함수에서 다음과 같이 사용합니다.

int init_module(void)
{
    REGISTER_JPROBE(my_probe);
    ...
    return 0;
}

void cleanup_module(void)
{
    UNREGISTER_JPROBE(my_probe);
}

자. 이렇게 하면 커널 프로브를 심는 모듈을 정의하고, 사용할 수 있습니다. 생각보다 어렵지 않습니다. KProbe나 Kretprobe도 이와 비슷한 방식으로 사용이 가능합니다. 나중에 그에 관해서는 따로 소개할 기회가 있을것 같군요. 오늘은 이정도로 마무리 하겠습니다.




Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/119 관련글 쓰기

댓글을 달아 주세요

  1. 안녕하세요 ~!
    kprobe에 관한 흥미있는 글 잘 읽었습니다 :D
    궁금한게 있는데요 kprobe로 후킹을 하다보니 후킹이 되는 함수가 있는가 하면
    안되는 함수들도 있더라구요 특히 register_jprobe()를 사용할 때 등록이 안되는 경우가 많습니다.

    Sysmap으로 확인할 때 코드가 T 인 경우와 t 인경우에 따라서 안되는 경우가 있나요???
    예로 sys_read나 do_fork는 잘 후킹이 되는데 put_queue와 같은 함수는 잘 안되네요 .. ^^;

    2008/08/28 13:33 [ ADDR : EDIT/ DEL : REPLY ]
    • 안녕하세요? 코드가 T인 경우와 t인 경우에 차이가 있는지는 여지껏 생각해보지 않은 문제인데... 새로운 숙제를 주시는군요. ^^;; 제가 요즘 이쪽일을 안하고 있어서.. 시간나는대로 한번 살펴보겠습니다. 좋은 질문 감사해요~

      2008/08/29 09:41 [ ADDR : EDIT/ DEL ]
    • http://unixhelp.ed.ac.uk/CGI/man-cgi?nm 여기를 찾아보니 T는 text section에 있는 global symbol이고 t는 local symbol이라는군요. 제 생각에 local symbol은 참조가 불가능할 것 같습니다. 그 scope가 해당 symbol이 정의된 파일 안으로 한정될것 같거든요. (C에서 static 키워드가 하는 일을 생각해보시면 쉬울듯) 실제로 lxr.linux.no사이트에서 검색해보니 put_queue는 static으로 정의되어 있네요.

      2008/08/29 10:00 [ ADDR : EDIT/ DEL ]
  2. bin00pang

    앗 .. 이렇게나 빠른 답변을 ^^
    정말 감사합니다 ~! 대소문자가 전역과 지역을 나타내는 거였군요
    local symbol에서는 참조가 안된다니 아쉽네요 ㅋ
    다른 방법을 강구해봐야 겠군요 ~
    커널 2.6.x에서 IDT 후킹을 하고 있는데 이게 잘 안되서 지금 죽을맛이에요 ㅎㅎ

    좋은 답변 감사 드립니다 ^^!

    2008/08/29 12:01 [ ADDR : EDIT/ DEL : REPLY ]
    • 별말씀을... 제가 도움이 될것같은 일이 있다면 또 들러주세요. ^^

      2008/08/29 13:12 [ ADDR : EDIT/ DEL ]

Systems/Unix / Linux2008/03/06 12:48

Kprobes는 Linux 커널을 hooking하여, 동적으로 프로브(Probe)를 심을 수 있게 해 주는 기술입니다. Solaris 진영에서는 이와 유사한 기술로 Dtrace라는 것을 제공하고 있습니다만, 아직까지는 리눅스에는 그에 필적할 정도의 커널 hooking/probing 메커니즘은 없습니다. Dtrace는 D라는 프로그래밍 언어까지 제공하고 있죠. 최근 Dprobes와 같이 좀 더 동적인 probing 기술을 개발하고 있는 것 같습니다만, 거기까지는 공부해 보지 못했습니다.

커널 후킹을 하기 위해서는 커널 모듈(kernel module)이라는 것을 만들어야 합니다. 커널 모듈을 만드는 것은 그다지 어려운 일이 아닙니다. 레드햇이라면 우선 kernel-devel 이라는 RPM이 설치되어 있어야 합니다. 그 RPM이 설치되어 있다고 치고, 다음과 같은 Makefilie을 만듭니다.

# Makefile
#
#
# make -C path/to/kernel/src M=`pwd` modules

obj-m := kprobebio.o

위의 Makefile은 kprobebio.c라는 커널 모듈 소스 코드를 컴파일하기 위한 것입니다. 이 소스 코드와 이 Makefile이 있을 때, 다음과 같이 make를 때리게 되면 이제 모듈 코드가 컴파일됩니다.

%> make  -C /lib/modules/`uname -r`/build M=`pwd` modules

모듈 코드를 만드는 것도 크게 어려운 일은 아닙니다. 다음과 같은 기본 골격을 가지면 됩니다.

#include <linux/module.h>
...
int init_module(void)
{
...
}

void cleanup_module(void)
{
...
}

MODULE_LICENSE("GPL");

init_module()은 커널 모듈을 초기화하는 작업을 정의하는 함수입니다. cleanup_module()은 반대로 커널 모듈을 메모리에서 내릴 때 필요한 정리 작업을 정의하는 함수입니다. 이 함수들을 입맛에 맞게 고쳐서, 나름대로의 커널 모듈을 정의할 수 있습니다. 컴파일이 끝난 모듈을 커널에 붙이려면 다음과 같이 하면 됩니다.

%> /sbin/insmod kprobebio.ko

이렇게 하면 커널 모듈을 커널에 붙여 돌릴 수 있습니다.

자. 이제 커널 모듈을 만드는 방법을 알았으니, 실제로 커널 모듈과 KProbes를 사용해 Linux 커널을 후킹하는 방법을 살펴보겠습니다. 그런데, 커널을 후킹하려면, 커널에 어떤 함수들이 존재하는지를 알 필요가 있습니다. 그런데, 커널에 존재하는 함수의 종류와 이름은 커널 버전마다 조금씩 차이가 나는데다 굉장히 많기 때문에, 꼼꼼히 살펴보려고 작정하고 달려들더라도 분석 자체가 힘겹습니다. 커널 소스를 받아서 설치한다고 해도, 그 코드를 vi로 일일이 브라우징하다 보면 곧 포기하게 되죠. ctags같은것을 활용하려고 해도, 코드 자체가 너무 방대해서 무리일 때가 많아요.

그러므로, 커널 소스가 올라오는 웹 사이트를 참고하는 것이 좋습니다. http://lxr.linux.no/ 같은 사이트가 그 중 가장 쓸만한 사이트입니다. 이 사이트에 접속하면 첫 화면에 Browse the code라는 섹션이 있습니다. 이 사이트에서 Linux 2.6.11 and Later 링크를 클릭하면 버전에 맞는 소스 코드를 브라우징 할 수 있습니다. 이 사이트에는 이것 말고도 다양한 버전의 OS 소스 코드가 있습니다. 이 사이트의 좋은 점은, 함수 이름에 대해 인덱스가 걸려 있어서, 링크를 따라 브라우징이 가능하다는 점입니다. 가령 어떤 함수의 실제 코드를 보고 싶으면, 그 함수가 사용된 곳에서 함수 이름을 클릭하면 됩니다. 그러면 그 함수가 정의된 곳으로 데려다 주죠. 같은 이름의 함수가 많을 경우에는 그 함수들의 목록을 보여줍니다. 그 중에서 하나를 고르면 됩니다.

각설하고, 다음은 Kprobes 관련된 자료 중 쓸만한 것들입니다.

1. kprobes를 사용한 커널 디버깅
2. Linux Technology Center: Kernel Probes
3. Kprobes를 사용한 커널 디버깅
4. Gaining insight into the Linux® kernel with Kprobes
5. Linux Kernel Documentation :: kprobes.txt

기타 커널 관련 자료들 중에 봐두면 좋을 것들
1. Linux Kernel : The linkely/unlikely macros

Kprobes 로 심을 수 있는 커널 프로브로는 Kprobe, Jprobe, Kretprobe 등이 있습니다. 이들 각각은 그 용도가 조금씩 다릅니다. Kprobe는 가장 일반적인 프로브로, 특정한 커널 함수가 호출되기 전에 호출됩니다. Jprobe는 같은 용도이긴 한데, 함수에 전달되는 인사들 까지 검사할 수 있습니다. Kretprobe는 함수의 반환값을 알아보기 위한 프로브입니다. 저는 주로 Jprobe를 사용하여 커널을 후킹하고, 함수 인자값을 검사하는 작업을 했습니다. Jprobe를 잘 활용하면, 커널에 대한 디버깅도 OS 중단 없이 해나갈 수 있습니다. prink같은 것을 코드 안에 일일이 삽입해야 할 필요도 줄어들기 때문에 더 편합니다.

다음 글에서는, 실제로 이들 프로브들을 사용해 커널을 후킹하는 방법과 그 사례를 살펴보겠습니다.




Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/113 관련글 쓰기

댓글을 달아 주세요