linux没有网卡驱动能pxe吗,PXE所需要的网卡驱动制作

2023-05-16

对PXE 来说:

vmlinuz:就是引导内核文件

initr.img:就是驱动文件

如果遇到机器网卡不被PXE支持怎么办?

解决思路

如果熟悉 Linux 的启动过程和驱动程序,那么要解决本文的问题,基本上有两条路可走。第一就是将网卡驱动编译进内核(静态链接进内核),第二种方法就是将网卡驱动做成模块,然后想办法在 Linux 启动的时候让 Linux 内核能找到并挂载该驱动。面对这两种方案,第二种方法有更好的可行性和扩展性。因为首先有些网卡驱动本身就不能被静态链接进入内核,而只能被编译成一个模块,例如下文要举的例子 - e1000 网卡驱动;其次,驱动做成模块的方式,可以适应多个内核版本,用方法 1,更换一个内核版本就要重新编译一次内核;最后,等会会看到,相比编译内核,方法 2 更简单和可操作。

方法 2 的实现手段就是定制 initrd.img,将我们的网卡驱动加进去。initrd.img 是一个小型的根文件系统,在 Linux 内核没有挂载硬盘上的根分区的时候,initrd.img 将在内存中展开。一般情况下,initrd.img 中将包含一些必需的命令和驱动,如 insmod 命令和磁盘驱动。有了 insmod,才能将磁盘驱动挂载进内核,有了磁盘驱动,内核才能挂载位于磁盘上的根文件系统。

大部分的 Linux 发行版都提供了用于网络安装 Linux 的 initrd.img,一般位于第一张安装光盘的 images/pxeboot 目录下。在一台已经装好 Linux 的机器中,在 /boot 目录下我们也能找到 initrd.img,比较一下这两个 initrd.img,会发现 pxeboot 目录下的 initrd.img 会比 /boot 下的大很多,这是因为在网络安装的情况下,Linux 不会尝试去挂载位于磁盘上的根分区(事实上,在没有安装Linux的机器上,此时磁盘中可能什么数据都没有),所以此时的 initrd.img 需要包含大量的驱动,使 Linux 能识别大量的硬件。位于 /boot 下的 initrd.img,基本上唯一需要的东西就是磁盘驱动,只要内核能访问磁盘,那么其余所需的东西都可以从磁盘取得而不需要依赖 initrd.img。

--------------------------------------------------------------------------------

具体操作和实例

从安装光盘中取得 initrd.img 之后,就可以开始对其进行定制。这里要感谢 Jeremy Mates,他写的 initrd-util.sh 能很好的解开和生成一个 initrd.img。脚本可以在下载到。

下面我们以RedHat Enterprise Linux Advance Server 4 Update 2 x86_64,Intel e1000网卡驱动为例,讲述具体的操作过程(在本例中,服务器和客户机拥有相同的Intel e1000网卡,而且我们已经手动在服务器上安装完成了正确的e1000驱动):

首先从光盘取到initrd.img,登录到服务器,然后用initrd-util.sh解开:

命令输出 1. 解开initrd.img

[root@ericvm ~]# cd `./initrd-util.sh unpack initrd.img |tail -1`

info: initrd unpack expanded into: /var/tmp/initrd-util.workdir.DA29317

[root@ericvm initrd-util.workdir.DA29317]# pwd

/var/tmp/initrd-util.workdir.DA29317

[root@ericvm initrd-util.workdir.DA29317]# ls

2.6.9-22.EL  bin  dev  etc  linuxrc  lost+found  modules

proc  sbin  selinux  sys  tmp  var

initrd-util.sh很简单,利用gunzip, mount和cpio这些工具将initrd.img解开,其中驱动包位于modules目录下,名为modules.cgz,将这个文件解开后,生成了2.6.9-22.EL目录,进入该目录,就能找到包含在initrd.img中的驱动。本例中,RedHat已经包含了一个e1000的驱动,但是这个驱动不能驱动我们新的Intel e1000网卡。为此,我们在e1000网站下载新版的驱动,然后在服务器上编译完成,生成ko模块文件,然后拷贝到2.6.9-22.EL目录下,覆盖原文件即可。

