mininet-wifi無線自組網實現原理及代碼分析


 

mn_wifi\examples\double_xxx_xxxx.py

 

組網圖:

 

 

 

無線自組網實現原理:

對每個node節點(所有的節點的基類都是Node)啟動一個shell進程,記住進程的pid。通過導入的mac80211_hwsim模塊,創建若干個(就是每個nodewlans參數的總和)無線網絡設備(這里包括了phydevphy表示無線網絡設備,dev表示接口,他們是一一對應的關系),把每個網絡設備加入到名稱為"某個進程id"的網絡名字空間里面去。把接口改一下名稱(比如ap1-wlan1改成ap1-mp1)。用hostapd這個程序把每個無線接口配置好,啟動這個無線熱點。addlink的時候,如果是station就使用iwconfig命令把當前的station加入到某個熱點。如果是ap並且是mesh組網的話,使用類似於“iw dev ap1-mp2 mesh join mesh-ssid freq 2432”這樣的命令把這個熱點加入到mesh網絡里面去。然后在controller.startap.start的時候,在對應的shell里面把相關的進程拉起來。這個就完成了整個網絡的搭建過程。

 

代碼分析:

前提,大部分和mininet-wifi自帶的mesh組網的代碼的流程相同。下面只講差異點,mininet-wifi自帶mesh組網代碼分析見下面的連接:

https://www.cnblogs.com/matthew-2013/p/13043617.html

 

net.addParameters(c1, False, node_mode='master', **defaults)

疑問:為什么這里的wlans=1控制器的輸入參數里面沒有wlans參數啊,1是從哪里來的呢?

node.func.append('none')

node.phyID.append(0)

node.params['wlan']里面添加上'c1-wlan1'————這里只是給node分配wlan的名稱,並沒有實際創建或者分配wlan的接口。

node.params['ip'] = ['']

node.params['mac'] = ['']

把node.params 中的 'antennaGain=5.0', 'antennaHeight=1.0', 'txpower=14', 'channel=1', 'mode=g', 'freq=2.412' 參數,設置為默認值。

self.add_range_param(node, **params)  // 把range參數初始化為[0,0]

if node_mode == 'master':

node.params['associatedStations'] = []

node.params['stationsInRange'] = {}

node.params['mac'] = []

node.params['mac'].append('')

設置 node.params['ssid'] 為輸入的參數。注意:無線自組網的ssid有可能是這樣的 ['','2']

node.params['ssid']=['new-ssid']

 

net.configureWifiNodes()

nodes =這里包括3ap1controllor

module(nodes, self.n_radios, self.alt_module, **params)  // nodes=ap+stationn_radios=這個表示當前的網絡里面總的無線網卡的數量,當前是7alt_module=none,

module::__init__

module::start

h = subprocess.check_output // subprocess模塊用來創建新的進程,連接到其stdin、stdout、stderr管道並獲取它們的返回碼在子進程執行命令,以字符串形式返回執行結果的輸出。如果子進程退出碼   不是0,拋出subprocess.CalledProcessError異常,異常的output字段包含錯誤輸出

cmd = ps -aux | grep -ic hostapd  //   統計hostapd進程的數量

process = Popen(stdout=PIPE, *popenargs, **kwargs) // PIPE=-1, popenargs = {tuple: 1} ps -aux | grep -ic 'hostapd', kwargs = {dict: 1} {'shell': True}

但是這個好像也沒有執行這個命令。

output, unused_err = process.communicate()  // 在這里開啟一個子進程,執行上述命令的。ps -aux | grep -ic 'hostapd'  == 統計hostapd進程的數量。

if h >= 2:  // 這里的h等於2.

os.system('pkill -f \'hostapd\'')   // kill掉 hostapd 相關進程。這里為什么要關閉hostapd進程呢?

physicalWlans = module::get_physical_wlan()

wlans = subprocess.check_output("iw dev 2>&1 | grep Interface | awk '{print $2}'", shell=True)).split("\n")

iw dev 2>&1 ————該命令列出了如下接口。

awk '{print $2}'  表示把上述內如輸出到 標准錯誤 里面去。

wlans = ['']  // 這種組網模式下,獲取的接口是空的,為什么呢?

