Network Working Group W. Stevens Request for Comments: 2292 Consultant Category: Informational M. Thomas AltaVista February 1998
Network Working Group W. Stevens Request for Comments: 2292 Consultant Category: Informational M. Thomas AltaVista February 1998
Advanced Sockets API for IPv6
用于IPv6的高级套接字API
Status of this Memo
本备忘录的状况
This memo provides information for the Internet community. It does not specify an Internet standard of any kind. Distribution of this memo is unlimited.
本备忘录为互联网社区提供信息。它没有规定任何类型的互联网标准。本备忘录的分发不受限制。
Copyright Notice
版权公告
Copyright (C) The Internet Society (1998). All Rights Reserved.
版权所有(C)互联网协会(1998年)。版权所有。
Abstract
摘要
Specifications are in progress for changes to the sockets API to support IP version 6 [RFC-2133]. These changes are for TCP and UDP-based applications and will support most end-user applications in use today: Telnet and FTP clients and servers, HTTP clients and servers, and the like.
为支持IP版本6[RFC-2133],sockets API的变更规范正在进行中。这些更改适用于基于TCP和UDP的应用程序,并将支持当前使用的大多数最终用户应用程序:Telnet和FTP客户端和服务器、HTTP客户端和服务器等。
But another class of applications exists that will also be run under IPv6. We call these "advanced" applications and today this includes programs such as Ping, Traceroute, routing daemons, multicast routing daemons, router discovery daemons, and the like. The API feature typically used by these programs that make them "advanced" is a raw socket to access ICMPv4, IGMPv4, or IPv4, along with some knowledge of the packet header formats used by these protocols. To provide portability for applications that use raw sockets under IPv6, some standardization is needed for the advanced API features.
但另一类应用程序也将在IPv6下运行。我们将这些应用程序称为“高级”应用程序,现在包括Ping、Traceroute、路由守护程序、多播路由守护程序、路由器发现守护程序等程序。这些使其成为“高级”的程序通常使用的API功能是一个原始套接字,用于访问ICMPv4、IGMPv4或IPv4,并了解这些协议使用的数据包头格式。为了为在IPv6下使用原始套接字的应用程序提供可移植性,需要对高级API功能进行一些标准化。
There are other features of IPv6 that some applications will need to access: interface identification (specifying the outgoing interface and determining the incoming interface) and IPv6 extension headers that are not addressed in [RFC-2133]: Hop-by-Hop options, Destination options, and the Routing header (source routing). This document provides API access to these features too.
有些应用程序需要访问IPv6的其他功能:接口标识(指定传出接口并确定传入接口)和[RFC-2133]中未提及的IPv6扩展头:逐跳选项、目标选项和路由头(源路由)。本文档还提供了对这些功能的API访问。
Table of Contents
目录
1. Introduction ................................................3 2. Common Structures and Definitions ...........................5 2.1. The ip6_hdr Structure ..................................5 2.1.1. IPv6 Next Header Values .........................6 2.1.2. IPv6 Extension Headers ..........................6 2.2. The icmp6_hdr Structure ................................8 2.2.1. ICMPv6 Type and Code Values .....................8 2.2.2. ICMPv6 Neighbor Discovery Type and Code Values ..9 2.3. Address Testing Macros .................................12 2.4. Protocols File .........................................12 3. IPv6 Raw Sockets ............................................13 3.1. Checksums ..............................................14 3.2. ICMPv6 Type Filtering ..................................14 4. Ancillary Data ..............................................17 4.1. The msghdr Structure ...................................18 4.2. The cmsghdr Structure ..................................18 4.3. Ancillary Data Object Macros ...........................19 4.3.1. CMSG_FIRSTHDR ...................................20 4.3.2. CMSG_NXTHDR .....................................22 4.3.3. CMSG_DATA .......................................22 4.3.4. CMSG_SPACE ......................................22 4.3.5. CMSG_LEN ........................................22 4.4. Summary of Options Described Using Ancillary Data ......23 4.5. IPV6_PKTOPTIONS Socket Option ..........................24 4.5.1. TCP Sticky Options ..............................25 4.5.2. UDP and Raw Socket Sticky Options ...............26 5. Packet Information ..........................................26 5.1. Specifying/Receiving the Interface .....................27 5.2. Specifying/Receiving Source/Destination Address ........27 5.3. Specifying/Receiving the Hop Limit .....................28 5.4. Specifying the Next Hop Address ........................29 5.5. Additional Errors with sendmsg() .......................29 6. Hop-By-Hop Options ..........................................30 6.1. Receiving Hop-by-Hop Options ...........................31 6.2. Sending Hop-by-Hop Options .............................31 6.3. Hop-by-Hop and Destination Options Processing ..........32 6.3.1. inet6_option_space ..............................32 6.3.2. inet6_option_init ...............................32 6.3.3. inet6_option_append .............................33 6.3.4. inet6_option_alloc ..............................33 6.3.5. inet6_option_next ...............................34 6.3.6. inet6_option_find ...............................35 6.3.7. Options Examples ................................35 7. Destination Options .........................................42 7.1. Receiving Destination Options ..........................42 7.2. Sending Destination Options ............................43
1. Introduction ................................................3 2. Common Structures and Definitions ...........................5 2.1. The ip6_hdr Structure ..................................5 2.1.1. IPv6 Next Header Values .........................6 2.1.2. IPv6 Extension Headers ..........................6 2.2. The icmp6_hdr Structure ................................8 2.2.1. ICMPv6 Type and Code Values .....................8 2.2.2. ICMPv6 Neighbor Discovery Type and Code Values ..9 2.3. Address Testing Macros .................................12 2.4. Protocols File .........................................12 3. IPv6 Raw Sockets ............................................13 3.1. Checksums ..............................................14 3.2. ICMPv6 Type Filtering ..................................14 4. Ancillary Data ..............................................17 4.1. The msghdr Structure ...................................18 4.2. The cmsghdr Structure ..................................18 4.3. Ancillary Data Object Macros ...........................19 4.3.1. CMSG_FIRSTHDR ...................................20 4.3.2. CMSG_NXTHDR .....................................22 4.3.3. CMSG_DATA .......................................22 4.3.4. CMSG_SPACE ......................................22 4.3.5. CMSG_LEN ........................................22 4.4. Summary of Options Described Using Ancillary Data ......23 4.5. IPV6_PKTOPTIONS Socket Option ..........................24 4.5.1. TCP Sticky Options ..............................25 4.5.2. UDP and Raw Socket Sticky Options ...............26 5. Packet Information ..........................................26 5.1. Specifying/Receiving the Interface .....................27 5.2. Specifying/Receiving Source/Destination Address ........27 5.3. Specifying/Receiving the Hop Limit .....................28 5.4. Specifying the Next Hop Address ........................29 5.5. Additional Errors with sendmsg() .......................29 6. Hop-By-Hop Options ..........................................30 6.1. Receiving Hop-by-Hop Options ...........................31 6.2. Sending Hop-by-Hop Options .............................31 6.3. Hop-by-Hop and Destination Options Processing ..........32 6.3.1. inet6_option_space ..............................32 6.3.2. inet6_option_init ...............................32 6.3.3. inet6_option_append .............................33 6.3.4. inet6_option_alloc ..............................33 6.3.5. inet6_option_next ...............................34 6.3.6. inet6_option_find ...............................35 6.3.7. Options Examples ................................35 7. Destination Options .........................................42 7.1. Receiving Destination Options ..........................42 7.2. Sending Destination Options ............................43
8. Routing Header Option .......................................43 8.1. inet6_rthdr_space ......................................44 8.2. inet6_rthdr_init .......................................45 8.3. inet6_rthdr_add ........................................45 8.4. inet6_rthdr_lasthop ....................................46 8.5. inet6_rthdr_reverse ....................................46 8.6. inet6_rthdr_segments ...................................46 8.7. inet6_rthdr_getaddr ....................................46 8.8. inet6_rthdr_getflags ...................................47 8.9. Routing Header Example .................................47 9. Ordering of Ancillary Data and IPv6 Extension Headers .......53 10. IPv6-Specific Options with IPv4-Mapped IPv6 Addresses .......54 11. rresvport_af ................................................55 12. Future Items ................................................55 12.1. Flow Labels ...........................................55 12.2. Path MTU Discovery and UDP ............................56 12.3. Neighbor Reachability and UDP .........................56 13. Summary of New Definitions ..................................56 14. Security Considerations .....................................59 15. Change History ..............................................59 16. References ..................................................65 17. Acknowledgments .............................................65 18. Authors' Addresses ..........................................66 19. Full Copyright Statement ....................................67
8. Routing Header Option .......................................43 8.1. inet6_rthdr_space ......................................44 8.2. inet6_rthdr_init .......................................45 8.3. inet6_rthdr_add ........................................45 8.4. inet6_rthdr_lasthop ....................................46 8.5. inet6_rthdr_reverse ....................................46 8.6. inet6_rthdr_segments ...................................46 8.7. inet6_rthdr_getaddr ....................................46 8.8. inet6_rthdr_getflags ...................................47 8.9. Routing Header Example .................................47 9. Ordering of Ancillary Data and IPv6 Extension Headers .......53 10. IPv6-Specific Options with IPv4-Mapped IPv6 Addresses .......54 11. rresvport_af ................................................55 12. Future Items ................................................55 12.1. Flow Labels ...........................................55 12.2. Path MTU Discovery and UDP ............................56 12.3. Neighbor Reachability and UDP .........................56 13. Summary of New Definitions ..................................56 14. Security Considerations .....................................59 15. Change History ..............................................59 16. References ..................................................65 17. Acknowledgments .............................................65 18. Authors' Addresses ..........................................66 19. Full Copyright Statement ....................................67
Specifications are in progress for changes to the sockets API to support IP version 6 [RFC-2133]. These changes are for TCP and UDP-based applications. The current document defines some the "advanced" features of the sockets API that are required for applications to take advantage of additional features of IPv6.
为支持IP版本6[RFC-2133],sockets API的变更规范正在进行中。这些更改适用于基于TCP和UDP的应用程序。当前文档定义了sockets API的一些“高级”功能,这些功能是应用程序利用IPv6附加功能所必需的。
Today, the portability of applications using IPv4 raw sockets is quite high, but this is mainly because most IPv4 implementations started from a common base (the Berkeley source code) or at least started with the Berkeley headers. This allows programs such as Ping and Traceroute, for example, to compile with minimal effort on many hosts that support the sockets API. With IPv6, however, there is no common source code base that implementors are starting from, and the possibility for divergence at this level between different implementations is high. To avoid a complete lack of portability amongst applications that use raw IPv6 sockets, some standardization is necessary.
如今,使用IPv4原始套接字的应用程序的可移植性相当高,但这主要是因为大多数IPv4实现都是从公共基础(Berkeley源代码)开始的,或者至少是从Berkeley头开始的。例如,这允许Ping和Traceroute等程序在许多支持socketsapi的主机上以最小的工作量进行编译。然而,在IPv6中,实现者并没有共同的源代码基础,不同实现之间在这一级别上出现差异的可能性很高。为了避免使用原始IPv6套接字的应用程序之间完全缺乏可移植性,需要进行一些标准化。
There are also features from the basic IPv6 specification that are not addressed in [RFC-2133]: sending and receiving Hop-by-Hop options, Destination options, and Routing headers, specifying the outgoing interface, and being told of the receiving interface.
[RFC-2133]中还未涉及基本IPv6规范中的一些功能:发送和接收逐跳选项、目标选项和路由头,指定传出接口,并告知接收接口。
This document can be divided into the following main sections.
本文件可分为以下主要部分。
1. Definitions of the basic constants and structures required for applications to use raw IPv6 sockets. This includes structure definitions for the IPv6 and ICMPv6 headers and all associated constants (e.g., values for the Next Header field).
1. 应用程序使用原始IPv6套接字所需的基本常量和结构的定义。这包括IPv6和ICMPv6标头的结构定义以及所有相关常量(例如,下一个标头字段的值)。
2. Some basic semantic definitions for IPv6 raw sockets. For example, a raw ICMPv4 socket requires the application to calculate and store the ICMPv4 header checksum. But with IPv6 this would require the application to choose the source IPv6 address because the source address is part of the pseudo header that ICMPv6 now uses for its checksum computation. It should be defined that with a raw ICMPv6 socket the kernel always calculates and stores the ICMPv6 header checksum.
2. IPv6原始套接字的一些基本语义定义。例如,原始ICMPv4套接字要求应用程序计算并存储ICMPv4头校验和。但对于IPv6,这将要求应用程序选择源IPv6地址,因为源地址是ICMPv6现在用于校验和计算的伪报头的一部分。应该定义,对于原始ICMPv6套接字,内核始终计算并存储ICMPv6头校验和。
3. Packet information: how applications can obtain the received interface, destination address, and received hop limit, along with specifying these values on a per-packet basis. There are a class of applications that need this capability and the technique should be portable.
3. 数据包信息:应用程序如何获得接收接口、目标地址和接收的跃点限制,以及在每个数据包的基础上指定这些值。有一类应用程序需要这种功能,而且这种技术应该是可移植的。
4. Access to the optional Hop-by-Hop, Destination, and Routing headers.
4. 访问可选的逐跳、目标和路由标头。
5. Additional features required for IPv6 application portability.
5. IPv6应用程序可移植性所需的其他功能。
The packet information along with access to the extension headers (Hop-by-Hop options, Destination options, and Routing header) are specified using the "ancillary data" fields that were added to the 4.3BSD Reno sockets API in 1990. The reason is that these ancillary data fields are part of the Posix.1g standard (which should be approved in 1997) and should therefore be adopted by most vendors.
使用1990年添加到4.3BSD Reno sockets API中的“辅助数据”字段指定数据包信息以及对扩展头的访问(逐跳选项、目的地选项和路由头)。原因是这些辅助数据字段是Posix.1g标准的一部分(应在1997年获得批准),因此应被大多数供应商采用。
This document does not address application access to either the authentication header or the encapsulating security payload header.
本文档不涉及对身份验证标头或封装安全有效负载标头的应用程序访问。
All examples in this document omit error checking in favor of brevity and clarity.
为了简洁明了,本文档中的所有示例都省略了错误检查。
We note that many of the functions and socket options defined in this document may have error returns that are not defined in this document. Many of these possible error returns will be recognized only as implementations proceed.
我们注意到,本文档中定义的许多函数和套接字选项可能具有本文档中未定义的错误返回。许多可能的错误返回只有在实现过程中才能被识别。
Datatypes in this document follow the Posix.1g format: intN_t means a signed integer of exactly N bits (e.g., int16_t) and uintN_t means an unsigned integer of exactly N bits (e.g., uint32_t).
本文档中的数据类型遵循Posix.1g格式:intN_t表示正好N位的有符号整数(例如int16_t),uintN_t表示正好N位的无符号整数(例如uint32_t)。
Note that we use the (unofficial) terminology ICMPv4, IGMPv4, and ARPv4 to avoid any confusion with the newer ICMPv6 protocol.
请注意,我们使用(非官方)术语ICMPv4、IGMPv4和ARPv4,以避免与较新的ICMPv6协议混淆。
Many advanced applications examine fields in the IPv6 header and set and examine fields in the various ICMPv6 headers. Common structure definitions for these headers are required, along with common constant definitions for the structure members.
许多高级应用程序检查IPv6标头中的字段,并设置和检查各种ICMPv6标头中的字段。这些标头需要公共结构定义,以及结构成员的公共常量定义。
Two new headers are defined: <netinet/ip6.h> and <netinet/icmp6.h>.
定义了两个新的头文件:<netinet/ip6.h>和<netinet/icmp6.h>。
When an include file is specified, that include file is allowed to include other files that do the actual declaration or definition.
指定包含文件时,该包含文件允许包含执行实际声明或定义的其他文件。
The following structure is defined as a result of including <netinet/ip6.h>. Note that this is a new header.
以下结构定义为包含<netinet/ip6.h>的结果。请注意,这是一个新标题。
struct ip6_hdr { union { struct ip6_hdrctl { uint32_t ip6_un1_flow; /* 24 bits of flow-ID */ uint16_t ip6_un1_plen; /* payload length */ uint8_t ip6_un1_nxt; /* next header */ uint8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; uint8_t ip6_un2_vfc; /* 4 bits version, 4 bits priority */ } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ };
struct ip6_hdr { union { struct ip6_hdrctl { uint32_t ip6_un1_flow; /* 24 bits of flow-ID */ uint16_t ip6_un1_plen; /* payload length */ uint8_t ip6_un1_nxt; /* next header */ uint8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; uint8_t ip6_un2_vfc; /* 4 bits version, 4 bits priority */ } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ };
#define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
#定义ip6_vfc ip6_ctlun.ip6_un2_vfc#定义ip6_流ip6_ctlun.ip6_un1.ip6_un1_流#定义ip6_plen ip6_ctlun.ip6_un1.ip6_un1#定义ip6_nxt ip6_un1.ip6_un1.ip6_1#nxt
#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
#定义ip6_跃点ip6_ctlun.ip6_un1.ip6_un1_hlim
IPv6 defines many new values for the Next Header field. The following constants are defined as a result of including <netinet/in.h>.
IPv6为下一个标头字段定义了许多新值。以下常量是由于包含<netinet/in.h>而定义的。
#define IPPROTO_HOPOPTS 0 /* IPv6 Hop-by-Hop options */ #define IPPROTO_IPV6 41 /* IPv6 header */ #define IPPROTO_ROUTING 43 /* IPv6 Routing header */ #define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ #define IPPROTO_ESP 50 /* encapsulating security payload */ #define IPPROTO_AH 51 /* authentication header */ #define IPPROTO_ICMPV6 58 /* ICMPv6 */ #define IPPROTO_NONE 59 /* IPv6 no next header */ #define IPPROTO_DSTOPTS 60 /* IPv6 Destination options */
#define IPPROTO_HOPOPTS 0 /* IPv6 Hop-by-Hop options */ #define IPPROTO_IPV6 41 /* IPv6 header */ #define IPPROTO_ROUTING 43 /* IPv6 Routing header */ #define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ #define IPPROTO_ESP 50 /* encapsulating security payload */ #define IPPROTO_AH 51 /* authentication header */ #define IPPROTO_ICMPV6 58 /* ICMPv6 */ #define IPPROTO_NONE 59 /* IPv6 no next header */ #define IPPROTO_DSTOPTS 60 /* IPv6 Destination options */
Berkeley-derived IPv4 implementations also define IPPROTO_IP to be 0. This should not be a problem since IPPROTO_IP is used only with IPv4 sockets and IPPROTO_HOPOPTS only with IPv6 sockets.
Berkeley派生的IPv4实现还将IPPROTO_IP定义为0。这应该不是问题,因为IPPROTO_IP仅用于IPv4套接字,而IPPROTO_hopts仅用于IPv6套接字。
Six extension headers are defined for IPv6. We define structures for all except the Authentication header and Encapsulating Security Payload header, both of which are beyond the scope of this document. The following structures are defined as a result of including <netinet/ip6.h>.
为IPv6定义了六个扩展标头。我们为除身份验证头和封装安全负载头之外的所有头定义了结构,这两个头都超出了本文的范围。以下结构定义为包含<netinet/ip6.h>的结果。
/* Hop-by-Hop options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ struct ip6_hbh { uint8_t ip6h_nxt; /* next header */ uint8_t ip6h_len; /* length in units of 8 octets */ /* followed by options */ };
/* Hop-by-Hop options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ struct ip6_hbh { uint8_t ip6h_nxt; /* next header */ uint8_t ip6h_len; /* length in units of 8 octets */ /* followed by options */ };
/* Destination options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ struct ip6_dest { uint8_t ip6d_nxt; /* next header */ uint8_t ip6d_len; /* length in units of 8 octets */ /* followed by options */ };
/* Destination options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ struct ip6_dest { uint8_t ip6d_nxt; /* next header */ uint8_t ip6d_len; /* length in units of 8 octets */ /* followed by options */ };
/* Routing header */ struct ip6_rthdr {
/* Routing header */ struct ip6_rthdr {
uint8_t ip6r_nxt; /* next header */ uint8_t ip6r_len; /* length in units of 8 octets */ uint8_t ip6r_type; /* routing type */ uint8_t ip6r_segleft; /* segments left */ /* followed by routing type specific data */ };
uint8_t ip6r_nxt; /* next header */ uint8_t ip6r_len; /* length in units of 8 octets */ uint8_t ip6r_type; /* routing type */ uint8_t ip6r_segleft; /* segments left */ /* followed by routing type specific data */ };
/* Type 0 Routing header */ struct ip6_rthdr0 { uint8_t ip6r0_nxt; /* next header */ uint8_t ip6r0_len; /* length in units of 8 octets */ uint8_t ip6r0_type; /* always zero */ uint8_t ip6r0_segleft; /* segments left */ uint8_t ip6r0_reserved; /* reserved field */ uint8_t ip6r0_slmap[3]; /* strict/loose bit map */ struct in6_addr ip6r0_addr[1]; /* up to 23 addresses */ };
/* Type 0 Routing header */ struct ip6_rthdr0 { uint8_t ip6r0_nxt; /* next header */ uint8_t ip6r0_len; /* length in units of 8 octets */ uint8_t ip6r0_type; /* always zero */ uint8_t ip6r0_segleft; /* segments left */ uint8_t ip6r0_reserved; /* reserved field */ uint8_t ip6r0_slmap[3]; /* strict/loose bit map */ struct in6_addr ip6r0_addr[1]; /* up to 23 addresses */ };
/* Fragment header */ struct ip6_frag { uint8_t ip6f_nxt; /* next header */ uint8_t ip6f_reserved; /* reserved field */ uint16_t ip6f_offlg; /* offset, reserved, and flag */ uint32_t ip6f_ident; /* identification */ };
/* Fragment header */ struct ip6_frag { uint8_t ip6f_nxt; /* next header */ uint8_t ip6f_reserved; /* reserved field */ uint16_t ip6f_offlg; /* offset, reserved, and flag */ uint32_t ip6f_ident; /* identification */ };
#if BYTE_ORDER == BIG_ENDIAN #define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */ #define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */ #define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */ #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */ #define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */ #define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */ #endif
#if BYTE_ORDER == BIG_ENDIAN #define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */ #define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */ #define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */ #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */ #define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */ #define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */ #endif
Defined constants for fields larger than 1 byte depend on the byte ordering that is used. This API assumes that the fields in the protocol headers are left in the network byte order, which is big-endian for the Internet protocols. If not, then either these constants or the fields being tested must be converted at run-time, using something like htons() or htonl().
大于1字节的字段的定义常量取决于所使用的字节顺序。此API假定协议头中的字段按网络字节顺序保留,这是Internet协议的大端。如果不是,则必须在运行时使用诸如htons()或htonl()之类的方法转换这些常量或正在测试的字段。
(Note: We show an implementation that supports both big-endian and little-endian byte ordering, assuming a hypothetical compile-time #if test to determine the byte ordering. The constant that we show,
(注意:我们展示了一个同时支持big-endian和little-endian字节顺序的实现,假设一个假设的编译时#if测试来确定字节顺序,
BYTE_ORDER, with values of BIG_ENDIAN and LITTLE_ENDIAN, are for example purposes only. If an implementation runs on only one type of hardware it need only define the set of constants for that hardware's byte ordering.)
值为BIG_ENDIAN和LITTLE_ENDIAN的字节顺序仅用于示例目的。如果实现仅在一种类型的硬件上运行,则只需为该硬件的字节顺序定义一组常量。)
The ICMPv6 header is needed by numerous IPv6 applications including Ping, Traceroute, router discovery daemons, and neighbor discovery daemons. The following structure is defined as a result of including <netinet/icmp6.h>. Note that this is a new header.
许多IPv6应用程序(包括Ping、Traceroute、路由器发现守护程序和邻居发现守护程序)都需要ICMPv6报头。以下结构定义为包含<netinet/icmp6.h>的结果。请注意,这是一个新标题。
struct icmp6_hdr { uint8_t icmp6_type; /* type field */ uint8_t icmp6_code; /* code field */ uint16_t icmp6_cksum; /* checksum field */ union { uint32_t icmp6_un_data32[1]; /* type-specific field */ uint16_t icmp6_un_data16[2]; /* type-specific field */ uint8_t icmp6_un_data8[4]; /* type-specific field */ } icmp6_dataun; };
struct icmp6_hdr { uint8_t icmp6_type; /* type field */ uint8_t icmp6_code; /* code field */ uint16_t icmp6_cksum; /* checksum field */ union { uint32_t icmp6_un_data32[1]; /* type-specific field */ uint16_t icmp6_un_data16[2]; /* type-specific field */ uint8_t icmp6_un_data8[4]; /* type-specific field */ } icmp6_dataun; };
#define icmp6_data32 icmp6_dataun.icmp6_un_data32 #define icmp6_data16 icmp6_dataun.icmp6_un_data16 #define icmp6_data8 icmp6_dataun.icmp6_un_data8 #define icmp6_pptr icmp6_data32[0] /* parameter prob */ #define icmp6_mtu icmp6_data32[0] /* packet too big */ #define icmp6_id icmp6_data16[0] /* echo request/reply */ #define icmp6_seq icmp6_data16[1] /* echo request/reply */ #define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */
#define icmp6_data32 icmp6_dataun.icmp6_un_data32 #define icmp6_data16 icmp6_dataun.icmp6_un_data16 #define icmp6_data8 icmp6_dataun.icmp6_un_data8 #define icmp6_pptr icmp6_data32[0] /* parameter prob */ #define icmp6_mtu icmp6_data32[0] /* packet too big */ #define icmp6_id icmp6_data16[0] /* echo request/reply */ #define icmp6_seq icmp6_data16[1] /* echo request/reply */ #define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */
In addition to a common structure for the ICMPv6 header, common definitions are required for the ICMPv6 type and code fields. The following constants are also defined as a result of including <netinet/icmp6.h>.
除了ICMPv6头的通用结构外,ICMPv6类型和代码字段还需要通用定义。以下常量也是由于包含<netinet/icmp6.h>而定义的。
#define ICMP6_DST_UNREACH 1 #define ICMP6_PACKET_TOO_BIG 2 #define ICMP6_TIME_EXCEEDED 3 #define ICMP6_PARAM_PROB 4
#定义ICMP6未读1定义ICMP6数据包太大2定义ICMP6时间超过3定义ICMP6参数问题4
#define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */
#define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */
#define ICMP6_ECHO_REQUEST 128 #define ICMP6_ECHO_REPLY 129
#定义ICMP6_ECHO_请求128#定义ICMP6_ECHO_回复129
#define ICMP6_MEMBERSHIP_QUERY 130 #define ICMP6_MEMBERSHIP_REPORT 131 #define ICMP6_MEMBERSHIP_REDUCTION 132
#定义ICMP6_成员资格查询130#定义ICMP6_成员资格报告131#定义ICMP6_成员资格减少132
#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ #define ICMP6_DST_UNREACH_ADMIN 1 /* communication with */ /* destination */ /* administratively */ /* prohibited */ #define ICMP6_DST_UNREACH_NOTNEIGHBOR 2 /* not a neighbor */ #define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */ #define ICMP6_DST_UNREACH_NOPORT 4 /* bad port */
#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ #define ICMP6_DST_UNREACH_ADMIN 1 /* communication with */ /* destination */ /* administratively */ /* prohibited */ #define ICMP6_DST_UNREACH_NOTNEIGHBOR 2 /* not a neighbor */ #define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */ #define ICMP6_DST_UNREACH_NOPORT 4 /* bad port */
#define ICMP6_TIME_EXCEED_TRANSIT 0 /* Hop Limit == 0 in transit */ #define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* Reassembly time out */
#define ICMP6_TIME_EXCEED_TRANSIT 0 /* Hop Limit == 0 in transit */ #define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* Reassembly time out */
#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */ #define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized Next Header */ #define ICMP6_PARAMPROB_OPTION 2 /* unrecognized IPv6 option */
#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */ #define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized Next Header */ #define ICMP6_PARAMPROB_OPTION 2 /* unrecognized IPv6 option */
The five ICMP message types defined by IPv6 neighbor discovery (133- 137) are defined in the next section.
IPv6邻居发现(133-137)定义的五种ICMP消息类型将在下一节中定义。
The following structures and definitions are defined as a result of including <netinet/icmp6.h>.
以下结构和定义是包含<netinet/icmp6.h>的结果。
#define ND_ROUTER_SOLICIT 133 #define ND_ROUTER_ADVERT 134 #define ND_NEIGHBOR_SOLICIT 135 #define ND_NEIGHBOR_ADVERT 136 #define ND_REDIRECT 137
#定义NDU路由器请求133#定义NDU路由器请求134#定义NDU邻居请求135#定义NDU邻居请求136#定义NDU重定向137
struct nd_router_solicit { /* router solicitation */ struct icmp6_hdr nd_rs_hdr; /* could be followed by options */ };
struct nd_router_solicit { /* router solicitation */ struct icmp6_hdr nd_rs_hdr; /* could be followed by options */ };
#define nd_rs_type nd_rs_hdr.icmp6_type #define nd_rs_code nd_rs_hdr.icmp6_code #define nd_rs_cksum nd_rs_hdr.icmp6_cksum #define nd_rs_reserved nd_rs_hdr.icmp6_data32[0]
#定义nd_rs_类型nd_rs_hdr.icmp6_类型#定义nd_rs_hdr.icmp6_代码#定义nd_rs_校验和nd_rs_hdr.icmp6#定义nd_rs_保留nd_rs_hdr.icmp6#数据32[0]
struct nd_router_advert { /* router advertisement */ struct icmp6_hdr nd_ra_hdr; uint32_t nd_ra_reachable; /* reachable time */ uint32_t nd_ra_retransmit; /* retransmit timer */
struct nd_router_advert { /* router advertisement */ struct icmp6_hdr nd_ra_hdr; uint32_t nd_ra_reachable; /* reachable time */ uint32_t nd_ra_retransmit; /* retransmit timer */
/* could be followed by options */ };
/* could be followed by options */ };
#define nd_ra_type nd_ra_hdr.icmp6_type #define nd_ra_code nd_ra_hdr.icmp6_code #define nd_ra_cksum nd_ra_hdr.icmp6_cksum #define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0] #define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] #define ND_RA_FLAG_MANAGED 0x80 #define ND_RA_FLAG_OTHER 0x40 #define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1]
#define nd_ra_type nd_ra_hdr.icmp6_type #define nd_ra_code nd_ra_hdr.icmp6_code #define nd_ra_cksum nd_ra_hdr.icmp6_cksum #define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0] #define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] #define ND_RA_FLAG_MANAGED 0x80 #define ND_RA_FLAG_OTHER 0x40 #define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1]
struct nd_neighbor_solicit { /* neighbor solicitation */ struct icmp6_hdr nd_ns_hdr; struct in6_addr nd_ns_target; /* target address */ /* could be followed by options */ };
struct nd_neighbor_solicit { /* neighbor solicitation */ struct icmp6_hdr nd_ns_hdr; struct in6_addr nd_ns_target; /* target address */ /* could be followed by options */ };
#define nd_ns_type nd_ns_hdr.icmp6_type #define nd_ns_code nd_ns_hdr.icmp6_code #define nd_ns_cksum nd_ns_hdr.icmp6_cksum #define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
#定义nd_ns_类型nd_ns_hdr.icmp6_类型#定义nd_ns_hdr.icmp6_代码#定义nd_ns_校验和nd_ns_hdr.icmp6_校验和#定义nd_ns_保留的nd_ns_hdr.icmp6_数据32[0]
struct nd_neighbor_advert { /* neighbor advertisement */ struct icmp6_hdr nd_na_hdr; struct in6_addr nd_na_target; /* target address */ /* could be followed by options */ };
struct nd_neighbor_advert { /* neighbor advertisement */ struct icmp6_hdr nd_na_hdr; struct in6_addr nd_na_target; /* target address */ /* could be followed by options */ };
#define nd_na_type nd_na_hdr.icmp6_type #define nd_na_code nd_na_hdr.icmp6_code #define nd_na_cksum nd_na_hdr.icmp6_cksum #define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0] #if BYTE_ORDER == BIG_ENDIAN #define ND_NA_FLAG_ROUTER 0x80000000 #define ND_NA_FLAG_SOLICITED 0x40000000 #define ND_NA_FLAG_OVERRIDE 0x20000000 #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define ND_NA_FLAG_ROUTER 0x00000080 #define ND_NA_FLAG_SOLICITED 0x00000040 #define ND_NA_FLAG_OVERRIDE 0x00000020 #endif
#define nd_na_type nd_na_hdr.icmp6_type #define nd_na_code nd_na_hdr.icmp6_code #define nd_na_cksum nd_na_hdr.icmp6_cksum #define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0] #if BYTE_ORDER == BIG_ENDIAN #define ND_NA_FLAG_ROUTER 0x80000000 #define ND_NA_FLAG_SOLICITED 0x40000000 #define ND_NA_FLAG_OVERRIDE 0x20000000 #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define ND_NA_FLAG_ROUTER 0x00000080 #define ND_NA_FLAG_SOLICITED 0x00000040 #define ND_NA_FLAG_OVERRIDE 0x00000020 #endif
struct nd_redirect { /* redirect */ struct icmp6_hdr nd_rd_hdr; struct in6_addr nd_rd_target; /* target address */ struct in6_addr nd_rd_dst; /* destination address */ /* could be followed by options */
struct nd_redirect { /* redirect */ struct icmp6_hdr nd_rd_hdr; struct in6_addr nd_rd_target; /* target address */ struct in6_addr nd_rd_dst; /* destination address */ /* could be followed by options */
};
};
#define nd_rd_type nd_rd_hdr.icmp6_type #define nd_rd_code nd_rd_hdr.icmp6_code #define nd_rd_cksum nd_rd_hdr.icmp6_cksum #define nd_rd_reserved nd_rd_hdr.icmp6_data32[0]
#定义nd#rd#U类型nd#rd#U hdr.icmp6#U类型#定义nd#rd#U代码nd#U hdr.icmp6#定义nd#rd#U保留nd#rd#U hdr.icmp6#U数据32[0]
struct nd_opt_hdr { /* Neighbor discovery option header */ uint8_t nd_opt_type; uint8_t nd_opt_len; /* in units of 8 octets */ /* followed by option specific data */ };
struct nd_opt_hdr { /* Neighbor discovery option header */ uint8_t nd_opt_type; uint8_t nd_opt_len; /* in units of 8 octets */ /* followed by option specific data */ };
#define ND_OPT_SOURCE_LINKADDR 1 #define ND_OPT_TARGET_LINKADDR 2 #define ND_OPT_PREFIX_INFORMATION 3 #define ND_OPT_REDIRECTED_HEADER 4 #define ND_OPT_MTU 5
#定义ND选项源链接地址1#定义ND选项目标链接地址2#定义ND选项前缀信息3#定义ND选项重定向标题4#定义ND选项MTU 5
struct nd_opt_prefix_info { /* prefix information */ uint8_t nd_opt_pi_type; uint8_t nd_opt_pi_len; uint8_t nd_opt_pi_prefix_len; uint8_t nd_opt_pi_flags_reserved; uint32_t nd_opt_pi_valid_time; uint32_t nd_opt_pi_preferred_time; uint32_t nd_opt_pi_reserved2; struct in6_addr nd_opt_pi_prefix; };
struct nd_opt_prefix_info { /* prefix information */ uint8_t nd_opt_pi_type; uint8_t nd_opt_pi_len; uint8_t nd_opt_pi_prefix_len; uint8_t nd_opt_pi_flags_reserved; uint32_t nd_opt_pi_valid_time; uint32_t nd_opt_pi_preferred_time; uint32_t nd_opt_pi_reserved2; struct in6_addr nd_opt_pi_prefix; };
#define ND_OPT_PI_FLAG_ONLINK 0x80 #define ND_OPT_PI_FLAG_AUTO 0x40
#定义ND_OPT_PI_FLAG_ONLINK 0x80#定义ND_OPT_PI_FLAG_AUTO 0x40
struct nd_opt_rd_hdr { /* redirected header */ uint8_t nd_opt_rh_type; uint8_t nd_opt_rh_len; uint16_t nd_opt_rh_reserved1; uint32_t nd_opt_rh_reserved2; /* followed by IP header and data */ };
struct nd_opt_rd_hdr { /* redirected header */ uint8_t nd_opt_rh_type; uint8_t nd_opt_rh_len; uint16_t nd_opt_rh_reserved1; uint32_t nd_opt_rh_reserved2; /* followed by IP header and data */ };
struct nd_opt_mtu { /* MTU option */ uint8_t nd_opt_mtu_type; uint8_t nd_opt_mtu_len; uint16_t nd_opt_mtu_reserved; uint32_t nd_opt_mtu_mtu; };
struct nd_opt_mtu { /* MTU option */ uint8_t nd_opt_mtu_type; uint8_t nd_opt_mtu_len; uint16_t nd_opt_mtu_reserved; uint32_t nd_opt_mtu_mtu; };
We note that the nd_na_flags_reserved flags have the same byte ordering problems as we discussed with ip6f_offlg.
我们注意到,nd_na_标志(reserved flags)与我们与ip6f_offlg讨论的字节排序问题相同。
The basic API ([RFC-2133]) defines some macros for testing an IPv6 address for certain properties. This API extends those definitions with additional address testing macros, defined as a result of including <netinet/in.h>.
基本API([RFC-2133])定义了一些宏,用于测试IPv6地址的某些属性。此API使用附加的地址测试宏扩展了这些定义,这些宏是由于包含<netinet/in.h>而定义的。
int IN6_ARE_ADDR_EQUAL(const struct in6_addr *, const struct in6_addr *);
int IN6_ARE_ADDR_EQUAL(const struct in6_addr *, const struct in6_addr *);
Many hosts provide the file /etc/protocols that contains the names of the various IP protocols and their protocol number (e.g., the value of the protocol field in the IPv4 header for that protocol, such as 1 for ICMP). Some programs then call the function getprotobyname() to obtain the protocol value that is then specified as the third argument to the socket() function. For example, the Ping program contains code of the form
许多主机提供文件/etc/协议,其中包含各种IP协议的名称及其协议号(例如,该协议的IPv4报头中的协议字段值,如ICMP的1)。然后,一些程序调用函数getprotobyname()以获取协议值,该值随后被指定为socket()函数的第三个参数。例如,Ping程序包含表单的代码
struct protoent *proto;
结构-原型*proto;
proto = getprotobyname("icmp");
proto = getprotobyname("icmp");
s = socket(AF_INET, SOCK_RAW, proto->p_proto);
s = socket(AF_INET, SOCK_RAW, proto->p_proto);
Common names are required for the new IPv6 protocols in this file, to provide portability of applications that call the getprotoXXX() functions.
此文件中的新IPv6协议需要通用名称,以提供调用getprotoXXX()函数的应用程序的可移植性。
We define the following protocol names with the values shown. These are taken from ftp://ftp.isi.edu/in-notes/iana/assignments/protocol-numbers.
我们使用显示的值定义以下协议名称。这些是从ftp://ftp.isi.edu/in-notes/iana/assignments/protocol-numbers.
hopopt 0 # hop-by-hop options for ipv6 ipv6 41 # ipv6 ipv6-route 43 # routing header for ipv6 ipv6-frag 44 # fragment header for ipv6 esp 50 # encapsulating security payload for ipv6 ah 51 # authentication header for ipv6 ipv6-icmp 58 # icmp for ipv6 ipv6-nonxt 59 # no next header for ipv6 ipv6-opts 60 # destination options for ipv6
hopopt 0#ipv6的逐跳选项41#ipv6的路由43#ipv6的路由头frag 44#ipv6的片段头esp 50#ipv6的封装安全负载ah 51#ipv6的身份验证头icmp 58#ipv6的icmp非文本59#ipv6的无下一个头选项60#ipv6的目标选项
Raw sockets bypass the transport layer (TCP or UDP). With IPv4, raw sockets are used to access ICMPv4, IGMPv4, and to read and write IPv4 datagrams containing a protocol field that the kernel does not process. An example of the latter is a routing daemon for OSPF, since it uses IPv4 protocol field 89. With IPv6 raw sockets will be used for ICMPv6 and to read and write IPv6 datagrams containing a Next Header field that the kernel does not process. Examples of the latter are a routing daemon for OSPF for IPv6 and RSVP (protocol field 46).
原始套接字绕过传输层(TCP或UDP)。对于IPv4,原始套接字用于访问ICMPv4、IGMPv4,以及读写包含内核不处理的协议字段的IPv4数据报。后者的一个例子是OSPF的路由守护进程,因为它使用IPv4协议字段89。对于IPv6,原始套接字将用于ICMPv6,并用于读写包含内核不处理的下一个标头字段的IPv6数据报。后者的示例是用于IPv6和RSVP的OSPF路由守护进程(协议字段46)。
All data sent via raw sockets MUST be in network byte order and all data received via raw sockets will be in network byte order. This differs from the IPv4 raw sockets, which did not specify a byte ordering and typically used the host's byte order.
通过原始套接字发送的所有数据必须按网络字节顺序,通过原始套接字接收的所有数据将按网络字节顺序。这与IPv4原始套接字不同,后者没有指定字节顺序,通常使用主机的字节顺序。
Another difference from IPv4 raw sockets is that complete packets (that is, IPv6 packets with extension headers) cannot be read or written using the IPv6 raw sockets API. Instead, ancillary data objects are used to transfer the extension headers, as described later in this document. Should an application need access to the complete IPv6 packet, some other technique, such as the datalink interfaces BPF or DLPI, must be used.
与IPv4原始套接字的另一个区别是,不能使用IPv6原始套接字API读取或写入完整的数据包(即具有扩展头的IPv6数据包)。相反,辅助数据对象用于传输扩展头,如本文档后面所述。如果应用程序需要访问完整的IPv6数据包,则必须使用其他一些技术,例如数据链路接口BPF或DLPI。
All fields in the IPv6 header that an application might want to change (i.e., everything other than the version number) can be modified using ancillary data and/or socket options by the application for output. All fields in a received IPv6 header (other than the version number and Next Header fields) and all extension headers are also made available to the application as ancillary data on input. Hence there is no need for a socket option similar to the IPv4 IP_HDRINCL socket option.
应用程序可以使用辅助数据和/或套接字选项修改IPv6标头中应用程序可能要更改的所有字段(即版本号以外的所有内容),以进行输出。接收到的IPv6报头中的所有字段(版本号和下一个报头字段除外)以及所有扩展报头也可作为输入的辅助数据提供给应用程序。因此,不需要类似于IPv4 IP_HDRINCL套接字选项的套接字选项。
When writing to a raw socket the kernel will automatically fragment the packet if its size exceeds the path MTU, inserting the required fragmentation headers. On input the kernel reassembles received fragments, so the reader of a raw socket never sees any fragment headers.
当写入原始套接字时,如果数据包的大小超过路径MTU,内核将自动对数据包进行分段,插入所需的分段头。在输入时,内核重新组装接收到的片段,因此原始套接字的读取器永远不会看到任何片段头。
When we say "an ICMPv6 raw socket" we mean a socket created by calling the socket function with the three arguments PF_INET6, SOCK_RAW, and IPPROTO_ICMPV6.
当我们说“一个ICMPv6原始套接字”时,我们指的是一个通过调用socket函数创建的套接字,该函数有三个参数PF_INET6、SOCK_raw和IPPROTO_ICMPv6。
Most IPv4 implementations give special treatment to a raw socket created with a third argument to socket() of IPPROTO_RAW, whose value is normally 255. We note that this value has no special meaning to an IPv6 raw socket (and the IANA currently reserves the value of 255
大多数IPv4实现对使用IPPROTO_raw的socket()的第三个参数创建的原始套接字进行了特殊处理,该参数的值通常为255。我们注意到,该值对IPv6原始套接字没有特殊意义(IANA目前保留255的值)
when used as a next-header field). (Note: This feature was added to IPv4 in 1988 by Van Jacobson to support traceroute, allowing a complete IP header to be passed by the application, before the IP_HDRINCL socket option was added.)
当用作下一个标题字段时)。(注意:在添加IP_HDRINCL套接字选项之前,Van Jacobson于1988年将此功能添加到IPv4以支持跟踪路由,允许应用程序传递完整的IP头。)
The kernel will calculate and insert the ICMPv6 checksum for ICMPv6 raw sockets, since this checksum is mandatory.
内核将计算并插入ICMPv6原始套接字的ICMPv6校验和,因为该校验和是必需的。
For other raw IPv6 sockets (that is, for raw IPv6 sockets created with a third argument other than IPPROTO_ICMPV6), the application must set the new IPV6_CHECKSUM socket option to have the kernel (1) compute and store a checksum for output, and (2) verify the received checksum on input, discarding the packet if the checksum is in error. This option prevents applications from having to perform source address selection on the packets they send. The checksum will incorporate the IPv6 pseudo-header, defined in Section 8.1 of [RFC-1883]. This new socket option also specifies an integer offset into the user data of where the checksum is located.
对于其他原始IPv6套接字(即,对于使用IPPROTO_ICMPV6以外的第三个参数创建的原始IPv6套接字),应用程序必须设置新的IPv6_校验和套接字选项,以使内核(1)计算并存储输出校验和,(2)在输入时验证收到的校验和,如果校验和出错,则丢弃数据包。此选项防止应用程序必须对其发送的数据包执行源地址选择。校验和将包含[RFC-1883]第8.1节中定义的IPv6伪报头。这个新的套接字选项还指定校验和所在的用户数据的整数偏移量。
int offset = 2; setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset));
int offset = 2; setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset));
By default, this socket option is disabled. Setting the offset to -1 also disables the option. By disabled we mean (1) the kernel will not calculate and store a checksum for outgoing packets, and (2) the kernel will not verify a checksum for received packets.
默认情况下,此套接字选项处于禁用状态。将偏移设置为-1也会禁用该选项。所谓禁用,我们的意思是(1)内核不会计算和存储传出数据包的校验和,(2)内核不会验证接收到的数据包的校验和。
(Note: Since the checksum is always calculated by the kernel for an ICMPv6 socket, applications are not able to generate ICMPv6 packets with incorrect checksums (presumably for testing purposes) using this API.)
(注意:由于内核总是为ICMPv6套接字计算校验和,因此应用程序无法使用此API生成校验和不正确的ICMPv6数据包(可能是出于测试目的)
ICMPv4 raw sockets receive most ICMPv4 messages received by the kernel. (We say "most" and not "all" because Berkeley-derived kernels never pass echo requests, timestamp requests, or address mask requests to a raw socket. Instead these three messages are processed entirely by the kernel.) But ICMPv6 is a superset of ICMPv4, also including the functionality of IGMPv4 and ARPv4. This means that an ICMPv6 raw socket can potentially receive many more messages than would be received with an ICMPv4 raw socket: ICMP messages similar to ICMPv4, along with neighbor solicitations, neighbor advertisements, and the three group membership messages.
ICMPv4原始套接字接收内核接收的大多数ICMPv4消息。(我们说“大多数”而不是“全部”,因为Berkeley派生的内核从不向原始套接字传递回显请求、时间戳请求或地址掩码请求。相反,这三条消息完全由内核处理。)但ICMPv6是ICMPv4的超集,还包括IGMPv4和ARPv4的功能。这意味着ICMPv6原始套接字可能接收到比ICMPv4原始套接字更多的消息:类似于ICMPv4的ICMP消息,以及邻居请求、邻居播发和三个组成员身份消息。
Most applications using an ICMPv6 raw socket care about only a small subset of the ICMPv6 message types. To transfer extraneous ICMPv6 messages from the kernel to user can incur a significant overhead. Therefore this API includes a method of filtering ICMPv6 messages by the ICMPv6 type field.
大多数使用ICMPv6原始套接字的应用程序只关心ICMPv6消息类型的一小部分。将无关的ICMPv6消息从内核传输到用户可能会产生很大的开销。因此,此API包含一种通过ICMPv6类型字段过滤ICMPv6消息的方法。
Each ICMPv6 raw socket has an associated filter whose datatype is defined as
每个ICMPv6原始套接字都有一个关联的筛选器,其数据类型定义为
struct icmp6_filter;
结构icmp6_过滤器;
This structure, along with the macros and constants defined later in this section, are defined as a result of including the <netinet/icmp6.h> header.
此结构以及本节后面定义的宏和常量是由于包含<netinet/icmp6.h>标题而定义的。
The current filter is fetched and stored using getsockopt() and setsockopt() with a level of IPPROTO_ICMPV6 and an option name of ICMP6_FILTER.
使用getsockopt()和setsockopt()获取和存储当前筛选器,级别为IPPROTO_ICMPV6,选项名称为ICMP6_filter。
Six macros operate on an icmp6_filter structure:
六个宏在icmp6_过滤器结构上运行:
void ICMP6_FILTER_SETPASSALL (struct icmp6_filter *); void ICMP6_FILTER_SETBLOCKALL(struct icmp6_filter *);
void ICMP6_FILTER_SETPASSALL (struct icmp6_filter *); void ICMP6_FILTER_SETBLOCKALL(struct icmp6_filter *);
void ICMP6_FILTER_SETPASS ( int, struct icmp6_filter *); void ICMP6_FILTER_SETBLOCK( int, struct icmp6_filter *);
void ICMP6_FILTER_SETPASS ( int, struct icmp6_filter *); void ICMP6_FILTER_SETBLOCK( int, struct icmp6_filter *);
int ICMP6_FILTER_WILLPASS (int, const struct icmp6_filter *); int ICMP6_FILTER_WILLBLOCK(int, const struct icmp6_filter *);
int ICMP6_FILTER_WILLPASS (int, const struct icmp6_filter *); int ICMP6_FILTER_WILLBLOCK(int, const struct icmp6_filter *);
The first argument to the last four macros (an integer) is an ICMPv6 message type, between 0 and 255. The pointer argument to all six macros is a pointer to a filter that is modified by the first four macros examined by the last two macros.
最后四个宏(整数)的第一个参数是ICMPv6消息类型,介于0和255之间。指向所有六个宏的指针参数是指向过滤器的指针,该过滤器由最后两个宏检查的前四个宏修改。
The first two macros, SETPASSALL and SETBLOCKALL, let us specify that all ICMPv6 messages are passed to the application or that all ICMPv6 messages are blocked from being passed to the application.
前两个宏SETPASSALL和SETBLOCKALL允许我们指定将所有ICMPv6消息传递给应用程序,或者阻止所有ICMPv6消息传递给应用程序。
The next two macros, SETPASS and SETBLOCK, let us specify that messages of a given ICMPv6 type should be passed to the application or not passed to the application (blocked).
接下来的两个宏SETPASS和SETBLOCK让我们指定给定ICMPv6类型的消息应该传递给应用程序,或者不传递给应用程序(阻塞)。
The final two macros, WILLPASS and WILLBLOCK, return true or false depending whether the specified message type is passed to the application or blocked from being passed to the application by the filter pointed to by the second argument.
最后两个宏WILLPASS和WILLBLOCK返回true或false,具体取决于指定的消息类型是传递给应用程序还是被第二个参数指向的筛选器阻止传递给应用程序。
When an ICMPv6 raw socket is created, it will by default pass all ICMPv6 message types to the application.
创建ICMPv6原始套接字时,默认情况下,它会将所有ICMPv6消息类型传递给应用程序。
As an example, a program that wants to receive only router advertisements could execute the following:
例如,只希望接收路由器广告的程序可以执行以下操作:
struct icmp6_filter myfilt;
结构icmp6_过滤器myfilt;
fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
ICMP6_FILTER_SETBLOCKALL(&myfilt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &myfilt); setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &myfilt, sizeof(myfilt));
ICMP6_FILTER_SETBLOCKALL(&myfilt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &myfilt); setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &myfilt, sizeof(myfilt));
The filter structure is declared and then initialized to block all messages types. The filter structure is then changed to allow router advertisement messages to be passed to the application and the filter is installed using setsockopt().
声明并初始化筛选器结构以阻止所有消息类型。然后更改筛选器结构,以允许将路由器广告消息传递给应用程序,并使用setsockopt()安装筛选器。
The icmp6_filter structure is similar to the fd_set datatype used with the select() function in the sockets API. The icmp6_filter structure is an opaque datatype and the application should not care how it is implemented. All the application does with this datatype is allocate a variable of this type, pass a pointer to a variable of this type to getsockopt() and setsockopt(), and operate on a variable of this type using the six macros that we just defined.
icmp6_过滤器结构类似于sockets API中select()函数使用的fd_集合数据类型。icmp6_筛选器结构是一种不透明的数据类型,应用程序不应该关心它是如何实现的。应用程序对该数据类型所做的只是分配一个该类型的变量,将指向该类型变量的指针传递给getsockopt()和setsockopt(),并使用我们刚才定义的六个宏对该类型的变量进行操作。
Nevertheless, it is worth showing a simple implementation of this datatype and the six macros.
不过,值得展示此数据类型和六个宏的简单实现。
struct icmp6_filter { uint32_t icmp6_filt[8]; /* 8*32 = 256 bits */ };
struct icmp6_filter { uint32_t icmp6_filt[8]; /* 8*32 = 256 bits */ };
#define ICMP6_FILTER_WILLPASS(type, filterp) \ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0) #define ICMP6_FILTER_WILLBLOCK(type, filterp) \ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0) #define ICMP6_FILTER_SETPASS(type, filterp) \ ((((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31)))) #define ICMP6_FILTER_SETBLOCK(type, filterp) \ ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31)))) #define ICMP6_FILTER_SETPASSALL(filterp) \ memset((filterp), 0xFF, sizeof(struct icmp6_filter)) #define ICMP6_FILTER_SETBLOCKALL(filterp) \ memset((filterp), 0, sizeof(struct icmp6_filter))
#define ICMP6_FILTER_WILLPASS(type, filterp) \ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0) #define ICMP6_FILTER_WILLBLOCK(type, filterp) \ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0) #define ICMP6_FILTER_SETPASS(type, filterp) \ ((((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31)))) #define ICMP6_FILTER_SETBLOCK(type, filterp) \ ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31)))) #define ICMP6_FILTER_SETPASSALL(filterp) \ memset((filterp), 0xFF, sizeof(struct icmp6_filter)) #define ICMP6_FILTER_SETBLOCKALL(filterp) \ memset((filterp), 0, sizeof(struct icmp6_filter))
(Note: These sample definitions have two limitations that an implementation may want to change. The first four macros evaluate their first argument two times. The second two macros require the inclusion of the <string.h> header for the memset() function.)
(注意:这些示例定义有两个实现可能需要更改的限制。前四个宏对其第一个参数求值两次。后两个宏要求包含memset()函数的<string.h>头。)
4.2BSD allowed file descriptors to be transferred between separate processes across a UNIX domain socket using the sendmsg() and recvmsg() functions. Two members of the msghdr structure, msg_accrights and msg_accrightslen, were used to send and receive the descriptors. When the OSI protocols were added to 4.3BSD Reno in 1990 the names of these two fields in the msghdr structure were changed to msg_control and msg_controllen, because they were used by the OSI protocols for "control information", although the comments in the source code call this "ancillary data".
4.2BSD允许使用sendmsg()和recvmsg()函数在UNIX域套接字上的不同进程之间传输文件描述符。msghdr结构的两个成员msg_accrights和msg_accrightslen用于发送和接收描述符。当OSI协议于1990年添加到4.3BSD Reno时,msghdr结构中这两个字段的名称被更改为msg_control和msg_controllen,因为OSI协议使用它们作为“控制信息”,尽管源代码中的注释称之为“辅助数据”。
Other than the OSI protocols, the use of ancillary data has been rare. In 4.4BSD, for example, the only use of ancillary data with IPv4 is to return the destination address of a received UDP datagram if the IP_RECVDSTADDR socket option is set. With Unix domain sockets ancillary data is still used to send and receive descriptors.
除了OSI协议之外,辅助数据的使用很少。例如,在4.4BSD中,如果设置了IP_RECVDSTADDR socket选项,则IPv4的辅助数据的唯一用途是返回接收到的UDP数据报的目标地址。对于Unix域套接字,辅助数据仍然用于发送和接收描述符。
Nevertheless the ancillary data fields of the msghdr structure provide a clean way to pass information in addition to the data that is being read or written. The inclusion of the msg_control and msg_controllen members of the msghdr structure along with the cmsghdr structure that is pointed to by the msg_control member is required by the Posix.1g sockets API standard (which should be completed during 1997).
然而,msghdr结构的辅助数据字段提供了一种干净的方式来传递除正在读取或写入的数据之外的信息。Posix.1g sockets API标准(应在1997年完成)要求将msghdr结构的msg_control和msg_controllen成员以及msg_control成员所指向的cmsghdr结构包括在内。
In this document ancillary data is used to exchange the following optional information between the application and the kernel:
在本文档中,辅助数据用于在应用程序和内核之间交换以下可选信息:
1. the send/receive interface and source/destination address, 2. the hop limit, 3. next hop address, 4. Hop-by-Hop options, 5. Destination options, and 6. Routing header.
1. 发送/接收接口和源/目标地址,2。跳跃限制,3。下一跳地址,4。逐跳选项,5。目的地选项,以及6。路由标头。
Before describing these uses in detail, we review the definition of the msghdr structure itself, the cmsghdr structure that defines an ancillary data object, and some functions that operate on the ancillary data objects.
在详细描述这些用途之前,我们回顾了msghdr结构本身的定义、定义辅助数据对象的cmsghdr结构以及对辅助数据对象进行操作的一些函数。
The msghdr structure is used by the recvmsg() and sendmsg() functions. Its Posix.1g definition is:
msghdr结构由recvmsg()和sendmsg()函数使用。其Posix.1g定义为:
struct msghdr { void *msg_name; /* ptr to socket address structure */ socklen_t msg_namelen; /* size of socket address structure */ struct iovec *msg_iov; /* scatter/gather array */ size_t msg_iovlen; /* # elements in msg_iov */ void *msg_control; /* ancillary data */ socklen_t msg_controllen; /* ancillary data buffer length */ int msg_flags; /* flags on received message */ };
struct msghdr { void *msg_name; /* ptr to socket address structure */ socklen_t msg_namelen; /* size of socket address structure */ struct iovec *msg_iov; /* scatter/gather array */ size_t msg_iovlen; /* # elements in msg_iov */ void *msg_control; /* ancillary data */ socklen_t msg_controllen; /* ancillary data buffer length */ int msg_flags; /* flags on received message */ };
The structure is declared as a result of including <sys/socket.h>.
该结构声明为包含<sys/socket.h>的结果。
(Note: Before Posix.1g the two "void *" pointers were typically "char *", and the two socklen_t members and the size_t member were typically integers. Earlier drafts of Posix.1g had the two socklen_t members as size_t, but Draft 6.6 of Posix.1g, apparently the final draft, changed these to socklen_t to simplify binary portability for 64-bit implementations and to align Posix.1g with X/Open's Networking Services, Issue 5. The change in msg_control to a "void *" pointer affects any code that increments this pointer.)
(注意:在Posix.1g之前,两个“void*”指针通常是“char*”,两个socklen_t成员和size_t成员通常是整数。Posix.1g的早期草案将两个socklen_t成员作为size_t,但Posix.1g的草案6.6(显然是最终草案)将其更改为socklen_t,以简化64位实现的二进制可移植性,并使Posix.1g与X/Open的网络服务保持一致5.将msg_控件更改为“void*”指针会影响任何增加此指针的代码。)
Most Berkeley-derived implementations limit the amount of ancillary data in a call to sendmsg() to no more than 108 bytes (an mbuf). This API requires a minimum of 10240 bytes of ancillary data, but it is recommended that the amount be limited only by the buffer space reserved by the socket (which can be modified by the SO_SNDBUF socket option). (Note: This magic number 10240 was picked as a value that should always be large enough. 108 bytes is clearly too small as the maximum size of a Type 0 Routing header is 376 bytes.)
大多数Berkeley派生的实现将sendmsg()调用中的辅助数据量限制为不超过108字节(一个mbuf)。此API至少需要10240字节的辅助数据,但建议仅通过套接字保留的缓冲区空间(可通过SO_SNDBUF socket选项修改)来限制该数量。(注意:这个神奇的数字10240被选为一个应该总是足够大的值。108字节显然太小了,因为类型0路由头的最大大小是376字节。)
The cmsghdr structure describes ancillary data objects transferred by recvmsg() and sendmsg(). Its Posix.1g definition is:
cmsghdr结构描述由recvmsg()和sendmsg()传输的辅助数据对象。其Posix.1g定义为:
struct cmsghdr { socklen_t cmsg_len; /* #bytes, including this header */ int cmsg_level; /* originating protocol */ int cmsg_type; /* protocol-specific type */ /* followed by unsigned char cmsg_data[]; */ };
struct cmsghdr { socklen_t cmsg_len; /* #bytes, including this header */ int cmsg_level; /* originating protocol */ int cmsg_type; /* protocol-specific type */ /* followed by unsigned char cmsg_data[]; */ };
This structure is declared as a result of including <sys/socket.h>.
声明此结构是因为包含了<sys/socket.h>。
As shown in this definition, normally there is no member with the name cmsg_data[]. Instead, the data portion is accessed using the CMSG_xxx() macros, as described shortly. Nevertheless, it is common to refer to the cmsg_data[] member.
如该定义所示,通常没有名为cmsg_data[]的成员。相反,使用CMSG_xxx()宏访问数据部分,如下所述。然而,通常提及cmsg_data[]成员。
(Note: Before Posix.1g the cmsg_len member was an integer, and not a socklen_t. See the Note in the previous section for why socklen_t is used here.)
(注意:在Posix.1g之前,cmsg_len成员是一个整数,而不是socklen_t。请参阅上一节中的说明,了解此处使用socklen_t的原因。)
When ancillary data is sent or received, any number of ancillary data objects can be specified by the msg_control and msg_controllen members of the msghdr structure, because each object is preceded by a cmsghdr structure defining the object's length (the cmsg_len member). Historically Berkeley-derived implementations have passed only one object at a time, but this API allows multiple objects to be passed in a single call to sendmsg() or recvmsg(). The following example shows two ancillary data objects in a control buffer.
当发送或接收辅助数据时,msghdr结构的msg_control和msg_controllen成员可以指定任意数量的辅助数据对象,因为每个对象前面都有一个定义对象长度的cmsghdr结构(cmsg_len成员)。从历史上看,Berkeley派生的实现一次只传递一个对象,但此API允许在对sendmsg()或recvmsg()的单个调用中传递多个对象。以下示例显示控件缓冲区中的两个辅助数据对象。
|<--------------------------- msg_controllen -------------------------->| | | |<----- ancillary data object ----->|<----- ancillary data object ----->| |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->| | | | |<---------- cmsg_len ---------->| |<--------- cmsg_len ----------->| | |<--------- CMSG_LEN() --------->| |<-------- CMSG_LEN() ---------->| | | | | | | +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ |cmsg_|cmsg_|cmsg_|XX| |XX|cmsg_|cmsg_|cmsg_|XX| |XX| |len |level|type |XX|cmsg_data[]|XX|len |level|type |XX|cmsg_data[]|XX| +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ ^ | msg_control points here
|<--------------------------- msg_controllen -------------------------->| | | |<----- ancillary data object ----->|<----- ancillary data object ----->| |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->| | | | |<---------- cmsg_len ---------->| |<--------- cmsg_len ----------->| | |<--------- CMSG_LEN() --------->| |<-------- CMSG_LEN() ---------->| | | | | | | +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ |cmsg_|cmsg_|cmsg_|XX| |XX|cmsg_|cmsg_|cmsg_|XX| |XX| |len |level|type |XX|cmsg_data[]|XX|len |level|type |XX|cmsg_data[]|XX| +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ ^ | msg_control points here
The fields shown as "XX" are possible padding, between the cmsghdr structure and the data, and between the data and the next cmsghdr structure, if required by the implementation.
如果实现需要,显示为“XX”的字段可能是cmsghdr结构和数据之间以及数据和下一个cmsghdr结构之间的填充。
To aid in the manipulation of ancillary data objects, three macros from 4.4BSD are defined by Posix.1g: CMSG_DATA(), CMSG_NXTHDR(), and CMSG_FIRSTHDR(). Before describing these macros, we show the following example of how they might be used with a call to recvmsg().
为了帮助操作辅助数据对象,Posix.1g定义了4.4BSD中的三个宏:CMSG_data()、CMSG_NXTHDR()和CMSG_FIRSTHDR()。在描述这些宏之前,我们将展示以下示例,说明如何在调用recvmsg()时使用这些宏。
struct msghdr msg; struct cmsghdr *cmsgptr;
struct msghdr msg; struct cmsghdr *cmsgptr;
/* fill in msg */
/* fill in msg */
/* call recvmsg() */
/* call recvmsg() */
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == ... && cmsgptr->cmsg_type == ... ) { u_char *ptr;
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == ... && cmsgptr->cmsg_type == ... ) { u_char *ptr;
ptr = CMSG_DATA(cmsgptr); /* process data pointed to by ptr */ } }
ptr = CMSG_DATA(cmsgptr); /* process data pointed to by ptr */ } }
We now describe the three Posix.1g macros, followed by two more that are new with this API: CMSG_SPACE() and CMSG_LEN(). All these macros are defined as a result of including <sys/socket.h>.
我们现在介绍三个Posix.1g宏,然后介绍另外两个与此API相关的新宏:CMSG_SPACE()和CMSG_LEN()。所有这些宏都是由于包含<sys/socket.h>而定义的。
struct cmsghdr *CMSG_FIRSTHDR(const struct msghdr *mhdr);
struct cmsghdr *CMSG_FIRSTHDR(const struct msghdr *mhdr);
CMSG_FIRSTHDR() returns a pointer to the first cmsghdr structure in the msghdr structure pointed to by mhdr. The macro returns NULL if there is no ancillary data pointed to the by msghdr structure (that is, if either msg_control is NULL or if msg_controllen is less than the size of a cmsghdr structure).
CMSG_FIRSTHDR()返回指向mhdr指向的msghdr结构中的第一个cmsghdr结构的指针。如果没有指向by msghdr结构的辅助数据(即,如果msg_control为NULL或msg_controllen小于cmsghdr结构的大小),则宏返回NULL。
One possible implementation could be
一种可能的实施方式是
#define CMSG_FIRSTHDR(mhdr) \ ( (mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ (struct cmsghdr *)(mhdr)->msg_control : \ (struct cmsghdr *)NULL )
#define CMSG_FIRSTHDR(mhdr) \ ( (mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ (struct cmsghdr *)(mhdr)->msg_control : \ (struct cmsghdr *)NULL )
(Note: Most existing implementations do not test the value of msg_controllen, and just return the value of msg_control. The value of msg_controllen must be tested, because if the application asks recvmsg() to return ancillary data, by setting msg_control to point to the application's buffer and setting msg_controllen to the length of this buffer, the kernel indicates that no ancillary data is available by setting msg_controllen to 0 on return. It is also easier to put this test into this macro, than making the application perform the test.)
(注意:大多数现有实现不测试msg_controllen的值,只返回msg_control的值。必须测试msg_controllen的值,因为如果应用程序请求recvmsg()要返回辅助数据,通过将msg_control设置为指向应用程序的缓冲区,并将msg_controllen设置为该缓冲区的长度,内核在返回时将msg_controllen设置为0,表明没有辅助数据可用。将此测试放入此宏也比让应用程序执行测试更容易。)
struct cmsghdr *CMSG_NXTHDR(const struct msghdr *mhdr, const struct cmsghdr *cmsg);
struct cmsghdr *CMSG_NXTHDR(const struct msghdr *mhdr, const struct cmsghdr *cmsg);
CMSG_NXTHDR() returns a pointer to the cmsghdr structure describing the next ancillary data object. mhdr is a pointer to a msghdr structure and cmsg is a pointer to a cmsghdr structure. If there is not another ancillary data object, the return value is NULL.
CMSG_NXTHDR()返回指向描述下一个辅助数据对象的cmsghdr结构的指针。mhdr是指向msghdr结构的指针,cmsg是指向cmsghdr结构的指针。如果没有其他辅助数据对象,则返回值为NULL。
The following behavior of this macro is new to this API: if the value of the cmsg pointer is NULL, a pointer to the cmsghdr structure describing the first ancillary data object is returned. That is, CMSG_NXTHDR(mhdr, NULL) is equivalent to CMSG_FIRSTHDR(mhdr). If there are no ancillary data objects, the return value is NULL. This provides an alternative way of coding the processing loop shown earlier:
此宏的以下行为对此API来说是新的:如果cmsg指针的值为NULL,则返回一个指向描述第一个辅助数据对象的cmsghdr结构的指针。也就是说,CMSG_NXTHDR(mhdr,NULL)等同于CMSG_FIRSTHDR(mhdr)。如果没有辅助数据对象,则返回值为NULL。这提供了一种对前面显示的处理循环进行编码的替代方法:
struct msghdr msg; struct cmsghdr *cmsgptr = NULL;
struct msghdr msg; struct cmsghdr *cmsgptr = NULL;
/* fill in msg */
/* fill in msg */
/* call recvmsg() */
/* call recvmsg() */
while ((cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) != NULL) { if (cmsgptr->cmsg_level == ... && cmsgptr->cmsg_type == ... ) { u_char *ptr;
while ((cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) != NULL) { if (cmsgptr->cmsg_level == ... && cmsgptr->cmsg_type == ... ) { u_char *ptr;
ptr = CMSG_DATA(cmsgptr); /* process data pointed to by ptr */ } }
ptr = CMSG_DATA(cmsgptr); /* process data pointed to by ptr */ } }
One possible implementation could be:
一种可能的实施方式是:
#define CMSG_NXTHDR(mhdr, cmsg) \ ( ((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \ (((u_char *)(cmsg) + ALIGN((cmsg)->cmsg_len) \ + ALIGN(sizeof(struct cmsghdr)) > \ (u_char *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \ (struct cmsghdr *)NULL : \ (struct cmsghdr *)((u_char *)(cmsg) + ALIGN((cmsg)->cmsg_len))) )
#define CMSG_NXTHDR(mhdr, cmsg) \ ( ((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \ (((u_char *)(cmsg) + ALIGN((cmsg)->cmsg_len) \ + ALIGN(sizeof(struct cmsghdr)) > \ (u_char *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \ (struct cmsghdr *)NULL : \ (struct cmsghdr *)((u_char *)(cmsg) + ALIGN((cmsg)->cmsg_len))) )
The macro ALIGN(), which is implementation dependent, rounds its argument up to the next even multiple of whatever alignment is required (probably a multiple of 4 or 8 bytes).
依赖于实现的宏ALIGN()将其参数向上舍入到所需对齐的下一个偶数倍(可能是4或8字节的倍数)。
unsigned char *CMSG_DATA(const struct cmsghdr *cmsg);
unsigned char *CMSG_DATA(const struct cmsghdr *cmsg);
CMSG_DATA() returns a pointer to the data (what is called the cmsg_data[] member, even though such a member is not defined in the structure) following a cmsghdr structure.
CMSG_DATA()返回一个指针,指向cmsghdr结构之后的数据(称为CMSG_DATA[]成员,即使该结构中未定义此类成员)。
One possible implementation could be:
一种可能的实施方式是:
#define CMSG_DATA(cmsg) ( (u_char *)(cmsg) + \ ALIGN(sizeof(struct cmsghdr)) )
#define CMSG_DATA(cmsg) ( (u_char *)(cmsg) + \ ALIGN(sizeof(struct cmsghdr)) )
unsigned int CMSG_SPACE(unsigned int length);
无符号整数CMSG_空间(无符号整数长度);
This macro is new with this API. Given the length of an ancillary data object, CMSG_SPACE() returns the space required by the object and its cmsghdr structure, including any padding needed to satisfy alignment requirements. This macro can be used, for example, to allocate space dynamically for the ancillary data. This macro should not be used to initialize the cmsg_len member of a cmsghdr structure; instead use the CMSG_LEN() macro.
此宏是此API新增的。给定辅助数据对象的长度,CMSG_SPACE()返回该对象及其cmsghdr结构所需的空间,包括满足对齐要求所需的任何填充。例如,可以使用此宏为辅助数据动态分配空间。此宏不应用于初始化cmsghdr结构的cmsg_len成员;而是使用CMSG_LEN()宏。
One possible implementation could be:
一种可能的实施方式是:
#define CMSG_SPACE(length) ( ALIGN(sizeof(struct cmsghdr)) + \ ALIGN(length) )
#define CMSG_SPACE(length) ( ALIGN(sizeof(struct cmsghdr)) + \ ALIGN(length) )
unsigned int CMSG_LEN(unsigned int length);
无符号整数CMSG_LEN(无符号整数长度);
This macro is new with this API. Given the length of an ancillary data object, CMSG_LEN() returns the value to store in the cmsg_len member of the cmsghdr structure, taking into account any padding needed to satisfy alignment requirements.
此宏是此API新增的。给定辅助数据对象的长度,CMSG_LEN()返回要存储在cmsghdr结构的CMSG_LEN成员中的值,同时考虑满足对齐要求所需的任何填充。
One possible implementation could be:
一种可能的实施方式是:
#define CMSG_LEN(length) ( ALIGN(sizeof(struct cmsghdr)) + length )
#define CMSG_LEN(length) ( ALIGN(sizeof(struct cmsghdr)) + length )
Note the difference between CMSG_SPACE() and CMSG_LEN(), shown also in the figure in Section 4.2: the former accounts for any required padding at the end of the ancillary data object and the latter is the actual length to store in the cmsg_len member of the ancillary data object.
注意CMSG_SPACE()和CMSG_LEN()之间的差异,如第4.2节中的图所示:前者用于在辅助数据对象的末尾进行任何所需的填充,后者是存储在辅助数据对象的CMSG_LEN成员中的实际长度。
There are six types of optional information described in this document that are passed between the application and the kernel using ancillary data:
本文档中描述的六种可选信息使用辅助数据在应用程序和内核之间传递:
1. the send/receive interface and source/destination address, 2. the hop limit, 3. next hop address, 4. Hop-by-Hop options, 5. Destination options, and 6. Routing header.
1. 发送/接收接口和源/目标地址,2。跳跃限制,3。下一跳地址,4。逐跳选项,5。目的地选项,以及6。路由标头。
First, to receive any of this optional information (other than the next hop address, which can only be set), the application must call setsockopt() to turn on the corresponding flag:
首先,要接收任何此可选信息(下一跳地址除外,该地址只能设置),应用程序必须调用setsockopt()以打开相应的标志:
int on = 1;
int on=1;
setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)); setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)); setsockopt(fd, IPPROTO_IPV6, IPV6_HOPOPTS, &on, sizeof(on)); setsockopt(fd, IPPROTO_IPV6, IPV6_DSTOPTS, &on, sizeof(on)); setsockopt(fd, IPPROTO_IPV6, IPV6_RTHDR, &on, sizeof(on));
setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)); setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)); setsockopt(fd, IPPROTO_IPV6, IPV6_HOPOPTS, &on, sizeof(on)); setsockopt(fd, IPPROTO_IPV6, IPV6_DSTOPTS, &on, sizeof(on)); setsockopt(fd, IPPROTO_IPV6, IPV6_RTHDR, &on, sizeof(on));
When any of these options are enabled, the corresponding data is returned as control information by recvmsg(), as one or more ancillary data objects.
当启用这些选项中的任何一个时,recvmsg()将相应的数据作为一个或多个辅助数据对象作为控制信息返回。
Nothing special need be done to send any of this optional information; the application just calls sendmsg() and specifies one or more ancillary data objects as control information.
发送此可选信息无需任何特殊操作;应用程序只调用sendmsg()并指定一个或多个辅助数据对象作为控制信息。
We also summarize the three cmsghdr fields that describe the ancillary data objects:
我们还总结了描述辅助数据对象的三个cmsghdr字段:
cmsg_level cmsg_type cmsg_data[] #times ------------ ------------ ------------------------ ------ IPPROTO_IPV6 IPV6_PKTINFO in6_pktinfo structure once IPPROTO_IPV6 IPV6_HOPLIMIT int once IPPROTO_IPV6 IPV6_NEXTHOP socket address structure once IPPROTO_IPV6 IPV6_HOPOPTS implementation dependent mult.
cmsg_level cmsg_type cmsg_data[] #times ------------ ------------ ------------------------ ------ IPPROTO_IPV6 IPV6_PKTINFO in6_pktinfo structure once IPPROTO_IPV6 IPV6_HOPLIMIT int once IPPROTO_IPV6 IPV6_NEXTHOP socket address structure once IPPROTO_IPV6 IPV6_HOPOPTS implementation dependent mult.
IPPROTO_IPV6 IPV6_DSTOPTS implementation dependent mult. IPPROTO_IPV6 IPV6_RTHDR implementation dependent once
IPPROTO_IPV6_数据选择依赖于实现的mult。IPPROTO_IPV6_RTHDR实现依赖于一次
The final column indicates how many times an ancillary data object of that type can appear as control information. The Hop-by-Hop and Destination options can appear multiple times, while all the others can appear only one time.
最后一列指示该类型的辅助数据对象作为控制信息出现的次数。“逐跳”和“目标”选项可以显示多次,而所有其他选项只能显示一次。
All these options are described in detail in following sections. All the constants beginning with IPV6_ are defined as a result of including the <netinet/in.h> header.
以下各节将详细介绍所有这些选项。所有以IPV6开头的常量都是由于包含<netinet/in.h>头而定义的。
(Note: We intentionally use the same constant for the cmsg_level member as is used as the second argument to getsockopt() and setsockopt() (what is called the "level"), and the same constant for the cmsg_type member as is used as the third argument to getsockopt() and setsockopt() (what is called the "option name"). This is consistent with the existing use of ancillary data in 4.4BSD: returning the destination address of an IPv4 datagram.)
(注意:我们有意为cmsg_级别成员使用与getsockopt()和setsockopt()的第二个参数相同的常数(称为“级别”),为cmsg_类型成员使用与getsockopt()和setsockopt()的第三个参数相同的常数(称为“选项名称”)。这与4.4BSD中辅助数据的现有用法一致:返回IPv4数据报的目标地址。)
(Note: It is up to the implementation what it passes as ancillary data for the Hop-by-Hop option, Destination option, and Routing header option, since the API to these features is through a set of inet6_option_XXX() and inet6_rthdr_XXX() functions that we define later. These functions serve two purposes: to simplify the interface to these features (instead of requiring the application to know the intimate details of the extension header formats), and to hide the actual implementation from the application. Nevertheless, we show some examples of these features that store the actual extension header as the ancillary data. Implementations need not use this technique.)
(注意:由于这些功能的API是通过一组inet6_option_XXX()和inet6_rthdr_XXX()传递的,因此它作为逐跳选项、目的地选项和路由头选项的辅助数据传递的内容取决于实现。)这些函数有两个目的:简化这些特性的接口(而不是要求应用程序了解扩展头格式的详细信息),并对应用程序隐藏实际实现。不过,我们展示了一些将实际扩展标头存储为辅助数据的功能示例。实现不需要使用此技术。)
The summary in the previous section assumes a UDP socket. Sending and receiving ancillary data is easy with UDP: the application calls sendmsg() and recvmsg() instead of sendto() and recvfrom().
上一节中的摘要假定为UDP套接字。使用UDP发送和接收辅助数据很容易:应用程序调用sendmsg()和recvmsg(),而不是sendto()和recvfrom()。
But there might be cases where a TCP application wants to send or receive this optional information. For example, a TCP client might want to specify a Routing header and this needs to be done before calling connect(). Similarly a TCP server might want to know the received interface after accept() returns along with any Destination options.
但在某些情况下,TCP应用程序可能希望发送或接收此可选信息。例如,TCP客户端可能希望指定路由头,这需要在调用connect()之前完成。类似地,TCP服务器可能希望在accept()与任何目标选项一起返回后知道接收到的接口。
A new socket option is defined that provides access to the optional information described in the previous section, but without using recvmsg() and sendmsg(). Setting the socket option specifies any of the optional output fields:
定义了一个新的套接字选项,该选项提供对上一节中描述的可选信息的访问,但不使用recvmsg()和sendmsg()。设置套接字选项可指定任意可选输出字段:
setsockopt(fd, IPPROTO_IPV6, IPV6_PKTOPTIONS, &buf, len);
设置锁定选项(fd、IPPROTO、IPV6、IPV6和buf、len);
The fourth argument points to a buffer containing one or more ancillary data objects, and the fifth argument is the total length of all these objects. The application fills in this buffer exactly as if the buffer were being passed to sendmsg() as control information.
第四个参数指向包含一个或多个辅助数据对象的缓冲区,第五个参数是所有这些对象的总长度。应用程序填充此缓冲区的方式与将缓冲区作为控制信息传递给sendmsg()的方式完全相同。
The options set by calling setsockopt() for IPV6_PKTOPTIONS are called "sticky" options because once set they apply to all packets sent on that socket. The application can call setsockopt() again to change all the sticky options, or it can call setsockopt() with a length of 0 to remove all the sticky options for the socket.
通过为IPV6_PKTOPTIONS调用setsockopt()设置的选项称为“粘性”选项,因为一旦设置,它们将应用于在该套接字上发送的所有数据包。应用程序可以再次调用setsockopt()来更改所有粘性选项,也可以调用长度为0的setsockopt()来删除套接字的所有粘性选项。
The corresponding receive option
相应的接收选项
getsockopt(fd, IPPROTO_IPV6, IPV6_PKTOPTIONS, &buf, &len);
getsockopt(fd、IPPROTO_IPV6、IPV6_PKTOPTIONS、buf和len);
returns a buffer with one or more ancillary data objects for all the optional receive information that the application has previously specified that it wants to receive. The fourth argument points to the buffer that is filled in by the call. The fifth argument is a pointer to a value-result integer: when the function is called the integer specifies the size of the buffer pointed to by the fourth argument, and on return this integer contains the actual number of bytes that were returned. The application processes this buffer exactly as if the buffer were returned by recvmsg() as control information.
返回一个缓冲区,其中包含应用程序先前指定要接收的所有可选接收信息的一个或多个辅助数据对象。第四个参数指向由调用填充的缓冲区。第五个参数是指向值结果整数的指针:调用函数时,整数指定第四个参数指向的缓冲区大小,返回时,该整数包含返回的实际字节数。应用程序处理该缓冲区的方式与recvmsg()返回该缓冲区作为控制信息的方式完全相同。
To simplify this document, in the remaining sections when we say "can be specified as ancillary data to sendmsg()" we mean "can be specified as ancillary data to sendmsg() or specified as a sticky option using setsockopt() and the IPV6_PKTOPTIONS socket option". Similarly when we say "can be returned as ancillary data by recvmsg()" we mean "can be returned as ancillary data by recvmsg() or returned by getsockopt() with the IPV6_PKTOPTIONS socket option".
为了简化本文档,在剩下的部分中,当我们说“可以指定为sendmsg()的辅助数据”时,我们的意思是“可以指定为sendmsg()的辅助数据,或者使用setsockopt()和IPv6pkToptions套接字选项指定为粘性选项”。类似地,当我们说“可以通过recvmsg()作为辅助数据返回”时,我们的意思是“可以通过recvmsg()作为辅助数据返回,或者通过带有IPV6_PKTOPTIONS套接字选项的getsockopt()返回”。
When using getsockopt() with the IPV6_PKTOPTIONS option and a TCP socket, only the options from the most recently received segment are retained and returned to the caller, and only after the socket option has been set. That is, TCP need not start saving a copy of the options until the application says to do so.
将getsockopt()与IPV6_PKTOPTIONS选项和TCP套接字一起使用时,仅保留最近接收的段中的选项并将其返回给调用者,并且仅在设置套接字选项之后。也就是说,TCP不需要开始保存选项的副本,直到应用程序要求这样做。
The application is not allowed to specify ancillary data in a call to sendmsg() on a TCP socket, and none of the ancillary data that we describe in this document is ever returned as control information by recvmsg() on a TCP socket.
不允许应用程序在TCP套接字上对sendmsg()的调用中指定辅助数据,并且我们在本文档中描述的任何辅助数据都不会由TCP套接字上的recvmsg()作为控制信息返回。
The IPV6_PKTOPTIONS socket option can also be used with a UDP socket or with a raw IPv6 socket, normally to set some of the options once, instead of with each call to sendmsg().
IPV6_PKTOPTIONS套接字选项也可以与UDP套接字或原始IPV6套接字一起使用,通常用于设置一些选项一次,而不是每次调用sendmsg()。
Unlike the TCP case, the sticky options can be overridden on a per-packet basis with ancillary data specified in a call to sendmsg() on a UDP or raw IPv6 socket. If any ancillary data is specified in a call to sendmsg(), none of the sticky options are sent with that datagram.
与TCP情况不同,可以使用UDP或原始IPv6套接字上对sendmsg()的调用中指定的辅助数据在每个数据包的基础上覆盖粘性选项。如果在对sendmsg()的调用中指定了任何辅助数据,则不会随该数据报发送任何粘性选项。
There are four pieces of information that an application can specify for an outgoing packet using ancillary data:
应用程序可以使用辅助数据为传出数据包指定四条信息:
1. the source IPv6 address, 2. the outgoing interface index, 3. the outgoing hop limit, and 4. the next hop address.
1. 源IPv6地址,2。传出接口索引,3。传出跃点限制,以及4。下一跳地址。
Three similar pieces of information can be returned for a received packet as ancillary data:
对于接收到的数据包,可以返回三条类似的信息作为辅助数据:
1. the destination IPv6 address, 2. the arriving interface index, and 3. the arriving hop limit.
1. 目标IPv6地址,2。到达接口索引,以及3。到达跳数限制。
The first two pieces of information are contained in an in6_pktinfo structure that is sent as ancillary data with sendmsg() and received as ancillary data with recvmsg(). This structure is defined as a result of including the <netinet/in.h> header.
前两条信息包含在in6_pktinfo结构中,该结构作为辅助数据通过sendmsg()发送,作为辅助数据通过recvmsg()接收。此结构定义为包含<netinet/in.h>标题的结果。
struct in6_pktinfo { struct in6_addr ipi6_addr; /* src/dst IPv6 address */ unsigned int ipi6_ifindex; /* send/recv interface index */ };
struct in6_pktinfo { struct in6_addr ipi6_addr; /* src/dst IPv6 address */ unsigned int ipi6_ifindex; /* send/recv interface index */ };
In the cmsghdr structure containing this ancillary data, the cmsg_level member will be IPPROTO_IPV6, the cmsg_type member will be IPV6_PKTINFO, and the first byte of cmsg_data[] will be the first byte of the in6_pktinfo structure.
在包含此辅助数据的cmsghdr结构中,cmsg_级成员将是IPPROTO_IPV6,cmsg_类型成员将是IPV6_PKTINFO,cmsg_data[]的第一个字节将是in6_PKTINFO结构的第一个字节。
This information is returned as ancillary data by recvmsg() only if the application has enabled the IPV6_PKTINFO socket option:
仅当应用程序已启用IPV6_PKTINFO套接字选项时,recvmsg()才会将此信息作为辅助数据返回:
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
Nothing special need be done to send this information: just specify the control information as ancillary data for sendmsg().
发送此信息无需执行任何特殊操作:只需将控制信息指定为sendmsg()的辅助数据。
(Note: The hop limit is not contained in the in6_pktinfo structure for the following reason. Some UDP servers want to respond to client requests by sending their reply out the same interface on which the request was received and with the source IPv6 address of the reply equal to the destination IPv6 address of the request. To do this the application can enable just the IPV6_PKTINFO socket option and then use the received control information from recvmsg() as the outgoing control information for sendmsg(). The application need not examine or modify the in6_pktinfo structure at all. But if the hop limit were contained in this structure, the application would have to parse the received control information and change the hop limit member, since the received hop limit is not the desired value for an outgoing packet.)
(注意:in6_pktinfo结构中不包含跃点限制,原因如下。某些UDP服务器希望通过将其回复发送到接收请求的同一接口,并且回复的源IPv6地址等于请求的目标IPv6地址来响应客户端请求。为此,应用程序on可以仅启用IPV6_PKTINFO套接字选项,然后使用从recvmsg()接收的控制信息作为sendmsg()的传出控制信息。应用程序根本不需要检查或修改in6_pktinfo结构。但是,如果此结构中包含跃点限制,则应用程序必须解析接收到的控制信息并更改跃点限制成员,因为接收到的跃点限制不是传出数据包的所需值。)
Interfaces on an IPv6 node are identified by a small positive integer, as described in Section 4 of [RFC-2133]. That document also describes a function to map an interface name to its interface index, a function to map an interface index to its interface name, and a function to return all the interface names and indexes. Notice from this document that no interface is ever assigned an index of 0.
IPv6节点上的接口由一个小的正整数标识,如[RFC-2133]第4节所述。该文档还描述了将接口名称映射到其接口索引的函数、将接口索引映射到其接口名称的函数以及返回所有接口名称和索引的函数。请注意,在此文档中,从未为任何接口分配索引0。
When specifying the outgoing interface, if the ipi6_ifindex value is 0, the kernel will choose the outgoing interface. If the application specifies an outgoing interface for a multicast packet, the interface specified by the ancillary data overrides any interface specified by the IPV6_MULTICAST_IF socket option (described in [RFC-2133]), for that call to sendmsg() only.
指定传出接口时,如果ipi6_iIndex值为0,内核将选择传出接口。如果应用程序为多播数据包指定传出接口,则辅助数据指定的接口将覆盖IPV6_multicast_If socket选项(如[RFC-2133]所述)指定的任何接口,仅用于对sendmsg()的调用。
When the IPV6_PKTINFO socket option is enabled, the received interface index is always returned as the ipi6_ifindex member of the in6_pktinfo structure.
启用IPV6_PKTINFO套接字选项时,收到的接口索引始终作为in6_PKTINFO结构的ipi6_iIndex成员返回。
The source IPv6 address can be specified by calling bind() before each output operation, but supplying the source address together with the data requires less overhead (i.e., fewer system calls) and
可以通过在每次输出操作之前调用bind()来指定源IPv6地址,但提供源地址和数据需要更少的开销(即更少的系统调用)和
requires less state to be stored and protected in a multithreaded application.
在多线程应用程序中需要存储和保护的状态更少。
When specifying the source IPv6 address as ancillary data, if the ipi6_addr member of the in6_pktinfo structure is the unspecified address (IN6ADDR_ANY_INIT), then (a) if an address is currently bound to the socket, it is used as the source address, or (b) if no address is currently bound to the socket, the kernel will choose the source address. If the ipi6_addr member is not the unspecified address, but the socket has already bound a source address, then the ipi6_addr value overrides the already-bound source address for this output operation only.
将源IPv6地址指定为辅助数据时,如果in6_pktinfo结构的ipi6_addr成员是未指定的地址(IN6ADDR_ANY_INIT),则(a)如果某个地址当前绑定到套接字,则将其用作源地址;或者(b)如果当前没有地址绑定到套接字,则内核将选择源地址。如果ipi6_addr成员不是未指定的地址,但套接字已绑定源地址,则ipi6_addr值仅覆盖此输出操作的已绑定源地址。
The kernel must verify that the requested source address is indeed a unicast address assigned to the node.
内核必须验证请求的源地址确实是分配给节点的单播地址。
When the in6_pktinfo structure is returned as ancillary data by recvmsg(), the ipi6_addr member contains the destination IPv6 address from the received packet.
当recvmsg()将in6_pktinfo结构作为辅助数据返回时,ipi6_addr成员包含来自接收数据包的目标IPv6地址。
The outgoing hop limit is normally specified with either the IPV6_UNICAST_HOPS socket option or the IPV6_MULTICAST_HOPS socket option, both of which are described in [RFC-2133]. Specifying the hop limit as ancillary data lets the application override either the kernel's default or a previously specified value, for either a unicast destination or a multicast destination, for a single output operation. Returning the received hop limit is useful for programs such as Traceroute and for IPv6 applications that need to verify that the received hop limit is 255 (e.g., that the packet has not been forwarded).
出站跃点限制通常通过IPV6_单播_跃点套接字选项或IPV6_多播_跃点套接字选项指定,这两个选项在[RFC-2133]中均有描述。对于单播目的地或多播目的地,将跃点限制指定为辅助数据可以让应用程序为单个输出操作覆盖内核的默认值或以前指定的值。返回接收到的跃点限制对于Traceroute等程序以及需要验证接收到的跃点限制是否为255(例如,数据包尚未转发)的IPv6应用程序非常有用。
The received hop limit is returned as ancillary data by recvmsg() only if the application has enabled the IPV6_HOPLIMIT socket option:
仅当应用程序已启用IPV6\u HOPLIMIT套接字选项时,recvmsg()才会将收到的跃点限制作为辅助数据返回:
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
In the cmsghdr structure containing this ancillary data, the cmsg_level member will be IPPROTO_IPV6, the cmsg_type member will be IPV6_HOPLIMIT, and the first byte of cmsg_data[] will be the first byte of the integer hop limit.
在包含此辅助数据的cmsghdr结构中,cmsg_级成员将是IPPROTO_IPV6,cmsg_类型成员将是IPV6_hopflimit,cmsg_data[]的第一个字节将是整数hop limit的第一个字节。
Nothing special need be done to specify the outgoing hop limit: just specify the control information as ancillary data for sendmsg(). As specified in [RFC-2133], the interpretation of the integer hop limit value is
无需执行任何特殊操作来指定传出跃点限制:只需将控制信息指定为sendmsg()的辅助数据。如[RFC-2133]所述,整数跃点限制值的解释为
x < -1: return an error of EINVAL x == -1: use kernel default 0 <= x <= 255: use x x >= 256: return an error of EINVAL
x < -1: return an error of EINVAL x == -1: use kernel default 0 <= x <= 255: use x x >= 256: return an error of EINVAL
The IPV6_NEXTHOP ancillary data object specifies the next hop for the datagram as a socket address structure. In the cmsghdr structure containing this ancillary data, the cmsg_level member will be IPPROTO_IPV6, the cmsg_type member will be IPV6_NEXTHOP, and the first byte of cmsg_data[] will be the first byte of the socket address structure.
IPV6_NEXTHOP辅助数据对象将数据报的下一个跃点指定为套接字地址结构。在包含此辅助数据的cmsghdr结构中,cmsg_级成员将是IPPROTO_IPV6,cmsg_类型成员将是IPV6_NEXTHOP,cmsg_data[]的第一个字节将是套接字地址结构的第一个字节。
This is a privileged option. (Note: It is implementation defined and beyond the scope of this document to define what "privileged" means. Unix systems use this term to mean the process must have an effective user ID of 0.)
这是一个特权选项。(注意:定义“特权”的含义是实现定义的,超出了本文档的范围。Unix系统使用此术语表示进程的有效用户ID必须为0。)
If the socket address structure contains an IPv6 address (e.g., the sin6_family member is AF_INET6), then the node identified by that address must be a neighbor of the sending host. If that address equals the destination IPv6 address of the datagram, then this is equivalent to the existing SO_DONTROUTE socket option.
如果套接字地址结构包含IPv6地址(例如,sin6_族成员是AF_INET6),则由该地址标识的节点必须是发送主机的邻居。如果该地址等于数据报的目标IPv6地址,则这相当于现有的SO_DONTROUTE套接字选项。
With the IPV6_PKTINFO socket option there are no additional errors possible with the call to recvmsg(). But when specifying the outgoing interface or the source address, additional errors are possible from sendmsg(). The following are examples, but some of these may not be provided by some implementations, and some implementations may define additional errors:
使用IPV6_PKTINFO socket选项,调用recvmsg()不会出现其他错误。但在指定传出接口或源地址时,sendmsg()可能会出现其他错误。以下是一些示例,但其中一些可能不是由某些实现提供的,某些实现可能会定义其他错误:
ENXIO The interface specified by ipi6_ifindex does not exist.
ENXIO ipi6_iIndex指定的接口不存在。
ENETDOWN The interface specified by ipi6_ifindex is not enabled for IPv6 use.
ENETDOWN ipi6\u iIndex指定的接口未启用IPv6使用。
EADDRNOTAVAIL ipi6_ifindex specifies an interface but the address ipi6_addr is not available for use on that interface.
EADDRNOTAVAIL ipi6_iIndex指定了一个接口,但地址ipi6_addr在该接口上不可用。
EHOSTUNREACH No route to the destination exists over the interface specified by ifi6_ifindex.
EHOSTUNREACH在ifi6\u ifindex指定的接口上不存在到目标的路由。
A variable number of Hop-by-Hop options can appear in a single Hop-by-Hop options header. Each option in the header is TLV-encoded with a type, length, and value.
单个逐跳选项标题中可以显示数量可变的逐跳选项。标头中的每个选项都使用类型、长度和值进行TLV编码。
Today only three Hop-by-Hop options are defined for IPv6 [RFC-1883]: Jumbo Payload, Pad1, and PadN, although a proposal exists for a router-alert Hop-by-Hop option. The Jumbo Payload option should not be passed back to an application and an application should receive an error if it attempts to set it. This option is processed entirely by the kernel. It is indirectly specified by datagram-based applications as the size of the datagram to send and indirectly passed back to these applications as the length of the received datagram. The two pad options are for alignment purposes and are automatically inserted by a sending kernel when needed and ignored by
如今,IPv6[RFC-1883]只定义了三个逐跳选项:巨型有效负载、Pad1和PadN,尽管存在路由器警报逐跳选项的建议。不应将Jumbo Payload选项传递回应用程序,如果应用程序试图设置该选项,则应收到错误。此选项完全由内核处理。它由基于数据报的应用程序间接指定为要发送的数据报的大小,并作为接收数据报的长度间接传递回这些应用程序。这两个pad选项用于对齐,在需要时由发送内核自动插入,并被忽略
the receiving kernel. This section of the API is therefore defined for future Hop-by-Hop options that an application may need to specify and receive.
接收内核。因此,API的这一部分是为应用程序可能需要指定和接收的未来逐跳选项定义的。
Individual Hop-by-Hop options (and Destination options, which are described shortly, and which are similar to the Hop-by-Hop options) may have specific alignment requirements. For example, the 4-byte Jumbo Payload length should appear on a 4-byte boundary, and IPv6 addresses are normally aligned on an 8-byte boundary. These requirements and the terminology used with these options are discussed in Section 4.2 and Appendix A of [RFC-1883]. The alignment of each option is specified by two values, called x and y, written as "xn + y". This states that the option must appear at an integer multiple of x bytes from the beginning of the options header (x can have the values 1, 2, 4, or 8), plus y bytes (y can have a value between 0 and 7, inclusive). The Pad1 and PadN options are inserted as needed to maintain the required alignment. Whatever code builds either a Hop-by-Hop options header or a Destination options header must know the values of x and y for each option.
单个逐跳选项(和目的地选项,将简要介绍,与逐跳选项类似)可能具有特定的对齐要求。例如,4字节的巨型有效负载长度应出现在4字节边界上,IPv6地址通常在8字节边界上对齐。[RFC-1883]第4.2节和附录A中讨论了这些要求和与这些选项一起使用的术语。每个选项的对齐方式由两个值指定,称为x和y,写为“xn+y”。这表示该选项必须以x字节的整数倍显示,从选项标题的开头开始(x可以具有值1、2、4或8),再加上y字节(y可以具有介于0和7之间的值,包括0和7)。根据需要插入Pad1和PadN选项,以保持所需的对齐。任何构建逐跳选项标头或目标选项标头的代码都必须知道每个选项的x和y值。
Multiple Hop-by-Hop options can be specified by the application. Normally one ancillary data object describes all the Hop-by-Hop options (since each option is itself TLV-encoded) but the application can specify multiple ancillary data objects for the Hop-by-Hop options, each object specifying one or more options. Care must be taken designing the API for these options since
应用程序可以指定多个逐跳选项。通常一个辅助数据对象描述所有逐跳选项(因为每个选项本身都是TLV编码的),但应用程序可以为逐跳选项指定多个辅助数据对象,每个对象指定一个或多个选项。必须注意为这些选项设计API,因为
1. it may be possible for some future Hop-by-Hop options to be generated by the application and processed entirely by the application (e.g., the kernel may not know the alignment restrictions for the option),
1. 应用程序可能会生成一些未来的逐跳选项,并完全由应用程序处理(例如,内核可能不知道该选项的对齐限制),
2. it must be possible for the kernel to insert its own Hop-by-Hop options in an outgoing packet (e.g., the Jumbo Payload option),
2. 内核必须能够在传出数据包中插入自己的逐跳选项(例如,巨型有效负载选项),
3. the application can place one or more Hop-by-Hop options into a single ancillary data object,
3. 应用程序可以将一个或多个逐跳选项放入单个辅助数据对象中,
4. if the application specifies multiple ancillary data objects, each containing one or more Hop-by-Hop options, the kernel must combine these a single Hop-by-Hop options header, and
4. 如果应用程序指定了多个辅助数据对象,每个对象都包含一个或多个逐跳选项,那么内核必须将这些对象组合为一个逐跳选项头,并且
5. it must be possible for the kernel to remove some Hop-by-Hop options from a received packet before returning the remaining Hop-by-Hop options to the application. (This removal might consist of the kernel converting the option into a pad option of the same length.)
5. 在将剩余的逐跳选项返回给应用程序之前,内核必须能够从接收到的数据包中删除一些逐跳选项。(此删除可能包括内核将选项转换为相同长度的pad选项。)
Finally, we note that access to some Hop-by-Hop options or to some Destination options, might require special privilege. That is, normal applications (without special privilege) might be forbidden from setting certain options in outgoing packets, and might never see certain options in received packets.
最后,我们注意到访问某些逐跳选项或某些目标选项可能需要特殊权限。也就是说,普通应用程序(没有特殊权限)可能被禁止在传出数据包中设置某些选项,并且可能永远不会在接收到的数据包中看到某些选项。
To receive Hop-by-Hop options the application must enable the IPV6_HOPOPTS socket option:
要接收逐跳选项,应用程序必须启用IPV6_HOPOPTS套接字选项:
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_HOPOPTS, &on, sizeof(on));
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_HOPOPTS, &on, sizeof(on));
All the Hop-by-Hop options are returned as one ancillary data object described by a cmsghdr structure. The cmsg_level member will be IPPROTO_IPV6 and the cmsg_type member will be IPV6_HOPOPTS. These options are then processed by calling the inet6_option_next() and inet6_option_find() functions, described shortly.
所有逐跳选项都作为cmsghdr结构描述的一个辅助数据对象返回。cmsg_级别的成员将是IPPROTO_IPV6,cmsg_类型的成员将是IPV6_HOPOPTS。然后通过调用inet6\u option\u next()和inet6\u option\u find()函数来处理这些选项,稍后将对此进行描述。
To send one or more Hop-by-Hop options, the application just specifies them as ancillary data in a call to sendmsg(). No socket option need be set.
要发送一个或多个逐跳选项,应用程序只需在对sendmsg()的调用中将它们指定为辅助数据。不需要设置套接字选项。
Normally all the Hop-by-Hop options are specified by a single ancillary data object. Multiple ancillary data objects, each containing one or more Hop-by-Hop options, can also be specified, in which case the kernel will combine all the Hop-by-Hop options into a single Hop-by-Hop extension header. But it should be more efficient to use a single ancillary data object to describe all the Hop-by-Hop
通常,所有逐跳选项都由单个辅助数据对象指定。还可以指定多个辅助数据对象,每个辅助数据对象包含一个或多个逐跳选项,在这种情况下,内核将把所有逐跳选项合并到一个逐跳扩展头中。但是,使用单个辅助数据对象逐个描述所有跳应该更有效
options. The cmsg_level member is set to IPPROTO_IPV6 and the cmsg_type member is set to IPV6_HOPOPTS. The option is normally constructed using the inet6_option_init(), inet6_option_append(), and inet6_option_alloc() functions, described shortly.
选项。cmsg_级别成员设置为IPPROTO_IPV6,cmsg_类型成员设置为IPV6_HOPOPTS。该选项通常是使用inet6\u option\u init()、inet6\u option\u append()和inet6\u option\u alloc()函数构造的,稍后将进行介绍。
Additional errors may be possible from sendmsg() if the specified option is in error.
如果指定的选项出错,sendmsg()可能会出现其他错误。
Building and parsing the Hop-by-Hop and Destination options is complicated for the reasons given earlier. We therefore define a set of functions to help the application. The function prototypes for these functions are all in the <netinet/in.h> header.
由于前面给出的原因,逐跳和目的地选项的构建和解析非常复杂。因此,我们定义了一组函数来帮助应用程序。这些函数的函数原型都在<netinet/in.h>标题中。
int inet6_option_space(int nbytes);
int inet6_选项_空间(int N字节);
This function returns the number of bytes required to hold an option when it is stored as ancillary data, including the cmsghdr structure at the beginning, and any padding at the end (to make its size a multiple of 8 bytes). The argument is the size of the structure defining the option, which must include any pad bytes at the beginning (the value y in the alignment term "xn + y"), the type byte, the length byte, and the option data.
此函数返回保存选项作为辅助数据时所需的字节数,包括开头的cmsghdr结构和结尾的任何填充(使其大小为8字节的倍数)。参数是定义选项的结构的大小,它必须包括开头的任何焊盘字节(对齐术语“xn+y”中的值y)、类型字节、长度字节和选项数据。
(Note: If multiple options are stored in a single ancillary data object, which is the recommended technique, this function overestimates the amount of space required by the size of N-1 cmsghdr structures, where N is the number of options to be stored in the object. This is of little consequence, since it is assumed that most Hop-by-Hop option headers and Destination option headers carry only one option (p. 33 of [RFC-1883]).)
(注意:如果多个选项存储在单个辅助数据对象中,这是推荐的技术,则此函数高估了N-1 cmsghdr结构的大小所需的空间量,其中N是要存储在对象中的选项数。这没有什么影响,因为假定大多数逐跳选项都是头ers和目的地选项标题仅包含一个选项(RFC-1883第33页)
int inet6_option_init(void *bp, struct cmsghdr **cmsgp, int type);
int inet6_option_init(void *bp, struct cmsghdr **cmsgp, int type);
This function is called once per ancillary data object that will contain either Hop-by-Hop or Destination options. It returns 0 on success or -1 on an error.
对于包含逐跳或目标选项的辅助数据对象,此函数只调用一次。成功时返回0,错误时返回-1。
bp is a pointer to previously allocated space that will contain the ancillary data object. It must be large enough to contain all the individual options to be added by later calls to inet6_option_append() and inet6_option_alloc().
bp是指向先前分配的空间的指针,该空间将包含辅助数据对象。它必须足够大,以包含稍后调用inet6\u option\u append()和inet6\u option\u alloc()添加的所有单个选项。
cmsgp is a pointer to a pointer to a cmsghdr structure. *cmsgp is initialized by this function to point to the cmsghdr structure constructed by this function in the buffer pointed to by bp.
cmsgp是指向cmsghdr结构的指针*cmsgp由该函数初始化,以指向由该函数在bp指向的缓冲区中构造的cmsghdr结构。
type is either IPV6_HOPOPTS or IPV6_DSTOPTS. This type is stored in the cmsg_type member of the cmsghdr structure pointed to by *cmsgp.
类型为IPV6_hopts或IPV6_DSTOPTS。此类型存储在由*cmsgp指向的cmsghdr结构的cmsg_类型成员中。
int inet6_option_append(struct cmsghdr *cmsg, const uint8_t *typep, int multx, int plusy);
int inet6_option_append(struct cmsghdr *cmsg, const uint8_t *typep, int multx, int plusy);
This function appends a Hop-by-Hop option or a Destination option into an ancillary data object that has been initialized by inet6_option_init(). This function returns 0 if it succeeds or -1 on an error.
此函数将逐跳选项或目标选项附加到已由inet6_option_init()初始化的辅助数据对象中。如果此函数成功,则返回0;如果出现错误,则返回-1。
cmsg is a pointer to the cmsghdr structure that must have been initialized by inet6_option_init().
cmsg是指向cmsghdr结构的指针,该结构必须已由inet6_option_init()初始化。
typep is a pointer to the 8-bit option type. It is assumed that this field is immediately followed by the 8-bit option data length field, which is then followed immediately by the option data. The caller initializes these three fields (the type-length-value, or TLV) before calling this function.
typep是指向8位选项类型的指针。假设该字段后面紧跟着8位选项数据长度字段,然后紧跟着选项数据。调用方在调用此函数之前初始化这三个字段(类型长度值或TLV)。
The option type must have a value from 2 to 255, inclusive. (0 and 1 are reserved for the Pad1 and PadN options, respectively.)
选项类型的值必须介于2和255之间(含2和255)。(0和1分别为Pad1和PadN选项保留。)
The option data length must have a value between 0 and 255, inclusive, and is the length of the option data that follows.
选项数据长度的值必须介于0和255(含0和255)之间,并且是后面选项数据的长度。
multx is the value x in the alignment term "xn + y" described earlier. It must have a value of 1, 2, 4, or 8.
multx是前面描述的对齐术语“xn+y”中的值x。它的值必须为1、2、4或8。
plusy is the value y in the alignment term "xn + y" described earlier. It must have a value between 0 and 7, inclusive.
plusy是前面描述的对齐术语“xn+y”中的值y。它的值必须介于0和7之间(包括0和7)。
uint8_t *inet6_option_alloc(struct cmsghdr *cmsg, int datalen, int multx, int plusy);
uint8_t *inet6_option_alloc(struct cmsghdr *cmsg, int datalen, int multx, int plusy);
This function appends a Hop-by-Hop option or a Destination option into an ancillary data object that has been initialized by inet6_option_init(). This function returns a pointer to the 8-bit option type field that starts the option on success, or NULL on an error.
此函数将逐跳选项或目标选项附加到已由inet6_option_init()初始化的辅助数据对象中。此函数返回指向8位选项类型字段的指针,该字段在成功时启动该选项,或在错误时返回NULL。
The difference between this function and inet6_option_append() is that the latter copies the contents of a previously built option into the ancillary data object while the current function returns a pointer to the space in the data object where the option's TLV must then be built by the caller.
此函数与inet6_option_append()之间的区别在于后者将先前构建的选项的内容复制到辅助数据对象中,而当前函数返回指向数据对象中的空间的指针,调用方必须在该空间中构建选项的TLV。
cmsg is a pointer to the cmsghdr structure that must have been initialized by inet6_option_init().
cmsg是指向cmsghdr结构的指针,该结构必须已由inet6_option_init()初始化。
datalen is the value of the option data length byte for this option. This value is required as an argument to allow the function to determine if padding must be appended at the end of the option. (The inet6_option_append() function does not need a data length argument since the option data length must already be stored by the caller.)
datalen是此选项的选项数据长度字节的值。此值作为参数是必需的,以允许函数确定是否必须在选项末尾追加填充。(inet6_option_append()函数不需要数据长度参数,因为调用方必须已经存储了选项数据长度。)
multx is the value x in the alignment term "xn + y" described earlier. It must have a value of 1, 2, 4, or 8.
multx是前面描述的对齐术语“xn+y”中的值x。它的值必须为1、2、4或8。
plusy is the value y in the alignment term "xn + y" described earlier. It must have a value between 0 and 7, inclusive.
plusy是前面描述的对齐术语“xn+y”中的值y。它的值必须介于0和7之间(包括0和7)。
int inet6_option_next(const struct cmsghdr *cmsg, uint8_t **tptrp);
int inet6_option_next(const struct cmsghdr *cmsg, uint8_t **tptrp);
This function processes the next Hop-by-Hop option or Destination option in an ancillary data object. If another option remains to be processed, the return value of the function is 0 and *tptrp points to the 8-bit option type field (which is followed by the 8-bit option data length, followed by the option data). If no more options remain to be processed, the return value is -1 and *tptrp is NULL. If an error occurs, the return value is -1 and *tptrp is not NULL.
此函数用于处理辅助数据对象中的下一个逐跳选项或目标选项。如果还有另一个选项需要处理,则函数的返回值为0,*tptrp指向8位选项类型字段(后跟8位选项数据长度,后跟选项数据)。如果没有更多的选项需要处理,则返回值为-1,*tptrp为空。如果发生错误,则返回值为-1,*tptrp不为空。
cmsg is a pointer to cmsghdr structure of which cmsg_level equals IPPROTO_IPV6 and cmsg_type equals either IPV6_HOPOPTS or IPV6_DSTOPTS.
cmsg是指向cmsghdr结构的指针,其中cmsg_级别等于IPPROTO_IPV6,cmsg_类型等于IPV6_hopts或IPV6_DSTOPTS。
tptrp is a pointer to a pointer to an 8-bit byte and *tptrp is used by the function to remember its place in the ancillary data object each time the function is called. The first time this function is called for a given ancillary data object, *tptrp must be set to NULL.
tptrp是指向8位字节的指针,函数每次调用该函数时都使用*tptrp来记住其在辅助数据对象中的位置。第一次为给定辅助数据对象调用此函数时,*tptrp必须设置为NULL。
Each time this function returns success, *tptrp points to the 8-bit option type field for the next option to be processed.
每次此函数返回成功,*tptrp都指向8位选项类型字段,以便下一个要处理的选项。
int inet6_option_find(const struct cmsghdr *cmsg, uint8_t *tptrp, int type);
int inet6_option_find(const struct cmsghdr *cmsg, uint8_t *tptrp, int type);
This function is similar to the previously described inet6_option_next() function, except this function lets the caller specify the option type to be searched for, instead of always returning the next option in the ancillary data object. cmsg is a pointer to cmsghdr structure of which cmsg_level equals IPPROTO_IPV6 and cmsg_type equals either IPV6_HOPOPTS or IPV6_DSTOPTS.
此函数类似于前面描述的inet6_option_next()函数,只是此函数允许调用方指定要搜索的选项类型,而不是始终返回辅助数据对象中的下一个选项。cmsg是指向cmsghdr结构的指针,其中cmsg_级别等于IPPROTO_IPV6,cmsg_类型等于IPV6_hopts或IPV6_DSTOPTS。
tptrp is a pointer to a pointer to an 8-bit byte and *tptrp is used by the function to remember its place in the ancillary data object each time the function is called. The first time this function is called for a given ancillary data object, *tptrp must be set to NULL.
tptrp是指向8位字节的指针,函数每次调用该函数时都使用*tptrp来记住其在辅助数据对象中的位置。第一次为给定辅助数据对象调用此函数时,*tptrp必须设置为NULL。
This function starts searching for an option of the specified type beginning after the value of *tptrp. If an option of the specified type is located, this function returns 0 and *tptrp points to the 8- bit option type field for the option of the specified type. If an option of the specified type is not located, the return value is -1 and *tptrp is NULL. If an error occurs, the return value is -1 and *tptrp is not NULL.
此函数开始搜索指定类型的选项,该选项从*tptrp的值开始。如果找到指定类型的选项,此函数将返回0,*tptrp指向指定类型选项的8位选项类型字段。如果未找到指定类型的选项,则返回值为-1,*tptrp为空。如果发生错误,则返回值为-1,*tptrp不为空。
We now provide an example that builds two Hop-by-Hop options. First we define two options, called X and Y, taken from the example in Appendix A of [RFC-1883]. We assume that all options will have structure definitions similar to what is shown below.
现在,我们提供了一个构建两个逐跳选项的示例。首先,我们从[RFC-1883]附录A中的示例中定义了两个选项,称为X和Y。我们假设所有选项的结构定义与下面所示类似。
/* option X and option Y are defined in [RFC-1883], pp. 33-34 */ #define IP6_X_OPT_TYPE X /* replace X with assigned value */ #define IP6_X_OPT_LEN 12 #define IP6_X_OPT_MULTX 8 /* 8n + 2 alignment */ #define IP6_X_OPT_OFFSETY 2
/* option X and option Y are defined in [RFC-1883], pp. 33-34 */ #define IP6_X_OPT_TYPE X /* replace X with assigned value */ #define IP6_X_OPT_LEN 12 #define IP6_X_OPT_MULTX 8 /* 8n + 2 alignment */ #define IP6_X_OPT_OFFSETY 2
struct ip6_X_opt { uint8_t ip6_X_opt_pad[IP6_X_OPT_OFFSETY]; uint8_t ip6_X_opt_type; uint8_t ip6_X_opt_len; uint32_t ip6_X_opt_val1; uint64_t ip6_X_opt_val2; };
struct ip6_X_opt { uint8_t ip6_X_opt_pad[IP6_X_OPT_OFFSETY]; uint8_t ip6_X_opt_type; uint8_t ip6_X_opt_len; uint32_t ip6_X_opt_val1; uint64_t ip6_X_opt_val2; };
#define IP6_Y_OPT_TYPE Y /* replace Y with assigned value */ #define IP6_Y_OPT_LEN 7 #define IP6_Y_OPT_MULTX 4 /* 4n + 3 alignment */ #define IP6_Y_OPT_OFFSETY 3
#define IP6_Y_OPT_TYPE Y /* replace Y with assigned value */ #define IP6_Y_OPT_LEN 7 #define IP6_Y_OPT_MULTX 4 /* 4n + 3 alignment */ #define IP6_Y_OPT_OFFSETY 3
struct ip6_Y_opt { uint8_t ip6_Y_opt_pad[IP6_Y_OPT_OFFSETY]; uint8_t ip6_Y_opt_type; uint8_t ip6_Y_opt_len; uint8_t ip6_Y_opt_val1; uint16_t ip6_Y_opt_val2; uint32_t ip6_Y_opt_val3; };
struct ip6_Y_opt { uint8_t ip6_Y_opt_pad[IP6_Y_OPT_OFFSETY]; uint8_t ip6_Y_opt_type; uint8_t ip6_Y_opt_len; uint8_t ip6_Y_opt_val1; uint16_t ip6_Y_opt_val2; uint32_t ip6_Y_opt_val3; };
We now show the code fragment to build one ancillary data object containing both options.
现在,我们展示构建一个包含这两个选项的辅助数据对象的代码片段。
struct msghdr msg; struct cmsghdr *cmsgptr; struct ip6_X_opt optX; struct ip6_Y_opt optY;
struct msghdr msg; struct cmsghdr *cmsgptr; struct ip6_X_opt optX; struct ip6_Y_opt optY;
msg.msg_control = malloc(inet6_option_space(sizeof(optX) + sizeof(optY)));
msg.msg_control = malloc(inet6_option_space(sizeof(optX) + sizeof(optY)));
inet6_option_init(msg.msg_control, &cmsgptr, IPV6_HOPOPTS);
inet6选项初始化(msg.msg控制和cmsgptr、IPV6选项);
optX.ip6_X_opt_type = IP6_X_OPT_TYPE; optX.ip6_X_opt_len = IP6_X_OPT_LEN; optX.ip6_X_opt_val1 = <32-bit value>; optX.ip6_X_opt_val2 = <64-bit value>; inet6_option_append(cmsgptr, &optX.ip6_X_opt_type, IP6_X_OPT_MULTX, IP6_X_OPT_OFFSETY);
optX.ip6_X_opt_type = IP6_X_OPT_TYPE; optX.ip6_X_opt_len = IP6_X_OPT_LEN; optX.ip6_X_opt_val1 = <32-bit value>; optX.ip6_X_opt_val2 = <64-bit value>; inet6_option_append(cmsgptr, &optX.ip6_X_opt_type, IP6_X_OPT_MULTX, IP6_X_OPT_OFFSETY);
optY.ip6_Y_opt_type = IP6_Y_OPT_TYPE; optY.ip6_Y_opt_len = IP6_Y_OPT_LEN; optY.ip6_Y_opt_val1 = <8-bit value>; optY.ip6_Y_opt_val2 = <16-bit value>; optY.ip6_Y_opt_val3 = <32-bit value>; inet6_option_append(cmsgptr, &optY.ip6_Y_opt_type, IP6_Y_OPT_MULTX, IP6_Y_OPT_OFFSETY);
optY.ip6_Y_opt_type = IP6_Y_OPT_TYPE; optY.ip6_Y_opt_len = IP6_Y_OPT_LEN; optY.ip6_Y_opt_val1 = <8-bit value>; optY.ip6_Y_opt_val2 = <16-bit value>; optY.ip6_Y_opt_val3 = <32-bit value>; inet6_option_append(cmsgptr, &optY.ip6_Y_opt_type, IP6_Y_OPT_MULTX, IP6_Y_OPT_OFFSETY);
msg.msg_controllen = cmsgptr->cmsg_len;
msg.msg_controllen = cmsgptr->cmsg_len;
The call to inet6_option_init() builds the cmsghdr structure in the control buffer.
调用inet6_option_init()在控制缓冲区中构建cmsghdr结构。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = CMSG_LEN(0) = 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = CMSG_LEN(0) = 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Here we assume a 32-bit architecture where sizeof(struct cmsghdr) equals 12, with a desired alignment of 4-byte boundaries (that is, the ALIGN() macro shown in the sample implementations of the CMSG_xxx() macros rounds up to a multiple of 4).
在这里,我们假设一个32位的体系结构,其中sizeof(struct cmsghdr)等于12,需要对齐4字节边界(即,CMSG_xxx()宏的示例实现中显示的ALIGN()宏四舍五入为4的倍数)。
The first call to inet6_option_append() appends the X option. Since this is the first option in the ancillary data object, 2 bytes are allocated for the Next Header byte and for the Hdr Ext Len byte. The former will be set by the kernel, depending on the type of header that follows this header, and the latter byte is set to 1. These 2 bytes form the 2 bytes of padding (IP6_X_OPT_OFFSETY) required at the beginning of this option.
对inet6\u option\u append()的第一个调用附加了X选项。由于这是辅助数据对象中的第一个选项,因此为下一个报头字节和Hdr Ext Len字节分配了2个字节。前者将由内核设置,具体取决于此标头后面的标头类型,后者字节设置为1。这2个字节构成此选项开头所需的2个字节的填充(IP6_X_OPT_OFFSETY)。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 28 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=1 | Option Type=X |Opt Data Len=12| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + 8-octet field + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 28 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=1 | Option Type=X |Opt Data Len=12| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + 8-octet field + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The cmsg_len member of the cmsghdr structure is incremented by 16, the size of the option.
cmsghdr结构的cmsg_len成员增加16,即选项的大小。
The next call to inet6_option_append() appends the Y option to the ancillary data object.
对inet6\u option\u append()的下一个调用将Y选项附加到辅助数据对象。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 44 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=3 | Option Type=X |Opt Data Len=12| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + 8-octet field + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PadN Option=1 |Opt Data Len=1 | 0 | Option Type=Y | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Opt Data Len=7 | 1-octet field | 2-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PadN Option=1 |Opt Data Len=2 | 0 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 44 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=3 | Option Type=X |Opt Data Len=12| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + 8-octet field + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PadN Option=1 |Opt Data Len=1 | 0 | Option Type=Y | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Opt Data Len=7 | 1-octet field | 2-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PadN Option=1 |Opt Data Len=2 | 0 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 bytes are appended by this function, so cmsg_len becomes 44. The inet6_option_append() function notices that the appended data requires 4 bytes of padding at the end, to make the size of the ancillary data object a multiple of 8, and appends the PadN option before returning. The Hdr Ext Len byte is incremented by 2 to become 3.
此函数追加16个字节,因此cmsg_len变为44。inet6_option_append()函数注意到附加的数据需要在末尾添加4字节的填充,以使辅助数据对象的大小为8的倍数,并在返回之前附加PadN选项。Hdr Ext Len字节增加2,变为3。
Alternately, the application could build two ancillary data objects, one per option, although this will probably be less efficient than combining the two options into a single ancillary data object (as just shown). The kernel must combine these into a single Hop-by-Hop extension header in the final IPv6 packet.
或者,应用程序可以构建两个辅助数据对象,每个选项一个,尽管这可能比将两个选项组合到一个辅助数据对象(如图所示)效率低。内核必须在最后一个IPv6数据包中将它们组合成一个逐跳扩展头。
struct msghdr msg; struct cmsghdr *cmsgptr; struct ip6_X_opt optX; struct ip6_Y_opt optY;
struct msghdr msg; struct cmsghdr *cmsgptr; struct ip6_X_opt optX; struct ip6_Y_opt optY;
msg.msg_control = malloc(inet6_option_space(sizeof(optX)) + inet6_option_space(sizeof(optY)));
msg.msg_control = malloc(inet6_option_space(sizeof(optX)) + inet6_option_space(sizeof(optY)));
inet6_option_init(msg.msg_control, &cmsgptr, IPPROTO_HOPOPTS);
inet6选项初始化(msg.msg\u控件和cmsgptr、IPPROTO\u HOPOPTS);
optX.ip6_X_opt_type = IP6_X_OPT_TYPE;
optX.ip6_X_opt_type=ip6_X_opt_type;
optX.ip6_X_opt_len = IP6_X_OPT_LEN; optX.ip6_X_opt_val1 = <32-bit value>; optX.ip6_X_opt_val2 = <64-bit value>; inet6_option_append(cmsgptr, &optX.ip6_X_opt_type, IP6_X_OPT_MULTX, IP6_X_OPT_OFFSETY); msg.msg_controllen = CMSG_SPACE(sizeof(optX));
optX.ip6_X_opt_len = IP6_X_OPT_LEN; optX.ip6_X_opt_val1 = <32-bit value>; optX.ip6_X_opt_val2 = <64-bit value>; inet6_option_append(cmsgptr, &optX.ip6_X_opt_type, IP6_X_OPT_MULTX, IP6_X_OPT_OFFSETY); msg.msg_controllen = CMSG_SPACE(sizeof(optX));
inet6_option_init((u_char *)msg.msg_control + msg.msg_controllen, &cmsgptr, IPPROTO_HOPOPTS);
inet6_option_init((u_char *)msg.msg_control + msg.msg_controllen, &cmsgptr, IPPROTO_HOPOPTS);
optY.ip6_Y_opt_type = IP6_Y_OPT_TYPE; optY.ip6_Y_opt_len = IP6_Y_OPT_LEN; optY.ip6_Y_opt_val1 = <8-bit value>; optY.ip6_Y_opt_val2 = <16-bit value>; optY.ip6_Y_opt_val3 = <32-bit value>; inet6_option_append(cmsgptr, &optY.ip6_Y_opt_type, IP6_Y_OPT_MULTX, IP6_Y_OPT_OFFSETY); msg.msg_controllen += cmsgptr->cmsg_len;
optY.ip6_Y_opt_type = IP6_Y_OPT_TYPE; optY.ip6_Y_opt_len = IP6_Y_OPT_LEN; optY.ip6_Y_opt_val1 = <8-bit value>; optY.ip6_Y_opt_val2 = <16-bit value>; optY.ip6_Y_opt_val3 = <32-bit value>; inet6_option_append(cmsgptr, &optY.ip6_Y_opt_type, IP6_Y_OPT_MULTX, IP6_Y_OPT_OFFSETY); msg.msg_controllen += cmsgptr->cmsg_len;
Each call to inet6_option_init() builds a new cmsghdr structure, and the final result looks like the following:
每次调用inet6_option_init()都会构建一个新的cmsghdr结构,最终结果如下所示:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 28 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=1 | Option Type=X |Opt Data Len=12| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + 8-octet field + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 28 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=1 | Pad1 Option=0 | Option Type=Y | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Opt Data Len=7 | 1-octet field | 2-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PadN Option=1 |Opt Data Len=2 | 0 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 28 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=1 | Option Type=X |Opt Data Len=12| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + 8-octet field + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 28 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_HOPOPTS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=1 | Pad1 Option=0 | Option Type=Y | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Opt Data Len=7 | 1-octet field | 2-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 4-octet field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PadN Option=1 |Opt Data Len=2 | 0 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
When the kernel combines these two options into a single Hop-by-Hop extension header, the first 3 bytes of the second ancillary data object (the Next Header byte, the Hdr Ext Len byte, and the Pad1 option) will be combined into a PadN option occupying 3 bytes.
当内核将这两个选项组合成单个逐跳扩展头时,第二个辅助数据对象的前3个字节(下一个头字节、Hdr Ext Len字节和Pad1选项)将组合成一个占据3个字节的PadN选项。
The following code fragment is a redo of the first example shown (building two options in a single ancillary data object) but this time we use inet6_option_alloc().
下面的代码片段是所示第一个示例(在一个辅助数据对象中构建两个选项)的重做,但这次我们使用inet6_option_alloc()。
uint8_t *typep; struct msghdr msg; struct cmsghdr *cmsgptr; struct ip6_X_opt *optXp; /* now a pointer, not a struct */ struct ip6_Y_opt *optYp; /* now a pointer, not a struct */
uint8_t *typep; struct msghdr msg; struct cmsghdr *cmsgptr; struct ip6_X_opt *optXp; /* now a pointer, not a struct */ struct ip6_Y_opt *optYp; /* now a pointer, not a struct */
msg.msg_control = malloc(inet6_option_space(sizeof(*optXp) + sizeof(*optYp)));
msg.msg_control = malloc(inet6_option_space(sizeof(*optXp) + sizeof(*optYp)));
inet6_option_init(msg.msg_control, &cmsgptr, IPV6_HOPOPTS);
inet6选项初始化(msg.msg控制和cmsgptr、IPV6选项);
typep = inet6_option_alloc(cmsgptr, IP6_X_OPT_LEN, IP6_X_OPT_MULTX, IP6_X_OPT_OFFSETY); optXp = (struct ip6_X_opt *) (typep - IP6_X_OPT_OFFSETY); optXp->ip6_X_opt_type = IP6_X_OPT_TYPE; optXp->ip6_X_opt_len = IP6_X_OPT_LEN; optXp->ip6_X_opt_val1 = <32-bit value>; optXp->ip6_X_opt_val2 = <64-bit value>;
typep = inet6_option_alloc(cmsgptr, IP6_X_OPT_LEN, IP6_X_OPT_MULTX, IP6_X_OPT_OFFSETY); optXp = (struct ip6_X_opt *) (typep - IP6_X_OPT_OFFSETY); optXp->ip6_X_opt_type = IP6_X_OPT_TYPE; optXp->ip6_X_opt_len = IP6_X_OPT_LEN; optXp->ip6_X_opt_val1 = <32-bit value>; optXp->ip6_X_opt_val2 = <64-bit value>;
typep = inet6_option_alloc(cmsgptr, IP6_Y_OPT_LEN, IP6_Y_OPT_MULTX, IP6_Y_OPT_OFFSETY); optYp = (struct ip6_Y_opt *) (typep - IP6_Y_OPT_OFFSETY); optYp->ip6_Y_opt_type = IP6_Y_OPT_TYPE; optYp->ip6_Y_opt_len = IP6_Y_OPT_LEN; optYp->ip6_Y_opt_val1 = <8-bit value>; optYp->ip6_Y_opt_val2 = <16-bit value>; optYp->ip6_Y_opt_val3 = <32-bit value>;
typep = inet6_option_alloc(cmsgptr, IP6_Y_OPT_LEN, IP6_Y_OPT_MULTX, IP6_Y_OPT_OFFSETY); optYp = (struct ip6_Y_opt *) (typep - IP6_Y_OPT_OFFSETY); optYp->ip6_Y_opt_type = IP6_Y_OPT_TYPE; optYp->ip6_Y_opt_len = IP6_Y_OPT_LEN; optYp->ip6_Y_opt_val1 = <8-bit value>; optYp->ip6_Y_opt_val2 = <16-bit value>; optYp->ip6_Y_opt_val3 = <32-bit value>;
msg.msg_controllen = cmsgptr->cmsg_len;
msg.msg_controllen = cmsgptr->cmsg_len;
Notice that inet6_option_alloc() returns a pointer to the 8-bit option type field. If the program wants a pointer to an option structure that includes the padding at the front (as shown in our definitions of the ip6_X_opt and ip6_Y_opt structures), the y-offset at the beginning of the structure must be subtracted from the returned pointer.
请注意,inet6\u option\u alloc()返回指向8位选项类型字段的指针。如果程序需要指向包含前面填充的选项结构的指针(如我们对ip6_X_opt和ip6_Y_opt结构的定义所示),则必须从返回的指针中减去结构开头的Y偏移量。
The following code fragment shows the processing of Hop-by-Hop options using the inet6_option_next() function.
下面的代码片段显示了使用inet6\u option\u next()函数处理逐跳选项的过程。
struct msghdr msg; struct cmsghdr *cmsgptr;
struct msghdr msg; struct cmsghdr *cmsgptr;
/* fill in msg */
/* fill in msg */
/* call recvmsg() */
/* call recvmsg() */
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPOPTS) {
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPOPTS) {
uint8_t *tptr = NULL;
uint8_t *tptr = NULL;
while (inet6_option_next(cmsgptr, &tptr) == 0) { if (*tptr == IP6_X_OPT_TYPE) { struct ip6_X_opt *optXp;
while (inet6_option_next(cmsgptr, &tptr) == 0) { if (*tptr == IP6_X_OPT_TYPE) { struct ip6_X_opt *optXp;
optXp = (struct ip6_X_opt *) (tptr - IP6_X_OPT_OFFSETY); <do whatever with> optXp->ip6_X_opt_val1; <do whatever with> optXp->ip6_X_opt_val2;
optXp = (struct ip6_X_opt *) (tptr - IP6_X_OPT_OFFSETY); <do whatever with> optXp->ip6_X_opt_val1; <do whatever with> optXp->ip6_X_opt_val2;
} else if (*tptr == IP6_Y_OPT_TYPE) { struct ip6_Y_opt *optYp;
} else if (*tptr == IP6_Y_OPT_TYPE) { struct ip6_Y_opt *optYp;
optYp = (struct ip6_Y_opt *) (tptr - IP6_Y_OPT_OFFSETY); <do whatever with> optYp->ip6_Y_opt_val1; <do whatever with> optYp->ip6_Y_opt_val2; <do whatever with> optYp->ip6_Y_opt_val3; } } if (tptr != NULL) <error encountered by inet6_option_next()>; } }
optYp = (struct ip6_Y_opt *) (tptr - IP6_Y_OPT_OFFSETY); <do whatever with> optYp->ip6_Y_opt_val1; <do whatever with> optYp->ip6_Y_opt_val2; <do whatever with> optYp->ip6_Y_opt_val3; } } if (tptr != NULL) <error encountered by inet6_option_next()>; } }
A variable number of Destination options can appear in one or more Destination option headers. As defined in [RFC-1883], a Destination options header appearing before a Routing header is processed by the first destination plus any subsequent destinations specified in the Routing header, while a Destination options header appearing after a Routing header is processed only by the final destination. As with the Hop-by-Hop options, each option in a Destination options header is TLV-encoded with a type, length, and value.
一个或多个目标选项标题中可以出现数量可变的目标选项。如[RFC-1883]中所定义,在路由报头之前出现的目的地选项报头由第一个目的地加上路由报头中指定的任何后续目的地处理,而在路由报头之后出现的目的地选项报头仅由最终目的地处理。与逐跳选项一样,目标选项标头中的每个选项都使用类型、长度和值进行TLV编码。
Today no Destination options are defined for IPv6 [RFC-1883], although proposals exist to use Destination options with mobility and anycasting.
今天,IPv6[RFC-1883]没有定义任何目的地选项,尽管有建议将目的地选项与移动性和选播结合使用。
To receive Destination options the application must enable the IPV6_DSTOPTS socket option:
要接收目标选项,应用程序必须启用IPv6DStopts套接字选项:
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_DSTOPTS, &on, sizeof(on));
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_DSTOPTS, &on, sizeof(on));
All the Destination options appearing before a Routing header are returned as one ancillary data object described by a cmsghdr structure and all the Destination options appearing after a Routing header are returned as another ancillary data object described by a cmsghdr structure. For these ancillary data objects, the cmsg_level
在路由报头之前出现的所有目的地选项作为cmsghdr结构描述的一个辅助数据对象返回,在路由报头之后出现的所有目的地选项作为cmsghdr结构描述的另一个辅助数据对象返回。对于这些辅助数据对象,cmsg_级别
member will be IPPROTO_IPV6 and the cmsg_type member will be IPV6_HOPOPTS. These options are then processed by calling the inet6_option_next() and inet6_option_find() functions.
成员将是IPPROTO_IPV6,cmsg_类型成员将是IPV6_HOPOPTS。然后通过调用inet6\u option\u next()和inet6\u option\u find()函数来处理这些选项。
To send one or more Destination options, the application just specifies them as ancillary data in a call to sendmsg(). No socket option need be set.
要发送一个或多个目标选项,应用程序只需在对sendmsg()的调用中将它们指定为辅助数据。不需要设置套接字选项。
As described earlier, one set of Destination options can appear before a Routing header, and one set can appear after a Routing header. Each set can consist of one or more options.
如前所述,一组目的地选项可以出现在路由标头之前,一组可以出现在路由标头之后。每组可包含一个或多个选项。
Normally all the Destination options in a set are specified by a single ancillary data object, since each option is itself TLV-encoded. Multiple ancillary data objects, each containing one or more Destination options, can also be specified, in which case the kernel will combine all the Destination options in the set into a single Destination extension header. But it should be more efficient to use a single ancillary data object to describe all the Destination options in a set. The cmsg_level member is set to IPPROTO_IPV6 and the cmsg_type member is set to IPV6_DSTOPTS. The option is normally constructed using the inet6_option_init(), inet6_option_append(), and inet6_option_alloc() functions.
通常,集合中的所有目标选项都由单个辅助数据对象指定,因为每个选项本身都是TLV编码的。还可以指定多个辅助数据对象,每个辅助数据对象包含一个或多个目标选项,在这种情况下,内核将把集合中的所有目标选项合并到一个目标扩展头中。但是,使用单个辅助数据对象来描述集合中的所有目标选项应该更有效。cmsg_级别成员设置为IPPROTO_IPV6,cmsg_类型成员设置为IPV6_DSTOPTS。该选项通常使用inet6\u option\u init()、inet6\u option\u append()和inet6\u option\u alloc()函数构造。
Additional errors may be possible from sendmsg() if the specified option is in error.
如果指定的选项出错,sendmsg()可能会出现其他错误。
Source routing in IPv6 is accomplished by specifying a Routing header as an extension header. There can be different types of Routing headers, but IPv6 currently defines only the Type 0 Routing header [RFC-1883]. This type supports up to 23 intermediate nodes. With this maximum number of intermediate nodes, a source, and a destination, there are 24 hops, each of which is defined as a strict or loose hop.
IPv6中的源路由是通过将路由标头指定为扩展标头来完成的。可以有不同类型的路由头,但IPv6目前仅定义类型0路由头[RFC-1883]。此类型最多支持23个中间节点。对于中间节点、源和目标的最大数量,有24个跃点,每个跃点定义为严格或松散的跃点。
Source routing with IPv4 sockets API (the IP_OPTIONS socket option) requires the application to build the source route in the format that appears as the IPv4 header option, requiring intimate knowledge of the IPv4 options format. This IPv6 API, however, defines eight functions that the application calls to build and examine a Routing header. Four functions build a Routing header:
使用IPv4套接字API(IP_选项套接字选项)的源路由要求应用程序以显示为IPv4标头选项的格式构建源路由,这需要熟悉IPv4选项格式。但是,此IPv6 API定义了应用程序调用的八个函数,用于构建和检查路由头。四个功能构建路由标头:
inet6_rthdr_space() - return #bytes required for ancillary data inet6_rthdr_init() - initialize ancillary data for Routing header
inet6_rthdr_space() - return #bytes required for ancillary data inet6_rthdr_init() - initialize ancillary data for Routing header
inet6_rthdr_add() - add IPv6 address & flags to Routing header inet6_rthdr_lasthop() - specify the flags for the final hop
inet6_rthdr_add() - add IPv6 address & flags to Routing header inet6_rthdr_lasthop() - specify the flags for the final hop
Four functions deal with a returned Routing header:
四个函数处理返回的路由标头:
inet6_rthdr_reverse() - reverse a Routing header inet6_rthdr_segments() - return #segments in a Routing header inet6_rthdr_getaddr() - fetch one address from a Routing header inet6_rthdr_getflags() - fetch one flag from a Routing header
inet6_rthdr_reverse() - reverse a Routing header inet6_rthdr_segments() - return #segments in a Routing header inet6_rthdr_getaddr() - fetch one address from a Routing header inet6_rthdr_getflags() - fetch one flag from a Routing header
The function prototypes for these functions are all in the <netinet/in.h> header.
这些函数的函数原型都在<netinet/in.h>标题中。
To receive a Routing header the application must enable the IPV6_RTHDR socket option:
要接收路由标头,应用程序必须启用IPV6\r套接字选项:
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_RTHDR, &on, sizeof(on));
int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_RTHDR, &on, sizeof(on));
To send a Routing header the application just specifies it as ancillary data in a call to sendmsg().
要发送路由头,应用程序只需在对sendmsg()的调用中将其指定为辅助数据。
A Routing header is passed between the application and the kernel as an ancillary data object. The cmsg_level member has a value of IPPROTO_IPV6 and the cmsg_type member has a value of IPV6_RTHDR. The contents of the cmsg_data[] member is implementation dependent and should not be accessed directly by the application, but should be accessed using the eight functions that we are about to describe.
路由头作为辅助数据对象在应用程序和内核之间传递。cmsg_级别成员的值为IPPROTO_IPV6,cmsg_类型成员的值为IPV6_RTHDR。cmsg_data[]成员的内容取决于实现,不应由应用程序直接访问,但应使用我们将要描述的八个函数进行访问。
The following constants are defined in the <netinet/in.h> header:
以下常量在<netinet/in.h>标题中定义:
#define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor */ #define IPV6_RTHDR_STRICT 1 /* this hop must be a neighbor */
#define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor */ #define IPV6_RTHDR_STRICT 1 /* this hop must be a neighbor */
#define IPV6_RTHDR_TYPE_0 0 /* IPv6 Routing header type 0 */
#define IPV6_RTHDR_TYPE_0 0 /* IPv6 Routing header type 0 */
When a Routing header is specified, the destination address specified for connect(), sendto(), or sendmsg() is the final destination address of the datagram. The Routing header then contains the addresses of all the intermediate nodes.
指定路由标头时,为connect()、sendto()或sendmsg()指定的目标地址是数据报的最终目标地址。然后,路由报头包含所有中间节点的地址。
size_t inet6_rthdr_space(int type, int segments);
大小inet6\uRTHDR\u空间(int类型,int段);
This function returns the number of bytes required to hold a Routing header of the specified type containing the specified number of
此函数返回保存指定类型的路由头所需的字节数,该路由头包含指定数量的
segments (addresses). For an IPv6 Type 0 Routing header, the number of segments must be between 1 and 23, inclusive. The return value includes the size of the cmsghdr structure that precedes the Routing header, and any required padding.
段(地址)。对于IPv6类型0路由标头,段数必须介于1和23之间(包括1和23)。返回值包括路由头之前的cmsghdr结构的大小以及任何所需的填充。
If the return value is 0, then either the type of the Routing header is not supported by this implementation or the number of segments is invalid for this type of Routing header.
如果返回值为0,则此实现不支持路由标头的类型,或者此类型路由标头的段数无效。
(Note: This function returns the size but does not allocate the space required for the ancillary data. This allows an application to allocate a larger buffer, if other ancillary data objects are desired, since all the ancillary data objects must be specified to sendmsg() as a single msg_control buffer.)
(注意:此函数返回大小,但不分配辅助数据所需的空间。如果需要其他辅助数据对象,则允许应用程序分配更大的缓冲区,因为必须将所有辅助数据对象指定给sendmsg(),作为单个msg_控制缓冲区。)
struct cmsghdr *inet6_rthdr_init(void *bp, int type);
struct cmsghdr *inet6_rthdr_init(void *bp, int type);
This function initializes the buffer pointed to by bp to contain a cmsghdr structure followed by a Routing header of the specified type. The cmsg_len member of the cmsghdr structure is initialized to the size of the structure plus the amount of space required by the Routing header. The cmsg_level and cmsg_type members are also initialized as required.
此函数初始化bp指向的缓冲区,使其包含cmsghdr结构,后跟指定类型的路由标头。cmsghdr结构的cmsg_len成员初始化为结构的大小加上路由报头所需的空间量。cmsg_级别和cmsg_类型成员也会根据需要进行初始化。
The caller must allocate the buffer and its size can be determined by calling inet6_rthdr_space().
调用者必须分配缓冲区,其大小可以通过调用inet6\u rthdr\u space()来确定。
Upon success the return value is the pointer to the cmsghdr structure, and this is then used as the first argument to the next two functions. Upon an error the return value is NULL.
成功后,返回值是指向cmsghdr结构的指针,然后将其用作下两个函数的第一个参数。出现错误时,返回值为空。
int inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, unsigned int flags);
int inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, unsigned int flags);
This function adds the address pointed to by addr to the end of the Routing header being constructed and sets the type of this hop to the value of flags. For an IPv6 Type 0 Routing header, flags must be either IPV6_RTHDR_LOOSE or IPV6_RTHDR_STRICT.
此函数将addr指向的地址添加到正在构造的路由头的末尾,并将此跃点的类型设置为标志值。对于IPv6类型0路由标头,标志必须是IPv6\u RTHDR\u LOOSE或IPv6\u RTHDR\u STRICT。
If successful, the cmsg_len member of the cmsghdr structure is updated to account for the new address in the Routing header and the return value of the function is 0. Upon an error the return value of the function is -1.
如果成功,将更新cmsghdr结构的cmsg_len成员,以说明路由标头中的新地址,并且函数的返回值为0。出现错误时,函数的返回值为-1。
int inet6_rthdr_lasthop(struct cmsghdr *cmsg, unsigned int flags);
int inet6_rthdr_lasthop(结构cmsghdr*cmsg,无符号int标志);
This function specifies the Strict/Loose flag for the final hop of a Routing header. For an IPv6 Type 0 Routing header, flags must be either IPV6_RTHDR_LOOSE or IPV6_RTHDR_STRICT.
此函数为路由标头的最后一个跃点指定严格/松散标志。对于IPv6类型0路由标头,标志必须是IPv6\u RTHDR\u LOOSE或IPv6\u RTHDR\u STRICT。
The return value of the function is 0 upon success, or -1 upon an error.
函数的返回值在成功时为0,或在错误时为-1。
Notice that a Routing header specifying N intermediate nodes requires N+1 Strict/Loose flags. This requires N calls to inet6_rthdr_add() followed by one call to inet6_rthdr_lasthop().
请注意,指定N个中间节点的路由标头需要N+1个严格/松散标志。这需要N次调用inet6\u rthdr\u add(),然后一次调用inet6\u rthdr\u lasthop()。
int inet6_rthdr_reverse(const struct cmsghdr *in, struct cmsghdr *out);
int inet6_rthdr_reverse(const struct cmsghdr *in, struct cmsghdr *out);
This function takes a Routing header that was received as ancillary data (pointed to by the first argument) and writes a new Routing header that sends datagrams along the reverse of that route. Both arguments are allowed to point to the same buffer (that is, the reversal can occur in place).
此函数接受作为辅助数据(由第一个参数指向)接收的路由标头,并写入一个新的路由标头,该标头沿该路由的相反方向发送数据报。这两个参数都可以指向同一个缓冲区(也就是说,反转可以就地发生)。
The return value of the function is 0 on success, or -1 upon an error.
函数的返回值在成功时为0,或在错误时为-1。
int inet6_rthdr_segments(const struct cmsghdr *cmsg);
int inet6_rthdr_segments(const struct cmsghdr *cmsg);
This function returns the number of segments (addresses) contained in the Routing header described by cmsg. On success the return value is between 1 and 23, inclusive. The return value of the function is -1 upon an error.
此函数返回cmsg描述的路由标头中包含的段数(地址)。成功时,返回值介于1和23之间(包括1和23)。出现错误时,函数的返回值为-1。
struct in6_addr *inet6_rthdr_getaddr(struct cmsghdr *cmsg, int index);
struct in6_addr *inet6_rthdr_getaddr(struct cmsghdr *cmsg, int index);
This function returns a pointer to the IPv6 address specified by index (which must have a value between 1 and the value returned by inet6_rthdr_segments()) in the Routing header described by cmsg. An application should first call inet6_rthdr_segments() to obtain the number of segments in the Routing header.
此函数返回一个指针,指向cmsg描述的路由标头中由索引指定的IPv6地址(其值必须介于1和inet6_rthdr_segments()返回的值之间)。应用程序应首先调用inet6_rthdr_segments(),以获取路由标头中的段数。
Upon an error the return value of the function is NULL.
出现错误时,函数的返回值为NULL。
int inet6_rthdr_getflags(const struct cmsghdr *cmsg, int index);
int inet6_rthdr_getflags(const struct cmsghdr *cmsg, int index);
This function returns the flags value specified by index (which must have a value between 0 and the value returned by inet6_rthdr_segments()) in the Routing header described by cmsg. For an IPv6 Type 0 Routing header the return value will be either IPV6_RTHDR_LOOSE or IPV6_RTHDR_STRICT.
此函数返回cmsg描述的路由标头中由索引指定的标志值(该值必须介于0和inet6_rthdr_segments()返回的值之间)。对于IPv6类型0路由标头,返回值将为IPv6\u RTHDR\u LOOSE或IPv6\u RTHDR\u STRICT。
Upon an error the return value of the function is -1.
出现错误时,函数的返回值为-1。
(Note: Addresses are indexed starting at 1, and flags starting at 0, to maintain consistency with the terminology and figures in [RFC-1883].)
(注:地址索引从1开始,标志索引从0开始,以保持与[RFC-1883]中的术语和数字的一致性。)
As an example of these Routing header functions, we go through the function calls for the example on p. 18 of [RFC-1883]. The source is S, the destination is D, and the three intermediate nodes are I1, I2, and I3. f0, f1, f2, and f3 are the Strict/Loose flags for each hop.
作为这些路由头函数的一个示例,我们将介绍p。[RFC-1883]第18条。源是S,目标是D,三个中间节点是I1、I2和I3。f0、f1、f2和f3是每个跃点的严格/松散标志。
f0 f1 f2 f3 S -----> I1 -----> I2 -----> I3 -----> D
f0 f1 f2 f3 S -----> I1 -----> I2 -----> I3 -----> D
src: * S S S S S dst: D I1 I2 I3 D D A[1]: I1 I2 I1 I1 I1 I1 A[2]: I2 I3 I3 I2 I2 I2 A[3]: I3 D D D I3 I3 #seg: 3 3 2 1 0 3
src: * S S S S S dst: D I1 I2 I3 D D A[1]: I1 I2 I1 I1 I1 I1 A[2]: I2 I3 I3 I2 I2 I2 A[3]: I3 D D D I3 I3 #seg: 3 3 2 1 0 3
check: f0 f1 f2 f3
检查:f0 f1 f2 f3
src and dst are the source and destination IPv6 addresses in the IPv6 header. A[1], A[2], and A[3] are the three addresses in the Routing header. #seg is the Segments Left field in the Routing header. check indicates which bit of the Strict/Loose Bit Map (0 through 3, specified as f0 through f3) that node checks.
src和dst是IPv6标头中的源和目标IPv6地址。A[1]、A[2]和A[3]是路由报头中的三个地址#seg是路由标头中的Segments Left字段。检查指示节点检查严格/松散位映射(0到3,指定为f0到f3)的哪个位。
The six values in the column beneath node S are the values in the Routing header specified by the application using sendmsg(). The function calls by the sender would look like:
节点S下列中的六个值是应用程序使用sendmsg()指定的路由标头中的值。发送方的函数调用如下所示:
void *ptr; struct msghdr msg; struct cmsghdr *cmsgptr; struct sockaddr_in6 I1, I2, I3, D; unsigned int f0, f1, f2, f3;
void *ptr; struct msghdr msg; struct cmsghdr *cmsgptr; struct sockaddr_in6 I1, I2, I3, D; unsigned int f0, f1, f2, f3;
ptr = malloc(inet6_rthdr_space(IPV6_RTHDR_TYPE_0, 3)); cmsgptr = inet6_rthdr_init(ptr, IPV6_RTHDR_TYPE_0);
ptr = malloc(inet6_rthdr_space(IPV6_RTHDR_TYPE_0, 3)); cmsgptr = inet6_rthdr_init(ptr, IPV6_RTHDR_TYPE_0);
inet6_rthdr_add(cmsgptr, &I1.sin6_addr, f0); inet6_rthdr_add(cmsgptr, &I2.sin6_addr, f1); inet6_rthdr_add(cmsgptr, &I3.sin6_addr, f2); inet6_rthdr_lasthop(cmsgptr, f3);
inet6_rthdr_add(cmsgptr, &I1.sin6_addr, f0); inet6_rthdr_add(cmsgptr, &I2.sin6_addr, f1); inet6_rthdr_add(cmsgptr, &I3.sin6_addr, f2); inet6_rthdr_lasthop(cmsgptr, f3);
msg.msg_control = ptr; msg.msg_controllen = cmsgptr->cmsg_len;
msg.msg_control = ptr; msg.msg_controllen = cmsgptr->cmsg_len;
/* finish filling in msg{}, msg_name = D */ /* call sendmsg() */
/* finish filling in msg{}, msg_name = D */ /* call sendmsg() */
We also assume that the source address for the socket is not specified (i.e., the asterisk in the figure).
我们还假设未指定套接字的源地址(即图中的星号)。
The four columns of six values that are then shown between the five nodes are the values of the fields in the packet while the packet is in transit between the two nodes. Notice that before the packet is sent by the source node S, the source address is chosen (replacing the asterisk), I1 becomes the destination address of the datagram, the two addresses A[2] and A[3] are "shifted up", and D is moved to A[3]. If f0 is IPV6_RTHDR_STRICT, then I1 must be a neighbor of S.
然后在五个节点之间显示的六个值的四列是数据包在两个节点之间传输时的字段值。注意,在源节点S发送分组之前,选择源地址(替换星号),I1成为数据报的目的地址,两个地址A[2]和A[3]被“上移”,并且D被移动到A[3]。如果f0是严格的IPV6,那么I1必须是S的邻居。
The columns of values that are shown beneath the destination node are the values returned by recvmsg(), assuming the application has enabled both the IPV6_PKTINFO and IPV6_RTHDR socket options. The source address is S (contained in the sockaddr_in6 structure pointed to by the msg_name member), the destination address is D (returned as an ancillary data object in an in6_pktinfo structure), and the ancillary data object specifying the Routing header will contain three addresses (I1, I2, and I3) and four flags (f0, f1, f2, and f3). The number of segments in the Routing header is known from the Hdr Ext Len field in the Routing header (a value of 6, indicating 3 addresses).
目标节点下方显示的值列是recvmsg()返回的值,假设应用程序同时启用了IPV6_PKTINFO和IPV6_RTHDR套接字选项。源地址是S(包含在msg_name成员指向的sockaddr_in6结构中),目标地址是D(作为in6_pktinfo结构中的辅助数据对象返回),指定路由头的辅助数据对象将包含三个地址(I1、I2和I3)和四个标志(f0、f1、f2和f3)。从路由头中的Hdr Ext Len字段可以知道路由头中的段数(值为6,表示3个地址)。
The return value from inet6_rthdr_segments() will be 3 and inet6_rthdr_getaddr(1) will return I1, inet6_rthdr_getaddr(2) will return I2, and inet6_rthdr_getaddr(3) will return I3, The return
inet6_rthdr_segments()的返回值将为3,inet6_rthdr_getaddr(1)将返回I1,inet6_rthdr_getaddr(2)将返回I2,inet6_rthdr_getaddr(3)将返回I3,即返回值
value from inet6_rthdr_flags(0) will be f0, inet6_rthdr_flags(1) will return f1, inet6_rthdr_flags(2) will return f2, and inet6_rthdr_flags(3) will return f3.
inet6_rthdr_标志(0)的值将为f0,inet6_rthdr_标志(1)将返回f1,inet6_rthdr_标志(2)将返回f2,inet6_rthdr_标志(3)将返回f3。
If the receiving application then calls inet6_rthdr_reverse(), the order of the three addresses will become I3, I2, and I1, and the order of the four Strict/Loose flags will become f3, f2, f1, and f0.
如果接收应用程序随后调用inet6_rthdr_reverse(),则三个地址的顺序将变为I3、I2和I1,四个严格/松散标志的顺序将变为f3、f2、f1和f0。
We can also show what an implementation might store in the ancillary data object as the Routing header is being built by the sending process. If we assume a 32-bit architecture where sizeof(struct cmsghdr) equals 12, with a desired alignment of 4-byte boundaries, then the call to inet6_rthdr_space(3) returns 68: 12 bytes for the cmsghdr structure and 56 bytes for the Routing header (8 + 3*16).
我们还可以展示当发送进程正在构建路由头时,实现可能在辅助数据对象中存储的内容。如果我们假设一个32位的体系结构,其中sizeof(struct cmsghdr)等于12,并且需要4字节边界对齐,那么对inet6_rthdr_空间(3)的调用返回68:12字节用于cmsghdr结构,56字节用于路由头(8+3*16)。
The call to inet6_rthdr_init() initializes the ancillary data object to contain a Type 0 Routing header:
对inet6_rthdr_init()的调用初始化辅助数据对象以包含类型0路由头:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 20 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_RTHDR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=0 | Routing Type=0| Seg Left=0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved | Strict/Loose Bit Map | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 20 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_RTHDR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=0 | Routing Type=0| Seg Left=0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved | Strict/Loose Bit Map | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The first call to inet6_rthdr_add() adds I1 to the list.
对inet6\u rthdr\u add()的第一个调用将I1添加到列表中。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 36 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_RTHDR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=2 | Routing Type=0| Seg Left=1 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved |X| Strict/Loose Bit Map | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[1] = I1 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 36 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_RTHDR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=2 | Routing Type=0| Seg Left=1 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved |X| Strict/Loose Bit Map | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[1] = I1 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Bit 0 of the Strict/Loose Bit Map contains the value f0, which we just mark as X. cmsg_len is incremented by 16, the Hdr Ext Len field is incremented by 2, and the Segments Left field is incremented by 1.
严格/松散位图的位0包含值f0,我们只是将其标记为X。cmsg_len递增16,Hdr Ext len字段递增2,Segments Left字段递增1。
The next call to inet6_rthdr_add() adds I2 to the list.
对inet6\u rthdr\u add()的下一个调用将I2添加到列表中。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 52 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_RTHDR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=4 | Routing Type=0| Seg Left=2 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved |X|X| Strict/Loose Bit Map | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[1] = I1 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[2] = I2 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 52 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_RTHDR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=4 | Routing Type=0| Seg Left=2 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved |X|X| Strict/Loose Bit Map | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[1] = I1 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[2] = I2 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The next bit of the Strict/Loose Bit Map contains the value f1. cmsg_len is incremented by 16, the Hdr Ext Len field is incremented by 2, and the Segments Left field is incremented by 1.
严格/松散位图的下一位包含值f1。cmsg_len增加16,Hdr Ext len字段增加2,Segments Left字段增加1。
The last call to inet6_rthdr_add() adds I3 to the list.
最后一次调用inet6\u rthdr\u add()将I3添加到列表中。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 68 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_RTHDR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=6 | Routing Type=0| Seg Left=3 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved |X|X|X| Strict/Loose Bit Map | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[1] = I1 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[2] = I2 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[3] = I3 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_len = 68 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_level = IPPROTO_IPV6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cmsg_type = IPV6_RTHDR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len=6 | Routing Type=0| Seg Left=3 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved |X|X|X| Strict/Loose Bit Map | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[1] = I1 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[2] = I2 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Address[3] = I3 + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The next bit of the Strict/Loose Bit Map contains the value f2. cmsg_len is incremented by 16, the Hdr Ext Len field is incremented by 2, and the Segments Left field is incremented by 1.
严格/松散位图的下一位包含值f2。cmsg_len增加16,Hdr Ext len字段增加2,Segments Left字段增加1。
Finally, the call to inet6_rthdr_lasthop() sets the next bit of the Strict/Loose Bit Map to the value specified by f3. All the lengths remain unchanged.
最后,调用inet6_rthdr_lasthop()将严格/松散位映射的下一位设置为f3指定的值。所有长度保持不变。
Three IPv6 extension headers can be specified by the application and returned to the application using ancillary data with sendmsg() and recvmsg(): Hop-by-Hop options, Destination options, and the Routing header. When multiple ancillary data objects are transferred via sendmsg() or recvmsg() and these objects represent any of these three extension headers, their placement in the control buffer is directly tied to their location in the corresponding IPv6 datagram. This API imposes some ordering constraints when using multiple ancillary data objects with sendmsg().
应用程序可以指定三个IPv6扩展头,并使用sendmsg()和recvmsg()的辅助数据将其返回给应用程序:逐跳选项、目标选项和路由头。当多个辅助数据对象通过sendmsg()或recvmsg()传输,并且这些对象表示这三个扩展头中的任何一个时,它们在控制缓冲区中的位置将直接绑定到它们在相应IPv6数据报中的位置。当将多个辅助数据对象与sendmsg()一起使用时,此API施加了一些排序约束。
When multiple IPv6 Hop-by-Hop options having the same option type are specified, these options will be inserted into the Hop-by-Hop options header in the same order as they appear in the control buffer. But when multiple Hop-by-Hop options having different option types are specified, these options may be reordered by the kernel to reduce padding in the Hop-by-Hop options header. Hop-by-Hop options may appear anywhere in the control buffer and will always be collected by the kernel and placed into a single Hop-by-Hop options header that immediately follows the IPv6 header.
当指定具有相同选项类型的多个IPv6逐跳选项时,这些选项将以与它们在控制缓冲区中显示的相同顺序插入到逐跳选项标头中。但是,当指定了具有不同选项类型的多个逐跳选项时,内核可能会对这些选项重新排序,以减少逐跳选项标头中的填充。逐跳选项可能出现在控制缓冲区中的任何位置,并且总是由内核收集并放入紧跟IPv6标头之后的单个逐跳选项标头中。
Similar rules apply to the Destination options: (1) those of the same type will appear in the same order as they are specified, and (2) those of differing types may be reordered. But the kernel will build up to two Destination options headers: one to precede the Routing header and one to follow the Routing header. If the application specifies a Routing header then all Destination options that appear in the control buffer before the Routing header will appear in a Destination options header before the Routing header and these options might be reordered, subject to the two rules that we just stated. Similarly all Destination options that appear in the control buffer after the Routing header will appear in a Destination options header after the Routing header, and these options might be reordered, subject to the two rules that we just stated.
类似的规则适用于目标选项:(1)相同类型的选项将按指定的顺序显示,(2)不同类型的选项可能会重新排序。但是内核将构建多达两个目的地选项头:一个位于路由头之前,另一个位于路由头之后。如果应用程序指定了一个路由头,那么在路由头之前的控制缓冲区中出现的所有目标选项都将出现在路由头之前的目标选项头中,并且这些选项可能会被重新排序,这取决于我们刚才提到的两条规则。类似地,在路由头之后出现在控制缓冲区中的所有目标选项都将出现在路由头之后的目标选项头中,并且这些选项可能会重新排序,这取决于我们刚才提到的两个规则。
As an example, assume that an application specifies control information to sendmsg() containing six ancillary data objects: the first containing two Hop-by-Hop options, the second containing one Destination option, the third containing two Destination options, the fourth containing a Routing header, the fifth containing a Hop-by-Hop option, and the sixth containing two Destination options. We also assume that all the Hop-by-Hop options are of different types, as are all the Destination options. We number these options 1-9, corresponding to their order in the control buffer, and show them on the left below.
例如,假设应用程序将控制信息指定给sendmsg(),其中包含六个辅助数据对象:第一个包含两个逐跳选项,第二个包含一个目标选项,第三个包含两个目标选项,第四个包含路由标头,第五个包含逐跳选项,第六个包含两个目的地选项。我们还假设所有逐跳选项都是不同类型的,就像所有的目标选项一样。我们将这些选项编号为1-9,对应于它们在控制缓冲区中的顺序,并在下面的左侧显示它们。
In the middle we show the final arrangement of the options in the extension headers built by the kernel. On the right we show the four ancillary data objects returned to the receiving application.
在中间,我们展示了由内核构建的扩展头中的选项的最终排列。在右侧,我们显示了返回到接收应用程序的四个辅助数据对象。
Sender's Receiver's Ancillary Data --> IPv6 Extension --> Ancillary Data Objects Headers Objects ------------------ --------------- -------------- HOPOPT-1,2 (first) HOPHDR(J,7,1,2) HOPOPT-7,1,2 DSTOPT-3 DSTHDR(4,5,3) DSTOPT-4,5,3 DSTOPT-4,5 RTHDR(6) RTHDR-6 RTHDR-6 DSTHDR(8,9) DSTOPT-8,9 HOPOPT-7 DSTOPT-8,9 (last)
Sender's Receiver's Ancillary Data --> IPv6 Extension --> Ancillary Data Objects Headers Objects ------------------ --------------- -------------- HOPOPT-1,2 (first) HOPHDR(J,7,1,2) HOPOPT-7,1,2 DSTOPT-3 DSTHDR(4,5,3) DSTOPT-4,5,3 DSTOPT-4,5 RTHDR(6) RTHDR-6 RTHDR-6 DSTHDR(8,9) DSTOPT-8,9 HOPOPT-7 DSTOPT-8,9 (last)
The sender's two Hop-by-Hop ancillary data objects are reordered, as are the first two Destination ancillary data objects. We also show a Jumbo Payload option (denoted as J) inserted by the kernel before the sender's three Hop-by-Hop options. The first three Destination options must appear in a Destination header before the Routing header, and the final two Destination options must appear in a Destination header after the Routing header.
发送方的两个逐跳辅助数据对象被重新排序,前两个目标辅助数据对象也是如此。我们还显示了内核在发送方的三个逐跳选项之前插入的一个巨型有效负载选项(表示为J)。前三个目的地选项必须出现在路由标头之前的目的地标头中,最后两个目的地选项必须出现在路由标头之后的目的地标头中。
If Destination options are specified in the control buffer after a Routing header, or if Destination options are specified without a Routing header, the kernel will place those Destination options after an authentication header and/or an encapsulating security payload header, if present.
如果在控制缓冲区中的路由头之后指定了目标选项,或者如果在没有路由头的情况下指定了目标选项,那么内核将把这些目标选项放在身份验证头和/或封装安全负载头(如果存在)之后。
The various socket options and ancillary data specifications defined in this document apply only to true IPv6 sockets. It is possible to create an IPv6 socket that actually sends and receives IPv4 packets, using IPv4-mapped IPv6 addresses, but the mapping of the options defined in this document to an IPv4 datagram is beyond the scope of this document.
本文档中定义的各种套接字选项和辅助数据规范仅适用于真正的IPv6套接字。可以使用IPv4映射的IPv6地址创建实际发送和接收IPv4数据包的IPv6套接字,但本文档中定义的选项到IPv4数据报的映射超出了本文档的范围。
In general, attempting to specify an IPv6-only option, such as the Hop-by-Hop options, Destination options, or Routing header on an IPv6 socket that is using IPv4-mapped IPv6 addresses, will probably result in an error. Some implementations, however, may provide access to the packet information (source/destination address, send/receive interface, and hop limit) on an IPv6 socket that is using IPv4-mapped IPv6 addresses.
通常,尝试在使用IPv4映射IPv6地址的IPv6套接字上指定仅限IPv6的选项(例如逐跳选项、目标选项或路由标头)可能会导致错误。然而,一些实现可能提供对使用IPv4映射IPv6地址的IPv6套接字上的数据包信息(源/目标地址、发送/接收接口和跃点限制)的访问。
The rresvport() function is used by the rcmd() function, and this function is in turn called by many of the "r" commands such as rlogin. While new applications are not being written to use the rcmd() function, legacy applications such as rlogin will continue to use it and these will be ported to IPv6.
rcmd()函数使用rresvport()函数,许多“r”命令(如rlogin)依次调用该函数。虽然新的应用程序没有编写为使用rcmd()函数,但传统应用程序(如rlogin)将继续使用它,并将这些应用程序移植到IPv6。
rresvport() creates an IPv4/TCP socket and binds a "reserved port" to the socket. Instead of defining an IPv6 version of this function we define a new function that takes an address family as its argument.
rresvport()创建IPv4/TCP套接字并将“保留端口”绑定到该套接字。我们没有定义此函数的IPv6版本,而是定义了一个新函数,该函数将地址族作为其参数。
#include <unistd.h>
#include <unistd.h>
int rresvport_af(int *port, int family);
int rresvport_af(int *port, int family);
This function behaves the same as the existing rresvport() function, but instead of creating an IPv4/TCP socket, it can also create an IPv6/TCP socket. The family argument is either AF_INET or AF_INET6, and a new error return is EAFNOSUPPORT if the address family is not supported.
此函数的行为与现有的rresvport()函数相同,但它不创建IPv4/TCP套接字,还可以创建IPv6/TCP套接字。family参数为AF_INET或AF_INET6,如果不支持地址族,则新的错误返回为EAFNOSUPPORT。
(Note: There is little consensus on which header defines the rresvport() and rcmd() function prototypes. 4.4BSD defines it in <unistd.h>, others in <netdb.h>, and others don't define the function prototypes at all.)
(注意:对于哪个头定义了rresvport()和rcmd()函数原型,几乎没有共识。4.4BSD在<unistd.h>中定义了它,其他头在<netdb.h>中定义了它,而其他头根本不定义函数原型。)
(Note: We define this function only, and do not define something like rcmd_af() or rcmd6(). The reason is that rcmd() calls gethostbyname(), which returns the type of address: AF_INET or AF_INET6. It should therefore be possible to modify rcmd() to support either IPv4 or IPv6, based on the address family returned by gethostbyname().)
(注意:我们仅定义此函数,不定义类似于rcmd_af()或rcmd6()的内容。原因是rcmd()调用gethostbyname(),后者返回地址类型:af_INET或af_INET6。因此,根据gethostbyname()返回的地址族,应该可以修改rcmd()以支持IPv4或IPv6。)
Some additional items may require standardization, but no concrete proposals have been made for the API to perform these tasks. These may be addressed in a later document.
一些附加项目可能需要标准化,但尚未就API执行这些任务提出具体建议。这些问题可在以后的文件中解决。
Earlier revisions of this document specified a set of inet6_flow_XXX() functions to assign, share, and free IPv6 flow labels. Consensus, however, indicated that it was premature to specify this part of the API.
本文档的早期版本指定了一组inet6_flow_XXX()函数来分配、共享和释放IPv6流标签。然而,一致意见表明,指定API的这一部分为时过早。
A standard method may be desirable for a UDP application to determine the "maximum send transport-message size" (Section 5.1 of [RFC-1981]) to a given destination. This would let the UDP application send smaller datagrams to the destination, avoiding fragmentation.
UDP应用程序可能需要一种标准方法来确定到给定目的地的“最大发送传输消息大小”(RFC-1981第5.1节)。这将允许UDP应用程序向目标发送较小的数据报,从而避免碎片。
A standard method may be desirable for a UDP application to tell the kernel that it is making forward progress with a given peer (Section 7.3.1 of [RFC-1970]). This could save unneeded neighbor solicitations and neighbor advertisements.
UDP应用程序可能需要一种标准方法来告诉内核它正在与给定的对等机进行转发(RFC-1970的第7.3.1节)。这可以节省不必要的邻居邀请和邻居广告。
The following list summarizes the constants and structure, definitions discussed in this memo, sorted by header.
以下列表总结了本备忘录中讨论的常量和结构、定义,并按标题排序。
<netinet/icmp6.h> ICMP6_DST_UNREACH <netinet/icmp6.h> ICMP6_DST_UNREACH_ADDR <netinet/icmp6.h> ICMP6_DST_UNREACH_ADMIN <netinet/icmp6.h> ICMP6_DST_UNREACH_NOPORT <netinet/icmp6.h> ICMP6_DST_UNREACH_NOROUTE <netinet/icmp6.h> ICMP6_DST_UNREACH_NOTNEIGHBOR <netinet/icmp6.h> ICMP6_ECHO_REPLY <netinet/icmp6.h> ICMP6_ECHO_REQUEST <netinet/icmp6.h> ICMP6_INFOMSG_MASK <netinet/icmp6.h> ICMP6_MEMBERSHIP_QUERY <netinet/icmp6.h> ICMP6_MEMBERSHIP_REDUCTION <netinet/icmp6.h> ICMP6_MEMBERSHIP_REPORT <netinet/icmp6.h> ICMP6_PACKET_TOO_BIG <netinet/icmp6.h> ICMP6_PARAMPROB_HEADER <netinet/icmp6.h> ICMP6_PARAMPROB_NEXTHEADER <netinet/icmp6.h> ICMP6_PARAMPROB_OPTION <netinet/icmp6.h> ICMP6_PARAM_PROB <netinet/icmp6.h> ICMP6_TIME_EXCEEDED <netinet/icmp6.h> ICMP6_TIME_EXCEED_REASSEMBLY <netinet/icmp6.h> ICMP6_TIME_EXCEED_TRANSIT <netinet/icmp6.h> ND_NA_FLAG_OVERRIDE <netinet/icmp6.h> ND_NA_FLAG_ROUTER <netinet/icmp6.h> ND_NA_FLAG_SOLICITED <netinet/icmp6.h> ND_NEIGHBOR_ADVERT <netinet/icmp6.h> ND_NEIGHBOR_SOLICIT <netinet/icmp6.h> ND_OPT_MTU <netinet/icmp6.h> ND_OPT_PI_FLAG_AUTO <netinet/icmp6.h> ND_OPT_PI_FLAG_ONLINK <netinet/icmp6.h> ND_OPT_PREFIX_INFORMATION
<netinet/icmp6.h> ICMP6_DST_UNREACH <netinet/icmp6.h> ICMP6_DST_UNREACH_ADDR <netinet/icmp6.h> ICMP6_DST_UNREACH_ADMIN <netinet/icmp6.h> ICMP6_DST_UNREACH_NOPORT <netinet/icmp6.h> ICMP6_DST_UNREACH_NOROUTE <netinet/icmp6.h> ICMP6_DST_UNREACH_NOTNEIGHBOR <netinet/icmp6.h> ICMP6_ECHO_REPLY <netinet/icmp6.h> ICMP6_ECHO_REQUEST <netinet/icmp6.h> ICMP6_INFOMSG_MASK <netinet/icmp6.h> ICMP6_MEMBERSHIP_QUERY <netinet/icmp6.h> ICMP6_MEMBERSHIP_REDUCTION <netinet/icmp6.h> ICMP6_MEMBERSHIP_REPORT <netinet/icmp6.h> ICMP6_PACKET_TOO_BIG <netinet/icmp6.h> ICMP6_PARAMPROB_HEADER <netinet/icmp6.h> ICMP6_PARAMPROB_NEXTHEADER <netinet/icmp6.h> ICMP6_PARAMPROB_OPTION <netinet/icmp6.h> ICMP6_PARAM_PROB <netinet/icmp6.h> ICMP6_TIME_EXCEEDED <netinet/icmp6.h> ICMP6_TIME_EXCEED_REASSEMBLY <netinet/icmp6.h> ICMP6_TIME_EXCEED_TRANSIT <netinet/icmp6.h> ND_NA_FLAG_OVERRIDE <netinet/icmp6.h> ND_NA_FLAG_ROUTER <netinet/icmp6.h> ND_NA_FLAG_SOLICITED <netinet/icmp6.h> ND_NEIGHBOR_ADVERT <netinet/icmp6.h> ND_NEIGHBOR_SOLICIT <netinet/icmp6.h> ND_OPT_MTU <netinet/icmp6.h> ND_OPT_PI_FLAG_AUTO <netinet/icmp6.h> ND_OPT_PI_FLAG_ONLINK <netinet/icmp6.h> ND_OPT_PREFIX_INFORMATION
<netinet/icmp6.h> ND_OPT_REDIRECTED_HEADER <netinet/icmp6.h> ND_OPT_SOURCE_LINKADDR <netinet/icmp6.h> ND_OPT_TARGET_LINKADDR <netinet/icmp6.h> ND_RA_FLAG_MANAGED <netinet/icmp6.h> ND_RA_FLAG_OTHER <netinet/icmp6.h> ND_REDIRECT <netinet/icmp6.h> ND_ROUTER_ADVERT <netinet/icmp6.h> ND_ROUTER_SOLICIT
<netinet/icmp6.h> ND_OPT_REDIRECTED_HEADER <netinet/icmp6.h> ND_OPT_SOURCE_LINKADDR <netinet/icmp6.h> ND_OPT_TARGET_LINKADDR <netinet/icmp6.h> ND_RA_FLAG_MANAGED <netinet/icmp6.h> ND_RA_FLAG_OTHER <netinet/icmp6.h> ND_REDIRECT <netinet/icmp6.h> ND_ROUTER_ADVERT <netinet/icmp6.h> ND_ROUTER_SOLICIT
<netinet/icmp6.h> struct icmp6_filter{}; <netinet/icmp6.h> struct icmp6_hdr{}; <netinet/icmp6.h> struct nd_neighbor_advert{}; <netinet/icmp6.h> struct nd_neighbor_solicit{}; <netinet/icmp6.h> struct nd_opt_hdr{}; <netinet/icmp6.h> struct nd_opt_mtu{}; <netinet/icmp6.h> struct nd_opt_prefix_info{}; <netinet/icmp6.h> struct nd_opt_rd_hdr{}; <netinet/icmp6.h> struct nd_redirect{}; <netinet/icmp6.h> struct nd_router_advert{}; <netinet/icmp6.h> struct nd_router_solicit{};
<netinet/icmp6.h> struct icmp6_filter{}; <netinet/icmp6.h> struct icmp6_hdr{}; <netinet/icmp6.h> struct nd_neighbor_advert{}; <netinet/icmp6.h> struct nd_neighbor_solicit{}; <netinet/icmp6.h> struct nd_opt_hdr{}; <netinet/icmp6.h> struct nd_opt_mtu{}; <netinet/icmp6.h> struct nd_opt_prefix_info{}; <netinet/icmp6.h> struct nd_opt_rd_hdr{}; <netinet/icmp6.h> struct nd_redirect{}; <netinet/icmp6.h> struct nd_router_advert{}; <netinet/icmp6.h> struct nd_router_solicit{};
<netinet/in.h> IPPROTO_AH <netinet/in.h> IPPROTO_DSTOPTS <netinet/in.h> IPPROTO_ESP <netinet/in.h> IPPROTO_FRAGMENT <netinet/in.h> IPPROTO_HOPOPTS <netinet/in.h> IPPROTO_ICMPV6 <netinet/in.h> IPPROTO_IPV6 <netinet/in.h> IPPROTO_NONE <netinet/in.h> IPPROTO_ROUTING <netinet/in.h> IPV6_DSTOPTS <netinet/in.h> IPV6_HOPLIMIT <netinet/in.h> IPV6_HOPOPTS <netinet/in.h> IPV6_NEXTHOP <netinet/in.h> IPV6_PKTINFO <netinet/in.h> IPV6_PKTOPTIONS <netinet/in.h> IPV6_RTHDR <netinet/in.h> IPV6_RTHDR_LOOSE <netinet/in.h> IPV6_RTHDR_STRICT <netinet/in.h> IPV6_RTHDR_TYPE_0 <netinet/in.h> struct in6_pktinfo{};
<netinet/in.h> IPPROTO_AH <netinet/in.h> IPPROTO_DSTOPTS <netinet/in.h> IPPROTO_ESP <netinet/in.h> IPPROTO_FRAGMENT <netinet/in.h> IPPROTO_HOPOPTS <netinet/in.h> IPPROTO_ICMPV6 <netinet/in.h> IPPROTO_IPV6 <netinet/in.h> IPPROTO_NONE <netinet/in.h> IPPROTO_ROUTING <netinet/in.h> IPV6_DSTOPTS <netinet/in.h> IPV6_HOPLIMIT <netinet/in.h> IPV6_HOPOPTS <netinet/in.h> IPV6_NEXTHOP <netinet/in.h> IPV6_PKTINFO <netinet/in.h> IPV6_PKTOPTIONS <netinet/in.h> IPV6_RTHDR <netinet/in.h> IPV6_RTHDR_LOOSE <netinet/in.h> IPV6_RTHDR_STRICT <netinet/in.h> IPV6_RTHDR_TYPE_0 <netinet/in.h> struct in6_pktinfo{};
<netinet/ip6.h> IP6F_OFF_MASK <netinet/ip6.h> IP6F_RESERVED_MASK <netinet/ip6.h> IP6F_MORE_FRAG <netinet/ip6.h> struct ip6_dest{}; <netinet/ip6.h> struct ip6_frag{}; <netinet/ip6.h> struct ip6_hbh{};
<netinet/ip6.h> IP6F_OFF_MASK <netinet/ip6.h> IP6F_RESERVED_MASK <netinet/ip6.h> IP6F_MORE_FRAG <netinet/ip6.h> struct ip6_dest{}; <netinet/ip6.h> struct ip6_frag{}; <netinet/ip6.h> struct ip6_hbh{};
<netinet/ip6.h> struct ip6_hdr{}; <netinet/ip6.h> struct ip6_rthdr{}; <netinet/ip6.h> struct ip6_rthdr0{};
<netinet/ip6.h> struct ip6_hdr{}; <netinet/ip6.h> struct ip6_rthdr{}; <netinet/ip6.h> struct ip6_rthdr0{};
<sys/socket.h> struct cmsghdr{}; <sys/socket.h> struct msghdr{};
<sys/socket.h> struct cmsghdr{}; <sys/socket.h> struct msghdr{};
The following list summarizes the function and macro prototypes discussed in this memo, sorted by header.
下表总结了本备忘录中讨论的功能和宏原型,按标题排序。
<netinet/icmp6.h> void ICMP6_FILTER_SETBLOCK(int, struct icmp6_filter *); <netinet/icmp6.h> void ICMP6_FILTER_SETBLOCKALL(struct icmp6_filter *); <netinet/icmp6.h> void ICMP6_FILTER_SETPASS(int, struct icmp6_filter *); <netinet/icmp6.h> void ICMP6_FILTER_SETPASSALL(struct icmp6_filter *); <netinet/icmp6.h> int ICMP6_FILTER_WILLBLOCK(int, const struct icmp6_filter *); <netinet/icmp6.h> int ICMP6_FILTER_WILLPASS(int, const struct icmp6_filter *);
<netinet/icmp6.h> void ICMP6_FILTER_SETBLOCK(int, struct icmp6_filter *); <netinet/icmp6.h> void ICMP6_FILTER_SETBLOCKALL(struct icmp6_filter *); <netinet/icmp6.h> void ICMP6_FILTER_SETPASS(int, struct icmp6_filter *); <netinet/icmp6.h> void ICMP6_FILTER_SETPASSALL(struct icmp6_filter *); <netinet/icmp6.h> int ICMP6_FILTER_WILLBLOCK(int, const struct icmp6_filter *); <netinet/icmp6.h> int ICMP6_FILTER_WILLPASS(int, const struct icmp6_filter *);
<netinet/in.h> int IN6_ARE_ADDR_EQUAL(const struct in6_addr *, const struct in6_addr *);
<netinet/in.h> int IN6_ARE_ADDR_EQUAL(const struct in6_addr *, const struct in6_addr *);
<netinet/in.h> uint8_t *inet6_option_alloc(struct cmsghdr *, int, int, int); <netinet/in.h> int inet6_option_append(struct cmsghdr *, const uint8_t *, int, int); <netinet/in.h> int inet6_option_find(const struct cmsghdr *, uint8_t *, int); <netinet/in.h> int inet6_option_init(void *, struct cmsghdr **, int); <netinet/in.h> int inet6_option_next(const struct cmsghdr *, uint8_t **); <netinet/in.h> int inet6_option_space(int);
<netinet/in.h> uint8_t *inet6_option_alloc(struct cmsghdr *, int, int, int); <netinet/in.h> int inet6_option_append(struct cmsghdr *, const uint8_t *, int, int); <netinet/in.h> int inet6_option_find(const struct cmsghdr *, uint8_t *, int); <netinet/in.h> int inet6_option_init(void *, struct cmsghdr **, int); <netinet/in.h> int inet6_option_next(const struct cmsghdr *, uint8_t **); <netinet/in.h> int inet6_option_space(int);
<netinet/in.h> int inet6_rthdr_add(struct cmsghdr *, const struct in6_addr *, unsigned int); <netinet/in.h> struct in6_addr inet6_rthdr_getaddr(struct cmsghdr *, int); <netinet/in.h> int inet6_rthdr_getflags(const struct cmsghdr *, int); <netinet/in.h> struct cmsghdr *inet6_rthdr_init(void *, int); <netinet/in.h> int inet6_rthdr_lasthop(struct cmsghdr *, unsigned int); <netinet/in.h> int inet6_rthdr_reverse(const struct cmsghdr *, struct cmsghdr *); <netinet/in.h> int inet6_rthdr_segments(const struct cmsghdr *); <netinet/in.h> size_t inet6_rthdr_space(int, int);
<netinet/in.h> int inet6_rthdr_add(struct cmsghdr *, const struct in6_addr *, unsigned int); <netinet/in.h> struct in6_addr inet6_rthdr_getaddr(struct cmsghdr *, int); <netinet/in.h> int inet6_rthdr_getflags(const struct cmsghdr *, int); <netinet/in.h> struct cmsghdr *inet6_rthdr_init(void *, int); <netinet/in.h> int inet6_rthdr_lasthop(struct cmsghdr *, unsigned int); <netinet/in.h> int inet6_rthdr_reverse(const struct cmsghdr *, struct cmsghdr *); <netinet/in.h> int inet6_rthdr_segments(const struct cmsghdr *); <netinet/in.h> size_t inet6_rthdr_space(int, int);
<sys/socket.h> unsigned char *CMSG_DATA(const struct cmsghdr *); <sys/socket.h> struct cmsghdr *CMSG_FIRSTHDR(const struct msghdr *); <sys/socket.h> unsigned int CMSG_LEN(unsigned int); <sys/socket.h> struct cmsghdr *CMSG_NXTHDR(const struct msghdr *mhdr, const struct cmsghdr *); <sys/socket.h> unsigned int CMSG_SPACE(unsigned int);
<sys/socket.h> unsigned char *CMSG_DATA(const struct cmsghdr *); <sys/socket.h> struct cmsghdr *CMSG_FIRSTHDR(const struct msghdr *); <sys/socket.h> unsigned int CMSG_LEN(unsigned int); <sys/socket.h> struct cmsghdr *CMSG_NXTHDR(const struct msghdr *mhdr, const struct cmsghdr *); <sys/socket.h> unsigned int CMSG_SPACE(unsigned int);
<unistd.h> int rresvport_af(int *, int);
<unistd.h> int rresvport_af(int *, int);
The setting of certain Hop-by-Hop options and Destination options may be restricted to privileged processes. Similarly some Hop-by-Hop options and Destination options may not be returned to nonprivileged applications.
某些逐跳选项和目标选项的设置可能仅限于特权进程。类似地,某些逐跳选项和目标选项可能不会返回给非特权应用程序。
Changes from the June 1997 Edition (-03 draft)
1997年6月版的变更(-03草案)
- Added a note that defined constants for multibyte fields are in network byte order. This affects the ip6f_offlg member of the Fragment header (Section 2.1.2) and the nd_na_flags_reserved member of the nd_neighbor_advert structure (Section 2.2.2).
- 添加了一个注释,说明多字节字段的定义常量是按网络字节顺序排列的。这会影响片段头(第2.1.2节)的ip6f_offlg成员和nd_邻居广告结构(第2.2.2节)的nd_Nau flags_保留成员。
- Section 5: the ipi6_ifindex member of the in6_pktinfo structure should be "unsigned int" instead of "int", for consistency with the interface indexes in [RFC-2133].
- 第5节:in6_pktinfo结构的ipi6_iIndex成员应为“unsigned int”而不是“int”,以与[RFC-2133]中的接口索引保持一致。
- Section 6.3.7: the three calls to inet6_option_space() in the examples needed to be arguments to malloc(). The final one of these was missing the "6" in the name "inet6_option_space".
- 第6.3.7节:示例中对inet6_option_space()的三个调用需要是malloc()的参数。最后一个选项是在名称“inet6\u option\u space”中缺少“6”。
- Section 8.6: the function prototype for inet6_rthdr_segments() was missing the ending semicolon.
- 第8.6节:inet6_rthdr_segments()的函数原型缺少结尾分号。
Changes from the March 1997 Edition (-02 draft)
1997年3月版的更改(-02草稿)
- In May 1997 Draft 6.6 of Posix 1003.1g (called Posix.1g herein) passed ballot and will be forwarded to the IEEE Standards Board later in 1997 for final approval. Some changes made for this final Posix draft are incorporated into this Internet Draft, specifically the datatypes mentioned in Section 1 (and used throughout the text), and the socklen_t datatype used in Section 4.1 and 4.2.
- 1997年5月,Posix 1003.1g草案6.6(此处称为Posix.1g)通过投票,并将于1997年晚些时候提交IEEE标准委员会进行最终批准。为Posix最终草案所做的一些更改被纳入到互联网草案中,特别是第1节中提到的数据类型(并在全文中使用),以及第4.1节和第4.2节中使用的socklen_t数据类型。
- Section 1: Added the intN_t signed datatypes, changed the datatype u_intN_t to uintN_t (no underscore after the "u"), and
- 第1节:添加intN_t签名数据类型,将数据类型u_intN_t更改为uintN_t(在“u”之后没有下划线),以及
removed the datatype u_intNm_t, as per Draft 6.6 of Posix.1g.
根据Posix.1g草案6.6,删除了数据类型u_intNm_t。
- Name space issues for structure and constant names in Section 2: Many of the structure member names and constant names were changed so that the prefixes are the same. The following prefixes are used for structure members: "ip6_", "icmp6_", and "nd_". All constants have the prefixes "ICMP6_" and "ND_".
- 第2节中的结构和常量名称的名称空间问题:许多结构成员名称和常量名称已更改,因此前缀相同。以下前缀用于结构成员:“ip6_339;”、“icmp6_339;”和“nd_339;”。所有常量的前缀都是“ICMP6_u3;”和“ND_3;”。
- New definitions: Section 2.1.2: contains definitions for the IPv6 extension headers, other than AH and ESP. Section 2.2.2: contains additional structures and constants for the neighbor discovery option header and redirected header.
- 新定义:第2.1.2节:包含除AH和ESP之外的IPv6扩展标头的定义。第2.2.2节:包含邻居发现选项标头和重定向标头的其他结构和常量。
- Section 2.2.2: the enum for the neighbor discovery option field was changed to be a set of #define constants.
- 第2.2.2节:邻居发现选项字段的枚举已更改为一组#定义常量。
- Changed the word "function" to "macro" for references to all the uppercase names in Sections 2.3 (IN6_ARE_ADDR_EQUAL), 3.2 (ICMPV6_FILTER_xxx), and 4.3 (CMSG_xxx).
- 将第2.3节(IN6_等于ADDR_)、第3.2节(ICMPV6_过滤器_xxx)和第4.3节(CMSG_xxx)中所有大写名称的引用词“function”改为“macro”。
- Added more protocols to the /etc/protocols file (Section 2.4) and changed the name of "icmpv6" to "ipv6-icmp".
- 在/etc/protocols文件(第2.4节)中添加了更多协议,并将“icmpv6”的名称更改为“ipv6 icmp”。
- Section 3: Made it more explicit that an application cannot read or write entire IPv6 packets, that all extension headers are passed as ancillary data. Added a sentence that the kernel fragments packets written to an IPv6 raw socket when necessary. Added a note that IPPROTO_RAW raw IPv6 sockets are not special.
- 第3节:更加明确了应用程序不能读取或写入整个IPv6数据包,所有扩展头都作为辅助数据传递。添加了一句话,内核在必要时对写入IPv6原始套接字的数据包进行分段。添加了一个注意事项,即IPPROTO_原始IPv6套接字并不特殊。
- Section 3.1: Explicitly stated that the checksum option applies to both outgoing packets and received packets.
- 第3.1节:明确说明校验和选项适用于传出数据包和接收数据包。
- Section 3.2: Changed the array name within the icmp6_filter structure from "data" to "icmp6_filt". Changes the prefix for the filter macros from "ICMPV6_" to "ICMP6_", for consistency with the names in Section 2.2. Changed the example from a ping program to a program that wants to receive only router advertisements.
- 第3.2节:将icmp6_筛选器结构中的数组名称从“数据”更改为“icmp6_筛选器”。为与第2.2节中的名称保持一致,将筛选器宏的前缀从“ICMPV6”更改为“ICMP6”。将示例从ping程序更改为只希望接收路由器广告的程序。
- Section 4.1: Changed msg_namelen and msg_controllen from size_t to the Posix.1g socklen_t datatype. Updated the Note that follows.
- 第4.1节:将msg_namelen和msg_controller从size_t更改为Posix.1g socklen_t数据类型。更新了下面的注释。
- Section 4.2: Changed cmsg_len from size_t to the Posix.1g socklen_t datatype. Updated the Note that follows.
- 第4.2节:将cmsg长度从大小更改为Posix.1g socklen长度数据类型。更新了下面的注释。
- Section 4.4: Added a Note that the second and third arguments to getsockopt() and setsockopt() are intentionally the same as the cmsg_level and cmsg_type members.
- 第4.4节:添加了一个注释,即getsockopt()和setsockopt()的第二个和第三个参数故意与cmsg_级别和cmsg_类型成员相同。
- Section 4.5: Reorganized the section into a description of the option, followed by the TCP semantics, and the UDP and raw socket semantics. Added a sentence on how to clear all the sticky options. Added a note that TCP need not save the options from the most recently received segment until the application says to do so. Added the statement that ancillary data is never passed with sendmsg() or recvmsg() on a TCP socket. Simplified the interaction of the sticky options with ancillary data for UDP or raw IP: none of the sticky options are sent if ancillary data is specified.
- 第4.5节:将该节重新组织为对选项的描述,然后是TCP语义、UDP和原始套接字语义。添加了一个关于如何清除所有粘性选项的句子。添加了一个注意事项,即在应用程序要求保存选项之前,TCP不需要保存最近收到的段中的选项。添加了一条语句,即在TCP套接字上永远不会使用sendmsg()或recvmsg()传递辅助数据。简化了粘性选项与UDP或原始IP的辅助数据的交互:如果指定了辅助数据,则不会发送任何粘性选项。
- Final paragraph of Section 5.1: ipi6_index should be ipi6_ifindex.
- 第5.1节:ipi6_索引的最后一段应为ipi6_iIndex。
- Section 5.4: Added a note on the term "privileged".
- 第5.4节:添加了关于“特权”一词的注释。
- Section 5.5: Noted that the errors listed are examples, and the actual errors depend on the implementation.
- 第5.5节:注意,列出的错误是示例,实际错误取决于实现。
- Removed Section 6 ("Flow Labels") as the consensus is that it is premature to try and specify an API for this feature. Access to the flow label field in the IPv6 header is still provided through the sin6_flowinfo member of the IPv6 socket address structure in [RFC-2133]. Added a subsection to Section 13 that this is a future item.
- 删除了第6节(“流标签”),因为普遍认为尝试为该功能指定API为时过早。仍可通过[RFC-2133]中IPv6套接字地址结构的sin6_flowinfo成员访问IPv6标头中的流标签字段。在第13节中增加了一个小节,说明这是一个未来项目。
All remaining changes are identified by their section number in the previous draft. With the removal of Section 6, the section numbers are decremented by one.
所有剩余的变更在上一份草案中通过其章节号进行标识。删除第6节后,节数减少1。
- Section 7.3.7: the calls to malloc() in all three examples should be calls to inet6_option_space() instead. The two calls to inet6_option_append() in the third example should be calls to inet6_option_alloc(). The two calls to CMSG_SPACE() in the first and third examples should be calls to CMSG_LEN(). The second call to CMSG_SPACE() in the second example should be a call to CMSG_LEN().
- 第7.3.7节:所有三个示例中对malloc()的调用都应该是对inet6_option_space()的调用。第三个示例中对inet6\u option\u append()的两个调用应该是对inet6\u option\u alloc()的调用。第一个和第三个示例中对CMSG_SPACE()的两个调用应该是对CMSG_LEN()的调用。第二个示例中对CMSG_SPACE()的第二个调用应该是对CMSG_LEN()的调用。
- Section 7.3.7: All the opt_X_ and opt_Y_ structure member names were changed to be ip6_X_opt_ and ip6_Y_opt_. The two structure names ipv6_opt_X and ipv6_opt_Y were changed to ip6_X_opt and ip6_Y_opt. The constants beginning with IPV6_OPT_X_ and IPV6_OPT_Y_ were changed to begin with IP6_X_OPT_ and IP6_Y_OPT_.
- 第7.3.7节:所有opt_X_和opt_Y_结构成员名称更改为ip6_X_opt_和ip6_Y_opt_。两个结构名称ipv6_opt_X和ipv6_opt_Y更改为ip6_X_opt和ip6_Y_opt。以IPV6_OPT_X_和IPV6_OPT_Y_开头的常量已更改为以IP6_X_OPT_和IP6_Y_OPT_开头。
- Use the term "Routing header" throughout the draft, instead of "source routing". Changed the names of the eight inet6_srcrt_XXX() functions in Section 9 to inet6_rthdr_XXX(). Changed the name of the socket option from IPV6_SRCRT to IPV6_RTHDR, and the names of the three IPV6_SRCRT_xxx constants in Section 9 to IPV6_RTHDR_xxx.
- 在整个草稿中使用术语“路由头”,而不是“源路由”。将第9节中八个inet6_srcrt_XXX()函数的名称更改为inet6_rthdr_XXX()。将套接字选项的名称从IPV6_SRCRT更改为IPV6_RTHDR,并将第9节中的三个IPV6_SRCRT_xxx常量的名称更改为IPV6_RTHDR_xxx。
- Added a paragraph to Section 9 on how to receive and send a Routing header.
- 在第9节中添加了一段关于如何接收和发送路由标头的内容。
- Changed inet6_rthdr_add() and inet6_rthdr_reverse() so that they return -1 upon an error, instead of an Exxx errno value.
- 更改了inet6_rthdr_add()和inet6_rthdr_reverse(),以便在出现错误时返回-1,而不是Exxx errno值。
- In the description of inet6_rthdr_space() in Section 9.1, added the qualifier "For an IPv6 Type 0 Routing header" to the restriction of between 1 and 23 segments.
- 在第9.1节中对inet6_rthdr_space()的描述中,在1到23段之间的限制中添加了限定符“用于IPv6类型0路由头”。
- Refer to final function argument in Sections 9.7 and 9.8 as index, not offset.
- 参考第9.7节和第9.8节中的最终函数参数作为索引,而不是偏移量。
- Updated Section 14 with new names from Section 2.
- 用第2节中的新名称更新了第14节。
- Changed the References from "[n]" to "[RFC-abcd]".
- 将引用从“[n]”更改为“[RFC abcd]”。
Changes from the February 1997 Edition (-01 draft)
与1997年2月版相比的变化(-01草稿)
- Changed the name of the ip6hdr structure to ip6_hdr (Section 2.1) for consistency with the icmp6hdr structure. Also changed the name of the ip6hdrctl structure contained within the ip6_hdr structure to ip6_hdrctl (Section 2.1). Finally, changed the name of the icmp6hdr structure to icmp6_hdr (Section 2.2). All other occurrences of this structure name, within the Neighbor Discovery structures in Section 2.2.1, already contained the underscore.
- 将ip6hdr结构的名称更改为ip6_hdr(第2.1节),以与icmp6hdr结构保持一致。还将ip6_hdr结构中包含的ip6hdrctl结构的名称更改为ip6_hdrctl(第2.1节)。最后,将icmp6hdr结构的名称更改为icmp6_hdr(第2.2节)。在第2.2.1节中的邻居发现结构中,此结构名称的所有其他引用都已包含下划线。
- The "struct nd_router_solicit" and "struct nd_router_advert" should both begin with "nd6_". (Section 2.2.2).
- “struct nd_router_request”和“struct nd_router_advert”都应该以“nd6_”开头。(第2.2.2节)。
- Changed the name of in6_are_addr_equal to IN6_ARE_ADDR_EQUAL (Section 2.3) for consistency with basic API address testing functions. The header defining this macro is <netinet/in.h>.
- 为了与基本API地址测试函数保持一致,将in6_are_addr_equal的名称更改为in6_are_addr_equal(第2.3节)。定义此宏的标题是<netinet/in.h>。
- getprotobyname("ipv6") now returns 41, not 0 (Section 2.4).
- getprotobyname(“ipv6”)现在返回41,而不是0(第2.4节)。
- The first occurrence of "struct icmpv6_filter" in Section 3.2 should be "struct icmp6_filter".
- 第3.2节中首次出现的“结构icmpv6_过滤器”应为“结构icmp6_过滤器”。
- Changed the name of the CMSG_LENGTH() macro to CMSG_LEN() (Section 4.3.5), since LEN is used throughout the <netinet/*.h>
- 将CMSG_LENGTH()宏的名称更改为CMSG_leng()(第4.3.5节),因为LEN在<netinet/*.h>
headers.
标题。
- Corrected the argument name for the sample implementations of the CMSG_SPACE() and CMSG_LEN() macros to be "length" (Sections 4.3.4 and 4.3.5).
- 将CMSG_SPACE()和CMSG_LEN()宏的示例实现的参数名称更正为“length”(第4.3.4节和第4.3.5节)。
- Corrected the socket option mentioned in Section 5.1 to specify the interface for multicasting from IPV6_ADD_MEMBERSHIP to IPV6_MULTICAST_IF.
- 更正了第5.1节中提到的套接字选项,以指定从IPV6\u向IPV6\u多播添加\u成员身份的接口。
- There were numerous errors in the previous draft that specified <netinet/ip6.h> that should have been <netinet/in.h>. These have all been corrected and the locations of all definitions is now summarized in the new Section 14 ("Summary of New Definitions").
- 以前的草案中有许多错误,规定<netinet/ip6.h>应该是<netinet/in.h>。所有这些都已更正,所有定义的位置现汇总在新的第14节(“新定义汇总”)。
Changes from the October 1996 Edition (-00 draft)
1996年10月版的更改(-00草稿)
- Numerous rationale added using the format (Note: ...).
- 使用该格式添加了大量理由(注:…)。
- Added note that not all errors may be defined.
- 补充说明:并非所有错误都可以定义。
- Added note about ICMPv4, IGMPv4, and ARPv4 terminology.
- 增加了关于ICMPv4、IGMPv4和ARPv4术语的说明。
- Changed the name of <netinet/ip6_icmp.h> to <netinet/icmp6.h>.
- 将<netinet/ip6icmp.h>的名称更改为<netinet/icmp6.h>。
- Changed some names in Section 2.2.1: ICMPV6_PKT_TOOBIG to ICMPV6_PACKET_TOOBIG, ICMPV6_TIME_EXCEED to ICMPV6_TIME_EXCEEDED, ICMPV6_ECHORQST to ICMPV6_ECHOREQUEST, ICMPV6_ECHORPLY to ICMPV6_ECHOREPLY, ICMPV6_PARAMPROB_HDR to ICMPV6_PARAMPROB_HEADER, ICMPV6_PARAMPROB_NXT_HDR to ICMPV6_PARAMPROB_NEXTHEADER, and ICMPV6_PARAMPROB_OPTS to ICMPV6_PARAMPROB_OPTION.
- 将第2.2.1节中的一些名称更改为:ICMPV6_PKT_TOOBIG改为ICMPV6_PACKET_TOOBIG,ICMPV6_TIME_extend改为ICMPV6_TIME_extended,ICMPV6_ECHORQST改为ICMPV6_echorprey,ICMPV6_PARAMPROB_HDR改为ICMPV6_PARAMPROB_prob_头,ICMPV6_parampprob_NXT_HDR改为PV6_param prob_prob下一个,ICMPV6_PARAMPROB_选择ICMPV6_PARAMPROB_选项。
- Prepend the prefix "icmp6_" to the three members of the icmp6_dataun union of the icmp6hdr structure (Section 2.2).
- 在icmp6hdr结构(第2.2节)的icmp6_数据联合体的三个成员前面加上前缀“icmp6_”。
- Moved the neighbor discovery definitions into the <netinet/icmp6.h> header, instead of being in their own header (Section 2.2.1).
- 将邻居发现定义移动到<netinet/icmp6.h>头中,而不是移动到自己的头中(第2.2.1节)。
- Changed Section 2.3 ("Address Testing"). The basic macros are now in the basic API.
- 更改了第2.3节(“地址测试”)。基本宏现在位于基本API中。
- Added the new Section 2.4 on "Protocols File".
- 新增了关于“协议文件”的第2.4节。
- Added note to raw sockets description that something like BPF or DLPI must be used to read or write entire IPv6 packets.
- 在原始套接字描述中添加了一个注释,即必须使用BPF或DLPI之类的内容来读取或写入整个IPv6数据包。
- Corrected example of IPV6_CHECKSUM socket option (Section 3.1). Also defined value of -1 to disable.
- 已更正IPV6_校验和套接字选项示例(第3.1节)。还定义了-1值以禁用。
- Noted that <netinet/icmp6.h> defines all the ICMPv6 filtering constants, macros, and structures (Section 3.2).
- 注意,<netinet/icmp6.h>定义了所有ICMPv6过滤常量、宏和结构(第3.2节)。
- Added note on magic number 10240 for amount of ancillary data (Section 4.1).
- 增加了有关辅助数据量的幻数10240注释(第4.1节)。
- Added possible padding to picture of ancillary data (Section 4.2).
- 在辅助数据图片中添加了可能的填充(第4.2节)。
- Defined <sys/socket.h> header for CMSG_xxx() functions (Section 4.2).
- 为CMSG_xxx()函数定义<sys/socket.h>头(第4.2节)。
- Note that the data returned by getsockopt(IPV6_PKTOPTIONS) for a TCP socket is just from the optional headers, if present, of the most recently received segment. Also note that control information is never returned by recvmsg() for a TCP socket.
- 请注意,getsockopt(IPV6_PKTOPTIONS)为TCP套接字返回的数据仅来自最近接收的段的可选头(如果存在)。还要注意,对于TCP套接字,recvmsg()永远不会返回控制信息。
- Changed header for struct in6_pktinfo from <netinet.in.h> to <netinet/ip6.h> (Section 5).
- 将6_pktinfo结构的标题从<netinet.in.h>更改为<netinet/ip6.h>(第5节)。
- Removed the old Sections 5.1 and 5.2, because the interface identification functions went into the basic API.
- 删除了旧的第5.1节和第5.2节,因为接口标识函数包含在基本API中。
- Redid Section 5 to support the hop limit field.
- 重拨第5节以支持跃点限制字段。
- New Section 5.4 ("Next Hop Address").
- 新的第5.4节(“下一跳地址”)。
- New Section 6 ("Flow Labels").
- 新增第6节(“流量标签”)。
- Changed all of Sections 7 and 8 dealing with Hop-by-Hop and Destination options. We now define a set of inet6_option_XXX() functions.
- 更改了第7节和第8节中关于逐跳和目的地选项的所有内容。我们现在定义一组inet6_option_XXX()函数。
- Changed header for IPV6_SRCRT_xxx constants from <netinet.in.h> to <netinet/ip6.h> (Section 9).
- 将IPV6_SRCRT_xxx常量的标题从<netinet.in.h>更改为<netinet/ip6.h>(第9节)。
- Add inet6_rthdr_lasthop() function, and fix errors in description of Routing header (Section 9).
- 添加inet6\u rthdr\u lasthop()函数,并修复路由头描述中的错误(第9节)。
- Reworded some of the Routing header descriptions to conform to the terminology in [RFC-1883].
- 改写了一些路由头描述,以符合[RFC-1883]中的术语。
- Added the example from [RFC-1883] for the Routing header (Section 9.9).
- 添加[RFC-1883]中路由头的示例(第9.9节)。
- Expanded the example in Section 10 to show multiple options per ancillary data object, and to show the receiver's ancillary data objects.
- 扩展第10节中的示例,以显示每个辅助数据对象的多个选项,并显示接收器的辅助数据对象。
- New Section 11 ("IPv6-Specific Options with IPv4-Mapped IPv6 Addresses").
- 新增第11节(“具有IPv4映射IPv6地址的IPv6特定选项”)。
- New Section 12 ("rresvport_af").
- 新订的第12条(“rresvport_af”)。
- Redid old Section 10 ("Additional Items") into new Section 13 ("Future Items").
- 将旧的第10节(“附加项目”)重新划分为新的第13节(“未来项目”)。
[RFC-1883] Deering, S., and R. Hinden, "Internet Protocol, Version 6 (IPv6), Specification", RFC 1883, December 1995.
[RFC-1883]Deering,S.和R.Hinden,“互联网协议,第6版(IPv6),规范”,RFC 1883,1995年12月。
[RFC-2133] Gilligan, R., Thomson, S., Bound, J., and W. Stevens, "Basic Socket Interface Extensions for IPv6", RFC 2133, April 1997.
[RFC-2133]Gilligan,R.,Thomson,S.,Bound,J.,和W.Stevens,“IPv6的基本套接字接口扩展”,RFC 2133,1997年4月。
[RFC-1981] McCann, J., Deering, S., and J. Mogul, "Path MTU Discovery for IP version 6", RFC 1981, August 1996.
[RFC-1981]McCann,J.,Deering,S.,和J.Mogul,“IP版本6的路径MTU发现”,RFC 1981,1996年8月。
[RFC-1970] Narten, T., Nordmark, E., and W. Simpson, "Neighbor Discovery for IP Version 6 (IPv6)", RFC 1970, August 1996.
[RFC-1970]Narten,T.,Nordmark,E.,和W.Simpson,“IP版本6(IPv6)的邻居发现”,RFC 1970,1996年8月。
Matt Thomas and Jim Bound have been working on the technical details in this draft for over a year. Keith Sklower is the original implementor of ancillary data in the BSD networking code. Craig Metz provided lots of feedback, suggestions, and comments based on his implementing many of these features as the document was being written.
马特·托马斯(Matt Thomas)和吉姆·邦德(Jim Bound)一年多以来一直在研究该草案的技术细节。Keith Sklower是BSD网络代码中辅助数据的原始实现者。Craig Metz在编写文档时实现了许多这些特性,并根据这些特性提供了大量反馈、建议和评论。
The following provided comments on earlier drafts: Pascal Anelli, Hamid Asayesh, Ran Atkinson, Karl Auerbach, Hamid Asayesh, Matt Crawford, Sam T. Denton, Richard Draves, Francis Dupont, Bob Gilligan, Tim Hartrick, Masaki Hirabaru, Yoshinobu Inoue, Mukesh Kacker, A. N. Kuznetsov, Pedro Marques, Jack McCann, der Mouse, John Moy, Thomas Narten, Erik Nordmark, Steve Parker, Charles Perkins, Tom Pusateri, Pedro Roque, Sameer Shah, Peter Sjodin, Stephen P. Spackman, Jinmei Tatuya, Karen Tracey, Quaizar Vohra, Carl Williams, Steve Wise, and Kazu Yamamoto.
以下是对早期草案的评论:帕斯卡·阿内利、哈米德·阿萨耶什、冉·阿特金森、卡尔·奥尔巴赫、哈米德·阿萨耶什、马特·克劳福德、萨姆·丹顿、理查德·德拉维斯、弗朗西斯·杜邦、鲍勃·吉利根、蒂姆·哈特里克、平拉巴鲁、井上吉诺布、穆克什·卡克尔、A.N.库兹涅佐夫、佩德罗·马奎斯、杰克·麦肯、德·穆斯、约翰·莫伊、托马斯·纳腾、,Erik Nordmark、Steve Parker、Charles Perkins、Tom Pusateri、Pedro Roque、Sameer Shah、Peter Sjodin、Stephen P.Spackman、Jinmei Tatuya、Karen Tracey、Quaizar Vohra、Carl Williams、Steve Wise和Kazu Yamamoto。
W. Richard Stevens 1202 E. Paseo del Zorro Tucson, AZ 85718
W.理查德·史蒂文斯1202 E.帕西奥·德尔·佐罗·图森,亚利桑那州,85718
EMail: rstevens@kohala.com
EMail: rstevens@kohala.com
Matt Thomas AltaVista Internet Software LJO2-1/J8 30 Porter Rd Littleton, MA 01460 EMail: matt.thomas@altavista-software.com
马特·托马斯·阿尔塔维斯塔互联网软件LJO2-1/J8马萨诸塞州利特尔顿波特路30号01460电子邮件:马特。thomas@altavista-软件网站
Copyright (C) The Internet Society (1998). All Rights Reserved.
版权所有(C)互联网协会(1998年)。版权所有。
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.
本文件及其译本可复制并提供给他人,对其进行评论或解释或协助其实施的衍生作品可全部或部分编制、复制、出版和分发,不受任何限制,前提是上述版权声明和本段包含在所有此类副本和衍生作品中。但是,不得以任何方式修改本文件本身,例如删除版权通知或对互联网协会或其他互联网组织的引用,除非出于制定互联网标准的需要,在这种情况下,必须遵循互联网标准过程中定义的版权程序,或根据需要将其翻译成英语以外的其他语言。
The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.
上述授予的有限许可是永久性的,互联网协会或其继承人或受让人不会撤销。
This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
本文件和其中包含的信息是按“原样”提供的,互联网协会和互联网工程任务组否认所有明示或暗示的保证,包括但不限于任何保证,即使用本文中的信息不会侵犯任何权利,或对适销性或特定用途适用性的任何默示保证。