That's Just the Way It Is - How NT Describes I/O Requests

本文详细介绍了Windows NT操作系统中I/O请求的处理机制,重点解释了I/O请求包(IRP)的概念及其结构,同时探讨了Direct I/O、Buffered I/O和Neither I/O三种数据缓冲处理方式的特点及应用场景。

That's Just the Way It Is - How NT Describes I/O Requests 
The NT Insider, Vol 5, Issue 1, Jan-Feb 1998 | Published: 15-Feb-98| Modified: 20-Aug-02 

声明:原文来自www.osr.com,所有权利归原作者所有,翻译并贴在这里的目的只为学习和交流,除了商用你可以随意地使用这篇译文。但请不要删除声明。

                                                     ——by jununfly

版本:20090124

NT驱动中的根本问题:IRPs和数据缓冲… 在此之前我们从未真正地进行详论的细节.

NT用一个基于包的架构描述I/O请求。即任何一个I/O请求都能用一个单一的I/O请求包也就是IRP来描述。当发出一个I/O系统服务时(比如创建文件或读文件的请求),I/O管理器服务通过构造一个描述此请求的IRP并把该IRP的一个指针传给设备驱动来开始对这个请求的处理。

一个IRP,包含要向I/O管理器和设备驱动完整地描述一个I/O请求的所有必需的信息。IRP是一个标准的NT结构,其定义在NTDDK.H中。结构如图1:

1 – 一个IRP的结构

如图1所示,任何一个IRP都能被认为是由两部分组成:一个"固定的"部分和一个I/O栈。IRP的固定部分包含这个请求的相关信息,有可能不同驱动中的IRP的固定部分相同,也可能在不同驱动间传递IRP时不需要关注它。I/O栈包含被指定给任何一个要处理该请求的驱动的信息。 

虽然一个IRP被I/O管理器创建时它的大小是固定的,但是I/O管理器创建的任何一个IRP的大小都不一样。当I/O管理器分配一个IRP时,它为IRP分配的空间是:IRP的固定部分的空间,加上其数量至少等于驱动栈中将会处理这个请求的驱动的数量的I/O栈位置的空间。因此,如果对一个软盘上的文件发出一个写I/O请求,要处理这个请求的驱动栈如图2。I/O管理器将会创建一个IRP来描述这个请求,这个IRP中至少有两个I/O栈位置:一个位置是FSD的,第二个位置是软盘设备驱动的。

2 – 驱动栈示例

注意我们说的例子中的IRP将至少有两个I/O栈位置。为避免每一个IRP都要从NT的非分页池中分配,I/O管理器维护一对保存有预分配的IRPs的旁观列表。NT V4.0中,其中一个旁观列表保存带有一个单一的I/O栈位置的IRP。 

另外一个旁观列表保存带有三个I/O栈位置的旁观列表。I/O管理器总是尽可能使用这些旁观列表中的IRP。因此,对一个被引导到带有两个驱动的驱动栈上的I/O请求来说,I/O管理器会试图从保存带有三个I/O栈位置的IRP的旁观列表中分配一个IRP。如果没有可用的IRP,或者要分配的IRP所需的I/O栈位置超过三个,I/O管理器就会从非分页池中分配IRP。

IRP的固定部分中需要特别关注或有用的域如下:

MdlAddres, UserBufferAssociatedIrp.SystemBuffer – 如果有一个关联I/O操作请求者的数据缓冲,则这三个域被用来描述这个缓冲。后面会加以详述。

Flags – 顾名思义,这个域包含描述I/O请求的标记。例如,如果在此域中设置了IRP_PAGING_IO标记,则表示IRP所描述的读或写操作是一个分页请求。以此类推,如果设置了IRP_NOCACHE则表示这个请求是在没有中间缓冲的情况下被处理的。一般只有文件系统才关心这个域。

IoStatus – 当IRP被完成时,完成这个IRP的驱动把IoStatus.Status域设置为I/O操作的完成状态,而把IoStatus.Information域设置为一些要返回给调用者的额外信息。典型的,在一个传输请求(读或写等会引起数据传输的请求)中IoStatus.Information 将会包含实际上被读或被写的字节数。

RequestorMode – 指示这个请求是从哪种模式(内核模式或用户模式)发动的。