返回wlans  // 這里返回的也是空的。

self.load_module(n_radios, nodes, alt_module, **params)    // 初始化wifi模塊 n_radios=6,nodes=2個station+2個ap

output_ = os.system('modprobe mac80211_hwsim radios=0 >/dev/null 2>&1')  // 導入 mac80211_hwsim 模塊,這個就是wifi模塊。

self.__create_hwsim_mgmt_devices(n_radios, nodes, **params)

cmd = 'find /sys/kernel/debug/ieee80211 -name hwsim | cut -d/ -f 6 | sort'    // 列出 phy

phys = subprocess.check_output(cmd, shell=True).split("\n")  // 執行cmd命令

返回['']  // 返回的phy為空,為什么?

對phys進行遍歷

phy.startswith(self.prefix)  prefix=='mn00s'   Python startswith() 方法用於檢查字符串是否是以指定子字符串開頭,如果是則返回 True,否則返回 False

for i in range(0, n_radios): 當前的n_radios=7

分別執行如下命令,

cmd = ['hwsim_mgmt', '-c', '-n', 'mn00s00']   // 這些命令是使用導入的模塊創建名稱為'mn00s00'mac80211_hwsim 設備。這些命令執行之后,在/sys/kernel/debug/ieee80211/目錄下可以看到'mn00s00'這些目錄都被創建了。注意,這里是devphy是同時創建好了的,並且是一一對應關系;phy應該是表示無線網絡設備,而dev表示無線網絡接口。

...

cmd = ['hwsim_mgmt', '-c', '-n', 'mn00s06']

 

module::get_phy

