version 1.1.1.2, 2013/07/21 23:54:40
|
version 1.1.1.3, 2016/11/02 10:09:10
|
Line 61 long rip_global_route_changes = 0;
|
Line 61 long rip_global_route_changes = 0;
|
|
|
/* RIP queries. */ |
/* RIP queries. */ |
long rip_global_queries = 0; |
long rip_global_queries = 0; |
| |
/* Prototypes. */ |
/* Prototypes. */ |
static void rip_event (enum rip_event, int); |
static void rip_event (enum rip_event, int); |
static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char); |
static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char); |
static int rip_triggered_update (struct thread *); |
static int rip_triggered_update (struct thread *); |
static int rip_update_jitter (unsigned long); |
static int rip_update_jitter (unsigned long); |
| |
/* RIP output routes type. */ |
/* RIP output routes type. */ |
enum |
enum |
{ |
{ |
rip_all_route, |
rip_all_route, |
rip_changed_route |
rip_changed_route |
}; |
}; |
| |
/* RIP command strings. */ |
/* RIP command strings. */ |
static const struct message rip_msg[] = |
static const struct message rip_msg[] = |
{ |
{ |
Line 86 static const struct message rip_msg[] =
|
Line 86 static const struct message rip_msg[] =
|
{RIP_POLL_ENTRY, "POLL ENTRY"}, |
{RIP_POLL_ENTRY, "POLL ENTRY"}, |
{0, NULL}, |
{0, NULL}, |
}; |
}; |
| |
/* Utility function to set boradcast option to the socket. */ |
/* Utility function to set boradcast option to the socket. */ |
static int |
static int |
sockopt_broadcast (int sock) |
sockopt_broadcast (int sock) |
Line 138 rip_garbage_collect (struct thread *t)
|
Line 138 rip_garbage_collect (struct thread *t)
|
rp = rinfo->rp; |
rp = rinfo->rp; |
|
|
/* Unlock route_node. */ |
/* Unlock route_node. */ |
rp->info = NULL; | listnode_delete (rp->info, rinfo); |
route_unlock_node (rp); | if (list_isempty ((struct list *)rp->info)) |
| { |
| list_free (rp->info); |
| rp->info = NULL; |
| route_unlock_node (rp); |
| } |
|
|
/* Free RIP routing information. */ |
/* Free RIP routing information. */ |
rip_info_free (rinfo); |
rip_info_free (rinfo); |
Line 147 rip_garbage_collect (struct thread *t)
|
Line 152 rip_garbage_collect (struct thread *t)
|
return 0; |
return 0; |
} |
} |
|
|
/* Timeout RIP routes. */ | static void rip_timeout_update (struct rip_info *rinfo); |
static int | |
rip_timeout (struct thread *t) | /* Add new route to the ECMP list. |
| * RETURN: the new entry added in the list, or NULL if it is not the first |
| * entry and ECMP is not allowed. |
| */ |
| struct rip_info * |
| rip_ecmp_add (struct rip_info *rinfo_new) |
{ |
{ |
struct rip_info *rinfo; | struct route_node *rp = rinfo_new->rp; |
struct route_node *rn; | struct rip_info *rinfo = NULL; |
| struct list *list = NULL; |
|
|
rinfo = THREAD_ARG (t); | if (rp->info == NULL) |
rinfo->t_timeout = NULL; | rp->info = list_new (); |
| list = (struct list *)rp->info; |
|
|
rn = rinfo->rp; | /* If ECMP is not allowed and some entry already exists in the list, |
| * do nothing. */ |
| if (listcount (list) && !rip->ecmp) |
| return NULL; |
|
|
/* - The garbage-collection timer is set for 120 seconds. */ | rinfo = rip_info_new (); |
RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, | memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); |
rip->garbage_time); | listnode_add (list, rinfo); |
|
|
rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop, | if (rip_route_rte (rinfo)) |
rinfo->metric); | { |
/* - The metric for the route is set to 16 (infinity). This causes | rip_timeout_update (rinfo); |
the route to be removed from service. */ | rip_zebra_ipv4_add (rp); |
rinfo->metric = RIP_METRIC_INFINITY; | } |
rinfo->flags &= ~RIP_RTF_FIB; | |
|
|
/* - The route change flag is to indicate that this entry has been | /* Set the route change flag on the first entry. */ |
changed. */ | rinfo = listgetdata (listhead (list)); |
rinfo->flags |= RIP_RTF_CHANGED; | SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); |
|
|
/* - The output process is signalled to trigger a response. */ | /* Signal the output process to trigger an update (see section 2.5). */ |
rip_event (RIP_TRIGGERED_UPDATE, 0); |
rip_event (RIP_TRIGGERED_UPDATE, 0); |
|
|
|
return rinfo; |
|
} |
|
|
|
/* Replace the ECMP list with the new route. |
|
* RETURN: the new entry added in the list |
|
*/ |
|
struct rip_info * |
|
rip_ecmp_replace (struct rip_info *rinfo_new) |
|
{ |
|
struct route_node *rp = rinfo_new->rp; |
|
struct list *list = (struct list *)rp->info; |
|
struct rip_info *rinfo = NULL, *tmp_rinfo = NULL; |
|
struct listnode *node = NULL, *nextnode = NULL; |
|
|
|
if (list == NULL || listcount (list) == 0) |
|
return rip_ecmp_add (rinfo_new); |
|
|
|
/* Get the first entry */ |
|
rinfo = listgetdata (listhead (list)); |
|
|
|
/* Learnt route replaced by a local one. Delete it from zebra. */ |
|
if (rip_route_rte (rinfo) && !rip_route_rte (rinfo_new)) |
|
if (CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) |
|
rip_zebra_ipv4_delete (rp); |
|
|
|
/* Re-use the first entry, and delete the others. */ |
|
for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) |
|
if (tmp_rinfo != rinfo) |
|
{ |
|
RIP_TIMER_OFF (tmp_rinfo->t_timeout); |
|
RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); |
|
list_delete_node (list, node); |
|
rip_info_free (tmp_rinfo); |
|
} |
|
|
|
RIP_TIMER_OFF (rinfo->t_timeout); |
|
RIP_TIMER_OFF (rinfo->t_garbage_collect); |
|
memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); |
|
|
|
if (rip_route_rte (rinfo)) |
|
{ |
|
rip_timeout_update (rinfo); |
|
/* The ADD message implies an update. */ |
|
rip_zebra_ipv4_add (rp); |
|
} |
|
|
|
/* Set the route change flag. */ |
|
SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); |
|
|
|
/* Signal the output process to trigger an update (see section 2.5). */ |
|
rip_event (RIP_TRIGGERED_UPDATE, 0); |
|
|
|
return rinfo; |
|
} |
|
|
|
/* Delete one route from the ECMP list. |
|
* RETURN: |
|
* null - the entry is freed, and other entries exist in the list |
|
* the entry - the entry is the last one in the list; its metric is set |
|
* to INFINITY, and the garbage collector is started for it |
|
*/ |
|
struct rip_info * |
|
rip_ecmp_delete (struct rip_info *rinfo) |
|
{ |
|
struct route_node *rp = rinfo->rp; |
|
struct list *list = (struct list *)rp->info; |
|
|
|
RIP_TIMER_OFF (rinfo->t_timeout); |
|
|
|
if (listcount (list) > 1) |
|
{ |
|
/* Some other ECMP entries still exist. Just delete this entry. */ |
|
RIP_TIMER_OFF (rinfo->t_garbage_collect); |
|
listnode_delete (list, rinfo); |
|
if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) |
|
/* The ADD message implies the update. */ |
|
rip_zebra_ipv4_add (rp); |
|
rip_info_free (rinfo); |
|
rinfo = NULL; |
|
} |
|
else |
|
{ |
|
assert (rinfo == listgetdata (listhead (list))); |
|
|
|
/* This is the only entry left in the list. We must keep it in |
|
* the list for garbage collection time, with INFINITY metric. */ |
|
|
|
rinfo->metric = RIP_METRIC_INFINITY; |
|
RIP_TIMER_ON (rinfo->t_garbage_collect, |
|
rip_garbage_collect, rip->garbage_time); |
|
|
|
if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) |
|
rip_zebra_ipv4_delete (rp); |
|
} |
|
|
|
/* Set the route change flag on the first entry. */ |
|
rinfo = listgetdata (listhead (list)); |
|
SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); |
|
|
|
/* Signal the output process to trigger an update (see section 2.5). */ |
|
rip_event (RIP_TRIGGERED_UPDATE, 0); |
|
|
|
return rinfo; |
|
} |
|
|
|
/* Timeout RIP routes. */ |
|
static int |
|
rip_timeout (struct thread *t) |
|
{ |
|
rip_ecmp_delete ((struct rip_info *)THREAD_ARG (t)); |
return 0; |
return 0; |
} |
} |
|
|
Line 365 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
Line 489 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
int ret; |
int ret; |
struct prefix_ipv4 p; |
struct prefix_ipv4 p; |
struct route_node *rp; |
struct route_node *rp; |
struct rip_info *rinfo, rinfotmp; | struct rip_info *rinfo = NULL, newinfo; |
struct rip_interface *ri; |
struct rip_interface *ri; |
struct in_addr *nexthop; |
struct in_addr *nexthop; |
u_char oldmetric; |
|
int same = 0; |
int same = 0; |
int route_reuse = 0; |
|
unsigned char old_dist, new_dist; |
unsigned char old_dist, new_dist; |
|
struct list *list = NULL; |
|
struct listnode *node = NULL; |
|
|
/* Make prefix structure. */ |
/* Make prefix structure. */ |
memset (&p, 0, sizeof (struct prefix_ipv4)); |
memset (&p, 0, sizeof (struct prefix_ipv4)); |
Line 389 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
Line 513 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
if (ret < 0) |
if (ret < 0) |
return; |
return; |
|
|
|
memset (&newinfo, 0, sizeof (newinfo)); |
|
newinfo.type = ZEBRA_ROUTE_RIP; |
|
newinfo.sub_type = RIP_ROUTE_RTE; |
|
newinfo.nexthop = rte->nexthop; |
|
newinfo.from = from->sin_addr; |
|
newinfo.ifindex = ifp->ifindex; |
|
newinfo.metric = rte->metric; |
|
newinfo.metric_out = rte->metric; /* XXX */ |
|
newinfo.tag = ntohs (rte->tag); /* XXX */ |
|
|
/* Modify entry according to the interface routemap. */ |
/* Modify entry according to the interface routemap. */ |
if (ri->routemap[RIP_FILTER_IN]) |
if (ri->routemap[RIP_FILTER_IN]) |
{ |
{ |
int ret; |
int ret; |
struct rip_info newinfo; |
|
|
|
memset (&newinfo, 0, sizeof (newinfo)); |
|
newinfo.type = ZEBRA_ROUTE_RIP; |
|
newinfo.sub_type = RIP_ROUTE_RTE; |
|
newinfo.nexthop = rte->nexthop; |
|
newinfo.from = from->sin_addr; |
|
newinfo.ifindex = ifp->ifindex; |
|
newinfo.metric = rte->metric; |
|
newinfo.metric_out = rte->metric; /* XXX */ |
|
newinfo.tag = ntohs (rte->tag); /* XXX */ |
|
|
|
/* The object should be of the type of rip_info */ |
/* The object should be of the type of rip_info */ |
ret = route_map_apply (ri->routemap[RIP_FILTER_IN], |
ret = route_map_apply (ri->routemap[RIP_FILTER_IN], |
(struct prefix *) &p, RMAP_RIP, &newinfo); |
(struct prefix *) &p, RMAP_RIP, &newinfo); |
Line 433 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
Line 556 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
/* If offset-list does not modify the metric use interface's |
/* If offset-list does not modify the metric use interface's |
metric. */ |
metric. */ |
if (!ret) |
if (!ret) |
rte->metric += ifp->metric; | rte->metric += ifp->metric ? ifp->metric : 1; |
|
|
if (rte->metric > RIP_METRIC_INFINITY) |
if (rte->metric > RIP_METRIC_INFINITY) |
rte->metric = RIP_METRIC_INFINITY; |
rte->metric = RIP_METRIC_INFINITY; |
Line 455 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
Line 578 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
/* Get index for the prefix. */ |
/* Get index for the prefix. */ |
rp = route_node_get (rip->table, (struct prefix *) &p); |
rp = route_node_get (rip->table, (struct prefix *) &p); |
|
|
|
newinfo.rp = rp; |
|
newinfo.nexthop = *nexthop; |
|
newinfo.metric = rte->metric; |
|
newinfo.tag = ntohs (rte->tag); |
|
newinfo.distance = rip_distance_apply (&newinfo); |
|
|
|
new_dist = newinfo.distance ? newinfo.distance : ZEBRA_RIP_DISTANCE_DEFAULT; |
|
|
/* Check to see whether there is already RIP route on the table. */ |
/* Check to see whether there is already RIP route on the table. */ |
rinfo = rp->info; | if ((list = rp->info) != NULL) |
| for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) |
| { |
| /* Need to compare with redistributed entry or local entry */ |
| if (!rip_route_rte (rinfo)) |
| break; |
|
|
|
if (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) && |
|
IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) |
|
break; |
|
|
|
if (!listnextnode (node)) |
|
{ |
|
/* Not found in the list */ |
|
|
|
if (rte->metric > rinfo->metric) |
|
{ |
|
/* New route has a greater metric. Discard it. */ |
|
route_unlock_node (rp); |
|
return; |
|
} |
|
|
|
if (rte->metric < rinfo->metric) |
|
/* New route has a smaller metric. Replace the ECMP list |
|
* with the new one in below. */ |
|
break; |
|
|
|
/* Metrics are same. We compare the distances. */ |
|
old_dist = rinfo->distance ? \ |
|
rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; |
|
|
|
if (new_dist > old_dist) |
|
{ |
|
/* New route has a greater distance. Discard it. */ |
|
route_unlock_node (rp); |
|
return; |
|
} |
|
|
|
if (new_dist < old_dist) |
|
/* New route has a smaller distance. Replace the ECMP list |
|
* with the new one in below. */ |
|
break; |
|
|
|
/* Metrics and distances are both same. Keep "rinfo" null and |
|
* the new route is added in the ECMP list in below. */ |
|
} |
|
} |
|
|
if (rinfo) |
if (rinfo) |
{ |
{ |
/* Local static route. */ |
/* Local static route. */ |
Line 474 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
Line 651 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
if (rinfo->type != ZEBRA_ROUTE_RIP |
if (rinfo->type != ZEBRA_ROUTE_RIP |
&& rinfo->metric != RIP_METRIC_INFINITY) |
&& rinfo->metric != RIP_METRIC_INFINITY) |
{ |
{ |
/* Fill in a minimaly temporary rip_info structure, for a future |
|
rip_distance_apply() use) */ |
|
memset (&rinfotmp, 0, sizeof (rinfotmp)); |
|
IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr); |
|
rinfotmp.rp = rinfo->rp; |
|
new_dist = rip_distance_apply (&rinfotmp); |
|
new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT; |
|
old_dist = rinfo->distance; |
old_dist = rinfo->distance; |
/* Only connected routes may have a valid NULL distance */ | /* Only routes directly connected to an interface (nexthop == 0) |
if (rinfo->type != ZEBRA_ROUTE_CONNECT) | * may have a valid NULL distance */ |
| if (rinfo->nexthop.s_addr != 0) |
old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT; |
old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT; |
/* If imported route does not have STRICT precedence, |
/* If imported route does not have STRICT precedence, |
mark it as a ghost */ |
mark it as a ghost */ |
if (new_dist > old_dist | if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY) |
|| rte->metric == RIP_METRIC_INFINITY) | rip_ecmp_replace (&newinfo); |
{ | |
route_unlock_node (rp); | route_unlock_node (rp); |
return; | return; |
} | |
else | |
{ | |
RIP_TIMER_OFF (rinfo->t_timeout); | |
RIP_TIMER_OFF (rinfo->t_garbage_collect); | |
| |
rp->info = NULL; | |
if (rip_route_rte (rinfo)) | |
rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, | |
&rinfo->nexthop, rinfo->metric); | |
rip_info_free (rinfo); | |
rinfo = NULL; | |
route_reuse = 1; | |
} | |
} |
} |
} |
} |
|
|
if (!rinfo) |
if (!rinfo) |
{ |
{ |
|
if (rp->info) |
|
route_unlock_node (rp); |
|
|
/* Now, check to see whether there is already an explicit route |
/* Now, check to see whether there is already an explicit route |
for the destination prefix. If there is no such route, add |
for the destination prefix. If there is no such route, add |
this route to the routing table, unless the metric is |
this route to the routing table, unless the metric is |
infinity (there is no point in adding a route which |
infinity (there is no point in adding a route which |
unusable). */ |
unusable). */ |
if (rte->metric != RIP_METRIC_INFINITY) |
if (rte->metric != RIP_METRIC_INFINITY) |
{ | rip_ecmp_add (&newinfo); |
rinfo = rip_info_new (); | |
| |
/* - Setting the destination prefix and length to those in | |
the RTE. */ | |
rinfo->rp = rp; | |
| |
/* - Setting the metric to the newly calculated metric (as | |
described above). */ | |
rinfo->metric = rte->metric; | |
rinfo->tag = ntohs (rte->tag); | |
| |
/* - Set the next hop address to be the address of the router | |
from which the datagram came or the next hop address | |
specified by a next hop RTE. */ | |
IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); | |
IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); | |
rinfo->ifindex = ifp->ifindex; | |
| |
/* - Initialize the timeout for the route. If the | |
garbage-collection timer is running for this route, stop it | |
(see section 2.3 for a discussion of the timers). */ | |
rip_timeout_update (rinfo); | |
| |
/* - Set the route change flag. */ | |
rinfo->flags |= RIP_RTF_CHANGED; | |
| |
/* - Signal the output process to trigger an update (see section | |
2.5). */ | |
rip_event (RIP_TRIGGERED_UPDATE, 0); | |
| |
/* Finally, route goes into the kernel. */ | |
rinfo->type = ZEBRA_ROUTE_RIP; | |
rinfo->sub_type = RIP_ROUTE_RTE; | |
| |
/* Set distance value. */ | |
rinfo->distance = rip_distance_apply (rinfo); | |
| |
rp->info = rinfo; | |
rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric, | |
rinfo->distance); | |
rinfo->flags |= RIP_RTF_FIB; | |
} | |
| |
/* Unlock temporary lock, i.e. same behaviour */ | |
if (route_reuse) | |
route_unlock_node (rp); | |
} |
} |
else |
else |
{ |
{ |
/* Route is there but we are not sure the route is RIP or not. */ |
/* Route is there but we are not sure the route is RIP or not. */ |
rinfo = rp->info; |
|
|
|
/* If there is an existing route, compare the next hop address |
/* If there is an existing route, compare the next hop address |
to the address of the router from which the datagram came. |
to the address of the router from which the datagram came. |
Line 577 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
Line 690 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) |
same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) |
&& (rinfo->ifindex == ifp->ifindex)); |
&& (rinfo->ifindex == ifp->ifindex)); |
|
|
if (same) | old_dist = rinfo->distance ? \ |
rip_timeout_update (rinfo); | rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; |
|
|
|
|
/* Fill in a minimaly temporary rip_info structure, for a future |
|
rip_distance_apply() use) */ |
|
memset (&rinfotmp, 0, sizeof (rinfotmp)); |
|
IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr); |
|
rinfotmp.rp = rinfo->rp; |
|
|
|
|
|
/* Next, compare the metrics. If the datagram is from the same |
/* Next, compare the metrics. If the datagram is from the same |
router as the existing route, and the new metric is different |
router as the existing route, and the new metric is different |
than the old one; or, if the new metric is lower than the old |
than the old one; or, if the new metric is lower than the old |
Line 598 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
Line 703 rip_rte_process (struct rte *rte, struct sockaddr_in *
|
|| (rte->metric < rinfo->metric) |
|| (rte->metric < rinfo->metric) |
|| ((same) |
|| ((same) |
&& (rinfo->metric == rte->metric) |
&& (rinfo->metric == rte->metric) |
&& ntohs (rte->tag) != rinfo->tag) | && (newinfo.tag != rinfo->tag)) |
|| (rinfo->distance > rip_distance_apply (&rinfotmp)) | || (old_dist > new_dist) |
|| ((rinfo->distance != rip_distance_apply (rinfo)) && same)) | || ((old_dist != new_dist) && same)) |
{ |
{ |
/* - Adopt the route from the datagram. That is, put the | if (listcount (list) == 1) |
new metric in, and adjust the next hop address (if | |
necessary). */ | |
oldmetric = rinfo->metric; | |
rinfo->metric = rte->metric; | |
rinfo->tag = ntohs (rte->tag); | |
IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); | |
rinfo->ifindex = ifp->ifindex; | |
rinfo->distance = rip_distance_apply (rinfo); | |
| |
/* Should a new route to this network be established | |
while the garbage-collection timer is running, the | |
new route will replace the one that is about to be | |
deleted. In this case the garbage-collection timer | |
must be cleared. */ | |
| |
if (oldmetric == RIP_METRIC_INFINITY && | |
rinfo->metric < RIP_METRIC_INFINITY) | |
{ |
{ |
rinfo->type = ZEBRA_ROUTE_RIP; | if (newinfo.metric != RIP_METRIC_INFINITY) |
rinfo->sub_type = RIP_ROUTE_RTE; | rip_ecmp_replace (&newinfo); |
| else |
RIP_TIMER_OFF (rinfo->t_garbage_collect); | rip_ecmp_delete (rinfo); |
| |
if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) | |
IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); | |
| |
rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, | |
rinfo->distance); | |
rinfo->flags |= RIP_RTF_FIB; | |
} |
} |
| else |
/* Update nexthop and/or metric value. */ | |
if (oldmetric != RIP_METRIC_INFINITY) | |
{ |
{ |
rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); | if (newinfo.metric < rinfo->metric) |
rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, | rip_ecmp_replace (&newinfo); |
rinfo->distance); | else if (newinfo.metric > rinfo->metric) |
rinfo->flags |= RIP_RTF_FIB; | rip_ecmp_delete (rinfo); |
| else if (new_dist < old_dist) |
| rip_ecmp_replace (&newinfo); |
| else if (new_dist > old_dist) |
| rip_ecmp_delete (rinfo); |
| else |
| { |
| int update = CHECK_FLAG (rinfo->flags, RIP_RTF_FIB) ? 1 : 0; |
|
|
if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) | assert (newinfo.metric != RIP_METRIC_INFINITY); |
IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); | |
} | |
|
|
/* - Set the route change flag and signal the output process |
|
to trigger an update. */ |
|
rinfo->flags |= RIP_RTF_CHANGED; |
|
rip_event (RIP_TRIGGERED_UPDATE, 0); |
|
|
|
/* - If the new metric is infinity, start the deletion |
|
process (described above); */ |
|
if (rinfo->metric == RIP_METRIC_INFINITY) |
|
{ |
|
/* If the new metric is infinity, the deletion process |
|
begins for the route, which is no longer used for |
|
routing packets. Note that the deletion process is |
|
started only when the metric is first set to |
|
infinity. If the metric was already infinity, then a |
|
new deletion process is not started. */ |
|
if (oldmetric != RIP_METRIC_INFINITY) |
|
{ |
|
/* - The garbage-collection timer is set for 120 seconds. */ |
|
RIP_TIMER_ON (rinfo->t_garbage_collect, |
|
rip_garbage_collect, rip->garbage_time); |
|
RIP_TIMER_OFF (rinfo->t_timeout); |
RIP_TIMER_OFF (rinfo->t_timeout); |
|
RIP_TIMER_OFF (rinfo->t_garbage_collect); |
|
memcpy (rinfo, &newinfo, sizeof (struct rip_info)); |
|
rip_timeout_update (rinfo); |
|
|
/* - The metric for the route is set to 16 | if (update) |
(infinity). This causes the route to be removed | rip_zebra_ipv4_add (rp); |
from service. */ | |
rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); | |
rinfo->flags &= ~RIP_RTF_FIB; | |
|
|
/* - The route change flag is to indicate that this | /* - Set the route change flag on the first entry. */ |
entry has been changed. */ | rinfo = listgetdata (listhead (list)); |
/* - The output process is signalled to trigger a | SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); |
response. */ | rip_event (RIP_TRIGGERED_UPDATE, 0); |
; /* Above processes are already done previously. */ | |
} |
} |
} |
} |
else |
|
{ |
|
/* otherwise, re-initialize the timeout. */ |
|
rip_timeout_update (rinfo); |
|
} |
|
} |
} |
|
else /* same & no change */ |
|
rip_timeout_update (rinfo); |
|
|
/* Unlock tempolary lock of the route. */ |
/* Unlock tempolary lock of the route. */ |
route_unlock_node (rp); |
route_unlock_node (rp); |
} |
} |
Line 1107 rip_response_process (struct rip_packet *packet, int s
|
Line 1168 rip_response_process (struct rip_packet *packet, int s
|
struct prefix_ipv4 ifaddr; |
struct prefix_ipv4 ifaddr; |
struct prefix_ipv4 ifaddrclass; |
struct prefix_ipv4 ifaddrclass; |
int subnetted; |
int subnetted; |
| |
| memset(&ifaddr, 0, sizeof(ifaddr)); |
/* We don't know yet. */ |
/* We don't know yet. */ |
subnetted = -1; |
subnetted = -1; |
|
|
Line 1515 rip_send_packet (u_char * buf, int size, struct sockad
|
Line 1577 rip_send_packet (u_char * buf, int size, struct sockad
|
/* Add redistributed route to RIP table. */ |
/* Add redistributed route to RIP table. */ |
void |
void |
rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, |
rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, |
unsigned int ifindex, struct in_addr *nexthop, | ifindex_t ifindex, struct in_addr *nexthop, |
unsigned int metric, unsigned char distance) |
unsigned int metric, unsigned char distance) |
{ |
{ |
int ret; |
int ret; |
struct route_node *rp; | struct route_node *rp = NULL; |
struct rip_info *rinfo; | struct rip_info *rinfo = NULL, newinfo; |
| struct list *list = NULL; |
|
|
/* Redistribute route */ |
/* Redistribute route */ |
ret = rip_destination_check (p->prefix); |
ret = rip_destination_check (p->prefix); |
Line 1529 rip_redistribute_add (int type, int sub_type, struct p
|
Line 1592 rip_redistribute_add (int type, int sub_type, struct p
|
|
|
rp = route_node_get (rip->table, (struct prefix *) p); |
rp = route_node_get (rip->table, (struct prefix *) p); |
|
|
rinfo = rp->info; | memset (&newinfo, 0, sizeof (struct rip_info)); |
| newinfo.type = type; |
| newinfo.sub_type = sub_type; |
| newinfo.ifindex = ifindex; |
| newinfo.metric = 1; |
| newinfo.external_metric = metric; |
| newinfo.distance = distance; |
| newinfo.rp = rp; |
| if (nexthop) |
| newinfo.nexthop = *nexthop; |
|
|
if (rinfo) | if ((list = rp->info) != NULL && listcount (list) != 0) |
{ |
{ |
|
rinfo = listgetdata (listhead (list)); |
|
|
if (rinfo->type == ZEBRA_ROUTE_CONNECT |
if (rinfo->type == ZEBRA_ROUTE_CONNECT |
&& rinfo->sub_type == RIP_ROUTE_INTERFACE |
&& rinfo->sub_type == RIP_ROUTE_INTERFACE |
&& rinfo->metric != RIP_METRIC_INFINITY) |
&& rinfo->metric != RIP_METRIC_INFINITY) |
Line 1554 rip_redistribute_add (int type, int sub_type, struct p
|
Line 1628 rip_redistribute_add (int type, int sub_type, struct p
|
} |
} |
} |
} |
|
|
RIP_TIMER_OFF (rinfo->t_timeout); | rinfo = rip_ecmp_replace (&newinfo); |
RIP_TIMER_OFF (rinfo->t_garbage_collect); | route_unlock_node (rp); |
| |
if (rip_route_rte (rinfo)) | |
rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop, | |
rinfo->metric); | |
rp->info = NULL; | |
rip_info_free (rinfo); | |
| |
route_unlock_node (rp); | |
} |
} |
|
else |
|
rinfo = rip_ecmp_add (&newinfo); |
|
|
rinfo = rip_info_new (); |
|
|
|
rinfo->type = type; |
|
rinfo->sub_type = sub_type; |
|
rinfo->ifindex = ifindex; |
|
rinfo->metric = 1; |
|
rinfo->external_metric = metric; |
|
rinfo->distance = distance; |
|
rinfo->rp = rp; |
|
|
|
if (nexthop) |
|
rinfo->nexthop = *nexthop; |
|
|
|
rinfo->flags |= RIP_RTF_FIB; |
|
rp->info = rinfo; |
|
|
|
rinfo->flags |= RIP_RTF_CHANGED; |
|
|
|
if (IS_RIP_DEBUG_EVENT) { |
if (IS_RIP_DEBUG_EVENT) { |
if (!nexthop) |
if (!nexthop) |
zlog_debug ("Redistribute new prefix %s/%d on the interface %s", |
zlog_debug ("Redistribute new prefix %s/%d on the interface %s", |
Line 1595 rip_redistribute_add (int type, int sub_type, struct p
|
Line 1645 rip_redistribute_add (int type, int sub_type, struct p
|
ifindex2ifname(ifindex)); |
ifindex2ifname(ifindex)); |
} |
} |
|
|
|
|
rip_event (RIP_TRIGGERED_UPDATE, 0); |
rip_event (RIP_TRIGGERED_UPDATE, 0); |
} |
} |
|
|
/* Delete redistributed route from RIP table. */ |
/* Delete redistributed route from RIP table. */ |
void |
void |
rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, |
rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, |
unsigned int ifindex) | ifindex_t ifindex) |
{ |
{ |
int ret; |
int ret; |
struct route_node *rp; |
struct route_node *rp; |
Line 1615 rip_redistribute_delete (int type, int sub_type, struc
|
Line 1664 rip_redistribute_delete (int type, int sub_type, struc
|
rp = route_node_lookup (rip->table, (struct prefix *) p); |
rp = route_node_lookup (rip->table, (struct prefix *) p); |
if (rp) |
if (rp) |
{ |
{ |
rinfo = rp->info; | struct list *list = rp->info; |
|
|
if (rinfo != NULL | if (list != NULL && listcount (list) != 0) |
&& rinfo->type == type | { |
&& rinfo->sub_type == sub_type | rinfo = listgetdata (listhead (list)); |
&& rinfo->ifindex == ifindex) | if (rinfo != NULL |
{ | && rinfo->type == type |
/* Perform poisoned reverse. */ | && rinfo->sub_type == sub_type |
rinfo->metric = RIP_METRIC_INFINITY; | && rinfo->ifindex == ifindex) |
RIP_TIMER_ON (rinfo->t_garbage_collect, | { |
rip_garbage_collect, rip->garbage_time); | /* Perform poisoned reverse. */ |
RIP_TIMER_OFF (rinfo->t_timeout); | rinfo->metric = RIP_METRIC_INFINITY; |
rinfo->flags |= RIP_RTF_CHANGED; | RIP_TIMER_ON (rinfo->t_garbage_collect, |
| rip_garbage_collect, rip->garbage_time); |
| RIP_TIMER_OFF (rinfo->t_timeout); |
| rinfo->flags |= RIP_RTF_CHANGED; |
|
|
if (IS_RIP_DEBUG_EVENT) | if (IS_RIP_DEBUG_EVENT) |
zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]", | zlog_debug ("Poisone %s/%d on the interface %s with an " |
inet_ntoa(p->prefix), p->prefixlen, | "infinity metric [delete]", |
ifindex2ifname(ifindex)); | inet_ntoa(p->prefix), p->prefixlen, |
| ifindex2ifname(ifindex)); |
|
|
rip_event (RIP_TRIGGERED_UPDATE, 0); | rip_event (RIP_TRIGGERED_UPDATE, 0); |
} | } |
| } |
| route_unlock_node (rp); |
} |
} |
} |
} |
|
|
Line 1683 rip_request_process (struct rip_packet *packet, int si
|
Line 1738 rip_request_process (struct rip_packet *packet, int si
|
ntohs (rte->family) == 0 && |
ntohs (rte->family) == 0 && |
ntohl (rte->metric) == RIP_METRIC_INFINITY) |
ntohl (rte->metric) == RIP_METRIC_INFINITY) |
{ |
{ |
struct prefix_ipv4 saddr; |
|
|
|
/* saddr will be used for determining which routes to split-horizon. |
|
Since the source address we'll pick will be on the same subnet as the |
|
destination, for the purpose of split-horizoning, we'll |
|
pretend that "from" is our source address. */ |
|
saddr.family = AF_INET; |
|
saddr.prefixlen = IPV4_MAX_BITLEN; |
|
saddr.prefix = from->sin_addr; |
|
|
|
/* All route with split horizon */ |
/* All route with split horizon */ |
rip_output_process (ifc, from, rip_all_route, packet->version); |
rip_output_process (ifc, from, rip_all_route, packet->version); |
} |
} |
Line 1717 rip_request_process (struct rip_packet *packet, int si
|
Line 1762 rip_request_process (struct rip_packet *packet, int si
|
rp = route_node_lookup (rip->table, (struct prefix *) &p); |
rp = route_node_lookup (rip->table, (struct prefix *) &p); |
if (rp) |
if (rp) |
{ |
{ |
rinfo = rp->info; | rinfo = listgetdata (listhead ((struct list *)rp->info)); |
rte->metric = htonl (rinfo->metric); |
rte->metric = htonl (rinfo->metric); |
route_unlock_node (rp); |
route_unlock_node (rp); |
} |
} |
Line 1748 setsockopt_pktinfo (int sock)
|
Line 1793 setsockopt_pktinfo (int sock)
|
/* Read RIP packet by recvmsg function. */ |
/* Read RIP packet by recvmsg function. */ |
int |
int |
rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, |
rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, |
int *ifindex) | ifindex_t *ifindex) |
{ |
{ |
int ret; |
int ret; |
struct msghdr msg; |
struct msghdr msg; |
Line 1789 rip_read_new (struct thread *t)
|
Line 1834 rip_read_new (struct thread *t)
|
int sock; |
int sock; |
char buf[RIP_PACKET_MAXSIZ]; |
char buf[RIP_PACKET_MAXSIZ]; |
struct sockaddr_in from; |
struct sockaddr_in from; |
unsigned int ifindex; | ifindex_t ifindex; |
|
|
/* Fetch socket then register myself. */ |
/* Fetch socket then register myself. */ |
sock = THREAD_FD (t); |
sock = THREAD_FD (t); |
Line 2152 rip_output_process (struct connected *ifc, struct sock
|
Line 2197 rip_output_process (struct connected *ifc, struct sock
|
int num = 0; |
int num = 0; |
int rtemax; |
int rtemax; |
int subnetted = 0; |
int subnetted = 0; |
|
struct list *list = NULL; |
|
struct listnode *listnode = NULL; |
|
|
/* Logging output event. */ |
/* Logging output event. */ |
if (IS_RIP_DEBUG_EVENT) |
if (IS_RIP_DEBUG_EVENT) |
Line 2168 rip_output_process (struct connected *ifc, struct sock
|
Line 2215 rip_output_process (struct connected *ifc, struct sock
|
|
|
/* Reset stream and RTE counter. */ |
/* Reset stream and RTE counter. */ |
stream_reset (s); |
stream_reset (s); |
rtemax = (RIP_PACKET_MAXSIZ - 4) / 20; | rtemax = RIP_MAX_RTE; |
|
|
/* Get RIP interface. */ |
/* Get RIP interface. */ |
ri = ifc->ifp->info; |
ri = ifc->ifp->info; |
Line 2209 rip_output_process (struct connected *ifc, struct sock
|
Line 2256 rip_output_process (struct connected *ifc, struct sock
|
} |
} |
|
|
for (rp = route_top (rip->table); rp; rp = route_next (rp)) |
for (rp = route_top (rip->table); rp; rp = route_next (rp)) |
if ((rinfo = rp->info) != NULL) | if ((list = rp->info) != NULL && listcount (list) != 0) |
{ |
{ |
|
rinfo = listgetdata (listhead (list)); |
/* For RIPv1, if we are subnetted, output subnets in our network */ |
/* For RIPv1, if we are subnetted, output subnets in our network */ |
/* that have the same mask as the output "interface". For other */ |
/* that have the same mask as the output "interface". For other */ |
/* networks, only the classfull version is output. */ |
/* networks, only the classfull version is output. */ |
Line 2269 rip_output_process (struct connected *ifc, struct sock
|
Line 2317 rip_output_process (struct connected *ifc, struct sock
|
* (in order to handle the case when multiple subnets are |
* (in order to handle the case when multiple subnets are |
* configured on the same interface). |
* configured on the same interface). |
*/ |
*/ |
if (rinfo->type == ZEBRA_ROUTE_RIP && | int suppress = 0; |
rinfo->ifindex == ifc->ifp->ifindex) | struct rip_info *tmp_rinfo = NULL; |
continue; | |
if (rinfo->type == ZEBRA_ROUTE_CONNECT && | for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) |
| if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && |
| tmp_rinfo->ifindex == ifc->ifp->ifindex) |
| { |
| suppress = 1; |
| break; |
| } |
| |
| if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT && |
prefix_match((struct prefix *)p, ifc->address)) |
prefix_match((struct prefix *)p, ifc->address)) |
|
suppress = 1; |
|
|
|
if (suppress) |
continue; |
continue; |
} |
} |
|
|
Line 2367 rip_output_process (struct connected *ifc, struct sock
|
Line 2426 rip_output_process (struct connected *ifc, struct sock
|
* (in order to handle the case when multiple subnets are |
* (in order to handle the case when multiple subnets are |
* configured on the same interface). |
* configured on the same interface). |
*/ |
*/ |
if (rinfo->type == ZEBRA_ROUTE_RIP && | struct rip_info *tmp_rinfo = NULL; |
rinfo->ifindex == ifc->ifp->ifindex) | |
rinfo->metric_out = RIP_METRIC_INFINITY; | for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) |
if (rinfo->type == ZEBRA_ROUTE_CONNECT && | if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && |
| tmp_rinfo->ifindex == ifc->ifp->ifindex) |
| rinfo->metric_out = RIP_METRIC_INFINITY; |
| if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT && |
prefix_match((struct prefix *)p, ifc->address)) |
prefix_match((struct prefix *)p, ifc->address)) |
rinfo->metric_out = RIP_METRIC_INFINITY; | rinfo->metric_out = RIP_METRIC_INFINITY; |
} |
} |
|
|
/* Prepare preamble, auth headers, if needs be */ |
/* Prepare preamble, auth headers, if needs be */ |
Line 2512 rip_update_process (int route_type)
|
Line 2574 rip_update_process (int route_type)
|
|
|
if (IS_RIP_DEBUG_EVENT) |
if (IS_RIP_DEBUG_EVENT) |
zlog_debug("SEND UPDATE to %s ifindex %d", |
zlog_debug("SEND UPDATE to %s ifindex %d", |
(ifp->name ? ifp->name : "_unknown_"), ifp->ifindex); | ifp->name, ifp->ifindex); |
|
|
/* send update on each connected network */ |
/* send update on each connected network */ |
for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected)) |
for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected)) |
Line 2592 static void
|
Line 2654 static void
|
rip_clear_changed_flag (void) |
rip_clear_changed_flag (void) |
{ |
{ |
struct route_node *rp; |
struct route_node *rp; |
struct rip_info *rinfo; | struct rip_info *rinfo = NULL; |
| struct list *list = NULL; |
| struct listnode *listnode = NULL; |
|
|
for (rp = route_top (rip->table); rp; rp = route_next (rp)) |
for (rp = route_top (rip->table); rp; rp = route_next (rp)) |
if ((rinfo = rp->info) != NULL) | if ((list = rp->info) != NULL) |
if (rinfo->flags & RIP_RTF_CHANGED) | for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) |
rinfo->flags &= ~RIP_RTF_CHANGED; | { |
| UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED); |
| /* This flag can be set only on the first entry. */ |
| break; |
| } |
} |
} |
|
|
/* Triggered update interval timer. */ |
/* Triggered update interval timer. */ |
Line 2662 void
|
Line 2730 void
|
rip_redistribute_withdraw (int type) |
rip_redistribute_withdraw (int type) |
{ |
{ |
struct route_node *rp; |
struct route_node *rp; |
struct rip_info *rinfo; | struct rip_info *rinfo = NULL; |
| struct list *list = NULL; |
|
|
if (!rip) |
if (!rip) |
return; |
return; |
|
|
for (rp = route_top (rip->table); rp; rp = route_next (rp)) |
for (rp = route_top (rip->table); rp; rp = route_next (rp)) |
if ((rinfo = rp->info) != NULL) | if ((list = rp->info) != NULL) |
{ |
{ |
|
rinfo = listgetdata (listhead (list)); |
if (rinfo->type == type |
if (rinfo->type == type |
&& rinfo->sub_type != RIP_ROUTE_INTERFACE) |
&& rinfo->sub_type != RIP_ROUTE_INTERFACE) |
{ |
{ |
Line 2773 rip_request_send (struct sockaddr_in *to, struct inter
|
Line 2843 rip_request_send (struct sockaddr_in *to, struct inter
|
} |
} |
return sizeof (rip_packet); |
return sizeof (rip_packet); |
} |
} |
| |
static int |
static int |
rip_update_jitter (unsigned long time) |
rip_update_jitter (unsigned long time) |
{ |
{ |
Line 2790 rip_update_jitter (unsigned long time)
|
Line 2860 rip_update_jitter (unsigned long time)
|
if (jitter_input < JITTER_BOUND) |
if (jitter_input < JITTER_BOUND) |
jitter_input = JITTER_BOUND; |
jitter_input = JITTER_BOUND; |
|
|
jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input)); | jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input)); |
|
|
return jitter/JITTER_BOUND; |
return jitter/JITTER_BOUND; |
} |
} |
Line 2827 rip_event (enum rip_event event, int sock)
|
Line 2897 rip_event (enum rip_event event, int sock)
|
break; |
break; |
} |
} |
} |
} |
| |
DEFUN (router_rip, |
DEFUN (router_rip, |
router_rip_cmd, |
router_rip_cmd, |
"router rip", |
"router rip", |
Line 2982 static void
|
Line 3052 static void
|
rip_update_default_metric (void) |
rip_update_default_metric (void) |
{ |
{ |
struct route_node *np; |
struct route_node *np; |
struct rip_info *rinfo; | struct rip_info *rinfo = NULL; |
| struct list *list = NULL; |
| struct listnode *listnode = NULL; |
|
|
for (np = route_top (rip->table); np; np = route_next (np)) |
for (np = route_top (rip->table); np; np = route_next (np)) |
if ((rinfo = np->info) != NULL) | if ((list = np->info) != NULL) |
if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) | for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) |
rinfo->metric = rip->default_metric; | if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) |
| rinfo->metric = rip->default_metric; |
} |
} |
#endif |
#endif |
|
|
Line 3103 ALIAS (no_rip_timers,
|
Line 3176 ALIAS (no_rip_timers,
|
"Routing information timeout timer. Default is 180.\n" |
"Routing information timeout timer. Default is 180.\n" |
"Garbage collection timer. Default is 120.\n") |
"Garbage collection timer. Default is 120.\n") |
|
|
| |
struct route_table *rip_distance_table; |
struct route_table *rip_distance_table; |
|
|
struct rip_distance |
struct rip_distance |
Line 3180 rip_distance_unset (struct vty *vty, const char *dista
|
Line 3253 rip_distance_unset (struct vty *vty, const char *dista
|
{ |
{ |
int ret; |
int ret; |
struct prefix_ipv4 p; |
struct prefix_ipv4 p; |
u_char distance; |
|
struct route_node *rn; |
struct route_node *rn; |
struct rip_distance *rdistance; |
struct rip_distance *rdistance; |
|
|
Line 3191 rip_distance_unset (struct vty *vty, const char *dista
|
Line 3263 rip_distance_unset (struct vty *vty, const char *dista
|
return CMD_WARNING; |
return CMD_WARNING; |
} |
} |
|
|
distance = atoi (distance_str); |
|
|
|
rn = route_node_lookup (rip_distance_table, (struct prefix *)&p); |
rn = route_node_lookup (rip_distance_table, (struct prefix *)&p); |
if (! rn) |
if (! rn) |
{ |
{ |
Line 3371 DEFUN (no_rip_distance_source_access_list,
|
Line 3441 DEFUN (no_rip_distance_source_access_list,
|
rip_distance_unset (vty, argv[0], argv[1], argv[2]); |
rip_distance_unset (vty, argv[0], argv[1], argv[2]); |
return CMD_SUCCESS; |
return CMD_SUCCESS; |
} |
} |
| |
| /* Update ECMP routes to zebra when ECMP is disabled. */ |
| static void |
| rip_ecmp_disable (void) |
| { |
| struct route_node *rp; |
| struct rip_info *rinfo, *tmp_rinfo; |
| struct list *list; |
| struct listnode *node, *nextnode; |
| |
| if (!rip) |
| return; |
| |
| for (rp = route_top (rip->table); rp; rp = route_next (rp)) |
| if ((list = rp->info) != NULL && listcount (list) > 1) |
| { |
| rinfo = listgetdata (listhead (list)); |
| if (!rip_route_rte (rinfo)) |
| continue; |
| |
| /* Drop all other entries, except the first one. */ |
| for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) |
| if (tmp_rinfo != rinfo) |
| { |
| RIP_TIMER_OFF (tmp_rinfo->t_timeout); |
| RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); |
| list_delete_node (list, node); |
| rip_info_free (tmp_rinfo); |
| } |
| |
| /* Update zebra. */ |
| rip_zebra_ipv4_add (rp); |
| |
| /* Set the route change flag. */ |
| SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); |
| |
| /* Signal the output process to trigger an update. */ |
| rip_event (RIP_TRIGGERED_UPDATE, 0); |
| } |
| } |
| |
| DEFUN (rip_allow_ecmp, |
| rip_allow_ecmp_cmd, |
| "allow-ecmp", |
| "Allow Equal Cost MultiPath\n") |
| { |
| if (rip->ecmp) |
| { |
| vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE); |
| return CMD_WARNING; |
| } |
| |
| rip->ecmp = 1; |
| zlog_info ("ECMP is enabled."); |
| return CMD_SUCCESS; |
| } |
| |
| DEFUN (no_rip_allow_ecmp, |
| no_rip_allow_ecmp_cmd, |
| "no allow-ecmp", |
| NO_STR |
| "Allow Equal Cost MultiPath\n") |
| { |
| if (!rip->ecmp) |
| { |
| vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE); |
| return CMD_WARNING; |
| } |
| |
| rip->ecmp = 0; |
| zlog_info ("ECMP is disabled."); |
| rip_ecmp_disable (); |
| return CMD_SUCCESS; |
| } |
| |
/* Print out routes update time. */ |
/* Print out routes update time. */ |
static void |
static void |
rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) |
rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) |
Line 3426 DEFUN (show_ip_rip,
|
Line 3570 DEFUN (show_ip_rip,
|
"Show RIP routes\n") |
"Show RIP routes\n") |
{ |
{ |
struct route_node *np; |
struct route_node *np; |
struct rip_info *rinfo; | struct rip_info *rinfo = NULL; |
| struct list *list = NULL; |
| struct listnode *listnode = NULL; |
|
|
if (! rip) |
if (! rip) |
return CMD_SUCCESS; |
return CMD_SUCCESS; |
Line 3439 DEFUN (show_ip_rip,
|
Line 3585 DEFUN (show_ip_rip,
|
VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); |
VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); |
|
|
for (np = route_top (rip->table); np; np = route_next (np)) |
for (np = route_top (rip->table); np; np = route_next (np)) |
if ((rinfo = np->info) != NULL) | if ((list = np->info) != NULL) |
| for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) |
{ |
{ |
int len; |
int len; |
|
|
Line 3676 config_write_rip (struct vty *vty)
|
Line 3823 config_write_rip (struct vty *vty)
|
rdistance->access_list ? rdistance->access_list : "", |
rdistance->access_list ? rdistance->access_list : "", |
VTY_NEWLINE); |
VTY_NEWLINE); |
|
|
|
/* ECMP configuration. */ |
|
if (rip->ecmp) |
|
vty_out (vty, " allow-ecmp%s", VTY_NEWLINE); |
|
|
/* RIP static route configuration. */ |
/* RIP static route configuration. */ |
for (rn = route_top (rip->route); rn; rn = route_next (rn)) |
for (rn = route_top (rip->route); rn; rn = route_next (rn)) |
if (rn->info) |
if (rn->info) |
Line 3695 static struct cmd_node rip_node =
|
Line 3846 static struct cmd_node rip_node =
|
"%s(config-router)# ", |
"%s(config-router)# ", |
1 |
1 |
}; |
}; |
| |
/* Distribute-list update functions. */ |
/* Distribute-list update functions. */ |
static void |
static void |
rip_distribute_update (struct distribute *dist) |
rip_distribute_update (struct distribute *dist) |
Line 3786 rip_distribute_update_all_wrapper(struct access_list *
|
Line 3937 rip_distribute_update_all_wrapper(struct access_list *
|
{ |
{ |
rip_distribute_update_all(NULL); |
rip_distribute_update_all(NULL); |
} |
} |
| |
/* Delete all added rip route. */ |
/* Delete all added rip route. */ |
void |
void |
rip_clean (void) |
rip_clean (void) |
{ |
{ |
int i; |
int i; |
struct route_node *rp; |
struct route_node *rp; |
struct rip_info *rinfo; | struct rip_info *rinfo = NULL; |
| struct list *list = NULL; |
| struct listnode *listnode = NULL; |
|
|
if (rip) |
if (rip) |
{ |
{ |
/* Clear RIP routes */ |
/* Clear RIP routes */ |
for (rp = route_top (rip->table); rp; rp = route_next (rp)) |
for (rp = route_top (rip->table); rp; rp = route_next (rp)) |
if ((rinfo = rp->info) != NULL) | if ((list = rp->info) != NULL) |
{ | { |
if (rinfo->type == ZEBRA_ROUTE_RIP && | rinfo = listgetdata (listhead (list)); |
rinfo->sub_type == RIP_ROUTE_RTE) | if (rip_route_rte (rinfo)) |
rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, | rip_zebra_ipv4_delete (rp); |
&rinfo->nexthop, rinfo->metric); | |
| |
RIP_TIMER_OFF (rinfo->t_timeout); | |
RIP_TIMER_OFF (rinfo->t_garbage_collect); | |
|
|
rp->info = NULL; | for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) |
route_unlock_node (rp); | { |
| RIP_TIMER_OFF (rinfo->t_timeout); |
| RIP_TIMER_OFF (rinfo->t_garbage_collect); |
| rip_info_free (rinfo); |
| } |
| list_delete (list); |
| rp->info = NULL; |
| route_unlock_node (rp); |
| } |
|
|
rip_info_free (rinfo); |
|
} |
|
|
|
/* Cancel RIP related timers. */ |
/* Cancel RIP related timers. */ |
RIP_TIMER_OFF (rip->t_update); |
RIP_TIMER_OFF (rip->t_update); |
RIP_TIMER_OFF (rip->t_triggered_update); |
RIP_TIMER_OFF (rip->t_triggered_update); |
Line 3979 void
|
Line 4133 void
|
rip_init (void) |
rip_init (void) |
{ |
{ |
/* Randomize for triggered update random(). */ |
/* Randomize for triggered update random(). */ |
srand (time (NULL)); | srandom (time (NULL)); |
|
|
/* Install top nodes. */ |
/* Install top nodes. */ |
install_node (&rip_node, config_write_rip); |
install_node (&rip_node, config_write_rip); |
Line 4010 rip_init (void)
|
Line 4164 rip_init (void)
|
install_element (RIP_NODE, &no_rip_distance_source_cmd); |
install_element (RIP_NODE, &no_rip_distance_source_cmd); |
install_element (RIP_NODE, &rip_distance_source_access_list_cmd); |
install_element (RIP_NODE, &rip_distance_source_access_list_cmd); |
install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd); |
install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd); |
|
install_element (RIP_NODE, &rip_allow_ecmp_cmd); |
|
install_element (RIP_NODE, &no_rip_allow_ecmp_cmd); |
|
|
/* Debug related init. */ |
/* Debug related init. */ |
rip_debug_init (); |
rip_debug_init (); |