[완료] skb_clone을 이용한 packet forwarding 질문

seraphino의 이미지

안녕하세요. 아래 목적을 달성하기 위하여 간단한 검증 성 코드를 작성하여 실했하였습니다.

#########목적##############
skb_clone을 이용하여 kernel에 수신된 packet의 ip와 port를 변경하여 다수의 상대방에게 전송하도록 한다.
1.1.1.1 20000 -> kernel -> 1.1.1.2 50002 (A)
kernel -> 1.1.1.2 50258 (B)

일단 1.1.1.1 20000을 수신하면,
원 skb의 IP, port를 바꾸어 A로 전송하고,
skb_clone한 newskb를 이용하여 B로 전송하려 합니다.

이때, newskb의 h와 nh를
kmalloc( sizeof(struct udphdr) + sizeof(struct iphdr), GFP_ATOMIC);
kmalloc으로 생성한 데이터에 새로운 ip와 port를 넣어서 전송하려 합니다.

############ 문제점#################
간단한 테스트 코드를 짰는데, A로 전송하는 것 까지는 성공하였습니다.
그런데, B로 전송하기 위해 아래 코드를 추가 하였습니다.

struct iphdr* newIph = kmalloc( sizeof(struct udphdr) + sizeof(struct iphdr), GFP_ATOMIC);
struct udphdr* newUdph = NULL;

if(newIph==NULL){
mpLogMod( MPMOD_MIN, "pfem: ERROR [forward_pkt] udphdr is NULL!\n" );
return -1;

}

newskb->nh.iph = newIph;
memcpy(newIph, iph, sizeof(struct iphdr) );

newUdph = (struct udphdr *)((char *)newIph + (newIph->ihl << 2));

newUdph->dest=udph->dest+1;
newUdph->source=udph->source;
newUdph->len=udph->len;
newUdph->check=udph->check;

newskb->h.uh = newUdph;
iph = newskb->nh.iph;

############console log ###################
_23 [xpfemOpen: 951] CRIT open block.pid = 5701

