diff options
author | hasso <hasso> | 2004-05-18 20:57:06 +0200 |
---|---|---|
committer | hasso <hasso> | 2004-05-18 20:57:06 +0200 |
commit | 508e53e2eef3eefba4c1aa771529027fd4486ea8 (patch) | |
tree | 0e25e1b344a7b8e2c4551cfcb74d5a011dd0865d /ospf6d/ospf6_asbr.c | |
parent | Start of new ospf6d merge from Zebra. (diff) | |
download | frr-508e53e2eef3eefba4c1aa771529027fd4486ea8.tar.xz frr-508e53e2eef3eefba4c1aa771529027fd4486ea8.zip |
Ospf6d merge from Zebra repository with added privs stuff and merged
zclient changes.
Diffstat (limited to 'ospf6d/ospf6_asbr.c')
-rw-r--r-- | ospf6d/ospf6_asbr.c | 1875 |
1 files changed, 1090 insertions, 785 deletions
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 5846ab8a7..81edb60d1 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2002 Yasuhiro Ohara + * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * @@ -30,78 +30,644 @@ #include "table.h" #include "plist.h" #include "thread.h" +#include "linklist.h" -#include "ospf6_prefix.h" /* xxx for ospf6_asbr.h */ -#include "ospf6_lsa.h" /* xxx for ospf6_asbr.h */ -#include "ospf6_route.h" /* xxx for ospf6_asbr.h, ospf6_zebra.h */ +#include "ospf6d.h" +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" #include "ospf6_zebra.h" -#include "ospf6_asbr.h" -#include "ospf6_damp.h" #include "ospf6_top.h" -#include "ospf6_lsdb.h" -#include "ospf6_proto.h" +#include "ospf6_area.h" +#include "ospf6_asbr.h" +#include "ospf6_intra.h" + +unsigned char conf_debug_ospf6_asbr = 0; + +char *zroute_name[] = +{ "system", "kernel", "connected", "static", + "rip", "ripng", "ospf", "ospf6", "bgp", "unknown" }; -extern struct thread_master *master; +char *zroute_abname[] = +{ "X", "K", "C", "S", "R", "R", "O", "O", "B", "?" }; -struct route_table *external_table; -struct +#define ZROUTE_NAME(x) \ + (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? zroute_name[(x)] : \ + zroute_name[ZEBRA_ROUTE_MAX]) +#define ZROUTE_ABNAME(x) \ + (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? zroute_abname[(x)] : \ + zroute_abname[ZEBRA_ROUTE_MAX]) + +/* AS External LSA origination */ +void +ospf6_as_external_lsa_originate_sub (struct ospf6_route *route, int force) { - char *name; - struct route_map *map; -} rmap [ZEBRA_ROUTE_MAX]; + char buffer[OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + struct ospf6_lsa *old, *lsa; -static u_int32_t link_state_id = 0; + struct ospf6_external_info *info = route->route_option; + struct ospf6_as_external_lsa *as_external_lsa; + char buf[64]; + caddr_t p; -char * -zroute_name[] = -{ - "system", "kernel", "connected", "static", - "rip", "ripng", "ospf", "ospf6", "isis", "bgp", "unknown" -}; -char * -zroute_abname[] = + /* find previous LSA */ + old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), + htonl (info->id), ospf6->router_id, + ospf6->lsdb); + + if (IS_OSPF6_DEBUG_LSA (ORIGINATE)) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info ("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 = htonl (info->id); + lsa_header->adv_router = ospf6->router_id; + lsa_header->seqnum = + ospf6_lsa_new_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, ospf6); + 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); + lsa->scope = ospf6; + if (force) + SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH); + + /* Originate */ + ospf6_lsa_originate (lsa); +} + +int +ospf6_as_external_lsa_reoriginate (struct ospf6_lsa *lsa) { - "X", "K", "C", "S", "R", "R", "O", "O", "I", "B", "?" -}; + struct prefix prefix_id; + struct route_node *node; + struct ospf6_route *route; + + /* create/update binding in external_id_table */ + prefix_id.family = AF_INET; + prefix_id.prefixlen = 32; + prefix_id.u.prefix4.s_addr = lsa->header->id; + node = route_node_get (ospf6->external_id_table, &prefix_id); + route = node->info; + + if (route) + ospf6_as_external_lsa_originate_sub (route, 1); + else + ospf6_lsa_premature_aging (lsa); + + return 0; +} + + + +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_ASBR) + zlog_info ("Calculate AS-External route for %s", lsa->name); + + if (lsa->header->adv_router == ospf6->router_id) + { + if (IS_OSPF6_DEBUG_ASBR) + zlog_info ("Ignore self-originated AS-External-LSA"); + return; + } + + if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) + { + if (IS_OSPF6_DEBUG_ASBR) + zlog_info ("Ignore LSA with LSInfinity Metric"); + return; + } -#define ZROUTE_NAME(x) \ - (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \ - zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX]) + asbr_id.family = AF_INET; + asbr_id.prefixlen = 32; + asbr_id.u.prefix4.s_addr = lsa->header->adv_router; + asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->asbr_table); + + if (asbr_entry == NULL) + { + if (IS_OSPF6_DEBUG_ASBR) + { + prefix2str (&asbr_id, buf, sizeof (buf)); + zlog_info ("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_ASBR) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info ("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_ASBR) + zlog_info ("Withdraw AS-External route for %s", lsa->name); + + if (lsa->header->adv_router == ospf6->router_id) + { + if (IS_OSPF6_DEBUG_ASBR) + zlog_info ("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_ASBR) + { + prefix2str (&prefix, buf, sizeof (buf)); + zlog_info ("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_ASBR) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info ("AS-External route remove: %s", buf); + } + ospf6_route_remove (route, ospf6->route_table); + } +} + +void +ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry) +{ + char buf[64]; + struct ospf6_lsa *lsa; + u_int16_t type; + u_int32_t router; + + if (IS_OSPF6_DEBUG_ASBR) + { + ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf)); + zlog_info ("New ASBR %s found", buf); + } + + 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); + } + + if (IS_OSPF6_DEBUG_ASBR) + { + ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf)); + zlog_info ("Calculation for new ASBR %s done", buf); + } +} + +void +ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry) +{ + char buf[64]; + struct ospf6_lsa *lsa; + u_int16_t type; + u_int32_t router; + + if (IS_OSPF6_DEBUG_ASBR) + { + ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf)); + zlog_info ("ASBR %s disappeared", buf); + } + + 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); + + if (IS_OSPF6_DEBUG_ASBR) + { + ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf)); + zlog_info ("Calculation for old ASBR %s done", buf); + } +} -#define ZROUTE_ABNAME(x) \ - (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \ - zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX]) + /* redistribute function */ + void ospf6_asbr_routemap_set (int type, char *mapname) { - if (rmap[type].name) - free (rmap[type].name); - - rmap[type].name = strdup (mapname); - rmap[type].map = route_map_lookup_by_name (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); } void ospf6_asbr_routemap_unset (int type) { - if (rmap[type].name) - free (rmap[type].name); - rmap[type].name = NULL; - rmap[type].map = NULL; + if (ospf6->rmap[type].name) + free (ospf6->rmap[type].name); + ospf6->rmap[type].name = NULL; + ospf6->rmap[type].map = NULL; } void ospf6_asbr_routemap_update () { - int i; - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + int type; + + if (ospf6 == NULL) + return; + + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { - if (rmap[i].name) - rmap[i].map = route_map_lookup_by_name (rmap[i].name); + if (ospf6->rmap[type].name) + ospf6->rmap[type].map = + route_map_lookup_by_name (ospf6->rmap[type].name); else - rmap[i].map = NULL; + ospf6->rmap[type].map = NULL; + } +} + +int +ospf6_asbr_is_asbr (struct ospf6 *o) +{ + return o->external_table->count; +} + +void +ospf6_asbr_redistribute_set (int type) +{ + ospf6_zebra_redistribute (type); +} + +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]; + listnode lnode; + struct ospf6_area *oa; + + if (! ospf6_zebra_is_redistribute (type)) + return; + + if (IS_OSPF6_DEBUG_ASBR) + { + prefix2str (prefix, pbuf, sizeof (pbuf)); + zlog_info ("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 (); + 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_MATCH) + { + if (IS_OSPF6_DEBUG_ASBR) + zlog_info ("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_info ("Advertise as AS-External Id:%s", ibuf); + } + + ospf6_as_external_lsa_originate_sub (match, 0); + 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 *) + XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, sizeof (struct ospf6_external_info)); + memset (info, 0, 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_info ("Advertise as AS-External Id:%s", ibuf); + } + + ospf6_as_external_lsa_originate_sub (route, 0); + + /* Router-Bit (ASBR Flag) may have to be updated */ + for (lnode = listhead (ospf6->area_list); lnode; nextnode (lnode)) + { + oa = (struct ospf6_area *) getdata (lnode); + 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]; + listnode lnode; + 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_info ("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_info ("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_info ("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_premature_aging (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 (lnode = listhead (ospf6->area_list); lnode; nextnode (lnode)) + { + oa = (struct ospf6_area *) getdata (lnode); + OSPF6_ROUTER_LSA_SCHEDULE (oa); } } @@ -129,9 +695,9 @@ DEFUN (ospf6_redistribute, else if (strncmp (argv[0], "bgp", 3) == 0) type = ZEBRA_ROUTE_BGP; - ospf6_zebra_no_redistribute (type); + ospf6_asbr_redistribute_unset (type); ospf6_asbr_routemap_unset (type); - ospf6_zebra_redistribute (type); + ospf6_asbr_redistribute_set (type); return CMD_SUCCESS; } @@ -161,9 +727,9 @@ DEFUN (ospf6_redistribute_routemap, else if (strncmp (argv[0], "bgp", 3) == 0) type = ZEBRA_ROUTE_BGP; - ospf6_zebra_no_redistribute (type); + ospf6_asbr_redistribute_unset (type); ospf6_asbr_routemap_set (type, argv[1]); - ospf6_zebra_redistribute (type); + ospf6_asbr_redistribute_set (type); return CMD_SUCCESS; } @@ -180,9 +746,6 @@ DEFUN (no_ospf6_redistribute, ) { int type = 0; - struct route_node *node; - struct ospf6_external_route *route; - struct ospf6_external_info *info, *info_next = NULL; if (strncmp (argv[0], "sta", 3) == 0) type = ZEBRA_ROUTE_STATIC; @@ -195,48 +758,30 @@ DEFUN (no_ospf6_redistribute, else if (strncmp (argv[0], "bgp", 3) == 0) type = ZEBRA_ROUTE_BGP; - ospf6_zebra_no_redistribute (type); + ospf6_asbr_redistribute_unset (type); ospf6_asbr_routemap_unset (type); - /* remove redistributed route */ - for (node = route_top (external_table); node; node = route_next (node)) - { - route = node->info; - if (! route) - continue; - for (info = route->info_head; info; info = info_next) - { - info_next = info->next; - if (info->type != type) - continue; - ospf6_asbr_route_remove (info->type, info->ifindex, - &route->prefix); - } - } - return CMD_SUCCESS; } - int ospf6_redistribute_config_write (struct vty *vty) { - int i; + int type; - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { - if (i == ZEBRA_ROUTE_OSPF6) + if (type == ZEBRA_ROUTE_OSPF6) continue; - - if (! ospf6_zebra_is_redistribute (i)) + if (! ospf6_zebra_is_redistribute (type)) continue; - if (rmap[i].map) + if (ospf6->rmap[type].name) vty_out (vty, " redistribute %s route-map %s%s", - ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE); + ZROUTE_NAME (type), ospf6->rmap[type].name, VTY_NEWLINE); else vty_out (vty, " redistribute %s%s", - ZROUTE_NAME(i), VTY_NEWLINE); + ZROUTE_NAME (type), VTY_NEWLINE); } return 0; @@ -245,748 +790,420 @@ ospf6_redistribute_config_write (struct vty *vty) void ospf6_redistribute_show_config (struct vty *vty) { - int i; + int type; + int nroute[ZEBRA_ROUTE_MAX]; + int total; + struct ospf6_route *route; + struct ospf6_external_info *info; - if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) && - ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) && - ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) && - ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) && - ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP)) - return; + 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", VTY_NEWLINE); - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + vty_out (vty, "Redistributing External Routes from:%s", VTY_NEWLINE); + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { - if (i == ZEBRA_ROUTE_OSPF6) + if (type == ZEBRA_ROUTE_OSPF6) continue; - if (! ospf6_zebra_is_redistribute (i)) + if (! ospf6_zebra_is_redistribute (type)) continue; - if (rmap[i].map) - vty_out (vty, " %s with route-map %s%s", - ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE); + 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 !)"), + VTY_NEWLINE); else - vty_out (vty, " %s%s", ZROUTE_NAME(i), VTY_NEWLINE); + vty_out (vty, " %d: %s%s", nroute[type], + ZROUTE_NAME (type), VTY_NEWLINE); } + vty_out (vty, "Total %d routes%s", total, VTY_NEWLINE); } -/* AS External LSA origination */ -int -ospf6_asbr_external_lsa_originate (struct thread *thread) -{ - struct ospf6_external_info *info; - char buffer [MAXLSASIZE]; - struct ospf6_lsa_as_external *e; - char *p; - - info = THREAD_ARG (thread); - - /* clear thread */ - info->thread_originate = NULL; - - if (info->is_removed) - { - if (IS_OSPF6_DUMP_ASBR) - { - char pbuf[64]; - prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); - zlog_info ("ASBR: quit redistribution %s: state is down", - pbuf); - } - return 0; - } - - /* prepare buffer */ - memset (buffer, 0, sizeof (buffer)); - e = (struct ospf6_lsa_as_external *) buffer; - p = (char *) (e + 1); - - if (info->metric_type == 2) - SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */ - else - UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */ - - /* forwarding address */ - if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding)) - SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F); - else - UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F); - - /* external route tag */ - UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T); - - /* set metric. note: related to E bit */ - OSPF6_ASBR_METRIC_SET (e, info->metric); - - /* prefixlen */ - e->prefix.prefix_length = info->route->prefix.prefixlen; - - /* PrefixOptions */ - e->prefix.prefix_options = info->prefix_options; - /* don't use refer LS-type */ - e->prefix.prefix_refer_lstype = htons (0); + +/* Routemap Functions */ +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; - /* set Prefix */ - memcpy (p, &info->route->prefix.u.prefix6, - OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen)); - ospf6_prefix_apply_mask (&e->prefix); - p += OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen); + if (type != RMAP_OSPF6) + return RMAP_NOMATCH; - /* Forwarding address */ - if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F)) - { - memcpy (p, &info->forwarding, sizeof (struct in6_addr)); - p += sizeof (struct in6_addr); - } + plist = prefix_list_lookup (AFI_IP6, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; - /* External Route Tag */ - if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T)) - { - /* xxx */ - } - - ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), - htonl (info->id), ospf6->router_id, - (char *) buffer, p - buffer, ospf6); - return 0; + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); } -int -ospf6_asbr_schedule_external (void *data) +void * +ospf6_routemap_rule_match_address_prefixlist_compile (char *arg) { - struct ospf6_external_info *info = data; - u_long elasped_time, time = 0; - - if (info->thread_originate) - { - if (IS_OSPF6_DUMP_ASBR) - { - char pbuf[64]; - prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); - zlog_info ("ASBR: schedule redistribution %s: another thread", - pbuf); - } - return 0; - } - - elasped_time = - ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), - htonl (info->id), ospf6->router_id, ospf6); - if (elasped_time < OSPF6_MIN_LS_INTERVAL) - time = OSPF6_MIN_LS_INTERVAL - elasped_time; - else - time = 0; - - //if (IS_OSPF6_DUMP_ASBR) - { - char pbuf[64]; - prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); - zlog_info ("ASBR: schedule redistribution %s as LS-ID %ld after %lu sec", - pbuf, (u_long) info->id, time); - } - - if (time) - info->thread_originate = - thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, time); - else - info->thread_originate = - thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, 0); - - return 0; + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } -int -ospf6_asbr_external_lsa_flush (void *data) +void +ospf6_routemap_rule_match_address_prefixlist_free (void *rule) { - struct ospf6_lsa *lsa = data; - if (lsa) - ospf6_lsa_premature_aging (lsa); - return 0; + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } -int -ospf6_asbr_external_lsa_refresh (void *data) +struct route_map_rule_cmd +ospf6_routemap_rule_match_address_prefixlist_cmd = { - struct ospf6_lsa *lsa = data; - struct ospf6_lsa_as_external *e; - struct prefix prefix; - struct route_node *node; - struct ospf6_external_route *route = NULL; - struct ospf6_external_info *info = NULL; - struct ospf6_external_info *match = NULL; - - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: refresh %s", lsa->str); - - e = (struct ospf6_lsa_as_external *) (lsa->header + 1); - ospf6_prefix_in6_addr (&e->prefix, &prefix.u.prefix6); - prefix.prefixlen = e->prefix.prefix_length; - prefix.family = AF_INET6; - apply_mask_ipv6 ((struct prefix_ipv6 *) &prefix); - - for (node = route_top (external_table); node; node = route_next (node)) - { - route = node->info; - if (route == NULL) - continue; - - for (info = route->info_head; info; info = info->next) - { - if (lsa->header->id == htonl (info->id)) - match = info; - } - } - - if (match == NULL) - { - ospf6_lsa_premature_aging (lsa); - return 0; - } - - ospf6_asbr_schedule_external (match); - return 0; + "ipv6 address prefix-list", + ospf6_routemap_rule_match_address_prefixlist, + ospf6_routemap_rule_match_address_prefixlist_compile, + ospf6_routemap_rule_match_address_prefixlist_free, +}; -#if 0 - node = route_node_lookup (external_table, &prefix); - if (! node || ! node->info) - { - char pname[64]; +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; - prefix2str (&prefix, pname, sizeof (pname)); - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: could not find %s: premature age", pname); - ospf6_lsa_premature_aging (lsa); - return 0; - } + if (type != RMAP_OSPF6) + return RMAP_OKAY; - /* find external_info */ - route = node->info; - for (info = route->info_head; info; info = info->next) - { - if (lsa->header->id == htonl (info->id)) - break; - } - - if (info) - ospf6_asbr_schedule_external (info); + if (strcmp (metric_type, "type-2") == 0) + route->path.metric_type = 2; else - ospf6_lsa_premature_aging (lsa); + route->path.metric_type = 1; - return 0; -#endif + return RMAP_OKAY; } -void -ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix, - u_int nexthop_num, struct in6_addr *nexthop) +void * +ospf6_routemap_rule_set_metric_type_compile (char *arg) { - int ret; - struct route_node *node; - struct ospf6_external_route *route; - struct ospf6_external_info *info, tinfo; - -#if defined (MUSICA) || defined (LINUX) - /* XXX As long as the OSPFv3 redistribution is applied to all the connected - * routes, one needs to filter the ::/96 prefixes. - * However it could be a wanted case, it will be removed soon. - */ - struct prefix_ipv6 *p = (prefix_ipv6 *)prefix; - - if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) || - (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) - return; -#endif /* MUSICA or LINUX */ - - if (! ospf6_zebra_is_redistribute (type)) - return; - - /* apply route-map */ - memset (&tinfo, 0, sizeof (struct ospf6_external_info)); - if (rmap[type].map) - { - ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo); - if (ret == RMAP_DENYMATCH) - { - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: denied by route-map %s", rmap[type].name); - return; - } - } - - node = route_node_get (external_table, prefix); - route = node->info; - - if (! route) - { - route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, - sizeof (struct ospf6_external_route)); - memset (route, 0, sizeof (struct ospf6_external_route)); - - memcpy (&route->prefix, prefix, sizeof (struct prefix)); - - node->info = route; - route->node = node; - } - - for (info = route->info_head; info; info = info->next) - { - if (info->type == type && info->ifindex == ifindex) - break; - } - - if (! info) - { - info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, - sizeof (struct ospf6_external_info)); - memset (info, 0, sizeof (struct ospf6_external_info)); - - info->route = route; - /* add tail */ - info->prev = route->info_tail; - if (route->info_tail) - route->info_tail->next = info; - else - route->info_head = info; - route->info_tail = info; - - info->id = link_state_id++; - } - - /* copy result of route-map */ - info->metric_type = tinfo.metric_type; - info->metric = tinfo.metric; - memcpy (&info->forwarding, &tinfo.forwarding, - sizeof (struct in6_addr)); - - info->type = type; - info->ifindex = ifindex; - - if (nexthop_num && nexthop) - { - info->nexthop_num = nexthop_num; - - if (info->nexthop) - XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop); - - info->nexthop = (struct in6_addr *) - XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, - nexthop_num * sizeof (struct in6_addr)); - memcpy (info->nexthop, nexthop, - nexthop_num * sizeof (struct in6_addr)); - } - - info->is_removed = 0; - - //if (IS_OSPF6_DUMP_ASBR) - { - char pbuf[64]; - struct timeval now; - prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); - gettimeofday (&now, NULL); - zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld", - pbuf, (u_long) info->id, now.tv_sec, now.tv_usec); - } - -#ifdef HAVE_OSPF6_DAMP - ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix, - ospf6_asbr_schedule_external, info); -#else /*HAVE_OSPF6_DAMP*/ - ospf6_asbr_schedule_external (info); -#endif /*HAVE_OSPF6_DAMP*/ + if (strcmp (arg, "type-2") && strcmp (arg, "type-1")) + return NULL; + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } void -ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix) +ospf6_routemap_rule_set_metric_type_free (void *rule) { - struct route_node *node; - struct ospf6_external_route *route; - struct ospf6_external_info *info; - struct ospf6_lsa *lsa; - -#if defined (MUSICA) || defined (LINUX) - /* XXX As long as the OSPFv3 redistribution is applied to all the connected - * routes, one needs to filter the ::/96 prefixes. - * However it could be a wanted case, it will be removed soon. - */ - struct prefix_ipv6 *p = (prefix_ipv6 *)prefix; - - if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) || - (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) - return; -#endif /* MUSICA or LINUX */ - - node = route_node_get (external_table, prefix); - route = node->info; - - if (! route) - return; - - for (info = route->info_head; info; info = info->next) - { - if (info->type == type && info->ifindex == ifindex) - break; - } + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} - if (! info) - return; +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, +}; - //if (IS_OSPF6_DUMP_ASBR) - { - char pbuf[64]; - struct timeval now; - prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); - gettimeofday (&now, NULL); - zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld", - pbuf, (u_long) info->id, now.tv_sec, now.tv_usec); - } +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 (info->thread_originate) - thread_cancel (info->thread_originate); - info->thread_originate = NULL; - - lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), - htonl (info->id), ospf6->router_id, ospf6); -#ifdef HAVE_OSPF6_DAMP - ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix, - ospf6_asbr_external_lsa_flush, lsa); -#else /*HAVE_OSPF6_DAMP*/ - ospf6_asbr_external_lsa_flush (lsa); -#endif /*HAVE_OSPF6_DAMP*/ - -#if 1 - info->is_removed = 1; -#else - /* remove from route */ - if (info->prev) - info->prev->next = info->next; - else - info->route->info_head = info->next; - if (info->next) - info->next->prev = info->prev; - else - info->route->info_tail = info->prev; + if (type != RMAP_OSPF6) + return RMAP_OKAY; - /* if no info, free route */ - if (! info->route->info_head && ! info->route->info_tail) - { - info->route->node->info = NULL; - free (info->route); - } + route->path.cost = atoi (metric); + return RMAP_OKAY; +} - if (info->nexthop) - free (info->nexthop); - free (info); -#endif /*0*/ +void * +ospf6_routemap_rule_set_metric_compile (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); } void -ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa) +ospf6_routemap_rule_set_metric_free (void *rule) { - struct ospf6_lsa_as_external *external; - struct prefix_ls asbr_id; - struct ospf6_route_req asbr_entry; - struct ospf6_route_req request; - - external = OSPF6_LSA_HEADER_END (lsa->header); - - if (IS_LSA_MAXAGE (lsa)) - { - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: maxage external lsa: %s seq: %lx", - lsa->str, (u_long)ntohl (lsa->header->seqnum)); - ospf6_asbr_external_lsa_remove (lsa); - return; - } - - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: new external lsa: %s seq: %lx", - lsa->str, (u_long)ntohl (lsa->header->seqnum)); - - if (lsa->header->adv_router == ospf6->router_id) - { - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: my external LSA, ignore"); - return; - } + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} - if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) - { - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: metric is infinity, ignore"); - return; - } +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, +}; - memset (&asbr_id, 0, sizeof (asbr_id)); - asbr_id.family = AF_UNSPEC; - asbr_id.prefixlen = 64; /* xxx */ - asbr_id.adv_router.s_addr = lsa->header->adv_router; +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; - ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id, - ospf6->topology_table); + if (type != RMAP_OSPF6) + return RMAP_OKAY; - if (ospf6_route_end (&asbr_entry)) + if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1) { - if (IS_OSPF6_DUMP_ASBR) - { - char buf[64]; - inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf)); - zlog_info ("ASBR: router %s not found, ignore", buf); - } - return; + memset (&info->forwarding, 0, sizeof (struct in6_addr)); + return RMAP_ERROR; } - memset (&request, 0, sizeof (request)); - request.route.type = OSPF6_DEST_TYPE_NETWORK; - request.route.prefix.family = AF_INET6; - request.route.prefix.prefixlen = external->prefix.prefix_length; - memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1), - OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen)); - - request.path.area_id = asbr_entry.path.area_id; - request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL); - request.path.origin.id = lsa->header->id; - request.path.origin.adv_router = lsa->header->adv_router; - if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E)) - { - request.path.type = OSPF6_PATH_TYPE_EXTERNAL2; - request.path.metric_type = 2; - request.path.cost = asbr_entry.path.cost; - request.path.cost_e2 = OSPF6_ASBR_METRIC (external); - } - else - { - request.path.type = OSPF6_PATH_TYPE_EXTERNAL1; - request.path.metric_type = 1; - request.path.cost = asbr_entry.path.cost - + OSPF6_ASBR_METRIC (external); - request.path.cost_e2 = 0; - } - request.path.prefix_options = external->prefix.prefix_options; + return RMAP_OKAY; +} - while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr == - asbr_id.adv_router.s_addr && - asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER) - { - memcpy (&request.nexthop, &asbr_entry.nexthop, - sizeof (struct ospf6_nexthop)); - if (IS_OSPF6_DUMP_ASBR) - { - char buf[64], nhop[64], ifname[IFNAMSIZ]; - prefix2str (&request.route.prefix, buf, sizeof (buf)); - inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop)); - if_indextoname (request.nexthop.ifindex, ifname); - zlog_info ("ASBR: add route: %s %s%%%s", buf, nhop, ifname); - } - ospf6_route_add (&request, ospf6->route_table); - ospf6_route_next (&asbr_entry); - } +void * +ospf6_routemap_rule_set_forwarding_compile (char *arg) +{ + struct in6_addr a; + if (inet_pton (AF_INET6, arg, &a) != 1) + return NULL; + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } void -ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa) +ospf6_routemap_rule_set_forwarding_free (void *rule) { - struct ospf6_lsa_as_external *external; - struct prefix dest; - char buf[64]; - struct ospf6_route_req request; - - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: withdraw external lsa: %s seq: %lx", - lsa->str, (u_long)ntohl (lsa->header->seqnum)); - - if (lsa->header->adv_router == ospf6->router_id) - { - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: my external LSA, ignore"); - return; - } - - external = OSPF6_LSA_HEADER_END (lsa->header); - memset (&dest, 0, sizeof (dest)); - dest.family = AF_INET6; - dest.prefixlen = external->prefix.prefix_length; - memcpy (&dest.u.prefix6, (char *)(external + 1), - OSPF6_PREFIX_SPACE (dest.prefixlen)); + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} - ospf6_route_lookup (&request, &dest, ospf6->route_table); - if (ospf6_route_end (&request)) - { - if (IS_OSPF6_DUMP_ASBR) - { - prefix2str (&dest, buf, sizeof (buf)); - zlog_info ("ASBR: %s not found", buf); - } - return; - } +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, +}; - while (request.path.origin.id != lsa->header->id || - request.path.origin.adv_router != lsa->header->adv_router) - { - if (prefix_same (&request.route.prefix, &dest) != 1) - { - if (IS_OSPF6_DUMP_ASBR) - zlog_info ("ASBR: Can't find the entry matches the origin"); - return; - } - ospf6_route_next (&request); - } - assert (request.path.origin.id == lsa->header->id); - assert (request.path.origin.adv_router == request.path.origin.adv_router); +int +route_map_command_status (struct vty *vty, int ret) +{ + if (! ret) + return CMD_SUCCESS; - while (request.path.origin.id == lsa->header->id && - request.path.origin.adv_router == lsa->header->adv_router && - prefix_same (&request.route.prefix, &dest) == 1) + switch (ret) { - if (IS_OSPF6_DUMP_ASBR) - { - char nhop[64], ifname[IFNAMSIZ]; - prefix2str (&dest, buf, sizeof (buf)); - inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop)); - if_indextoname (request.nexthop.ifindex, ifname); - zlog_info ("ASBR: remove route: %s %s%%%s", buf, nhop, ifname); - } - - ospf6_route_remove (&request, ospf6->route_table); - ospf6_route_next (&request); + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + break; + default: + vty_out (vty, "route-map add set failed.%s", VTY_NEWLINE); + break; } + return CMD_WARNING; } -void -ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new) +/* 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") { - assert (old || new); + 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); +} - if (old == NULL) - ospf6_asbr_external_lsa_add (new); - else if (new == NULL) - ospf6_asbr_external_lsa_remove (old); - else - { - ospf6_route_table_freeze (ospf6->route_table); - ospf6_asbr_external_lsa_remove (old); - ospf6_asbr_external_lsa_add (new); - ospf6_route_table_thaw (ospf6->route_table); - } +/* 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); } -void -ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry) +/* 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") { - struct ospf6_lsdb_node node; + int ret = route_map_add_set ((struct route_map_index *) vty->index, + "metric-type", argv[0]); + return route_map_command_status (vty, ret); +} - struct prefix_ls *inter_router; - u_int32_t id, adv_router; +/* 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); +} - inter_router = (struct prefix_ls *) &topo_entry->route.prefix; - id = inter_router->id.s_addr; - adv_router = inter_router->adv_router.s_addr; +/* 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); +} - if (IS_OSPF6_DUMP_ASBR) - { - char buf[64]; - inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf)); - zlog_info ("ASBR: new router found: %s", buf); - } +/* 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); +} - if (ntohl (id) != 0 || - ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E)) - { - zlog_warn ("ASBR: Inter topology table malformed"); - return; - } +/* 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); +} - for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL), - adv_router, ospf6->lsdb); - ! ospf6_lsdb_is_end (&node); - ospf6_lsdb_next (&node)) - ospf6_asbr_external_lsa_add (node.lsa); +/* 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); } void -ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry) +ospf6_routemap_init () { - struct prefix_ls *inter_router; - u_int32_t id, adv_router; - struct ospf6_route_req request; - - inter_router = (struct prefix_ls *) &topo_entry->route.prefix; - id = inter_router->id.s_addr; - adv_router = inter_router->adv_router.s_addr; - - if (IS_OSPF6_DUMP_ASBR) - { - char buf[64]; - inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf)); - zlog_info ("ASBR: router disappearing: %s", buf); - } - - if (ntohl (id) != 0 || - ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E)) - { - zlog_warn ("ASBR: Inter topology table malformed"); - } - - for (ospf6_route_head (&request, ospf6->route_table); - ! ospf6_route_end (&request); - ospf6_route_next (&request)) - { - if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 && - request.path.type != OSPF6_PATH_TYPE_EXTERNAL2) - continue; - if (request.path.area_id != topo_entry->path.area_id) - continue; - if (request.path.origin.adv_router != topo_entry->path.origin.adv_router) - continue; - if (memcmp (&topo_entry->nexthop, &request.nexthop, - sizeof (struct ospf6_nexthop))) - continue; - - ospf6_route_remove (&request, ospf6->route_table); - } + 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 */ int -ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa) +ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { - struct ospf6_lsa_as_external *external; - char buf[128], *ptr; - struct in6_addr in6; + struct ospf6_as_external_lsa *external; + char buf[64]; + struct in6_addr in6, *forwarding; assert (lsa->header); - external = (struct ospf6_lsa_as_external *)(lsa->header + 1); + external = (struct ospf6_as_external_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); /* bits */ - snprintf (buf, sizeof (buf), "%s%s%s", - (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" : "-")); + 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, VTY_NEWLINE); - vty_out (vty, " Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external), + vty_out (vty, " Metric: %5lu%s", (u_long) OSPF6_ASBR_METRIC (external), VTY_NEWLINE); - ospf6_prefix_options_str (external->prefix.prefix_options, - buf, sizeof (buf)); - vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE); + ospf6_prefix_options_printbuf (external->prefix.prefix_options, + buf, sizeof (buf)); + vty_out (vty, " Prefix Options: %s%s", buf, + VTY_NEWLINE); vty_out (vty, " Referenced LSType: %d%s", - ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE); + ntohs (external->prefix.prefix_refer_lstype), + VTY_NEWLINE); - ospf6_prefix_in6_addr (&external->prefix, &in6); + 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, VTY_NEWLINE); + vty_out (vty, " Prefix: %s/%d%s", buf, + external->prefix.prefix_length, VTY_NEWLINE); /* Forwarding-Address */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) { - ptr = ((char *)(external + 1)) - + OSPF6_PREFIX_SPACE (external->prefix.prefix_length); - inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf)); + 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, VTY_NEWLINE); } @@ -994,96 +1211,184 @@ ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa) } void -ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new) -{ - if (old) - ospf6_asbr_external_lsa_remove (old); - if (new && ! IS_LSA_MAXAGE (new)) - ospf6_asbr_external_lsa_add (new); -} - -void -ospf6_asbr_register_as_external () +ospf6_asbr_external_route_show (struct vty *vty, struct ospf6_route *route) { - struct ospf6_lsa_slot slot; + struct ospf6_external_info *info = route->route_option; + char prefix[64], id[16], forwarding[64]; + u_int32_t tmp_id; - memset (&slot, 0, sizeof (slot)); - slot.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL); - slot.name = "AS-External"; - slot.func_show = ospf6_asbr_external_show; - slot.func_refresh = ospf6_asbr_external_lsa_refresh; - ospf6_lsa_slot_register (&slot); - - ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook = - ospf6_asbr_database_hook; + 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, "%s %-32s %-15s type-%d %5lu %s%s", + ZROUTE_ABNAME (info->type), + prefix, id, route->path.metric_type, + (u_long) (route->path.metric_type == 2 ? + route->path.cost_e2 : route->path.cost), + forwarding, VTY_NEWLINE); } -void -ospf6_asbr_external_info_show (struct vty *vty, - struct ospf6_external_info *info) +DEFUN (show_ipv6_ospf6_redistribute, + show_ipv6_ospf6_redistribute_cmd, + "show ipv6 ospf6 redistribute", + SHOW_STR + IP6_STR + OSPF6_STR + "redistributing External information\n" + ) { - char prefix_buf[64], id_buf[16]; - struct in_addr id; + struct ospf6_route *route; - if (info->is_removed) - return; + ospf6_redistribute_show_config (vty); - id.s_addr = ntohl (info->id); - inet_ntop (AF_INET, &id, id_buf, sizeof (id_buf)); - prefix2str (&info->route->prefix, prefix_buf, sizeof (prefix_buf)); - vty_out (vty, "%s %-32s %3d %-15s %3d %lu(type-%d)%s", - ZROUTE_ABNAME(info->type), prefix_buf, info->ifindex, id_buf, - info->nexthop_num, (u_long) info->metric, info->metric_type, - VTY_NEWLINE); + for (route = ospf6_route_head (ospf6->external_table); route; + route = ospf6_route_next (route)) + ospf6_asbr_external_route_show (vty, route); + + return CMD_SUCCESS; } -void -ospf6_asbr_external_route_show (struct vty *vty, - struct ospf6_external_route *route) +DEFUN (show_ipv6_ospf6_asbr, + show_ipv6_ospf6_asbr_cmd, + "show ipv6 ospf6 asbr", + SHOW_STR + IP6_STR + OSPF6_STR + "Show AS Boundary Router table\n" + ) { - struct ospf6_external_info *info; - for (info = route->info_head; info; info = info->next) - ospf6_asbr_external_info_show (vty, info); + ospf6_lsentry_table_show (vty, argc, argv, ospf6->asbr_table); + return CMD_SUCCESS; } -DEFUN (show_ipv6_route_ospf6_external, - show_ipv6_route_ospf6_external_cmd, - "show ipv6 ospf6 route redistribute", +ALIAS (show_ipv6_ospf6_asbr, + show_ipv6_ospf6_asbr_1_cmd, + "show ipv6 ospf6 asbr (A.B.C.D|A.B.C.D/M|detail)", SHOW_STR IP6_STR - ROUTE_STR OSPF6_STR - "redistributing External information\n" - ) + "Show AS Boundary Router table\n" + "Specify Router-ID\n" + "Display multiple entry by specifying match-prefix of Router-ID\n" + "Display Detail\n" + ); + +ALIAS (show_ipv6_ospf6_asbr, + show_ipv6_ospf6_asbr_2_cmd, + "show ipv6 ospf6 asbr (A.B.C.D|A.B.C.D/M|*) (A.B.C.D|A.B.C.D/M|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + "Show AS Boundary Router table\n" + "Specify Router-ID\n" + "Display multiple entry by specifying match-prefix of Router-ID\n" + "Wildcard Router-ID\n" + "Specify Link State ID\n" + "Display multiple entry by specifying match-prefix of Link State ID\n" + "Display Detail\n" + ); + +DEFUN (show_ipv6_ospf6_asbr_3, + show_ipv6_ospf6_asbr_3_cmd, + "show ipv6 ospf6 asbr (A.B.C.D|*) A.B.C.D/M detail", + SHOW_STR + IP6_STR + OSPF6_STR + "Show AS Boundary Router table\n" + "Specify Router-ID\n" + "Wildcard Router-ID\n" + "Display multiple entry by specifying match-prefix of Link State ID\n" + "Display Detail\n" + ) { - struct route_node *node; - struct ospf6_external_route *route; + char *sargv[CMD_ARGC_MAX]; + int i, sargc; - vty_out (vty, "%s %-32s %3s %-15s %3s %s%s", - " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric", - VTY_NEWLINE); - for (node = route_top (external_table); node; node = route_next (node)) - { - route = node->info; - if (route) - ospf6_asbr_external_route_show (vty, route); - } + /* copy argv to sargv and then append "detail" */ + for (i = 0; i < argc; i++) + sargv[i] = argv[i]; + sargc = argc; + sargv[sargc++] = "detail"; + sargv[sargc] = NULL; + + ospf6_lsentry_table_show (vty, sargc, sargv, ospf6->asbr_table); return CMD_SUCCESS; } + void ospf6_asbr_init () { - external_table = route_table_init (); - link_state_id = 0; + ospf6_routemap_init (); + + ospf6_lstype[5].name = "AS-External"; + ospf6_lstype[5].reoriginate = ospf6_as_external_lsa_reoriginate; + ospf6_lstype[5].show = ospf6_as_external_lsa_show; - ospf6_asbr_register_as_external (); + install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_redistribute_cmd); + + install_element (VIEW_NODE, &show_ipv6_ospf6_asbr_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_asbr_1_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_asbr_2_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_asbr_3_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_asbr_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_asbr_1_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_asbr_2_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_asbr_3_cmd); - install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_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", VTY_NEWLINE); + 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); +} + + |