驱动更新完毕后,现在我们需要将2.6.9-22.EL这个目录重新制作成modules.cgz,这个功能initrd-util.sh不能为我们完成,所以我们手动操作:

命令输出 2. 加入驱动并重新打包

[root@ericvm initrd-util.workdir.DA29317]# find 2.6.9-22.EL | cpio -o -H crc > newmodules

16582 blocks

[root@ericvm initrd-util.workdir.DA29317]# gzip -n -9 newmodules

[root@ericvm initrd-util.workdir.DA29317]# mv newmodules.gz modules

[root@ericvm initrd-util.workdir.DA29317]# cd modules

[root@ericvm modules]# rm -f modules.cgz

[root@ericvm modules]# mv newmodules.gz modules.cgz

[root@ericvm modules]# pwd

/var/tmp/initrd-util.workdir.DA29317/modules

驱动包重新生成了并不意味着Linux就可以识别网卡了,因为Linux必须依靠一种逻辑,将硬件设备和驱动模块文件对应起来。这个逻辑就被定义在modules目录下的除modules.cgz之外的文件中:

命令输出 3. 设备驱动识别信息文件

[root@ericvm modules]# ls

module-info  modules.cgz  modules.dep  modules.pcimap  modules.usbmap  pci.ids  pcitable

如上所示,pcitable, modules.pcimap中定义了PCI设备和驱动模块之间的对应关系,modules.dep中定义了模块和模块之间的依赖关系(比如,各种SCSI设备都会依赖一个基础的SCSI驱动模块),module-info中定义了驱动的静态描述信息......

要填写这些文本文件,也很简单,首先我们必须要知道这块e1000网卡的PCI设备信息,由于在服务器上e1000这块网卡已经安装完成了,所以我们可以在服务器上取到我们想要的信息:

命令输出 4. 查看网卡硬件信息

[root@ericvm ~]# lspci

............  ignore some outputs

04:00.0 Ethernet controller: Intel Corporation Enterprise Southbridge DPT LAN Copper

04:00.1 Ethernet controller: Intel Corporation Enterprise Southbridge DPT LAN Copper

............  ignore some outputs

lspci列出了服务器上两块网卡的设备信息,根据网卡设备的ID号码(04:00.0, 04:00.1),我们就可以在lspci –n的输出中找到设备的vendor code和device code(请参考lspci的manual了解lspci):

命令输出 5. 查看网卡code

[root@ericvm ~]# lspci –n

............  ignore some outputs

04:00.0 Class 0200: 8086:1096 (rev 01)

04:00.1 Class 0200: 8086:1096 (rev 01)

............  ignore some outputs

在lspci –n的输出中,我们找到了两块网卡的vendor code和device code – 8086和1096。得到了vendor code和device code之后,就可以更新initrd.img中modules目录下的pcitable, modules.pcimap等这些文件了。举例来说,在pcitable中查找e1000,能发现很多设备和e1000这个驱动关联,但是唯独没有8086:1096的组合,这就是为什么Linux无法驱动这块e1000网卡的原因了,我们需要手动将8086, 1096这两个code加入到pcitable中,并将这个设备对应到e1000驱动上。照此方法,更新其余的文件,如module-info, modules.pcimap等。

这样我们就完成了对initrd.img的完全修改,用initrd-util.sh重新将目录打包,生成一个新的initrd.img:

命令输出 6. 重新生成initrd.img

[root@ericvm ~]# ./initrd-util.sh pack /var/tmp/initrd-util.workdir.DA29317/

notice: new initrd size: 6144K

6144+0 records in

6144+0 records out

mke2fs 1.35 (28-Feb-2004)

info: initrd packed into: /var/tmp/initrd-util.initrd-new.IV29439.gz

/var/tmp/initrd-util.initrd-new.IV29439.gz

[root@ericvm ~]# ls -lh /var/tmp

total 3.7M

