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
36 request information about neighboring IPv6 systems on the local network, much
40 NDP is also responsible for spreading information about the network gateway and
41 how hosts should configure themselves
42 .Pq see Xr in.ndpd 1M for more on how this happens .
43 .Sh APPLICATION PROGRAMMING INTERFACE
44 The operating system provides several ioctls to help manipulate the mappings
51 for getting, setting, and deleting respectively.
52 Each of these ioctls takes a
54 .Pq see Xr if 7P for details ,
58 .Vt struct lif_nd_req :
59 .Bd -literal -offset 2m
60 typedef struct lif_nd_req {
61 struct sockaddr_storage lnr_addr;
62 uint8_t lnr_state_create;
63 uint8_t lnr_state_same_lla;
64 uint8_t lnr_state_diff_lla;
68 char lnr_hdw_addr[ND_MAX_HDW_LEN];
74 field should be filled in with an IPv6 address
75 .Pq see Xr sockaddr_in6 3SOCKET ,
78 is the link-layer address of length
82 .Fa lnr_state_create ,
83 .Fa lnr_state_same_lla ,
85 .Fa lnr_state_diff_lla
86 can be set to one of the following values:
87 .Bl -tag -offset indent -width 16m
89 For ioctls that don't modify state
91 Address resolution is currently in progress
93 The link-layer address has recently been reachable
95 The link-layer address may be unreachable, and the system shouldn't do anything
97 This entry hasn't yet started sending Neighbor Solicitations
99 The operating system is currently sending out Neighbor Solicitations for the address
100 .It Sy ND_UNREACHABLE
101 The link-layer address is unreachable, and this entry is going to be deleted.
104 When creating a new entry, the only valid values for
110 Any other value will return
113 .Fa lnr_state_same_lla
115 .Fa lnr_state_diff_lla
116 fields are reserved for future use and can be safely set to
122 Flags that can be placed in
125 .Bl -tag -offset indent -width 16m
126 .It Sy NDF_ISROUTER_ON
127 Mark this entry as being a router.
128 This will cause Neighbor Advertisements for this address to be sent with the
130 .It Sy NDF_ISROUTER_OFF
131 If this entry was flagged as being a router, remove the flag.
132 .It Sy NDF_ANYCAST_ON
133 Mark this entry as being for an anycast address.
134 This prevents sending Neighbor Advertisements with the O-bit (Override).
135 .It Sy NDF_ANYCAST_OFF
136 If this entry was flagged as an anycast address, remove the flag.
138 Prevent this entry from being deleted by the system.
143 these flags represent the current state of the corresponding Neighbor Cache
147 these flags represent what changes should be applied to the underlying entry.
149 The only fields that need to be set for the
157 All other fields should be zeroed out.
158 After successfully getting an entry, the other fields will be filled in.
161 all fields should be set to an appropriate value, as described above, with the
164 which is unused and only exists for padding purposes.
166 After performing the ioctl, the following errors may be returned through the
170 .Bl -tag -offset indent -width 16m
172 A non-IPv6 socket was used to perform the ioctl.
174 The request contents were bad.
175 This could be because conflicting flags were used, the specified interface
176 wasn't logical unit zero, or another reason.
178 The system ran out of memory for internal data structures.
180 The specified interface does not exist.
182 The caller does not have permission to modify the Neighbor Cache Entries
183 associated with this interface.
184 They may be lacking the
185 .Sy PRIV_SYS_NET_CONFIG
187 .Po see Xr privileges 5 Pc ,
188 or the interface is managed by IPMP (IP Network Multipathing).
190 There is no entry matching the specified address.
193 The following examples demonstrate how to get and set NDP mappings using the
195 They can be compiled by using a C compiler and linking against the sockets
197 .Ss Example 1: Getting a mapping
198 .Bd -literal -offset indent
199 $ gcc -Wall -lsocket -o get get.c
202 * Example of getting a mapping for a node name.
207 #include <sys/socket.h>
208 #include <sys/sockio.h>
213 int get(char *host) {
215 struct addrinfo hints, *serverinfo, *p;
218 bzero(&hints, sizeof (struct addrinfo));
219 hints.ai_family = PF_INET6;
220 hints.ai_protocol = IPPROTO_IPV6;
222 if ((err = getaddrinfo(host, NULL, &hints, &serverinfo)) != 0) {
223 (void) fprintf(stderr, "Unable to lookup %s: %s\\n", host,
228 s = socket(AF_INET6, SOCK_DGRAM, 0);
230 perror("Failed to open IPv6 socket");
234 for (p = serverinfo; p != NULL; p = p->ai_next) {
235 /* Zero out structure */
236 bzero(&lifr, sizeof (struct lifreq));
237 (void) strlcpy(lifr.lifr_name, "net0",
238 sizeof (lifr.lifr_name));
239 (void) memcpy(&lifr.lifr_nd.lnr_addr, p->ai_addr,
240 sizeof (struct sockaddr_storage));
243 if (ioctl(s, SIOCLIFGETND, &lifr) < 0) {
244 perror("Unable to get NDP mapping");
249 * lifr.lifr_nd.lnr_hdw_addr now contains the MAC address,
250 * and can be used as desired.
255 * Clean up linked list.
257 freeaddrinfo(serverinfo);
261 int main(int argc, char *argv[]) {
264 return (get(argv[1]));
268 Deleting a mapping would work similarly, except that instead of using
270 you would instead use the
273 .Ss Example 2: Adding a mapping
274 .Bd -literal -offset indent
275 $ gcc -Wall -lsocket -o set set.c
278 * Example of setting a mapping to an all-zero Ethernet address.
283 #include <sys/socket.h>
284 #include <sys/sockio.h>
289 int set(char *host) {
291 struct addrinfo hints, *serverinfo, *p;
294 bzero(&hints, sizeof (struct addrinfo));
295 hints.ai_family = PF_INET6;
296 hints.ai_protocol = IPPROTO_IPV6;
298 if ((err = getaddrinfo(host, NULL, &hints, &serverinfo)) != 0) {
299 (void) fprintf(stderr, "Unable to lookup %s: %s\\n", host,
304 s = socket(AF_INET6, SOCK_DGRAM, 0);
306 perror("Failed to open IPv6 socket");
310 for (p = serverinfo; p != NULL; p = p->ai_next) {
311 /* Zero out structure */
312 bzero(&lifr, sizeof (struct lifreq));
313 (void) strlcpy(lifr.lifr_name, "net0",
314 sizeof (lifr.lifr_name));
315 (void) memcpy(&lifr.lifr_nd.lnr_addr, p->ai_addr,
316 sizeof (struct sockaddr_storage));
318 lifr.lifr_nd.lnr_state_create = ND_REACHABLE;
319 lifr.lifr_nd.lnr_flags = NDF_STATIC;
322 if (ioctl(s, SIOCLIFSETND, &lifr) < 0) {
323 perror("Unable to set NDP mapping");
329 * Clean up linked list.
331 freeaddrinfo(serverinfo);
335 int main(int argc, char *argv[]) {
338 return (set(argv[1]));
345 .Xr sockaddr_in6 3SOCKET ,
352 .%R Neighbor Discovery for IP version 6