RIPng Protocol Operation (IPv6 Unicast Routing Protocols) Part 4

Initiate Triggered Update

Listing 1-47

Listing 1-47

1343-1344 A triggered update will be sent immediately if the next regular update is beyond a delay of 5 (RIP_TRIG_INT6_MAX) seconds. The global nextalarm variable records the time when the next regular update will be sent.

This code does not really conform to the protocol specification. [RFC2080] requires that an initial triggered update be delayed for a random interval between 1 and 5 seconds, and that subsequent updates also be delayed until this interval elapses. The idea is to accumulate as many triggered updates as possible before sending a response message containing all the updates in order to reduce overhead and maximize bandwidth utilization. This implementation does not impose the random delay.

1345-1352 Function ripsend() is called to send the update packet on all of the running interfaces except the one on which the response arrived. A running interface has the IFF_UP flag. Since the RRTF_CHANGED flag is given as an argument, ripsend() will send only those routes that carry this change flag, in other words, it will send a triggered update.


1354—1355 The RRTF_CHANGE flag is cleared for all of the recently updated routes once ripsend() returns.

riprequest() Function

Function riprequest() is called to generate a response message for a given request.

Listing 1-48

Listing 1-48

1392—1396 On input ifcp points to the receiving interface. np points to the first RTE in the received message. nn holds the number of RTEs that are present in the request message. sin6 points to the destination to where the response message is to be sent.

1401—1414 The requester is asking for the entire routing table if there is exactly one RTE, the destination prefix is ::/0, and the metric is infinity. The if statement on lines 1401 and 1402 tests to see if the conditions of sending the entire routing table are met. If not, then each of the RTEs in the request message is processed one by one. Function rtsearch() is called to look up the destination prefix in the local routing table by exact matching(*). If an entry is found then the metric value of that entry is stored in the RTE. Otherwise, the metric is set to infinity (16) to indicate the route is missing in the router’s routing table.

(*): It is not clear from the specification [RFC2080] whether this should be an exact match or a longest prefix match.

Function sendpacket() is called to transmit the response packet once all of the RTEs have been processed.

1417 Function ripsend() is called to send the entire routing table.

ripsend() Function

Function ripsend() is called to generate and transmit a RIPng response packet. A RIPng response packet is generated for one of the following reasons:

• A router sends its entire routing table every 30 seconds (with some random offset).

• A router sends a response packet due to triggered updates.

• A router sends the entire routing table due to an explicit request.

Function riprequest() handles the case where route6d daemon sends a response packet in reply to an explicit query of specific IPv6 destination prefixes (see Section 1.13.3).

Listing 1-49

Listing 1-49

789—793 On input, ifcp points to the interface associated with a directly attached network on which the response would be sent. sin6 points to the destination address of the response packet. flag contains the output filter flags.

Listing 1-50

Listing 1-50

799—800 The local node is in the quiet mode, which only listens to RIPng advertisements if the qflag is set to 1. In this case, ripsend() returns here without taking further action.

Listing 1-51

Listing 1-51

 

 

 

 

Listing 1-51

802—826 The ifcp pointer may be NULL if the kernel was not able to allocate an ancillary data object to return the received packet information back to the caller of recvmsg().

The code comment sounds as if the packet comes from an off-link node in this case, but this is not always correct; ifcp can be NULL for an on-link request, too. Even if the packet is sent from an off-link node, the protocol specification does not require such requests to be processed differently, so the code in the rest of this block does not conform to the specification. In particular, skipping the split horizon algorithm and configured route filters for an on-link request will cause an undesirable routing effect and should be considered a bug. This block of code should therefore be removed and the caller should make sure that a valid ifp pointer is provided. Further discussion on the rest of the block is omitted.

Listing 1-52

Listing 1-52

828-830 The response packet is not sent on the loopback interface unless the RRTF_SENDANYWAY flag is set by the caller.5 This flag is set when route6d is sending a response message to a request (see Listing 1-48), in which case another process in the local node, such as a monitoring process, may have sent the request and it must be responded to.

Listing 1-53

Listing 1-53

832-834 As discussed in Listing 1-35,the -N option prevents route6d from advertising RIPng routes on specific interfaces. The ripsend() function returns here if iff_find() indicates that the given interface ifcp is in the exclusion list.

Listing 1-54

Listing 1-54

837—850 The -T option instructs route6d to generate only a default route on a given interface. If function iff_find() determines the -T option applies to the given interface represented by ifcp, then a default route is built and is sent by ripflush().

The global variable routetag is initialized by the -t option, which specifies a route tag to be assigned to all routes that are originated by the local route6d daemon.

Again, the route metric is the sum of the hop count and the ifc_metric value. The hop count is set to 1.

Listing 1-55

Listing 1-55

852—855 maxrte is calculated according to the formula given by Equation 1.1.The link MTU is retrieved from the output interface.

Computing maxrte based on the link MTU may not be reasonable when this response message is sent as a result of a request message (i.e., not a regular or triggered update), because in this case the packet may be sent off-link and there may be an intermediate link with a smaller MTU. It should be safer to use the IPv6 minimum link MTU (1280 bytes) for off-link destinations. 

Listing 1-56

Listing 1-56

857 Variables nrt and np are globally accessible in route6d.c and are shared with other routines; nrt is the number of RTEs contained in the response message, and np points to the netinfo6{} structure that is currently built in the message buffer. Both variables will be updated as the message construction proceeds. A global buffer ripbuf,is used as a work space to construct the response message. When non-NULL, nh points to an in6_addr{} structure of the next hop address of particular route destinations.