phy = subprocess.check_output("find /sys/kernel/debug/ieee80211 -name hwsim | cut -d/ -f 6 | sort"

返回 ['mn00s00' ~ 'mn00s06'],共計7phy

self.assign_iface(nodes, physicalWlans, phys, **params)  # 這個函數的作用啟用該無線網絡設備,並分配網絡名字空間。

nodes=3個ap1controller

physicalWlans = []  // 上面獲取的physicalWlans為空。

wlan_list = self.get_wlan_iface(physicalWlans)// 查詢到 wlan0~wlan6 這7個接口

下發 iw dev 2>&1 | grep Interface | awk '{print $2}  命令查詢所有的接口

返回 [wlan0~wlan6 ]7個接口。

for node in nodes:   // 對nodes進行遍歷

for wlan in range(0, len(node.params['wlan'])):   // 對當前節點的wlan參數進行遍歷。

node.phyID[wlan] =0  // 把該節點的物理id分別分配成012…

無論是ap還是controller都做如下操作:

rfkill = subprocess.check_output(rfkill list | grep mn00s00 | awk '{print $1}'| tr -d ":")  // rfkill list  #列出所有可用wifi設備,返回的是rfkill list的前面的哪個序號。

mn00s00前面的索引號是7,所以返回的是 ['7','']

os.system('rfkill unblock %s' % rfkill[0])// rfkill unblock啟用索引號為7wifi設備。

os.system('iw phy %s set netns %s' % (phys[0], node.pid))    // 把這個無線設備放入不同的網絡名字空間。這個命令執行后,phydevrootshell就查詢不到了,應該是加入到node的網絡名字空間了。應該從對應的nodeshell里面查詢才能查詢的到了。

node.cmd('ip link set %s down' % wlan_list[0])   // 關閉wlan0這個無線網絡接口。

node.cmd('ip link set %s name %s' % (wlan_list[0], node.params['wlan'][wlan]))  // 改名,wlan0改成ap1-wlan1wlan1改成ap1-wlan2wlan2改成ap2-wlan1wlan3改成ap2-wlan2

self.configureWirelessLink()  // 這里只對station的無線接口進行配置,所以這個組網不涉及

createVirtualIfaces  // 對stations創建虛接口,這個也不涉及

AccessPoint(self.aps, self.driver, self.link)

aps = 3個ap+1controller; driver = {str} 'nl80211'; link = {type} <class 'mn_wifi.link.wmediumd'>

AccessPoint::__init__

AccessPoint::configure

for ap in aps:    // node進行遍歷,這里包括了apcontroller

for wlan in range(len(ap.params['wlan'])):  // nodewlan進行遍歷

cls.configAP(ap, wlan)  // 配置ap的wlan參數

TCLinkWirelessAP::__init__

WirelessLinkAP.__init__

params1[ 'port' ] = node1.newPort()  // 這里只是分配一個int類型的端口號。

intf1 = IntfWireless::__init__()   // 創建一個名稱叫 'ap1-wlan1'的接口(接口這個類只是mininet的一個類),給這個接口分配一個int類型的端口號。

node.addIntf(self, port=port)

// 把端口1和接口'ap1-wlan1'建立映射關系

cls.setIPMAC(node, wlan) 

// 使用命令  ip addr show ap1-wlan1  mac地址:02:00:00:00:02:00

checkNetworkManager(cls, mac)  // add mac address into /etc/NetworkManager/NetworkManager.conf                                                       

restartNetworkManager()

nm_is_running = os.system('service network-manager status 2>&1 | grep -ic running >/dev/null 2>&1')  // 查詢network-manager服務的狀態,這里沒有做什么。

for ap in aps: // node進行遍歷,這里包括了apcontroller

for wlan in range(len(ap.params['wlan'])):  // nodewlan進行遍歷

cls.setConfig(ap, aps, wlan, link)

cls.setHostapdConfig(ap, wlan, aplist, link)

cls.APConfigFile(cmd, ap, wlan)

ap = {UserAP} ap1; wlan = {int} 0

cmd = {str} 'echo \'interface=ap1-wlan1\ndriver=nl80211\nssid=ssid91\nwds_sta=1\nhw_mode=g\nchannel=1\nctrl_interface=/var/run/hostapd\nctrl_interface_group=0'

content = 'echo \'interface=ap1-wlan1\ndriver=nl80211\nssid=ssid91\nwds_sta=1\nhw_mode=g\nchannel=1\nctrl_interface=/var/run/hostapd\nctrl_interface_group=0'  > mn10379_ap1-wlan1.apconf'

ap.cmd(content)  // 把 上面的語句寫入 mn10379_ap1-wlan1.apconf 文件

cmd = hostapd -B mn10379_ap1-wlan1.apconf    // 啟動 hostapd; hostapd是一個帶加密功能的無線接入點程序,通過這個配置配置這個無線接入點。

ap.cmd(cmd)  // 執行上面的命令

self.configureWmediumd()   //當前配置的無線模式是干擾模式,也就是可以人為插入噪音的

mob.wmediumd_mode = 3

MyWmediumd::__init__ ()  // 這里的參數有噪音門限等。這個類是自己實現的類。

MyWmediumd::configureWmediumd 下面是對ap和controller都操作了的

設置 wmediumd 的位置和發射功率

start_wmediumd(intfrefs, wmediumd.links, wmediumd.positions,fading_coefficient, noise_threshold,wmediumd.txpowers, isnodeaps, propagation_model,maclist)

w_starter::start

w_starter::initialize

cmdline = ['wmediumd', '-l', '4', '-s', '-c', '/tmp/mn_wmd_config_p_sV91.cfg', '-x', '/home/zhangmeng/mininet-wifi/mn_wifi/data/signal_table_ieee80211']

執行這個命令

w_server.connect()

啟動一個socket,並連接到 '/var/run/wmediumd.sock' 上面去。

for node in nodes:

for wlan in range(0, len(node.params['wlan'])):

node.params['range'][wlan] = node.getRange(intf=intf) // 設置node的range參數。

node.setTxPower(node.params['txpower'][wlan],intf=node.params['wlan'][wlan],setParam=setParam)  // 根據node的 txpower 參數信息,設置節點的發射功率

cmd = iw dev ap1-wlan1 set txpower fixed 1400

執行上面的命令,設置發射功率

node.setAntennaGain(node.params['antennaGain'][wlan],intf=node.params['wlan'][wlan],setParam=setParam)  // 根據node的 antennaGain 參數信息,設置節點的天線增益

setGainWmediumd

w_server.update_gain(w_gain(self.wmIface[wlan], int(gain_)))

ret = w_server.send_gain_update(gain)

cls.sock.send(cls.__create_gain_update_request(gain))

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM