2 .\" This file and its contents are supplied under the terms of the
3 .\" Common Development and Distribution License ("CDDL"), version 1.0.
4 .\" You may only use this file in accordance with the terms of version
7 .\" A full copy of the text of the CDDL should have accompanied this
8 .\" source. A copy of the CDDL is also available via the Internet at
9 .\" http://www.illumos.org/license/CDDL.
12 .\" Copyright (c) 2015, Joyent, Inc. All rights reserved.
20 .Nd Neighbor Discovery Protocol
27 s = socket(PF_INET6, SOCK_DGRAM, 0);
30 ioctl(s, SIOCLIFGETND, &lifr);
31 ioctl(s, SIOCLIFSETND, &lifr);
32 ioctl(s, SIOCLIFDELND, &lifr);
35 The Neighbor Discovery Protocol (NDP) is a protocol used to distribute and request
36 information about neighboring IPv6 systems on the local network, much like
38 for IPv4. NDP is also responsible for spreading information about the network
39 gateway and how hosts should configure themselves
40 .Pq see Xr in.ndpd 1M for more on how this happens .
41 .Sh APPLICATION PROGRAMMING INTERFACE
42 The operating system provides several ioctls to help manipulate the mappings
43 obtained through NDP. They are
48 for getting, setting, and deleting respectively. Each of these ioctls takes a
50 .Pq see Xr if 7P for details ,
54 .Vt struct lif_nd_req :
55 .Bd -literal -offset 2m
56 typedef struct lif_nd_req {
57 struct sockaddr_storage lnr_addr;
58 uint8_t lnr_state_create;
59 uint8_t lnr_state_same_lla;
60 uint8_t lnr_state_diff_lla;
64 char lnr_hdw_addr[ND_MAX_HDW_LEN];
70 field should be filled in with an IPv6 address
71 .Pq see Xr sockaddr_in6 3SOCKET ,
74 is the link-layer address of length
78 .Fa lnr_state_create ,
79 .Fa lnr_state_same_lla ,
81 .Fa lnr_state_diff_lla
82 can be set to one of the following values:
83 .Bl -tag -offset indent -width 16m
85 For ioctls that don't modify state
87 Address resolution is currently in progress
89 The link-layer address has recently been reachable
91 The link-layer address may be unreachable, and the system shouldn't do anything
93 This entry hasn't yet started sending Neighbor Solicitations
95 The operating system is currently sending out Neighbor Solicitations for the address
97 The link-layer address is unreachable, and this entry is going to be deleted.
100 When creating a new entry, the only valid values for
106 Any other value will return
109 .Fa lnr_state_same_lla
111 .Fa lnr_state_diff_lla
112 fields are reserved for future use and can be safely set to
118 Flags that can be placed in
121 .Bl -tag -offset indent -width 16m
122 .It Sy NDF_ISROUTER_ON
123 Mark this entry as being a router. This will cause Neighbor Advertisements for
124 this address to be sent with the R-bit (Router).
125 .It Sy NDF_ISROUTER_OFF
126 If this entry was flagged as being a router, remove the flag.
127 .It Sy NDF_ANYCAST_ON
128 Mark this entry as being for an anycast address. This prevents sending Neighbor
129 Advertisements with the O-bit (Override).
130 .It Sy NDF_ANYCAST_OFF
131 If this entry was flagged as an anycast address, remove the flag.
133 Prevent this entry from being deleted by the system.
138 these flags represent the current state of the corresponding Neighbor Cache
141 these flags represent what changes should be applied to the underlying entry.
143 The only fields that need to be set for the
151 All other fields should be zeroed out. After successfully getting an entry, the
152 other fields will be filled in. When using
154 all fields should be set to an appropriate value, as described above, with the
157 which is unused and only exists for padding purposes.
159 After performing the ioctl, the following errors may be returned through the
163 .Bl -tag -offset indent -width 16m
165 A non-IPv6 socket was used to perform the ioctl.
167 The request contents were bad. This could be because conflicting flags were
168 used, the specified interface wasn't logical unit zero, or another reason.
170 The system ran out of memory for internal data structures.
172 The specified interface does not exist.
174 The caller does not have permission to modify the Neighbor Cache Entries
175 associated with this interface. They may be lacking the
176 .Sy PRIV_SYS_NET_CONFIG
178 .Po see Xr privileges 5 Pc ,
179 or the interface is managed by IPMP (IP Network Multipathing).
181 There is no entry matching the specified address.
184 The following examples demonstrate how to get and set NDP mappings using the
185 provided ioctls. They can be compiled by using a C compiler and linking against
187 .Ss Example 1: Getting a mapping
188 .Bd -literal -offset indent
189 $ gcc -Wall -lsocket -o get get.c
192 * Example of getting a mapping for a node name.
197 #include <sys/socket.h>
198 #include <sys/sockio.h>
203 int get(char *host) {
205 struct addrinfo hints, *serverinfo, *p;
208 bzero(&hints, sizeof (struct addrinfo));
209 hints.ai_family = PF_INET6;
210 hints.ai_protocol = IPPROTO_IPV6;
212 if ((err = getaddrinfo(host, NULL, &hints, &serverinfo)) != 0) {
213 (void) fprintf(stderr, "Unable to lookup %s: %s\\n", host,
218 s = socket(AF_INET6, SOCK_DGRAM, 0);
220 perror("Failed to open IPv6 socket");
224 for (p = serverinfo; p != NULL; p = p->ai_next) {
225 /* Zero out structure */
226 bzero(&lifr, sizeof (struct lifreq));
227 (void) strlcpy(lifr.lifr_name, "net0",
228 sizeof (lifr.lifr_name));
229 (void) memcpy(&lifr.lifr_nd.lnr_addr, p->ai_addr,
230 sizeof (struct sockaddr_storage));
233 if (ioctl(s, SIOCLIFGETND, &lifr) < 0) {
234 perror("Unable to get NDP mapping");
239 * lifr.lifr_nd.lnr_hdw_addr now contains the MAC address,
240 * and can be used as desired.
245 * Clean up linked list.
247 freeaddrinfo(serverinfo);
251 int main(int argc, char *argv[]) {
254 return (get(argv[1]));
258 Deleting a mapping would work similarly, except that instead of using
260 you would instead use the
263 .Ss Example 2: Adding a mapping
264 .Bd -literal -offset indent
265 $ gcc -Wall -lsocket -o set set.c
268 * Example of setting a mapping to an all-zero Ethernet address.
273 #include <sys/socket.h>
274 #include <sys/sockio.h>
279 int set(char *host) {
281 struct addrinfo hints, *serverinfo, *p;
284 bzero(&hints, sizeof (struct addrinfo));
285 hints.ai_family = PF_INET6;
286 hints.ai_protocol = IPPROTO_IPV6;
288 if ((err = getaddrinfo(host, NULL, &hints, &serverinfo)) != 0) {
289 (void) fprintf(stderr, "Unable to lookup %s: %s\\n", host,
294 s = socket(AF_INET6, SOCK_DGRAM, 0);
296 perror("Failed to open IPv6 socket");
300 for (p = serverinfo; p != NULL; p = p->ai_next) {
301 /* Zero out structure */
302 bzero(&lifr, sizeof (struct lifreq));
303 (void) strlcpy(lifr.lifr_name, "net0",
304 sizeof (lifr.lifr_name));
305 (void) memcpy(&lifr.lifr_nd.lnr_addr, p->ai_addr,
306 sizeof (struct sockaddr_storage));
308 lifr.lifr_nd.lnr_state_create = ND_REACHABLE;
309 lifr.lifr_nd.lnr_flags = NDF_STATIC;
312 if (ioctl(s, SIOCLIFSETND, &lifr) < 0) {
313 perror("Unable to set NDP mapping");
319 * Clean up linked list.
321 freeaddrinfo(serverinfo);
325 int main(int argc, char *argv[]) {
328 return (set(argv[1]));
335 .Xr sockaddr_in6 3SOCKET ,
342 .%R Neighbor Discovery for IP version 6