Cancel, CancelIrql, and CancelRoutine – 如果正在进行时需要取消这个IRP就会用到它们。Cancel是一个BOOLEAN类型值,当被I/O管理器设置为TRUE时表示这个IRP正被取消。CancelRoutine是一个指针,在把这个IRP保存到一个队列中时由一个驱动设置它指向一个函数,I/O管理器会调用这个函数来让该驱动取消此IRP。因为CancelRoutine是在IRQL DISPATCH_LEVEL被调用CancelIRQL是驱动应该返回到的IRQL(The NT Insider的卷46期的Part I,有篇文章关于取消处理)

Tail.Overlay.Thread – 指向请求线程的ETHREAD. 

TailOverlay.ListEntry – 可能被驱动用来排队的位置,尽管它拥有这个IRP。

IRP中的任何一个I/O栈位置都包含一个指定的驱动与此I/O请求相关的信息。在NTDDK.H 中I/O栈位置的定义如结构IO_STACK_LOCATION.要在一个给定的IRP中定位当前的I/O栈位置,驱动得调用函数IoGetCurrentIrpStackLocation(…).其唯一的参数是一个指向IRP的指针。返回值是当前I/O栈位置的一个指针。

I/O管理器开始分配IRP并初始化它的固定部分时,它也初始化IRP中的首个I/O栈位置。这个位置中的信息与被传到将会处理这个请求的驱动栈中的首个驱动的信息相一致。I/O栈位置中有以下域:

MajorFunction – 关联这个请求的主I/O函数代码。它从总体上指示了要执行的I/O操作的类型。

MinorFunction  关联这个请求的辅助I/O函数代码。当被使用时,这会改变主函数代码。Minor function几乎是被网络传输驱动和文件系统独占地使用,大多数设备驱动会忽略它们。

Flags – 指定给正被执行的I/O函数的处理标记。此域主要为FSD所关注。

Control – 一组指示I/O管理器如何处理这个IRP的标记,由I/O管理器设置并参阅。例如若设置了SL_PENDING(因驱动调用了IoMarkIrpPending(…))就指示给I/O管理器此IRP还需其他处理。类推之SL_INVOKE_ON_CANCELSL_INVOKE_ON_ERRORSL_INVOKE_ON_SUCCESS都指示了驱动的I/O完成例程什么时候应该被调用。

Parameters – 这个域由几个子成员组成,任何一个都基于正被执行的I/O主函数被指定。

DeviceObject – 这个I/O请求的目标设备对象的一个指针。

FileObject – 关联这个请求的文件对象的一个指针。

在IRP的固定部分和首个I/O栈位置之后的部分都被适当地初始化,I/O管理器在它的与此请求的主函数代码对应的分发入口点中调用驱动栈中的顶部驱动。因此,如果I/O管理器刚好已经构造了一个IRP来描述一个读请求,那么它会在它的读分发入口点中调用首个驱动。在此分发入口点上,刚构造的IRP的指针,和驱动要在其上处理这个请求的设备所对应的设备对象的指针会被I/O管理器作为参数传给驱动。

描述数据缓冲

请求者的数据缓冲的描述符出现在IRP的固定部分中。为了让驱动程序员能描述关联一个I/O操作的请求者的数据缓冲,NT提供了三个不同的选项:

若缓冲被一个叫做内存描述符列表(MDL)的结构,以该缓冲在请求者的物理地址空间中的真实位置的方式描述了,那这就叫做Direct I/O

若缓冲中的数据会从请求者的地址空间中被复制到系统地址空间中的一个中间位置,且驱动被提供了这个数据副本的一个指针,那这就叫做Buffered I/O

若驱动被提供了请求者的缓冲的虚拟地址,那这就叫做Neither I/O

驱动必须为I/O管理器选择一种方式来描述所有被发送到一个特定设备上的读写请求。通过设置设备对象中的Flags域可以做出这个选择 (通常在设备对象被创建的初始化阶段) 。任何一个由驱动支持的设备I/O控制(IOCTL)代码,都会为读写请求选择不同的方式。

如果驱动选择Direct I/O,一切关联读或写I/O请求的数据缓冲都会被I/O管理器用MDL描述。MDL描述了这个数据缓冲在请求者的物理地址空间中的真实的位置。MDL的地址在被传给驱动的IRP的MdlAddress域中.

在IRP被传给驱动之前,I/O管理器会做检查来确保调用者对整个数据缓冲有适当的访问权。如果访问检查失败,I/O管理器会以一个错误状态来完成这个请求,而此请求也永远不会被传给驱动。