-rw-r--r--   1 root root 3.7M Jun 20 17:10 initrd-util.initrd-new.IV29439.gz

drwxr-xr-x  12 root root 4.0K Jun 20 17:10 initrd-util.workdir.DA29317

drwxr-xr-x  13 root root 4.0K Jun 20 15:53 initrd-util.workdir.ID29288

initrd-util.sh首先创建一个“空洞文件”,然后在这个文件中建立ext2 文件系统,然后将这个文件mount到一个目录中,最后用rsync这种方式将我们更新过的文件“拷贝”到了mount的目录下,这样“空洞”文件中就有了内容,最后对文件进行压缩,生成最终的img文件。

将/var/tmp/initrd-util.initrd-new.IV29439.gz改名成initrd.img,放到tftp配置的目录下,就可以让客户机在网络启动的时候取到新的initrd.img了,从而识别网卡开始网络安装。

--------------------------------------------------------------------------------

回页首

到此为止了么?

到目前为止,一切看起来都很好。客户机通过网络启动,能把网卡驱动起来并从服务器上得到所有需要的东西,并开始安装。但是,如果没有做特殊处理的话,客户机上Linux安装完成后,启动进入Linux,会发现网卡依旧驱动不了,典型的出错信息就是“无法成功挂载XXX驱动”,“ethX的MAC地址和预计的不一样”等。出现这样问题的原因很简单,这是因为正确的网卡驱动只存在于服务器上的 initrd.img 中,而没有体现到客户机的硬盘上。客户机在网络启动的时候得到了服务器上的 initrd.img,但 Linux 还没有智能到能自动解开这个 initrd.img 并将里面的驱动拷贝到客户机的硬盘上。一旦客户机完成安装重启,从硬盘启动之后,所有的驱动文件和信息就都从硬盘读取了。

还举刚才的例子,e1000 网卡驱动在 RedHat 中其实自带就有一个,但不适用于我们的 Intel e1000 网卡,用 rpm 命令可以查到安装在硬盘上的这个 e1000 驱动属于哪个RPM包:

命令输出 7. 查看驱动所在的 RPM 包

# rpm -qf /lib/modules/2.6.9-42.ELsmp/kernel/drivers/net/e1000/e1000.ko

kernel-smp-2.6.9-42.EL

所以,很明显的就是,要解决这样的问题,我们需要重新生成这个 kernel RPM 包。但是要在 RPM 包中替换一个文件,或是加入一个文件,可不像在 RAR 文件中用鼠标直接拖拽那么简单。有兴趣的可以参考 RPM 的相关资料。

除了重新生成 RPM 之外,还有一些简单的办法也是可行的,但不如重新生成 RPM 来的中规中矩。有兴趣的读者可以和我交流,这里就不赘述了。

参考资料

Jeremy Mates的initrd-utils, ,帮助我们创建/解开 initrd.img

Adding driver modules to a Fedora Core 2 CD for kickstart install:

实际制作案例:

网络安装 RedHat 4.8 支持82578DM网卡芯片

一 编译网卡驱动

使用2.6.9-89.EL 内核进入系统,

下载INTEL e1000e-1.1.2源码安装包 (或者更高版本)

yum groupinstall “Development Tools” -y

yum install kernel-devel -y

tar vxf e1000e-1.1.2.tar.gz

cd e1000e-1.1.2/src

make install

安装结束之后会新建一个/lib/modules/2.6.18-53.el5/kernel/drivers/net/e1000e/e1000e.ko模块文件,这个文件做为initrd.img的e1000e.ko网卡驱动(与平时使用的2.6.9-89.ELsmp内核系统的e1000e.ko不同)。

二从光盘取到initrd.img,登录到服务器,然后用initrd-util.sh解开:

命令输出 1. 解开initrd.img

[root@ericvm ~]# cd `./initrd-util.sh unpack initrd.img |tail -1`

info: initrd unpack expanded into: /var/tmp/initrd-util.workdir.DA29317

[root@ericvm initrd-util.workdir.DA29317]# pwd

