2012-07-05 190 views
4

我正在創建一個腳本,它向Tap0發送所有流量給Eth0,並向Eth0發送Tap0的所有流量。在網上找到很多例子後,我設法讓它工作。我遇到的問題是性能非常低。Scapy的低性能

不使用腳本而在2個虛擬機之間進行ping操作的時間少於1ms。用腳本需要〜15ms。

當我發送一個10 MB的文件從一個虛擬機到另一個使用scp,平均。沒有腳本的傳輸速率是12 Mbps。隨着腳本降低到不到1 Mbps。

我知道Python實際上並不是處理網絡流量的最快的語言,但它是否很慢?

有沒有一種方法來優化此代碼?

我的虛擬機是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 2012-08-24 18:56:52

+0

探查者說什麼?哪裏是瓶頸? – jfs 2012-08-24 19:08:25

+0

最後如何解決你的問題? – 2013-10-18 21:27:42

回答

3

說實話,我很驚訝,它的預成型,以及它是。如果你能比現在做得更好,我會感到驚訝。

記住一個數據包必須遵循跨用戶,陸橋路徑:

即將在一個接口,通過網卡驅動程序,進入內核,那麼它​​必須等待上下文切換用戶所在地,在它可以通過你的代碼進行評估之前,它必須使scapy協議抽象成爲可能。隨後你的代碼發送回scapy協議抽象(可能在python用戶空間中重新組裝),寫入套接字,等待上下文切換回內核區,寫入NIC驅動程序,最後被髮送出去接口......

現在,當您ping通該鏈接時,您需要測量整個過程兩次 - 一次和一次返回所需的時間。

要考慮從內核到用戶的上下文切換4次(每個方向2次),並且您可以在0.015秒內完成 - 這相當不錯。

1

我有類似的問題:從一個鏈接,似乎有 disected scapy's source code

每次調用的send()或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()