blob: 848d801e213f5257858a9a805d6e6e2ab53f99f5 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* RIP version 1 and 2.
vincentfbf5d032005-09-29 11:25:50 +00002 * Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
paul718e3742002-12-13 20:15:29 +00003 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro <kunihiro@zebra.org>
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 "if.h"
26#include "command.h"
27#include "prefix.h"
28#include "table.h"
29#include "thread.h"
30#include "memory.h"
31#include "log.h"
32#include "stream.h"
33#include "filter.h"
34#include "sockunion.h"
hasso1af81932004-09-26 16:11:14 +000035#include "sockopt.h"
paul718e3742002-12-13 20:15:29 +000036#include "routemap.h"
hasso16705132003-05-25 14:49:19 +000037#include "if_rmap.h"
paul718e3742002-12-13 20:15:29 +000038#include "plist.h"
39#include "distribute.h"
vincentc1a03d42005-09-28 15:47:44 +000040#include "md5.h"
paul718e3742002-12-13 20:15:29 +000041#include "keychain.h"
pauledd7c242003-06-04 13:59:38 +000042#include "privs.h"
paul718e3742002-12-13 20:15:29 +000043
44#include "ripd/ripd.h"
45#include "ripd/rip_debug.h"
46
paul0b3acf42004-09-17 08:39:08 +000047/* UDP receive buffer size */
48#define RIP_UDP_RCV_BUF 41600
49
50/* privileges global */
pauledd7c242003-06-04 13:59:38 +000051extern struct zebra_privs_t ripd_privs;
52
paul718e3742002-12-13 20:15:29 +000053/* RIP Structure. */
54struct rip *rip = NULL;
55
56/* RIP neighbor address table. */
57struct route_table *rip_neighbor_table;
58
59/* RIP route changes. */
60long rip_global_route_changes = 0;
61
62/* RIP queries. */
63long rip_global_queries = 0;
David Lamparter6b0655a2014-06-04 06:53:35 +020064
paul718e3742002-12-13 20:15:29 +000065/* Prototypes. */
pauldc63bfd2005-10-25 23:31:05 +000066static void rip_event (enum rip_event, int);
67static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char);
68static int rip_triggered_update (struct thread *);
69static int rip_update_jitter (unsigned long);
David Lamparter6b0655a2014-06-04 06:53:35 +020070
paul718e3742002-12-13 20:15:29 +000071/* RIP output routes type. */
72enum
73{
74 rip_all_route,
75 rip_changed_route
76};
David Lamparter6b0655a2014-06-04 06:53:35 +020077
paul718e3742002-12-13 20:15:29 +000078/* RIP command strings. */
Stephen Hemminger1423c802008-08-14 17:59:25 +010079static const struct message rip_msg[] =
paul718e3742002-12-13 20:15:29 +000080{
81 {RIP_REQUEST, "REQUEST"},
82 {RIP_RESPONSE, "RESPONSE"},
83 {RIP_TRACEON, "TRACEON"},
84 {RIP_TRACEOFF, "TRACEOFF"},
85 {RIP_POLL, "POLL"},
86 {RIP_POLL_ENTRY, "POLL ENTRY"},
Stephen Hemminger1423c802008-08-14 17:59:25 +010087 {0, NULL},
paul718e3742002-12-13 20:15:29 +000088};
David Lamparter6b0655a2014-06-04 06:53:35 +020089
paul718e3742002-12-13 20:15:29 +000090/* Utility function to set boradcast option to the socket. */
pauldc63bfd2005-10-25 23:31:05 +000091static int
paul718e3742002-12-13 20:15:29 +000092sockopt_broadcast (int sock)
93{
94 int ret;
95 int on = 1;
96
97 ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on);
98 if (ret < 0)
99 {
100 zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock);
101 return -1;
102 }
103 return 0;
104}
105
pauldc63bfd2005-10-25 23:31:05 +0000106static int
paul718e3742002-12-13 20:15:29 +0000107rip_route_rte (struct rip_info *rinfo)
108{
109 return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE);
110}
111
pauldc63bfd2005-10-25 23:31:05 +0000112static struct rip_info *
Stephen Hemminger393deb92008-08-18 14:13:29 -0700113rip_info_new (void)
paul718e3742002-12-13 20:15:29 +0000114{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700115 return XCALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info));
paul718e3742002-12-13 20:15:29 +0000116}
117
118void
119rip_info_free (struct rip_info *rinfo)
120{
121 XFREE (MTYPE_RIP_INFO, rinfo);
122}
123
124/* RIP route garbage collect timer. */
pauldc63bfd2005-10-25 23:31:05 +0000125static int
paul718e3742002-12-13 20:15:29 +0000126rip_garbage_collect (struct thread *t)
127{
128 struct rip_info *rinfo;
129 struct route_node *rp;
130
131 rinfo = THREAD_ARG (t);
132 rinfo->t_garbage_collect = NULL;
133
134 /* Off timeout timer. */
135 RIP_TIMER_OFF (rinfo->t_timeout);
136
137 /* Get route_node pointer. */
138 rp = rinfo->rp;
139
140 /* Unlock route_node. */
Lu Fengb397cf42014-07-18 06:13:18 +0000141 listnode_delete (rp->info, rinfo);
142 if (list_isempty ((struct list *)rp->info))
143 {
144 list_free (rp->info);
145 rp->info = NULL;
146 route_unlock_node (rp);
147 }
paul718e3742002-12-13 20:15:29 +0000148
149 /* Free RIP routing information. */
150 rip_info_free (rinfo);
151
152 return 0;
153}
154
Lu Fengb397cf42014-07-18 06:13:18 +0000155static void rip_timeout_update (struct rip_info *rinfo);
156
157/* Add new route to the ECMP list.
Lu Feng0b74a0a2014-07-18 06:13:19 +0000158 * RETURN: the new entry added in the list, or NULL if it is not the first
159 * entry and ECMP is not allowed.
Lu Fengb397cf42014-07-18 06:13:18 +0000160 */
161struct rip_info *
162rip_ecmp_add (struct rip_info *rinfo_new)
163{
164 struct route_node *rp = rinfo_new->rp;
165 struct rip_info *rinfo = NULL;
166 struct list *list = NULL;
167
168 if (rp->info == NULL)
169 rp->info = list_new ();
170 list = (struct list *)rp->info;
171
Lu Feng0b74a0a2014-07-18 06:13:19 +0000172 /* If ECMP is not allowed and some entry already exists in the list,
173 * do nothing. */
174 if (listcount (list) && !rip->ecmp)
175 return NULL;
176
Lu Fengb397cf42014-07-18 06:13:18 +0000177 rinfo = rip_info_new ();
178 memcpy (rinfo, rinfo_new, sizeof (struct rip_info));
179 listnode_add (list, rinfo);
180
181 if (rip_route_rte (rinfo))
182 {
183 rip_timeout_update (rinfo);
184 rip_zebra_ipv4_add (rp);
185 }
186
187 /* Set the route change flag on the first entry. */
188 rinfo = listgetdata (listhead (list));
189 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
190
191 /* Signal the output process to trigger an update (see section 2.5). */
192 rip_event (RIP_TRIGGERED_UPDATE, 0);
193
194 return rinfo;
195}
196
197/* Replace the ECMP list with the new route.
198 * RETURN: the new entry added in the list
199 */
200struct rip_info *
201rip_ecmp_replace (struct rip_info *rinfo_new)
202{
203 struct route_node *rp = rinfo_new->rp;
204 struct list *list = (struct list *)rp->info;
205 struct rip_info *rinfo = NULL, *tmp_rinfo = NULL;
206 struct listnode *node = NULL, *nextnode = NULL;
207
208 if (list == NULL || listcount (list) == 0)
209 return rip_ecmp_add (rinfo_new);
210
211 /* Get the first entry */
212 rinfo = listgetdata (listhead (list));
213
214 /* Learnt route replaced by a local one. Delete it from zebra. */
215 if (rip_route_rte (rinfo) && !rip_route_rte (rinfo_new))
216 if (CHECK_FLAG (rinfo->flags, RIP_RTF_FIB))
217 rip_zebra_ipv4_delete (rp);
218
219 /* Re-use the first entry, and delete the others. */
220 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
221 if (tmp_rinfo != rinfo)
222 {
223 RIP_TIMER_OFF (tmp_rinfo->t_timeout);
224 RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect);
225 list_delete_node (list, node);
226 rip_info_free (tmp_rinfo);
227 }
228
229 RIP_TIMER_OFF (rinfo->t_timeout);
230 RIP_TIMER_OFF (rinfo->t_garbage_collect);
231 memcpy (rinfo, rinfo_new, sizeof (struct rip_info));
232
233 if (rip_route_rte (rinfo))
234 {
235 rip_timeout_update (rinfo);
236 /* The ADD message implies an update. */
237 rip_zebra_ipv4_add (rp);
238 }
239
240 /* Set the route change flag. */
241 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
242
243 /* Signal the output process to trigger an update (see section 2.5). */
244 rip_event (RIP_TRIGGERED_UPDATE, 0);
245
246 return rinfo;
247}
248
249/* Delete one route from the ECMP list.
250 * RETURN:
251 * null - the entry is freed, and other entries exist in the list
252 * the entry - the entry is the last one in the list; its metric is set
253 * to INFINITY, and the garbage collector is started for it
254 */
255struct rip_info *
256rip_ecmp_delete (struct rip_info *rinfo)
257{
258 struct route_node *rp = rinfo->rp;
259 struct list *list = (struct list *)rp->info;
260
261 RIP_TIMER_OFF (rinfo->t_timeout);
262
263 if (listcount (list) > 1)
264 {
265 /* Some other ECMP entries still exist. Just delete this entry. */
266 RIP_TIMER_OFF (rinfo->t_garbage_collect);
267 listnode_delete (list, rinfo);
268 if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB))
269 /* The ADD message implies the update. */
270 rip_zebra_ipv4_add (rp);
271 rip_info_free (rinfo);
272 rinfo = NULL;
273 }
274 else
275 {
276 assert (rinfo == listgetdata (listhead (list)));
277
278 /* This is the only entry left in the list. We must keep it in
279 * the list for garbage collection time, with INFINITY metric. */
280
281 rinfo->metric = RIP_METRIC_INFINITY;
282 RIP_TIMER_ON (rinfo->t_garbage_collect,
283 rip_garbage_collect, rip->garbage_time);
284
285 if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB))
286 rip_zebra_ipv4_delete (rp);
287 }
288
289 /* Set the route change flag on the first entry. */
290 rinfo = listgetdata (listhead (list));
291 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
292
293 /* Signal the output process to trigger an update (see section 2.5). */
294 rip_event (RIP_TRIGGERED_UPDATE, 0);
295
296 return rinfo;
297}
298
paul718e3742002-12-13 20:15:29 +0000299/* Timeout RIP routes. */
pauldc63bfd2005-10-25 23:31:05 +0000300static int
paul718e3742002-12-13 20:15:29 +0000301rip_timeout (struct thread *t)
302{
Lu Fengb397cf42014-07-18 06:13:18 +0000303 rip_ecmp_delete ((struct rip_info *)THREAD_ARG (t));
paul718e3742002-12-13 20:15:29 +0000304 return 0;
305}
306
pauldc63bfd2005-10-25 23:31:05 +0000307static void
paul718e3742002-12-13 20:15:29 +0000308rip_timeout_update (struct rip_info *rinfo)
309{
310 if (rinfo->metric != RIP_METRIC_INFINITY)
311 {
312 RIP_TIMER_OFF (rinfo->t_timeout);
313 RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
314 }
315}
316
pauldc63bfd2005-10-25 23:31:05 +0000317static int
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200318rip_filter (int rip_distribute, struct prefix_ipv4 *p, struct rip_interface *ri)
paul718e3742002-12-13 20:15:29 +0000319{
320 struct distribute *dist;
321 struct access_list *alist;
322 struct prefix_list *plist;
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200323 int distribute = rip_distribute == RIP_FILTER_OUT ?
Matthieu Boutierdf2ef242014-09-10 16:50:45 +0200324 DISTRIBUTE_V4_OUT : DISTRIBUTE_V4_IN;
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200325 const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in";
paul718e3742002-12-13 20:15:29 +0000326
327 /* Input distribute-list filtering. */
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200328 if (ri->list[rip_distribute])
paul718e3742002-12-13 20:15:29 +0000329 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200330 if (access_list_apply (ri->list[rip_distribute],
paul718e3742002-12-13 20:15:29 +0000331 (struct prefix *) p) == FILTER_DENY)
332 {
333 if (IS_RIP_DEBUG_PACKET)
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200334 zlog_debug ("%s/%d filtered by distribute %s",
335 inet_ntoa (p->prefix), p->prefixlen, inout);
paul718e3742002-12-13 20:15:29 +0000336 return -1;
337 }
338 }
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200339 if (ri->prefix[rip_distribute])
paul718e3742002-12-13 20:15:29 +0000340 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200341 if (prefix_list_apply (ri->prefix[rip_distribute],
paul718e3742002-12-13 20:15:29 +0000342 (struct prefix *) p) == PREFIX_DENY)
343 {
344 if (IS_RIP_DEBUG_PACKET)
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200345 zlog_debug ("%s/%d filtered by prefix-list %s",
346 inet_ntoa (p->prefix), p->prefixlen, inout);
paul718e3742002-12-13 20:15:29 +0000347 return -1;
348 }
349 }
350
351 /* All interface filter check. */
352 dist = distribute_lookup (NULL);
353 if (dist)
354 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200355 if (dist->list[distribute])
paul718e3742002-12-13 20:15:29 +0000356 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200357 alist = access_list_lookup (AFI_IP, dist->list[distribute]);
358
paul718e3742002-12-13 20:15:29 +0000359 if (alist)
360 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200361 if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY)
paul718e3742002-12-13 20:15:29 +0000362 {
363 if (IS_RIP_DEBUG_PACKET)
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200364 zlog_debug ("%s/%d filtered by distribute %s",
365 inet_ntoa (p->prefix), p->prefixlen, inout);
paul718e3742002-12-13 20:15:29 +0000366 return -1;
367 }
368 }
369 }
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200370 if (dist->prefix[distribute])
paul718e3742002-12-13 20:15:29 +0000371 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200372 plist = prefix_list_lookup (AFI_IP, dist->prefix[distribute]);
373
paul718e3742002-12-13 20:15:29 +0000374 if (plist)
375 {
376 if (prefix_list_apply (plist,
377 (struct prefix *) p) == PREFIX_DENY)
378 {
379 if (IS_RIP_DEBUG_PACKET)
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200380 zlog_debug ("%s/%d filtered by prefix-list %s",
381 inet_ntoa (p->prefix), p->prefixlen, inout);
paul718e3742002-12-13 20:15:29 +0000382 return -1;
383 }
384 }
385 }
386 }
387 return 0;
388}
389
390/* Check nexthop address validity. */
391static int
392rip_nexthop_check (struct in_addr *addr)
393{
hasso52dc7ee2004-09-23 19:18:23 +0000394 struct listnode *node;
395 struct listnode *cnode;
paul718e3742002-12-13 20:15:29 +0000396 struct interface *ifp;
397 struct connected *ifc;
398 struct prefix *p;
399
400 /* If nexthop address matches local configured address then it is
401 invalid nexthop. */
paul1eb8ef22005-04-07 07:30:20 +0000402 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +0000403 {
paul1eb8ef22005-04-07 07:30:20 +0000404 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
paul718e3742002-12-13 20:15:29 +0000405 {
paul718e3742002-12-13 20:15:29 +0000406 p = ifc->address;
407
408 if (p->family == AF_INET
409 && IPV4_ADDR_SAME (&p->u.prefix4, addr))
410 return -1;
411 }
412 }
413 return 0;
414}
415
416/* RIP add route to routing table. */
pauldc63bfd2005-10-25 23:31:05 +0000417static void
paul718e3742002-12-13 20:15:29 +0000418rip_rte_process (struct rte *rte, struct sockaddr_in *from,
paula87552c2004-05-03 20:00:17 +0000419 struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000420{
421 int ret;
422 struct prefix_ipv4 p;
423 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +0000424 struct rip_info *rinfo = NULL, newinfo;
paul718e3742002-12-13 20:15:29 +0000425 struct rip_interface *ri;
426 struct in_addr *nexthop;
paul718e3742002-12-13 20:15:29 +0000427 int same = 0;
vincentfbf5d032005-09-29 11:25:50 +0000428 unsigned char old_dist, new_dist;
Lu Fengb397cf42014-07-18 06:13:18 +0000429 struct list *list = NULL;
430 struct listnode *node = NULL;
paul718e3742002-12-13 20:15:29 +0000431
432 /* Make prefix structure. */
433 memset (&p, 0, sizeof (struct prefix_ipv4));
434 p.family = AF_INET;
435 p.prefix = rte->prefix;
436 p.prefixlen = ip_masklen (rte->mask);
437
438 /* Make sure mask is applied. */
439 apply_mask_ipv4 (&p);
440
441 /* Apply input filters. */
442 ri = ifp->info;
443
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200444 ret = rip_filter (RIP_FILTER_IN, &p, ri);
paul718e3742002-12-13 20:15:29 +0000445 if (ret < 0)
446 return;
447
Lu Fengb397cf42014-07-18 06:13:18 +0000448 memset (&newinfo, 0, sizeof (newinfo));
449 newinfo.type = ZEBRA_ROUTE_RIP;
450 newinfo.sub_type = RIP_ROUTE_RTE;
451 newinfo.nexthop = rte->nexthop;
452 newinfo.from = from->sin_addr;
453 newinfo.ifindex = ifp->ifindex;
454 newinfo.metric = rte->metric;
455 newinfo.metric_out = rte->metric; /* XXX */
456 newinfo.tag = ntohs (rte->tag); /* XXX */
457
hasso16705132003-05-25 14:49:19 +0000458 /* Modify entry according to the interface routemap. */
459 if (ri->routemap[RIP_FILTER_IN])
460 {
461 int ret;
hasso16705132003-05-25 14:49:19 +0000462
463 /* The object should be of the type of rip_info */
paula87552c2004-05-03 20:00:17 +0000464 ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
465 (struct prefix *) &p, RMAP_RIP, &newinfo);
hasso16705132003-05-25 14:49:19 +0000466
467 if (ret == RMAP_DENYMATCH)
paula87552c2004-05-03 20:00:17 +0000468 {
469 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000470 zlog_debug ("RIP %s/%d is filtered by route-map in",
paula87552c2004-05-03 20:00:17 +0000471 inet_ntoa (p.prefix), p.prefixlen);
472 return;
473 }
hasso16705132003-05-25 14:49:19 +0000474
475 /* Get back the object */
paula87552c2004-05-03 20:00:17 +0000476 rte->nexthop = newinfo.nexthop_out;
477 rte->tag = htons (newinfo.tag_out); /* XXX */
478 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
hasso16705132003-05-25 14:49:19 +0000479 }
480
paul718e3742002-12-13 20:15:29 +0000481 /* Once the entry has been validated, update the metric by
482 adding the cost of the network on wich the message
483 arrived. If the result is greater than infinity, use infinity
484 (RFC2453 Sec. 3.9.2) */
485 /* Zebra ripd can handle offset-list in. */
486 ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
487
488 /* If offset-list does not modify the metric use interface's
489 metric. */
paula87552c2004-05-03 20:00:17 +0000490 if (!ret)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000491 rte->metric += ifp->metric ? ifp->metric : 1;
paul718e3742002-12-13 20:15:29 +0000492
493 if (rte->metric > RIP_METRIC_INFINITY)
494 rte->metric = RIP_METRIC_INFINITY;
495
496 /* Set nexthop pointer. */
497 if (rte->nexthop.s_addr == 0)
498 nexthop = &from->sin_addr;
499 else
500 nexthop = &rte->nexthop;
501
hasso16705132003-05-25 14:49:19 +0000502 /* Check if nexthop address is myself, then do nothing. */
paul718e3742002-12-13 20:15:29 +0000503 if (rip_nexthop_check (nexthop) < 0)
504 {
505 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000506 zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
paul718e3742002-12-13 20:15:29 +0000507 return;
508 }
509
510 /* Get index for the prefix. */
511 rp = route_node_get (rip->table, (struct prefix *) &p);
512
Lu Fengb397cf42014-07-18 06:13:18 +0000513 newinfo.rp = rp;
514 newinfo.nexthop = *nexthop;
515 newinfo.metric = rte->metric;
516 newinfo.tag = ntohs (rte->tag);
517 newinfo.distance = rip_distance_apply (&newinfo);
518
519 new_dist = newinfo.distance ? newinfo.distance : ZEBRA_RIP_DISTANCE_DEFAULT;
520
paul718e3742002-12-13 20:15:29 +0000521 /* Check to see whether there is already RIP route on the table. */
Lu Fengb397cf42014-07-18 06:13:18 +0000522 if ((list = rp->info) != NULL)
523 for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
524 {
525 /* Need to compare with redistributed entry or local entry */
526 if (!rip_route_rte (rinfo))
527 break;
528
529 if (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) &&
530 IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
531 break;
532
533 if (!listnextnode (node))
534 {
535 /* Not found in the list */
536
537 if (rte->metric > rinfo->metric)
538 {
539 /* New route has a greater metric. Discard it. */
540 route_unlock_node (rp);
541 return;
542 }
543
544 if (rte->metric < rinfo->metric)
545 /* New route has a smaller metric. Replace the ECMP list
546 * with the new one in below. */
547 break;
548
549 /* Metrics are same. We compare the distances. */
550 old_dist = rinfo->distance ? \
551 rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT;
552
553 if (new_dist > old_dist)
554 {
555 /* New route has a greater distance. Discard it. */
556 route_unlock_node (rp);
557 return;
558 }
559
560 if (new_dist < old_dist)
561 /* New route has a smaller distance. Replace the ECMP list
562 * with the new one in below. */
563 break;
564
565 /* Metrics and distances are both same. Keep "rinfo" null and
566 * the new route is added in the ECMP list in below. */
567 }
568 }
paul718e3742002-12-13 20:15:29 +0000569
570 if (rinfo)
571 {
paul718e3742002-12-13 20:15:29 +0000572 /* Local static route. */
573 if (rinfo->type == ZEBRA_ROUTE_RIP
paula87552c2004-05-03 20:00:17 +0000574 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
575 (rinfo->sub_type == RIP_ROUTE_DEFAULT))
576 && rinfo->metric != RIP_METRIC_INFINITY)
vincentfbf5d032005-09-29 11:25:50 +0000577 {
578 route_unlock_node (rp);
579 return;
580 }
581
582 /* Redistributed route check. */
583 if (rinfo->type != ZEBRA_ROUTE_RIP
584 && rinfo->metric != RIP_METRIC_INFINITY)
585 {
vincentfbf5d032005-09-29 11:25:50 +0000586 old_dist = rinfo->distance;
David Lamparterb68da442013-02-28 22:17:00 +0100587 /* Only routes directly connected to an interface (nexthop == 0)
588 * may have a valid NULL distance */
589 if (rinfo->nexthop.s_addr != 0)
vincent7a383332006-01-30 18:12:42 +0000590 old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
vincentfbf5d032005-09-29 11:25:50 +0000591 /* If imported route does not have STRICT precedence,
592 mark it as a ghost */
Lu Fengb397cf42014-07-18 06:13:18 +0000593 if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY)
594 rip_ecmp_replace (&newinfo);
595
596 route_unlock_node (rp);
597 return;
vincentfbf5d032005-09-29 11:25:50 +0000598 }
paul718e3742002-12-13 20:15:29 +0000599 }
paula87552c2004-05-03 20:00:17 +0000600
601 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000602 {
Lu Fengb397cf42014-07-18 06:13:18 +0000603 if (rp->info)
604 route_unlock_node (rp);
605
paul718e3742002-12-13 20:15:29 +0000606 /* Now, check to see whether there is already an explicit route
paula87552c2004-05-03 20:00:17 +0000607 for the destination prefix. If there is no such route, add
608 this route to the routing table, unless the metric is
609 infinity (there is no point in adding a route which
610 unusable). */
paul718e3742002-12-13 20:15:29 +0000611 if (rte->metric != RIP_METRIC_INFINITY)
Lu Fengb397cf42014-07-18 06:13:18 +0000612 rip_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +0000613 }
614 else
615 {
616 /* Route is there but we are not sure the route is RIP or not. */
paula87552c2004-05-03 20:00:17 +0000617
paul718e3742002-12-13 20:15:29 +0000618 /* If there is an existing route, compare the next hop address
paula87552c2004-05-03 20:00:17 +0000619 to the address of the router from which the datagram came.
620 If this datagram is from the same router as the existing
621 route, reinitialize the timeout. */
hasso16705132003-05-25 14:49:19 +0000622 same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
paula87552c2004-05-03 20:00:17 +0000623 && (rinfo->ifindex == ifp->ifindex));
paul718e3742002-12-13 20:15:29 +0000624
Lu Fengb397cf42014-07-18 06:13:18 +0000625 old_dist = rinfo->distance ? \
626 rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT;
paulb94f9db2004-05-01 20:45:38 +0000627
paul718e3742002-12-13 20:15:29 +0000628 /* Next, compare the metrics. If the datagram is from the same
paula87552c2004-05-03 20:00:17 +0000629 router as the existing route, and the new metric is different
630 than the old one; or, if the new metric is lower than the old
631 one, or if the tag has been changed; or if there is a route
632 with a lower administrave distance; or an update of the
633 distance on the actual route; do the following actions: */
634 if ((same && rinfo->metric != rte->metric)
635 || (rte->metric < rinfo->metric)
636 || ((same)
637 && (rinfo->metric == rte->metric)
Lu Fengb397cf42014-07-18 06:13:18 +0000638 && (newinfo.tag != rinfo->tag))
639 || (old_dist > new_dist)
640 || ((old_dist != new_dist) && same))
paula87552c2004-05-03 20:00:17 +0000641 {
Lu Fengb397cf42014-07-18 06:13:18 +0000642 if (listcount (list) == 1)
paula87552c2004-05-03 20:00:17 +0000643 {
Lu Fengb397cf42014-07-18 06:13:18 +0000644 if (newinfo.metric != RIP_METRIC_INFINITY)
645 rip_ecmp_replace (&newinfo);
646 else
647 rip_ecmp_delete (rinfo);
paula87552c2004-05-03 20:00:17 +0000648 }
649 else
650 {
Lu Fengb397cf42014-07-18 06:13:18 +0000651 if (newinfo.metric < rinfo->metric)
652 rip_ecmp_replace (&newinfo);
653 else if (newinfo.metric > rinfo->metric)
654 rip_ecmp_delete (rinfo);
655 else if (new_dist < old_dist)
656 rip_ecmp_replace (&newinfo);
657 else if (new_dist > old_dist)
658 rip_ecmp_delete (rinfo);
659 else
660 {
661 int update = CHECK_FLAG (rinfo->flags, RIP_RTF_FIB) ? 1 : 0;
662
663 assert (newinfo.metric != RIP_METRIC_INFINITY);
664
665 RIP_TIMER_OFF (rinfo->t_timeout);
666 RIP_TIMER_OFF (rinfo->t_garbage_collect);
667 memcpy (rinfo, &newinfo, sizeof (struct rip_info));
668 rip_timeout_update (rinfo);
669
670 if (update)
671 rip_zebra_ipv4_add (rp);
672
673 /* - Set the route change flag on the first entry. */
674 rinfo = listgetdata (listhead (list));
675 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
676 rip_event (RIP_TRIGGERED_UPDATE, 0);
677 }
paula87552c2004-05-03 20:00:17 +0000678 }
679 }
Lu Fengb397cf42014-07-18 06:13:18 +0000680 else /* same & no change */
681 rip_timeout_update (rinfo);
682
paul718e3742002-12-13 20:15:29 +0000683 /* Unlock tempolary lock of the route. */
684 route_unlock_node (rp);
685 }
686}
687
688/* Dump RIP packet */
pauldc63bfd2005-10-25 23:31:05 +0000689static void
hasso8a676be2004-10-08 06:36:38 +0000690rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000691{
692 caddr_t lim;
693 struct rte *rte;
hasso8a676be2004-10-08 06:36:38 +0000694 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000695 char pbuf[BUFSIZ], nbuf[BUFSIZ];
696 u_char netmask = 0;
697 u_char *p;
698
699 /* Set command string. */
700 if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
701 command_str = lookup (rip_msg, packet->command);
702 else
703 command_str = "unknown";
704
705 /* Dump packet header. */
ajs5d6c3772004-12-08 19:24:06 +0000706 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000707 sndrcv, command_str, packet->version, size);
708
709 /* Dump each routing table entry. */
710 rte = packet->rte;
711
712 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
713 {
714 if (packet->version == RIPv2)
715 {
716 netmask = ip_masklen (rte->mask);
717
paulca5e5162004-06-06 22:06:33 +0000718 if (rte->family == htons (RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +0000719 {
paulca5e5162004-06-06 22:06:33 +0000720 if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000721 {
722 p = (u_char *)&rte->prefix;
723
ajs5d6c3772004-12-08 19:24:06 +0000724 zlog_debug (" family 0x%X type %d auth string: %s",
paul718e3742002-12-13 20:15:29 +0000725 ntohs (rte->family), ntohs (rte->tag), p);
726 }
paulca5e5162004-06-06 22:06:33 +0000727 else if (rte->tag == htons (RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000728 {
729 struct rip_md5_info *md5;
730
731 md5 = (struct rip_md5_info *) &packet->rte;
732
ajs5d6c3772004-12-08 19:24:06 +0000733 zlog_debug (" family 0x%X type %d (MD5 authentication)",
paul718e3742002-12-13 20:15:29 +0000734 ntohs (md5->family), ntohs (md5->type));
ajs5d6c3772004-12-08 19:24:06 +0000735 zlog_debug (" RIP-2 packet len %d Key ID %d"
paulca5e5162004-06-06 22:06:33 +0000736 " Auth Data len %d",
737 ntohs (md5->packet_len), md5->keyid,
738 md5->auth_len);
ajs5d6c3772004-12-08 19:24:06 +0000739 zlog_debug (" Sequence Number %ld",
paulca5e5162004-06-06 22:06:33 +0000740 (u_long) ntohl (md5->sequence));
paul718e3742002-12-13 20:15:29 +0000741 }
paulca5e5162004-06-06 22:06:33 +0000742 else if (rte->tag == htons (RIP_AUTH_DATA))
paul718e3742002-12-13 20:15:29 +0000743 {
744 p = (u_char *)&rte->prefix;
745
ajs5d6c3772004-12-08 19:24:06 +0000746 zlog_debug (" family 0x%X type %d (MD5 data)",
paul718e3742002-12-13 20:15:29 +0000747 ntohs (rte->family), ntohs (rte->tag));
ajs5d6c3772004-12-08 19:24:06 +0000748 zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
Christian Franke93ad10e2016-06-14 20:07:08 +0200749 "%02X%02X%02X%02X%02X%02X%02X%02X",
paulca5e5162004-06-06 22:06:33 +0000750 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
Christian Franke93ad10e2016-06-14 20:07:08 +0200751 p[7], p[8], p[9], p[10], p[11], p[12], p[13],
paulca5e5162004-06-06 22:06:33 +0000752 p[14], p[15]);
paul718e3742002-12-13 20:15:29 +0000753 }
754 else
755 {
ajs5d6c3772004-12-08 19:24:06 +0000756 zlog_debug (" family 0x%X type %d (Unknown auth type)",
paul718e3742002-12-13 20:15:29 +0000757 ntohs (rte->family), ntohs (rte->tag));
758 }
759 }
760 else
ajs5d6c3772004-12-08 19:24:06 +0000761 zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
paulca5e5162004-06-06 22:06:33 +0000762 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
763 netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
764 BUFSIZ), ntohs (rte->family),
765 ntohs (rte->tag), (u_long) ntohl (rte->metric));
paul718e3742002-12-13 20:15:29 +0000766 }
767 else
768 {
ajs5d6c3772004-12-08 19:24:06 +0000769 zlog_debug (" %s family %d tag %d metric %ld",
paul718e3742002-12-13 20:15:29 +0000770 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
771 ntohs (rte->family), ntohs (rte->tag),
772 (u_long)ntohl (rte->metric));
773 }
774 }
775}
776
777/* Check if the destination address is valid (unicast; not net 0
778 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
779 check net 0 because we accept default route. */
pauldc63bfd2005-10-25 23:31:05 +0000780static int
paul718e3742002-12-13 20:15:29 +0000781rip_destination_check (struct in_addr addr)
782{
783 u_int32_t destination;
784
785 /* Convert to host byte order. */
786 destination = ntohl (addr.s_addr);
787
788 if (IPV4_NET127 (destination))
789 return 0;
790
791 /* Net 0 may match to the default route. */
792 if (IPV4_NET0 (destination) && destination != 0)
793 return 0;
794
795 /* Unicast address must belong to class A, B, C. */
796 if (IN_CLASSA (destination))
797 return 1;
798 if (IN_CLASSB (destination))
799 return 1;
800 if (IN_CLASSC (destination))
801 return 1;
802
803 return 0;
804}
805
806/* RIP version 2 authentication. */
pauldc63bfd2005-10-25 23:31:05 +0000807static int
paul718e3742002-12-13 20:15:29 +0000808rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
809 struct interface *ifp)
810{
811 struct rip_interface *ri;
812 char *auth_str;
813
814 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000815 zlog_debug ("RIPv2 simple password authentication from %s",
paul718e3742002-12-13 20:15:29 +0000816 inet_ntoa (from->sin_addr));
817
818 ri = ifp->info;
819
820 if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +0000821 || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000822 return 0;
823
824 /* Simple password authentication. */
825 if (ri->auth_str)
826 {
827 auth_str = (char *) &rte->prefix;
828
829 if (strncmp (auth_str, ri->auth_str, 16) == 0)
830 return 1;
831 }
832 if (ri->key_chain)
833 {
834 struct keychain *keychain;
835 struct key *key;
836
837 keychain = keychain_lookup (ri->key_chain);
838 if (keychain == NULL)
839 return 0;
840
841 key = key_match_for_accept (keychain, (char *) &rte->prefix);
842 if (key)
843 return 1;
844 }
845 return 0;
846}
847
848/* RIP version 2 authentication with MD5. */
pauldc63bfd2005-10-25 23:31:05 +0000849static int
paul718e3742002-12-13 20:15:29 +0000850rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
paulca5e5162004-06-06 22:06:33 +0000851 int length, struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000852{
853 struct rip_interface *ri;
854 struct rip_md5_info *md5;
855 struct rip_md5_data *md5data;
856 struct keychain *keychain;
857 struct key *key;
vincentc1a03d42005-09-28 15:47:44 +0000858 MD5_CTX ctx;
paul718e3742002-12-13 20:15:29 +0000859 u_char digest[RIP_AUTH_MD5_SIZE];
860 u_int16_t packet_len;
paul98fd1e62006-01-17 17:26:25 +0000861 char auth_str[RIP_AUTH_MD5_SIZE];
paul718e3742002-12-13 20:15:29 +0000862
863 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000864 zlog_debug ("RIPv2 MD5 authentication from %s",
paulca5e5162004-06-06 22:06:33 +0000865 inet_ntoa (from->sin_addr));
paul718e3742002-12-13 20:15:29 +0000866
867 ri = ifp->info;
868 md5 = (struct rip_md5_info *) &packet->rte;
869
870 /* Check auth type. */
paulca5e5162004-06-06 22:06:33 +0000871 if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000872 return 0;
873
paulca5e5162004-06-06 22:06:33 +0000874 /* If the authentication length is less than 16, then it must be wrong for
875 * any interpretation of rfc2082. Some implementations also interpret
876 * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
paul98fd1e62006-01-17 17:26:25 +0000877 */
paulca5e5162004-06-06 22:06:33 +0000878 if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
879 || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
paulc2bfbcc2004-06-04 01:42:38 +0000880 {
881 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000882 zlog_debug ("RIPv2 MD5 authentication, strange authentication "
paulca5e5162004-06-06 22:06:33 +0000883 "length field %d", md5->auth_len);
paul718e3742002-12-13 20:15:29 +0000884 return 0;
paulc2bfbcc2004-06-04 01:42:38 +0000885 }
paul718e3742002-12-13 20:15:29 +0000886
paulca5e5162004-06-06 22:06:33 +0000887 /* grab and verify check packet length */
888 packet_len = ntohs (md5->packet_len);
889
890 if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
891 {
892 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000893 zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
paulca5e5162004-06-06 22:06:33 +0000894 "greater than received length %d!",
895 md5->packet_len, length);
896 return 0;
897 }
898
899 /* retrieve authentication data */
900 md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
paul98fd1e62006-01-17 17:26:25 +0000901
902 memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
paulca5e5162004-06-06 22:06:33 +0000903
paul718e3742002-12-13 20:15:29 +0000904 if (ri->key_chain)
905 {
906 keychain = keychain_lookup (ri->key_chain);
907 if (keychain == NULL)
908 return 0;
909
910 key = key_lookup_for_accept (keychain, md5->keyid);
911 if (key == NULL)
912 return 0;
913
paul98fd1e62006-01-17 17:26:25 +0000914 strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000915 }
paul98fd1e62006-01-17 17:26:25 +0000916 else if (ri->auth_str)
917 strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000918
Paul Jakmafa93b162008-05-29 19:03:08 +0000919 if (auth_str[0] == 0)
paul718e3742002-12-13 20:15:29 +0000920 return 0;
paul98fd1e62006-01-17 17:26:25 +0000921
paul718e3742002-12-13 20:15:29 +0000922 /* MD5 digest authentication. */
vincentc1a03d42005-09-28 15:47:44 +0000923 memset (&ctx, 0, sizeof(ctx));
924 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +0000925 MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
926 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
vincentc1a03d42005-09-28 15:47:44 +0000927 MD5Final(digest, &ctx);
paul98fd1e62006-01-17 17:26:25 +0000928
929 if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
paul718e3742002-12-13 20:15:29 +0000930 return packet_len;
931 else
932 return 0;
933}
934
paulb14ee002005-02-04 23:42:41 +0000935/* Pick correct auth string for sends, prepare auth_str buffer for use.
936 * (left justified and padded).
937 *
938 * presumes one of ri or key is valid, and that the auth strings they point
939 * to are nul terminated. If neither are present, auth_str will be fully
940 * zero padded.
941 *
942 */
943static void
944rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
945 char *auth_str, int len)
paul718e3742002-12-13 20:15:29 +0000946{
paulb14ee002005-02-04 23:42:41 +0000947 assert (ri || key);
paul718e3742002-12-13 20:15:29 +0000948
paulb14ee002005-02-04 23:42:41 +0000949 memset (auth_str, 0, len);
950 if (key && key->string)
951 strncpy (auth_str, key->string, len);
952 else if (ri->auth_str)
953 strncpy (auth_str, ri->auth_str, len);
paul718e3742002-12-13 20:15:29 +0000954
paulb14ee002005-02-04 23:42:41 +0000955 return;
956}
paul718e3742002-12-13 20:15:29 +0000957
paulb14ee002005-02-04 23:42:41 +0000958/* Write RIPv2 simple password authentication information
959 *
960 * auth_str is presumed to be 2 bytes and correctly prepared
961 * (left justified and zero padded).
962 */
963static void
964rip_auth_simple_write (struct stream *s, char *auth_str, int len)
965{
966 assert (s && len == RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +0000967
paulb14ee002005-02-04 23:42:41 +0000968 stream_putw (s, RIP_FAMILY_AUTH);
969 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
970 stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
971
972 return;
973}
974
975/* write RIPv2 MD5 "authentication header"
976 * (uses the auth key data field)
977 *
978 * Digest offset field is set to 0.
979 *
980 * returns: offset of the digest offset field, which must be set when
981 * length to the auth-data MD5 digest is known.
982 */
983static size_t
984rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
985 struct key *key)
986{
paul98fd1e62006-01-17 17:26:25 +0000987 size_t doff = 0;
paulb14ee002005-02-04 23:42:41 +0000988
989 assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
paul718e3742002-12-13 20:15:29 +0000990
991 /* MD5 authentication. */
paulca5e5162004-06-06 22:06:33 +0000992 stream_putw (s, RIP_FAMILY_AUTH);
paul718e3742002-12-13 20:15:29 +0000993 stream_putw (s, RIP_AUTH_MD5);
994
paulb14ee002005-02-04 23:42:41 +0000995 /* MD5 AH digest offset field.
996 *
997 * Set to placeholder value here, to true value when RIP-2 Packet length
998 * is known. Actual value is set in .....().
999 */
paul98fd1e62006-01-17 17:26:25 +00001000 doff = stream_get_endp(s);
paulb14ee002005-02-04 23:42:41 +00001001 stream_putw (s, 0);
paul718e3742002-12-13 20:15:29 +00001002
1003 /* Key ID. */
1004 if (key)
1005 stream_putc (s, key->index % 256);
1006 else
1007 stream_putc (s, 1);
1008
paulca5e5162004-06-06 22:06:33 +00001009 /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
1010 * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
1011 * to be configurable.
1012 */
1013 stream_putc (s, ri->md5_auth_len);
paul718e3742002-12-13 20:15:29 +00001014
1015 /* Sequence Number (non-decreasing). */
1016 /* RFC2080: The value used in the sequence number is
1017 arbitrary, but two suggestions are the time of the
1018 message's creation or a simple message counter. */
1019 stream_putl (s, time (NULL));
1020
1021 /* Reserved field must be zero. */
1022 stream_putl (s, 0);
1023 stream_putl (s, 0);
1024
paul98fd1e62006-01-17 17:26:25 +00001025 return doff;
paulb14ee002005-02-04 23:42:41 +00001026}
paul718e3742002-12-13 20:15:29 +00001027
paulb14ee002005-02-04 23:42:41 +00001028/* If authentication is in used, write the appropriate header
1029 * returns stream offset to which length must later be written
1030 * or 0 if this is not required
1031 */
1032static size_t
1033rip_auth_header_write (struct stream *s, struct rip_interface *ri,
1034 struct key *key, char *auth_str, int len)
1035{
1036 assert (ri->auth_type != RIP_NO_AUTH);
1037
1038 switch (ri->auth_type)
1039 {
1040 case RIP_AUTH_SIMPLE_PASSWORD:
1041 rip_auth_prepare_str_send (ri, key, auth_str, len);
1042 rip_auth_simple_write (s, auth_str, len);
1043 return 0;
1044 case RIP_AUTH_MD5:
1045 return rip_auth_md5_ah_write (s, ri, key);
1046 }
1047 assert (1);
paul98fd1e62006-01-17 17:26:25 +00001048 return 0;
paulb14ee002005-02-04 23:42:41 +00001049}
1050
1051/* Write RIPv2 MD5 authentication data trailer */
1052static void
1053rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
1054 char *auth_str, int authlen)
1055{
1056 unsigned long len;
vincentc1a03d42005-09-28 15:47:44 +00001057 MD5_CTX ctx;
paulb14ee002005-02-04 23:42:41 +00001058 unsigned char digest[RIP_AUTH_MD5_SIZE];
1059
1060 /* Make it sure this interface is configured as MD5
1061 authentication. */
1062 assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
1063 assert (doff > 0);
1064
1065 /* Get packet length. */
1066 len = stream_get_endp(s);
1067
1068 /* Check packet length. */
1069 if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
1070 {
1071 zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
1072 return;
1073 }
1074
1075 /* Set the digest offset length in the header */
1076 stream_putw_at (s, doff, len);
1077
paul718e3742002-12-13 20:15:29 +00001078 /* Set authentication data. */
paulca5e5162004-06-06 22:06:33 +00001079 stream_putw (s, RIP_FAMILY_AUTH);
1080 stream_putw (s, RIP_AUTH_DATA);
paul718e3742002-12-13 20:15:29 +00001081
1082 /* Generate a digest for the RIP packet. */
vincentc1a03d42005-09-28 15:47:44 +00001083 memset(&ctx, 0, sizeof(ctx));
1084 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +00001085 MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
vincentc1a03d42005-09-28 15:47:44 +00001086 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
1087 MD5Final(digest, &ctx);
paul718e3742002-12-13 20:15:29 +00001088
1089 /* Copy the digest to the packet. */
1090 stream_write (s, digest, RIP_AUTH_MD5_SIZE);
1091}
1092
1093/* RIP routing information. */
pauldc63bfd2005-10-25 23:31:05 +00001094static void
paul718e3742002-12-13 20:15:29 +00001095rip_response_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001096 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001097{
1098 caddr_t lim;
1099 struct rte *rte;
paul727d1042002-12-13 20:50:29 +00001100 struct prefix_ipv4 ifaddr;
1101 struct prefix_ipv4 ifaddrclass;
paul727d1042002-12-13 20:50:29 +00001102 int subnetted;
Donald Sharp26a18eb2015-09-29 09:25:10 -04001103
1104 memset(&ifaddr, 0, sizeof(ifaddr));
paul727d1042002-12-13 20:50:29 +00001105 /* We don't know yet. */
1106 subnetted = -1;
1107
paul718e3742002-12-13 20:15:29 +00001108 /* The Response must be ignored if it is not from the RIP
1109 port. (RFC2453 - Sec. 3.9.2)*/
paulca5e5162004-06-06 22:06:33 +00001110 if (from->sin_port != htons(RIP_PORT_DEFAULT))
paul718e3742002-12-13 20:15:29 +00001111 {
1112 zlog_info ("response doesn't come from RIP port: %d",
1113 from->sin_port);
1114 rip_peer_bad_packet (from);
1115 return;
1116 }
1117
1118 /* The datagram's IPv4 source address should be checked to see
1119 whether the datagram is from a valid neighbor; the source of the
ajs35a60c22005-10-30 23:51:32 +00001120 datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
1121 if (if_lookup_address(from->sin_addr) == NULL)
paul718e3742002-12-13 20:15:29 +00001122 {
1123 zlog_info ("This datagram doesn't came from a valid neighbor: %s",
1124 inet_ntoa (from->sin_addr));
1125 rip_peer_bad_packet (from);
1126 return;
1127 }
1128
1129 /* It is also worth checking to see whether the response is from one
1130 of the router's own addresses. */
1131
1132 ; /* Alredy done in rip_read () */
1133
1134 /* Update RIP peer. */
1135 rip_peer_update (from, packet->version);
1136
1137 /* Set RTE pointer. */
1138 rte = packet->rte;
1139
1140 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
1141 {
1142 /* RIPv2 authentication check. */
1143 /* If the Address Family Identifier of the first (and only the
1144 first) entry in the message is 0xFFFF, then the remainder of
1145 the entry contains the authentication. */
1146 /* If the packet gets here it means authentication enabled */
1147 /* Check is done in rip_read(). So, just skipping it */
1148 if (packet->version == RIPv2 &&
1149 rte == packet->rte &&
paulca5e5162004-06-06 22:06:33 +00001150 rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001151 continue;
1152
paulca5e5162004-06-06 22:06:33 +00001153 if (rte->family != htons(AF_INET))
paul718e3742002-12-13 20:15:29 +00001154 {
1155 /* Address family check. RIP only supports AF_INET. */
1156 zlog_info ("Unsupported family %d from %s.",
1157 ntohs (rte->family), inet_ntoa (from->sin_addr));
1158 continue;
1159 }
1160
1161 /* - is the destination address valid (e.g., unicast; not net 0
1162 or 127) */
1163 if (! rip_destination_check (rte->prefix))
1164 {
1165 zlog_info ("Network is net 0 or net 127 or it is not unicast network");
1166 rip_peer_bad_route (from);
1167 continue;
1168 }
1169
1170 /* Convert metric value to host byte order. */
1171 rte->metric = ntohl (rte->metric);
1172
1173 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1174 if (! (rte->metric >= 1 && rte->metric <= 16))
1175 {
1176 zlog_info ("Route's metric is not in the 1-16 range.");
1177 rip_peer_bad_route (from);
1178 continue;
1179 }
1180
1181 /* RIPv1 does not have nexthop value. */
1182 if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
1183 {
1184 zlog_info ("RIPv1 packet with nexthop value %s",
1185 inet_ntoa (rte->nexthop));
1186 rip_peer_bad_route (from);
1187 continue;
1188 }
1189
1190 /* That is, if the provided information is ignored, a possibly
1191 sub-optimal, but absolutely valid, route may be taken. If
1192 the received Next Hop is not directly reachable, it should be
1193 treated as 0.0.0.0. */
1194 if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
1195 {
1196 u_int32_t addrval;
1197
1198 /* Multicast address check. */
1199 addrval = ntohl (rte->nexthop.s_addr);
1200 if (IN_CLASSD (addrval))
1201 {
1202 zlog_info ("Nexthop %s is multicast address, skip this rte",
1203 inet_ntoa (rte->nexthop));
1204 continue;
1205 }
1206
1207 if (! if_lookup_address (rte->nexthop))
1208 {
1209 struct route_node *rn;
1210 struct rip_info *rinfo;
1211
1212 rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
1213
1214 if (rn)
1215 {
1216 rinfo = rn->info;
1217
1218 if (rinfo->type == ZEBRA_ROUTE_RIP
1219 && rinfo->sub_type == RIP_ROUTE_RTE)
1220 {
1221 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001222 zlog_debug ("Next hop %s is on RIP network. Set nexthop to the packet's originator", inet_ntoa (rte->nexthop));
paul718e3742002-12-13 20:15:29 +00001223 rte->nexthop = rinfo->from;
1224 }
1225 else
1226 {
1227 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001228 zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
paul718e3742002-12-13 20:15:29 +00001229 rte->nexthop.s_addr = 0;
1230 }
1231
1232 route_unlock_node (rn);
1233 }
1234 else
1235 {
1236 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001237 zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
paul718e3742002-12-13 20:15:29 +00001238 rte->nexthop.s_addr = 0;
1239 }
1240
1241 }
1242 }
1243
1244 /* For RIPv1, there won't be a valid netmask.
1245
1246 This is a best guess at the masks. If everyone was using old
1247 Ciscos before the 'ip subnet zero' option, it would be almost
1248 right too :-)
1249
1250 Cisco summarize ripv1 advertisments to the classful boundary
1251 (/16 for class B's) except when the RIP packet does to inside
1252 the classful network in question. */
1253
1254 if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
1255 || (packet->version == RIPv2
1256 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
1257 {
1258 u_int32_t destination;
1259
paul727d1042002-12-13 20:50:29 +00001260 if (subnetted == -1)
paulc49ad8f2004-10-22 10:27:28 +00001261 {
1262 memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
1263 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
1264 apply_classful_mask_ipv4 (&ifaddrclass);
1265 subnetted = 0;
1266 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
1267 subnetted = 1;
1268 }
paul727d1042002-12-13 20:50:29 +00001269
paul718e3742002-12-13 20:15:29 +00001270 destination = ntohl (rte->prefix.s_addr);
1271
paul727d1042002-12-13 20:50:29 +00001272 if (IN_CLASSA (destination))
paul718e3742002-12-13 20:15:29 +00001273 masklen2ip (8, &rte->mask);
paul727d1042002-12-13 20:50:29 +00001274 else if (IN_CLASSB (destination))
1275 masklen2ip (16, &rte->mask);
1276 else if (IN_CLASSC (destination))
1277 masklen2ip (24, &rte->mask);
1278
1279 if (subnetted == 1)
1280 masklen2ip (ifaddrclass.prefixlen,
1281 (struct in_addr *) &destination);
1282 if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
1283 ifaddrclass.prefix.s_addr))
1284 {
1285 masklen2ip (ifaddr.prefixlen, &rte->mask);
1286 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1287 masklen2ip (32, &rte->mask);
1288 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001289 zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
paul727d1042002-12-13 20:50:29 +00001290 }
1291 else
1292 {
1293 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1294 continue;
1295 }
1296
1297 if (IS_RIP_DEBUG_EVENT)
1298 {
ajs5d6c3772004-12-08 19:24:06 +00001299 zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
1300 zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
paul718e3742002-12-13 20:15:29 +00001301 }
1302 }
1303
1304 /* In case of RIPv2, if prefix in RTE is not netmask applied one
1305 ignore the entry. */
1306 if ((packet->version == RIPv2)
1307 && (rte->mask.s_addr != 0)
1308 && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
1309 {
1310 zlog_warn ("RIPv2 address %s is not mask /%d applied one",
1311 inet_ntoa (rte->prefix), ip_masklen (rte->mask));
1312 rip_peer_bad_route (from);
1313 continue;
1314 }
1315
1316 /* Default route's netmask is ignored. */
1317 if (packet->version == RIPv2
1318 && (rte->prefix.s_addr == 0)
1319 && (rte->mask.s_addr != 0))
1320 {
1321 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001322 zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
paul718e3742002-12-13 20:15:29 +00001323 rte->mask.s_addr = 0;
1324 }
1325
1326 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001327 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001328 }
1329}
1330
paula4e987e2005-06-03 17:46:49 +00001331/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001332static int
paul2c61ae32005-08-16 15:22:14 +00001333rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001334{
1335 int ret;
1336 int sock;
1337 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001338
paul2c61ae32005-08-16 15:22:14 +00001339 memset (&addr, 0, sizeof (struct sockaddr_in));
1340
1341 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001342 {
paulf69bd9d2005-06-03 18:01:50 +00001343 addr.sin_family = AF_INET;
1344 addr.sin_addr.s_addr = INADDR_ANY;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001345#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001346 addr.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001347#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
jardin38d3c162005-10-19 19:29:59 +00001348 } else {
1349 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001350 }
1351
paul2c61ae32005-08-16 15:22:14 +00001352 /* sending port must always be the RIP port */
1353 addr.sin_port = htons (RIP_PORT_DEFAULT);
1354
paula4e987e2005-06-03 17:46:49 +00001355 /* Make datagram socket. */
1356 sock = socket (AF_INET, SOCK_DGRAM, 0);
1357 if (sock < 0)
1358 {
1359 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1360 exit (1);
1361 }
1362
1363 sockopt_broadcast (sock);
1364 sockopt_reuseaddr (sock);
1365 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001366#ifdef RIP_RECVMSG
1367 setsockopt_pktinfo (sock);
1368#endif /* RIP_RECVMSG */
Stephen Hemminger78b31d52009-07-21 16:27:26 -07001369#ifdef IPTOS_PREC_INTERNETCONTROL
1370 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
1371#endif
paula4e987e2005-06-03 17:46:49 +00001372
1373 if (ripd_privs.change (ZPRIVS_RAISE))
1374 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001375 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1376 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1377
paula4e987e2005-06-03 17:46:49 +00001378 {
1379 int save_errno = errno;
1380 if (ripd_privs.change (ZPRIVS_LOWER))
1381 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001382
1383 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1384 sock, inet_ntoa(addr.sin_addr),
1385 (int) ntohs(addr.sin_port),
1386 safe_strerror(save_errno));
1387
paulf69bd9d2005-06-03 18:01:50 +00001388 close (sock);
paula4e987e2005-06-03 17:46:49 +00001389 return ret;
1390 }
paulf69bd9d2005-06-03 18:01:50 +00001391
paula4e987e2005-06-03 17:46:49 +00001392 if (ripd_privs.change (ZPRIVS_LOWER))
1393 zlog_err ("rip_create_socket: could not lower privs");
1394
1395 return sock;
1396}
1397
paulc49ad8f2004-10-22 10:27:28 +00001398/* RIP packet send to destination address, on interface denoted by
1399 * by connected argument. NULL to argument denotes destination should be
1400 * should be RIP multicast group
1401 */
pauldc63bfd2005-10-25 23:31:05 +00001402static int
paulc49ad8f2004-10-22 10:27:28 +00001403rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1404 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001405{
paul931cd542004-01-23 15:31:42 +00001406 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001407 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001408
1409 assert (ifc != NULL);
1410
paul931cd542004-01-23 15:31:42 +00001411 if (IS_RIP_DEBUG_PACKET)
1412 {
paulf69bd9d2005-06-03 18:01:50 +00001413#define ADDRESS_SIZE 20
1414 char dst[ADDRESS_SIZE];
1415 dst[ADDRESS_SIZE - 1] = '\0';
1416
paul931cd542004-01-23 15:31:42 +00001417 if (to)
1418 {
paulf69bd9d2005-06-03 18:01:50 +00001419 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001420 }
1421 else
1422 {
1423 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001424 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001425 }
paulf69bd9d2005-06-03 18:01:50 +00001426#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001427 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001428 inet_ntoa(ifc->address->u.prefix4),
1429 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001430 }
paulf69bd9d2005-06-03 18:01:50 +00001431
paulc49ad8f2004-10-22 10:27:28 +00001432 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001433 {
1434 /*
1435 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1436 * with multiple addresses on the same subnet: the first address
1437 * on the subnet is configured "primary", and all subsequent addresses
1438 * on that subnet are treated as "secondary" addresses.
1439 * In order to avoid routing-table bloat on other rip listeners,
1440 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1441 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1442 * flag is set, we would end up sending a packet for a "secondary"
1443 * source address on non-linux systems.
1444 */
1445 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001446 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001447 return 0;
1448 }
1449
paul718e3742002-12-13 20:15:29 +00001450 /* Make destination address. */
1451 memset (&sin, 0, sizeof (struct sockaddr_in));
1452 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001453#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001454 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001455#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001456
1457 /* When destination is specified, use it's port and address. */
1458 if (to)
1459 {
paul718e3742002-12-13 20:15:29 +00001460 sin.sin_port = to->sin_port;
1461 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001462 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001463 }
1464 else
1465 {
paul2c61ae32005-08-16 15:22:14 +00001466 struct sockaddr_in from;
1467
paul718e3742002-12-13 20:15:29 +00001468 sin.sin_port = htons (RIP_PORT_DEFAULT);
1469 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001470
1471 /* multicast send should bind to local interface address */
Nick Hilliardbb2315f2012-08-18 15:10:57 +00001472 memset (&from, 0, sizeof (from));
paul2c61ae32005-08-16 15:22:14 +00001473 from.sin_family = AF_INET;
1474 from.sin_port = htons (RIP_PORT_DEFAULT);
1475 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001476#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001477 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001478#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001479
paul931cd542004-01-23 15:31:42 +00001480 /*
1481 * we have to open a new socket for each packet because this
1482 * is the most portable way to bind to a different source
1483 * ipv4 address for each packet.
1484 */
paul2c61ae32005-08-16 15:22:14 +00001485 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001486 {
paulf69bd9d2005-06-03 18:01:50 +00001487 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001488 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001489 }
paulc49ad8f2004-10-22 10:27:28 +00001490 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001491 }
1492
paul931cd542004-01-23 15:31:42 +00001493 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001494 sizeof (struct sockaddr_in));
1495
1496 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001497 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001498 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001499
1500 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001501 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001502
paul931cd542004-01-23 15:31:42 +00001503 if (!to)
1504 close(send_sock);
1505
paul718e3742002-12-13 20:15:29 +00001506 return ret;
1507}
1508
1509/* Add redistributed route to RIP table. */
1510void
1511rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001512 ifindex_t ifindex, struct in_addr *nexthop,
Christian Franke2bbacea2016-10-01 21:43:17 +02001513 unsigned int metric, unsigned char distance,
1514 route_tag_t tag)
paul718e3742002-12-13 20:15:29 +00001515{
1516 int ret;
Lu Fengb397cf42014-07-18 06:13:18 +00001517 struct route_node *rp = NULL;
1518 struct rip_info *rinfo = NULL, newinfo;
1519 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00001520
1521 /* Redistribute route */
1522 ret = rip_destination_check (p->prefix);
1523 if (! ret)
1524 return;
1525
1526 rp = route_node_get (rip->table, (struct prefix *) p);
1527
Lu Fengb397cf42014-07-18 06:13:18 +00001528 memset (&newinfo, 0, sizeof (struct rip_info));
1529 newinfo.type = type;
1530 newinfo.sub_type = sub_type;
1531 newinfo.ifindex = ifindex;
1532 newinfo.metric = 1;
1533 newinfo.external_metric = metric;
1534 newinfo.distance = distance;
Christian Franke2bbacea2016-10-01 21:43:17 +02001535 if (tag <= UINT16_MAX) /* RIP only supports 16 bit tags */
1536 newinfo.tag = tag;
Lu Fengb397cf42014-07-18 06:13:18 +00001537 newinfo.rp = rp;
1538 if (nexthop)
1539 newinfo.nexthop = *nexthop;
paul718e3742002-12-13 20:15:29 +00001540
Lu Fengb397cf42014-07-18 06:13:18 +00001541 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00001542 {
Lu Fengb397cf42014-07-18 06:13:18 +00001543 rinfo = listgetdata (listhead (list));
1544
paul718e3742002-12-13 20:15:29 +00001545 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1546 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1547 && rinfo->metric != RIP_METRIC_INFINITY)
1548 {
1549 route_unlock_node (rp);
1550 return;
1551 }
1552
1553 /* Manually configured RIP route check. */
1554 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001555 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1556 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001557 {
hasso16705132003-05-25 14:49:19 +00001558 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1559 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001560 {
1561 route_unlock_node (rp);
1562 return;
1563 }
1564 }
1565
Lu Fengb397cf42014-07-18 06:13:18 +00001566 rinfo = rip_ecmp_replace (&newinfo);
1567 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001568 }
Lu Fengb397cf42014-07-18 06:13:18 +00001569 else
1570 rinfo = rip_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +00001571
hasso16705132003-05-25 14:49:19 +00001572 if (IS_RIP_DEBUG_EVENT) {
1573 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001574 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001575 inet_ntoa(p->prefix), p->prefixlen,
1576 ifindex2ifname(ifindex));
1577 else
ajs5d6c3772004-12-08 19:24:06 +00001578 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001579 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1580 ifindex2ifname(ifindex));
1581 }
1582
paul718e3742002-12-13 20:15:29 +00001583 rip_event (RIP_TRIGGERED_UPDATE, 0);
1584}
1585
1586/* Delete redistributed route from RIP table. */
1587void
1588rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001589 ifindex_t ifindex)
paul718e3742002-12-13 20:15:29 +00001590{
1591 int ret;
1592 struct route_node *rp;
1593 struct rip_info *rinfo;
1594
1595 ret = rip_destination_check (p->prefix);
1596 if (! ret)
1597 return;
1598
1599 rp = route_node_lookup (rip->table, (struct prefix *) p);
1600 if (rp)
1601 {
Lu Fengb397cf42014-07-18 06:13:18 +00001602 struct list *list = rp->info;
paul718e3742002-12-13 20:15:29 +00001603
Lu Fengb397cf42014-07-18 06:13:18 +00001604 if (list != NULL && listcount (list) != 0)
1605 {
1606 rinfo = listgetdata (listhead (list));
1607 if (rinfo != NULL
1608 && rinfo->type == type
1609 && rinfo->sub_type == sub_type
1610 && rinfo->ifindex == ifindex)
1611 {
1612 /* Perform poisoned reverse. */
1613 rinfo->metric = RIP_METRIC_INFINITY;
1614 RIP_TIMER_ON (rinfo->t_garbage_collect,
1615 rip_garbage_collect, rip->garbage_time);
1616 RIP_TIMER_OFF (rinfo->t_timeout);
1617 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001618
Lu Fengb397cf42014-07-18 06:13:18 +00001619 if (IS_RIP_DEBUG_EVENT)
1620 zlog_debug ("Poisone %s/%d on the interface %s with an "
1621 "infinity metric [delete]",
1622 inet_ntoa(p->prefix), p->prefixlen,
1623 ifindex2ifname(ifindex));
hasso16705132003-05-25 14:49:19 +00001624
Lu Fengb397cf42014-07-18 06:13:18 +00001625 rip_event (RIP_TRIGGERED_UPDATE, 0);
1626 }
1627 }
1628 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001629 }
1630}
1631
1632/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001633static void
paul718e3742002-12-13 20:15:29 +00001634rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001635 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001636{
1637 caddr_t lim;
1638 struct rte *rte;
1639 struct prefix_ipv4 p;
1640 struct route_node *rp;
1641 struct rip_info *rinfo;
1642 struct rip_interface *ri;
1643
hasso16705132003-05-25 14:49:19 +00001644 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001645 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001646 return;
1647
hasso429a0f82004-02-22 23:42:22 +00001648 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001649 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001650 if (! ri->running)
1651 return;
paul718e3742002-12-13 20:15:29 +00001652
1653 /* When passive interface is specified, suppress responses */
1654 if (ri->passive)
1655 return;
paulc49ad8f2004-10-22 10:27:28 +00001656
paul718e3742002-12-13 20:15:29 +00001657 /* RIP peer update. */
1658 rip_peer_update (from, packet->version);
1659
1660 lim = ((caddr_t) packet) + size;
1661 rte = packet->rte;
1662
1663 /* The Request is processed entry by entry. If there are no
1664 entries, no response is given. */
1665 if (lim == (caddr_t) rte)
1666 return;
1667
1668 /* There is one special case. If there is exactly one entry in the
1669 request, and it has an address family identifier of zero and a
1670 metric of infinity (i.e., 16), then this is a request to send the
1671 entire routing table. */
1672 if (lim == ((caddr_t) (rte + 1)) &&
1673 ntohs (rte->family) == 0 &&
1674 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1675 {
1676 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001677 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001678 }
1679 else
1680 {
1681 /* Examine the list of RTEs in the Request one by one. For each
1682 entry, look up the destination in the router's routing
1683 database and, if there is a route, put that route's metric in
1684 the metric field of the RTE. If there is no explicit route
1685 to the specified destination, put infinity in the metric
1686 field. Once all the entries have been filled in, change the
1687 command from Request to Response and send the datagram back
1688 to the requestor. */
1689 p.family = AF_INET;
1690
1691 for (; ((caddr_t) rte) < lim; rte++)
1692 {
1693 p.prefix = rte->prefix;
1694 p.prefixlen = ip_masklen (rte->mask);
1695 apply_mask_ipv4 (&p);
1696
1697 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1698 if (rp)
1699 {
Lu Fengb397cf42014-07-18 06:13:18 +00001700 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001701 rte->metric = htonl (rinfo->metric);
1702 route_unlock_node (rp);
1703 }
1704 else
1705 rte->metric = htonl (RIP_METRIC_INFINITY);
1706 }
1707 packet->command = RIP_RESPONSE;
1708
paulc49ad8f2004-10-22 10:27:28 +00001709 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001710 }
1711 rip_global_queries++;
1712}
1713
1714#if RIP_RECVMSG
1715/* Set IPv6 packet info to the socket. */
1716static int
1717setsockopt_pktinfo (int sock)
1718{
1719 int ret;
1720 int val = 1;
1721
1722 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1723 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001724 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001725 return ret;
1726}
1727
1728/* Read RIP packet by recvmsg function. */
1729int
1730rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001731 ifindex_t *ifindex)
paul718e3742002-12-13 20:15:29 +00001732{
1733 int ret;
1734 struct msghdr msg;
1735 struct iovec iov;
1736 struct cmsghdr *ptr;
1737 char adata[1024];
1738
1739 msg.msg_name = (void *) from;
1740 msg.msg_namelen = sizeof (struct sockaddr_in);
1741 msg.msg_iov = &iov;
1742 msg.msg_iovlen = 1;
1743 msg.msg_control = (void *) adata;
1744 msg.msg_controllen = sizeof adata;
1745 iov.iov_base = buf;
1746 iov.iov_len = size;
1747
1748 ret = recvmsg (sock, &msg, 0);
1749 if (ret < 0)
1750 return ret;
1751
ajsb99760a2005-01-04 16:24:43 +00001752 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001753 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1754 {
1755 struct in_pktinfo *pktinfo;
1756 int i;
1757
1758 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1759 i = pktinfo->ipi_ifindex;
1760 }
1761 return ret;
1762}
1763
1764/* RIP packet read function. */
1765int
1766rip_read_new (struct thread *t)
1767{
1768 int ret;
1769 int sock;
1770 char buf[RIP_PACKET_MAXSIZ];
1771 struct sockaddr_in from;
Paul Jakma9099f9b2016-01-18 10:12:10 +00001772 ifindex_t ifindex;
paul718e3742002-12-13 20:15:29 +00001773
1774 /* Fetch socket then register myself. */
1775 sock = THREAD_FD (t);
1776 rip_event (RIP_READ, sock);
1777
1778 /* Read RIP packet. */
1779 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1780 if (ret < 0)
1781 {
ajs6099b3b2004-11-20 02:06:59 +00001782 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001783 return ret;
1784 }
1785
1786 return ret;
1787}
1788#endif /* RIP_RECVMSG */
1789
1790/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001791static int
paul718e3742002-12-13 20:15:29 +00001792rip_read (struct thread *t)
1793{
1794 int sock;
1795 int ret;
1796 int rtenum;
1797 union rip_buf rip_buf;
1798 struct rip_packet *packet;
1799 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001800 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001801 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001802 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001803 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001804 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001805 struct rip_interface *ri;
1806
1807 /* Fetch socket then register myself. */
1808 sock = THREAD_FD (t);
1809 rip->t_read = NULL;
1810
1811 /* Add myself to tne next event */
1812 rip_event (RIP_READ, sock);
1813
1814 /* RIPd manages only IPv4. */
1815 memset (&from, 0, sizeof (struct sockaddr_in));
1816 fromlen = sizeof (struct sockaddr_in);
1817
1818 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1819 (struct sockaddr *) &from, &fromlen);
1820 if (len < 0)
1821 {
ajs6099b3b2004-11-20 02:06:59 +00001822 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001823 return len;
1824 }
1825
1826 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001827 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001828 {
1829 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001830 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001831 return -1;
1832 }
1833
1834 /* Which interface is this packet comes from. */
1835 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001836
paul718e3742002-12-13 20:15:29 +00001837 /* RIP packet received */
1838 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001839 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001840 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1841 ifp ? ifp->name : "unknown");
1842
1843 /* If this packet come from unknown interface, ignore it. */
1844 if (ifp == NULL)
1845 {
ajs766a0ca2004-12-15 14:55:51 +00001846 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1847 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001848 return -1;
1849 }
1850
1851 ifc = connected_lookup_address (ifp, from.sin_addr);
1852
1853 if (ifc == NULL)
1854 {
ajs766a0ca2004-12-15 14:55:51 +00001855 zlog_info ("rip_read: cannot find connected address for packet from %s "
1856 "port %d on interface %s",
1857 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001858 return -1;
1859 }
1860
1861 /* Packet length check. */
1862 if (len < RIP_PACKET_MINSIZ)
1863 {
1864 zlog_warn ("packet size %d is smaller than minimum size %d",
1865 len, RIP_PACKET_MINSIZ);
1866 rip_peer_bad_packet (&from);
1867 return len;
1868 }
1869 if (len > RIP_PACKET_MAXSIZ)
1870 {
1871 zlog_warn ("packet size %d is larger than max size %d",
1872 len, RIP_PACKET_MAXSIZ);
1873 rip_peer_bad_packet (&from);
1874 return len;
1875 }
1876
1877 /* Packet alignment check. */
1878 if ((len - RIP_PACKET_MINSIZ) % 20)
1879 {
1880 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1881 rip_peer_bad_packet (&from);
1882 return len;
1883 }
1884
1885 /* Set RTE number. */
1886 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1887
1888 /* For easy to handle. */
1889 packet = &rip_buf.rip_packet;
1890
1891 /* RIP version check. */
1892 if (packet->version == 0)
1893 {
1894 zlog_info ("version 0 with command %d received.", packet->command);
1895 rip_peer_bad_packet (&from);
1896 return -1;
1897 }
1898
1899 /* Dump RIP packet. */
1900 if (IS_RIP_DEBUG_RECV)
1901 rip_packet_dump (packet, len, "RECV");
1902
1903 /* RIP version adjust. This code should rethink now. RFC1058 says
1904 that "Version 1 implementations are to ignore this extra data and
1905 process only the fields specified in this document.". So RIPv3
1906 packet should be treated as RIPv1 ignoring must be zero field. */
1907 if (packet->version > RIPv2)
1908 packet->version = RIPv2;
1909
1910 /* Is RIP running or is this RIP neighbor ?*/
1911 ri = ifp->info;
1912 if (! ri->running && ! rip_neighbor_lookup (&from))
1913 {
1914 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001915 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001916 rip_peer_bad_packet (&from);
1917 return -1;
1918 }
1919
Paul Jakma15a2b082006-05-04 07:36:34 +00001920 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001921 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1922 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001923 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001924 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001925 if (IS_RIP_DEBUG_PACKET)
1926 zlog_debug (" packet's v%d doesn't fit to if version spec",
1927 packet->version);
1928 rip_peer_bad_packet (&from);
1929 return -1;
paul718e3742002-12-13 20:15:29 +00001930 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001931 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1932 {
1933 if (IS_RIP_DEBUG_PACKET)
1934 zlog_debug (" packet's v%d doesn't fit to if version spec",
1935 packet->version);
1936 rip_peer_bad_packet (&from);
1937 return -1;
1938 }
1939
paul718e3742002-12-13 20:15:29 +00001940 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1941 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1942 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00001943 if ((ri->auth_type == RIP_NO_AUTH)
1944 && rtenum
paulca5e5162004-06-06 22:06:33 +00001945 && (packet->version == RIPv2)
1946 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001947 {
1948 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001949 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001950 packet->version);
1951 rip_peer_bad_packet (&from);
1952 return -1;
1953 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001954
1955 /* RFC:
1956 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00001957 RIP-1 messages and RIP-2 messages which pass authentication
1958 testing shall be accepted; unauthenticated and failed
1959 authentication RIP-2 messages shall be discarded. For maximum
1960 security, RIP-1 messages should be ignored when authentication is
1961 in use (see section 4.1); otherwise, the routing information from
1962 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00001963 unauthenticated manner.
1964 */
1965 /* We make an exception for RIPv1 REQUEST packets, to which we'll
1966 * always reply regardless of authentication settings, because:
1967 *
1968 * - if there other authorised routers on-link, the REQUESTor can
1969 * passively obtain the routing updates anyway
1970 * - if there are no other authorised routers on-link, RIP can
1971 * easily be disabled for the link to prevent giving out information
1972 * on state of this routers RIP routing table..
1973 *
1974 * I.e. if RIPv1 has any place anymore these days, it's as a very
1975 * simple way to distribute routing information (e.g. to embedded
1976 * hosts / appliances) and the ability to give out RIPv1
1977 * routing-information freely, while still requiring RIPv2
1978 * authentication for any RESPONSEs might be vaguely useful.
1979 */
1980 if (ri->auth_type != RIP_NO_AUTH
1981 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00001982 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001983 /* Discard RIPv1 messages other than REQUESTs */
1984 if (packet->command != RIP_REQUEST)
1985 {
1986 if (IS_RIP_DEBUG_PACKET)
1987 zlog_debug ("RIPv1" " dropped because authentication enabled");
1988 rip_peer_bad_packet (&from);
1989 return -1;
1990 }
1991 }
1992 else if (ri->auth_type != RIP_NO_AUTH)
1993 {
1994 const char *auth_desc;
1995
1996 if (rtenum == 0)
1997 {
1998 /* There definitely is no authentication in the packet. */
1999 if (IS_RIP_DEBUG_PACKET)
2000 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2001 rip_peer_bad_packet (&from);
2002 return -1;
2003 }
2004
2005 /* First RTE must be an Authentication Family RTE */
2006 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2007 {
2008 if (IS_RIP_DEBUG_PACKET)
2009 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002010 rip_peer_bad_packet (&from);
2011 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002012 }
2013
paul718e3742002-12-13 20:15:29 +00002014 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002015 switch (ntohs(packet->rte->tag))
2016 {
2017 case RIP_AUTH_SIMPLE_PASSWORD:
2018 auth_desc = "simple";
2019 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2020 break;
2021
2022 case RIP_AUTH_MD5:
2023 auth_desc = "MD5";
2024 ret = rip_auth_md5 (packet, &from, len, ifp);
2025 /* Reset RIP packet length to trim MD5 data. */
2026 len = ret;
2027 break;
2028
2029 default:
2030 ret = 0;
2031 auth_desc = "unknown type";
2032 if (IS_RIP_DEBUG_PACKET)
2033 zlog_debug ("RIPv2 Unknown authentication type %d",
2034 ntohs (packet->rte->tag));
2035 }
2036
2037 if (ret)
2038 {
2039 if (IS_RIP_DEBUG_PACKET)
2040 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2041 }
2042 else
2043 {
2044 if (IS_RIP_DEBUG_PACKET)
2045 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2046 rip_peer_bad_packet (&from);
2047 return -1;
2048 }
paul718e3742002-12-13 20:15:29 +00002049 }
2050
2051 /* Process each command. */
2052 switch (packet->command)
2053 {
2054 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002055 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002056 break;
2057 case RIP_REQUEST:
2058 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002059 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002060 break;
2061 case RIP_TRACEON:
2062 case RIP_TRACEOFF:
2063 zlog_info ("Obsolete command %s received, please sent it to routed",
2064 lookup (rip_msg, packet->command));
2065 rip_peer_bad_packet (&from);
2066 break;
2067 case RIP_POLL_ENTRY:
2068 zlog_info ("Obsolete command %s received",
2069 lookup (rip_msg, packet->command));
2070 rip_peer_bad_packet (&from);
2071 break;
2072 default:
2073 zlog_info ("Unknown RIP command %d received", packet->command);
2074 rip_peer_bad_packet (&from);
2075 break;
2076 }
2077
2078 return len;
2079}
2080
paul718e3742002-12-13 20:15:29 +00002081/* Write routing table entry to the stream and return next index of
2082 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002083static int
paul718e3742002-12-13 20:15:29 +00002084rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002085 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002086{
2087 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002088
2089 /* Write routing table entry. */
2090 if (version == RIPv1)
2091 {
2092 stream_putw (s, AF_INET);
2093 stream_putw (s, 0);
2094 stream_put_ipv4 (s, p->prefix.s_addr);
2095 stream_put_ipv4 (s, 0);
2096 stream_put_ipv4 (s, 0);
2097 stream_putl (s, rinfo->metric_out);
2098 }
2099 else
2100 {
2101 masklen2ip (p->prefixlen, &mask);
2102
2103 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002104 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002105 stream_put_ipv4 (s, p->prefix.s_addr);
2106 stream_put_ipv4 (s, mask.s_addr);
2107 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2108 stream_putl (s, rinfo->metric_out);
2109 }
2110
2111 return ++num;
2112}
2113
2114/* Send update to the ifp or spcified neighbor. */
2115void
paulc49ad8f2004-10-22 10:27:28 +00002116rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2117 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002118{
2119 int ret;
2120 struct stream *s;
2121 struct route_node *rp;
2122 struct rip_info *rinfo;
2123 struct rip_interface *ri;
2124 struct prefix_ipv4 *p;
2125 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002126 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002127 struct key *key = NULL;
2128 /* this might need to made dynamic if RIP ever supported auth methods
2129 with larger key string sizes */
2130 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002131 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002132 int num = 0;
paul718e3742002-12-13 20:15:29 +00002133 int rtemax;
paul01d09082003-06-08 21:22:18 +00002134 int subnetted = 0;
Lu Fengb397cf42014-07-18 06:13:18 +00002135 struct list *list = NULL;
2136 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002137
2138 /* Logging output event. */
2139 if (IS_RIP_DEBUG_EVENT)
2140 {
2141 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002142 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002143 else
ajs5d6c3772004-12-08 19:24:06 +00002144 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002145 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002146 }
2147
2148 /* Set output stream. */
2149 s = rip->obuf;
2150
2151 /* Reset stream and RTE counter. */
2152 stream_reset (s);
Lu Feng342a31b2014-06-25 07:43:15 +00002153 rtemax = RIP_MAX_RTE;
paul718e3742002-12-13 20:15:29 +00002154
2155 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002156 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002157
2158 /* If output interface is in simple password authentication mode, we
2159 need space for authentication data. */
2160 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2161 rtemax -= 1;
2162
2163 /* If output interface is in MD5 authentication mode, we need space
2164 for authentication header and data. */
2165 if (ri->auth_type == RIP_AUTH_MD5)
2166 rtemax -= 2;
2167
2168 /* If output interface is in simple password authentication mode
2169 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002170 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002171 {
2172 if (ri->key_chain)
2173 {
2174 struct keychain *keychain;
2175
2176 keychain = keychain_lookup (ri->key_chain);
2177 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002178 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002179 }
paulb14ee002005-02-04 23:42:41 +00002180 /* to be passed to auth functions later */
2181 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002182 }
2183
paul727d1042002-12-13 20:50:29 +00002184 if (version == RIPv1)
2185 {
paulc49ad8f2004-10-22 10:27:28 +00002186 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002187 apply_classful_mask_ipv4 (&ifaddrclass);
2188 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002189 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002190 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002191 }
2192
paul718e3742002-12-13 20:15:29 +00002193 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002194 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00002195 {
Lu Fengb397cf42014-07-18 06:13:18 +00002196 rinfo = listgetdata (listhead (list));
paul727d1042002-12-13 20:50:29 +00002197 /* For RIPv1, if we are subnetted, output subnets in our network */
2198 /* that have the same mask as the output "interface". For other */
2199 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002200
2201 if (version == RIPv1)
2202 {
paul727d1042002-12-13 20:50:29 +00002203 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002204
2205 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002206 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002207 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002208
paul727d1042002-12-13 20:50:29 +00002209 if (subnetted &&
2210 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2211 {
paulc49ad8f2004-10-22 10:27:28 +00002212 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002213 (rp->p.prefixlen != 32))
2214 continue;
2215 }
2216 else
2217 {
2218 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2219 apply_classful_mask_ipv4(&classfull);
2220 if (rp->p.u.prefix4.s_addr != 0 &&
2221 classfull.prefixlen != rp->p.prefixlen)
2222 continue;
2223 }
paul718e3742002-12-13 20:15:29 +00002224 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002225 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002226 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002227 }
2228 else
2229 p = (struct prefix_ipv4 *) &rp->p;
2230
2231 /* Apply output filters. */
Matthieu Boutierfafa8992014-09-10 16:50:43 +02002232 ret = rip_filter (RIP_FILTER_OUT, p, ri);
paul718e3742002-12-13 20:15:29 +00002233 if (ret < 0)
2234 continue;
2235
2236 /* Changed route only output. */
2237 if (route_type == rip_changed_route &&
2238 (! (rinfo->flags & RIP_RTF_CHANGED)))
2239 continue;
2240
2241 /* Split horizon. */
2242 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002243 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002244 {
paul42d14d92003-11-17 09:15:18 +00002245 /*
2246 * We perform split horizon for RIP and connected route.
2247 * For rip routes, we want to suppress the route if we would
2248 * end up sending the route back on the interface that we
2249 * learned it from, with a higher metric. For connected routes,
2250 * we suppress the route if the prefix is a subset of the
2251 * source address that we are going to use for the packet
2252 * (in order to handle the case when multiple subnets are
2253 * configured on the same interface).
2254 */
Lu Fengb397cf42014-07-18 06:13:18 +00002255 int suppress = 0;
2256 struct rip_info *tmp_rinfo = NULL;
2257
2258 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
2259 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2260 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2261 {
2262 suppress = 1;
2263 break;
2264 }
2265
2266 if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002267 prefix_match((struct prefix *)p, ifc->address))
Lu Fengb397cf42014-07-18 06:13:18 +00002268 suppress = 1;
2269
2270 if (suppress)
paul718e3742002-12-13 20:15:29 +00002271 continue;
2272 }
2273
2274 /* Preparation for route-map. */
2275 rinfo->metric_set = 0;
2276 rinfo->nexthop_out.s_addr = 0;
2277 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002278 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002279 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002280
hasso16705132003-05-25 14:49:19 +00002281 /* In order to avoid some local loops,
2282 * if the RIP route has a nexthop via this interface, keep the nexthop,
2283 * otherwise set it to 0. The nexthop should not be propagated
2284 * beyond the local broadcast/multicast area in order
2285 * to avoid an IGP multi-level recursive look-up.
2286 * see (4.4)
2287 */
paulc49ad8f2004-10-22 10:27:28 +00002288 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002289 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002290
2291 /* Interface route-map */
2292 if (ri->routemap[RIP_FILTER_OUT])
2293 {
2294 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2295 (struct prefix *) p, RMAP_RIP,
2296 rinfo);
2297
2298 if (ret == RMAP_DENYMATCH)
2299 {
2300 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002301 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002302 inet_ntoa (p->prefix), p->prefixlen);
2303 continue;
2304 }
2305 }
paul718e3742002-12-13 20:15:29 +00002306
hasso16705132003-05-25 14:49:19 +00002307 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002308 if (rip->route_map[rinfo->type].name
2309 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2310 {
2311 ret = route_map_apply (rip->route_map[rinfo->type].map,
2312 (struct prefix *)p, RMAP_RIP, rinfo);
2313
2314 if (ret == RMAP_DENYMATCH)
2315 {
2316 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002317 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002318 inet_ntoa (p->prefix), p->prefixlen);
2319 continue;
2320 }
2321 }
2322
2323 /* When route-map does not set metric. */
2324 if (! rinfo->metric_set)
2325 {
2326 /* If redistribute metric is set. */
2327 if (rip->route_map[rinfo->type].metric_config
2328 && rinfo->metric != RIP_METRIC_INFINITY)
2329 {
2330 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2331 }
2332 else
2333 {
2334 /* If the route is not connected or localy generated
2335 one, use default-metric value*/
2336 if (rinfo->type != ZEBRA_ROUTE_RIP
2337 && rinfo->type != ZEBRA_ROUTE_CONNECT
2338 && rinfo->metric != RIP_METRIC_INFINITY)
2339 rinfo->metric_out = rip->default_metric;
2340 }
2341 }
2342
2343 /* Apply offset-list */
2344 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002345 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002346
2347 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2348 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002349
2350 /* Perform split-horizon with poisoned reverse
2351 * for RIP and connected routes.
2352 **/
2353 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002354 /*
2355 * We perform split horizon for RIP and connected route.
2356 * For rip routes, we want to suppress the route if we would
2357 * end up sending the route back on the interface that we
2358 * learned it from, with a higher metric. For connected routes,
2359 * we suppress the route if the prefix is a subset of the
2360 * source address that we are going to use for the packet
2361 * (in order to handle the case when multiple subnets are
2362 * configured on the same interface).
2363 */
Lu Fengb397cf42014-07-18 06:13:18 +00002364 struct rip_info *tmp_rinfo = NULL;
2365
2366 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
Donald Sharp7e7a1012016-04-08 22:03:22 -04002367 {
2368 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2369 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2370 rinfo->metric_out = RIP_METRIC_INFINITY;
2371 if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT &&
2372 prefix_match((struct prefix *)p, ifc->address))
2373 rinfo->metric_out = RIP_METRIC_INFINITY;
2374 }
hasso16705132003-05-25 14:49:19 +00002375 }
paulb14ee002005-02-04 23:42:41 +00002376
2377 /* Prepare preamble, auth headers, if needs be */
2378 if (num == 0)
2379 {
2380 stream_putc (s, RIP_RESPONSE);
2381 stream_putc (s, version);
2382 stream_putw (s, 0);
2383
paul0cb8a012005-05-29 11:27:24 +00002384 /* auth header for !v1 && !no_auth */
2385 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002386 doff = rip_auth_header_write (s, ri, key, auth_str,
2387 RIP_AUTH_SIMPLE_SIZE);
2388 }
2389
paul718e3742002-12-13 20:15:29 +00002390 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002391 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002392 if (num == rtemax)
2393 {
2394 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002395 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002396
2397 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002398 to, ifc);
paul718e3742002-12-13 20:15:29 +00002399
2400 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2401 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2402 stream_get_endp(s), "SEND");
2403 num = 0;
2404 stream_reset (s);
2405 }
2406 }
2407
2408 /* Flush unwritten RTE. */
2409 if (num != 0)
2410 {
2411 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002412 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002413
paulc49ad8f2004-10-22 10:27:28 +00002414 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002415
2416 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2417 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2418 stream_get_endp (s), "SEND");
2419 num = 0;
2420 stream_reset (s);
2421 }
2422
2423 /* Statistics updates. */
2424 ri->sent_updates++;
2425}
2426
2427/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002428static void
paulc49ad8f2004-10-22 10:27:28 +00002429rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002430{
paul718e3742002-12-13 20:15:29 +00002431 struct sockaddr_in to;
2432
2433 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002434 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002435 {
2436 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002437 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002438
paulc49ad8f2004-10-22 10:27:28 +00002439 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002440 return;
2441 }
paulc49ad8f2004-10-22 10:27:28 +00002442
paul718e3742002-12-13 20:15:29 +00002443 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002444 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002445 {
paulc49ad8f2004-10-22 10:27:28 +00002446 if (ifc->address->family == AF_INET)
2447 {
2448 /* Destination address and port setting. */
2449 memset (&to, 0, sizeof (struct sockaddr_in));
2450 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002451 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002452 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002453 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002454 /* calculate the appropriate broadcast address */
2455 to.sin_addr.s_addr =
2456 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2457 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002458 else
2459 /* do not know where to send the packet */
2460 return;
paulc49ad8f2004-10-22 10:27:28 +00002461 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002462
paulc49ad8f2004-10-22 10:27:28 +00002463 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002464 zlog_debug("%s announce to %s on %s",
2465 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2466 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002467
paulc49ad8f2004-10-22 10:27:28 +00002468 rip_output_process (ifc, &to, route_type, version);
2469 }
paul718e3742002-12-13 20:15:29 +00002470 }
2471}
2472
2473/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002474static void
paul718e3742002-12-13 20:15:29 +00002475rip_update_process (int route_type)
2476{
paul1eb8ef22005-04-07 07:30:20 +00002477 struct listnode *node;
2478 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002479 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002480 struct interface *ifp;
2481 struct rip_interface *ri;
2482 struct route_node *rp;
2483 struct sockaddr_in to;
2484 struct prefix_ipv4 *p;
2485
2486 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002487 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002488 {
paul718e3742002-12-13 20:15:29 +00002489 if (if_is_loopback (ifp))
2490 continue;
2491
paul2e3b2e42002-12-13 21:03:13 +00002492 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002493 continue;
2494
2495 /* Fetch RIP interface information. */
2496 ri = ifp->info;
2497
2498 /* When passive interface is specified, suppress announce to the
2499 interface. */
2500 if (ri->passive)
2501 continue;
2502
2503 if (ri->running)
2504 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002505 /*
2506 * If there is no version configuration in the interface,
2507 * use rip's version setting.
2508 */
2509 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2510 rip->version_send : ri->ri_send);
2511
paul718e3742002-12-13 20:15:29 +00002512 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002513 zlog_debug("SEND UPDATE to %s ifindex %d",
Christian Franke1ca8d402015-11-10 17:45:03 +01002514 ifp->name, ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002515
paulcc1131a2003-10-15 23:20:17 +00002516 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002517 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002518 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002519 if (connected->address->family == AF_INET)
2520 {
2521 if (vsend & RIPv1)
2522 rip_update_interface (connected, RIPv1, route_type);
2523 if ((vsend & RIPv2) && if_is_multicast(ifp))
2524 rip_update_interface (connected, RIPv2, route_type);
2525 }
2526 }
paul718e3742002-12-13 20:15:29 +00002527 }
2528 }
2529
2530 /* RIP send updates to each neighbor. */
2531 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2532 if (rp->info != NULL)
2533 {
2534 p = (struct prefix_ipv4 *) &rp->p;
2535
2536 ifp = if_lookup_address (p->prefix);
2537 if (! ifp)
2538 {
paulc49ad8f2004-10-22 10:27:28 +00002539 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002540 inet_ntoa (p->prefix));
2541 continue;
2542 }
paulc49ad8f2004-10-22 10:27:28 +00002543
2544 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2545 {
2546 zlog_warn ("Neighbor %s doesnt have connected network",
2547 inet_ntoa (p->prefix));
2548 continue;
2549 }
2550
paul718e3742002-12-13 20:15:29 +00002551 /* Set destination address and port */
2552 memset (&to, 0, sizeof (struct sockaddr_in));
2553 to.sin_addr = p->prefix;
2554 to.sin_port = htons (RIP_PORT_DEFAULT);
2555
2556 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002557 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002558 }
2559}
2560
2561/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002562static int
paul718e3742002-12-13 20:15:29 +00002563rip_update (struct thread *t)
2564{
2565 /* Clear timer pointer. */
2566 rip->t_update = NULL;
2567
2568 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002569 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002570
2571 /* Process update output. */
2572 rip_update_process (rip_all_route);
2573
2574 /* Triggered updates may be suppressed if a regular update is due by
2575 the time the triggered update would be sent. */
2576 if (rip->t_triggered_interval)
2577 {
2578 thread_cancel (rip->t_triggered_interval);
2579 rip->t_triggered_interval = NULL;
2580 }
2581 rip->trigger = 0;
2582
2583 /* Register myself. */
2584 rip_event (RIP_UPDATE_EVENT, 0);
2585
2586 return 0;
2587}
2588
2589/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002590static void
paul216565a2005-10-25 23:35:28 +00002591rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002592{
2593 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002594 struct rip_info *rinfo = NULL;
2595 struct list *list = NULL;
2596 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002597
2598 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002599 if ((list = rp->info) != NULL)
2600 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2601 {
2602 UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
2603 /* This flag can be set only on the first entry. */
2604 break;
2605 }
paul718e3742002-12-13 20:15:29 +00002606}
2607
2608/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002609static int
paul718e3742002-12-13 20:15:29 +00002610rip_triggered_interval (struct thread *t)
2611{
2612 int rip_triggered_update (struct thread *);
2613
2614 rip->t_triggered_interval = NULL;
2615
2616 if (rip->trigger)
2617 {
2618 rip->trigger = 0;
2619 rip_triggered_update (t);
2620 }
2621 return 0;
2622}
2623
2624/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002625static int
paul718e3742002-12-13 20:15:29 +00002626rip_triggered_update (struct thread *t)
2627{
2628 int interval;
2629
2630 /* Clear thred pointer. */
2631 rip->t_triggered_update = NULL;
2632
2633 /* Cancel interval timer. */
2634 if (rip->t_triggered_interval)
2635 {
2636 thread_cancel (rip->t_triggered_interval);
2637 rip->t_triggered_interval = NULL;
2638 }
2639 rip->trigger = 0;
2640
2641 /* Logging triggered update. */
2642 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002643 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002644
2645 /* Split Horizon processing is done when generating triggered
2646 updates as well as normal updates (see section 2.6). */
2647 rip_update_process (rip_changed_route);
2648
2649 /* Once all of the triggered updates have been generated, the route
2650 change flags should be cleared. */
2651 rip_clear_changed_flag ();
2652
2653 /* After a triggered update is sent, a timer should be set for a
2654 random interval between 1 and 5 seconds. If other changes that
2655 would trigger updates occur before the timer expires, a single
2656 update is triggered when the timer expires. */
2657 interval = (random () % 5) + 1;
2658
2659 rip->t_triggered_interval =
2660 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2661
2662 return 0;
2663}
2664
2665/* Withdraw redistributed route. */
2666void
2667rip_redistribute_withdraw (int type)
2668{
2669 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002670 struct rip_info *rinfo = NULL;
2671 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00002672
2673 if (!rip)
2674 return;
2675
2676 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002677 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00002678 {
Lu Fengb397cf42014-07-18 06:13:18 +00002679 rinfo = listgetdata (listhead (list));
paul718e3742002-12-13 20:15:29 +00002680 if (rinfo->type == type
2681 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2682 {
2683 /* Perform poisoned reverse. */
2684 rinfo->metric = RIP_METRIC_INFINITY;
2685 RIP_TIMER_ON (rinfo->t_garbage_collect,
2686 rip_garbage_collect, rip->garbage_time);
2687 RIP_TIMER_OFF (rinfo->t_timeout);
2688 rinfo->flags |= RIP_RTF_CHANGED;
2689
hasso16705132003-05-25 14:49:19 +00002690 if (IS_RIP_DEBUG_EVENT) {
2691 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2692
ajs5d6c3772004-12-08 19:24:06 +00002693 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002694 inet_ntoa(p->prefix), p->prefixlen,
2695 ifindex2ifname(rinfo->ifindex));
2696 }
2697
paul718e3742002-12-13 20:15:29 +00002698 rip_event (RIP_TRIGGERED_UPDATE, 0);
2699 }
2700 }
2701}
2702
2703/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002704static int
2705rip_create (void)
paul718e3742002-12-13 20:15:29 +00002706{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002707 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002708
2709 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002710 rip->version_send = RI_RIP_VERSION_2;
2711 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002712 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2713 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2714 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2715 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2716
2717 /* Initialize RIP routig table. */
2718 rip->table = route_table_init ();
2719 rip->route = route_table_init ();
2720 rip->neighbor = route_table_init ();
2721
2722 /* Make output stream. */
2723 rip->obuf = stream_new (1500);
2724
2725 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002726 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002727 if (rip->sock < 0)
2728 return rip->sock;
2729
2730 /* Create read and timer thread. */
2731 rip_event (RIP_READ, rip->sock);
2732 rip_event (RIP_UPDATE_EVENT, 1);
2733
2734 return 0;
2735}
2736
2737/* Sned RIP request to the destination. */
2738int
2739rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002740 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002741{
2742 struct rte *rte;
2743 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002744 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002745
2746 memset (&rip_packet, 0, sizeof (rip_packet));
2747
2748 rip_packet.command = RIP_REQUEST;
2749 rip_packet.version = version;
2750 rte = rip_packet.rte;
2751 rte->metric = htonl (RIP_METRIC_INFINITY);
2752
paul931cd542004-01-23 15:31:42 +00002753 if (connected)
2754 {
2755 /*
2756 * connected is only sent for ripv1 case, or when
2757 * interface does not support multicast. Caller loops
2758 * over each connected address for this case.
2759 */
paul11dde9c2004-05-31 14:00:00 +00002760 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002761 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002762 return -1;
2763 else
2764 return sizeof (rip_packet);
2765 }
2766
paulcc1131a2003-10-15 23:20:17 +00002767 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002768 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002769 {
2770 struct prefix_ipv4 *p;
2771
2772 p = (struct prefix_ipv4 *) connected->address;
2773
2774 if (p->family != AF_INET)
2775 continue;
2776
paul11dde9c2004-05-31 14:00:00 +00002777 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002778 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002779 return -1;
2780 }
2781 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002782}
David Lamparter6b0655a2014-06-04 06:53:35 +02002783
pauldc63bfd2005-10-25 23:31:05 +00002784static int
paul718e3742002-12-13 20:15:29 +00002785rip_update_jitter (unsigned long time)
2786{
paul239389b2004-05-05 14:09:37 +00002787#define JITTER_BOUND 4
2788 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2789 Given that, we cannot let time be less than JITTER_BOUND seconds.
2790 The RIPv2 RFC says jitter should be small compared to
2791 update_time. We consider 1/JITTER_BOUND to be small.
2792 */
2793
2794 int jitter_input = time;
2795 int jitter;
2796
2797 if (jitter_input < JITTER_BOUND)
2798 jitter_input = JITTER_BOUND;
2799
Donald Sharpf31bab42015-06-19 19:26:19 -04002800 jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input));
paul239389b2004-05-05 14:09:37 +00002801
2802 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002803}
2804
2805void
2806rip_event (enum rip_event event, int sock)
2807{
2808 int jitter = 0;
2809
2810 switch (event)
2811 {
2812 case RIP_READ:
2813 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2814 break;
2815 case RIP_UPDATE_EVENT:
2816 if (rip->t_update)
2817 {
2818 thread_cancel (rip->t_update);
2819 rip->t_update = NULL;
2820 }
2821 jitter = rip_update_jitter (rip->update_time);
2822 rip->t_update =
2823 thread_add_timer (master, rip_update, NULL,
2824 sock ? 2 : rip->update_time + jitter);
2825 break;
2826 case RIP_TRIGGERED_UPDATE:
2827 if (rip->t_triggered_interval)
2828 rip->trigger = 1;
2829 else if (! rip->t_triggered_update)
2830 rip->t_triggered_update =
2831 thread_add_event (master, rip_triggered_update, NULL, 0);
2832 break;
2833 default:
2834 break;
2835 }
2836}
David Lamparter6b0655a2014-06-04 06:53:35 +02002837
paul718e3742002-12-13 20:15:29 +00002838DEFUN (router_rip,
2839 router_rip_cmd,
2840 "router rip",
2841 "Enable a routing process\n"
2842 "Routing Information Protocol (RIP)\n")
2843{
2844 int ret;
2845
2846 /* If rip is not enabled before. */
2847 if (! rip)
2848 {
2849 ret = rip_create ();
2850 if (ret < 0)
2851 {
2852 zlog_info ("Can't create RIP");
2853 return CMD_WARNING;
2854 }
2855 }
2856 vty->node = RIP_NODE;
2857 vty->index = rip;
2858
2859 return CMD_SUCCESS;
2860}
2861
2862DEFUN (no_router_rip,
2863 no_router_rip_cmd,
2864 "no router rip",
2865 NO_STR
2866 "Enable a routing process\n"
2867 "Routing Information Protocol (RIP)\n")
2868{
2869 if (rip)
2870 rip_clean ();
2871 return CMD_SUCCESS;
2872}
2873
2874DEFUN (rip_version,
2875 rip_version_cmd,
2876 "version <1-2>",
2877 "Set routing protocol version\n"
2878 "version\n")
2879{
2880 int version;
2881
2882 version = atoi (argv[0]);
2883 if (version != RIPv1 && version != RIPv2)
2884 {
2885 vty_out (vty, "invalid rip version %d%s", version,
2886 VTY_NEWLINE);
2887 return CMD_WARNING;
2888 }
paulf38a4712003-06-07 01:10:00 +00002889 rip->version_send = version;
2890 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002891
2892 return CMD_SUCCESS;
2893}
2894
2895DEFUN (no_rip_version,
2896 no_rip_version_cmd,
2897 "no version",
2898 NO_STR
2899 "Set routing protocol version\n")
2900{
2901 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002902 rip->version_send = RI_RIP_VERSION_2;
2903 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002904
2905 return CMD_SUCCESS;
2906}
2907
2908ALIAS (no_rip_version,
2909 no_rip_version_val_cmd,
2910 "no version <1-2>",
2911 NO_STR
2912 "Set routing protocol version\n"
2913 "version\n")
2914
2915DEFUN (rip_route,
2916 rip_route_cmd,
2917 "route A.B.C.D/M",
2918 "RIP static route configuration\n"
2919 "IP prefix <network>/<length>\n")
2920{
2921 int ret;
2922 struct prefix_ipv4 p;
2923 struct route_node *node;
2924
2925 ret = str2prefix_ipv4 (argv[0], &p);
2926 if (ret < 0)
2927 {
2928 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2929 return CMD_WARNING;
2930 }
2931 apply_mask_ipv4 (&p);
2932
2933 /* For router rip configuration. */
2934 node = route_node_get (rip->route, (struct prefix *) &p);
2935
2936 if (node->info)
2937 {
2938 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2939 route_unlock_node (node);
2940 return CMD_WARNING;
2941 }
2942
hasso8a676be2004-10-08 06:36:38 +00002943 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002944
Christian Franke2bbacea2016-10-01 21:43:17 +02002945 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +00002946
2947 return CMD_SUCCESS;
2948}
2949
2950DEFUN (no_rip_route,
2951 no_rip_route_cmd,
2952 "no route A.B.C.D/M",
2953 NO_STR
2954 "RIP static route configuration\n"
2955 "IP prefix <network>/<length>\n")
2956{
2957 int ret;
2958 struct prefix_ipv4 p;
2959 struct route_node *node;
2960
2961 ret = str2prefix_ipv4 (argv[0], &p);
2962 if (ret < 0)
2963 {
2964 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2965 return CMD_WARNING;
2966 }
2967 apply_mask_ipv4 (&p);
2968
2969 /* For router rip configuration. */
2970 node = route_node_lookup (rip->route, (struct prefix *) &p);
2971 if (! node)
2972 {
2973 vty_out (vty, "Can't find route %s.%s", argv[0],
2974 VTY_NEWLINE);
2975 return CMD_WARNING;
2976 }
2977
2978 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2979 route_unlock_node (node);
2980
2981 node->info = NULL;
2982 route_unlock_node (node);
2983
2984 return CMD_SUCCESS;
2985}
2986
Stephen Hemminger2c239702009-12-10 19:16:05 +03002987#if 0
pauldc63bfd2005-10-25 23:31:05 +00002988static void
paul216565a2005-10-25 23:35:28 +00002989rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002990{
2991 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00002992 struct rip_info *rinfo = NULL;
2993 struct list *list = NULL;
2994 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002995
2996 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00002997 if ((list = np->info) != NULL)
2998 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2999 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
3000 rinfo->metric = rip->default_metric;
paul718e3742002-12-13 20:15:29 +00003001}
Stephen Hemminger2c239702009-12-10 19:16:05 +03003002#endif
paul718e3742002-12-13 20:15:29 +00003003
3004DEFUN (rip_default_metric,
3005 rip_default_metric_cmd,
3006 "default-metric <1-16>",
3007 "Set a metric of redistribute routes\n"
3008 "Default metric\n")
3009{
3010 if (rip)
3011 {
3012 rip->default_metric = atoi (argv[0]);
3013 /* rip_update_default_metric (); */
3014 }
3015 return CMD_SUCCESS;
3016}
3017
3018DEFUN (no_rip_default_metric,
3019 no_rip_default_metric_cmd,
3020 "no default-metric",
3021 NO_STR
3022 "Set a metric of redistribute routes\n"
3023 "Default metric\n")
3024{
3025 if (rip)
3026 {
3027 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3028 /* rip_update_default_metric (); */
3029 }
3030 return CMD_SUCCESS;
3031}
3032
3033ALIAS (no_rip_default_metric,
3034 no_rip_default_metric_val_cmd,
3035 "no default-metric <1-16>",
3036 NO_STR
3037 "Set a metric of redistribute routes\n"
3038 "Default metric\n")
3039
3040DEFUN (rip_timers,
3041 rip_timers_cmd,
3042 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3043 "Adjust routing timers\n"
3044 "Basic routing protocol update timers\n"
3045 "Routing table update timer value in second. Default is 30.\n"
3046 "Routing information timeout timer. Default is 180.\n"
3047 "Garbage collection timer. Default is 120.\n")
3048{
3049 unsigned long update;
3050 unsigned long timeout;
3051 unsigned long garbage;
3052 char *endptr = NULL;
3053 unsigned long RIP_TIMER_MAX = 2147483647;
3054 unsigned long RIP_TIMER_MIN = 5;
3055
3056 update = strtoul (argv[0], &endptr, 10);
3057 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3058 {
3059 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3060 return CMD_WARNING;
3061 }
3062
3063 timeout = strtoul (argv[1], &endptr, 10);
3064 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3065 {
3066 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3067 return CMD_WARNING;
3068 }
3069
3070 garbage = strtoul (argv[2], &endptr, 10);
3071 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3072 {
3073 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3074 return CMD_WARNING;
3075 }
3076
3077 /* Set each timer value. */
3078 rip->update_time = update;
3079 rip->timeout_time = timeout;
3080 rip->garbage_time = garbage;
3081
3082 /* Reset update timer thread. */
3083 rip_event (RIP_UPDATE_EVENT, 0);
3084
3085 return CMD_SUCCESS;
3086}
3087
3088DEFUN (no_rip_timers,
3089 no_rip_timers_cmd,
3090 "no timers basic",
3091 NO_STR
3092 "Adjust routing timers\n"
3093 "Basic routing protocol update timers\n")
3094{
3095 /* Set each timer value to the default. */
3096 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3097 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3098 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3099
3100 /* Reset update timer thread. */
3101 rip_event (RIP_UPDATE_EVENT, 0);
3102
3103 return CMD_SUCCESS;
3104}
hasso16705132003-05-25 14:49:19 +00003105
3106ALIAS (no_rip_timers,
3107 no_rip_timers_val_cmd,
3108 "no timers basic <0-65535> <0-65535> <0-65535>",
3109 NO_STR
3110 "Adjust routing timers\n"
3111 "Basic routing protocol update timers\n"
3112 "Routing table update timer value in second. Default is 30.\n"
3113 "Routing information timeout timer. Default is 180.\n"
3114 "Garbage collection timer. Default is 120.\n")
3115
David Lamparter6b0655a2014-06-04 06:53:35 +02003116
paul718e3742002-12-13 20:15:29 +00003117struct route_table *rip_distance_table;
3118
3119struct rip_distance
3120{
3121 /* Distance value for the IP source prefix. */
3122 u_char distance;
3123
3124 /* Name of the access-list to be matched. */
3125 char *access_list;
3126};
3127
pauldc63bfd2005-10-25 23:31:05 +00003128static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003129rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003130{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003131 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003132}
3133
pauldc63bfd2005-10-25 23:31:05 +00003134static void
paul718e3742002-12-13 20:15:29 +00003135rip_distance_free (struct rip_distance *rdistance)
3136{
3137 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3138}
3139
pauldc63bfd2005-10-25 23:31:05 +00003140static int
hasso98b718a2004-10-11 12:57:57 +00003141rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3142 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003143{
3144 int ret;
3145 struct prefix_ipv4 p;
3146 u_char distance;
3147 struct route_node *rn;
3148 struct rip_distance *rdistance;
3149
3150 ret = str2prefix_ipv4 (ip_str, &p);
3151 if (ret == 0)
3152 {
3153 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3154 return CMD_WARNING;
3155 }
3156
3157 distance = atoi (distance_str);
3158
3159 /* Get RIP distance node. */
3160 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3161 if (rn->info)
3162 {
3163 rdistance = rn->info;
3164 route_unlock_node (rn);
3165 }
3166 else
3167 {
3168 rdistance = rip_distance_new ();
3169 rn->info = rdistance;
3170 }
3171
3172 /* Set distance value. */
3173 rdistance->distance = distance;
3174
3175 /* Reset access-list configuration. */
3176 if (rdistance->access_list)
3177 {
3178 free (rdistance->access_list);
3179 rdistance->access_list = NULL;
3180 }
3181 if (access_list_str)
3182 rdistance->access_list = strdup (access_list_str);
3183
3184 return CMD_SUCCESS;
3185}
3186
pauldc63bfd2005-10-25 23:31:05 +00003187static int
hasso98b718a2004-10-11 12:57:57 +00003188rip_distance_unset (struct vty *vty, const char *distance_str,
3189 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003190{
3191 int ret;
3192 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +00003193 struct route_node *rn;
3194 struct rip_distance *rdistance;
3195
3196 ret = str2prefix_ipv4 (ip_str, &p);
3197 if (ret == 0)
3198 {
3199 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3200 return CMD_WARNING;
3201 }
3202
paul718e3742002-12-13 20:15:29 +00003203 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3204 if (! rn)
3205 {
3206 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3207 return CMD_WARNING;
3208 }
3209
3210 rdistance = rn->info;
3211
3212 if (rdistance->access_list)
3213 free (rdistance->access_list);
3214 rip_distance_free (rdistance);
3215
3216 rn->info = NULL;
3217 route_unlock_node (rn);
3218 route_unlock_node (rn);
3219
3220 return CMD_SUCCESS;
3221}
3222
pauldc63bfd2005-10-25 23:31:05 +00003223static void
paul216565a2005-10-25 23:35:28 +00003224rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003225{
3226 struct route_node *rn;
3227 struct rip_distance *rdistance;
3228
3229 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3230 if ((rdistance = rn->info) != NULL)
3231 {
3232 if (rdistance->access_list)
3233 free (rdistance->access_list);
3234 rip_distance_free (rdistance);
3235 rn->info = NULL;
3236 route_unlock_node (rn);
3237 }
3238}
3239
3240/* Apply RIP information to distance method. */
3241u_char
3242rip_distance_apply (struct rip_info *rinfo)
3243{
3244 struct route_node *rn;
3245 struct prefix_ipv4 p;
3246 struct rip_distance *rdistance;
3247 struct access_list *alist;
3248
3249 if (! rip)
3250 return 0;
3251
3252 memset (&p, 0, sizeof (struct prefix_ipv4));
3253 p.family = AF_INET;
3254 p.prefix = rinfo->from;
3255 p.prefixlen = IPV4_MAX_BITLEN;
3256
3257 /* Check source address. */
3258 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3259 if (rn)
3260 {
3261 rdistance = rn->info;
3262 route_unlock_node (rn);
3263
3264 if (rdistance->access_list)
3265 {
3266 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3267 if (alist == NULL)
3268 return 0;
3269 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3270 return 0;
3271
3272 return rdistance->distance;
3273 }
3274 else
3275 return rdistance->distance;
3276 }
3277
3278 if (rip->distance)
3279 return rip->distance;
3280
3281 return 0;
3282}
3283
pauldc63bfd2005-10-25 23:31:05 +00003284static void
paul718e3742002-12-13 20:15:29 +00003285rip_distance_show (struct vty *vty)
3286{
3287 struct route_node *rn;
3288 struct rip_distance *rdistance;
3289 int header = 1;
3290 char buf[BUFSIZ];
3291
3292 vty_out (vty, " Distance: (default is %d)%s",
3293 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3294 VTY_NEWLINE);
3295
3296 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3297 if ((rdistance = rn->info) != NULL)
3298 {
3299 if (header)
3300 {
3301 vty_out (vty, " Address Distance List%s",
3302 VTY_NEWLINE);
3303 header = 0;
3304 }
3305 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3306 vty_out (vty, " %-20s %4d %s%s",
3307 buf, rdistance->distance,
3308 rdistance->access_list ? rdistance->access_list : "",
3309 VTY_NEWLINE);
3310 }
3311}
3312
3313DEFUN (rip_distance,
3314 rip_distance_cmd,
3315 "distance <1-255>",
3316 "Administrative distance\n"
3317 "Distance value\n")
3318{
3319 rip->distance = atoi (argv[0]);
3320 return CMD_SUCCESS;
3321}
3322
3323DEFUN (no_rip_distance,
3324 no_rip_distance_cmd,
3325 "no distance <1-255>",
3326 NO_STR
3327 "Administrative distance\n"
3328 "Distance value\n")
3329{
3330 rip->distance = 0;
3331 return CMD_SUCCESS;
3332}
3333
3334DEFUN (rip_distance_source,
3335 rip_distance_source_cmd,
3336 "distance <1-255> A.B.C.D/M",
3337 "Administrative distance\n"
3338 "Distance value\n"
3339 "IP source prefix\n")
3340{
3341 rip_distance_set (vty, argv[0], argv[1], NULL);
3342 return CMD_SUCCESS;
3343}
3344
3345DEFUN (no_rip_distance_source,
3346 no_rip_distance_source_cmd,
3347 "no distance <1-255> A.B.C.D/M",
3348 NO_STR
3349 "Administrative distance\n"
3350 "Distance value\n"
3351 "IP source prefix\n")
3352{
3353 rip_distance_unset (vty, argv[0], argv[1], NULL);
3354 return CMD_SUCCESS;
3355}
3356
3357DEFUN (rip_distance_source_access_list,
3358 rip_distance_source_access_list_cmd,
3359 "distance <1-255> A.B.C.D/M WORD",
3360 "Administrative distance\n"
3361 "Distance value\n"
3362 "IP source prefix\n"
3363 "Access list name\n")
3364{
3365 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3366 return CMD_SUCCESS;
3367}
3368
3369DEFUN (no_rip_distance_source_access_list,
3370 no_rip_distance_source_access_list_cmd,
3371 "no distance <1-255> A.B.C.D/M WORD",
3372 NO_STR
3373 "Administrative distance\n"
3374 "Distance value\n"
3375 "IP source prefix\n"
3376 "Access list name\n")
3377{
3378 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3379 return CMD_SUCCESS;
3380}
David Lamparter6b0655a2014-06-04 06:53:35 +02003381
Lu Feng0b74a0a2014-07-18 06:13:19 +00003382/* Update ECMP routes to zebra when ECMP is disabled. */
3383static void
3384rip_ecmp_disable (void)
3385{
3386 struct route_node *rp;
3387 struct rip_info *rinfo, *tmp_rinfo;
3388 struct list *list;
3389 struct listnode *node, *nextnode;
3390
3391 if (!rip)
3392 return;
3393
3394 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3395 if ((list = rp->info) != NULL && listcount (list) > 1)
3396 {
3397 rinfo = listgetdata (listhead (list));
3398 if (!rip_route_rte (rinfo))
3399 continue;
3400
3401 /* Drop all other entries, except the first one. */
3402 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
3403 if (tmp_rinfo != rinfo)
3404 {
3405 RIP_TIMER_OFF (tmp_rinfo->t_timeout);
3406 RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect);
3407 list_delete_node (list, node);
3408 rip_info_free (tmp_rinfo);
3409 }
3410
3411 /* Update zebra. */
3412 rip_zebra_ipv4_add (rp);
3413
3414 /* Set the route change flag. */
3415 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
3416
3417 /* Signal the output process to trigger an update. */
3418 rip_event (RIP_TRIGGERED_UPDATE, 0);
3419 }
3420}
3421
3422DEFUN (rip_allow_ecmp,
3423 rip_allow_ecmp_cmd,
3424 "allow-ecmp",
3425 "Allow Equal Cost MultiPath\n")
3426{
3427 if (rip->ecmp)
3428 {
3429 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
3430 return CMD_WARNING;
3431 }
3432
3433 rip->ecmp = 1;
3434 zlog_info ("ECMP is enabled.");
3435 return CMD_SUCCESS;
3436}
3437
3438DEFUN (no_rip_allow_ecmp,
3439 no_rip_allow_ecmp_cmd,
3440 "no allow-ecmp",
3441 NO_STR
3442 "Allow Equal Cost MultiPath\n")
3443{
3444 if (!rip->ecmp)
3445 {
3446 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
3447 return CMD_WARNING;
3448 }
3449
3450 rip->ecmp = 0;
3451 zlog_info ("ECMP is disabled.");
3452 rip_ecmp_disable ();
3453 return CMD_SUCCESS;
3454}
3455
paul718e3742002-12-13 20:15:29 +00003456/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003457static void
paul718e3742002-12-13 20:15:29 +00003458rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3459{
paul718e3742002-12-13 20:15:29 +00003460 time_t clock;
3461 struct tm *tm;
3462#define TIME_BUF 25
3463 char timebuf [TIME_BUF];
3464 struct thread *thread;
3465
paul718e3742002-12-13 20:15:29 +00003466 if ((thread = rinfo->t_timeout) != NULL)
3467 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003468 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003469 tm = gmtime (&clock);
3470 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3471 vty_out (vty, "%5s", timebuf);
3472 }
3473 else if ((thread = rinfo->t_garbage_collect) != NULL)
3474 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003475 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003476 tm = gmtime (&clock);
3477 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3478 vty_out (vty, "%5s", timebuf);
3479 }
3480}
3481
pauldc63bfd2005-10-25 23:31:05 +00003482static const char *
paul718e3742002-12-13 20:15:29 +00003483rip_route_type_print (int sub_type)
3484{
3485 switch (sub_type)
3486 {
3487 case RIP_ROUTE_RTE:
3488 return "n";
3489 case RIP_ROUTE_STATIC:
3490 return "s";
3491 case RIP_ROUTE_DEFAULT:
3492 return "d";
3493 case RIP_ROUTE_REDISTRIBUTE:
3494 return "r";
3495 case RIP_ROUTE_INTERFACE:
3496 return "i";
3497 default:
3498 return "?";
3499 }
3500}
3501
3502DEFUN (show_ip_rip,
3503 show_ip_rip_cmd,
3504 "show ip rip",
3505 SHOW_STR
3506 IP_STR
3507 "Show RIP routes\n")
3508{
3509 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003510 struct rip_info *rinfo = NULL;
3511 struct list *list = NULL;
3512 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003513
3514 if (! rip)
3515 return CMD_SUCCESS;
3516
hasso16705132003-05-25 14:49:19 +00003517 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3518 "Sub-codes:%s"
3519 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003520 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003521 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003522 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003523
3524 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003525 if ((list = np->info) != NULL)
3526 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00003527 {
3528 int len;
3529
ajsf52d13c2005-10-01 17:38:06 +00003530 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003531 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003532 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003533 rip_route_type_print (rinfo->sub_type),
3534 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3535
hassoa1455d82004-03-03 19:36:24 +00003536 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003537
3538 if (len > 0)
3539 vty_out (vty, "%*s", len, " ");
3540
3541 if (rinfo->nexthop.s_addr)
3542 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3543 rinfo->metric);
3544 else
3545 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3546
3547 /* Route which exist in kernel routing table. */
3548 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3549 (rinfo->sub_type == RIP_ROUTE_RTE))
3550 {
3551 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003552 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003553 rip_vty_out_uptime (vty, rinfo);
3554 }
3555 else if (rinfo->metric == RIP_METRIC_INFINITY)
3556 {
3557 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003558 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003559 rip_vty_out_uptime (vty, rinfo);
3560 }
3561 else
hasso16705132003-05-25 14:49:19 +00003562 {
vincentfbf5d032005-09-29 11:25:50 +00003563 if (rinfo->external_metric)
3564 {
3565 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003566 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003567 rinfo->external_metric);
3568 len = 16 - len;
3569 if (len > 0)
3570 vty_out (vty, "%*s", len, " ");
3571 }
3572 else
3573 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003574 vty_out (vty, "%3d", rinfo->tag);
3575 }
paul718e3742002-12-13 20:15:29 +00003576
3577 vty_out (vty, "%s", VTY_NEWLINE);
3578 }
3579 return CMD_SUCCESS;
3580}
3581
hasso16705132003-05-25 14:49:19 +00003582/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3583DEFUN (show_ip_rip_status,
3584 show_ip_rip_status_cmd,
3585 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003586 SHOW_STR
3587 IP_STR
hasso16705132003-05-25 14:49:19 +00003588 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003589 "IP routing protocol process parameters and statistics\n")
3590{
hasso52dc7ee2004-09-23 19:18:23 +00003591 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003592 struct interface *ifp;
3593 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003594 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003595 const char *send_version;
3596 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003597
3598 if (! rip)
3599 return CMD_SUCCESS;
3600
3601 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3602 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3603 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003604 vty_out (vty, " next due in %lu seconds%s",
3605 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003606 VTY_NEWLINE);
3607 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3608 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3609 VTY_NEWLINE);
3610
3611 /* Filtering status show. */
3612 config_show_distribute (vty);
3613
3614 /* Default metric information. */
3615 vty_out (vty, " Default redistribution metric is %d%s",
3616 rip->default_metric, VTY_NEWLINE);
3617
3618 /* Redistribute information. */
3619 vty_out (vty, " Redistributing:");
3620 config_write_rip_redistribute (vty, 0);
3621 vty_out (vty, "%s", VTY_NEWLINE);
3622
paulf38a4712003-06-07 01:10:00 +00003623 vty_out (vty, " Default version control: send version %s,",
3624 lookup(ri_version_msg,rip->version_send));
3625 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3626 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3627 else
3628 vty_out (vty, " receive version %s %s",
3629 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003630
3631 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3632
paul1eb8ef22005-04-07 07:30:20 +00003633 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003634 {
paul718e3742002-12-13 20:15:29 +00003635 ri = ifp->info;
3636
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003637 if (!ri->running)
3638 continue;
3639
paul718e3742002-12-13 20:15:29 +00003640 if (ri->enable_network || ri->enable_interface)
3641 {
3642 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003643 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003644 else
3645 send_version = lookup (ri_version_msg, ri->ri_send);
3646
3647 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003648 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003649 else
3650 receive_version = lookup (ri_version_msg, ri->ri_receive);
3651
3652 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3653 send_version,
3654 receive_version,
3655 ri->key_chain ? ri->key_chain : "",
3656 VTY_NEWLINE);
3657 }
3658 }
3659
3660 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3661 config_write_rip_network (vty, 0);
3662
paul4aaff3f2003-06-07 01:04:45 +00003663 {
3664 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003665 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003666 {
paul4aaff3f2003-06-07 01:04:45 +00003667 ri = ifp->info;
3668
3669 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3670 {
3671 if (!found_passive)
3672 {
3673 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3674 found_passive = 1;
3675 }
3676 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3677 }
3678 }
3679 }
3680
paul718e3742002-12-13 20:15:29 +00003681 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3682 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3683 rip_peer_display (vty);
3684
3685 rip_distance_show (vty);
3686
3687 return CMD_SUCCESS;
3688}
3689
3690/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003691static int
paul718e3742002-12-13 20:15:29 +00003692config_write_rip (struct vty *vty)
3693{
3694 int write = 0;
3695 struct route_node *rn;
3696 struct rip_distance *rdistance;
3697
3698 if (rip)
3699 {
3700 /* Router RIP statement. */
3701 vty_out (vty, "router rip%s", VTY_NEWLINE);
3702 write++;
3703
3704 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003705 if (rip->version_send != RI_RIP_VERSION_2
3706 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3707 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003708 VTY_NEWLINE);
3709
3710 /* RIP timer configuration. */
3711 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3712 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3713 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3714 vty_out (vty, " timers basic %lu %lu %lu%s",
3715 rip->update_time,
3716 rip->timeout_time,
3717 rip->garbage_time,
3718 VTY_NEWLINE);
3719
3720 /* Default information configuration. */
3721 if (rip->default_information)
3722 {
3723 if (rip->default_information_route_map)
3724 vty_out (vty, " default-information originate route-map %s%s",
3725 rip->default_information_route_map, VTY_NEWLINE);
3726 else
3727 vty_out (vty, " default-information originate%s",
3728 VTY_NEWLINE);
3729 }
3730
3731 /* Redistribute configuration. */
3732 config_write_rip_redistribute (vty, 1);
3733
3734 /* RIP offset-list configuration. */
3735 config_write_rip_offset_list (vty);
3736
3737 /* RIP enabled network and interface configuration. */
3738 config_write_rip_network (vty, 1);
3739
3740 /* RIP default metric configuration */
3741 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3742 vty_out (vty, " default-metric %d%s",
3743 rip->default_metric, VTY_NEWLINE);
3744
3745 /* Distribute configuration. */
3746 write += config_write_distribute (vty);
3747
hasso16705132003-05-25 14:49:19 +00003748 /* Interface routemap configuration */
3749 write += config_write_if_rmap (vty);
3750
paul718e3742002-12-13 20:15:29 +00003751 /* Distance configuration. */
3752 if (rip->distance)
3753 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3754
3755 /* RIP source IP prefix distance configuration. */
3756 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3757 if ((rdistance = rn->info) != NULL)
3758 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3759 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3760 rdistance->access_list ? rdistance->access_list : "",
3761 VTY_NEWLINE);
3762
Lu Feng0b74a0a2014-07-18 06:13:19 +00003763 /* ECMP configuration. */
3764 if (rip->ecmp)
3765 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
3766
paul718e3742002-12-13 20:15:29 +00003767 /* RIP static route configuration. */
3768 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3769 if (rn->info)
3770 vty_out (vty, " route %s/%d%s",
3771 inet_ntoa (rn->p.u.prefix4),
3772 rn->p.prefixlen,
3773 VTY_NEWLINE);
3774
3775 }
3776 return write;
3777}
3778
3779/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003780static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003781{
3782 RIP_NODE,
3783 "%s(config-router)# ",
3784 1
3785};
David Lamparter6b0655a2014-06-04 06:53:35 +02003786
paul718e3742002-12-13 20:15:29 +00003787/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003788static void
paul718e3742002-12-13 20:15:29 +00003789rip_distribute_update (struct distribute *dist)
3790{
3791 struct interface *ifp;
3792 struct rip_interface *ri;
3793 struct access_list *alist;
3794 struct prefix_list *plist;
3795
3796 if (! dist->ifname)
3797 return;
3798
3799 ifp = if_lookup_by_name (dist->ifname);
3800 if (ifp == NULL)
3801 return;
3802
3803 ri = ifp->info;
3804
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003805 if (dist->list[DISTRIBUTE_V4_IN])
paul718e3742002-12-13 20:15:29 +00003806 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003807 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_IN]);
paul718e3742002-12-13 20:15:29 +00003808 if (alist)
3809 ri->list[RIP_FILTER_IN] = alist;
3810 else
3811 ri->list[RIP_FILTER_IN] = NULL;
3812 }
3813 else
3814 ri->list[RIP_FILTER_IN] = NULL;
3815
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003816 if (dist->list[DISTRIBUTE_V4_OUT])
paul718e3742002-12-13 20:15:29 +00003817 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003818 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_OUT]);
paul718e3742002-12-13 20:15:29 +00003819 if (alist)
3820 ri->list[RIP_FILTER_OUT] = alist;
3821 else
3822 ri->list[RIP_FILTER_OUT] = NULL;
3823 }
3824 else
3825 ri->list[RIP_FILTER_OUT] = NULL;
3826
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003827 if (dist->prefix[DISTRIBUTE_V4_IN])
paul718e3742002-12-13 20:15:29 +00003828 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003829 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]);
paul718e3742002-12-13 20:15:29 +00003830 if (plist)
3831 ri->prefix[RIP_FILTER_IN] = plist;
3832 else
3833 ri->prefix[RIP_FILTER_IN] = NULL;
3834 }
3835 else
3836 ri->prefix[RIP_FILTER_IN] = NULL;
3837
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003838 if (dist->prefix[DISTRIBUTE_V4_OUT])
paul718e3742002-12-13 20:15:29 +00003839 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003840 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]);
paul718e3742002-12-13 20:15:29 +00003841 if (plist)
3842 ri->prefix[RIP_FILTER_OUT] = plist;
3843 else
3844 ri->prefix[RIP_FILTER_OUT] = NULL;
3845 }
3846 else
3847 ri->prefix[RIP_FILTER_OUT] = NULL;
3848}
3849
3850void
3851rip_distribute_update_interface (struct interface *ifp)
3852{
3853 struct distribute *dist;
3854
3855 dist = distribute_lookup (ifp->name);
3856 if (dist)
3857 rip_distribute_update (dist);
3858}
3859
3860/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003861/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003862static void
paul02ff83c2004-06-11 11:27:03 +00003863rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003864{
3865 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003866 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003867
paul1eb8ef22005-04-07 07:30:20 +00003868 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3869 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003870}
paul11dde9c2004-05-31 14:00:00 +00003871/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003872static void
paul11dde9c2004-05-31 14:00:00 +00003873rip_distribute_update_all_wrapper(struct access_list *notused)
3874{
paul02ff83c2004-06-11 11:27:03 +00003875 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003876}
David Lamparter6b0655a2014-06-04 06:53:35 +02003877
paul718e3742002-12-13 20:15:29 +00003878/* Delete all added rip route. */
3879void
paul216565a2005-10-25 23:35:28 +00003880rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003881{
3882 int i;
3883 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00003884 struct rip_info *rinfo = NULL;
3885 struct list *list = NULL;
3886 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003887
3888 if (rip)
3889 {
3890 /* Clear RIP routes */
3891 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00003892 if ((list = rp->info) != NULL)
3893 {
3894 rinfo = listgetdata (listhead (list));
3895 if (rip_route_rte (rinfo))
3896 rip_zebra_ipv4_delete (rp);
paul718e3742002-12-13 20:15:29 +00003897
Lu Fengb397cf42014-07-18 06:13:18 +00003898 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3899 {
3900 RIP_TIMER_OFF (rinfo->t_timeout);
3901 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3902 rip_info_free (rinfo);
3903 }
3904 list_delete (list);
3905 rp->info = NULL;
3906 route_unlock_node (rp);
3907 }
paul718e3742002-12-13 20:15:29 +00003908
3909 /* Cancel RIP related timers. */
3910 RIP_TIMER_OFF (rip->t_update);
3911 RIP_TIMER_OFF (rip->t_triggered_update);
3912 RIP_TIMER_OFF (rip->t_triggered_interval);
3913
3914 /* Cancel read thread. */
3915 if (rip->t_read)
3916 {
3917 thread_cancel (rip->t_read);
3918 rip->t_read = NULL;
3919 }
3920
3921 /* Close RIP socket. */
3922 if (rip->sock >= 0)
3923 {
3924 close (rip->sock);
3925 rip->sock = -1;
3926 }
3927
3928 /* Static RIP route configuration. */
3929 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3930 if (rp->info)
3931 {
3932 rp->info = NULL;
3933 route_unlock_node (rp);
3934 }
3935
3936 /* RIP neighbor configuration. */
3937 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3938 if (rp->info)
3939 {
3940 rp->info = NULL;
3941 route_unlock_node (rp);
3942 }
3943
3944 /* Redistribute related clear. */
3945 if (rip->default_information_route_map)
3946 free (rip->default_information_route_map);
3947
3948 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3949 if (rip->route_map[i].name)
3950 free (rip->route_map[i].name);
3951
3952 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3953 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3954 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3955
3956 XFREE (MTYPE_RIP, rip);
3957 rip = NULL;
3958 }
3959
3960 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003961 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003962 rip_offset_clean ();
Paul Jakmad319a3a2016-05-25 14:47:00 +01003963 rip_interfaces_clean ();
paul718e3742002-12-13 20:15:29 +00003964 rip_distance_reset ();
3965 rip_redistribute_clean ();
3966}
3967
3968/* Reset all values to the default settings. */
3969void
paul216565a2005-10-25 23:35:28 +00003970rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003971{
3972 /* Reset global counters. */
3973 rip_global_route_changes = 0;
3974 rip_global_queries = 0;
3975
3976 /* Call ripd related reset functions. */
3977 rip_debug_reset ();
3978 rip_route_map_reset ();
3979
3980 /* Call library reset functions. */
3981 vty_reset ();
3982 access_list_reset ();
3983 prefix_list_reset ();
3984
3985 distribute_list_reset ();
3986
Paul Jakmad319a3a2016-05-25 14:47:00 +01003987 rip_interfaces_reset ();
paul718e3742002-12-13 20:15:29 +00003988 rip_distance_reset ();
3989
3990 rip_zclient_reset ();
3991}
3992
pauldc63bfd2005-10-25 23:31:05 +00003993static void
hasso16705132003-05-25 14:49:19 +00003994rip_if_rmap_update (struct if_rmap *if_rmap)
3995{
3996 struct interface *ifp;
3997 struct rip_interface *ri;
3998 struct route_map *rmap;
3999
4000 ifp = if_lookup_by_name (if_rmap->ifname);
4001 if (ifp == NULL)
4002 return;
4003
4004 ri = ifp->info;
4005
4006 if (if_rmap->routemap[IF_RMAP_IN])
4007 {
4008 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
4009 if (rmap)
4010 ri->routemap[IF_RMAP_IN] = rmap;
4011 else
4012 ri->routemap[IF_RMAP_IN] = NULL;
4013 }
4014 else
4015 ri->routemap[RIP_FILTER_IN] = NULL;
4016
4017 if (if_rmap->routemap[IF_RMAP_OUT])
4018 {
4019 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
4020 if (rmap)
4021 ri->routemap[IF_RMAP_OUT] = rmap;
4022 else
4023 ri->routemap[IF_RMAP_OUT] = NULL;
4024 }
4025 else
4026 ri->routemap[RIP_FILTER_OUT] = NULL;
4027}
4028
4029void
4030rip_if_rmap_update_interface (struct interface *ifp)
4031{
4032 struct if_rmap *if_rmap;
4033
4034 if_rmap = if_rmap_lookup (ifp->name);
4035 if (if_rmap)
4036 rip_if_rmap_update (if_rmap);
4037}
4038
pauldc63bfd2005-10-25 23:31:05 +00004039static void
hasso16705132003-05-25 14:49:19 +00004040rip_routemap_update_redistribute (void)
4041{
4042 int i;
4043
4044 if (rip)
4045 {
4046 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4047 {
4048 if (rip->route_map[i].name)
4049 rip->route_map[i].map =
4050 route_map_lookup_by_name (rip->route_map[i].name);
4051 }
4052 }
4053}
4054
paul11dde9c2004-05-31 14:00:00 +00004055/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00004056static void
hasso98b718a2004-10-11 12:57:57 +00004057rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00004058{
4059 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00004060 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00004061
paul1eb8ef22005-04-07 07:30:20 +00004062 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
4063 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00004064
4065 rip_routemap_update_redistribute ();
4066}
4067
paul718e3742002-12-13 20:15:29 +00004068/* Allocate new rip structure and set default value. */
4069void
pauldc63bfd2005-10-25 23:31:05 +00004070rip_init (void)
paul718e3742002-12-13 20:15:29 +00004071{
4072 /* Randomize for triggered update random(). */
Donald Sharpf31bab42015-06-19 19:26:19 -04004073 srandom (time (NULL));
paul718e3742002-12-13 20:15:29 +00004074
4075 /* Install top nodes. */
4076 install_node (&rip_node, config_write_rip);
4077
4078 /* Install rip commands. */
4079 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004080 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004081 install_element (CONFIG_NODE, &router_rip_cmd);
4082 install_element (CONFIG_NODE, &no_router_rip_cmd);
4083
4084 install_default (RIP_NODE);
4085 install_element (RIP_NODE, &rip_version_cmd);
4086 install_element (RIP_NODE, &no_rip_version_cmd);
4087 install_element (RIP_NODE, &no_rip_version_val_cmd);
4088 install_element (RIP_NODE, &rip_default_metric_cmd);
4089 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4090 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4091 install_element (RIP_NODE, &rip_timers_cmd);
4092 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004093 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004094 install_element (RIP_NODE, &rip_route_cmd);
4095 install_element (RIP_NODE, &no_rip_route_cmd);
4096 install_element (RIP_NODE, &rip_distance_cmd);
4097 install_element (RIP_NODE, &no_rip_distance_cmd);
4098 install_element (RIP_NODE, &rip_distance_source_cmd);
4099 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4100 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4101 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
Lu Feng0b74a0a2014-07-18 06:13:19 +00004102 install_element (RIP_NODE, &rip_allow_ecmp_cmd);
4103 install_element (RIP_NODE, &no_rip_allow_ecmp_cmd);
paul718e3742002-12-13 20:15:29 +00004104
4105 /* Debug related init. */
4106 rip_debug_init ();
4107
paul718e3742002-12-13 20:15:29 +00004108 /* SNMP init. */
4109#ifdef HAVE_SNMP
4110 rip_snmp_init ();
4111#endif /* HAVE_SNMP */
4112
4113 /* Access list install. */
4114 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004115 access_list_add_hook (rip_distribute_update_all_wrapper);
4116 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004117
4118 /* Prefix list initialize.*/
4119 prefix_list_init ();
4120 prefix_list_add_hook (rip_distribute_update_all);
4121 prefix_list_delete_hook (rip_distribute_update_all);
4122
4123 /* Distribute list install. */
4124 distribute_list_init (RIP_NODE);
4125 distribute_list_add_hook (rip_distribute_update);
4126 distribute_list_delete_hook (rip_distribute_update);
4127
hasso16705132003-05-25 14:49:19 +00004128 /* Route-map */
4129 rip_route_map_init ();
4130 rip_offset_init ();
4131
4132 route_map_add_hook (rip_routemap_update);
4133 route_map_delete_hook (rip_routemap_update);
4134
4135 if_rmap_init (RIP_NODE);
4136 if_rmap_hook_add (rip_if_rmap_update);
4137 if_rmap_hook_delete (rip_if_rmap_update);
4138
paul718e3742002-12-13 20:15:29 +00004139 /* Distance control. */
4140 rip_distance_table = route_table_init ();
4141}