1/*
2 * OSPF AS Boundary Router functions.
3 * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "thread.h"
26#include "memory.h"
27#include "linklist.h"
28#include "prefix.h"
29#include "if.h"
30#include "table.h"
31#include "vty.h"
32#include "filter.h"
33#include "log.h"
34
35#include "ospfd/ospfd.h"
36#include "ospfd/ospf_interface.h"
37#include "ospfd/ospf_asbr.h"
38#include "ospfd/ospf_lsa.h"
39#include "ospfd/ospf_lsdb.h"
40#include "ospfd/ospf_neighbor.h"
41#include "ospfd/ospf_spf.h"
42#include "ospfd/ospf_flood.h"
43#include "ospfd/ospf_route.h"
44#include "ospfd/ospf_zebra.h"
45#include "ospfd/ospf_dump.h"
46
47/* Remove external route. */
48void
49ospf_external_route_remove (struct prefix_ipv4 *p)
50{
51  struct route_node *rn;
52  struct ospf_route *or;
53
54  rn = route_node_lookup (ospf_top->old_external_route, (struct prefix *) p);
55  if (rn)
56    if ((or = rn->info))
57      {
58	zlog_info ("Route[%s/%d]: external path deleted",
59		   inet_ntoa (p->prefix), p->prefixlen);
60
61	/* Remove route from zebra. */
62        if (or->type == OSPF_DESTINATION_NETWORK)
63	  ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
64
65	ospf_route_free (or);
66	rn->info = NULL;
67
68	route_unlock_node (rn);
69	route_unlock_node (rn);
70	return;
71      }
72
73  zlog_info ("Route[%s/%d]: no such external path",
74	     inet_ntoa (p->prefix), p->prefixlen);
75}
76
77/* Lookup external route. */
78struct ospf_route *
79ospf_external_route_lookup (struct prefix_ipv4 *p)
80{
81  struct route_node *rn;
82
83  rn = route_node_lookup (ospf_top->old_external_route, (struct prefix *) p);
84  if (rn)
85    {
86      route_unlock_node (rn);
87      if (rn->info)
88	return rn->info;
89    }
90
91  zlog_warn ("Route[%s/%d]: lookup, no such prefix",
92	     inet_ntoa (p->prefix), p->prefixlen);
93
94  return NULL;
95}
96
97
98/* Add an External info for AS-external-LSA. */
99struct external_info *
100ospf_external_info_new (u_char type)
101{
102  struct external_info *new;
103
104  new = (struct external_info *)
105    XMALLOC (MTYPE_OSPF_EXTERNAL_INFO, sizeof (struct external_info));
106  memset (new, 0, sizeof (struct external_info));
107  new->type = type;
108
109  ospf_reset_route_map_set_values (&new->route_map_set);
110  return new;
111}
112
113void
114ospf_external_info_free (struct external_info *ei)
115{
116  XFREE (MTYPE_OSPF_EXTERNAL_INFO, ei);
117}
118
119void
120ospf_reset_route_map_set_values (struct route_map_set_values *values)
121{
122  values->metric = -1;
123  values->metric_type = -1;
124}
125
126int
127ospf_route_map_set_compare (struct route_map_set_values *values1,
128			    struct route_map_set_values *values2)
129{
130  return values1->metric == values2->metric &&
131    values1->metric_type == values2->metric_type;
132}
133
134/* Add an External info for AS-external-LSA. */
135struct external_info *
136ospf_external_info_add (u_char type, struct prefix_ipv4 p,
137			unsigned int ifindex, struct in_addr nexthop)
138{
139  struct external_info *new;
140  struct route_node *rn;
141
142  /* Initialize route table. */
143  if (EXTERNAL_INFO (type) == NULL)
144    EXTERNAL_INFO (type) = route_table_init ();
145
146  rn = route_node_get (EXTERNAL_INFO (type), (struct prefix *) &p);
147  /* If old info exists, -- discard new one or overwrite with new one? */
148  if (rn)
149    if (rn->info)
150      {
151	route_unlock_node (rn);
152	zlog_warn ("Redistribute[%s]: %s/%d already exists, discard.",
153		   LOOKUP (ospf_redistributed_proto, type),
154		   inet_ntoa (p.prefix), p.prefixlen);
155	/* XFREE (MTYPE_OSPF_TMP, rn->info); */
156	return rn->info;
157      }
158
159  /* Create new External info instance. */
160  new = ospf_external_info_new (type);
161  new->p = p;
162  new->ifindex = ifindex;
163  new->nexthop = nexthop;
164  new->tag = 0;
165
166  rn->info = new;
167
168  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
169    zlog_info ("Redistribute[%s]: %s/%d external info created.",
170	       LOOKUP (ospf_redistributed_proto, type),
171	       inet_ntoa (p.prefix), p.prefixlen);
172  return new;
173}
174
175void
176ospf_external_info_delete (u_char type, struct prefix_ipv4 p)
177{
178  struct route_node *rn;
179
180  rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p);
181  if (rn)
182    {
183      ospf_external_info_free (rn->info);
184      rn->info = NULL;
185      route_unlock_node (rn);
186      route_unlock_node (rn);
187    }
188}
189
190struct external_info *
191ospf_external_info_lookup (u_char type, struct prefix_ipv4 *p)
192{
193  struct route_node *rn;
194  rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) p);
195  if (rn)
196    {
197      route_unlock_node (rn);
198      if (rn->info)
199	return rn->info;
200    }
201
202  return NULL;
203}
204
205struct ospf_lsa *
206ospf_external_info_find_lsa (struct prefix_ipv4 *p)
207{
208  struct ospf_lsa *lsa;
209  struct as_external_lsa *al;
210  struct in_addr mask, id;
211
212  lsa = ospf_lsdb_lookup_by_id (ospf_top->lsdb, OSPF_AS_EXTERNAL_LSA,
213			       p->prefix, ospf_top->router_id);
214
215  if (!lsa)
216    return NULL;
217
218  al = (struct as_external_lsa *) lsa->data;
219
220  masklen2ip (p->prefixlen, &mask);
221
222  if (mask.s_addr != al->mask.s_addr)
223    {
224      id.s_addr = p->prefix.s_addr | (~mask.s_addr);
225      lsa = ospf_lsdb_lookup_by_id (ospf_top->lsdb, OSPF_AS_EXTERNAL_LSA,
226				   id, ospf_top->router_id);
227      if (!lsa)
228	return NULL;
229    }
230
231  return lsa;
232}
233
234
235/* Update ASBR status. */
236void
237ospf_asbr_status_update (u_char status)
238{
239  zlog_info ("ASBR[Status:%d]: Update", status);
240
241  /* ASBR on. */
242  if (status)
243    {
244      /* Already ASBR. */
245      if (OSPF_IS_ASBR)
246	{
247	  zlog_info ("ASBR[Status:%d]: Already ASBR", status);
248	  return;
249	}
250      SET_FLAG (ospf_top->flags, OSPF_FLAG_ASBR);
251    }
252  else
253    {
254      /* Already non ASBR. */
255      if (! OSPF_IS_ASBR)
256	{
257	  zlog_info ("ASBR[Status:%d]: Already non ASBR", status);
258	  return;
259	}
260      UNSET_FLAG (ospf_top->flags, OSPF_FLAG_ASBR);
261    }
262
263  /* Transition from/to status ASBR, schedule timer. */
264  ospf_spf_calculate_schedule ();
265  OSPF_TIMER_ON (ospf_top->t_router_lsa_update,
266		 ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY);
267}
268
269void
270ospf_redistribute_withdraw (u_char type)
271{
272  struct route_node *rn;
273  struct external_info *ei;
274
275  /* Delete external info for specified type. */
276  if (EXTERNAL_INFO (type))
277    for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn))
278      if ((ei = rn->info))
279	if (ospf_external_info_find_lsa (&ei->p))
280	  {
281	    if (is_prefix_default (&ei->p) &&
282		ospf_top->default_originate != DEFAULT_ORIGINATE_NONE)
283	      continue;
284	    ospf_external_lsa_flush (type, &ei->p, ei->ifindex, ei->nexthop);
285	    ospf_external_info_delete (type, ei->p);
286	  }
287}
288