/var/tmp/initrd-util.workdir.DA29317

[root@ericvm initrd-util.workdir.DA29317]# ls

2.6.9-22.EL  bin  dev  etc  linuxrc  lost+found  modules

proc  sbin  selinux  sys  tmp  var

initrd- util.sh很简单,利用gunzip, mount和cpio这些工具将initrd.img解开,其中驱动包位于modules目录下,名为modules.cgz,将这个文件解 开后,生成了 2.6.9-22.EL目录,进入该目录,就能找到包含在initrd.img中的驱动。本例中,RedHat已经包含了一个e1000的驱动,但是这个 驱动不能驱动我们新的Intel e1000网卡。为此,我们在e1000网站下载新版的驱动,然后在服务器上编译完成,生成ko模块文件,然后拷贝到2.6.9-22.EL目录下,覆盖 原文件即可。

驱动更新完毕后,现在我们需要将2.6.9-22.EL这个目录重新制作成modules.cgz,这个功能initrd-util.sh不能为我们完成,所以我们手动操作:

命令输出 2. 加入驱动并重新打包

[root@ericvm initrd-util.workdir.DA29317]# find 2.6.9-22.EL | cpio -o -H crc > newmodules

16582 blocks

[root@ericvm initrd-util.workdir.DA29317]# gzip -n -9 newmodules

[root@ericvm initrd-util.workdir.DA29317]# mv newmodules.gz modules

[root@ericvm initrd-util.workdir.DA29317]# cd modules

[root@ericvm modules]# rm -f modules.cgz

[root@ericvm modules]# mv newmodules.gz modules.cgz

[root@ericvm modules]# pwd

/var/tmp/initrd-util.workdir.DA29317/modules

驱动包重新生成了并不意味着Linux就可以识别网卡了,因为Linux必须依靠一种逻辑,将硬件设备和驱动模块文件对应起来。这个逻辑就被定义在modules目录下的除modules.cgz之外的文件中:

命令输出 3. 设备驱动识别信息文件

[root@ericvm modules]# ls

module-info  modules.cgz  modules.dep  modules.pcimap  modules.usbmap  pci.ids  pcitable

如 上所示,pcitable, modules.pcimap中定义了PCI设备和驱动模块之间的对应关系,modules.dep中定义了模块和模块之间的依赖关系(比如,各种 SCSI设备都会依赖一个基础的SCSI驱动模块),module-info中定义了驱动的静态描述信息......

要填写这些文本文件,也很简单,首先我们必须要知道这块e1000网卡的PCI设备信息,由于在服务器上e1000这块网卡已经安装完成了,所以我们可以在服务器上取到我们想要的信息:

命令输出 4. 查看网卡硬件信息

[root@ericvm ~]# lspci

............  ignore some outputs

04:00.0 Ethernet controller: Intel Corporation Enterprise Southbridge DPT LAN Copper

04:00.1 Ethernet controller: Intel Corporation Enterprise Southbridge DPT LAN Copper

............  ignore some outputs

lspci列出了服务器上两块网卡的设备信息,根据网卡设备的ID号码(04:00.0, 04:00.1),我们就可以在lspci –n的输出中找到设备的vendor code和device code(请参考lspci的manual了解lspci):

命令输出 5. 查看网卡code

[root@ericvm ~]# lspci –n

............  ignore some outputs

04:00.0 Class 0200: 8086:1096 (rev 01)

04:00.1 Class 0200: 8086:1096 (rev 01)

............  ignore some outputs

在lspci –n的输出中,我们找到了两块网卡的vendor code和device code – 8086和1096。得到了vendor code和device code之后,就可以更新initrd.img中modules目录下的pcitable, modules.pcimap等这些文件了。举例来说,在pcitable中查找e1000,能发现很多设备和e1000这个驱动关联,但是唯独没有 8086:1096的组合,这就是为什么Linux无法驱动这块e1000网卡的原因了,我们需要手动将8086, 1096这两个code加入到pcitable中,并将这个设备对应到e1000驱动上。照此方法,更新其余的文件,如module-info, modules.pcimap等。