858 Each entry in the routing table (rrt) is now examined in the for loop; some are used to add an RTE in the response message, and others are filtered based on the filtering configuration or the property of the route. Figure 1-53 shows the relationship between the routing table and the actual response message with the initial setting of related parameters.

859-860 Any route that is explicitly marked with the RRTF_NOADVERTISE flag will not be advertised and is bypassed here.

Listing 1-57

Listing 1-57

863-864 The function out_filter() (not described in this topic) is called to determine if an additional filter on the output interface applies to the route. A return value of 0 indicates out_filter() has filtered the route, so the route is bypassed.

Listing 1-58

Listing 1-58

FIGURE 1-53

FIGURE 1-53

867—868 The tobeadv() function (not described in this topic) examines the given route and determines if the route should be filtered by the split horizon algorithm, or if the route should be filtered because it is a manually installed route with the reject or blackhole flag. In these cases tobeadv() returns 0, and this route entry is ignored.

Listing 1-59

Listing 1-59

871—873 If ripsend() is currently called to send triggered updates, which is indicated by the RRTF_CHANGED flag (see Listing 1-47), then only those routes that have been modified recently will be included in this response, while all other routes are bypassed.

Listing 1-60

Listing 1-60

876-878 This block of the code checks to see if the next hop address should be explicitly specified as a separate RTE and includes the RTE when necessary. The purpose of such explicit next hop information is to optimize a redundant forwarding path within a single link. Consider the network topology shown in Figure 1-54, where routers A and B exchange routes via RIPng while router C does not advertise any routes by itself. It is also assumed that router C is connected to a different network identified by the prefix 2001:db8:1::/48 and router A configures a static route to the network. Since router B does not know how to route packets to 2001:db8:1::/48, router A must advertise this route. Router A could advertise the route just like other routes so that router B would forward subsequent packets to router A, but router A can tell B the better path by the use of next hop RTE with a link-local address of C in the shared link.

Usually the tobeadv() function filters a route entry if its outgoing interface is equal to the interface to which the RIPng response is going to be sent; so if the if condition on line 876 is met, it is likely to be a statically configured route which should be advertised with an explicit next hop. [RFC2080] requires the next hop address to be a link-local address, which is checked in the subsequent conditions of the if statement.

FIGURE 1-54

FIGURE 1-54

There are two other, probably unintended cases where these conditions hold when the tobeadv() function skips filtering by the split horizon algorithm. One case is that the route was learned from another router on the link via RIPng. The other case is that the route is a direct route to the interface associated with an address configured on the interface.

But supporting these cases does not really make sense. The first case is to disable split horizon, but in that case the route should simply be readvertised as a route from this router, rather than specifying the next hop. In the second case, rrt_gw is not a link-local address,and will be treated as the unspecified address by the receiver; it does not make sense because the purpose of the explicit next hop is to optimize the forwarding path for the destination.

This block of code should be revised so that only the intended cases will be covered.

879 Variable nh remembers the current next hop. If it is currently not specified or a different next hop is specified, a new next hop RTE must be included.

880—881 A buffer space for at least two RTEs must be available, one for setting the next hop, the other for at least one route entry to which the next hop applies. The ripflush() function is called to transmit the accumulated routes if the space is insufficient. Note that ripflush() will reset np and nrt.

882—890 The RTE is filled with the next hop information as shown in Figure 1-12.

Listing 1-61

Listing 1-61

891—900 The else case holds if the route goes to a different link or the route is configured with a non link-local gateway address, which is probably statically configured. If, in addition, an explicit next hop is specified, it is reset here to the unspecified address, meaning this local router. It will allow the receiving routers to use the link-local address of the local router as the next hop for the advertised routes.

The latter part of the else if condition should always hold and is redundant; it should suffice to check nh. This check may have intended to allow the local router to specify itself for a route entry with a non link-local address, but this code does not fully implement the possible intent because this block is effective only when a next hop was previously specified.

Listing 1-62

Listing 1-62

904—909 The route is copied into the output buffer and if the number of accumulated routes has reached the maximum, ripflush() is called to transmit the RIPng response message.

911—912 The remaining portion of the output buffer, if any, is sent out by ripflush().

ripalarm() Function

The ripalarm() function is invoked about every 30 seconds (with some random offsets) to transmit the entire routing table. The route lifetime (RIP_LIFETIME, 180 seconds) and holddown time (rip_HOLDDOWN, 30 seconds) are updated in this function, which makes sense because these are multiples of this call interval.

Listing 1-63

Listing 1-63

572—573 Since rrt_t is not updated after its initialization, t_lifetime and t_holddown calculate the lifetime and holddown times in the reverse to determine expiration.

574—575 Every entry in the route6d routing table is examined to see if one of the two timers has expired.

577—579 A route entry that has rrt_t being 0 indicates a static route entry. Static route entries do not expire and are bypassed in this function.

581—590 If the holddown timer has expired for a route entry, function delroute() is called to delete this route entry from the kernel routing table. The memory associated with the deleted route entry is freed. If rrt_prev is NULL, then the first entry in the routing table is being deleted, so riprt is also updated.

591—592 If the route entry has expired, its metric is set to infinity (metric of 16) indicating the destination is no longer reachable.

596—599 A RIPng response message is generated for each directly connected network. The function ripsend() is called to send the RIPng response message on each active interface. Since the message is a regular update, the response message is sent to the all-rip-routers multicast address.

600 The interval timer is re-armed here. The ripinterval() function provides the timer interval based on the requirement of [RFC2080] to avoid synchronized updates among multiple routers. Specifically, it returns the standard interval (SUPPLY_INTERVAL6, which is 30) ±randomtime where randomtime is between 0 and 15. It also sets the global variable nextalarm to the next expiration time of the timer.

Next post:

Previous post: