| /* |
| * Copyright (C) 2003 Yasuhiro Ohara |
| * |
| * This file is part of GNU Zebra. |
| * |
| * GNU Zebra is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2, or (at your option) any |
| * later version. |
| * |
| * GNU Zebra is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with GNU Zebra; see the file COPYING. If not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| * Boston, MA 02111-1307, USA. |
| */ |
| |
| #include <zebra.h> |
| |
| #include "log.h" |
| #include "memory.h" |
| #include "prefix.h" |
| #include "command.h" |
| #include "vty.h" |
| #include "routemap.h" |
| #include "table.h" |
| #include "plist.h" |
| #include "thread.h" |
| #include "linklist.h" |
| |
| #include "ospf6_proto.h" |
| #include "ospf6_lsa.h" |
| #include "ospf6_lsdb.h" |
| #include "ospf6_route.h" |
| #include "ospf6_zebra.h" |
| #include "ospf6_message.h" |
| |
| #include "ospf6_top.h" |
| #include "ospf6_area.h" |
| #include "ospf6_interface.h" |
| #include "ospf6_neighbor.h" |
| #include "ospf6_asbr.h" |
| #include "ospf6_intra.h" |
| #include "ospf6_flood.h" |
| #include "ospf6d.h" |
| |
| unsigned char conf_debug_ospf6_asbr = 0; |
| |
| #define ZROUTE_NAME(x) zebra_route_string(x) |
| |
| /* AS External LSA origination */ |
| static void |
| ospf6_as_external_lsa_originate (struct ospf6_route *route) |
| { |
| char buffer[OSPF6_MAX_LSASIZE]; |
| struct ospf6_lsa_header *lsa_header; |
| struct ospf6_lsa *old, *lsa; |
| struct ospf6_external_info *info = route->route_option; |
| |
| struct ospf6_as_external_lsa *as_external_lsa; |
| char buf[64]; |
| caddr_t p; |
| |
| /* find previous LSA */ |
| old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), |
| route->path.origin.id, ospf6->router_id, |
| ospf6->lsdb); |
| |
| if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE (AS_EXTERNAL)) |
| { |
| prefix2str (&route->prefix, buf, sizeof (buf)); |
| zlog_debug ("Originate AS-External-LSA for %s", buf); |
| } |
| |
| /* prepare buffer */ |
| memset (buffer, 0, sizeof (buffer)); |
| lsa_header = (struct ospf6_lsa_header *) buffer; |
| as_external_lsa = (struct ospf6_as_external_lsa *) |
| ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); |
| p = (caddr_t) |
| ((caddr_t) as_external_lsa + sizeof (struct ospf6_as_external_lsa)); |
| |
| /* Fill AS-External-LSA */ |
| /* Metric type */ |
| if (route->path.metric_type == 2) |
| SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E); |
| else |
| UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E); |
| |
| /* forwarding address */ |
| if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding)) |
| SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F); |
| else |
| UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F); |
| |
| /* external route tag */ |
| UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T); |
| |
| /* Set metric */ |
| OSPF6_ASBR_METRIC_SET (as_external_lsa, route->path.cost); |
| |
| /* prefixlen */ |
| as_external_lsa->prefix.prefix_length = route->prefix.prefixlen; |
| |
| /* PrefixOptions */ |
| as_external_lsa->prefix.prefix_options = route->path.prefix_options; |
| |
| /* don't use refer LS-type */ |
| as_external_lsa->prefix.prefix_refer_lstype = htons (0); |
| |
| /* set Prefix */ |
| memcpy (p, &route->prefix.u.prefix6, |
| OSPF6_PREFIX_SPACE (route->prefix.prefixlen)); |
| ospf6_prefix_apply_mask (&as_external_lsa->prefix); |
| p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen); |
| |
| /* Forwarding address */ |
| if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) |
| { |
| memcpy (p, &info->forwarding, sizeof (struct in6_addr)); |
| p += sizeof (struct in6_addr); |
| } |
| |
| /* External Route Tag */ |
| if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) |
| { |
| /* xxx */ |
| } |
| |
| /* Fill LSA Header */ |
| lsa_header->age = 0; |
| lsa_header->type = htons (OSPF6_LSTYPE_AS_EXTERNAL); |
| lsa_header->id = route->path.origin.id; |
| lsa_header->adv_router = ospf6->router_id; |
| lsa_header->seqnum = |
| ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, |
| lsa_header->adv_router, ospf6->lsdb); |
| lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header); |
| |
| /* LSA checksum */ |
| ospf6_lsa_checksum (lsa_header); |
| |
| /* create LSA */ |
| lsa = ospf6_lsa_create (lsa_header); |
| |
| /* Originate */ |
| ospf6_lsa_originate_process (lsa, ospf6); |
| } |
| |
| |
| void |
| ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) |
| { |
| struct ospf6_as_external_lsa *external; |
| struct prefix asbr_id; |
| struct ospf6_route *asbr_entry, *route; |
| char buf[64]; |
| int i; |
| |
| external = (struct ospf6_as_external_lsa *) |
| OSPF6_LSA_HEADER_END (lsa->header); |
| |
| if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) |
| zlog_debug ("Calculate AS-External route for %s", lsa->name); |
| |
| if (lsa->header->adv_router == ospf6->router_id) |
| { |
| if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) |
| zlog_debug ("Ignore self-originated AS-External-LSA"); |
| return; |
| } |
| |
| if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) |
| { |
| if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) |
| zlog_debug ("Ignore LSA with LSInfinity Metric"); |
| return; |
| } |
| |
| ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &asbr_id); |
| asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->brouter_table); |
| if (asbr_entry == NULL || |
| ! CHECK_FLAG (asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E)) |
| { |
| if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) |
| { |
| prefix2str (&asbr_id, buf, sizeof (buf)); |
| zlog_debug ("ASBR entry not found: %s", buf); |
| } |
| return; |
| } |
| |
| route = ospf6_route_create (); |
| route->type = OSPF6_DEST_TYPE_NETWORK; |
| route->prefix.family = AF_INET6; |
| route->prefix.prefixlen = external->prefix.prefix_length; |
| ospf6_prefix_in6_addr (&route->prefix.u.prefix6, &external->prefix); |
| |
| route->path.area_id = asbr_entry->path.area_id; |
| route->path.origin.type = lsa->header->type; |
| route->path.origin.id = lsa->header->id; |
| route->path.origin.adv_router = lsa->header->adv_router; |
| |
| route->path.prefix_options = external->prefix.prefix_options; |
| if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E)) |
| { |
| route->path.type = OSPF6_PATH_TYPE_EXTERNAL2; |
| route->path.metric_type = 2; |
| route->path.cost = asbr_entry->path.cost; |
| route->path.cost_e2 = OSPF6_ASBR_METRIC (external); |
| } |
| else |
| { |
| route->path.type = OSPF6_PATH_TYPE_EXTERNAL1; |
| route->path.metric_type = 1; |
| route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external); |
| route->path.cost_e2 = 0; |
| } |
| |
| for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) |
| ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]); |
| |
| if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) |
| { |
| prefix2str (&route->prefix, buf, sizeof (buf)); |
| zlog_debug ("AS-External route add: %s", buf); |
| } |
| |
| ospf6_route_add (route, ospf6->route_table); |
| } |
| |
| void |
| ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa) |
| { |
| struct ospf6_as_external_lsa *external; |
| struct prefix prefix; |
| struct ospf6_route *route; |
| char buf[64]; |
| |
| external = (struct ospf6_as_external_lsa *) |
| OSPF6_LSA_HEADER_END (lsa->header); |
| |
| if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) |
| zlog_debug ("Withdraw AS-External route for %s", lsa->name); |
| |
| if (lsa->header->adv_router == ospf6->router_id) |
| { |
| if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) |
| zlog_debug ("Ignore self-originated AS-External-LSA"); |
| return; |
| } |
| |
| memset (&prefix, 0, sizeof (struct prefix)); |
| prefix.family = AF_INET6; |
| prefix.prefixlen = external->prefix.prefix_length; |
| ospf6_prefix_in6_addr (&prefix.u.prefix6, &external->prefix); |
| |
| route = ospf6_route_lookup (&prefix, ospf6->route_table); |
| if (route == NULL) |
| { |
| if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) |
| { |
| prefix2str (&prefix, buf, sizeof (buf)); |
| zlog_debug ("AS-External route %s not found", buf); |
| } |
| return; |
| } |
| |
| for (ospf6_route_lock (route); |
| route && ospf6_route_is_prefix (&prefix, route); |
| route = ospf6_route_next (route)) |
| { |
| if (route->type != OSPF6_DEST_TYPE_NETWORK) |
| continue; |
| if (route->path.origin.type != lsa->header->type) |
| continue; |
| if (route->path.origin.id != lsa->header->id) |
| continue; |
| if (route->path.origin.adv_router != lsa->header->adv_router) |
| continue; |
| |
| if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) |
| { |
| prefix2str (&route->prefix, buf, sizeof (buf)); |
| zlog_debug ("AS-External route remove: %s", buf); |
| } |
| ospf6_route_remove (route, ospf6->route_table); |
| } |
| } |
| |
| void |
| ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry) |
| { |
| struct ospf6_lsa *lsa; |
| u_int16_t type; |
| u_int32_t router; |
| |
| if (! CHECK_FLAG (asbr_entry->flag, OSPF6_ROUTE_BEST)) |
| { |
| char buf[16]; |
| inet_ntop (AF_INET, &ADV_ROUTER_IN_PREFIX (&asbr_entry->prefix), |
| buf, sizeof (buf)); |
| zlog_info ("ignore non-best path: lsentry %s add", buf); |
| return; |
| } |
| |
| type = htons (OSPF6_LSTYPE_AS_EXTERNAL); |
| router = ospf6_linkstate_prefix_adv_router (&asbr_entry->prefix); |
| for (lsa = ospf6_lsdb_type_router_head (type, router, ospf6->lsdb); lsa; |
| lsa = ospf6_lsdb_type_router_next (type, router, lsa)) |
| { |
| if (! OSPF6_LSA_IS_MAXAGE (lsa)) |
| ospf6_asbr_lsa_add (lsa); |
| } |
| } |
| |
| void |
| ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry) |
| { |
| struct ospf6_lsa *lsa; |
| u_int16_t type; |
| u_int32_t router; |
| |
| type = htons (OSPF6_LSTYPE_AS_EXTERNAL); |
| router = ospf6_linkstate_prefix_adv_router (&asbr_entry->prefix); |
| for (lsa = ospf6_lsdb_type_router_head (type, router, ospf6->lsdb); |
| lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa)) |
| ospf6_asbr_lsa_remove (lsa); |
| } |
| |
| |
| |
| /* redistribute function */ |
| |
| static void |
| ospf6_asbr_routemap_set (int type, const char *mapname) |
| { |
| if (ospf6->rmap[type].name) |
| free (ospf6->rmap[type].name); |
| ospf6->rmap[type].name = strdup (mapname); |
| ospf6->rmap[type].map = route_map_lookup_by_name (mapname); |
| } |
| |
| static void |
| ospf6_asbr_routemap_unset (int type) |
| { |
| if (ospf6->rmap[type].name) |
| free (ospf6->rmap[type].name); |
| ospf6->rmap[type].name = NULL; |
| ospf6->rmap[type].map = NULL; |
| } |
| |
| static void |
| ospf6_asbr_routemap_update (const char *mapname) |
| { |
| int type; |
| |
| if (ospf6 == NULL) |
| return; |
| |
| for (type = 0; type < ZEBRA_ROUTE_MAX; type++) |
| { |
| if (ospf6->rmap[type].name) |
| ospf6->rmap[type].map = |
| route_map_lookup_by_name (ospf6->rmap[type].name); |
| else |
| ospf6->rmap[type].map = NULL; |
| } |
| } |
| |
| int |
| ospf6_asbr_is_asbr (struct ospf6 *o) |
| { |
| return o->external_table->count; |
| } |
| |
| static void |
| ospf6_asbr_redistribute_set (int type) |
| { |
| ospf6_zebra_redistribute (type); |
| } |
| |
| static void |
| ospf6_asbr_redistribute_unset (int type) |
| { |
| struct ospf6_route *route; |
| struct ospf6_external_info *info; |
| |
| ospf6_zebra_no_redistribute (type); |
| |
| for (route = ospf6_route_head (ospf6->external_table); route; |
| route = ospf6_route_next (route)) |
| { |
| info = route->route_option; |
| if (info->type != type) |
| continue; |
| |
| ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex, |
| &route->prefix); |
| } |
| } |
| |
| void |
| ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, |
| u_int nexthop_num, struct in6_addr *nexthop) |
| { |
| int ret; |
| struct ospf6_route troute; |
| struct ospf6_external_info tinfo; |
| struct ospf6_route *route, *match; |
| struct ospf6_external_info *info; |
| struct prefix prefix_id; |
| struct route_node *node; |
| char pbuf[64], ibuf[16]; |
| struct listnode *lnode, *lnnode; |
| struct ospf6_area *oa; |
| |
| if (! ospf6_zebra_is_redistribute (type)) |
| return; |
| |
| if (IS_OSPF6_DEBUG_ASBR) |
| { |
| prefix2str (prefix, pbuf, sizeof (pbuf)); |
| zlog_debug ("Redistribute %s (%s)", pbuf, ZROUTE_NAME (type)); |
| } |
| |
| /* if route-map was specified but not found, do not advertise */ |
| if (ospf6->rmap[type].name) |
| { |
| if (ospf6->rmap[type].map == NULL) |
| ospf6_asbr_routemap_update (NULL); |
| if (ospf6->rmap[type].map == NULL) |
| { |
| zlog_warn ("route-map \"%s\" not found, suppress redistributing", |
| ospf6->rmap[type].name); |
| return; |
| } |
| } |
| |
| /* apply route-map */ |
| if (ospf6->rmap[type].map) |
| { |
| memset (&troute, 0, sizeof (troute)); |
| memset (&tinfo, 0, sizeof (tinfo)); |
| troute.route_option = &tinfo; |
| |
| ret = route_map_apply (ospf6->rmap[type].map, prefix, |
| RMAP_OSPF6, &troute); |
| if (ret == RMAP_DENYMATCH) |
| { |
| if (IS_OSPF6_DEBUG_ASBR) |
| zlog_debug ("Denied by route-map \"%s\"", ospf6->rmap[type].name); |
| return; |
| } |
| } |
| |
| match = ospf6_route_lookup (prefix, ospf6->external_table); |
| if (match) |
| { |
| info = match->route_option; |
| |
| /* copy result of route-map */ |
| if (ospf6->rmap[type].map) |
| { |
| if (troute.path.metric_type) |
| match->path.metric_type = troute.path.metric_type; |
| if (troute.path.cost) |
| match->path.cost = troute.path.cost; |
| if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding)) |
| memcpy (&info->forwarding, &tinfo.forwarding, |
| sizeof (struct in6_addr)); |
| } |
| |
| info->type = type; |
| match->nexthop[0].ifindex = ifindex; |
| if (nexthop_num && nexthop) |
| memcpy (&match->nexthop[0].address, nexthop, sizeof (struct in6_addr)); |
| |
| /* create/update binding in external_id_table */ |
| prefix_id.family = AF_INET; |
| prefix_id.prefixlen = 32; |
| prefix_id.u.prefix4.s_addr = htonl (info->id); |
| node = route_node_get (ospf6->external_id_table, &prefix_id); |
| node->info = match; |
| |
| if (IS_OSPF6_DEBUG_ASBR) |
| { |
| inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); |
| zlog_debug ("Advertise as AS-External Id:%s", ibuf); |
| } |
| |
| match->path.origin.id = htonl (info->id); |
| ospf6_as_external_lsa_originate (match); |
| return; |
| } |
| |
| /* create new entry */ |
| route = ospf6_route_create (); |
| route->type = OSPF6_DEST_TYPE_NETWORK; |
| memcpy (&route->prefix, prefix, sizeof (struct prefix)); |
| |
| info = (struct ospf6_external_info *) |
| XCALLOC (MTYPE_OSPF6_EXTERNAL_INFO, sizeof (struct ospf6_external_info)); |
| route->route_option = info; |
| info->id = ospf6->external_id++; |
| |
| /* copy result of route-map */ |
| if (ospf6->rmap[type].map) |
| { |
| if (troute.path.metric_type) |
| route->path.metric_type = troute.path.metric_type; |
| if (troute.path.cost) |
| route->path.cost = troute.path.cost; |
| if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding)) |
| memcpy (&info->forwarding, &tinfo.forwarding, |
| sizeof (struct in6_addr)); |
| } |
| |
| info->type = type; |
| route->nexthop[0].ifindex = ifindex; |
| if (nexthop_num && nexthop) |
| memcpy (&route->nexthop[0].address, nexthop, sizeof (struct in6_addr)); |
| |
| /* create/update binding in external_id_table */ |
| prefix_id.family = AF_INET; |
| prefix_id.prefixlen = 32; |
| prefix_id.u.prefix4.s_addr = htonl (info->id); |
| node = route_node_get (ospf6->external_id_table, &prefix_id); |
| node->info = route; |
| |
| route = ospf6_route_add (route, ospf6->external_table); |
| route->route_option = info; |
| |
| if (IS_OSPF6_DEBUG_ASBR) |
| { |
| inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); |
| zlog_debug ("Advertise as AS-External Id:%s", ibuf); |
| } |
| |
| route->path.origin.id = htonl (info->id); |
| ospf6_as_external_lsa_originate (route); |
| |
| /* Router-Bit (ASBR Flag) may have to be updated */ |
| for (ALL_LIST_ELEMENTS (ospf6->area_list, lnode, lnnode, oa)) |
| OSPF6_ROUTER_LSA_SCHEDULE (oa); |
| } |
| |
| void |
| ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix) |
| { |
| struct ospf6_route *match; |
| struct ospf6_external_info *info = NULL; |
| struct route_node *node; |
| struct ospf6_lsa *lsa; |
| struct prefix prefix_id; |
| char pbuf[64], ibuf[16]; |
| struct listnode *lnode, *lnnode; |
| struct ospf6_area *oa; |
| |
| match = ospf6_route_lookup (prefix, ospf6->external_table); |
| if (match == NULL) |
| { |
| if (IS_OSPF6_DEBUG_ASBR) |
| { |
| prefix2str (prefix, pbuf, sizeof (pbuf)); |
| zlog_debug ("No such route %s to withdraw", pbuf); |
| } |
| return; |
| } |
| |
| info = match->route_option; |
| assert (info); |
| |
| if (info->type != type) |
| { |
| if (IS_OSPF6_DEBUG_ASBR) |
| { |
| prefix2str (prefix, pbuf, sizeof (pbuf)); |
| zlog_debug ("Original protocol mismatch: %s", pbuf); |
| } |
| return; |
| } |
| |
| if (IS_OSPF6_DEBUG_ASBR) |
| { |
| prefix2str (prefix, pbuf, sizeof (pbuf)); |
| inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); |
| zlog_debug ("Withdraw %s (AS-External Id:%s)", pbuf, ibuf); |
| } |
| |
| lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), |
| htonl (info->id), ospf6->router_id, ospf6->lsdb); |
| if (lsa) |
| ospf6_lsa_purge (lsa); |
| |
| /* remove binding in external_id_table */ |
| prefix_id.family = AF_INET; |
| prefix_id.prefixlen = 32; |
| prefix_id.u.prefix4.s_addr = htonl (info->id); |
| node = route_node_lookup (ospf6->external_id_table, &prefix_id); |
| assert (node); |
| node->info = NULL; |
| route_unlock_node (node); |
| |
| ospf6_route_remove (match, ospf6->external_table); |
| XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info); |
| |
| /* Router-Bit (ASBR Flag) may have to be updated */ |
| for (ALL_LIST_ELEMENTS (ospf6->area_list, lnode, lnnode, oa)) |
| OSPF6_ROUTER_LSA_SCHEDULE (oa); |
| } |
| |
| DEFUN (ospf6_redistribute, |
| ospf6_redistribute_cmd, |
| "redistribute (static|kernel|connected|ripng|bgp)", |
| "Redistribute\n" |
| "Static route\n" |
| "Kernel route\n" |
| "Connected route\n" |
| "RIPng route\n" |
| "BGP route\n" |
| ) |
| { |
| int type = 0; |
| |
| if (strncmp (argv[0], "sta", 3) == 0) |
| type = ZEBRA_ROUTE_STATIC; |
| else if (strncmp (argv[0], "ker", 3) == 0) |
| type = ZEBRA_ROUTE_KERNEL; |
| else if (strncmp (argv[0], "con", 3) == 0) |
| type = ZEBRA_ROUTE_CONNECT; |
| else if (strncmp (argv[0], "rip", 3) == 0) |
| type = ZEBRA_ROUTE_RIPNG; |
| else if (strncmp (argv[0], "bgp", 3) == 0) |
| type = ZEBRA_ROUTE_BGP; |
| |
| ospf6_asbr_redistribute_unset (type); |
| ospf6_asbr_routemap_unset (type); |
| ospf6_asbr_redistribute_set (type); |
| return CMD_SUCCESS; |
| } |
| |
| DEFUN (ospf6_redistribute_routemap, |
| ospf6_redistribute_routemap_cmd, |
| "redistribute (static|kernel|connected|ripng|bgp) route-map WORD", |
| "Redistribute\n" |
| "Static routes\n" |
| "Kernel route\n" |
| "Connected route\n" |
| "RIPng route\n" |
| "BGP route\n" |
| "Route map reference\n" |
| "Route map name\n" |
| ) |
| { |
| int type = 0; |
| |
| if (strncmp (argv[0], "sta", 3) == 0) |
| type = ZEBRA_ROUTE_STATIC; |
| else if (strncmp (argv[0], "ker", 3) == 0) |
| type = ZEBRA_ROUTE_KERNEL; |
| else if (strncmp (argv[0], "con", 3) == 0) |
| type = ZEBRA_ROUTE_CONNECT; |
| else if (strncmp (argv[0], "rip", 3) == 0) |
| type = ZEBRA_ROUTE_RIPNG; |
| else if (strncmp (argv[0], "bgp", 3) == 0) |
| type = ZEBRA_ROUTE_BGP; |
| |
| ospf6_asbr_redistribute_unset (type); |
| ospf6_asbr_routemap_set (type, argv[1]); |
| ospf6_asbr_redistribute_set (type); |
| return CMD_SUCCESS; |
| } |
| |
| DEFUN (no_ospf6_redistribute, |
| no_ospf6_redistribute_cmd, |
| "no redistribute (static|kernel|connected|ripng|bgp)", |
| NO_STR |
| "Redistribute\n" |
| "Static route\n" |
| "Kernel route\n" |
| "Connected route\n" |
| "RIPng route\n" |
| "BGP route\n" |
| ) |
| { |
| int type = 0; |
| |
| if (strncmp (argv[0], "sta", 3) == 0) |
| type = ZEBRA_ROUTE_STATIC; |
| else if (strncmp (argv[0], "ker", 3) == 0) |
| type = ZEBRA_ROUTE_KERNEL; |
| else if (strncmp (argv[0], "con", 3) == 0) |
| type = ZEBRA_ROUTE_CONNECT; |
| else if (strncmp (argv[0], "rip", 3) == 0) |
| type = ZEBRA_ROUTE_RIPNG; |
| else if (strncmp (argv[0], "bgp", 3) == 0) |
| type = ZEBRA_ROUTE_BGP; |
| |
| ospf6_asbr_redistribute_unset (type); |
| ospf6_asbr_routemap_unset (type); |
| |
| return CMD_SUCCESS; |
| } |
| |
| int |
| ospf6_redistribute_config_write (struct vty *vty) |
| { |
| int type; |
| |
| for (type = 0; type < ZEBRA_ROUTE_MAX; type++) |
| { |
| if (type == ZEBRA_ROUTE_OSPF6) |
| continue; |
| if (! ospf6_zebra_is_redistribute (type)) |
| continue; |
| |
| if (ospf6->rmap[type].name) |
| vty_out (vty, " redistribute %s route-map %s%s", |
| ZROUTE_NAME (type), ospf6->rmap[type].name, VNL); |
| else |
| vty_out (vty, " redistribute %s%s", |
| ZROUTE_NAME (type), VNL); |
| } |
| |
| return 0; |
| } |
| |
| static void |
| ospf6_redistribute_show_config (struct vty *vty) |
| { |
| int type; |
| int nroute[ZEBRA_ROUTE_MAX]; |
| int total; |
| struct ospf6_route *route; |
| struct ospf6_external_info *info; |
| |
| total = 0; |
| for (type = 0; type < ZEBRA_ROUTE_MAX; type++) |
| nroute[type] = 0; |
| for (route = ospf6_route_head (ospf6->external_table); route; |
| route = ospf6_route_next (route)) |
| { |
| info = route->route_option; |
| nroute[info->type]++; |
| total++; |
| } |
| |
| vty_out (vty, "Redistributing External Routes from:%s", VNL); |
| for (type = 0; type < ZEBRA_ROUTE_MAX; type++) |
| { |
| if (type == ZEBRA_ROUTE_OSPF6) |
| continue; |
| if (! ospf6_zebra_is_redistribute (type)) |
| continue; |
| |
| if (ospf6->rmap[type].name) |
| vty_out (vty, " %d: %s with route-map \"%s\"%s%s", nroute[type], |
| ZROUTE_NAME (type), ospf6->rmap[type].name, |
| (ospf6->rmap[type].map ? "" : " (not found !)"), |
| VNL); |
| else |
| vty_out (vty, " %d: %s%s", nroute[type], |
| ZROUTE_NAME (type), VNL); |
| } |
| vty_out (vty, "Total %d routes%s", total, VNL); |
| } |
| |
| |
| |
| /* Routemap Functions */ |
| static route_map_result_t |
| ospf6_routemap_rule_match_address_prefixlist (void *rule, |
| struct prefix *prefix, |
| route_map_object_t type, |
| void *object) |
| { |
| struct prefix_list *plist; |
| |
| if (type != RMAP_OSPF6) |
| return RMAP_NOMATCH; |
| |
| plist = prefix_list_lookup (AFI_IP6, (char *) rule); |
| if (plist == NULL) |
| return RMAP_NOMATCH; |
| |
| return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? |
| RMAP_NOMATCH : RMAP_MATCH); |
| } |
| |
| static void * |
| ospf6_routemap_rule_match_address_prefixlist_compile (const char *arg) |
| { |
| return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); |
| } |
| |
| static void |
| ospf6_routemap_rule_match_address_prefixlist_free (void *rule) |
| { |
| XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); |
| } |
| |
| struct route_map_rule_cmd |
| ospf6_routemap_rule_match_address_prefixlist_cmd = |
| { |
| "ipv6 address prefix-list", |
| ospf6_routemap_rule_match_address_prefixlist, |
| ospf6_routemap_rule_match_address_prefixlist_compile, |
| ospf6_routemap_rule_match_address_prefixlist_free, |
| }; |
| |
| static route_map_result_t |
| ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix, |
| route_map_object_t type, void *object) |
| { |
| char *metric_type = rule; |
| struct ospf6_route *route = object; |
| |
| if (type != RMAP_OSPF6) |
| return RMAP_OKAY; |
| |
| if (strcmp (metric_type, "type-2") == 0) |
| route->path.metric_type = 2; |
| else |
| route->path.metric_type = 1; |
| |
| return RMAP_OKAY; |
| } |
| |
| static void * |
| ospf6_routemap_rule_set_metric_type_compile (const char *arg) |
| { |
| if (strcmp (arg, "type-2") && strcmp (arg, "type-1")) |
| return NULL; |
| return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); |
| } |
| |
| static void |
| ospf6_routemap_rule_set_metric_type_free (void *rule) |
| { |
| XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); |
| } |
| |
| struct route_map_rule_cmd |
| ospf6_routemap_rule_set_metric_type_cmd = |
| { |
| "metric-type", |
| ospf6_routemap_rule_set_metric_type, |
| ospf6_routemap_rule_set_metric_type_compile, |
| ospf6_routemap_rule_set_metric_type_free, |
| }; |
| |
| static route_map_result_t |
| ospf6_routemap_rule_set_metric (void *rule, struct prefix *prefix, |
| route_map_object_t type, void *object) |
| { |
| char *metric = rule; |
| struct ospf6_route *route = object; |
| |
| if (type != RMAP_OSPF6) |
| return RMAP_OKAY; |
| |
| route->path.cost = atoi (metric); |
| return RMAP_OKAY; |
| } |
| |
| static void * |
| ospf6_routemap_rule_set_metric_compile (const char *arg) |
| { |
| u_int32_t metric; |
| char *endp; |
| metric = strtoul (arg, &endp, 0); |
| if (metric > LS_INFINITY || *endp != '\0') |
| return NULL; |
| return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); |
| } |
| |
| static void |
| ospf6_routemap_rule_set_metric_free (void *rule) |
| { |
| XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); |
| } |
| |
| struct route_map_rule_cmd |
| ospf6_routemap_rule_set_metric_cmd = |
| { |
| "metric", |
| ospf6_routemap_rule_set_metric, |
| ospf6_routemap_rule_set_metric_compile, |
| ospf6_routemap_rule_set_metric_free, |
| }; |
| |
| static route_map_result_t |
| ospf6_routemap_rule_set_forwarding (void *rule, struct prefix *prefix, |
| route_map_object_t type, void *object) |
| { |
| char *forwarding = rule; |
| struct ospf6_route *route = object; |
| struct ospf6_external_info *info = route->route_option; |
| |
| if (type != RMAP_OSPF6) |
| return RMAP_OKAY; |
| |
| if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1) |
| { |
| memset (&info->forwarding, 0, sizeof (struct in6_addr)); |
| return RMAP_ERROR; |
| } |
| |
| return RMAP_OKAY; |
| } |
| |
| static void * |
| ospf6_routemap_rule_set_forwarding_compile (const char *arg) |
| { |
| struct in6_addr a; |
| if (inet_pton (AF_INET6, arg, &a) != 1) |
| return NULL; |
| return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); |
| } |
| |
| static void |
| ospf6_routemap_rule_set_forwarding_free (void *rule) |
| { |
| XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); |
| } |
| |
| struct route_map_rule_cmd |
| ospf6_routemap_rule_set_forwarding_cmd = |
| { |
| "forwarding-address", |
| ospf6_routemap_rule_set_forwarding, |
| ospf6_routemap_rule_set_forwarding_compile, |
| ospf6_routemap_rule_set_forwarding_free, |
| }; |
| |
| static int |
| route_map_command_status (struct vty *vty, int ret) |
| { |
| if (! ret) |
| return CMD_SUCCESS; |
| |
| switch (ret) |
| { |
| case RMAP_RULE_MISSING: |
| vty_out (vty, "Can't find rule.%s", VNL); |
| break; |
| case RMAP_COMPILE_ERROR: |
| vty_out (vty, "Argument is malformed.%s", VNL); |
| break; |
| default: |
| vty_out (vty, "route-map add set failed.%s", VNL); |
| break; |
| } |
| return CMD_WARNING; |
| } |
| |
| /* add "match address" */ |
| DEFUN (ospf6_routemap_match_address_prefixlist, |
| ospf6_routemap_match_address_prefixlist_cmd, |
| "match ipv6 address prefix-list WORD", |
| "Match values\n" |
| IPV6_STR |
| "Match address of route\n" |
| "Match entries of prefix-lists\n" |
| "IPv6 prefix-list name\n") |
| { |
| int ret = route_map_add_match ((struct route_map_index *) vty->index, |
| "ipv6 address prefix-list", argv[0]); |
| return route_map_command_status (vty, ret); |
| } |
| |
| /* delete "match address" */ |
| DEFUN (ospf6_routemap_no_match_address_prefixlist, |
| ospf6_routemap_no_match_address_prefixlist_cmd, |
| "no match ipv6 address prefix-list WORD", |
| NO_STR |
| "Match values\n" |
| IPV6_STR |
| "Match address of route\n" |
| "Match entries of prefix-lists\n" |
| "IPv6 prefix-list name\n") |
| { |
| int ret = route_map_delete_match ((struct route_map_index *) vty->index, |
| "ipv6 address prefix-list", argv[0]); |
| return route_map_command_status (vty, ret); |
| } |
| |
| /* add "set metric-type" */ |
| DEFUN (ospf6_routemap_set_metric_type, |
| ospf6_routemap_set_metric_type_cmd, |
| "set metric-type (type-1|type-2)", |
| "Set value\n" |
| "Type of metric\n" |
| "OSPF6 external type 1 metric\n" |
| "OSPF6 external type 2 metric\n") |
| { |
| int ret = route_map_add_set ((struct route_map_index *) vty->index, |
| "metric-type", argv[0]); |
| return route_map_command_status (vty, ret); |
| } |
| |
| /* delete "set metric-type" */ |
| DEFUN (ospf6_routemap_no_set_metric_type, |
| ospf6_routemap_no_set_metric_type_cmd, |
| "no set metric-type (type-1|type-2)", |
| NO_STR |
| "Set value\n" |
| "Type of metric\n" |
| "OSPF6 external type 1 metric\n" |
| "OSPF6 external type 2 metric\n") |
| { |
| int ret = route_map_delete_set ((struct route_map_index *) vty->index, |
| "metric-type", argv[0]); |
| return route_map_command_status (vty, ret); |
| } |
| |
| /* add "set metric" */ |
| DEFUN (set_metric, |
| set_metric_cmd, |
| "set metric <0-4294967295>", |
| "Set value\n" |
| "Metric value\n" |
| "Metric value\n") |
| { |
| int ret = route_map_add_set ((struct route_map_index *) vty->index, |
| "metric", argv[0]); |
| return route_map_command_status (vty, ret); |
| } |
| |
| /* delete "set metric" */ |
| DEFUN (no_set_metric, |
| no_set_metric_cmd, |
| "no set metric <0-4294967295>", |
| NO_STR |
| "Set value\n" |
| "Metric\n" |
| "METRIC value\n") |
| { |
| int ret = route_map_delete_set ((struct route_map_index *) vty->index, |
| "metric", argv[0]); |
| return route_map_command_status (vty, ret); |
| } |
| |
| /* add "set forwarding-address" */ |
| DEFUN (ospf6_routemap_set_forwarding, |
| ospf6_routemap_set_forwarding_cmd, |
| "set forwarding-address X:X::X:X", |
| "Set value\n" |
| "Forwarding Address\n" |
| "IPv6 Address\n") |
| { |
| int ret = route_map_add_set ((struct route_map_index *) vty->index, |
| "forwarding-address", argv[0]); |
| return route_map_command_status (vty, ret); |
| } |
| |
| /* delete "set forwarding-address" */ |
| DEFUN (ospf6_routemap_no_set_forwarding, |
| ospf6_routemap_no_set_forwarding_cmd, |
| "no set forwarding-address X:X::X:X", |
| NO_STR |
| "Set value\n" |
| "Forwarding Address\n" |
| "IPv6 Address\n") |
| { |
| int ret = route_map_delete_set ((struct route_map_index *) vty->index, |
| "forwarding-address", argv[0]); |
| return route_map_command_status (vty, ret); |
| } |
| |
| static void |
| ospf6_routemap_init (void) |
| { |
| route_map_init (); |
| route_map_init_vty (); |
| route_map_add_hook (ospf6_asbr_routemap_update); |
| route_map_delete_hook (ospf6_asbr_routemap_update); |
| |
| route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd); |
| route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd); |
| route_map_install_set (&ospf6_routemap_rule_set_metric_cmd); |
| route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd); |
| |
| /* Match address prefix-list */ |
| install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd); |
| install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd); |
| |
| /* ASE Metric Type (e.g. Type-1/Type-2) */ |
| install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd); |
| install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd); |
| |
| /* ASE Metric */ |
| install_element (RMAP_NODE, &set_metric_cmd); |
| install_element (RMAP_NODE, &no_set_metric_cmd); |
| |
| /* ASE Metric */ |
| install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd); |
| install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd); |
| } |
| |
| |
| /* Display functions */ |
| static int |
| ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) |
| { |
| struct ospf6_as_external_lsa *external; |
| char buf[64]; |
| struct in6_addr in6, *forwarding; |
| |
| assert (lsa->header); |
| external = (struct ospf6_as_external_lsa *) |
| OSPF6_LSA_HEADER_END (lsa->header); |
| |
| /* bits */ |
| snprintf (buf, sizeof (buf), "%c%c%c", |
| (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E' : '-'), |
| (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F' : '-'), |
| (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T' : '-')); |
| |
| vty_out (vty, " Bits: %s%s", buf, VNL); |
| vty_out (vty, " Metric: %5lu%s", (u_long) OSPF6_ASBR_METRIC (external), |
| VNL); |
| |
| ospf6_prefix_options_printbuf (external->prefix.prefix_options, |
| buf, sizeof (buf)); |
| vty_out (vty, " Prefix Options: %s%s", buf, |
| VNL); |
| |
| vty_out (vty, " Referenced LSType: %d%s", |
| ntohs (external->prefix.prefix_refer_lstype), |
| VNL); |
| |
| ospf6_prefix_in6_addr (&in6, &external->prefix); |
| inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); |
| vty_out (vty, " Prefix: %s/%d%s", buf, |
| external->prefix.prefix_length, VNL); |
| |
| /* Forwarding-Address */ |
| if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) |
| { |
| forwarding = (struct in6_addr *) |
| ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) + |
| OSPF6_PREFIX_SPACE (external->prefix.prefix_length)); |
| inet_ntop (AF_INET6, forwarding, buf, sizeof (buf)); |
| vty_out (vty, " Forwarding-Address: %s%s", buf, VNL); |
| } |
| |
| return 0; |
| } |
| |
| static void |
| ospf6_asbr_external_route_show (struct vty *vty, struct ospf6_route *route) |
| { |
| struct ospf6_external_info *info = route->route_option; |
| char prefix[64], id[16], forwarding[64]; |
| u_int32_t tmp_id; |
| |
| prefix2str (&route->prefix, prefix, sizeof (prefix)); |
| tmp_id = ntohl (info->id); |
| inet_ntop (AF_INET, &tmp_id, id, sizeof (id)); |
| if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding)) |
| inet_ntop (AF_INET6, &info->forwarding, forwarding, sizeof (forwarding)); |
| else |
| snprintf (forwarding, sizeof (forwarding), ":: (ifindex %d)", |
| route->nexthop[0].ifindex); |
| |
| vty_out (vty, "%c %-32s %-15s type-%d %5lu %s%s", |
| zebra_route_char(info->type), |
| prefix, id, route->path.metric_type, |
| (u_long) (route->path.metric_type == 2 ? |
| route->path.cost_e2 : route->path.cost), |
| forwarding, VNL); |
| } |
| |
| DEFUN (show_ipv6_ospf6_redistribute, |
| show_ipv6_ospf6_redistribute_cmd, |
| "show ipv6 ospf6 redistribute", |
| SHOW_STR |
| IP6_STR |
| OSPF6_STR |
| "redistributing External information\n" |
| ) |
| { |
| struct ospf6_route *route; |
| |
| ospf6_redistribute_show_config (vty); |
| |
| for (route = ospf6_route_head (ospf6->external_table); route; |
| route = ospf6_route_next (route)) |
| ospf6_asbr_external_route_show (vty, route); |
| |
| return CMD_SUCCESS; |
| } |
| |
| struct ospf6_lsa_handler as_external_handler = |
| { |
| OSPF6_LSTYPE_AS_EXTERNAL, |
| "AS-External", |
| ospf6_as_external_lsa_show |
| }; |
| |
| void |
| ospf6_asbr_init (void) |
| { |
| ospf6_routemap_init (); |
| |
| ospf6_install_lsa_handler (&as_external_handler); |
| |
| install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd); |
| install_element (ENABLE_NODE, &show_ipv6_ospf6_redistribute_cmd); |
| |
| install_element (OSPF6_NODE, &ospf6_redistribute_cmd); |
| install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd); |
| install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd); |
| } |
| |
| |
| DEFUN (debug_ospf6_asbr, |
| debug_ospf6_asbr_cmd, |
| "debug ospf6 asbr", |
| DEBUG_STR |
| OSPF6_STR |
| "Debug OSPFv3 ASBR function\n" |
| ) |
| { |
| OSPF6_DEBUG_ASBR_ON (); |
| return CMD_SUCCESS; |
| } |
| |
| DEFUN (no_debug_ospf6_asbr, |
| no_debug_ospf6_asbr_cmd, |
| "no debug ospf6 asbr", |
| NO_STR |
| DEBUG_STR |
| OSPF6_STR |
| "Debug OSPFv3 ASBR function\n" |
| ) |
| { |
| OSPF6_DEBUG_ASBR_OFF (); |
| return CMD_SUCCESS; |
| } |
| |
| int |
| config_write_ospf6_debug_asbr (struct vty *vty) |
| { |
| if (IS_OSPF6_DEBUG_ASBR) |
| vty_out (vty, "debug ospf6 asbr%s", VNL); |
| return 0; |
| } |
| |
| void |
| install_element_ospf6_debug_asbr () |
| { |
| install_element (ENABLE_NODE, &debug_ospf6_asbr_cmd); |
| install_element (ENABLE_NODE, &no_debug_ospf6_asbr_cmd); |
| install_element (CONFIG_NODE, &debug_ospf6_asbr_cmd); |
| install_element (CONFIG_NODE, &no_debug_ospf6_asbr_cmd); |
| } |
| |
| |