/* * 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 #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; tinfo.ifindex = ifindex; 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 " QUAGGA_REDIST_STR_OSPF6D, "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D ) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_OSPF6) return CMD_WARNING; 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 " QUAGGA_REDIST_STR_OSPF6D " route-map WORD", "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D "Route map reference\n" "Route map name\n" ) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_OSPF6) return CMD_WARNING; 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 " QUAGGA_REDIST_STR_OSPF6D, NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D ) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_OSPF6) return CMD_WARNING; 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, }; /* `match interface IFNAME' */ /* Match function should return 1 if match is success else return zero. */ static route_map_result_t ospf6_routemap_rule_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct interface *ifp; struct ospf6_external_info *ei; if (type == RMAP_OSPF6) { ei = ((struct ospf6_route *) object)->route_option; ifp = if_lookup_by_name ((char *)rule); if (ifp != NULL && ei->ifindex == ifp->ifindex) return RMAP_MATCH; } return RMAP_NOMATCH; } /* Route map `interface' match statement. `arg' should be interface name. */ static void * ospf6_routemap_rule_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `interface' value. */ static void ospf6_routemap_rule_match_interface_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for interface matching. */ struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = { "interface", ospf6_routemap_rule_match_interface, ospf6_routemap_rule_match_interface_compile, ospf6_routemap_rule_match_interface_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); } /* "match interface" */ DEFUN (ospf6_routemap_match_interface, ospf6_routemap_match_interface_cmd, "match interface WORD", MATCH_STR "Match first hop interface of route\n" "Interface name\n") { return route_map_add_match ((struct route_map_index *) vty->index, "interface", argv[0]); } /* "no match interface WORD" */ DEFUN (ospf6_routemap_no_match_interface, ospf6_routemap_no_match_interface_cmd, "no match interface", MATCH_STR NO_STR "Match first hop interface of route\n") { int ret = route_map_delete_match ((struct route_map_index *) vty->index, "interface", (argc == 0) ? NULL : argv[0]); return route_map_command_status (vty, ret); } ALIAS (ospf6_routemap_no_match_interface, ospf6_routemap_no_match_interface_val_cmd, "no match interface WORD", MATCH_STR NO_STR "Match first hop interface of route\n" "Interface name\n") /* 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_match (&ospf6_routemap_rule_match_interface_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); /* Match interface */ install_element (RMAP_NODE, &ospf6_routemap_match_interface_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_val_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); } void ospf6_asbr_terminate (void) { route_map_finish (); } 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); }