首页 > 代码库 > 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


本文出自 “软件测试” 博客,请务必保留此出处http://9614554.blog.51cto.com/9604554/1579884

KVM网卡模式