Skip to content
Gyumin Sim edited this page Dec 22, 2015 · 53 revisions

Project I-ACK wiki

Build & Install Instruction

한 일

  • 11월 4일 ~ 11월 10일
    • AP용 학내 IP(WAN) 받기
    • 과방에 AP 설치
    • OpenWrt & Ath9k 컴파일
    • AP에 OpenWrt & Ath9k 설치
  • 11월 11일 ~ 11월 17일
    • Github 저장소 생성
    • base_file 위치 찾기 rc.local 등
    • OpenWrt 컴파일 시 kernel 코드 받아오는 방식 파악
    • OpenWrt를 qemu로 실행하는 방법 파악
  • 11월 18일 ~ 11월 24일
    • 네트워크 관련 리눅스 커널 문서 조사
    • 리눅스 커널 문서 읽기
    • ath9k에서 frame 보내는 곳과 ACK 처리하는 소스코드 위치 확인
  • 11월 25일 ~ 12월 1일
    • Ath9k 모듈 새로 업로드 하면, AP가 알아서 업데이트 하도록 스크립트 추가 및 서버 구축
    • compat-wireless 저장소 분리 (linux-openwrt 저장소의 compat-wireless 브랜치로 관리)
    • openwrt build system 이해하고 Makefile 수정해서 local git repository와 연동
    • ethernet frame이 만들어져서 ath9k 드라이버까지 오는 경로 파악
    • TCP packet 감지할 위치와 ACK packet을 준비할 위치 파악
      • 관련 정보는 struct ieee80211_tx_info 에 담아두고 ath9k에서 ACK를 처리할 때 전송함.
  • 12월 2일 ~ 12월 8일
    • 구현
    • 실험
      • 아마존 서버에서 다운로드 => 잘 됨.
      • 개인 서버에서 다운로드(파일 크기 500KB) 하면서 서버 쪽에서 패킷 캡쳐 => 잘 됨, ACK가 두 개(만들어 준 것과 원래 STA이 보내는 것) 보임.
      • 개인 서버에서 큰 파일(100MB 이상) 다운로드 => 1~2MB 받았을 쯤 끊김, STA가 L2 ACK은 보냈지만 TCP 패킷은 손실됨.
        • 원인은 실제로 STA에서 받을 수 있는 AWnd를 무시하고 L4 ACK에 AWnd 값을 하드코딩 했기 때문에 실제로는 receive buffer에 여유가 없어서 드랍.
  • 12월 9일 ~ 12월 15일
    • AP에서 user가 IACK을 껐다 켰다 할 수 있게 작업 중
    • STA에서 TCP DATA에 대한 ACK을 안 보내도록 작업 중
  • 12월 16일 ~ 12월 22일
    • AP에 IACK을 보내는 커널 모듈과 아닌 커널 모듈을 둘 다 올려놓고, IACK 기능을 켜고 끌 수 있는 스크립트 작성
    • TCP DATA에 대한 ACK을 보내지 않도록 커널을 수정하고, 수정한 커널과 정상 커널 둘을 준비하여, 노트북에 virtual machine으로 두 개 커널을 바꿔가며 부팅할 수 있게 세팅
      • OS는 Ubuntu trusty
      • 노트북은 실험용 AP에 Wi-Fi 연결
      • VM은 bridged network
    • AP에서 IACK을 켰을 때와 껐을 때, STA에서 ACK을 켰을 때와 껐을 때, 총 4가지 설정 조합에 대해, 다운로드(작은 파일 12KB, 큰 파일 175MB) 실험
        1. AP IACK OFF, STA ACK ON: 당연하지만 정상적으로 작동한다.
        1. AP IACK OFF, STA ACK OFF: TCP handshake 이후에 멈춘다.
        1. AP IACK ON, STA ACK ON: 서버에 ACK이 두 개씩 오지만, 다운로드가 된다. 큰 파일은 시작하고 얼마 안돼 멈춘다(AWnd 때문).
        1. AP IACK ON, STA ACK OFF: 서버에 ACK이 한 개씩 오고, 다운로드가 된다. 큰 파일은 시작하고 얼마 안돼 멈춘다(AWnd 때문).
    • 아마존 서버에서 테스트 클라이언트를 실행 했을 때, 1을 기준으로 한 3, 4의 성능 비교
      • 3은 throughput이 0.35% 감소
      • 4는 throughput이 0.44% 증가
      • 테스트를 너무 짧게(1~2초) 해서 통계적으로 의미 있는 수치는 아닌 것으로 판단된다.
      • RTT가 약 200ms인데 ACK을 하나 덜 보내서 아낄 수 있는 시간은 1ms가 채 안되기 때문에 성능 향상을 보기 어려울 것이다.
      • RTT를 최대한 줄여서 IACK의 성능 향상 효과를 크게 해보기 위해, 첫번째 숙제에서 구현 했던 서버와 클라이언트로 학내망에서 다시 실험해 볼 계획이다.
    • 보고서 작성
    • 데모 영상 촬영

메모

Github 저장소

AP 정보

  • 설치 장소: 301동 314호
  • MAC(WAN): C4:6E:1F:ED:41:A7
  • MAC(LAN): C4:6E:1F:ED:41:A8
  • IP(WAN): 147.46.124.131
  • IP(LAN): 192.168.1.1

하드웨어 정보

  • ISA: MIPS MIPS 74Kc
  • CPU: AR9344 560 MHz
  • RAM: 128 MiB
  • WLAN 1: SoC-integrated: Atheros AR9340 2x2 MIMO for 2.4GHz 802.11b/g/n
  • WLAN 2: separate Chip: Atheros AR9580 3x3 MIMO for 5GHz 802.11a/n
  • Switch: Atheros AR8327N
  • Bootloader: U-Boot