在访问检查完成之后,IRP被传给驱动之前,I/O管理器锁住内存中由数据缓冲组成的物理页。如果这个操作失败了(例如,在某一时间由于数据缓冲太大而不适合内存),此请求会被I/O管理器以一个错误状态来完成。如果锁定操作成功,页会在这个I/O操作的整个时间段内都保持被锁状态(直到IRP最终完成).

MDL能描述一个单一的逻辑连续的数据缓冲而不是物理连续的。它被设计为使获得物理地址和由数据缓冲组成的段的长度变得快捷。MDL结构的定义在NTDDK.H.示意图如图3:

3 – 一个MDL

即使大家都知道了MDL的结构,这也只是NT中真正不透明的数据结构的冰山一角。通过不透明,我们要表达的意思是驱动绝对不能假设MDL的结构。因此,驱动绝对不能直接引用MDL中的域。I/O和内存管理器为使用MDL的数据缓冲提供了获得相关信息的函数。这些函数包括:

·        MmGetSystemAddressForMdl(…) – 返回在一个任意线程上下文环境中的一个内核虚拟地址,它用于引用MDL描述的缓冲。由图4看出, MDL中的一个域(如果存在的话)会包含关联此MDL的被映射的系统虚拟地址.实际上这个函数就是NTDDK.H中的一个宏.这个函数被首次调用时,它调用MmMapLockedPages(…)来映射缓冲到内核虚拟地址空间中。然后返回的内核虚拟地址被存储到MDL的MappedSystemVa域中.在后来的MmGetSystemAddressForMdl(…)调用中,之前被存到MappedSystemVa中的值会被返回给调用者。当MDL被释放时(例如当I/O请求最终被完成了)一切映射都会被删除。

·        IoMapTransfer(…) – 这个函数主要是被DMA设备驱动用来获得物理地址和数据缓冲组成的段的长度。

·        MmGetMdlVirtualAddress(…) – 这个函数(实际上是NTDDK.H中的一个宏)返回被MDL描述的缓冲的请求者的虚拟地址。这个虚拟地址只能在调用进程的上下文中使用。这个函数也常常像请求者的虚拟地址一样被DMA设备驱动用作IoMapTransfer(…)的一个入参。

·        MmGetMdlByteCount(…)  NTDDK.H中的另外一个宏,此函数返回被MDL描述的缓冲的长度。

·        MmGetMdlByteOffset(…) – 这个函数也是NTDDK.H中的一个宏,它返回MDL的首页中的数据缓冲的起始偏移。

4 – MDL的域

MDL中的一个值得关注的域是Next.这个域是用于构造一个MDL链,该链上的所有MDL共同描述一个单一的逻辑不连续的缓冲。链中的任何一个MDL都描述一个单一的逻辑连续的缓冲。MDL 链仅用于网络驱动,且不被I/O管理器的大多数标准函数支持。因此,在NT中MDL链不能被标准的设备驱动使用。

Direct I/O一般用于基于包的DMA设备驱动。但它也能被一切想在一个用户缓冲和一个外设之间直接传输数据,而没有重缓冲这个数据的消耗(Buffer I/O的情形)也无需在调用进程的上下文中执行传输(Neither I/O的情形)

当IRP最终被完成(通过调用IoCompleteRequest(…))MdlAddress域非零时,I/O管理器解映射和解锁那些被映射和被锁的页,然后释放关联这个IRP的MDL。

Buffered I/O中系统空间中的一个中间缓冲被用作一个数据缓冲。I/O管理器负责在中间缓冲和请求者的原始数据缓冲之间移动数据。当IRP最终被完成时,系统缓冲被I/O管理器释放。

5 -- Buffered I/O方式的写

为准备一个Buffered I/O请求,I/O管理器会做检查来确保调用者对整个数据缓冲有合适的访问权,这与Direct I/O一样.如果调用者没有合适的访问权,则这个请求被完成且不会被传给驱动。作为一个优化,如果请求是从内核模式发起的那么就不会执行这个检查。

然后I/O管理器从非分页内存池中分配一个与该数据缓冲等大的系统缓冲。如果这是一个写操作,那么I/O管理器会从请求者的缓冲中复制数据到中间缓冲中。不论请求是读还是写,中间缓冲的内核虚拟地址都会在被传给驱动的IRP的AssociatedIrp.SystemAddress域中.注意即使这个域时IRP中"AssociatedIrp"结构的一部分,这个域也与关联的IRP没有任何关系。因为中间缓冲的地址对应系统的非分页池中的位置,这个地址能被在任意线程上下文中的驱动使用。当然,这个系统缓冲是逻辑连续的。但它不一定是逻辑连续的。

