当然用起来之前还是得知道这东西是做什么的,以及相关的概念。
SR-IOV全称single root input/output virtualization,直译过来就是单根I/O虚拟化,怎么理解呢?首先SR-IOV最初的应用(也是我仅知的应用)是在网卡上,下图是一张SR-IOV示意图,单根的“根”即图片最底层的物理网卡,SR-IOV起到的作用是把一张物理网卡虚拟化成多个虚拟网卡给虚拟机(VM)用。
跳过产生背景、原理、优劣,我们先直接看实现。

一台支持SR-IOV的主机或服务器(主板),SR-IOV功能在BIOS中已开启;
我的就是台普通的DELL Optiplex7070主机,BIOS一开始都没动,好在虚拟化功能都是默认开启或者之前已经有人开启过的
一块支持SR-IOV且能安装于上述设备的网卡;
我的是Netronome CX 25Gx2的智能网卡(奢侈)
关于如何查看主机/服务器对SR-IOV的支持:
查起来太费劲,不如直接到BIOS里面看一看有没有这个选项,像Intel的就在BIOS中的
Advanced->CPU Setup界面下,有Intel Virtual Technology和VT-d Feature选项,都设置为Enabled就好。AMD则是叫AMD-Vi。而且一般来讲,支持的话都会默认打开吧,至少我的是默认打开的。网卡的产品介绍一般都会提到对SR-IOV的支持,这个查一查就好。
不满足以上硬件条件的话就别跟着做了。
我是基于Ubuntu 20.04.4,其他系统应该也没什么大碍,最好是Linux就是了。
在继续之前把系统intel_iommu打开:
先查看/proc/cmdline中是否有intel_iommu=on字样
$ cat /proc/cmdline
如果没有,修改/etc/default/grub文件,在其中的GRUB_CMDLINE_LINUX="",改为GRUB_CMDLINE_LINUX="intel_iommmu=on"(里面已有参数的话,多个参数用空格隔开),并执行sudo update-grub使修改生效(没有该命令的话是缺少软件包,执行:sudo apt-get install grub2-common),之后重启系统,再次查看iommu是否重新开启。使用dmesg | grep -e DMAR -e IOMMU以查看启动过程中与iommu有关的信息。
此外还需要安装虚机,我使用的是KVM,后续修改SR-IOV用的图形界面。其他的应该也支持SR-IOV吧。
其实我的初衷只是想做好Netronome网卡卸载OVS的实验,SR-IOV才是顺便一学的事情。
为了让Netronome网卡卸载OVS,需要更换网卡固件为flower,具体操作为:
$ cd /lib/firmware/netronome
$ rm -f *.nffw
$ for firmware in $(ls flower); do ln -sf flower/$firmware $firmware; done
还写了一个sh脚本,切换起来方便:
#!/bin/bash
# Usage: ./switch_firmware [bpf/flower/nic]
FIRMNAME=$1
pushd /lib/firmware/netronome
rm -f *.nffw
for firmware in $(ls $FIRMNAME); do ln -sf $FIRMNAME/$firmware $firmware; done
echo "Firmware re linked. Removing nfp mod..."
modprobe -r nfp
echo "nfp mod removed. Reloading nfp mod..."
modprobe nfp
echo "Firmware updated to $FIRMNAME."
这里我有一个BUG,一台主机切换flower固件后,lspci、ip link等都无法看到网卡,另一台机子就没问题。dmesg查看启动信息发现返回错误码(忘了多少了,后面补上)。
我们把SR-IOV创建出的虚拟网卡称为VF,如下命令可以查看网卡物理端口enp3s0np0(称PF)最大支持创建的VF为55个;
$ cat /sys/class/net/enp3s0np0/device/sriov_totalvfs
55
创建VF也很简单,直接写入文件就行,比如分配2个VF给enp3s0np0:
$ echo 2 > /sys/class/net/enp3s0np0/device/sriov_numvfs
这时lspci | grep Ethernet就能看到新添加的VF,以下设备中00:1f.6和03:00.0为物理网卡,03:08.0和03:08.1为新创建的VF虚拟网卡。此外使用ip link、ifconfig等命令也可以看到新创建的VF信息,使用ethtool命令可以看到对应的driver为nfp_netvf。
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (5) I219-LM
03:00.0 Ethernet controller: Netronome Systems, Inc. Device 4000
03:08.0 Ethernet controller: Netronome Systems, Inc. Device 6003
03:08.1 Ethernet controller: Netronome Systems, Inc. Device 6003
这里ifconfig会发现多了四个接口:
enp3s0v0和enp3s0v1,eth2和eth4(创建VF前我也不知道哪多出来一个eth3)。03:08.0、enp3s0v0和eth2是对应的,剩下三个也是对应的,当03:08.0与某个虚机绑定后,enp3s0v0在host主机中消失,eth2还留着,官网没有详细解释,这部分还有点乱,希望以后能搞清楚怎么回事。
然后我们就可以把创建的VF与VM绑定了,这里我采用的是KVM的图形化管理器,因为懒得敲代码。
完成以后,VM就像有了自己的网卡,像是把物理网卡的端口拆成了几小份,分给每个VM使用。
不过从一开始的图片可以看出来,此时VM还是无法与同Host其他主机和外部主机通信的,我们还缺少一个Vitual Switch或者叫网桥,这里我们使用OVS,避免复杂,我们直接用Ubuntu的apt进行安装:
$ sudo apt update
$ sudo apt install -y openvswitch-switch
Netronome部分内容,其他网卡略过:
为了卸载OVS的kernel datapath,我们还需要使能OVS的硬件卸载模式,并重启OVS服务以生效:
$ ovs-vsctl set Open_vSwitch . other_config:hw-offload=true other_config:tc-policy=none
$ systemctl restart openvswitch-switch
此外网卡也要确认TC卸载标志位hw-tc-offload是否为on,flower固件默认是开启的。
$ ethtool -k enp3s0np0 | grep hw-tc-offloadhw-tc-offload: on
若非on可以:
$ ethtool -K enp3s0np0 hw-tc-offload on
$ ovs-vsctl add-br br0$ ovs-vsctl add-port br0 enp3s0np0$ ovs-vsctl add-port br0 eth2
这时外部主机和VM就可以互相通信了,VM用着同一块网卡的硬件资源,虚拟出自己的网卡,做到节省Host主机资源、提高性能等。
可惜的是我的Host主机太拉胯,开两个SR-IOV的虚机就死机,导致没做成SR-IOV的VM-VM实验。
Netronome部分内容,其他网卡略过:
OVS卸载相较于原始方案,区别就在于Netronome可以将Kernel中OVS的Fast path卸载到智能网卡,让原本由Kernel处理的流转移到硬件处理,进一步释放主机资源并提高性能。
使用如下命令即可查看已被卸载到网卡的流表:
# 查看卸载的流表
$ ovs-appctl dpctl/dump-flows type=offloaded# 查看未被卸载的流表$ ovs-appctl dpctl/dump-flows type=ovs
更多可以参考Netronome官网,这里不多说。
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or