1/*
2 * Copyright (C) 2001 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
24void
25ospf6_asbr_external_lsa_update (struct ospf6_route_req *request)
26{
27  char buffer [MAXLSASIZE];
28  u_int16_t size;
29  struct ospf6_lsa_as_external *external;
30  char *p;
31  struct ospf6_route_req route;
32  char pbuf[BUFSIZ];
33
34  /* assert this is best path; if not, return */
35  ospf6_route_lookup (&route, &request->route.prefix, request->table);
36  if (memcmp (&route.path, &request->path, sizeof (route.path)))
37    return;
38
39  if (IS_OSPF6_DUMP_LSA)
40    zlog_info ("Update AS-External: ID: %lu",
41               (u_long) ntohl (request->path.origin.id));
42
43  /* prepare buffer */
44  memset (buffer, 0, sizeof (buffer));
45  size = sizeof (struct ospf6_lsa_as_external);
46  external = (struct ospf6_lsa_as_external *) buffer;
47  p = (char *) (external + 1);
48
49  if (route.path.metric_type == 2)
50    SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E);   /* type2 */
51  else
52    UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E); /* type1 */
53
54  /* forwarding address */
55  if (! IN6_IS_ADDR_UNSPECIFIED (&route.nexthop.address))
56    SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F);
57  else
58    UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F);
59
60  /* external route tag */
61  UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T);
62
63  /* set metric. note: related to E bit */
64  OSPF6_ASBR_METRIC_SET (external, route.path.cost);
65
66  /* prefixlen */
67  external->prefix.prefix_length = route.route.prefix.prefixlen;
68
69  /* PrefixOptions */
70  external->prefix.prefix_options = route.path.prefix_options;
71
72  /* don't use refer LS-type */
73  external->prefix.prefix_refer_lstype = htons (0);
74
75  if (IS_OSPF6_DUMP_LSA)
76    {
77      prefix2str (&route.route.prefix, pbuf, sizeof (pbuf));
78      zlog_info ("  Prefix: %s", pbuf);
79    }
80
81  /* set Prefix */
82  memcpy (p, &route.route.prefix.u.prefix6,
83          OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen));
84  ospf6_prefix_apply_mask (&external->prefix);
85  size += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen);
86  p += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen);
87
88  /* Forwarding address */
89  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
90    {
91      memcpy (p, &route.nexthop.address, sizeof (struct in6_addr));
92      size += sizeof (struct in6_addr);
93      p += sizeof (struct in6_addr);
94    }
95
96  /* External Route Tag */
97  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T))
98    {
99      /* xxx */
100    }
101
102  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
103                       route.path.origin.id, ospf6->router_id,
104                       (char *) external, size, ospf6);
105  return;
106}
107
108void
109ospf6_asbr_external_route_add (struct ospf6_route_req *route)
110{
111  ospf6_asbr_external_lsa_update (route);
112}
113
114void
115ospf6_asbr_external_route_remove (struct ospf6_route_req *route)
116{
117  struct ospf6_lsa *lsa;
118
119  lsa = ospf6_lsdb_lookup_lsdb (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
120                                htonl (route->path.origin.id),
121                                ospf6->router_id, ospf6->lsdb);
122  if (lsa)
123    ospf6_lsa_premature_aging (lsa);
124}
125
126void
127ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa)
128{
129  struct ospf6_lsa_as_external *external;
130  struct prefix_ls asbr_id;
131  struct ospf6_route_req asbr_entry;
132  struct ospf6_route_req request;
133
134  external = OSPF6_LSA_HEADER_END (lsa->header);
135
136  if (IS_LSA_MAXAGE (lsa))
137    return;
138
139  if (IS_OSPF6_DUMP_ASBR)
140    zlog_info ("ASBR: Calculate %s", lsa->str);
141
142  if (lsa->header->adv_router == ospf6->router_id)
143    {
144      if (IS_OSPF6_DUMP_ASBR)
145        zlog_info ("ASBR:   Self-originated, ignore");
146      return;
147    }
148
149  if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
150    {
151      if (IS_OSPF6_DUMP_ASBR)
152        zlog_info ("ASBR:   Metric is Infinity, ignore");
153      return;
154    }
155
156  memset (&asbr_id, 0, sizeof (asbr_id));
157  asbr_id.family = AF_UNSPEC;
158  asbr_id.prefixlen = 64; /* xxx */
159  asbr_id.adv_router.s_addr = lsa->header->adv_router;
160
161  ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id,
162                      ospf6->topology_table);
163
164  if (ospf6_route_end (&asbr_entry))
165    {
166      if (IS_OSPF6_DUMP_ASBR)
167        {
168          char buf[64];
169          inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf));
170          zlog_info ("ASBR:   ASBR %s not found, ignore", buf);
171        }
172      return;
173    }
174
175  memset (&request, 0, sizeof (request));
176  request.route.type = OSPF6_DEST_TYPE_NETWORK;
177  request.route.prefix.family = AF_INET6;
178  request.route.prefix.prefixlen = external->prefix.prefix_length;
179  memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1),
180          OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen));
181
182  request.path.area_id = asbr_entry.path.area_id;
183  request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
184  request.path.origin.id = lsa->header->id;
185  request.path.origin.adv_router = lsa->header->adv_router;
186  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E))
187    {
188      request.path.type = OSPF6_PATH_TYPE_EXTERNAL2;
189      request.path.metric_type = 2;
190      request.path.cost = asbr_entry.path.cost;
191      request.path.cost_e2 = OSPF6_ASBR_METRIC (external);
192    }
193  else
194    {
195      request.path.type = OSPF6_PATH_TYPE_EXTERNAL1;
196      request.path.metric_type = 1;
197      request.path.cost = asbr_entry.path.cost
198                          + OSPF6_ASBR_METRIC (external);
199      request.path.cost_e2 = 0;
200    }
201  request.path.prefix_options = external->prefix.prefix_options;
202
203  while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr ==
204         asbr_id.adv_router.s_addr &&
205         asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER)
206    {
207      memcpy (&request.nexthop, &asbr_entry.nexthop,
208              sizeof (struct ospf6_nexthop));
209      ospf6_route_add (&request, ospf6->route_table);
210      ospf6_route_next (&asbr_entry);
211    }
212}
213
214void
215ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa)
216{
217  struct ospf6_lsa_as_external *external;
218  struct prefix dest;
219  char buf[64];
220  struct ospf6_route_req request;
221
222  if (IS_OSPF6_DUMP_ASBR)
223    zlog_info ("ASBR: Withdraw route of %s", lsa->str);
224
225  if (lsa->header->adv_router == ospf6->router_id)
226    {
227      if (IS_OSPF6_DUMP_ASBR)
228        zlog_info ("ASBR:   Self-originated, ignore");
229      return;
230    }
231
232  external = OSPF6_LSA_HEADER_END (lsa->header);
233  memset (&dest, 0, sizeof (dest));
234  dest.family = AF_INET6;
235  dest.prefixlen = external->prefix.prefix_length;
236  memcpy (&dest.u.prefix6, (char *)(external + 1),
237          OSPF6_PREFIX_SPACE (dest.prefixlen));
238
239  prefix2str (&dest, buf, sizeof (buf));
240  if (IS_OSPF6_DUMP_ASBR)
241    zlog_info ("ASBR:   route: %s", buf);
242
243  ospf6_route_lookup (&request, &dest, ospf6->route_table);
244  if (ospf6_route_end (&request))
245    {
246      zlog_info ("ASBR:   route not found");
247      return;
248    }
249
250  while (request.path.origin.id != lsa->header->id ||
251         request.path.origin.adv_router != lsa->header->adv_router)
252    {
253      if (prefix_same (&request.route.prefix, &dest) != 1)
254        {
255          zlog_info ("ASBR:   Can't find the entry matches the origin");
256          return;
257        }
258      ospf6_route_next (&request);
259    }
260  assert (request.path.origin.id == lsa->header->id);
261  assert (request.path.origin.adv_router == request.path.origin.adv_router);
262
263  while (request.path.origin.id == lsa->header->id &&
264         request.path.origin.adv_router == lsa->header->adv_router &&
265         prefix_same (&request.route.prefix, &dest) == 1)
266    {
267      ospf6_route_remove (&request, ospf6->route_table);
268      ospf6_route_next (&request);
269    }
270}
271
272void
273ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new)
274{
275  assert (old || new);
276
277  if (old == NULL)
278    ospf6_asbr_external_lsa_add (new);
279  else if (new == NULL)
280    ospf6_asbr_external_lsa_remove (old);
281  else
282    {
283      ospf6_route_table_freeze (ospf6->route_table);
284      ospf6_asbr_external_lsa_remove (old);
285      ospf6_asbr_external_lsa_add (new);
286      ospf6_route_table_thaw (ospf6->route_table);
287    }
288}
289
290void
291ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry)
292{
293  struct ospf6_lsdb_node node;
294
295  struct prefix_ls *inter_router;
296  u_int32_t id, adv_router;
297
298  inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
299  id = inter_router->id.s_addr;
300  adv_router = inter_router->adv_router.s_addr;
301
302  if (IS_OSPF6_DUMP_ASBR)
303    {
304      char buf[64];
305      inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
306      zlog_info ("ASBR: New router found: %s", buf);
307    }
308
309  if (ntohl (id) != 0 ||
310      ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
311    {
312      zlog_warn ("ASBR: Inter topology table malformed");
313      return;
314    }
315
316  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
317                               adv_router, ospf6->lsdb);
318       ! ospf6_lsdb_is_end (&node);
319       ospf6_lsdb_next (&node))
320    ospf6_asbr_external_lsa_add (node.lsa);
321}
322
323void
324ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry)
325{
326  struct prefix_ls *inter_router;
327  u_int32_t id, adv_router;
328  struct ospf6_route_req request;
329
330  inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
331  id = inter_router->id.s_addr;
332  adv_router = inter_router->adv_router.s_addr;
333
334  if (IS_OSPF6_DUMP_ASBR)
335    {
336      char buf[64];
337      inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
338      zlog_info ("ASBR: Router disappearing: %s", buf);
339    }
340
341  if (ntohl (id) != 0 ||
342      ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
343    {
344      zlog_warn ("ASBR: Inter topology table malformed");
345    }
346
347  for (ospf6_route_head (&request, ospf6->route_table);
348       ! ospf6_route_end (&request);
349       ospf6_route_next (&request))
350    {
351      if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 &&
352          request.path.type != OSPF6_PATH_TYPE_EXTERNAL2)
353        continue;
354      if (request.path.area_id != topo_entry->path.area_id)
355        continue;
356      if (request.path.origin.adv_router != topo_entry->path.origin.adv_router)
357        continue;
358      if (memcmp (&topo_entry->nexthop, &request.nexthop,
359                  sizeof (struct ospf6_nexthop)))
360        continue;
361
362      ospf6_route_remove (&request, ospf6->route_table);
363    }
364}
365
366int
367ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa)
368{
369  struct ospf6_lsa_as_external *external;
370  char buf[128], *ptr;
371  struct in6_addr in6;
372
373  assert (lsa->header);
374  external = (struct ospf6_lsa_as_external *)(lsa->header + 1);
375
376  /* bits */
377  snprintf (buf, sizeof (buf), "%s%s%s",
378            (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ?
379             "E" : "-"),
380            (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ?
381             "F" : "-"),
382            (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ?
383             "T" : "-"));
384
385  vty_out (vty, "     Bits: %s%s", buf, VTY_NEWLINE);
386  vty_out (vty, "     Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external),
387           VTY_NEWLINE);
388
389  ospf6_prefix_options_str (external->prefix.prefix_options,
390                            buf, sizeof (buf));
391  vty_out (vty, "     Prefix Options: %s%s", buf, VTY_NEWLINE);
392
393  vty_out (vty, "     Referenced LSType: %d%s",
394           ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE);
395
396  ospf6_prefix_in6_addr (&external->prefix, &in6);
397  inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
398  vty_out (vty, "     Prefix: %s/%d%s",
399           buf, external->prefix.prefix_length, VTY_NEWLINE);
400
401  /* Forwarding-Address */
402  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
403    {
404      ptr = ((char *)(external + 1))
405            + OSPF6_PREFIX_SPACE (external->prefix.prefix_length);
406      inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf));
407      vty_out (vty, "     Forwarding-Address: %s%s", buf, VTY_NEWLINE);
408    }
409
410  return 0;
411}
412
413int
414ospf6_asbr_external_refresh (void *old)
415{
416  struct ospf6_lsa *lsa = old;
417  struct ospf6_route_req route, *target;
418
419  assert (ospf6);
420
421  target = NULL;
422  for (ospf6_route_head (&route, ospf6->external_table);
423       ! ospf6_route_end (&route);
424       ospf6_route_next (&route))
425    {
426      if (route.path.origin.id == lsa->header->id)
427        {
428          target = &route;
429          break;
430        }
431    }
432
433  if (target)
434    ospf6_asbr_external_lsa_update (target);
435  else
436    ospf6_lsa_premature_aging (lsa);
437
438  return 0;
439}
440
441void
442ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
443{
444  if (old)
445    ospf6_asbr_external_lsa_remove (old);
446  if (new && ! IS_LSA_MAXAGE (new))
447    ospf6_asbr_external_lsa_add (new);
448}
449
450void
451ospf6_asbr_register_as_external ()
452{
453  struct ospf6_lsa_slot slot;
454
455  memset (&slot, 0, sizeof (slot));
456  slot.type              = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
457  slot.name              = "AS-External";
458  slot.func_show         = ospf6_asbr_external_show;
459  slot.func_refresh      = ospf6_asbr_external_refresh;
460  ospf6_lsa_slot_register (&slot);
461
462  ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook =
463    ospf6_asbr_database_hook;
464}
465
466void
467ospf6_asbr_init ()
468{
469  ospf6_asbr_register_as_external ();
470}
471
472
473