当使用Buffered I/O,在I/O操作期间,由原始数据缓冲组成的内存页没有被锁住。因此,它们能被分页的能力不受I/O操作的影响。

当一个使用Buffer I/O的读操作最终完成时,I/O管理器负责从中间缓冲中复制数据到请求者的数据缓冲。作为一个优化,在发出这个I/O请求的线程成为下一个要被执行的线程之前(通过"指定I/O完成的内核APC"),I/O管理器会延迟这个复制操作。当请求者线程是下一个要被执行的线程时,I/O管理器从中间系统缓冲中复制数据到请求者的缓冲,并释放系统缓冲。此优化不仅避免了可能会有的页负担,而且也为一个缓存热身函数提供了服务 – 用来自缓冲的数据预加载处理器缓存,从而使得处理器能在从这个I/O请求返回的时候进行快速访问。

Buffered I/O常常被用于控制设备I/O的数据传输量小的驱动。在此驱动中,用一个系统虚拟地址描述请求者的数据非常方便。

I/O管理器描述请求者的数据缓冲的最后一种方式叫做"Neither I/O".它如此命名仅仅是因为这类驱动请求既不是Buffered I/O也不是I/O.在此方式中,I/O管理器为驱动提供数据缓冲的请求者的虚拟地址。这个缓冲没有被锁到内存中;也没有中间的数据缓冲。这个地址在IRPUserBuffer 域中.

很显然,请求者的虚拟地址仅在调用进程的上下文中有用.结果就是,只有用Neither I/O的驱动才能无需任何中间驱动就能从I/O管理器中被直接进入,并能在调用进程的上下文中执行(并完成)I/O操作。因此,传统的存储器设备的驱动不能使用Neither I/O,因为它们的分发例程是在任意线程上下文中被调用的。大多数常规的设备驱动也不能使用Neither I/O,因为这些驱动的I/O请求常常是从DPC例程中开始的,也就是说它们也在任意线程的上下文中。

如果使用得当且谨慎,Neither I/O可能会是一些设备驱动的最理想的方式。例如,如果一个在调用线程的上下文中的驱动同步地执行其大部分的工作,Neither I/O就能节省创建一个MDL或再次复制数据的消耗。即使这个驱动偶尔中间地缓冲下数据或创建一个描述符来允许从任意线程的上下文中引用数据缓冲,Neither I/O能节省的消耗也是相当可观的。

那在你的驱动中,你怎么判断要用Direct I/O,Buffered I/ONeither I/O中的哪个有一个规则:如果你正在写一个中间的驱动,而它将会被分层到另一个驱动之上的话,那么你所使用的缓冲方式必须与在你之下的设备所使用的缓冲方式保持一致。

对设备驱动来说,这种的选择无疑是一个架构决策,它将影响驱动的复杂性和性能。如果你因客观因素而不得不用Neither I/O,而且你能应付要使用它的需求,你就应该选I/O.

然而,因其严格的限制,大多数驱动不会使用Neither I/O.一般,每次传输要操作至少一页的数据的驱动最好是使用Direct I/O.在传输期间,I/O管理器将锁住内存中的页,这就避免了数据的再次复制的消耗。用Direct I/O来进行大量数据的传输也避免了众多系统池的占用。大多数DMA驱动也会用Direct I/O.基于DMA设备的信息包的驱动会用它是因为这会允许它们轻易地获得物理基础地址和由数据缓冲组成的段的长度。公有缓冲DMA设备的驱动用它来避免一次额外的复制操作的消耗。

用程序的I/O相对缓慢地移动数据的驱动,存在长时间的未决操作的驱动和传输小块数据的驱动大多会用Buffered I/O.这包括传统的串口和并口的设备,也包括大多数简单的机器控制驱动。Buffered I/O是最容易实现的方式,因为在IRP中提供了在系统空间中一个包含数据的逻辑连续的缓冲的一个指针。

在非临界情形的大多数情况中,相对Direct I/O来说Buffered是很重要的。几乎所有NT驱动程序员刚开始的时候都会花费大量的时间来决定要用哪种方式。如果你不确定,而你正在写一个程序I/O类型的设备的驱动的话,从用Buffered I/O开始吧。一旦你写好了你的驱动,你就可以尝试来看看转到Direct I/O会不会给你更多性能增效。毕竟,从编程的观点来看,二者的仅有的区别是你从IRP的哪个地方找你的信息(Irp->AssociatedIrp.SystemBuffer还是Irp->DmaAddress)和一个函数调用(即调用MmGetSystemAddressForMdl(…)来获得映射被一个MDL描述的缓冲的一个系统虚拟地址). 这不是小菜一碟嘛!