skb_under_panic: text:c05bb6b9 len:250952990 put:14 head:eefc3000 data:e006f432 tail:eefc3150 end:eefc3680 dev:eth0
------------[ cut here ]------------
kernel BUG at net/core/skbuff.c:111!
invalid opcode: 0000 [#1]
SMP
last sysfs file: /block/hda/removable
Modules linked in: xpfem(U) autofs4(U) hidp(U) rfcomm(U) l2cap(U) bluetooth(U) sunrpc(U) ipv6(U) xfrm_nalgo(U) crypto_api(U) ip_conntrack_netbios_ns(U) ip_conntrack(U) nfnetlink(U) xt_tcpudp(U) iptable_filter(U) ip_tables(U) x_tables(U) dm_multipath(U) video(U) sbs(U) backlight(U) i2c_ec(U) button(U) battery(U) asus_acpi(U) ac(U) lp(U) pcspkr(U) i2c_piix4(U) i2c_core(U) e1000(U) parport_pc(U) parport(U) ide_cd(U) cdrom(U) serio_raw(U) dm_snapshot(U) dm_zero(U) dm_mirror(U) dm_mod(U) ata_piix(U) libata(U) sd_mod(U) scsi_mod(U) ext3(U) jbd(U) uhci_hcd(U) ohci_hcd(U) ehci_hcd(U)
CPU: 0
EIP: 0060:[] Tainted: G VLI
EFLAGS: 00010246 (2.6.18-prep #1)
EIP is at skb_under_panic+0x37/0x45
eax: 00000077 ebx: ef583000 ecx: 00000086 edx: 00000000
esi: ef583000 edi: 00000800 ebp: 00000000 esp: c072be00
ds: 007b es: 007b ss: 0069
Process swapper (pid: 0, ti=c072b000 task=c06713c0 task.ti=c06e7000)
Stack: c06539a8 c05bb6b9 0ef53d1e 0000000e eefc3000 e006f432 eefc3150 eefc3680
ef583000 eb4f6440 eefbac00 c05bb6be ef583000 eb4f6440 eefad080 eefbac00
eef9f1c0 c05b4d9f eefad0a8 00000000 0ef53d10 ef583000 ef583000 00080286
Call Trace:
[] eth_header+0x37/0xee
[] eth_header+0x3c/0xee
[] neigh_resolve_output+0x15e/0x1dc
[] eth_header_cache_update+0x0/0x21
[] neigh_update+0x2ae/0x34d
[] arp_process+0x495/0x4d0
[] e1000_xmit_frame+0x9be/0xa08 [e1000]
[] e1000_xmit_frame+0x9be/0xa08 [e1000]
[] arp_rcv+0xd0/0xea
[] netif_receive_skb+0x2b1/0x325
[] e1000_clean_rx_irq+0x347/0x41c [e1000]
[] e1000_clean+0x6b/0x21f [e1000]
[] process_timeout+0x0/0x5
[] net_rx_action+0x92/0x175
[] __do_softirq+0x5a/0xbb
[] do_softirq+0x52/0x9d
[] apic_timer_interrupt+0x1f/0x24
[] mwait_idle+0x25/0x38
[] cpu_idle+0x9f/0xb9
[] start_kernel+0x379/0x380
=======================
Code: 0f 45 de 53 ff b0 a8 00 00 00 ff b0 a4 00 00 00 ff b0 a0 00 00 00 ff b0 9c 00 00 00 52 ff 70 60 51 68 a8 39 65 c0 e8 e0 bf e7 ff <0f> 0b 6f 00 41 39 65 c0 83 c4 24 5b 5e c3 56 53 8b 70 14 bb 2b
EIP: [] skb_under_panic+0x37/0x45 SS:ESP 0068:c072be00
<0>Kernel panic - not syncing: Fatal exception in interrupt

이런 에러를 찍으며 kernel panic이 발생하네요..
아마도 skb 조작을 잘못한 거 같은데 어떻게 하면 해결 할 수 있을 까요?

그리고 이와 관련하여 참조할 책이나 자료가 있으면, 알려 주시면 감사합니다. :)

wariua의 이미지

skb->nh.iph는 skb->data에 들어있는 데이터 가운데 네트워크 계층 헤더 시작점을 가리키지요. 그런데 skb->nh.iph는 새로 할당한 버퍼를 가리키고 (게다가 그 버퍼에는 데이터링크 헤더가 들어갈 자리도 없고) skb->data는 원래의 패킷 데이터를 가리키고 있으니 어디선가 잘못된 메모리 참조가 일어날 만도 합니다.

또한 skb의 data를 변경할 거라면 skb_clone()보다는 skb_copy()가 더 적합합니다.

struct sk_buff 구조체의 구조와 연산에 대해선 "sk_buff"로 검색하면 잘 정리된 자료들을 꽤 찾으실 수 있습니다.

한편으로... 하시려는 게 "skb를 복사해서 지정된 주소로 보내기"라면 netfilter의 TEE target 소스(~linux/net/netfilter/xt_TEE.c)를 참고하실 수도 있습니다. 목적 주소 변경은 하지 않지만 skb를 복사해서 내보낸다는 동작은 마찬가지이므로 skb 처리 방식을 참고하실 수 있습니다.

$PWD `date`

seraphino의 이미지

답변 감사드립니다. :)

skb_copy는 우선 차선책으로 사용해 보려고 합니다.
skb_clone을 사용하여 packet 데이터를 복사 하지 않고 헤더 buffer만 복사 또는 조작하여
network 성능을 향상 시키는 게 목적이거든요.

추후 성공한 다면, 여기에 답변을 달아 보겠습니다. :)

태훈의 이미지

꼭 커널에서 해야하는 이유가 있나요?

커널단에서 해야하는 것이 목적이 아니고 포워딩 하는 것만 목적이시면 pcap 라이브러리를 사용하시면 편리하게 하실 수 있습니다.

Just do it!

seraphino의 이미지

pcap이라 그것도 알아 봐야 겠네요.
커널 단에서 최대한 메모리 copy를 줄여 network 성능 향상을 시켜 보려는 목적에
이것을 시작했거든요 :)

답변 감사드립니다.

seraphino의 이미지

결과적으로 skb_clone으로는 불가능 합니다.
애초에 개념을 잘못 잡은 것 같습니다.
OSI 규격에 맞지 않는 짓을 하려 했군요. ;;;;
skb_copy가 답이네요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.