diff options
Diffstat (limited to 'ospf6d/ospf6_route.c')
-rw-r--r-- | ospf6d/ospf6_route.c | 291 |
1 files changed, 258 insertions, 33 deletions
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 50575564..e53ff365 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -37,6 +37,7 @@ #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6d.h" +#include "ospf6_zebra.h" unsigned char conf_debug_ospf6_route = 0; @@ -173,18 +174,232 @@ const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = { "??", "IA", "IE", "E1", "E2", }; +struct ospf6_nexthop * +ospf6_nexthop_create (void) +{ + struct ospf6_nexthop *nh; + + nh = XCALLOC (MTYPE_OSPF6_NEXTHOP, sizeof (struct ospf6_nexthop)); + return nh; +} + +void +ospf6_nexthop_delete (struct ospf6_nexthop *nh) +{ + if (nh) + XFREE (MTYPE_OSPF6_NEXTHOP, nh); +} + +void +ospf6_free_nexthops (struct list *nh_list) +{ + struct ospf6_nexthop *nh; + struct listnode *node, *nnode; + + if (nh_list) + { + for (ALL_LIST_ELEMENTS (nh_list, node, nnode, nh)) + ospf6_nexthop_delete (nh); + } +} + +void +ospf6_clear_nexthops (struct list *nh_list) +{ + struct listnode *node; + struct ospf6_nexthop *nh; + + if (nh_list) + { + for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh)) + ospf6_nexthop_clear (nh); + } +} + +static struct ospf6_nexthop * +ospf6_route_find_nexthop (struct list *nh_list, struct ospf6_nexthop *nh_match) +{ + struct listnode *node; + struct ospf6_nexthop *nh; + + if (nh_list && nh_match) + { + for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh)) + { + if (ospf6_nexthop_is_same (nh, nh_match)) + return (nh); + } + } + + return (NULL); +} + +void +ospf6_copy_nexthops (struct list *dst, struct list *src) +{ + struct ospf6_nexthop *nh_new, *nh; + struct listnode *node; + + if (dst && src) + { + for (ALL_LIST_ELEMENTS_RO (src, node, nh)) + { + if (ospf6_nexthop_is_set (nh)) + { + nh_new = ospf6_nexthop_create (); + ospf6_nexthop_copy (nh_new, nh); + listnode_add (dst, nh_new); + } + } + } +} + +void +ospf6_merge_nexthops (struct list *dst, struct list *src) +{ + struct listnode *node; + struct ospf6_nexthop *nh, *nh_new; + + if (src && dst) + { + for (ALL_LIST_ELEMENTS_RO (src, node, nh)) + { + if (!ospf6_route_find_nexthop (dst, nh)) + { + nh_new = ospf6_nexthop_create (); + ospf6_nexthop_copy (nh_new, nh); + listnode_add (dst, nh_new); + } + } + } +} + +int +ospf6_route_cmp_nexthops (struct ospf6_route *a, struct ospf6_route *b) +{ + struct listnode *anode, *bnode; + struct ospf6_nexthop *anh, *bnh; + + if (a && b) + { + if (listcount(a->nh_list) == listcount(b->nh_list)) + { + for (ALL_LIST_ELEMENTS_RO (a->nh_list, anode, anh)) + { + for (ALL_LIST_ELEMENTS_RO (b->nh_list, bnode, bnh)) + if (!ospf6_nexthop_is_same (anh, bnh)) + return (1); + } + return (0); + } + else + return (1); + } + /* One of the routes doesn't exist ? */ + return (1); +} + +int +ospf6_num_nexthops (struct list *nh_list) +{ + return (listcount(nh_list)); +} + +void +ospf6_add_nexthop (struct list *nh_list, int ifindex, + struct in6_addr *addr) +{ + struct ospf6_nexthop *nh; + struct ospf6_nexthop nh_match; + + if (nh_list) + { + nh_match.ifindex = ifindex; + if (addr != NULL) + memcpy (&nh_match.address, addr, sizeof (struct in6_addr)); + else + memset (&nh_match.address, 0, sizeof (struct in6_addr)); + + if (!ospf6_route_find_nexthop (nh_list, &nh_match)) + { + nh = ospf6_nexthop_create(); + ospf6_nexthop_copy (nh, &nh_match); + listnode_add (nh_list, nh); + } + } +} + +void +ospf6_route_zebra_copy_nexthops (struct ospf6_route *route, + ifindex_t *ifindexes, + struct in6_addr **nexthop_addr, + int entries) +{ + struct ospf6_nexthop *nh; + struct listnode *node; + char buf[64]; + int i; + + if (route) + { + i = 0; + for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh)) + { + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + { + char ifname[IFNAMSIZ]; + inet_ntop (AF_INET6, &nh->address, buf, sizeof (buf)); + if (!if_indextoname(nh->ifindex, ifname)) + strlcpy(ifname, "unknown", sizeof(ifname)); + zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname, + nh->ifindex); + } + if (i < entries) + { + nexthop_addr[i] = &nh->address; + ifindexes[i] = nh->ifindex; + i++; + } + else + { + return; + } + } + } +} + +int +ospf6_route_get_first_nh_index (struct ospf6_route *route) +{ + struct ospf6_nexthop *nh; + + if (route) + { + if ((nh = (struct ospf6_nexthop *)listhead (route->nh_list))) + return (nh->ifindex); + } + + return (-1); +} + struct ospf6_route * ospf6_route_create (void) { struct ospf6_route *route; route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route)); + route->nh_list = list_new(); return route; } void ospf6_route_delete (struct ospf6_route *route) { - XFREE (MTYPE_OSPF6_ROUTE, route); + if (route) + { + ospf6_free_nexthops (route->nh_list); + list_free (route->nh_list); + XFREE (MTYPE_OSPF6_ROUTE, route); + } } struct ospf6_route * @@ -193,7 +408,15 @@ ospf6_route_copy (struct ospf6_route *route) struct ospf6_route *new; new = ospf6_route_create (); - memcpy (new, route, sizeof (struct ospf6_route)); + new->type = route->type; + memcpy (&new->prefix, &route->prefix, sizeof (struct prefix)); + new->installed = route->installed; + new->changed = route->changed; + new->flag = route->flag; + new->route_option = route->route_option; + new->linkstate_id = route->linkstate_id; + new->path = route->path; + ospf6_copy_nexthops (new->nh_list, route->nh_list); new->rnode = NULL; new->prev = NULL; new->next = NULL; @@ -226,7 +449,7 @@ ospf6_route_unlock (struct ospf6_route *route) /* Route compare function. If ra is more preferred, it returns less than 0. If rb is more preferred returns greater than 0. Otherwise (neither one is preferred), returns 0 */ -static int +int ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb) { assert (ospf6_route_is_same (ra, rb)); @@ -246,8 +469,8 @@ ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb) if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) { - if (ra->path.cost_e2 != rb->path.cost_e2) - return (ra->path.cost_e2 - rb->path.cost_e2); + if (ra->path.u.cost_e2 != rb->path.u.cost_e2) + return (ra->path.u.cost_e2 - rb->path.u.cost_e2); } else { @@ -620,7 +843,7 @@ ospf6_route_remove (struct ospf6_route *route, if (node->info == route) { - if (route->next && ospf6_route_is_same (route->next, route)) + if (route->next && route->next->rnode == node) { node->info = route->next; SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST); @@ -795,6 +1018,8 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route) char duration[16]; const char *ifname; struct timeval now, res; + struct listnode *node; + struct ospf6_nexthop *nh; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &route->changed, &res); @@ -810,27 +1035,26 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route) else prefix2str (&route->prefix, destination, sizeof (destination)); - /* nexthop */ - inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop, - sizeof (nexthop)); - ifname = ifindex2ifname (route->nexthop[0].ifindex); - - vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", - (ospf6_route_is_best (route) ? '*' : ' '), - OSPF6_DEST_TYPE_SUBSTR (route->type), - OSPF6_PATH_TYPE_SUBSTR (route->path.type), - destination, nexthop, IFNAMSIZ, ifname, duration, VNL); - - for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + i = 0; + for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh)) { /* nexthop */ - inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, + inet_ntop (AF_INET6, &nh->address, nexthop, sizeof (nexthop)); - ifname = ifindex2ifname (route->nexthop[i].ifindex); - - vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", - ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL); + ifname = ifindex2ifname (nh->ifindex); + + if (!i) + { + vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", + (ospf6_route_is_best (route) ? '*' : ' '), + OSPF6_DEST_TYPE_SUBSTR (route->type), + OSPF6_PATH_TYPE_SUBSTR (route->path.type), + destination, nexthop, IFNAMSIZ, ifname, duration, VNL); + i++; + } + else + vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", + ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL); } } @@ -842,7 +1066,8 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) char area_id[16], id[16], adv_router[16], capa[16], options[16]; struct timeval now, res; char duration[16]; - int i; + struct listnode *node; + struct ospf6_nexthop *nh; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); @@ -914,17 +1139,16 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) vty_out (vty, "Metric Type: %d%s", route->path.metric_type, VNL); vty_out (vty, "Metric: %d (%d)%s", - route->path.cost, route->path.cost_e2, VNL); + route->path.cost, route->path.u.cost_e2, VNL); /* Nexthops */ vty_out (vty, "Nexthop:%s", VNL); - for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh)) { /* nexthop */ - inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, + inet_ntop (AF_INET6, &nh->address, nexthop, sizeof (nexthop)); - ifname = ifindex2ifname (route->nexthop[i].ifindex); + ifname = ifindex2ifname (nh->ifindex); vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL); } vty_out (vty, "%s", VNL); @@ -937,7 +1161,7 @@ ospf6_route_show_table_summary (struct vty *vty, struct ospf6_route *route, *prev = NULL; int i, pathtype[OSPF6_PATH_TYPE_MAX]; unsigned int number = 0; - int nhinval = 0, ecmp = 0; + int nh_count =0 , nhinval = 0, ecmp = 0; int alternative = 0, destination = 0; for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++) @@ -950,9 +1174,10 @@ ospf6_route_show_table_summary (struct vty *vty, destination++; else alternative++; - if (! ospf6_nexthop_is_set (&route->nexthop[0])) + nh_count = ospf6_num_nexthops (route->nh_list); + if (!nh_count) nhinval++; - else if (ospf6_nexthop_is_set (&route->nexthop[1])) + else if (nh_count > 1) ecmp++; pathtype[route->path.type]++; number++; |