{ // DHCPv4 configuration starts here. This section will be read by DHCPv4 server // and will be ignored by other components. "Control-agent": { "http-host": "localhost", "http-port": 8000 }, "Dhcp4": { "interfaces-config": { "interfaces": [ "enp3s0f0" ] }, "control-socket": { "socket-type": "unix", "socket-name": "/path/to/kea4-ctrl-socket" }, } "Dhcp4": { // Add names of your network interfaces to listen on. "interfaces-config": { // See section 8.2.4 for more details. You probably want to add just // interface name (e.g. "eth0" or specific IPv4 address on that // interface name (e.g. "eth0/192.0.2.1"). "interfaces": ["enp3s0f1/192.168.100.1"] // Kea DHCPv4 server by default listens using raw sockets. This ensures // all packets, including those sent by directly connected clients // that don't have IPv4 address yet, are received. However, if your // traffic is always relayed, it is often better to use regular // UDP sockets. If you want to do that, uncomment this line: // "dhcp-socket-type": "udp" }, // Kea supports control channel, which is a way to receive management // commands while the server is running. This is a Unix domain socket that // receives commands formatted in JSON, e.g. config-set (which sets new // configuration), config-reload (which tells Kea to reload its // configuration from file), statistic-get (to retrieve statistics) and many // more. For detailed description, see Sections 8.8, 16 and 15. "control-socket": { "socket-type": "unix", "socket-name": "kea4-ctrl-socket" }, // Use Memfile lease database backend to store leases in a CSV file. // Depending on how Kea was compiled, it may also support SQL databases // (MySQL and/or PostgreSQL). Those database backends require more // parameters, like name, host and possibly user and password. // There are dedicated examples for each backend. See Section 7.2.2 "Lease // Storage" for details. "lease-database": { // Memfile is the simplest and easiest backend to use. It's an in-memory // C++ database that stores its state in CSV file. "type": "memfile", "lfc-interval": 3600 }, // Kea allows storing host reservations in a database. If your network is // small or you have few reservations, it's probably easier to keep them // in the configuration file. If your network is large, it's usually better // to use database for it. To enable it, uncomment the following: // "hosts-database": { // "type": "mysql", // "name": "kea", // "user": "kea", // "password": "1234", // "host": "localhost", // "port": 3306 // }, // See Section 7.2.3 "Hosts storage" for details. // Setup reclamation of the expired leases and leases affinity. // Expired leases will be reclaimed every 10 seconds. Every 25 // seconds reclaimed leases, which have expired more than 3600 // seconds ago, will be removed. The limits for leases reclamation // are 100 leases or 250 ms for a single cycle. A warning message // will be logged if there are still expired leases in the // database after 5 consecutive reclamation cycles. // If both "flush-reclaimed-timer-wait-time" and "hold-reclaimed-time" are // not 0, when the client sends a release message the lease is expired // instead of being deleted from the lease storage. "expired-leases-processing": { "reclaim-timer-wait-time": 10, "flush-reclaimed-timer-wait-time": 25, "hold-reclaimed-time": 3600, "max-reclaim-leases": 100, "max-reclaim-time": 250, "unwarned-reclaim-cycles": 5 }, // Global timers specified here apply to all subnets, unless there are // subnet specific values defined in particular subnets. "renew-timer": 900, "rebind-timer": 60, "valid-lifetime": 3600, // Many additional parameters can be specified here: // - option definitions (if you want to define vendor options, your own // custom options or perhaps handle standard options // that Kea does not support out of the box yet) // - client classes // - hooks // - ddns information (how the DHCPv4 component can reach a DDNS daemon) // // Some of them have examples below, but there are other parameters. // Consult Kea User's Guide to find out about them. // These are global options. They are going to be sent when a client // requests them, unless overwritten with values in more specific scopes. // The scope hierarchy is: // - global (most generic, can be overwritten by class, subnet or host) // - class (can be overwritten by subnet or host) // - subnet (can be overwritten by host) // - host (most specific, overwrites any other scopes) // // Not all of those options make sense. Please configure only those that // are actually useful in your network. // // For a complete list of options currently supported by Kea, see // Section 7.2.8 "Standard DHCPv4 Options". Kea also supports // vendor options (see Section 7.2.10) and allows users to define their // own custom options (see Section 7.2.9). "option-data": [ // When specifying options, you typically need to specify // one of (name or code) and data. The full option specification // covers name, code, space, csv-format and data. // space defaults to "dhcp4" which is usually correct, unless you // use encapsulate options. csv-format defaults to "true", so // this is also correct, unless you want to specify the whole // option value as long hex string. For example, to specify // domain-name-servers you could do this: // { // "name": "domain-name-servers", // "code": 6, // "csv-format": "true", // "space": "dhcp4", // "data": "192.0.2.1, 192.0.2.2" // } // but it's a lot of writing, so it's easier to do this instead: { "name": "domain-name-servers", "data": "192.0.2.1, 192.0.2.2" }, // Typically people prefer to refer to options by their names, so they // don't need to remember the code names. However, some people like // to use numerical values. For example, option "domain-name" uses // option code 15, so you can reference to it either by // "name": "domain-name" or "code": 15. { "code": 15, "data": "example.org" }, // Domain search is also a popular option. It tells the client to // attempt to resolve names within those specified domains. For // example, name "foo" would be attempted to be resolved as // foo.mydomain.example.com and if it fails, then as foo.example.com { "name": "domain-search", "data": "mydomain.example.com, example.com" }, // String options that have a comma in their values need to have // it escaped (i.e. each comma is preceded by two backslashes). // That's because commas are reserved for separating fields in // compound options. At the same time, we need to be conformant // with JSON spec, that does not allow "\,". Therefore the // slightly uncommon double backslashes notation is needed. // Legal JSON escapes are \ followed by "\/bfnrt character // or \u followed by 4 hexadecimal numbers (currently Kea // supports only \u0000 to \u00ff code points). // CSV processing translates '\\' into '\' and '\,' into ',' // only so for instance '\x' is translated into '\x'. But // as it works on a JSON string value each of these '\' // characters must be doubled on JSON input. { "name": "boot-file-name", "data": "EST5EDT4\\,M3.2.0/02:00\\,M11.1.0/02:00" }, // Options that take integer values can either be specified in // dec or hex format. Hex format could be either plain (e.g. abcd) // or prefixed with 0x (e.g. 0xabcd). { "name": "default-ip-ttl", "data": "0xf0" } // Note that Kea provides some of the options on its own. In particular, // it sends IP Address lease type (code 51, based on valid-lifetime // parameter, Subnet mask (code 1, based on subnet definition), Renewal // time (code 58, based on renew-timer parameter), Rebind time (code 59, // based on rebind-timer parameter). ], // Other global parameters that can be defined here are option definitions // (this is useful if you want to use vendor options, your own custom // options or perhaps handle options that Kea does not handle out of the box // yet). // You can also define classes. If classes are defined, incoming packets // may be assigned to specific classes. A client class can represent any // group of devices that share some common characteristic, e.g. Windows // devices, iphones, broken printers that require special options, etc. // Based on the class information, you can then allow or reject clients // to use certain subnets, add special options for them or change values // of some fixed fields. "client-classes": [ { // This specifies a name of this class. It's useful if you need to // reference this class. "name": "voip", // This is a test. It is an expression that is being evaluated on // each incoming packet. It is supposed to evaluate to either // true or false. If it's true, the packet is added to specified // class. See Section 12 for a list of available expressions. There // are several dozens. Section 8.2.14 for more details for DHCPv4 // classification and Section 9.2.19 for DHCPv6. "test": "substring(option[60].hex,0,6) == 'Aastra'", // If a client belongs to this class, you can define extra behavior. // For example, certain fields in DHCPv4 packet will be set to // certain values. "next-server": "192.0.2.254", "server-hostname": "hal9000", "boot-file-name": "/dev/null" // You can also define option values here if you want devices from // this class to receive special options. } ], // Another thing possible here are hooks. Kea supports a powerful mechanism // that allows loading external libraries that can extract information and // even influence how the server processes packets. Those libraries include // additional forensic logging capabilities, ability to reserve hosts in // more flexible ways, and even add extra commands. For a list of available // hook libraries, see https://gitlab.isc.org/isc-projects/kea/wikis/Hooks-available. "hooks-libraries":[ { "library": "/usr/local/lib64/kea/hooks/libdhcp_macauth.so", "parameters": { "server_ip": "10.10.10.1", "ac_ip": "10.10.10.102", "port": 5001, "shared_secret": "7a5b8c3e9f" } }, { "library": "/usr/local/lib64/kea/hooks/libdhcp_lease_cmds.so" } //{ // "library": "/usr/local/lib64/kea/hooks/libdhcp_lease_query.so" // } ], // "hooks-libraries": [ // { // // Forensic Logging library generates forensic type of audit trail // // of all devices serviced by Kea, including their identifiers // // (like MAC address), their location in the network, times // // when they were active etc. // "library": "/usr/local/lib64/kea/hooks/libdhcp_legal_log.so", // "parameters": { // "base-name": "kea-forensic4" // } // }, // { // // Flexible identifier (flex-id). Kea software provides a way to // // handle host reservations that include addresses, prefixes, // // options, client classes and other features. The reservation can // // be based on hardware address, DUID, circuit-id or client-id in // // DHCPv4 and using hardware address or DUID in DHCPv6. However, // // there are sometimes scenario where the reservation is more // // complex, e.g. uses other options that mentioned above, uses part // // of specific options or perhaps even a combination of several // // options and fields to uniquely identify a client. Those scenarios // // are addressed by the Flexible Identifiers hook application. // "library": "/usr/local/lib64/kea/hooks/libdhcp_flex_id.so", // "parameters": { // "identifier-expression": "relay4[2].hex" // } // }, // { // // the MySQL host backend hook library required for host storage. // "library": "/usr/local/lib64/kea/hooks/libdhcp_mysql.so" // } // ], // Below an example of a simple IPv4 subnet declaration. Uncomment to enable // it. This is a list, denoted with [ ], of structures, each denoted with // { }. Each structure describes a single subnet and may have several // parameters. One of those parameters is "pools" that is also a list of // structures. "subnet4": [ { // This defines the whole subnet. Kea will use this information to // determine where the clients are connected. This is the whole // subnet in your network. // Subnet identifier should be unique for each subnet. "id": 1, // This is mandatory parameter for each subnet. "subnet": "192.168.30.0/24", // Pools define the actual part of your subnet that is governed // by Kea. Technically this is optional parameter, but it's // almost always needed for DHCP to do its job. If you omit it, // clients won't be able to get addresses, unless there are // host reservations defined for them. "pools": [ { "pool": "192.168.30.10 - 192.168.30.200" } ], // This is one of the subnet selectors. Uncomment the "interface" // parameter and specify the appropriate interface name if the DHCPv4 // server will receive requests from local clients (connected to the // same subnet as the server). This subnet will be selected for the // requests received by the server over the specified interface. // This rule applies to the DORA exchanges and rebinding clients. // Renewing clients unicast their messages, and the renewed addresses // are used by the server to determine the subnet they belong to. // When this parameter is used, the "relay" parameter is typically // unused. // "interface": "eth0", // This is another subnet selector. Uncomment the "relay" parameter // and specify a list of the relay addresses. The server will select // this subnet for lease assignments when it receives queries over one // of these relays. When this parameter is used, the "interface" parameter // is typically unused. // "relay": { // "ip-addresses": [ "10.0.0.1" ] // }, // These are options that are subnet specific. In most cases, // you need to define at least routers option, as without this // option your clients will not be able to reach their default // gateway and will not have Internet connectivity. "option-data": [ { // For each IPv4 subnet you most likely need to specify at // least one router. "name": "routers", "data": "192.0.2.1" } ], // Kea offers host reservations mechanism. Kea supports reservations // by several different types of identifiers: hw-address // (hardware/MAC address of the client), duid (DUID inserted by the // client), client-id (client identifier inserted by the client) and // circuit-id (circuit identifier inserted by the relay agent). // // Kea also support flexible identifier (flex-id), which lets you // specify an expression that is evaluated for each incoming packet. // Resulting value is then used for as an identifier. // // Note that reservations are subnet-specific in Kea. This is // different than ISC DHCP. Keep that in mind when migrating // your configurations. "reservations": [ // This is a reservation for a specific hardware/MAC address. // It's a rather simple reservation: just an address and nothing // else. // { // "hw-address": "1a:1b:1c:1d:1e:1f", // "ip-address": "192.0.2.201" // }, // This is a reservation for a specific client-id. It also shows // the this client will get a reserved hostname. A hostname can // be defined for any identifier type, not just client-id. { "client-id": "01:11:22:33:44:55:66", "ip-address": "192.168.30.202", "hostname": "special-snowflake" }, // The third reservation is based on DUID. This reservation defines // a special option values for this particular client. If the // domain-name-servers option would have been defined on a global, // subnet or class level, the host specific values take preference. { "duid": "01:02:03:04:05", "ip-address": "192.168.30.203", "option-data": [ { "name": "domain-name-servers", "data": "10.1.1.202, 10.1.1.203" } ] }, // The fourth reservation is based on circuit-id. This is an option // inserted by the relay agent that forwards the packet from client // to the server. In this example the host is also assigned vendor // specific options. // // When using reservations, it is useful to configure // reservations-global, reservations-in-subnet, // reservations-out-of-pool (subnet specific parameters) // and host-reservation-identifiers (global parameter). { "client-id": "01:12:23:34:45:56:67", "ip-address": "192.168.30.204", "option-data": [ { "name": "vivso-suboptions", "data": "4491" }, { "name": "tftp-servers", "space": "vendor-4491", "data": "10.1.1.202, 10.1.1.203" } ] }, // This reservation is for a client that needs specific DHCPv4 // fields to be set. Three supported fields are next-server, // server-hostname and boot-file-name { "client-id": "01:0a:0b:0c:0d:0e:0f", "ip-address": "192.168.30.205", "next-server": "192.168.30.1", "server-hostname": "hal9000", "boot-file-name": "/dev/null" }, // This reservation is using flexible identifier. Instead of // relying on specific field, sysadmin can define an expression // similar to what is used for client classification, // e.g. substring(relay[0].option[17],0,6). Then, based on the // value of that expression for incoming packet, the reservation // is matched. Expression can be specified either as hex or // plain text using single quotes. // // Note: flexible identifier requires flex_id hook library to be // loaded to work. { "flex-id": "'s0mEVaLue'", "ip-address": "192.168.30.206" } // You can add more reservations here. ] // You can add more subnets there. }, { "subnet": "192.168.100.0/24", "id":100, "pools": [ { "pool": "192.168.100.100 - 192.168.100.200" } ], "option-data": [ { "name": "routers", "data": "192.168.100.2" }, { "name": "domain-name-servers", "data": "8.8.8.8, 8.8.4.4" } ] }, { "subnet": "192.168.10.0/24", "id":10, "pools": [ { "pool": "192.168.10.100 - 192.168.10.200" } ], "relay": { "ip-addresses": ["192.168.10.1"] }, "option-data": [ { "name": "routers", "data": "192.168.10.1" }, { "name": "domain-name-servers", "data": "114.114.114.114,8.8.8.8" } ] }, { "id":20, "subnet": "192.168.20.0/24", "pools": [ { "pool": "192.168.20.100 - 192.168.20.200" } ], "relay": { "ip-addresses": ["192.168.20.1"] }, "option-data": [ { "name": "routers", "data": "192.168.20.1" }, { "name": "domain-name-servers", "data": "114.114.114.114, 8.8.4.4" } ] } ], // There are many, many more parameters that DHCPv4 server is able to use. // They were not added here to not overwhelm people with too much // information at once. // Logging configuration starts here. Kea uses different loggers to log various // activities. For details (e.g. names of loggers), see Chapter 18. "loggers": [ { // This section affects kea-dhcp4, which is the base logger for DHCPv4 // component. It tells DHCPv4 server to write all log messages (on // severity INFO or more) to a file. "name": "kea-dhcp4", "output-options": [ { // Specifies the output file. There are several special values // supported: // - stdout (prints on standard output) // - stderr (prints on standard error) // - syslog (logs to syslog) // - syslog:name (logs to syslog using specified name) // Any other value is considered a name of the file "output": "kea-dhcp4.log" // Shorter log pattern suitable for use with systemd, // avoids redundant information // "pattern": "%-5p %m\n", // This governs whether the log output is flushed to disk after // every write. // "flush": false, // This specifies the maximum size of the file before it is // rotated. // "maxsize": 1048576, // This specifies the maximum number of rotated files to keep. // "maxver": 8 } ], // This specifies the severity of log messages to keep. Supported values // are: FATAL, ERROR, WARN, INFO, DEBUG "severity": "INFO", // If DEBUG level is specified, this value is used. 0 is least verbose, // 99 is most verbose. Be cautious, Kea can generate lots and lots // of logs if told to do so. "debuglevel": 0 } ] } } 查看以上配置文件查看看dhcp配置接口开放配置有什么问题及语法错误并修复
最新发布
08-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值