github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/tcpip/stack/ndp.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package stack 16 17 import ( 18 "fmt" 19 "log" 20 "time" 21 22 "github.com/google/netstack/tcpip" 23 "github.com/google/netstack/tcpip/buffer" 24 "github.com/google/netstack/tcpip/header" 25 ) 26 27 const ( 28 // defaultDupAddrDetectTransmits is the default number of NDP Neighbor 29 // Solicitation messages to send when doing Duplicate Address Detection 30 // for a tentative address. 31 // 32 // Default = 1 (from RFC 4862 section 5.1) 33 defaultDupAddrDetectTransmits = 1 34 35 // defaultRetransmitTimer is the default amount of time to wait between 36 // sending NDP Neighbor solicitation messages. 37 // 38 // Default = 1s (from RFC 4861 section 10). 39 defaultRetransmitTimer = time.Second 40 41 // defaultHandleRAs is the default configuration for whether or not to 42 // handle incoming Router Advertisements as a host. 43 // 44 // Default = true. 45 defaultHandleRAs = true 46 47 // defaultDiscoverDefaultRouters is the default configuration for 48 // whether or not to discover default routers from incoming Router 49 // Advertisements, as a host. 50 // 51 // Default = true. 52 defaultDiscoverDefaultRouters = true 53 54 // defaultDiscoverOnLinkPrefixes is the default configuration for 55 // whether or not to discover on-link prefixes from incoming Router 56 // Advertisements' Prefix Information option, as a host. 57 // 58 // Default = true. 59 defaultDiscoverOnLinkPrefixes = true 60 61 // minimumRetransmitTimer is the minimum amount of time to wait between 62 // sending NDP Neighbor solicitation messages. Note, RFC 4861 does 63 // not impose a minimum Retransmit Timer, but we do here to make sure 64 // the messages are not sent all at once. We also come to this value 65 // because in the RetransmitTimer field of a Router Advertisement, a 66 // value of 0 means unspecified, so the smallest valid value is 1. 67 // Note, the unit of the RetransmitTimer field in the Router 68 // Advertisement is milliseconds. 69 // 70 // Min = 1ms. 71 minimumRetransmitTimer = time.Millisecond 72 73 // MaxDiscoveredDefaultRouters is the maximum number of discovered 74 // default routers. The stack should stop discovering new routers after 75 // discovering MaxDiscoveredDefaultRouters routers. 76 // 77 // This value MUST be at minimum 2 as per RFC 4861 section 6.3.4, and 78 // SHOULD be more. 79 // 80 // Max = 10. 81 MaxDiscoveredDefaultRouters = 10 82 83 // MaxDiscoveredOnLinkPrefixes is the maximum number of discovered 84 // on-link prefixes. The stack should stop discovering new on-link 85 // prefixes after discovering MaxDiscoveredOnLinkPrefixes on-link 86 // prefixes. 87 // 88 // Max = 10. 89 MaxDiscoveredOnLinkPrefixes = 10 90 ) 91 92 // NDPDispatcher is the interface integrators of netstack must implement to 93 // receive and handle NDP related events. 94 type NDPDispatcher interface { 95 // OnDuplicateAddressDetectionStatus will be called when the DAD process 96 // for an address (addr) on a NIC (with ID nicID) completes. resolved 97 // will be set to true if DAD completed successfully (no duplicate addr 98 // detected); false otherwise (addr was detected to be a duplicate on 99 // the link the NIC is a part of, or it was stopped for some other 100 // reason, such as the address being removed). If an error occured 101 // during DAD, err will be set and resolved must be ignored. 102 // 103 // This function is permitted to block indefinitely without interfering 104 // with the stack's operation. 105 OnDuplicateAddressDetectionStatus(nicID tcpip.NICID, addr tcpip.Address, resolved bool, err *tcpip.Error) 106 107 // OnDefaultRouterDiscovered will be called when a new default router is 108 // discovered. Implementations must return true along with a new valid 109 // route table if the newly discovered router should be remembered. If 110 // an implementation returns false, the second return value will be 111 // ignored. 112 // 113 // This function is not permitted to block indefinitely. This function 114 // is also not permitted to call into the stack. 115 OnDefaultRouterDiscovered(nicID tcpip.NICID, addr tcpip.Address) (bool, []tcpip.Route) 116 117 // OnDefaultRouterInvalidated will be called when a discovered default 118 // router is invalidated. Implementers must return a new valid route 119 // table. 120 // 121 // This function is not permitted to block indefinitely. This function 122 // is also not permitted to call into the stack. 123 OnDefaultRouterInvalidated(nicID tcpip.NICID, addr tcpip.Address) []tcpip.Route 124 125 // OnOnLinkPrefixDiscovered will be called when a new on-link prefix is 126 // discovered. Implementations must return true along with a new valid 127 // route table if the newly discovered on-link prefix should be 128 // remembered. If an implementation returns false, the second return 129 // value will be ignored. 130 // 131 // This function is not permitted to block indefinitely. This function 132 // is also not permitted to call into the stack. 133 OnOnLinkPrefixDiscovered(nicID tcpip.NICID, prefix tcpip.Subnet) (bool, []tcpip.Route) 134 135 // OnOnLinkPrefixInvalidated will be called when a discovered on-link 136 // prefix is invalidated. Implementers must return a new valid route 137 // table. 138 // 139 // This function is not permitted to block indefinitely. This function 140 // is also not permitted to call into the stack. 141 OnOnLinkPrefixInvalidated(nicID tcpip.NICID, prefix tcpip.Subnet) []tcpip.Route 142 } 143 144 // NDPConfigurations is the NDP configurations for the netstack. 145 type NDPConfigurations struct { 146 // The number of Neighbor Solicitation messages to send when doing 147 // Duplicate Address Detection for a tentative address. 148 // 149 // Note, a value of zero effectively disables DAD. 150 DupAddrDetectTransmits uint8 151 152 // The amount of time to wait between sending Neighbor solicitation 153 // messages. 154 // 155 // Must be greater than 0.5s. 156 RetransmitTimer time.Duration 157 158 // HandleRAs determines whether or not Router Advertisements will be 159 // processed. 160 HandleRAs bool 161 162 // DiscoverDefaultRouters determines whether or not default routers will 163 // be discovered from Router Advertisements. This configuration is 164 // ignored if HandleRAs is false. 165 DiscoverDefaultRouters bool 166 167 // DiscoverOnLinkPrefixes determines whether or not on-link prefixes 168 // will be discovered from Router Advertisements' Prefix Information 169 // option. This configuration is ignored if HandleRAs is false. 170 DiscoverOnLinkPrefixes bool 171 } 172 173 // DefaultNDPConfigurations returns an NDPConfigurations populated with 174 // default values. 175 func DefaultNDPConfigurations() NDPConfigurations { 176 return NDPConfigurations{ 177 DupAddrDetectTransmits: defaultDupAddrDetectTransmits, 178 RetransmitTimer: defaultRetransmitTimer, 179 HandleRAs: defaultHandleRAs, 180 DiscoverDefaultRouters: defaultDiscoverDefaultRouters, 181 DiscoverOnLinkPrefixes: defaultDiscoverOnLinkPrefixes, 182 } 183 } 184 185 // validate modifies an NDPConfigurations with valid values. If invalid values 186 // are present in c, the corresponding default values will be used instead. 187 // 188 // If RetransmitTimer is less than minimumRetransmitTimer, then a value of 189 // defaultRetransmitTimer will be used. 190 func (c *NDPConfigurations) validate() { 191 if c.RetransmitTimer < minimumRetransmitTimer { 192 c.RetransmitTimer = defaultRetransmitTimer 193 } 194 } 195 196 // ndpState is the per-interface NDP state. 197 type ndpState struct { 198 // The NIC this ndpState is for. 199 nic *NIC 200 201 // configs is the per-interface NDP configurations. 202 configs NDPConfigurations 203 204 // The DAD state to send the next NS message, or resolve the address. 205 dad map[tcpip.Address]dadState 206 207 // The default routers discovered through Router Advertisements. 208 defaultRouters map[tcpip.Address]defaultRouterState 209 210 // The on-link prefixes discovered through Router Advertisements' Prefix 211 // Information option. 212 onLinkPrefixes map[tcpip.Subnet]onLinkPrefixState 213 } 214 215 // dadState holds the Duplicate Address Detection timer and channel to signal 216 // to the DAD goroutine that DAD should stop. 217 type dadState struct { 218 // The DAD timer to send the next NS message, or resolve the address. 219 timer *time.Timer 220 221 // Used to let the DAD timer know that it has been stopped. 222 // 223 // Must only be read from or written to while protected by the lock of 224 // the NIC this dadState is associated with. 225 done *bool 226 } 227 228 // defaultRouterState holds data associated with a default router discovered by 229 // a Router Advertisement (RA). 230 type defaultRouterState struct { 231 invalidationTimer *time.Timer 232 233 // Used to inform the timer not to invalidate the default router (R) in 234 // a race condition (T1 is a goroutine that handles an RA from R and T2 235 // is the goroutine that handles R's invalidation timer firing): 236 // T1: Receive a new RA from R 237 // T1: Obtain the NIC's lock before processing the RA 238 // T2: R's invalidation timer fires, and gets blocked on obtaining the 239 // NIC's lock 240 // T1: Refreshes/extends R's lifetime & releases NIC's lock 241 // T2: Obtains NIC's lock & invalidates R immediately 242 // 243 // To resolve this, T1 will check to see if the timer already fired, and 244 // inform the timer using doNotInvalidate to not invalidate R, so that 245 // once T2 obtains the lock, it will see that it is set to true and do 246 // nothing further. 247 doNotInvalidate *bool 248 } 249 250 // onLinkPrefixState holds data associated with an on-link prefix discovered by 251 // a Router Advertisement's Prefix Information option (PI) when the NDP 252 // configurations was configured to do so. 253 type onLinkPrefixState struct { 254 invalidationTimer *time.Timer 255 256 // Used to signal the timer not to invalidate the on-link prefix (P) in 257 // a race condition (T1 is a goroutine that handles a PI for P and T2 258 // is the goroutine that handles P's invalidation timer firing): 259 // T1: Receive a new PI for P 260 // T1: Obtain the NIC's lock before processing the PI 261 // T2: P's invalidation timer fires, and gets blocked on obtaining the 262 // NIC's lock 263 // T1: Refreshes/extends P's lifetime & releases NIC's lock 264 // T2: Obtains NIC's lock & invalidates P immediately 265 // 266 // To resolve this, T1 will check to see if the timer already fired, and 267 // inform the timer using doNotInvalidate to not invalidate P, so that 268 // once T2 obtains the lock, it will see that it is set to true and do 269 // nothing further. 270 doNotInvalidate *bool 271 } 272 273 // startDuplicateAddressDetection performs Duplicate Address Detection. 274 // 275 // This function must only be called by IPv6 addresses that are currently 276 // tentative. 277 // 278 // The NIC that ndp belongs to MUST be locked. 279 func (ndp *ndpState) startDuplicateAddressDetection(addr tcpip.Address, ref *referencedNetworkEndpoint) *tcpip.Error { 280 // addr must be a valid unicast IPv6 address. 281 if !header.IsV6UnicastAddress(addr) { 282 return tcpip.ErrAddressFamilyNotSupported 283 } 284 285 // Should not attempt to perform DAD on an address that is currently in 286 // the DAD process. 287 if _, ok := ndp.dad[addr]; ok { 288 // Should never happen because we should only ever call this 289 // function for newly created addresses. If we attemped to 290 // "add" an address that already existed, we would returned an 291 // error since we attempted to add a duplicate address, or its 292 // reference count would have been increased without doing the 293 // work that would have been done for an address that was brand 294 // new. See NIC.addPermanentAddressLocked. 295 panic(fmt.Sprintf("ndpdad: already performing DAD for addr %s on NIC(%d)", addr, ndp.nic.ID())) 296 } 297 298 remaining := ndp.configs.DupAddrDetectTransmits 299 300 { 301 done, err := ndp.doDuplicateAddressDetection(addr, remaining, ref) 302 if err != nil { 303 return err 304 } 305 if done { 306 return nil 307 } 308 } 309 310 remaining-- 311 312 var done bool 313 var timer *time.Timer 314 timer = time.AfterFunc(ndp.configs.RetransmitTimer, func() { 315 var d bool 316 var err *tcpip.Error 317 318 // doDadIteration does a single iteration of the DAD loop. 319 // 320 // Returns true if the integrator needs to be informed of DAD 321 // completing. 322 doDadIteration := func() bool { 323 ndp.nic.mu.Lock() 324 defer ndp.nic.mu.Unlock() 325 326 if done { 327 // If we reach this point, it means that the DAD 328 // timer fired after another goroutine already 329 // obtained the NIC lock and stopped DAD before 330 // this function obtained the NIC lock. Simply 331 // return here and do nothing further. 332 return false 333 } 334 335 ref, ok := ndp.nic.endpoints[NetworkEndpointID{addr}] 336 if !ok { 337 // This should never happen. 338 // We should have an endpoint for addr since we 339 // are still performing DAD on it. If the 340 // endpoint does not exist, but we are doing DAD 341 // on it, then we started DAD at some point, but 342 // forgot to stop it when the endpoint was 343 // deleted. 344 panic(fmt.Sprintf("ndpdad: unrecognized addr %s for NIC(%d)", addr, ndp.nic.ID())) 345 } 346 347 d, err = ndp.doDuplicateAddressDetection(addr, remaining, ref) 348 if err != nil || d { 349 delete(ndp.dad, addr) 350 351 if err != nil { 352 log.Printf("ndpdad: Error occured during DAD iteration for addr (%s) on NIC(%d); err = %s", addr, ndp.nic.ID(), err) 353 } 354 355 // Let the integrator know DAD has completed. 356 return true 357 } 358 359 remaining-- 360 timer.Reset(ndp.nic.stack.ndpConfigs.RetransmitTimer) 361 return false 362 } 363 364 if doDadIteration() && ndp.nic.stack.ndpDisp != nil { 365 ndp.nic.stack.ndpDisp.OnDuplicateAddressDetectionStatus(ndp.nic.ID(), addr, d, err) 366 } 367 }) 368 369 ndp.dad[addr] = dadState{ 370 timer: timer, 371 done: &done, 372 } 373 374 return nil 375 } 376 377 // doDuplicateAddressDetection is called on every iteration of the timer, and 378 // when DAD starts. 379 // 380 // It handles resolving the address (if there are no more NS to send), or 381 // sending the next NS if there are more NS to send. 382 // 383 // This function must only be called by IPv6 addresses that are currently 384 // tentative. 385 // 386 // The NIC that ndp belongs to (n) MUST be locked. 387 // 388 // Returns true if DAD has resolved; false if DAD is still ongoing. 389 func (ndp *ndpState) doDuplicateAddressDetection(addr tcpip.Address, remaining uint8, ref *referencedNetworkEndpoint) (bool, *tcpip.Error) { 390 if ref.getKind() != permanentTentative { 391 // The endpoint should still be marked as tentative 392 // since we are still performing DAD on it. 393 panic(fmt.Sprintf("ndpdad: addr %s is not tentative on NIC(%d)", addr, ndp.nic.ID())) 394 } 395 396 if remaining == 0 { 397 // DAD has resolved. 398 ref.setKind(permanent) 399 return true, nil 400 } 401 402 // Send a new NS. 403 snmc := header.SolicitedNodeAddr(addr) 404 snmcRef, ok := ndp.nic.endpoints[NetworkEndpointID{snmc}] 405 if !ok { 406 // This should never happen as if we have the 407 // address, we should have the solicited-node 408 // address. 409 panic(fmt.Sprintf("ndpdad: NIC(%d) is not in the solicited-node multicast group (%s) but it has addr %s", ndp.nic.ID(), snmc, addr)) 410 } 411 412 // Use the unspecified address as the source address when performing 413 // DAD. 414 r := makeRoute(header.IPv6ProtocolNumber, header.IPv6Any, snmc, ndp.nic.linkEP.LinkAddress(), snmcRef, false, false) 415 416 hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.ICMPv6NeighborSolicitMinimumSize) 417 pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborSolicitMinimumSize)) 418 pkt.SetType(header.ICMPv6NeighborSolicit) 419 ns := header.NDPNeighborSolicit(pkt.NDPPayload()) 420 ns.SetTargetAddress(addr) 421 pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{})) 422 423 sent := r.Stats().ICMP.V6PacketsSent 424 if err := r.WritePacket(nil, NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: header.NDPHopLimit, TOS: DefaultTOS}, tcpip.PacketBuffer{ 425 Header: hdr, 426 }); err != nil { 427 sent.Dropped.Increment() 428 return false, err 429 } 430 sent.NeighborSolicit.Increment() 431 432 return false, nil 433 } 434 435 // stopDuplicateAddressDetection ends a running Duplicate Address Detection 436 // process. Note, this may leave the DAD process for a tentative address in 437 // such a state forever, unless some other external event resolves the DAD 438 // process (receiving an NA from the true owner of addr, or an NS for addr 439 // (implying another node is attempting to use addr)). It is up to the caller 440 // of this function to handle such a scenario. Normally, addr will be removed 441 // from n right after this function returns or the address successfully 442 // resolved. 443 // 444 // The NIC that ndp belongs to MUST be locked. 445 func (ndp *ndpState) stopDuplicateAddressDetection(addr tcpip.Address) { 446 dad, ok := ndp.dad[addr] 447 if !ok { 448 // Not currently performing DAD on addr, just return. 449 return 450 } 451 452 if dad.timer != nil { 453 dad.timer.Stop() 454 dad.timer = nil 455 456 *dad.done = true 457 dad.done = nil 458 } 459 460 delete(ndp.dad, addr) 461 462 // Let the integrator know DAD did not resolve. 463 if ndp.nic.stack.ndpDisp != nil { 464 go ndp.nic.stack.ndpDisp.OnDuplicateAddressDetectionStatus(ndp.nic.ID(), addr, false, nil) 465 } 466 } 467 468 // handleRA handles a Router Advertisement message that arrived on the NIC 469 // this ndp is for. Does nothing if the NIC is configured to not handle RAs. 470 // 471 // The NIC that ndp belongs to and its associated stack MUST be locked. 472 func (ndp *ndpState) handleRA(ip tcpip.Address, ra header.NDPRouterAdvert) { 473 // Is the NIC configured to handle RAs at all? 474 // 475 // Currently, the stack does not determine router interface status on a 476 // per-interface basis; it is a stack-wide configuration, so we check 477 // stack's forwarding flag to determine if the NIC is a routing 478 // interface. 479 if !ndp.configs.HandleRAs || ndp.nic.stack.forwarding { 480 return 481 } 482 483 // Is the NIC configured to discover default routers? 484 if ndp.configs.DiscoverDefaultRouters { 485 rtr, ok := ndp.defaultRouters[ip] 486 rl := ra.RouterLifetime() 487 switch { 488 case !ok && rl != 0: 489 // This is a new default router we are discovering. 490 // 491 // Only remember it if we currently know about less than 492 // MaxDiscoveredDefaultRouters routers. 493 if len(ndp.defaultRouters) < MaxDiscoveredDefaultRouters { 494 ndp.rememberDefaultRouter(ip, rl) 495 } 496 497 case ok && rl != 0: 498 // This is an already discovered default router. Update 499 // the invalidation timer. 500 timer := rtr.invalidationTimer 501 502 // We should ALWAYS have an invalidation timer for a 503 // discovered router. 504 if timer == nil { 505 panic("ndphandlera: RA invalidation timer should not be nil") 506 } 507 508 if !timer.Stop() { 509 // If we reach this point, then we know the 510 // timer fired after we already took the NIC 511 // lock. Inform the timer not to invalidate the 512 // router when it obtains the lock as we just 513 // got a new RA that refreshes its lifetime to a 514 // non-zero value. See 515 // defaultRouterState.doNotInvalidate for more 516 // details. 517 *rtr.doNotInvalidate = true 518 } 519 520 timer.Reset(rl) 521 522 case ok && rl == 0: 523 // We know about the router but it is no longer to be 524 // used as a default router so invalidate it. 525 ndp.invalidateDefaultRouter(ip) 526 } 527 } 528 529 // TODO(b/141556115): Do (RetransTimer, ReachableTime)) Parameter 530 // Discovery. 531 532 // We know the options is valid as far as wire format is concerned since 533 // we got the Router Advertisement, as documented by this fn. Given this 534 // we do not check the iterator for errors on calls to Next. 535 it, _ := ra.Options().Iter(false) 536 for opt, done, _ := it.Next(); !done; opt, done, _ = it.Next() { 537 switch opt.Type() { 538 case header.NDPPrefixInformationType: 539 if !ndp.configs.DiscoverOnLinkPrefixes { 540 continue 541 } 542 543 pi := opt.(header.NDPPrefixInformation) 544 545 prefix := pi.Subnet() 546 547 // Is the prefix a link-local? 548 if header.IsV6LinkLocalAddress(prefix.ID()) { 549 // ...Yes, skip as per RFC 4861 section 6.3.4. 550 continue 551 } 552 553 // Is the Prefix Length 0? 554 if prefix.Prefix() == 0 { 555 // ...Yes, skip as this is an invalid prefix 556 // as all IPv6 addresses cannot be on-link. 557 continue 558 } 559 560 if !pi.OnLinkFlag() { 561 // Not on-link so don't "discover" it as an 562 // on-link prefix. 563 continue 564 } 565 566 prefixState, ok := ndp.onLinkPrefixes[prefix] 567 vl := pi.ValidLifetime() 568 switch { 569 case !ok && vl == 0: 570 // Don't know about this prefix but has a zero 571 // valid lifetime, so just ignore. 572 continue 573 574 case !ok && vl != 0: 575 // This is a new on-link prefix we are 576 // discovering. 577 // 578 // Only remember it if we currently know about 579 // less than MaxDiscoveredOnLinkPrefixes on-link 580 // prefixes. 581 if len(ndp.onLinkPrefixes) < MaxDiscoveredOnLinkPrefixes { 582 ndp.rememberOnLinkPrefix(prefix, vl) 583 } 584 continue 585 586 case ok && vl == 0: 587 // We know about the on-link prefix, but it is 588 // no longer to be considered on-link, so 589 // invalidate it. 590 ndp.invalidateOnLinkPrefix(prefix) 591 continue 592 } 593 594 // This is an already discovered on-link prefix with a 595 // new non-zero valid lifetime. 596 // Update the invalidation timer. 597 timer := prefixState.invalidationTimer 598 599 if timer == nil && vl >= header.NDPPrefixInformationInfiniteLifetime { 600 // Had infinite valid lifetime before and 601 // continues to have an invalid lifetime. Do 602 // nothing further. 603 continue 604 } 605 606 if timer != nil && !timer.Stop() { 607 // If we reach this point, then we know the 608 // timer already fired after we took the NIC 609 // lock. Inform the timer to not invalidate 610 // the prefix once it obtains the lock as we 611 // just got a new PI that refeshes its lifetime 612 // to a non-zero value. See 613 // onLinkPrefixState.doNotInvalidate for more 614 // details. 615 *prefixState.doNotInvalidate = true 616 } 617 618 if vl >= header.NDPPrefixInformationInfiniteLifetime { 619 // Prefix is now valid forever so we don't need 620 // an invalidation timer. 621 prefixState.invalidationTimer = nil 622 ndp.onLinkPrefixes[prefix] = prefixState 623 continue 624 } 625 626 if timer != nil { 627 // We already have a timer so just reset it to 628 // expire after the new valid lifetime. 629 timer.Reset(vl) 630 continue 631 } 632 633 // We do not have a timer so just create a new one. 634 prefixState.invalidationTimer = ndp.prefixInvalidationCallback(prefix, vl, prefixState.doNotInvalidate) 635 ndp.onLinkPrefixes[prefix] = prefixState 636 } 637 638 // TODO(b/141556115): Do (MTU) Parameter Discovery. 639 } 640 } 641 642 // invalidateDefaultRouter invalidates a discovered default router. 643 // 644 // The NIC that ndp belongs to and its associated stack MUST be locked. 645 func (ndp *ndpState) invalidateDefaultRouter(ip tcpip.Address) { 646 rtr, ok := ndp.defaultRouters[ip] 647 648 // Is the router still discovered? 649 if !ok { 650 // ...Nope, do nothing further. 651 return 652 } 653 654 rtr.invalidationTimer.Stop() 655 rtr.invalidationTimer = nil 656 *rtr.doNotInvalidate = true 657 rtr.doNotInvalidate = nil 658 659 delete(ndp.defaultRouters, ip) 660 661 // Let the integrator know a discovered default router is invalidated. 662 if ndp.nic.stack.ndpDisp != nil { 663 ndp.nic.stack.routeTable = ndp.nic.stack.ndpDisp.OnDefaultRouterInvalidated(ndp.nic.ID(), ip) 664 } 665 } 666 667 // rememberDefaultRouter remembers a newly discovered default router with IPv6 668 // link-local address ip with lifetime rl. 669 // 670 // The router identified by ip MUST NOT already be known by the NIC. 671 // 672 // The NIC that ndp belongs to and its associated stack MUST be locked. 673 func (ndp *ndpState) rememberDefaultRouter(ip tcpip.Address, rl time.Duration) { 674 if ndp.nic.stack.ndpDisp == nil { 675 return 676 } 677 678 // Inform the integrator when we discovered a default router. 679 remember, routeTable := ndp.nic.stack.ndpDisp.OnDefaultRouterDiscovered(ndp.nic.ID(), ip) 680 if !remember { 681 // Informed by the integrator to not remember the router, do 682 // nothing further. 683 return 684 } 685 686 // Used to signal the timer not to invalidate the default router (R) in 687 // a race condition. See defaultRouterState.doNotInvalidate for more 688 // details. 689 var doNotInvalidate bool 690 691 ndp.defaultRouters[ip] = defaultRouterState{ 692 invalidationTimer: time.AfterFunc(rl, func() { 693 ndp.nic.stack.mu.Lock() 694 defer ndp.nic.stack.mu.Unlock() 695 ndp.nic.mu.Lock() 696 defer ndp.nic.mu.Unlock() 697 698 if doNotInvalidate { 699 doNotInvalidate = false 700 return 701 } 702 703 ndp.invalidateDefaultRouter(ip) 704 }), 705 doNotInvalidate: &doNotInvalidate, 706 } 707 708 ndp.nic.stack.routeTable = routeTable 709 } 710 711 // rememberOnLinkPrefix remembers a newly discovered on-link prefix with IPv6 712 // address with prefix prefix with lifetime l. 713 // 714 // The prefix identified by prefix MUST NOT already be known. 715 // 716 // The NIC that ndp belongs to and its associated stack MUST be locked. 717 func (ndp *ndpState) rememberOnLinkPrefix(prefix tcpip.Subnet, l time.Duration) { 718 if ndp.nic.stack.ndpDisp == nil { 719 return 720 } 721 722 // Inform the integrator when we discovered an on-link prefix. 723 remember, routeTable := ndp.nic.stack.ndpDisp.OnOnLinkPrefixDiscovered(ndp.nic.ID(), prefix) 724 if !remember { 725 // Informed by the integrator to not remember the prefix, do 726 // nothing further. 727 return 728 } 729 730 // Used to signal the timer not to invalidate the on-link prefix (P) in 731 // a race condition. See onLinkPrefixState.doNotInvalidate for more 732 // details. 733 var doNotInvalidate bool 734 var timer *time.Timer 735 736 // Only create a timer if the lifetime is not infinite. 737 if l < header.NDPPrefixInformationInfiniteLifetime { 738 timer = ndp.prefixInvalidationCallback(prefix, l, &doNotInvalidate) 739 } 740 741 ndp.onLinkPrefixes[prefix] = onLinkPrefixState{ 742 invalidationTimer: timer, 743 doNotInvalidate: &doNotInvalidate, 744 } 745 746 ndp.nic.stack.routeTable = routeTable 747 } 748 749 // invalidateOnLinkPrefix invalidates a discovered on-link prefix. 750 // 751 // The NIC that ndp belongs to and its associated stack MUST be locked. 752 func (ndp *ndpState) invalidateOnLinkPrefix(prefix tcpip.Subnet) { 753 s, ok := ndp.onLinkPrefixes[prefix] 754 755 // Is the on-link prefix still discovered? 756 if !ok { 757 // ...Nope, do nothing further. 758 return 759 } 760 761 if s.invalidationTimer != nil { 762 s.invalidationTimer.Stop() 763 s.invalidationTimer = nil 764 *s.doNotInvalidate = true 765 } 766 767 s.doNotInvalidate = nil 768 769 delete(ndp.onLinkPrefixes, prefix) 770 771 // Let the integrator know a discovered on-link prefix is invalidated. 772 if ndp.nic.stack.ndpDisp != nil { 773 ndp.nic.stack.routeTable = ndp.nic.stack.ndpDisp.OnOnLinkPrefixInvalidated(ndp.nic.ID(), prefix) 774 } 775 } 776 777 // prefixInvalidationCallback returns a new on-link prefix invalidation timer 778 // for prefix that fires after vl. 779 // 780 // doNotInvalidate is used to signal the timer when it fires at the same time 781 // that a prefix's valid lifetime gets refreshed. See 782 // onLinkPrefixState.doNotInvalidate for more details. 783 func (ndp *ndpState) prefixInvalidationCallback(prefix tcpip.Subnet, vl time.Duration, doNotInvalidate *bool) *time.Timer { 784 return time.AfterFunc(vl, func() { 785 ndp.nic.stack.mu.Lock() 786 defer ndp.nic.stack.mu.Unlock() 787 ndp.nic.mu.Lock() 788 defer ndp.nic.mu.Unlock() 789 790 if *doNotInvalidate { 791 *doNotInvalidate = false 792 return 793 } 794 795 ndp.invalidateOnLinkPrefix(prefix) 796 }) 797 }