2012-07-05 4 views
4

나는 Tap0에서 모든 트래픽을 Eth0으로 보내고 Eth0에서 모든 트래픽을 Tap0으로 보냅니다. 온라인으로 많은 예제를 찾은 후에, 나는 그것을 잘 만들 수있었습니다. 내가 가진 문제는 성능이 매우 낮다는 것입니다.Scapy로 낮은 성능

스크립트를 사용하지 않고 VM 2 개를 핑하는 데 1 밀리 초가 걸리지 않습니다. 스크립트로 ~ 15ms가 걸립니다.

scp를 사용하여 VM에서 다른 것으로 10MB 파일을 보낼 때 평균. 전송 속도는 스크립트없이 12Mbps입니다. 스크립트로 1Mbps 미만으로 내려갑니다.

저는 파이썬이 실제로 네트워크 트래픽을 처리하는 가장 빠른 언어가 아니라는 것을 알고 있습니다. 그러나 느린가?

이 코드를 최적화 할 수있는 방법이 있습니까?

내 VM은 Ubuntu 10.04 32 비트입니다. 여기

코드입니다 :

import os,sys,getopt,struct,re,string,logging 

from socket import * 
from fcntl import ioctl 
from select import select 

from scapy.all import * 

TUNSETIFF = 0x400454ca 
IFF_TAP = 0x0002 
TUNMODE = IFF_TAP 

ETH_IFACE = "eth0" 
TAP_IFACE = "tap0" 

conf.iface = ETH_IFACE 

# Here we capture frames on ETH0 
s = conf.L2listen(iface = ETH_IFACE) 

# Open /dev/net/tun in TAP (ether) mode (create TAP0) 
f = os.open("/dev/net/tun", os.O_RDWR) 
ifs = ioctl(f, TUNSETIFF, struct.pack("16sH", "tap%d", TUNMODE)) 


# Speed optimization so Scapy does not have to parse payloads 
Ether.payload_guess=[] 

os.system("ifconfig eth0 0.0.0.0") 
os.system("ifconfig tap0 192.168.40.107") 
os.system("ifconfig tap0 down") 
os.system("ifconfig tap0 hw ether 00:0c:29:7a:52:c4") 
os.system("ifconfig tap0 up") 

eth_hwaddr = get_if_hwaddr('eth0') 

while 1: 
r = select([f,s],[],[])[0] #Monitor f(TAP0) and s(ETH0) at the same time to see if a frame came in. 

#Frames from TAP0 
if f in r: #If TAP0 received a frame 
    # tuntap frame max. size is 1522 (ethernet, see RFC3580) + 4 
    tap_frame = os.read(f,1526) 
    tap_rcvd_frame = Ether(tap_frame[4:]) 
    sendp(tap_rcvd_frame,verbose=0) #Send frame to ETH0 

#Frames from ETH0 
if s in r: #If ETH0 received a frame 
    eth_frame = s.recv(1522) 
    if eth_frame.src != eth_hwaddr:   
    # Add Tun/Tap header to frame, convert to string and send. "\x00\x00\x00\x00" is a requirement when writing to tap interfaces. It is an identifier for the Kernel. 
    eth_sent_frame = "\x00\x00\x00\x00" + str(eth_frame)  
    os.write(f, eth_sent_frame) #Send frame to TAP0 
+0

REPL 외부에서 와일드 카드 가져 오기 ('*')를 사용하지 마십시오. – jfs

+0

프로파일 러는 무엇을 말합니까? 병목은 어디에 있습니까? – jfs

+0

어떻게 결국 문제를 해결 했습니까? –

답변

3

는 솔직히 말해서, 나는 그것뿐만 아니라 그대로 예비 성형 놀라게하고있다. 이미 당신보다 훨씬 잘 할 수 있다면 놀랄 것입니다.

마음에 패킷이 사용자-육교 건너하기 위해 수행해야하는 경로 유지 :

커널에, NIC 드라이버를 통해, 하나의 인터페이스에서 오는, 그것은에 컨텍스트 스위치 기다려야합니다 사용자가 코드에서 평가할 수 있기 전에 scapy protocol abstractions를 clime해야만하는 user-land. scapy 프로토콜 추상화 (아마도 파이썬 사용자 공간에서 패킷을 재조합)를 보내고, 소켓에 쓰여지고, 커널 토지로 다시 돌아가는 것을 기다리고, NIC 드라이버에 쓰여지고 마지막으로 보내집니다. 인터페이스 ...

이제 링크를 통해 핑 (ping) 할 때, 전체 프로세스를 두 번 수행하는 데 걸리는 시간을 측정합니다.

컨텍스트를 커널에서 사용자 토지로 4 회 전환 (각 방향 당 2 회)하고 0.015 초 내에 수행 할 수 있다고 생각하려면 꽤 좋습니다.

1

나는 비슷한 문제를 가지고 : 링크에서 disected scapy's source code

당신이 보내기를 호출 할 때마다 갖고있는 것 같아요 그() 또는 sendp() Scapy가 자동으로 만들고 보내는 모든 패킷에 대한 소켓을 닫습니다! 나는 편의를 볼 수있어 API가 훨씬 간단 해졌습니다! 그러나 나는 기꺼이 내기가 확실히 성과에 걸립니다!

또한 similar analysis here (link2)입니다. 따라서 link2의이 샘플 코드를 따라 최적화 할 수 있습니다.

#The code sample is from 
#https://home.regit.org/2014/04/speeding-up-scapy-packets-sending/ 
#also see https://byt3bl33d3r.github.io/mad-max-scapy-improving-scapys-packet-sending-performance.html for similar sample. This works. 
def run(self): 
    # open filename 
    filedesc = open(self.filename, 'r') 
    s = conf.L2socket(iface=self.iface) #added 
    # loop on read line 
    for line in filedesc: 
     # Build and send packet 
     # sendp(pkt, iface = self.iface, verbose = verbose) This line goes out 
     s.send(pkt) #sendp() is replaced with send()