paul | 718e374 | 2002-12-13 20:15:29 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2002 Yasuhiro Ohara |
| 3 | * |
| 4 | * This file is part of GNU Zebra. |
| 5 | * |
| 6 | * GNU Zebra is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License as published by the |
| 8 | * Free Software Foundation; either version 2, or (at your option) any |
| 9 | * later version. |
| 10 | * |
| 11 | * GNU Zebra is distributed in the hope that it will be useful, but |
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with GNU Zebra; see the file COPYING. If not, write to the |
| 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 19 | * Boston, MA 02111-1307, USA. |
| 20 | */ |
| 21 | |
| 22 | #include "ospf6d.h" |
| 23 | |
| 24 | static int intra_index; |
| 25 | #define IS_OSPF6_DUMP_INTRA (ospf6_dump_is_on (intra_index)) |
| 26 | |
| 27 | #define ADD 0 |
| 28 | #define REMOVE 1 |
| 29 | |
| 30 | static void |
| 31 | ospf6_intra_route_calculate (int type, struct ospf6_lsa *lsa, |
| 32 | struct ospf6_route_req *topo_entry) |
| 33 | { |
| 34 | struct ospf6_intra_area_prefix_lsa *intra_prefix; |
| 35 | char *start, *end; |
| 36 | struct ospf6_prefix *ospf6_prefix; |
| 37 | struct ospf6_route_req request; |
| 38 | struct ospf6_area *area; |
| 39 | |
| 40 | if (IS_OSPF6_DUMP_INTRA) |
| 41 | { |
| 42 | char buf[64]; |
| 43 | struct prefix_ls *p_ls; |
| 44 | p_ls = (struct prefix_ls *) &topo_entry->route.prefix; |
| 45 | inet_ntop (AF_INET, &p_ls->adv_router, buf, sizeof (buf)); |
| 46 | zlog_info ("INTRA: Calculate [%s] %s and %s", |
| 47 | (type == ADD ? "add" : "remove"), lsa->str, buf); |
| 48 | } |
| 49 | |
| 50 | intra_prefix = OSPF6_LSA_HEADER_END (lsa->header); |
| 51 | |
| 52 | area = lsa->scope; |
| 53 | assert (area); |
| 54 | |
| 55 | start = (char *) (intra_prefix + 1); |
| 56 | end = (char *) lsa->header + ntohs (lsa->header->length); |
| 57 | for (ospf6_prefix = (struct ospf6_prefix *) start; |
| 58 | (char *) ospf6_prefix < end; |
| 59 | ospf6_prefix = OSPF6_NEXT_PREFIX (ospf6_prefix)) |
| 60 | { |
| 61 | memset (&request, 0, sizeof (request)); |
| 62 | |
| 63 | request.route.type = OSPF6_DEST_TYPE_NETWORK; |
| 64 | request.route.prefix.family = AF_INET6; |
| 65 | request.route.prefix.prefixlen = ospf6_prefix->prefix_length; |
| 66 | ospf6_prefix_in6_addr (ospf6_prefix, &request.route.prefix.u.prefix6); |
| 67 | |
| 68 | request.path.type = OSPF6_PATH_TYPE_INTRA; |
| 69 | request.path.area_id = area->area_id; |
| 70 | request.path.origin.type = lsa->header->type; |
| 71 | request.path.origin.id = lsa->header->id; |
| 72 | request.path.origin.adv_router = lsa->header->adv_router; |
| 73 | request.path.cost = topo_entry->path.cost + |
| 74 | ntohs (ospf6_prefix->prefix_metric); |
| 75 | request.path.capability[0] = topo_entry->path.capability[0]; |
| 76 | request.path.capability[1] = topo_entry->path.capability[1]; |
| 77 | request.path.capability[2] = topo_entry->path.capability[2]; |
| 78 | |
| 79 | memcpy (&request.nexthop.address, &topo_entry->nexthop.address, |
| 80 | sizeof (request.nexthop.address)); |
| 81 | request.nexthop.ifindex = topo_entry->nexthop.ifindex; |
| 82 | |
| 83 | if (type == ADD) |
| 84 | ospf6_route_add (&request, area->route_table); |
| 85 | else if (type == REMOVE) |
| 86 | ospf6_route_remove (&request, area->route_table); |
| 87 | else |
| 88 | assert (0); |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | int |
| 93 | ospf6_intra_prefix_database_hook_remove (void *data) |
| 94 | { |
| 95 | struct ospf6_lsa *lsa = data; |
| 96 | struct ospf6_area *area; |
| 97 | struct ospf6_intra_area_prefix_lsa *iap; |
| 98 | struct prefix_ls prefix_ls; |
| 99 | struct ospf6_route_req topo_entry; |
| 100 | |
| 101 | if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX)) |
| 102 | return 0; |
| 103 | |
| 104 | area = (struct ospf6_area *) lsa->scope; |
| 105 | assert (area); |
| 106 | |
| 107 | if (IS_OSPF6_DUMP_INTRA) |
| 108 | zlog_info ("INTRA: area %s remove: %s", area->str, lsa->str); |
| 109 | |
| 110 | iap = OSPF6_LSA_HEADER_END (lsa->header); |
| 111 | memset (&prefix_ls, 0, sizeof (prefix_ls)); |
| 112 | prefix_ls.prefixlen = 64; |
| 113 | prefix_ls.adv_router.s_addr = iap->refer_advrtr; |
| 114 | prefix_ls.id.s_addr = iap->refer_lsid; |
| 115 | |
| 116 | if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && |
| 117 | iap->refer_lsid != htonl (0)) |
| 118 | { |
| 119 | zlog_warn ("SPF: Malformed ID %lu of Router reference in %s", |
| 120 | (u_long) ntohl (iap->refer_lsid), lsa->str); |
| 121 | prefix_ls.id.s_addr = htonl (0); |
| 122 | } |
| 123 | |
| 124 | ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls, |
| 125 | area->table_topology); |
| 126 | |
| 127 | while (iap->refer_lstype == topo_entry.path.origin.type && |
| 128 | iap->refer_lsid == topo_entry.path.origin.id && |
| 129 | iap->refer_advrtr == topo_entry.path.origin.adv_router) |
| 130 | { |
| 131 | ospf6_intra_route_calculate (REMOVE, lsa, &topo_entry); |
| 132 | ospf6_route_next (&topo_entry); |
| 133 | } |
| 134 | return 0; |
| 135 | } |
| 136 | |
| 137 | int |
| 138 | ospf6_intra_prefix_database_hook_add (void *data) |
| 139 | { |
| 140 | struct ospf6_lsa *lsa = data; |
| 141 | struct ospf6_area *area; |
| 142 | struct ospf6_intra_area_prefix_lsa *iap; |
| 143 | struct prefix_ls prefix_ls; |
| 144 | struct ospf6_route_req topo_entry; |
| 145 | |
| 146 | if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX)) |
| 147 | return 0; |
| 148 | |
| 149 | area = (struct ospf6_area *) lsa->scope; |
| 150 | assert (area); |
| 151 | |
| 152 | if (IS_LSA_MAXAGE (lsa)) |
| 153 | { |
| 154 | ospf6_intra_prefix_database_hook_remove (lsa); |
| 155 | return 0; |
| 156 | } |
| 157 | |
| 158 | if (IS_OSPF6_DUMP_INTRA) |
| 159 | zlog_info ("INTRA: area %s add: %s", area->str, lsa->str); |
| 160 | |
| 161 | iap = OSPF6_LSA_HEADER_END (lsa->header); |
| 162 | |
| 163 | memset (&prefix_ls, 0, sizeof (struct prefix_ls)); |
| 164 | prefix_ls.prefixlen = 64; |
| 165 | prefix_ls.adv_router.s_addr = iap->refer_advrtr; |
| 166 | prefix_ls.id.s_addr = iap->refer_lsid; |
| 167 | |
| 168 | if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && |
| 169 | iap->refer_lsid != htonl (0)) |
| 170 | { |
| 171 | zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s", |
| 172 | (u_long) ntohl (iap->refer_lsid), lsa->str); |
| 173 | prefix_ls.id.s_addr = htonl (0); |
| 174 | } |
| 175 | |
| 176 | ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls, |
| 177 | area->table_topology); |
| 178 | |
| 179 | while (iap->refer_lstype == topo_entry.path.origin.type && |
| 180 | iap->refer_lsid == topo_entry.path.origin.id && |
| 181 | iap->refer_advrtr == topo_entry.path.origin.adv_router) |
| 182 | { |
| 183 | ospf6_intra_route_calculate (ADD, lsa, &topo_entry); |
| 184 | ospf6_route_next (&topo_entry); |
| 185 | } |
| 186 | return 0; |
| 187 | } |
| 188 | |
| 189 | void |
| 190 | ospf6_intra_topology_add (void *data) |
| 191 | { |
| 192 | struct ospf6_route_req *topo_entry = data; |
| 193 | struct ospf6_area *area; |
| 194 | struct ospf6_intra_area_prefix_lsa *iap; |
| 195 | struct ospf6_lsdb_node node; |
| 196 | |
| 197 | area = ospf6_area_lookup (topo_entry->path.area_id, ospf6); |
| 198 | if (! area) |
| 199 | return; |
| 200 | |
| 201 | if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER && |
| 202 | (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) || |
| 203 | CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))) |
| 204 | ospf6_route_add (topo_entry, ospf6->topology_table); |
| 205 | |
| 206 | for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX), |
| 207 | area->lsdb); |
| 208 | ! ospf6_lsdb_is_end (&node); |
| 209 | ospf6_lsdb_next (&node)) |
| 210 | { |
| 211 | if (IS_LSA_MAXAGE (node.lsa)) |
| 212 | continue; |
| 213 | |
| 214 | iap = OSPF6_LSA_HEADER_END (node.lsa->header); |
| 215 | |
| 216 | if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && |
| 217 | iap->refer_lsid != htonl (0)) |
| 218 | { |
| 219 | zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s", |
| 220 | (u_long) ntohl (iap->refer_lsid), node.lsa->str); |
| 221 | } |
| 222 | |
| 223 | if (iap->refer_lstype != topo_entry->path.origin.type || |
| 224 | iap->refer_lsid != topo_entry->path.origin.id || |
| 225 | iap->refer_advrtr != topo_entry->path.origin.adv_router) |
| 226 | continue; |
| 227 | |
| 228 | ospf6_intra_route_calculate (ADD, node.lsa, topo_entry); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | void |
| 233 | ospf6_intra_topology_remove (void *data) |
| 234 | { |
| 235 | struct ospf6_route_req *topo_entry = data; |
| 236 | struct ospf6_area *area; |
| 237 | struct ospf6_intra_area_prefix_lsa *iap; |
| 238 | struct ospf6_lsdb_node node; |
| 239 | |
| 240 | area = ospf6_area_lookup (topo_entry->path.area_id, ospf6); |
| 241 | if (! area) |
| 242 | return; |
| 243 | |
| 244 | if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER && |
| 245 | (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) || |
| 246 | CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))) |
| 247 | ospf6_route_remove (topo_entry, ospf6->topology_table); |
| 248 | |
| 249 | for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX), |
| 250 | area->lsdb); |
| 251 | ! ospf6_lsdb_is_end (&node); |
| 252 | ospf6_lsdb_next (&node)) |
| 253 | { |
| 254 | if (IS_LSA_MAXAGE (node.lsa)) |
| 255 | continue; |
| 256 | |
| 257 | iap = OSPF6_LSA_HEADER_END (node.lsa->header); |
| 258 | |
| 259 | if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && |
| 260 | iap->refer_lsid != htonl (0)) |
| 261 | zlog_warn ("SPF: Malformed ID %lu of Router reference in %s", |
| 262 | (u_long) ntohl (iap->refer_lsid), node.lsa->str); |
| 263 | |
| 264 | if (iap->refer_lstype != topo_entry->path.origin.type || |
| 265 | iap->refer_lsid != topo_entry->path.origin.id || |
| 266 | iap->refer_advrtr != topo_entry->path.origin.adv_router) |
| 267 | continue; |
| 268 | |
| 269 | ospf6_intra_route_calculate (REMOVE, node.lsa, topo_entry); |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | |
| 274 | /*****************************************/ |
| 275 | /* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */ |
| 276 | /*****************************************/ |
| 277 | |
| 278 | #define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\ |
| 279 | if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\ |
| 280 | {\ |
| 281 | char buf[64];\ |
| 282 | prefix2str (addr, buf, sizeof (buf));\ |
| 283 | if (IS_OSPF6_DUMP_PREFIX)\ |
| 284 | zlog_info (" Filter out Linklocal: %s", buf);\ |
| 285 | continue;\ |
| 286 | } |
| 287 | |
| 288 | #define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\ |
| 289 | if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\ |
| 290 | {\ |
| 291 | char buf[64];\ |
| 292 | prefix2str (addr, buf, sizeof (buf));\ |
| 293 | if (IS_OSPF6_DUMP_PREFIX)\ |
| 294 | zlog_info (" Filter out Unspecified: %s", buf);\ |
| 295 | continue;\ |
| 296 | } |
| 297 | |
| 298 | #define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\ |
| 299 | if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\ |
| 300 | {\ |
| 301 | char buf[64];\ |
| 302 | prefix2str (addr, buf, sizeof (buf));\ |
| 303 | if (IS_OSPF6_DUMP_PREFIX)\ |
| 304 | zlog_info (" Filter out Loopback: %s", buf);\ |
| 305 | continue;\ |
| 306 | } |
| 307 | |
| 308 | #define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\ |
| 309 | if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\ |
| 310 | {\ |
| 311 | char buf[64];\ |
| 312 | prefix2str (addr, buf, sizeof (buf));\ |
| 313 | if (IS_OSPF6_DUMP_PREFIX)\ |
| 314 | zlog_info (" Filter out V4Compat: %s", buf);\ |
| 315 | continue;\ |
| 316 | } |
| 317 | |
| 318 | #define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\ |
| 319 | if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\ |
| 320 | {\ |
| 321 | char buf[64];\ |
| 322 | prefix2str (addr, buf, sizeof (buf));\ |
| 323 | if (IS_OSPF6_DUMP_PREFIX)\ |
| 324 | zlog_info (" Filter out V4Mapped: %s", buf);\ |
| 325 | continue;\ |
| 326 | } |
| 327 | |
| 328 | |
| 329 | int |
| 330 | ospf6_lsa_intra_prefix_show (struct vty *vty, struct ospf6_lsa *lsa) |
| 331 | { |
| 332 | struct ospf6_intra_area_prefix_lsa *iap_lsa; |
| 333 | struct ospf6_prefix *prefix; |
| 334 | unsigned short prefixnum; |
| 335 | char buf[128], type[32], id[32], adv_router[32]; |
| 336 | struct in6_addr in6; |
| 337 | char *start, *end, *current; |
| 338 | |
| 339 | assert (lsa->header); |
| 340 | iap_lsa = (struct ospf6_intra_area_prefix_lsa *) (lsa->header + 1); |
| 341 | |
| 342 | prefixnum = ntohs (iap_lsa->prefix_number); |
| 343 | ospf6_lsa_type_string (iap_lsa->refer_lstype, type, sizeof (type)); |
| 344 | inet_ntop (AF_INET, &iap_lsa->refer_lsid, id, sizeof (id)); |
| 345 | inet_ntop (AF_INET, &iap_lsa->refer_advrtr, adv_router, |
| 346 | sizeof (adv_router)); |
| 347 | |
| 348 | vty_out (vty, " Number of Prefix: %d%s", prefixnum, VTY_NEWLINE); |
| 349 | vty_out (vty, " Referenced LS Type: %s%s", type, VTY_NEWLINE); |
| 350 | vty_out (vty, " Referenced LS ID: %s%s", id, VTY_NEWLINE); |
| 351 | vty_out (vty, " Referenced Advertising Router: %s%s", adv_router, |
| 352 | VTY_NEWLINE); |
| 353 | |
| 354 | start = (char *) lsa->header + sizeof (struct ospf6_lsa_header) |
| 355 | + sizeof (struct ospf6_intra_area_prefix_lsa); |
| 356 | end = (char *) lsa->header + ntohs (lsa->header->length); |
| 357 | |
| 358 | for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix)) |
| 359 | { |
| 360 | prefix = (struct ospf6_prefix *) current; |
| 361 | if (current + OSPF6_PREFIX_SIZE (prefix) > end) |
| 362 | { |
| 363 | vty_out (vty, " Trailing %d byte garbage ... Malformed%s", |
| 364 | end - current, VTY_NEWLINE); |
| 365 | return -1; |
| 366 | } |
| 367 | |
| 368 | ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf)); |
| 369 | vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE); |
| 370 | |
| 371 | ospf6_prefix_in6_addr (prefix, &in6); |
| 372 | inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); |
| 373 | vty_out (vty, " Prefix: %s/%d%s", |
| 374 | buf, prefix->prefix_length, VTY_NEWLINE); |
| 375 | } |
| 376 | |
| 377 | return 0; |
| 378 | } |
| 379 | |
| 380 | void |
| 381 | ospf6_lsa_intra_prefix_update_transit (char *ifname) |
| 382 | { |
| 383 | char buffer [MAXLSASIZE]; |
| 384 | u_int16_t size; |
| 385 | struct ospf6_lsa *old; |
| 386 | struct interface *ifp; |
| 387 | struct ospf6_interface *o6i; |
| 388 | struct ospf6_neighbor *o6n; |
| 389 | |
| 390 | struct ospf6_intra_area_prefix_lsa *iap; |
| 391 | struct ospf6_lsdb_node n; |
| 392 | listnode node; |
| 393 | char *start, *end, *current; |
| 394 | struct ospf6_prefix *prefix, *dup, *src, *dst; |
| 395 | struct ospf6_link_lsa *link; |
| 396 | char buf[128]; |
| 397 | int count, prefix_num; |
| 398 | |
| 399 | list adv_list; |
| 400 | |
| 401 | ifp = if_lookup_by_name (ifname); |
| 402 | if (! ifp) |
| 403 | { |
| 404 | zlog_warn ("Update Intra-Prefix (Transit): No such Interface: %s", |
| 405 | ifname); |
| 406 | return; |
| 407 | } |
| 408 | |
| 409 | o6i = (struct ospf6_interface *) ifp->info; |
| 410 | if (! o6i || ! o6i->area) |
| 411 | { |
| 412 | zlog_warn ("Update Intra-Prefix (Transit): Interface not enabled: %s", |
| 413 | ifname); |
| 414 | return; |
| 415 | } |
| 416 | |
| 417 | /* find previous LSA */ |
| 418 | old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), |
| 419 | htonl (o6i->if_id), ospf6->router_id, |
| 420 | o6i->area); |
| 421 | |
| 422 | /* Don't originate Network-LSA if not DR */ |
| 423 | if (o6i->state != IFS_DR) |
| 424 | { |
| 425 | if (old) |
| 426 | { |
| 427 | if (IS_OSPF6_DUMP_PREFIX) |
| 428 | zlog_info ("Update Intra-Prefix (Transit): %s not DR", |
| 429 | o6i->interface->name); |
| 430 | ospf6_lsa_premature_aging (old); |
| 431 | } |
| 432 | return; |
| 433 | } |
| 434 | |
| 435 | /* If none of neighbor is adjacent to us */ |
| 436 | count = 0; |
| 437 | o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state); |
| 438 | if (count == 0) |
| 439 | { |
| 440 | if (IS_OSPF6_DUMP_PREFIX) |
| 441 | zlog_info ("Update Intra-Prefix (Transit): %s is Stub", |
| 442 | o6i->interface->name); |
| 443 | if (old) |
| 444 | ospf6_lsa_premature_aging (old); |
| 445 | return; |
| 446 | } |
| 447 | |
| 448 | if (IS_OSPF6_DUMP_PREFIX) |
| 449 | zlog_info ("Update Intra-Prefix (Transit): Interface %s", |
| 450 | o6i->interface->name); |
| 451 | |
| 452 | adv_list = list_new (); |
| 453 | |
| 454 | /* foreach Link-LSA associated with this Link */ |
| 455 | for (ospf6_lsdb_type (&n, htons (OSPF6_LSA_TYPE_LINK), o6i->lsdb); |
| 456 | ! ospf6_lsdb_is_end (&n); ospf6_lsdb_next (&n)) |
| 457 | { |
| 458 | if (IS_LSA_MAXAGE (n.lsa)) |
| 459 | continue; |
| 460 | |
| 461 | if (IS_OSPF6_DUMP_PREFIX) |
| 462 | zlog_info ("Update Intra-Prefix (Transit): Checking %s", |
| 463 | n.lsa->str); |
| 464 | |
| 465 | /* Check status of the advertising router */ |
| 466 | if (n.lsa->header->adv_router != o6i->area->ospf6->router_id) |
| 467 | { |
| 468 | o6n = ospf6_neighbor_lookup (n.lsa->header->adv_router, o6i); |
| 469 | if (! o6n) |
| 470 | { |
| 471 | if (IS_OSPF6_DUMP_PREFIX) |
| 472 | zlog_info ("Update Intra-Prefix (Transit): neighbor not found"); |
| 473 | continue; |
| 474 | } |
| 475 | |
| 476 | if (o6n->state != NBS_FULL) |
| 477 | { |
| 478 | if (IS_OSPF6_DUMP_PREFIX) |
| 479 | zlog_info ("Update Intra-Prefix (Transit): %s not FULL", |
| 480 | o6n->str); |
| 481 | continue; |
| 482 | } |
| 483 | } |
| 484 | |
| 485 | /* For each Prefix in this Link-LSA */ |
| 486 | link = (struct ospf6_link_lsa *) (n.lsa->header + 1); |
| 487 | prefix_num = ntohl (link->llsa_prefix_num); |
| 488 | |
| 489 | if (IS_OSPF6_DUMP_PREFIX) |
| 490 | zlog_info (" Prefix #%d", prefix_num); |
| 491 | |
| 492 | start = (char *) (link + 1); |
| 493 | end = (char *) (n.lsa->header) + ntohs (n.lsa->header->length); |
| 494 | prefix = (struct ospf6_prefix *) start; |
| 495 | for (current = start; current < end; |
| 496 | current += OSPF6_PREFIX_SIZE (prefix)) |
| 497 | { |
| 498 | prefix = (struct ospf6_prefix *) current; |
| 499 | ospf6_prefix_string (prefix, buf, sizeof (buf)); |
| 500 | |
| 501 | /* Check duplicate prefix */ |
| 502 | dup = ospf6_prefix_lookup (adv_list, prefix); |
| 503 | if (dup) |
| 504 | { |
| 505 | if (IS_OSPF6_DUMP_PREFIX) |
| 506 | zlog_info (" Duplicate %s", buf); |
| 507 | dup->prefix_options |= prefix->prefix_options; |
| 508 | continue; |
| 509 | } |
| 510 | |
| 511 | if (prefix_num <= 0) |
| 512 | { |
| 513 | zlog_warn (" Wong prefix number ..."); |
| 514 | break; |
| 515 | } |
| 516 | |
| 517 | if (IS_OSPF6_DUMP_PREFIX) |
| 518 | zlog_info (" Prefix %s", buf); |
| 519 | |
| 520 | /* copy prefix to advertise list */ |
| 521 | ospf6_prefix_add (adv_list, prefix); |
| 522 | |
| 523 | prefix_num --; |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | /* if no prefix to advertise, return */ |
| 528 | if (listcount (adv_list) == 0) |
| 529 | { |
| 530 | if (IS_OSPF6_DUMP_PREFIX) |
| 531 | zlog_info (" No Prefix to advertise"); |
| 532 | if (old) |
| 533 | ospf6_lsa_premature_aging (old); |
| 534 | return; |
| 535 | } |
| 536 | |
| 537 | /* prepare buffer */ |
| 538 | memset (buffer, 0, sizeof (buffer)); |
| 539 | size = sizeof (struct ospf6_intra_area_prefix_lsa); |
| 540 | iap = (struct ospf6_intra_area_prefix_lsa *) buffer; |
| 541 | |
| 542 | /* Set Referenced LSA field */ |
| 543 | iap->refer_lstype = htons (OSPF6_LSA_TYPE_NETWORK); |
| 544 | iap->refer_lsid = htonl (o6i->if_id); |
| 545 | iap->refer_advrtr = o6i->area->ospf6->router_id; |
| 546 | |
| 547 | dst = (struct ospf6_prefix *) (iap + 1); |
| 548 | for (node = listhead (adv_list); node; nextnode (node)) |
| 549 | { |
| 550 | src = (struct ospf6_prefix *) getdata (node); |
| 551 | |
| 552 | memcpy (dst, src, OSPF6_PREFIX_SIZE (src)); |
| 553 | |
| 554 | size += OSPF6_PREFIX_SIZE (dst); |
| 555 | dst = OSPF6_NEXT_PREFIX (dst); |
| 556 | } |
| 557 | iap->prefix_number = htons (listcount (adv_list)); |
| 558 | |
| 559 | while ((node = listhead (adv_list)) != NULL) |
| 560 | { |
| 561 | prefix = getdata (node); |
| 562 | ospf6_prefix_delete (prefix); |
| 563 | listnode_delete (adv_list, prefix); |
| 564 | } |
| 565 | list_delete (adv_list); |
| 566 | |
| 567 | ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), |
| 568 | htonl (o6i->if_id), ospf6->router_id, |
| 569 | buffer, size, o6i->area); |
| 570 | } |
| 571 | |
| 572 | void |
| 573 | ospf6_lsa_intra_prefix_update_stub (u_int32_t area_id) |
| 574 | { |
| 575 | char buffer [MAXLSASIZE]; |
| 576 | u_int16_t size; |
| 577 | struct ospf6_lsa *old; |
| 578 | struct ospf6_area *o6a; |
| 579 | int count; |
| 580 | |
| 581 | struct ospf6_intra_area_prefix_lsa *iap; |
| 582 | listnode i,j; |
| 583 | struct ospf6_interface *o6i = NULL; |
| 584 | struct ospf6_prefix *prefix, *dst, *src; |
| 585 | struct connected *c; |
| 586 | char buf[128]; |
| 587 | |
| 588 | list adv_list; |
| 589 | listnode node; |
| 590 | char prefix_buf[sizeof (struct ospf6_prefix) + sizeof (struct in6_addr)]; |
| 591 | |
| 592 | o6a = ospf6_area_lookup (area_id, ospf6); |
| 593 | if (! o6a) |
| 594 | { |
| 595 | char tmp[16]; |
| 596 | inet_ntop (AF_INET, &area_id, tmp, sizeof (tmp)); |
| 597 | zlog_warn ("Update Intra-Prefix (Stub): No such area: %s", tmp); |
| 598 | return; |
| 599 | } |
| 600 | else if (IS_OSPF6_DUMP_PREFIX) |
| 601 | { |
| 602 | zlog_info ("Update Intra-Prefix (Stub): area: %s", o6a->str); |
| 603 | } |
| 604 | |
| 605 | /* find previous LSA */ |
| 606 | old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), |
| 607 | htonl (0), ospf6->router_id, |
| 608 | o6a); /* xxx, ls-id */ |
| 609 | |
| 610 | adv_list = list_new (); |
| 611 | |
| 612 | /* Examin for each interface */ |
| 613 | for (i = listhead (o6a->if_list); i; nextnode (i)) |
| 614 | { |
| 615 | o6i = (struct ospf6_interface *) getdata (i); |
| 616 | |
| 617 | if (o6i->state == IFS_DOWN) |
| 618 | { |
| 619 | if (IS_OSPF6_DUMP_PREFIX) |
| 620 | zlog_info (" Interface %s: down", o6i->interface->name); |
| 621 | continue; |
| 622 | } |
| 623 | |
| 624 | count = 0; |
| 625 | o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state); |
| 626 | if (o6i->state != IFS_LOOPBACK && o6i->state != IFS_PTOP && |
| 627 | count != 0) |
| 628 | { |
| 629 | /* This interface's prefix will be included in DR's */ |
| 630 | if (IS_OSPF6_DUMP_PREFIX) |
| 631 | zlog_info (" Interface %s: not stub", o6i->interface->name); |
| 632 | continue; |
| 633 | } |
| 634 | |
| 635 | if (IS_OSPF6_DUMP_PREFIX) |
| 636 | zlog_info (" Interface %s:", o6i->interface->name); |
| 637 | |
| 638 | /* copy foreach address prefix */ |
| 639 | for (j = listhead (o6i->interface->connected); j; nextnode (j)) |
| 640 | { |
| 641 | c = (struct connected *) getdata (j); |
| 642 | |
| 643 | /* filter prefix not IPv6 */ |
| 644 | if (c->address->family != AF_INET6) |
| 645 | continue; |
| 646 | |
| 647 | /* for log */ |
| 648 | prefix2str (c->address, buf, sizeof (buf)); |
| 649 | |
| 650 | CONTINUE_IF_ADDRESS_LINKLOCAL (c->address); |
| 651 | CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address); |
| 652 | CONTINUE_IF_ADDRESS_LOOPBACK (c->address); |
| 653 | CONTINUE_IF_ADDRESS_V4COMPAT (c->address); |
| 654 | CONTINUE_IF_ADDRESS_V4MAPPED (c->address); |
| 655 | |
| 656 | /* filter prefix specified by configuration */ |
| 657 | if (o6i->plist_name) |
| 658 | { |
| 659 | struct prefix_list *plist; |
| 660 | enum prefix_list_type result = PREFIX_PERMIT; |
| 661 | |
| 662 | plist = prefix_list_lookup (AFI_IP6, o6i->plist_name); |
| 663 | if (plist) |
| 664 | result = prefix_list_apply (plist, c->address); |
| 665 | else |
| 666 | zlog_warn ("Update Intra-Prefix (Stub): " |
| 667 | "Prefix list \"%s\" not found", |
| 668 | o6i->plist_name); |
| 669 | |
| 670 | if (result == PREFIX_DENY) |
| 671 | { |
| 672 | if (IS_OSPF6_DUMP_PREFIX) |
| 673 | zlog_info (" %s: Filtered by %s", |
| 674 | buf, o6i->plist_name); |
| 675 | continue; |
| 676 | } |
| 677 | } |
| 678 | |
| 679 | /* initialize buffer for ospf6 prefix */ |
| 680 | memset (prefix_buf, 0, sizeof (prefix_buf)); |
| 681 | prefix = (struct ospf6_prefix *) prefix_buf; |
| 682 | |
| 683 | /* set ospf6 prefix according to its state */ |
| 684 | /* xxx, virtual links */ |
| 685 | if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX) && |
| 686 | (o6i->state == IFS_LOOPBACK || o6i->state == IFS_PTOP |
| 687 | /* xxx, PoinToMultiPoint I/F type */ )) |
| 688 | { |
| 689 | prefix->prefix_length = 128; |
| 690 | prefix->prefix_options = OSPF6_PREFIX_OPTION_LA; |
| 691 | prefix->prefix_metric = htons (0); |
| 692 | memcpy (prefix + 1, &c->address->u.prefix6, |
| 693 | OSPF6_PREFIX_SPACE (prefix->prefix_length)); |
| 694 | } |
| 695 | else |
| 696 | { |
| 697 | struct prefix_ipv6 prefix_ipv6; |
| 698 | /* apply mask */ |
| 699 | prefix_copy ((struct prefix *) &prefix_ipv6, c->address); |
| 700 | apply_mask_ipv6 (&prefix_ipv6); |
| 701 | |
| 702 | prefix->prefix_length = prefix_ipv6.prefixlen; |
| 703 | prefix->prefix_options = 0; /* xxx, no options yet */ |
| 704 | prefix->prefix_metric = htons (o6i->cost); |
| 705 | memcpy (prefix + 1, &prefix_ipv6.prefix, |
| 706 | OSPF6_PREFIX_SPACE (prefix->prefix_length)); |
| 707 | } |
| 708 | |
| 709 | ospf6_prefix_string (prefix, buf, sizeof (buf)); |
| 710 | if (IS_OSPF6_DUMP_PREFIX) |
| 711 | zlog_info (" Advertise %s", buf); |
| 712 | |
| 713 | /* check in the prefix to advertising prefix list */ |
| 714 | ospf6_prefix_add (adv_list, prefix); |
| 715 | } |
| 716 | } |
| 717 | |
| 718 | /* If no prefix to advertise */ |
| 719 | if (listcount (adv_list) == 0) |
| 720 | { |
| 721 | if (IS_OSPF6_DUMP_PREFIX) |
| 722 | zlog_info (" No prefix to advertise"); |
| 723 | if (old) |
| 724 | ospf6_lsa_premature_aging (old); |
| 725 | return; |
| 726 | } |
| 727 | |
| 728 | /* prepare buffer */ |
| 729 | memset (buffer, 0, sizeof (buffer)); |
| 730 | size = sizeof (struct ospf6_intra_area_prefix_lsa); |
| 731 | iap = (struct ospf6_intra_area_prefix_lsa *) buffer; |
| 732 | |
| 733 | /* Set Referenced LSA field */ |
| 734 | iap->refer_lstype = htons (OSPF6_LSA_TYPE_ROUTER); |
| 735 | iap->refer_lsid = htonl (0); |
| 736 | iap->refer_advrtr = o6a->ospf6->router_id; |
| 737 | |
| 738 | dst = (struct ospf6_prefix *) (iap + 1); |
| 739 | for (node = listhead (adv_list); node; nextnode (node)) |
| 740 | { |
| 741 | src = (struct ospf6_prefix *) getdata (node); |
| 742 | |
| 743 | memcpy (dst, src, OSPF6_PREFIX_SIZE (src)); |
| 744 | |
| 745 | size += OSPF6_PREFIX_SIZE (dst); |
| 746 | dst = OSPF6_NEXT_PREFIX (dst); |
| 747 | } |
| 748 | iap->prefix_number = htons (listcount (adv_list)); |
| 749 | |
| 750 | while ((node = listhead (adv_list)) != NULL) |
| 751 | { |
| 752 | prefix = getdata (node); |
| 753 | ospf6_prefix_delete (prefix); |
| 754 | listnode_delete (adv_list, prefix); |
| 755 | } |
| 756 | list_delete (adv_list); |
| 757 | |
| 758 | ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), |
| 759 | htonl (0) /* xxx */, ospf6->router_id, |
| 760 | buffer, size, o6a); |
| 761 | } |
| 762 | |
| 763 | int |
| 764 | ospf6_lsa_intra_prefix_hook_interface (void *interface) |
| 765 | { |
| 766 | struct ospf6_interface *o6i = interface; |
| 767 | if (o6i->area) |
| 768 | { |
| 769 | ospf6_lsa_intra_prefix_update_transit (o6i->interface->name); |
| 770 | ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id); |
| 771 | } |
| 772 | return 0; |
| 773 | } |
| 774 | |
| 775 | int |
| 776 | ospf6_lsa_intra_prefix_hook_neighbor (void *neighbor) |
| 777 | { |
| 778 | struct ospf6_neighbor *o6n = neighbor; |
| 779 | if (o6n->ospf6_interface->area) |
| 780 | { |
| 781 | ospf6_lsa_intra_prefix_update_transit (o6n->ospf6_interface->interface->name); |
| 782 | ospf6_lsa_intra_prefix_update_stub (o6n->ospf6_interface->area->area_id); |
| 783 | } |
| 784 | return 0; |
| 785 | } |
| 786 | |
| 787 | int |
| 788 | ospf6_intra_prefix_link_database_hook (void *new) |
| 789 | { |
| 790 | struct ospf6_lsa *lsa = new; |
| 791 | struct ospf6_interface *o6i; |
| 792 | |
| 793 | if (lsa->header->type != htons (OSPF6_LSA_TYPE_LINK)) |
| 794 | return 0; |
| 795 | |
| 796 | o6i = lsa->scope; |
| 797 | if (o6i->state != IFS_DR) |
| 798 | return 0; |
| 799 | |
| 800 | ospf6_lsa_intra_prefix_update_transit (o6i->interface->name); |
| 801 | ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id); |
| 802 | return 0; |
| 803 | } |
| 804 | |
| 805 | int |
| 806 | ospf6_lsa_intra_prefix_refresh (void *old) |
| 807 | { |
| 808 | struct ospf6_lsa *lsa = old; |
| 809 | struct ospf6_interface *o6i; |
| 810 | struct ospf6_area *o6a; |
| 811 | u_int32_t id; |
| 812 | |
| 813 | id = ntohl (lsa->header->id); |
| 814 | if (id) |
| 815 | { |
| 816 | o6i = ospf6_interface_lookup_by_index (id); |
| 817 | if (o6i) |
| 818 | ospf6_lsa_intra_prefix_update_transit (o6i->interface->name); |
| 819 | else |
| 820 | ospf6_lsa_premature_aging (lsa); |
| 821 | } |
| 822 | else |
| 823 | { |
| 824 | o6a = lsa->scope; |
| 825 | ospf6_lsa_intra_prefix_update_stub (o6a->area_id); |
| 826 | } |
| 827 | |
| 828 | return 0; |
| 829 | } |
| 830 | |
| 831 | void |
| 832 | ospf6_intra_prefix_register () |
| 833 | { |
| 834 | struct ospf6_lsa_slot slot, *sp; |
| 835 | struct ospf6_hook hook; |
| 836 | |
| 837 | memset (&slot, 0, sizeof (struct ospf6_lsa_slot)); |
| 838 | slot.type = htons (OSPF6_LSA_TYPE_INTRA_PREFIX); |
| 839 | slot.name = "Intra-Prefix"; |
| 840 | slot.func_show = ospf6_lsa_intra_prefix_show; |
| 841 | slot.func_refresh = ospf6_lsa_intra_prefix_refresh; |
| 842 | ospf6_lsa_slot_register (&slot); |
| 843 | |
| 844 | memset (&hook, 0, sizeof (hook)); |
| 845 | hook.name = "OriginateIntraPrefix"; |
| 846 | hook.hook_add = ospf6_lsa_intra_prefix_hook_interface; |
| 847 | hook.hook_change = ospf6_lsa_intra_prefix_hook_interface; |
| 848 | hook.hook_remove = NULL; /* XXX */ |
| 849 | ospf6_hook_register (&hook, &interface_hook); |
| 850 | |
| 851 | memset (&hook, 0, sizeof (hook)); |
| 852 | hook.name = "OriginateIntraPrefix"; |
| 853 | hook.hook_add = ospf6_lsa_intra_prefix_hook_neighbor; |
| 854 | hook.hook_change = ospf6_lsa_intra_prefix_hook_neighbor; |
| 855 | hook.hook_remove = ospf6_lsa_intra_prefix_hook_neighbor; |
| 856 | ospf6_hook_register (&hook, &neighbor_hook); |
| 857 | |
| 858 | sp = ospf6_lsa_slot_get (htons (OSPF6_LSA_TYPE_INTRA_PREFIX)); |
| 859 | hook.name = "CalculateIntraPrefix"; |
| 860 | hook.hook_add = ospf6_intra_prefix_database_hook_add; |
| 861 | hook.hook_change = ospf6_intra_prefix_database_hook_add; |
| 862 | hook.hook_remove = ospf6_intra_prefix_database_hook_remove; |
| 863 | ospf6_hook_register (&hook, &sp->database_hook); |
| 864 | } |
| 865 | |
| 866 | void |
| 867 | ospf6_intra_database_hook_intra_prefix (struct ospf6_lsa *old, |
| 868 | struct ospf6_lsa *new) |
| 869 | { |
| 870 | if (old) |
| 871 | ospf6_intra_prefix_database_hook_remove (old); |
| 872 | if (new && ! IS_LSA_MAXAGE (new)) |
| 873 | ospf6_intra_prefix_database_hook_add (new); |
| 874 | } |
| 875 | |
| 876 | void |
| 877 | ospf6_intra_database_hook_link (struct ospf6_lsa *old, |
| 878 | struct ospf6_lsa *new) |
| 879 | { |
| 880 | ospf6_intra_prefix_link_database_hook (new); |
| 881 | ospf6_spf_database_hook (old, new); |
| 882 | } |
| 883 | |
| 884 | void |
| 885 | ospf6_intra_init () |
| 886 | { |
| 887 | ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTRA_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook = |
| 888 | ospf6_intra_database_hook_intra_prefix; |
| 889 | ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook = |
| 890 | ospf6_intra_database_hook_link; |
| 891 | |
| 892 | intra_index = ospf6_dump_install ("intra-area", "Intra-area calculation\n"); |
| 893 | ospf6_intra_prefix_register (); |
| 894 | } |
| 895 | |
| 896 | |