这样我们就完成了对initrd.img的完全修改,用initrd-util.sh重新将目录打包,生成一个新的initrd.img:

命令输出 6. 重新生成initrd.img

[root@ericvm ~]# ./initrd-util.sh pack /var/tmp/initrd-util.workdir.DA29317/

notice: new initrd size: 6144K

6144+0 records in

6144+0 records out

mke2fs 1.35 (28-Feb-2004)

info: initrd packed into: /var/tmp/initrd-util.initrd-new.IV29439.gz

/var/tmp/initrd-util.initrd-new.IV29439.gz

[root@ericvm ~]# ls -lh /var/tmp

total 3.7M

-rw-r--r--   1 root root 3.7M Jun 20 17:10 initrd-util.initrd-new.IV29439.gz

drwxr-xr-x  12 root root 4.0K Jun 20 17:10 initrd-util.workdir.DA29317

drwxr-xr-x  13 root root 4.0K Jun 20 15:53 initrd-util.workdir.ID29288

initrd- util.sh首先创建一个“空洞文件”,然后在这个文件中建立ext2 文件系统,然后将这个文件mount到一个目录中,最后用rsync这种方式将我们更新过的文件“拷贝”到了mount的目录下,这样“空洞”文件中就有 了内容,最后对文件进行压缩,生成最终的img文件。

将/var/tmp/initrd-util.initrd-new.IV29439.gz改名成initrd.img,放到tftp配置的目录下,就可以让客户机在网络启动的时候取到新的initrd.img了,从而识别网卡开始网络安装。

三 为RedHat 4.8 系统安装 网卡/显卡驱动

在ks.cfg 文件最后%port 部分中添加:

rm –rf /lib/modules/2.6.9-89ELsmp/kernel/drivers/net/e1000e ;

mkdir /lib/modules/2.6.9-89ELsmp/kernel/drivers/net/e1000e ;

cd /lib/modules/2.6.9-89ELsmp/kernel/drivers/net/e1000e ;

wget

#***为kickstart 服务器地址,e1000e.ko为2.6.9-89ELsmp内核模块系统中编译出的驱动