리눅스 커널 문서

Kernel 코드 받아올 곳 변경 방법

  1. make menuconfig
  2. Advanced Configuration Options
  3. Enter git repository to clone
  4. Type "https://github.com/sim0629/linux-openwrt.git"
  5. Ok - Save - Exit
  6. make target/linux/clean && make

Kernel에 curl 빌트인 하기

  1. make menuconfig
  2. Network - File Transfer - curl 켜기

ath9k 작업하기 전에 읽을 문서들

다음의 구현이 실제로 활용되고 있는 것 같아서 확인해볼 필요가 있다.

ath9k에서 ACK 받아온 것을 알게 되는 위치

  • drivers/net/wireless/ath/ath9k/xmit.cath_tx_complete() 함수. 여기서 TCP 연결 정보에 접근할 수 있게 세팅해주고 TCP ACK를 만들어서 쏘아주면 될 것 같다.

ath9k local repository 설정

이미 openwrt repository를 clone했고, 8035b2e39... 를 받아왔다고 가정한다.

cd /somewhere/
git clone --branch compat-wireless [email protected]:sim0629/linux-openwrt.git compat-wireless
cd /some/other/place/openwrt
ln -s /somewhere/compat-wireless/.git package/kernel/mac80211/git-src
make menuconfig
  • 여기서 [*] Advanced configuration options (for developers) ---> 설정하고 들어간다.

  • [*] Enable package source tree override를 설정한다.

이제 다음을 수행하면, /somewhre/compat-wireless/ repository의 HEAD를 가져와서 커널 모듈을 생성한다.

make package/kernel/mac80211/clean
make package/kernel/mac80211/compile

다음은 모듈을 찾을 수 있는 곳이다. ./staging_dir/target-mips_34kc_uClibc-0.9.33.2/root-ar71xx/lib/modules/3.10.49/에 있는 것을 사용하면 된다.

mac80211 모듈 컴파일 할 때 kernel module 설정

{M} kmod-ath
<M> kmod-ath9k
{M} kmod-ath9k-common
{*} kmod-cfg80211
{M} kmod-mac80211

모듈만이 아니라, openwrt image를 컴파일 할 때에는 반드시 ppt에 나온 설정을 따라야 한다.

ethernet frame이 IEEE802.11로 만들어져서 전송되는 과정

net/mac80211/tx.c

(    )ieee80211_xmit -> update skb
( in )ieee80211_tx
( in )invoke_tx_handlers -> 암호화 (이 이후로는 skb에서 암호화된 내용만 보인다)
(over)__ieee80211_tx
( in )ieee80211_tx_frags
( in )drv_tx() (이것은 ath9k_tx()를 불러주는 함수임)

driver/net/wireless/ath/ath9k/xmit.c

ath9k_tx()

tcp 패킷 관련

tcp packet을 실제로 조립하는 건 net/ipv4/tcp_output.ctcp_transmit_skb에 방법이 있다. include/uapi/linux/tcp.hstruct tcphdr이 실제 TCP header의 구조. include/uapi/linux/ip.hstruct iphdr이 실제 IP header 구조.

  • ip_input.c ip_rcv()
  • ip_output.c ip_build_and_send_pkt()
  • tcp_input.c
  • tcp_output.c tcp_transmit_skb()

sk_buff 구조

간단히 생각하면, 프레임이 담긴 buffer이다. 커널 모듈 등에서는 패킷 데이터 같은 것들은 다 여기로 담긴다고 생각하면 편하다.

버퍼와 데이터가 담긴 부분을 나타내는 포인터는 head, data, tail, end가 있다. 실제 데이터가 담긴 범위는 [data, tail)이고, 할당된 영역은 [head, end)이다. 각 포인터는 skb->head, skb->data, skb_tail_pointer(skb), skb_end_pointer(skb)로 얻어와야 한다.

http://vger.kernel.org/~davem/skb_data.html 를 참고하면 좋다.

sk_buff를 자동으로 routing하고 전송하도록 하기

원래는 driver에서 프레임 등을 receive하는 부분에서 호출하는 함수로 netif_rx()가 있다. 이것의 NAPI 버전은 netif_receive_skb()이다.

netif_rx()에서 backlog에 넣어두면, 나중에 process_backlog()에서 __netif_receive_skb()로 처리하는데, 여기서는 __netif_receive_skb_core()를 불러서 본격적으로 패킷을 분석한다.

NAPI인 netif_receive_skb()에서는 __netif_receive_skb()가 비교적 일찍 불린다.

이 함수들은 net/core/dev.c에 있다.

mac80211에서 receive할 때

ieee80211_rx_handlers가 온갖 걸 다 함 ieee80211_deliver_skb를 잘 봐두자. netif_receive_skb를 호출해서 마무리

Custom 커널 컴파일

STA에서 TCP DATA에 대한 ACK을 전송하지 않도록 구현해서 테스트 해보기 위한 참고 문서

빠르게 custom 커널 virtual machine에다가 설치하는 방법

  1. Host와 virtual machine사이에 폴더 공유
  2. Host machine에서 컴파일 (make menuconfig, make bzImage, make modules)
  3. Virtual machine에서 설치 (sudo make modules_install, sudo make installl)

Custom kernel에서 shared folder 접근하는 기능을 다시 설치해야 됨으로 원 kernel에서 조작하는게 좋음.

Ubuntu 시작할때 Grub Menu항상 보이게 하기

  1. sudo vi /etc/default/grub
  2. Then comment-out GRUB_HIDDEN_TIMEOUT, and change GRUB_TIMEOUT to -1
  3. Save & exit
  4. subo update-grub
  5. sudo reboot