void ospf6_prefix_apply_mask (struct ospf6_prefix *op) { u_char *pnt, mask; int index, offset; pnt = (u_char *)((caddr_t) op + sizeof (struct ospf6_prefix)); index = op->prefix_length / 8; offset = op->prefix_length % 8; mask = 0xff << (8 - offset); if (index > 16) { zlog_warn ("Prefix length too long: %d", op->prefix_length); return; } if (index == 16) return; pnt[index] &= mask; index ++; while (index < OSPF6_PREFIX_SPACE (op->prefix_length)) pnt[index++] = 0; }
void ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa) { 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 route of %s", lsa->str); if (lsa->header->adv_router == ospf6->router_id) { if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: Self-originated, 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)); prefix2str (&dest, buf, sizeof (buf)); if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: route: %s", buf); ospf6_route_lookup (&request, &dest, ospf6->route_table); if (ospf6_route_end (&request)) { zlog_info ("ASBR: route not found"); return; } 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) { 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); while (request.path.origin.id == lsa->header->id && request.path.origin.adv_router == lsa->header->adv_router && prefix_same (&request.route.prefix, &dest) == 1) { ospf6_route_remove (&request, ospf6->route_table); ospf6_route_next (&request); } }
/* 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; /*restarter 不产生 lsa*/ if(ospf6->restart) { return ; } /* 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); }
/* RFC 2328 12.4.3. Summary-LSAs */ void ospf6_abr_originate_summary_to_area (struct ospf6_route *route, struct ospf6_area *area) { struct ospf6_lsa *lsa, *old = NULL; struct ospf6_interface *oi; struct ospf6_route *summary, *range = NULL; struct ospf6_area *route_area; char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; caddr_t p; struct ospf6_inter_prefix_lsa *prefix_lsa; struct ospf6_inter_router_lsa *router_lsa; struct ospf6_route_table *summary_table = NULL; u_int16_t type; char buf[64]; int is_debug = 0; if (route->type == OSPF6_DEST_TYPE_ROUTER) { if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER)) { is_debug++; inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, sizeof (buf)); zlog_debug ("Originating summary in area %s for ASBR %s", area->name, buf); } summary_table = area->summary_router; } else { if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_PREFIX)) { is_debug++; prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("Originating summary in area %s for %s", area->name, buf); } summary_table = area->summary_prefix; } summary = ospf6_route_lookup (&route->prefix, summary_table); if (summary) old = ospf6_lsdb_lookup (summary->path.origin.type, summary->path.origin.id, area->ospf6->router_id, area->lsdb); /* if this route has just removed, remove corresponding LSA */ if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE)) { if (is_debug) zlog_debug ("The route has just removed, purge previous LSA"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* Only destination type network, range or ASBR are considered */ if (route->type != OSPF6_DEST_TYPE_NETWORK && route->type != OSPF6_DEST_TYPE_RANGE && (route->type != OSPF6_DEST_TYPE_ROUTER || ! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E))) { if (is_debug) zlog_debug ("Route type is none of network, range nor ASBR, withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* AS External routes are never considered */ if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) { if (is_debug) zlog_debug ("Path type is external, withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* do not generate if the path's area is the same as target area */ if (route->path.area_id == area->area_id) { if (is_debug) zlog_debug ("The route is in the area itself, ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* do not generate if the nexthops belongs to the target area */ oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex); if (oi && oi->area && oi->area == area) { if (is_debug) zlog_debug ("The route's nexthop is in the same area, ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* do not generate if the route cost is greater or equal to LSInfinity */ if (route->path.cost >= OSPF_LS_INFINITY) { if (is_debug) zlog_debug ("The cost exceeds LSInfinity, withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* if this is a route to ASBR */ if (route->type == OSPF6_DEST_TYPE_ROUTER) { /* Only the prefered best path is considered */ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST)) { if (is_debug) zlog_debug ("This is the secondary path to the ASBR, ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* Do not generate if the area is stub */ /* XXX */ } /* if this is an intra-area route, this may be suppressed by aggregation */ if (route->type == OSPF6_DEST_TYPE_NETWORK && route->path.type == OSPF6_PATH_TYPE_INTRA) { /* search for configured address range for the route's area */ route_area = ospf6_area_lookup (route->path.area_id, area->ospf6); assert (route_area); range = ospf6_route_lookup_bestmatch (&route->prefix, route_area->range_table); /* ranges are ignored when originate backbone routes to transit area. Otherwise, if ranges are configured, the route is suppressed. */ if (range && ! CHECK_FLAG (range->flag, OSPF6_ROUTE_REMOVE) && (route->path.area_id != OSPF_AREA_BACKBONE || ! IS_AREA_TRANSIT (area))) { if (is_debug) { prefix2str (&range->prefix, buf, sizeof (buf)); zlog_debug ("Suppressed by range %s of area %s", buf, route_area->name); } if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } } /* If this is a configured address range */ if (route->type == OSPF6_DEST_TYPE_RANGE) { /* If DoNotAdvertise is set */ if (CHECK_FLAG (route->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) { if (is_debug) zlog_debug ("This is the range with DoNotAdvertise set. ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* Whether the route have active longer prefix */ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) { if (is_debug) zlog_debug ("The range is not active. withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } } /* Check export list */ if (EXPORT_NAME (area)) { if (EXPORT_LIST (area) == NULL) EXPORT_LIST (area) = access_list_lookup (AFI_IP6, EXPORT_NAME (area)); if (EXPORT_LIST (area)) if (access_list_apply (EXPORT_LIST (area), &route->prefix) == FILTER_DENY) { if (is_debug) { inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, sizeof(buf)); zlog_debug ("prefix %s was denied by export list", buf); } return; } } /* Check filter-list */ if (PREFIX_NAME_OUT (area)) { if (PREFIX_LIST_OUT (area) == NULL) PREFIX_LIST_OUT (area) = prefix_list_lookup(AFI_IP6, PREFIX_NAME_OUT (area)); if (PREFIX_LIST_OUT (area)) if (prefix_list_apply (PREFIX_LIST_OUT (area), &route->prefix) != PREFIX_PERMIT) { if (is_debug) { inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, sizeof (buf)); zlog_debug ("prefix %s was denied by filter-list out", buf); } return; } } /* the route is going to be originated. store it in area's summary_table */ if (summary == NULL) { summary = ospf6_route_copy (route); if (route->type == OSPF6_DEST_TYPE_NETWORK || route->type == OSPF6_DEST_TYPE_RANGE) summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX); else summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER); summary->path.origin.adv_router = area->ospf6->router_id; summary->path.origin.id = ospf6_new_ls_id (summary->path.origin.type, summary->path.origin.adv_router, area->lsdb); summary = ospf6_route_add (summary, summary_table); } else { summary->type = route->type; quagga_gettime (QUAGGA_CLK_MONOTONIC, &summary->changed); } summary->path.router_bits = route->path.router_bits; summary->path.options[0] = route->path.options[0]; summary->path.options[1] = route->path.options[1]; summary->path.options[2] = route->path.options[2]; summary->path.prefix_options = route->path.prefix_options; summary->path.area_id = area->area_id; summary->path.type = OSPF6_PATH_TYPE_INTER; summary->path.cost = route->path.cost; summary->nexthop[0] = route->nexthop[0]; /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; if (route->type == OSPF6_DEST_TYPE_ROUTER) { router_lsa = (struct ospf6_inter_router_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); p = (caddr_t) router_lsa + sizeof (struct ospf6_inter_router_lsa); /* Fill Inter-Area-Router-LSA */ router_lsa->options[0] = route->path.options[0]; router_lsa->options[1] = route->path.options[1]; router_lsa->options[2] = route->path.options[2]; OSPF6_ABR_SUMMARY_METRIC_SET (router_lsa, route->path.cost); router_lsa->router_id = ADV_ROUTER_IN_PREFIX (&route->prefix); type = htons (OSPF6_LSTYPE_INTER_ROUTER); } else { prefix_lsa = (struct ospf6_inter_prefix_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); p = (caddr_t) prefix_lsa + sizeof (struct ospf6_inter_prefix_lsa); /* Fill Inter-Area-Prefix-LSA */ OSPF6_ABR_SUMMARY_METRIC_SET (prefix_lsa, route->path.cost); prefix_lsa->prefix.prefix_length = route->prefix.prefixlen; prefix_lsa->prefix.prefix_options = route->path.prefix_options; /* set Prefix */ memcpy (p, &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE (route->prefix.prefixlen)); ospf6_prefix_apply_mask (&prefix_lsa->prefix); p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen); type = htons (OSPF6_LSTYPE_INTER_PREFIX); } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = type; lsa_header->id = summary->path.origin.id; lsa_header->adv_router = area->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, area->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_area (lsa, area); }
void ospf6_asbr_external_lsa_update (struct ospf6_route_req *request) { char buffer [MAXLSASIZE]; u_int16_t size; struct ospf6_lsa_as_external *external; char *p; struct ospf6_route_req route; char pbuf[BUFSIZ]; /* assert this is best path; if not, return */ ospf6_route_lookup (&route, &request->route.prefix, request->table); if (memcmp (&route.path, &request->path, sizeof (route.path))) return; if (IS_OSPF6_DUMP_LSA) zlog_info ("Update AS-External: ID: %lu", (u_long) ntohl (request->path.origin.id)); /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); size = sizeof (struct ospf6_lsa_as_external); external = (struct ospf6_lsa_as_external *) buffer; p = (char *) (external + 1); if (route.path.metric_type == 2) SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */ else UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E); /* type1 */ /* forwarding address */ if (! IN6_IS_ADDR_UNSPECIFIED (&route.nexthop.address)) SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F); else UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F); /* external route tag */ UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T); /* set metric. note: related to E bit */ OSPF6_ASBR_METRIC_SET (external, route.path.cost); /* prefixlen */ external->prefix.prefix_length = route.route.prefix.prefixlen; /* PrefixOptions */ external->prefix.prefix_options = route.path.prefix_options; /* don't use refer LS-type */ external->prefix.prefix_refer_lstype = htons (0); if (IS_OSPF6_DUMP_LSA) { prefix2str (&route.route.prefix, pbuf, sizeof (pbuf)); zlog_info (" Prefix: %s", pbuf); } /* set Prefix */ memcpy (p, &route.route.prefix.u.prefix6, OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen)); ospf6_prefix_apply_mask (&external->prefix); size += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen); p += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen); /* Forwarding address */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) { memcpy (p, &route.nexthop.address, sizeof (struct in6_addr)); size += sizeof (struct in6_addr); p += sizeof (struct in6_addr); } /* External Route Tag */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T)) { /* xxx */ } ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), route.path.origin.id, ospf6->router_id, (char *) external, size, ospf6); return; }
void ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa) { 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)) return; if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: Calculate %s", lsa->str); if (lsa->header->adv_router == ospf6->router_id) { if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: Self-originated, ignore"); return; } if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) { if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: Metric is Infinity, ignore"); return; } 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; ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id, ospf6->topology_table); if (ospf6_route_end (&asbr_entry)) { if (IS_OSPF6_DUMP_ASBR) { char buf[64]; inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf)); zlog_info ("ASBR: ASBR %s not found, ignore", buf); } return; } 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; 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)); ospf6_route_add (&request, ospf6->route_table); ospf6_route_next (&asbr_entry); } }