Cd /tmp ; wget ; rpm -ivh nvidia-260.19.12-1.x86_64.rpm

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux没有网卡驱动能pxe吗,PXE所需要的网卡驱动制作 的相关文章

  • 我们如何在使用循环时调用 ansible playbook 中的变量

    我有两个文件 其中这些文件包含server names and server IP s 我想更改 替换一些特定的server names and IP addressees根据要求在两个文件中 这与这篇文章 因为它被要求开设一个新职位 ht
  • 我想在 Red Hat Linux 服务器中执行 .ps1 powershell 脚本

    我有一个在窗口中执行的 ps1 powershell 脚本 但我的整个数据都在 Linux 服务器中 有什么可能的方法可以让我在红帽服务器中执行 powershell 脚本 powershell脚本是 Clear Host path D D
  • 如何获取与 shell 中的文件名模式匹配的所有文件的总文件大小?

    我正在尝试仅使用 shell 来计算与文件名模式匹配的所有文件 在目录树中 的总大小 以字节为单位 这是我到目前为止所拥有的 find name undo exec stat c s awk 总计 1 END 打印总计 有没有更简单的方法来
  • 使用 shell 脚本发送 HTML 邮件

    如何使用 shell 脚本发送 HTML 电子邮件 首先 您需要撰写消息 最低限度由这两个标头组成 MIME Version 1 0 Content Type text html 以及适当的消息正文 p Hello world p 获得后
  • 在 Linux 中重新启动时,新创建的文件变为 0 kb(数据被覆盖为空)

    我遇到了一个奇怪的问题 这让我发疯 当前的任务是在 root 用户第一次登录时启动一组文件 并在同一用户第二次登录时启动另一组文件 我决定使用 profile 和 bashrc 文件 并在第一次登录期间发生的任务结束时重新加载 bashrc
  • 更新Linux中的包含路径

    我的 my path to file 文件夹中有几个头文件 我知道如何将这些文件包含在新的 C 程序中 但每次我都需要在包含它之前输入头文件的完整路径 我可以在linux中设置一些路径变量 以便它自动查找头文件吗 您可以创建一个 makef
  • Ruby:在 Ubuntu 上安装 rmagick

    我正在尝试在 Ubuntu 10 04 上安装 RMagick 看起来here https stackoverflow com questions 1482823 is there an easy way to install rmagic
  • Linux shell 从用户输入中获取设备 ID

    我正在为一个程序编写安装脚本 该程序需要在其配置中使用 lsusb 的设备 ID 因此我正在考虑执行以下操作 usblist lsusb put the list into a array for each line use the arr
  • 如何在 Linux 和 C 中使用文件作为互斥体?

    我有不同的进程同时访问 Linux 中的命名管道 并且我想让此访问互斥 我知道可以使用放置在共享内存区域中的互斥体来实现这一点 但作为一种家庭作业 我有一些限制 于是 我想到的是对文件使用锁定原语来实现互斥 我做了一些尝试 但无法使其发挥作
  • 在 x86 汇编语言中获取文件大小的简单方法

    假设我已经在汇编中打开了一个文件 并且在寄存器 eax 中有该文件的文件句柄 我将如何获取文件的大小 以便为其分配足够的缓冲区空间 我在这里研究了另一个讨论 建议使用sys fstat 28 系统调用来获取文件统计信息但无法实现它 My a
  • 使用 libusb 输出不正确

    我用libusb编写了一个程序 我怀疑输出是否正确 因为所有条目都显示相同的供应商和产品 ID 以下是代码 include
  • 如何并行执行4个shell脚本,我不能使用GNU并行?

    我有4个shell脚本dog sh bird sh cow sh和fox sh 每个文件使用 xargs 并行执行 4 个 wget 来派生一个单独的进程 现在我希望这些脚本本身能够并行执行 由于某些我不知道的可移植性原因 我无法使用 GN
  • 正则表达式删除块注释也删除 * 选择器

    我正在尝试使用 bash 从 css 文件中删除所有块注释 我有以下 sed 命令的正则表达式 sed r s w s w d 这可以很好地去除块注释 例如 This is a comment this is another comment
  • LINUX:如何锁定内存中进程的页面

    我有一个 LINUX 服务器 运行一个具有大量内存占用的进程 某种数据库引擎 该进程分配的内存太大 需要将其中一部分换出 换出 我想做的是将所有其他进程 或正在运行的进程的子集 的内存页面锁定在内存中 以便只有数据库进程的页面被换出 例如
  • 来自守护程序的错误响应:加入会话密钥环:创建会话密钥:超出磁盘配额

    我尝试在我的服务器上安装 docker 使用本教程 https docs docker com install linux docker ce ubuntu 我想远程运行 docker 镜像并使用 portainer Web 界面来管理一切
  • 在内核代码中查找函数的最佳方法[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我开始浏览内核代码 遇到的一件事是如何跟踪函数调用 结构定义等 有没有一种好的方法可以快速跳转到函数定义并退出 我尝试过 Source N
  • 仅使用containerd(不使用Docker)修剪容器镜像

    如果我刚刚containerd安装在 Linux 系统上 即 Docker 是not安装 如何删除未使用的容器映像以节省磁盘空间 Docker 就是这么方便docker system prune https docs docker com
  • SSH,运行进程然后忽略输出

    我有一个命令可以使用 SSH 并在 SSH 后运行脚本 该脚本运行一个二进制文件 脚本完成后 我可以输入任意键 本地终端将恢复到正常状态 但是 由于该进程仍在我通过 SSH 连接的计算机中运行 因此任何时候它都会登录到stdout我在本地终
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • FileOutputStream.close() 中的设备 ioctl 不合适

    我有一些代码可以使用以下命令将一些首选项保存到文件中FileOutputStream 这是我已经写了一千遍的标准代码 FileOutputStream out new FileOutputStream file try BufferedOu

随机推荐