KVM網卡模式(初探KVM)

    最近在看“KVM虛擬化技術實戰與原理解析”這本書, 略讀了前四章後, 開始動手創建並安裝一個虛擬機. 然後發現一個很嚴重的問題, 就是我沒有辦法通過ssh連接到虛擬機(linux), 也沒有辦法通過mstsc連到到虛擬機(windows), 因爲我在創建虛擬機時網卡模式只能選擇NAT, 不知道爲什麼沒有其他選擇方式.


    我知道解決這個情況的辦法是使用橋接, 因爲以前用virtualbox或者vmware的時候都是選擇網卡橋接模式, 然後我就開始閱讀第四章的網卡配置. 按照書上的例子, 無法實現橋接(連最基本的virbr0是怎麼來的都沒有介紹……中間省略500字……, 就不繼續吐嘈了).


    然後上網找了一些文檔閱讀了之後, 明白了幾個關鍵點:

        1. virbr0是虛擬網絡適配器(即虛擬網卡), 該網卡由virsh維護.

        2. 創建的虛擬機都會綁定在這個網卡上, 通過brctl show可以看到.

        3. 需要將物理網卡(eth0)與virbr0綁定在一起並且將物理網卡上的所有ip平移到虛擬網卡上, 才能實現共享網絡.


    由於知識匱乏, 不知道如何繼續集成使橋接的配置更靈活. 每次開機後都要把幾個命令反覆的粘貼來實現橋接.

        1. ifconfig eth0 0;

        2. ip addr add ip地址/子網 dev virbr0

        3. route add default gw 網關地址 dev virbr0

        4. brctl addif virbr0 eth0

    幾天下來之後我就感覺到比較煩躁了, 於是又有了下面這段代碼, 來減少我對橋接的陰影.

[root@localhost ~]# vim bridgeWay.py
# -.- coding:utf-8 -.-
__author__ = 'root'

import re
import os
import sys
import getopt
from xml.sax import parse
from xml.sax.handler import ContentHandler

# 獲取XML文件中的Bridge網卡名稱
class getHandler(ContentHandler):
    def __init__(self):
        self.bridge = []

    def startElement(self, name, attrs):
        if name == "bridge":
            self.bridge.append(attrs["name"])

# 輸出幫助信息
def printHelp():
    print "INTRODUCTION"
    print "-"*60
    print "Syntax(1): python %s -i ethX [-h]" % sys.argv[0]
    print "Syntax(2): python %s --interface ethX [--help]" % sys.argv[0]
    print "-i or --interface: network interface which to grant bridge."
    print "-"*60

# 處理網卡配置,提取出一組或多組ip信息.
def handleNI(interface):
    with open("/etc/sysconfig/network-scripts/ifcfg-%s" % interface, "r") as netCar:
        ipAddress = {}
        result = []
        splitVar = []
        extrNum = []

        # 獲取出多組ip信息(IP地址, 子網掩碼, 網關)
        for i in netCar.readlines():
            # 拆分文本內容.
            eachPara = i.replace("\n", "").split("=")
            # 如果是註釋掉的內容則不處理.
            if "#" in eachPara[0]: continue
            # 提取ip信息(ipaddr、preffix、netmask、gateway).
            if re.findall(r"IPADDR|PREFIX|NETMASK|GATEWAY", eachPara[0]):
                ipAddress[eachPara[0]] = eachPara[1]

        for i in ipAddress.keys():
            # 拆分變量名稱(ipaddr2 --> ['ipaddr', '2'])
            splitVar.append([re.split(r"[0-9]+", i)[0], re.split(r"[a-zA-Z]+", i)[1]])
            # 提取變量數字(ipaddr2, ipaddr3 --> ['2', '3'])
            extrNum.append(re.split(r"[a-zA-Z]+", i)[1])

        # 提取並組合正確的ip組(即每組對應一個ip、preffix、netmask、gateway)
        for i in list(set(extrNum).intersection(set(extrNum))):
            temp = {}
            for j in splitVar:
                if i == j[1]:
                    temp[j[0]] = ipAddress[''.join(j)]
            result.append(temp)
        return result

def rebuildBridge(netInterface, bridgeName, ipList):
    result = []
    # 綁定網卡爲橋接模式
    os.popen("brctl addif %s %s >> /dev/null 2>&1" % (bridgeName, netInterface))

    for i in ipList:
        # 清除原網卡上所設定的ip地址
        os.popen("ip addr del %s/%s dev %s >> /dev/null 2>&1" % (i["IPADDR"], i["PREFIX"], netInterface))
        # 在橋接口上添加ip地址
        os.popen("ip addr add %s/%s dev %s >> /dev/null 2>&1" % (i["IPADDR"], i["PREFIX"], bridgeName))

        # 只要ip列表中包含有網關, 則會啓用該網關.
        if i.has_key("GATEWAY"):
            os.popen("route del default gw %s dev %s >> /dev/null 2>&1" % (i["GATEWAY"], netInterface))
            os.popen("route add default gw %s dev %s >> /dev/null 2>&1" % (i["GATEWAY"], bridgeName))

            # 若網關設置好了之後無法被ping通, 則會將該條默認網關清除掉.
            getPing = os.popen("ping -c 1 %s >> /dev/null 2>&1; echo $?" % i["GATEWAY"]).read().replace("\n", "")
            # linux中的操作, 正確返回0, 錯誤返回非0.
            if int(getPing) != 0:
                result.append(("error", i["GATEWAY"]))
                os.popen("route del default gw %s dev %s >> /dev/null 2>&1" % (i["GATEWAY"], bridgeName))
            else:
                result.append(("correct", i["GATEWAY"]))

    for i in result:
        if "correct" in i[0]:
            print "網關可以正常使用: ", i[1]

# 檢查輸入參數是否正確
def checkArguments(*args):
    options, args = getopt.getopt(sys.argv[1:], shortopts="hi:", longopts=["help", "interface="])

    for name, value in options:
        if name in ("-h", "--help"):
            printHelp()
            sys.exit(1)
        elif name in ("-i", "--interface"):
            return value
        else:
            printHelp()
            sys.exit(1)

if __name__ == "__main__":
    if len(sys.argv) > 1:
        # 定義kvm讀取網卡(virbrX)的配置信息.
        filePath = "/etc/libvirt/qemu/networks/default.xml"
        # 檢查參數是否正確.
        interface = checkArguments(sys.argv[1:])
        # 獲取ip信息
        ipList = handleNI(interface)
        # 獲取橋接網卡名稱(Bridge Name).
        handleXML = getHandler()
        parse(filePath, handleXML)
        bridgeName = handleXML.bridge[0]
        # 創建橋接. 
        rebuildBridge(interface, bridgeName, ipList)
    else:
        printHelp()


以後我要用虛擬機的時候,運行一下這個腳本, 就會幫助我解決網絡的問題.

[root@localhost ~]# python bridgeWay.py -i eth0


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章